+ Elf32_Dyn *dynTab = NULL;
+ uintptr_t iBaseDiff = -1;
+ Elf32_Ehdr *hdr = Base;
+ Elf32_Phdr *phtab = (void*)( (uintptr_t)Base + hdr->phoff );
+ for( int i = 0; i < hdr->phentcount; i ++ )
+ {
+ if(phtab[i].Type == PT_LOAD && iBaseDiff > phtab[i].VAddr)
+ iBaseDiff = phtab[i].VAddr;
+ if( phtab[i].Type == PT_DYNAMIC ) {
+ dynTab = (void*)(intptr_t)phtab[i].VAddr;
+ }
+ }
+ if( !dynTab ) {
+ SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
+ return 1;
+ }
+ iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
+ dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
+ for( int i = 0; dynTab[i].d_tag != DT_NULL; i++)
+ {
+ switch(dynTab[i].d_tag)
+ {
+ // --- Symbol Table ---
+ case DT_SYMTAB:
+ *symtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); // Rebased in Relocate
+ break;
+ case DT_STRTAB:
+ *dynstrtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff);
+ break;
+ // --- Hash Table --
+ case DT_HASH:
+ *pBuckets = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff);
+ break;
+ }
+ }
+
+ if( !*symtab ) {
+ SysDebug("ERRO - No DT_SYMTAB in %p", Base);
+ return 1;
+ }
+ if( !*pBuckets ) {
+ SysDebug("ERRO - No DT_HASH in %p", Base);
+ return 1;
+ }
+ if( !*dynstrtab ) {
+ SysDebug("ERRO - No DT_STRTAB in %p", Base);
+ return 1;
+ }
+
+ // ... ok... maybe they haven't been relocated
+ if( (uintptr_t)*symtab < (uintptr_t)Base )
+ {
+ SysDebug("Executable not yet relocated (symtab,pBuckets,dynstrtab = %p,%p,%p + 0x%x)",
+ *symtab,*pBuckets,*dynstrtab, iBaseDiff);
+ *symtab = (void*)( (uintptr_t)*symtab + iBaseDiff );
+ *pBuckets = (void*)( (uintptr_t)*pBuckets + iBaseDiff );
+ *dynstrtab = (void*)( (uintptr_t)*dynstrtab + iBaseDiff );
+ }
+ *piBaseDiff = iBaseDiff;
+ return 0;
+}
+
+int Elf32GetSymbolInfo(void *Base, const char *Name, void **Addr, size_t *Size, int* Section, int *Binding, int *Type)
+{
+ // Locate the tables
+ uintptr_t iBaseDiff = -1;
+ Elf32_Sym *symtab = NULL;
+ Elf32_Word *pBuckets = NULL;
+ const char *dynstrtab = NULL;
+ if( Elf32GetSymbolVars(Base, &symtab, &pBuckets, &dynstrtab, &iBaseDiff) )
+ return 1;
+
+ int nbuckets = pBuckets[0];
+// int iSymCount = pBuckets[1];
+ pBuckets = &pBuckets[2];
+ Elf32_Word* pChains = &pBuckets[ nbuckets ];
+ assert(pChains);
+
+ // Get hash
+ int iNameHash = ElfHashString(Name);
+ iNameHash %= nbuckets;
+
+ // Walk Chain
+ int idx = pBuckets[ iNameHash ];
+ do {
+ const Elf32_Sym *sym = &symtab[idx];
+ assert(sym);
+ if( strcmp(dynstrtab + sym->st_name, Name) == 0 )
+ {
+ TRACE("*sym = {value:0x%x,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
+ sym->st_value, sym->st_size, sym->st_info,
+ sym->st_other, sym->st_shndx);
+ if(Addr) *Addr = (void*)( sym->st_value );
+ if(Size) *Size = sym->st_size;
+ if(Binding) *Binding = ELF32_ST_BIND(sym->st_info);
+ if(Type) *Type = ELF32_ST_TYPE(sym->st_info);
+ if(Section) *Section = sym->st_shndx;
+ return 0;
+ }
+ } while( (idx = pChains[idx]) != STN_UNDEF && idx != pBuckets[iNameHash] );
+
+ TRACE("No symbol");
+ return 1;
+}
+
+int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
+{
+ int section, binding;
+ TRACE("Elf32GetSymbol(%p,%s,...)", Base, Name);
+ if( Elf32GetSymbolInfo(Base, Name, ret, Size, §ion, &binding, NULL) )
+ return 0;
+ if( section == SHN_UNDEF ) {
+ TRACE("Elf32GetSymbol: Undefined %p", *ret, (Size?*Size:0), section);
+ return 0;
+ }
+ if( binding == STB_WEAK ) {
+ TRACE("Elf32GetSymbol: Weak, return %p+0x%x,section=%i", *ret, (Size?*Size:0), section);
+ return 2;
+ }
+ TRACE("Elf32GetSymbol: Found %p+0x%x,section=%i", *ret, (Size?*Size:0), section);
+ return 1;
+}
+
+#ifdef SUPPORT_ELF64
+typedef int (*t_elf64_doreloc)(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend);
+
+int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend)
+{
+ int sym = ELF64_R_SYM(r_info);
+ int type = ELF64_R_TYPE(r_info);
+ const char *symname = strtab + symtab[sym].st_name;
+ void *symval;
+ //DEBUGS("_Elf64DoReloc: %s", symname);
+ switch( type )
+ {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_64:
+ if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
+ *(uint64_t*)ptr = (uintptr_t)symval + addend;
+ break;
+ case R_X86_64_COPY: {
+ size_t size;
+ if( !GetSymbol(symname, &symval, &size, NULL) ) return 1;
+ memcpy(ptr, symval, size);
+ } break;
+ case R_X86_64_GLOB_DAT:
+ if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
+ *(uint64_t*)ptr = (uintptr_t)symval;
+ break;
+ case R_X86_64_JUMP_SLOT:
+ if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
+ *(uint64_t*)ptr = (uintptr_t)symval;
+ break;
+ case R_X86_64_RELATIVE:
+ *(uint64_t*)ptr = (uintptr_t)Base + addend;
+ break;
+ default:
+ SysDebug("ld-acess - _Elf64DoReloc: Unknown relocation type %i", type);
+ return 2;
+ }
+ //DEBUGS("_Elf64DoReloc: - Good");
+ return 0;
+}
+
+void *Elf64Relocate(void *Base, char **envp, const char *Filename)
+{
+ int i;
+ Elf64_Ehdr *hdr = Base;
+ Elf64_Phdr *phtab;
+ Elf64_Dyn *dyntab = NULL;
+ Elf64_Addr compiledBase = -1, baseDiff;
+ Elf64_Sym *symtab = NULL;
+ char *strtab = NULL;
+ Elf64_Word *hashtab = NULL;
+ Elf64_Rel *rel = NULL;
+ int rel_count = 0;
+ Elf64_Rela *rela = NULL;
+ int rela_count = 0;
+ void *pltrel = NULL;
+ int plt_size = 0, plt_type = 0;
+
+ TRACE("hdr = {");
+ TRACE(" e_ident = '%.16s'", hdr->e_ident);
+ TRACE(" e_type = 0x%x", hdr->e_type);
+ TRACE(" e_machine = 0x%x", hdr->e_machine);
+ TRACE(" e_version = 0x%x", hdr->e_version);
+ TRACE(" e_entry = %p", hdr->e_entry);
+ TRACE(" e_phoff = 0x%llx", hdr->e_phoff);
+ TRACE(" e_shoff = 0x%llx", hdr->e_shoff);
+ TRACE(" e_flags = 0x%x", hdr->e_flags);
+ TRACE(" e_ehsize = 0x%x", hdr->e_ehsize);
+ TRACE(" e_phentsize = 0x%x", hdr->e_phentsize);
+ TRACE(" e_phnum = %i", hdr->e_phnum);
+
+ // Scan for the dynamic table (and find the compiled base)
+ phtab = (void*)((uintptr_t)Base + (uintptr_t)hdr->e_phoff);
+ for( i = 0; i < hdr->e_phnum; i ++ )
+ {
+ if(phtab[i].p_type == PT_DYNAMIC)
+ dyntab = (void *)(intptr_t)phtab[i].p_vaddr;
+ if(phtab[i].p_type == PT_LOAD && compiledBase > phtab[i].p_vaddr)
+ compiledBase = phtab[i].p_vaddr;
+ }
+
+ baseDiff = (uintptr_t)Base - compiledBase;
+
+ TRACE("baseDiff = %p", baseDiff);
+
+ if(dyntab == NULL) {
+ SysDebug(" Elf64Relocate: No PT_DYNAMIC segment in image %p, returning", Base);
+ return (void *)(uintptr_t)(hdr->e_entry + baseDiff);
+ }
+
+ dyntab = (void *)(uintptr_t)((uintptr_t)dyntab + baseDiff);
+
+ // Parse the dynamic table (first pass)
+ // - Search for String, Symbol and Hash tables
+ for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
+ {
+ switch(dyntab[i].d_tag)
+ {
+ case DT_SYMTAB:
+ dyntab[i].d_un.d_ptr += baseDiff;
+ symtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
+ break;
+ case DT_STRTAB:
+ dyntab[i].d_un.d_ptr += baseDiff;
+ strtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
+ break;
+ case DT_HASH:
+ dyntab[i].d_un.d_ptr += baseDiff;
+ hashtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
+ break;
+ }
+ }
+
+ if( !symtab || !strtab || !hashtab ) {
+ SysDebug("ld-acess - Elf64Relocate: Missing Symbol, string or hash table");
+ return NULL;
+ }
+
+ // Ready for symbol use
+ AddLoaded( Filename, Base );
+
+ // Second pass on dynamic table
+ for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
+ {
+ TRACE("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag);
+ switch(dyntab[i].d_tag)
+ {
+ case DT_SONAME: break;
+
+ case DT_NEEDED: {
+ char *libPath = strtab + dyntab[i].d_un.d_val;
+ TRACE("Elf64Relocate: libPath = '%s'", libPath);
+ if(LoadLibrary(libPath, NULL, envp) == 0) {
+ SysDebug("ld-acess - Elf64Relocate: Unable to load '%s'", libPath);
+ return NULL;
+ }
+ } break;
+
+ // Relocation entries
+ case DT_REL:
+ dyntab[i].d_un.d_ptr += baseDiff;
+ rel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
+ break;
+ case DT_RELSZ:
+ rel_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rel);
+ break;
+ case DT_RELENT:
+ if( dyntab[i].d_un.d_val != sizeof(Elf64_Rel) ) {
+ SysDebug("ld-acess - Elf64Relocate: DT_RELENT(%i) != sizeof(Elf64_Rel)(%i)",
+ dyntab[i].d_un.d_val, sizeof(Elf64_Rel));
+ return NULL;
+ }
+ break;
+ case DT_RELA:
+ dyntab[i].d_un.d_ptr += baseDiff;
+ rela = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
+ break;
+ case DT_RELASZ:
+ rela_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rela);
+ break;
+ case DT_RELAENT:
+ if( dyntab[i].d_un.d_val != sizeof(Elf64_Rela) ) {
+ SysDebug("ld-acess - Elf64Relocate: DT_RELAENT(%i) != sizeof(Elf64_Rela)(%i)",
+ dyntab[i].d_un.d_val, sizeof(Elf64_Rela));
+ return NULL;
+ }
+ break;
+ case DT_JMPREL:
+ dyntab[i].d_un.d_ptr += baseDiff;
+ pltrel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
+ break;
+ case DT_PLTREL:
+ plt_type = dyntab[i].d_un.d_val;
+ break;
+ case DT_PLTRELSZ:
+ plt_size = dyntab[i].d_un.d_val;
+ break;
+ }
+ }
+
+ // TODO: Relocate symbols
+
+ // Relocation function
+ t_elf64_doreloc fpElf64DoReloc = &_Elf64DoReloc_X86_64;
+ #define _Elf64DoReloc(info, ptr, addend) fpElf64DoReloc(Base, strtab, symtab, info, ptr, addend)
+
+ int fail = 0;
+ if( rel )
+ {
+ TRACE("rel_count = %i", rel_count);
+ for( i = 0; i < rel_count; i ++ )
+ {
+ uint64_t *ptr = (void *)(uintptr_t)( rel[i].r_offset + baseDiff );
+ fail |= _Elf64DoReloc( rel[i].r_info, ptr, *ptr);
+ }
+ }
+
+ if( rela )
+ {
+ TRACE("rela_count = %i", rela_count);
+ for( i = 0; i < rela_count; i ++ )
+ {
+ uint64_t *ptr = (void *)(uintptr_t)( rela[i].r_offset + baseDiff );
+ fail |= _Elf64DoReloc( rela[i].r_info, ptr, rela[i].r_addend );
+ }
+ }
+
+ if( pltrel && plt_type )
+ {
+ if( plt_type == DT_REL ) {
+ Elf64_Rel *plt = pltrel;
+ int count = plt_size / sizeof(Elf64_Rel);
+ TRACE("plt rel count = %i", count);
+ for( i = 0; i < count; i ++ )
+ {
+ uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
+ fail |= _Elf64DoReloc( plt[i].r_info, ptr, *ptr);
+ }
+ }
+ else {
+ Elf64_Rela *plt = pltrel;
+ int count = plt_size / sizeof(Elf64_Rela);
+ TRACE("plt rela count = %i", count);
+ for( i = 0; i < count; i ++ )
+ {
+ uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
+ fail |= _Elf64DoReloc( plt[i].r_info, ptr, plt[i].r_addend);
+ }
+ }
+ }
+
+ if( fail ) {
+ TRACE("Failure");
+ return NULL;
+ }
+
+ {
+ void *ret = (void *)(uintptr_t)(hdr->e_entry + baseDiff);
+ TRACE("Relocations done, return %p", ret);
+ return ret;
+ }
+}
+
+int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size)
+{
+ Elf64_Ehdr *hdr = Base;
+ Elf64_Sym *symtab;
+ int nbuckets = 0;
+// int iSymCount = 0;
+ int i;
+ Elf64_Word *pBuckets;
+ Elf64_Word *pChains;
+ uint32_t iNameHash;
+ const char *dynstrtab;
+ uintptr_t iBaseDiff = -1;
+
+ dynstrtab = NULL;
+ pBuckets = NULL;
+ symtab = NULL;
+
+ // Catch the current executable
+ if( !pBuckets )
+ {
+ Elf64_Phdr *phtab;
+ Elf64_Dyn *dynTab = NULL;
+ int j;
+
+ // Locate the tables
+ phtab = (void*)( (intptr_t)Base + (uintptr_t)hdr->e_phoff );
+ for( i = 0; i < hdr->e_phnum; i ++ )
+ {
+ if(phtab[i].p_type == PT_LOAD && iBaseDiff > phtab[i].p_vaddr)
+ iBaseDiff = phtab[i].p_vaddr;
+ if( phtab[i].p_type == PT_DYNAMIC ) {
+ dynTab = (void*)(intptr_t)phtab[i].p_vaddr;
+ }
+ }
+ if( !dynTab ) {
+ SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
+ return 0;
+ }
+ iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
+ dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
+
+ for( j = 0; dynTab[j].d_tag != DT_NULL; j++)
+ {
+ switch(dynTab[j].d_tag)
+ {
+ // --- Symbol Table ---
+ case DT_SYMTAB:
+ symtab = (void*)(intptr_t) dynTab[j].d_un.d_val; // Rebased in Relocate
+ break;
+ case DT_STRTAB:
+ dynstrtab = (void*)(intptr_t) dynTab[j].d_un.d_val;
+ break;
+ // --- Hash Table --
+ case DT_HASH:
+ pBuckets = (void*)(intptr_t) dynTab[j].d_un.d_val;
+ break;
+ }
+ }
+ }
+
+ nbuckets = pBuckets[0];
+// iSymCount = pBuckets[1];
+ pBuckets = &pBuckets[2];
+ pChains = &pBuckets[ nbuckets ];