2 * Acess2 Dynamic Linker
3 * - By John Hodge (thePowersGang)
6 * - ELF32/ELF64 relocation
8 #ifndef DEBUG // This code is #include'd from the kernel, so DEBUG may already be defined
13 # define PAGE_SIZE 4096
25 # define DEBUG_OUT(...) SysDebug(__VA_ARGS__)
27 # define DEBUG_OUT(...) do{}while(0) //((void)(__VA_ARGS__))
30 #define WARNING(f,...) SysDebug("WARN: "f ,## __VA_ARGS__) // Malformed file
31 #define NOTICE(f,...) SysDebug("NOTICE: "f ,## __VA_ARGS__) // Missing relocation
32 #define TRACE(f,...) DEBUG_OUT("TRACE:%s:%i "f, __func__, __LINE__ ,## __VA_ARGS__) // Debugging trace
35 # define SUPPORT_ELF64
46 typedef int tElf32RelocFcn(tElfRelocInfo *Info, uint32_t t_info, uint32_t *ptr, Elf32_Addr addend, int bRela);
50 //static const char *csaDT_NAMES[] = {"DT_NULL", "DT_NEEDED", "DT_PLTRELSZ", "DT_PLTGOT", "DT_HASH", "DT_STRTAB", "DT_SYMTAB", "DT_RELA", "DT_RELASZ", "DT_RELAENT", "DT_STRSZ", "DT_SYMENT", "DT_INIT", "DT_FINI", "DT_SONAME", "DT_RPATH", "DT_SYMBOLIC", "DT_REL", "DT_RELSZ", "DT_RELENT", "DT_PLTREL", "DT_DEBUG", "DT_TEXTREL", "DT_JMPREL"};
51 //static const char *csaR_NAMES[] = {"R_386_NONE", "R_386_32", "R_386_PC32", "R_386_GOT32", "R_386_PLT32", "R_386_COPY", "R_386_GLOB_DAT", "R_386_JMP_SLOT", "R_386_RELATIVE", "R_386_GOTOFF", "R_386_GOTPC", "R_386_LAST"};
55 void *ElfRelocate(void *Base, char **envp, const char *Filename);
56 int ElfGetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
57 void *Elf32Relocate(void *Base, char **envp, const char *Filename);
58 int Elf32GetSymbolVars(void *Base, Elf32_Sym** symtab, Elf32_Word** pBuckets, const char **dynstrtab, uintptr_t* piBaseDiff);
59 int Elf32GetSymbolInfo(void *Base, const char *Name, void **Addr, size_t *Size, int* Section, int *Binding, int *Type);
60 int Elf32GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
61 tElf32RelocFcn elf_doRelocate_386;
62 tElf32RelocFcn elf_doRelocate_arm;
63 tElf32RelocFcn elf_doRelocate_unk;
65 int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend);
66 void *Elf64Relocate(void *Base, char **envp, const char *Filename);
67 int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
69 int Elf32GetSymbolReloc(tElfRelocInfo *Info, const Elf32_Sym *Symbol, void **Ret, size_t *Size);
70 uint32_t ElfHashString(const char *name);
74 * \fn int ElfRelocate(void *Base, char **envp, const char *Filename)
75 * \brief Relocates a loaded ELF Executable
77 void *ElfRelocate(void *Base, char **envp, const char *Filename)
79 Elf32_Ehdr *hdr = Base;
81 switch(hdr->e_ident[4])
84 return Elf32Relocate(Base, envp, Filename);
87 return Elf64Relocate(Base, envp, Filename);
90 SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
96 * \fn int ElfGetSymbol(Uint Base, const char *name, void **ret)
98 int ElfGetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
100 Elf32_Ehdr *hdr = Base;
102 switch(hdr->e_ident[4])
105 return Elf32GetSymbol(Base, Name, ret, Size);
108 return Elf64GetSymbol(Base, Name, ret, Size);
111 SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
116 int elf_doRelocate_386(tElfRelocInfo *Info, uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int bRela)
118 const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
119 void *symval = (void*)sym->st_value;
120 size_t size = sym->st_size;
121 TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name);
122 switch( ELF32_R_TYPE(r_info) )
124 // Standard 32 Bit Relocation (S+A)
126 TRACE("R_386_32 *0x%x = %p + 0x%x", ptr, symval, addend);
127 *ptr = (intptr_t)symval + addend;
130 // 32 Bit Relocation wrt. Offset (S+A-P)
132 TRACE("R_386_PC32 *0x%x = 0x%x + 0x%p - 0x%x", ptr, *ptr, symval, (intptr_t)ptr );
133 *ptr = (intptr_t)symval + addend - (intptr_t)ptr;
134 //*ptr = val + addend - ((Uint)ptr - iBaseDiff);
137 // Absolute Value of a symbol (S)
139 TRACE("R_386_GLOB_DAT *0x%x = %p", ptr, symval); if(0)
141 TRACE("R_386_JMP_SLOT *0x%x = %p", ptr, symval);
142 *ptr = (intptr_t)symval;
145 // Base Address (B+A)
147 TRACE("R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend);
148 *ptr = Info->iBaseDiff + addend;
152 void *old_symval = symval;
153 GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base);
154 if( symval == old_symval ) {
155 WARNING("Can't find required external symbol '%s'", Info->strtab + sym->st_name);
158 TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
159 memcpy(ptr, symval, size);
163 WARNING("Unknown relocation %i", ELF32_ST_TYPE(r_info));
169 int elf_doRelocate_arm(tElfRelocInfo *Info, uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int bRela)
171 const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
172 void *symval = (void*)sym->st_value;
173 size_t size = sym->st_size;
174 TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name);
175 uintptr_t val = (uintptr_t)symval;
176 switch( ELF32_R_TYPE(r_info) )
180 TRACE("R_ARM_ABS32 %p (%p + %x)", ptr, symval, addend);
184 TRACE("R_ARM_GLOB_DAT %p (%p + %x)", ptr, symval, addend);
187 case R_ARM_JUMP_SLOT:
188 if(!bRela) addend = 0;
189 TRACE("R_ARM_JUMP_SLOT %p (%p + %x)", ptr, symval, addend);
194 TRACE("R_ARM_COPY (%p, %p, %i)", ptr, symval, size);
195 memcpy(ptr, symval, size);
197 // Delta between link and runtime locations + A
199 TRACE("R_ARM_RELATIVE %p (0x%x + 0x%x)", ptr, Info->iBaseDiff, addend);
200 if(ELF32_R_SYM(r_info) != 0) {
201 // TODO: Get delta for a symbol
202 WARNING("TODO - Implment R_ARM_RELATIVE for symbols");
206 *ptr = Info->iBaseDiff + addend;
210 WARNING("Unknown Relocation, %i", ELF32_R_TYPE(r_info));
216 int elf_doRelocate_unk(tElfRelocInfo *Info, uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int bRela)
221 void *Elf32Relocate(void *Base, char **envp, const char *Filename)
223 const Elf32_Ehdr *hdr = Base;
225 intptr_t iRealBase = -1;
227 Elf32_Rel *rel = NULL;
228 Elf32_Rela *rela = NULL;
230 int relSz=0, relEntSz=8;
231 int relaSz=0, relaEntSz=8;
232 int pltSz=0, pltType=0;
233 Elf32_Dyn *dynamicTab = NULL; // Dynamic Table Pointer
235 TRACE("(Base=0x%x)", Base);
237 // Check magic header
240 // Parse Program Header to get Dynamic Table
241 // - Determine the linked base of the executable
242 const Elf32_Phdr *phtab = (void*)( (uintptr_t)Base + hdr->phoff );
243 const int iSegmentCount = hdr->phentcount;
244 for(int i = 0; i < iSegmentCount; i ++)
246 switch(phtab[i].Type)
249 // Determine linked base address
250 if( iRealBase > phtab[i].VAddr)
251 iRealBase = phtab[i].VAddr;
254 // Find Dynamic Section
256 dynamicTab = (void *) (intptr_t) phtab[i].VAddr;
259 WARNING("elf_relocate: Multiple PT_DYNAMIC segments");
265 // Page Align real base
267 TRACE("True Base = 0x%x, Compiled Base = 0x%x", Base, iRealBase);
269 // Adjust "Real" Base
270 iBaseDiff = (intptr_t)Base - iRealBase;
272 // Check if a PT_DYNAMIC segement was found
274 SysDebug(" elf_relocate: No PT_DYNAMIC segment in image %p, returning", Base);
275 return (void *)(intptr_t)(hdr->entrypoint + iBaseDiff);
278 // Allow writing to read-only segments, just in case they need to be relocated
279 // - Will be reversed at the end of the function
280 for( int i = 0; i < iSegmentCount; i ++ )
282 if(phtab[i].Type == PT_LOAD && !(phtab[i].Flags & PF_W) ) {
283 uintptr_t addr = phtab[i].VAddr + iBaseDiff;
284 uintptr_t end = addr + phtab[i].MemSize;
285 for( ; addr < end; addr += PAGE_SIZE )
286 _SysSetMemFlags(addr, 0, 1); // Unset RO
290 // Adjust Dynamic Table
291 dynamicTab = (void *)( (intptr_t)dynamicTab + iBaseDiff );
293 // === Get Symbol table and String Table ===
294 char *dynstrtab = NULL; // .dynamic String Table
295 Elf32_Sym *dynsymtab = NULL;
296 Elf32_Word *hashtable = NULL;
298 for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
300 const Elf32_Dyn *dt = &dynamicTab[j];
303 // --- Symbol Table ---
305 TRACE("DYNAMIC Symbol Table 0x%x (0x%x)", dt->d_val, dt->d_val + iBaseDiff);
306 dynsymtab = (void*)((intptr_t)dt->d_val + iBaseDiff);
308 // --- String Table ---
310 TRACE("DYNAMIC String Table 0x%x (0x%x)", dt->d_val, dt->d_val + iBaseDiff);
311 dynstrtab = (void*)((intptr_t)dt->d_val + iBaseDiff);
315 TRACE("DYNAMIC Hash table %p (%p)", dt->d_val, dt->d_val + iBaseDiff);
316 hashtable = (void*)((intptr_t)dt->d_val + iBaseDiff);
317 iSymCount = hashtable[1];
322 if(dynsymtab == NULL) {
323 SysDebug("ld-acess.so - WARNING: No Dynamic Symbol table in %p, returning", hdr);
324 return (void *)(intptr_t) (hdr->entrypoint + iBaseDiff);
327 // Apply base offset to locally defined symbols
328 // - #0 is defined as ("" SHN_UNDEF), so skip it
329 for( int i = 1; i < iSymCount; i ++ )
331 Elf32_Sym *sym = &dynsymtab[i];
332 const char *name = dynstrtab + sym->st_name;
334 if( sym->st_shndx == SHN_UNDEF )
336 TRACE("Sym %i'%s' deferred (SHN_UNDEF)", i, name);
338 else if( sym->st_shndx == SHN_ABS )
341 SysDebug("Sym %i'%s' untouched", i, name);
345 // TODO: What about weak locally-defined symbols?
346 if( ELF32_ST_BIND(sym->st_info) == STB_WEAK )
348 WARNING("TODO: Weak bound local symbols '%s'", name);
349 //assert(ELF32_ST_BIND(sym->st_info) != STB_WEAK);
352 TRACE("Sym %i'%s' %p += 0x%x", i, name, sym->st_value, iBaseDiff);
353 sym->st_value += iBaseDiff;
357 // === Add to loaded list (can be imported now) ===
358 AddLoaded( Filename, Base );
360 // === Parse Relocation Data ===
361 TRACE("dynamicTab = 0x%x", dynamicTab);
362 for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
364 const Elf32_Dyn *dt = &dynamicTab[j];
367 // --- Shared Library Name ---
369 TRACE(".so Name '%s'", dynstrtab + dt->d_val);
371 // --- Needed Library ---
373 //assert(dt->d_val <= sizeof_dynstrtab);
374 libPath = dynstrtab + dt->d_val;
375 TRACE(" Required Library '%s'", libPath);
376 if(LoadLibrary(libPath, NULL, envp) == 0) {
377 SysDebug("Unable to load required library '%s'", libPath);
380 TRACE(" Lib loaded");
383 // case DT_PLTGOT: pltgot = (void*)(iBaseDiff + dt->d_val); break;
384 case DT_JMPREL: plt = (void*)(iBaseDiff + dt->d_val); break;
385 case DT_PLTREL: pltType = dt->d_val; break;
386 case DT_PLTRELSZ: pltSz = dt->d_val; break;
388 // --- Relocation ---
389 case DT_REL: rel = (void*)(iBaseDiff + dt->d_val); break;
390 case DT_RELSZ: relSz = dt->d_val; break;
391 case DT_RELENT: relEntSz = dt->d_val; break;
392 case DT_RELA: rela = (void*)(iBaseDiff + dt->d_val); break;
393 case DT_RELASZ: relaSz = dt->d_val; break;
394 case DT_RELAENT: relaEntSz = dt->d_val; break;
396 // --- Symbol Table ---
398 // --- Hash Table ---
400 // --- String Table ---
406 if(dt->d_tag > DT_JMPREL) continue;
407 //DEBUGS(" elf_relocate: %i-%i = %s,0x%x",
408 // i,j, csaDT_NAMES[dynamicTab[j].d_tag],dynamicTab[j].d_val);
413 // Resolve symbols (second pass)
414 // - #0 is defined as ("" SHN_UNDEF), so skip it
416 for( int i = 1; i < iSymCount; i ++ )
418 Elf32_Sym *sym = &dynsymtab[i];
419 const char *name = dynstrtab + sym->st_name;
420 if( sym->st_shndx == SHN_UNDEF )
424 if( !GetSymbol(name, &newval, &newsize, Base) ) {
425 if( ELF32_ST_BIND(sym->st_info) != STB_WEAK ) {
426 // Not a weak binding, set fail and move on
427 WARNING("Elf32Relocate: Can't find required symbol '%s' for '%s'",
432 // Leave the symbol value as-is
435 TRACE("Sym %i'%s' bound to %p+0x%x", i, name, newval, newsize);
436 sym->st_value = (intptr_t)newval;
437 sym->st_size = newsize;
440 else if( sym->st_shndx == SHN_ABS )
446 // Handled previously
447 // TODO: What about weak locally-defined symbols?
448 //assert( ELF32_ST_BIND(sym->st_info) != STB_WEAK );
452 WARNING("Relocation of '%s' failed", Filename);
456 TRACE("Beginning Relocation on '%s'", Filename);
459 tElf32RelocFcn *do_relocate;
463 do_relocate = elf_doRelocate_386;
466 do_relocate = elf_doRelocate_arm;
469 SysDebug("Elf32Relocate: Unknown machine type %i", hdr->machine);
470 do_relocate = elf_doRelocate_unk;
475 TRACE("do_relocate = %p (%p or %p)", do_relocate, &elf_doRelocate_386, &elf_doRelocate_arm);
477 #define _doRelocate(r_info, ptr, bRela, addend) \
478 do_relocate(&reloc_info, r_info, ptr, addend, bRela);
480 tElfRelocInfo reloc_info = {
482 .iBaseDiff = iBaseDiff,
487 // Parse Relocation Entries
491 TRACE("rel=0x%x, relSz=0x%x, relEntSz=0x%x", rel, relSz, relEntSz);
492 int max = relSz / relEntSz;
493 for( int i = 0; i < max; i++ )
495 ptr = (void*)(iBaseDiff + rel[i].r_offset);
496 fail |= _doRelocate(rel[i].r_info, ptr, 0, *ptr);
499 // Parse Relocation Entries
503 TRACE("rela=0x%x, relaSz=0x%x, relaEntSz=0x%x", rela, relaSz, relaEntSz);
504 int count = relaSz / relaEntSz;
505 for( int i = 0; i < count; i++ )
507 ptr = (void*)(iBaseDiff + rela[i].r_offset);
508 fail |= _doRelocate(rel[i].r_info, ptr, 1, rela[i].r_addend);
512 // === Process PLT (Procedure Linkage Table) ===
516 TRACE("Relocate PLT, plt=0x%x", plt);
517 if(pltType == DT_REL)
519 Elf32_Rel *pltRel = plt;
520 int count = pltSz / sizeof(Elf32_Rel);
521 TRACE("PLT Reloc Type = Rel, %i entries", count);
522 for(int i = 0; i < count; i ++)
524 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
525 fail |= _doRelocate(pltRel[i].r_info, ptr, 0, *ptr);
530 Elf32_Rela *pltRela = plt;
531 int count = pltSz / sizeof(Elf32_Rela);
532 TRACE("PLT Reloc Type = Rela, %i entries", count);
533 for(int i=0;i<count;i++)
535 ptr = (void*)(iRealBase + pltRela[i].r_offset);
536 fail |= _doRelocate(pltRela[i].r_info, ptr, 1, pltRela[i].r_addend);
542 for( int i = 0; i < iSegmentCount; i ++ )
544 // If load and not writable
545 if(phtab[i].Type == PT_LOAD && !(phtab[i].Flags & PF_W) ) {
546 uintptr_t addr = phtab[i].VAddr + iBaseDiff;
547 uintptr_t end = addr + phtab[i].MemSize;
548 for( ; addr < end; addr += PAGE_SIZE )
549 _SysSetMemFlags(addr, 1, 1); // Unset RO
554 TRACE("ElfRelocate: Failure");
560 TRACE("RETURN 0x%x to %p", hdr->entrypoint + iBaseDiff, __builtin_return_address(0));
561 return (void*)(intptr_t)( hdr->entrypoint + iBaseDiff );
564 int Elf32GetSymbolVars(void *Base, Elf32_Sym** symtab, Elf32_Word** pBuckets, const char **dynstrtab, uintptr_t* piBaseDiff)
566 Elf32_Dyn *dynTab = NULL;
567 uintptr_t iBaseDiff = -1;
568 Elf32_Ehdr *hdr = Base;
569 Elf32_Phdr *phtab = (void*)( (uintptr_t)Base + hdr->phoff );
570 for( int i = 0; i < hdr->phentcount; i ++ )
572 if(phtab[i].Type == PT_LOAD && iBaseDiff > phtab[i].VAddr)
573 iBaseDiff = phtab[i].VAddr;
574 if( phtab[i].Type == PT_DYNAMIC ) {
575 dynTab = (void*)(intptr_t)phtab[i].VAddr;
579 SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
582 iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
583 dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
584 for( int i = 0; dynTab[i].d_tag != DT_NULL; i++)
586 switch(dynTab[i].d_tag)
588 // --- Symbol Table ---
590 *symtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); // Rebased in Relocate
593 *dynstrtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff);
597 *pBuckets = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff);
603 SysDebug("ERRO - No DT_SYMTAB in %p", Base);
607 SysDebug("ERRO - No DT_HASH in %p", Base);
611 SysDebug("ERRO - No DT_STRTAB in %p", Base);
615 // ... ok... maybe they haven't been relocated
616 if( (uintptr_t)*symtab < (uintptr_t)Base )
618 SysDebug("Executable not yet relocated (symtab,pBuckets,dynstrtab = %p,%p,%p + 0x%x)",
619 *symtab,*pBuckets,*dynstrtab, iBaseDiff);
620 *symtab = (void*)( (uintptr_t)*symtab + iBaseDiff );
621 *pBuckets = (void*)( (uintptr_t)*pBuckets + iBaseDiff );
622 *dynstrtab = (void*)( (uintptr_t)*dynstrtab + iBaseDiff );
624 *piBaseDiff = iBaseDiff;
628 int Elf32GetSymbolInfo(void *Base, const char *Name, void **Addr, size_t *Size, int* Section, int *Binding, int *Type)
631 uintptr_t iBaseDiff = -1;
632 Elf32_Sym *symtab = NULL;
633 Elf32_Word *pBuckets = NULL;
634 const char *dynstrtab = NULL;
635 if( Elf32GetSymbolVars(Base, &symtab, &pBuckets, &dynstrtab, &iBaseDiff) )
638 int nbuckets = pBuckets[0];
639 // int iSymCount = pBuckets[1];
640 pBuckets = &pBuckets[2];
641 Elf32_Word* pChains = &pBuckets[ nbuckets ];
645 int iNameHash = ElfHashString(Name);
646 iNameHash %= nbuckets;
649 int idx = pBuckets[ iNameHash ];
651 const Elf32_Sym *sym = &symtab[idx];
653 if( strcmp(dynstrtab + sym->st_name, Name) == 0 )
655 TRACE("*sym = {value:0x%x,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
656 sym->st_value, sym->st_size, sym->st_info,
657 sym->st_other, sym->st_shndx);
658 if(Addr) *Addr = (void*)( sym->st_value );
659 if(Size) *Size = sym->st_size;
660 if(Binding) *Binding = ELF32_ST_BIND(sym->st_info);
661 if(Type) *Type = ELF32_ST_TYPE(sym->st_info);
662 if(Section) *Section = sym->st_shndx;
665 } while( (idx = pChains[idx]) != STN_UNDEF && idx != pBuckets[iNameHash] );
671 int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
674 TRACE("Elf32GetSymbol(%p,%s,...)", Base, Name);
675 if( Elf32GetSymbolInfo(Base, Name, ret, Size, §ion, NULL, NULL) )
677 if( section == SHN_UNDEF ) {
678 TRACE("Elf32GetSymbol: Undefined", *ret, (Size?*Size:0), section);
681 TRACE("Elf32GetSymbol: Found %p+0x%x,section=%i", *ret, (Size?*Size:0), section);
686 typedef int (*t_elf64_doreloc)(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend);
688 int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend)
690 int sym = ELF64_R_SYM(r_info);
691 int type = ELF64_R_TYPE(r_info);
692 const char *symname = strtab + symtab[sym].st_name;
694 //DEBUGS("_Elf64DoReloc: %s", symname);
700 if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
701 *(uint64_t*)ptr = (uintptr_t)symval + addend;
703 case R_X86_64_COPY: {
705 if( !GetSymbol(symname, &symval, &size, NULL) ) return 1;
706 memcpy(ptr, symval, size);
708 case R_X86_64_GLOB_DAT:
709 if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
710 *(uint64_t*)ptr = (uintptr_t)symval;
712 case R_X86_64_JUMP_SLOT:
713 if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
714 *(uint64_t*)ptr = (uintptr_t)symval;
716 case R_X86_64_RELATIVE:
717 *(uint64_t*)ptr = (uintptr_t)Base + addend;
720 SysDebug("ld-acess - _Elf64DoReloc: Unknown relocation type %i", type);
723 //DEBUGS("_Elf64DoReloc: - Good");
727 void *Elf64Relocate(void *Base, char **envp, const char *Filename)
730 Elf64_Ehdr *hdr = Base;
732 Elf64_Dyn *dyntab = NULL;
733 Elf64_Addr compiledBase = -1, baseDiff;
734 Elf64_Sym *symtab = NULL;
736 Elf64_Word *hashtab = NULL;
737 Elf64_Rel *rel = NULL;
739 Elf64_Rela *rela = NULL;
742 int plt_size = 0, plt_type = 0;
745 TRACE(" e_ident = '%.16s'", hdr->e_ident);
746 TRACE(" e_type = 0x%x", hdr->e_type);
747 TRACE(" e_machine = 0x%x", hdr->e_machine);
748 TRACE(" e_version = 0x%x", hdr->e_version);
749 TRACE(" e_entry = %p", hdr->e_entry);
750 TRACE(" e_phoff = 0x%llx", hdr->e_phoff);
751 TRACE(" e_shoff = 0x%llx", hdr->e_shoff);
752 TRACE(" e_flags = 0x%x", hdr->e_flags);
753 TRACE(" e_ehsize = 0x%x", hdr->e_ehsize);
754 TRACE(" e_phentsize = 0x%x", hdr->e_phentsize);
755 TRACE(" e_phnum = %i", hdr->e_phnum);
757 // Scan for the dynamic table (and find the compiled base)
758 phtab = (void*)((uintptr_t)Base + (uintptr_t)hdr->e_phoff);
759 for( i = 0; i < hdr->e_phnum; i ++ )
761 if(phtab[i].p_type == PT_DYNAMIC)
762 dyntab = (void *)(intptr_t)phtab[i].p_vaddr;
763 if(phtab[i].p_type == PT_LOAD && compiledBase > phtab[i].p_vaddr)
764 compiledBase = phtab[i].p_vaddr;
767 baseDiff = (uintptr_t)Base - compiledBase;
769 TRACE("baseDiff = %p", baseDiff);
772 SysDebug(" Elf64Relocate: No PT_DYNAMIC segment in image %p, returning", Base);
773 return (void *)(uintptr_t)(hdr->e_entry + baseDiff);
776 dyntab = (void *)(uintptr_t)((uintptr_t)dyntab + baseDiff);
778 // Parse the dynamic table (first pass)
779 // - Search for String, Symbol and Hash tables
780 for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
782 switch(dyntab[i].d_tag)
785 dyntab[i].d_un.d_ptr += baseDiff;
786 symtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
789 dyntab[i].d_un.d_ptr += baseDiff;
790 strtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
793 dyntab[i].d_un.d_ptr += baseDiff;
794 hashtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
799 if( !symtab || !strtab || !hashtab ) {
800 SysDebug("ld-acess - Elf64Relocate: Missing Symbol, string or hash table");
804 // Ready for symbol use
805 AddLoaded( Filename, Base );
807 // Second pass on dynamic table
808 for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
810 TRACE("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag);
811 switch(dyntab[i].d_tag)
813 case DT_SONAME: break;
816 char *libPath = strtab + dyntab[i].d_un.d_val;
817 TRACE("Elf64Relocate: libPath = '%s'", libPath);
818 if(LoadLibrary(libPath, NULL, envp) == 0) {
819 SysDebug("ld-acess - Elf64Relocate: Unable to load '%s'", libPath);
824 // Relocation entries
826 dyntab[i].d_un.d_ptr += baseDiff;
827 rel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
830 rel_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rel);
833 if( dyntab[i].d_un.d_val != sizeof(Elf64_Rel) ) {
834 SysDebug("ld-acess - Elf64Relocate: DT_RELENT(%i) != sizeof(Elf64_Rel)(%i)",
835 dyntab[i].d_un.d_val, sizeof(Elf64_Rel));
840 dyntab[i].d_un.d_ptr += baseDiff;
841 rela = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
844 rela_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rela);
847 if( dyntab[i].d_un.d_val != sizeof(Elf64_Rela) ) {
848 SysDebug("ld-acess - Elf64Relocate: DT_RELAENT(%i) != sizeof(Elf64_Rela)(%i)",
849 dyntab[i].d_un.d_val, sizeof(Elf64_Rela));
854 dyntab[i].d_un.d_ptr += baseDiff;
855 pltrel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
858 plt_type = dyntab[i].d_un.d_val;
861 plt_size = dyntab[i].d_un.d_val;
866 // TODO: Relocate symbols
868 // Relocation function
869 t_elf64_doreloc fpElf64DoReloc = &_Elf64DoReloc_X86_64;
870 #define _Elf64DoReloc(info, ptr, addend) fpElf64DoReloc(Base, strtab, symtab, info, ptr, addend)
875 TRACE("rel_count = %i", rel_count);
876 for( i = 0; i < rel_count; i ++ )
878 uint64_t *ptr = (void *)(uintptr_t)( rel[i].r_offset + baseDiff );
879 fail |= _Elf64DoReloc( rel[i].r_info, ptr, *ptr);
885 TRACE("rela_count = %i", rela_count);
886 for( i = 0; i < rela_count; i ++ )
888 uint64_t *ptr = (void *)(uintptr_t)( rela[i].r_offset + baseDiff );
889 fail |= _Elf64DoReloc( rela[i].r_info, ptr, rela[i].r_addend );
893 if( pltrel && plt_type )
895 if( plt_type == DT_REL ) {
896 Elf64_Rel *plt = pltrel;
897 int count = plt_size / sizeof(Elf64_Rel);
898 TRACE("plt rel count = %i", count);
899 for( i = 0; i < count; i ++ )
901 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
902 fail |= _Elf64DoReloc( plt[i].r_info, ptr, *ptr);
906 Elf64_Rela *plt = pltrel;
907 int count = plt_size / sizeof(Elf64_Rela);
908 TRACE("plt rela count = %i", count);
909 for( i = 0; i < count; i ++ )
911 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
912 fail |= _Elf64DoReloc( plt[i].r_info, ptr, plt[i].r_addend);
923 void *ret = (void *)(uintptr_t)(hdr->e_entry + baseDiff);
924 TRACE("Relocations done, return %p", ret);
929 int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size)
931 Elf64_Ehdr *hdr = Base;
934 // int iSymCount = 0;
936 Elf64_Word *pBuckets;
939 const char *dynstrtab;
940 uintptr_t iBaseDiff = -1;
946 // Catch the current executable
950 Elf64_Dyn *dynTab = NULL;
954 phtab = (void*)( (intptr_t)Base + (uintptr_t)hdr->e_phoff );
955 for( i = 0; i < hdr->e_phnum; i ++ )
957 if(phtab[i].p_type == PT_LOAD && iBaseDiff > phtab[i].p_vaddr)
958 iBaseDiff = phtab[i].p_vaddr;
959 if( phtab[i].p_type == PT_DYNAMIC ) {
960 dynTab = (void*)(intptr_t)phtab[i].p_vaddr;
964 SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
967 iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
968 dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
970 for( j = 0; dynTab[j].d_tag != DT_NULL; j++)
972 switch(dynTab[j].d_tag)
974 // --- Symbol Table ---
976 symtab = (void*)(intptr_t) dynTab[j].d_un.d_val; // Rebased in Relocate
979 dynstrtab = (void*)(intptr_t) dynTab[j].d_un.d_val;
983 pBuckets = (void*)(intptr_t) dynTab[j].d_un.d_val;
989 nbuckets = pBuckets[0];
990 // iSymCount = pBuckets[1];
991 pBuckets = &pBuckets[2];
992 pChains = &pBuckets[ nbuckets ];
995 iNameHash = ElfHashString(Name);
996 iNameHash %= nbuckets;
999 i = pBuckets[ iNameHash ];
1000 if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
1001 *Ret = (void*)( (intptr_t)symtab[i].st_value + iBaseDiff );
1002 if(Size) *Size = symtab[i].st_size;
1003 TRACE("%s = %p", Name, *Ret);
1007 while(pChains[i] != STN_UNDEF)
1010 if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
1011 *Ret = (void*)((intptr_t)symtab[i].st_value + iBaseDiff);
1012 if(Size) *Size = symtab[i].st_size;
1013 TRACE("%s = %p", Name, *Ret);
1022 uint32_t ElfHashString(const char *name)
1027 h = (h << 4) + *(uint8_t*)name++;
1028 if( (g = h & 0xf0000000) )