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 )
156 if( ELF32_ST_BIND(sym->st_info) != STB_WEAK )
158 WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
159 sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx);
160 WARNING("Can't find required external symbol '%s' for R_386_COPY", Info->strtab + sym->st_name);
163 // Don't bother doing the memcpy
164 TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
168 TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
169 memcpy(ptr, symval, size);
174 WARNING("Unknown relocation %i", ELF32_ST_TYPE(r_info));
180 int elf_doRelocate_arm(tElfRelocInfo *Info, uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int bRela)
182 const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
183 void *symval = (void*)sym->st_value;
184 size_t size = sym->st_size;
185 TRACE("%i '%s'", ELF32_R_TYPE(r_info), Info->strtab + sym->st_name);
186 uintptr_t val = (uintptr_t)symval;
187 switch( ELF32_R_TYPE(r_info) )
191 TRACE("R_ARM_ABS32 %p (%p + %x)", ptr, symval, addend);
195 TRACE("R_ARM_GLOB_DAT %p (%p + %x)", ptr, symval, addend);
198 case R_ARM_JUMP_SLOT:
199 if(!bRela) addend = 0;
200 TRACE("R_ARM_JUMP_SLOT %p (%p + %x)", ptr, symval, addend);
205 TRACE("R_ARM_COPY (%p, %p, %i)", ptr, symval, size);
206 memcpy(ptr, symval, size);
208 // Delta between link and runtime locations + A
210 TRACE("R_ARM_RELATIVE %p (0x%x + 0x%x)", ptr, Info->iBaseDiff, addend);
211 if(ELF32_R_SYM(r_info) != 0) {
212 // TODO: Get delta for a symbol
213 WARNING("TODO - Implment R_ARM_RELATIVE for symbols");
217 *ptr = Info->iBaseDiff + addend;
221 WARNING("Unknown Relocation, %i", ELF32_R_TYPE(r_info));
227 int elf_doRelocate_unk(tElfRelocInfo *Info, uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int bRela)
232 void *Elf32Relocate(void *Base, char **envp, const char *Filename)
234 const Elf32_Ehdr *hdr = Base;
236 intptr_t iRealBase = -1;
238 Elf32_Rel *rel = NULL;
239 Elf32_Rela *rela = NULL;
241 int relSz=0, relEntSz=8;
242 int relaSz=0, relaEntSz=8;
243 int pltSz=0, pltType=0;
244 Elf32_Dyn *dynamicTab = NULL; // Dynamic Table Pointer
246 TRACE("(Base=0x%x)", Base);
248 // Check magic header
251 // Parse Program Header to get Dynamic Table
252 // - Determine the linked base of the executable
253 const Elf32_Phdr *phtab = (void*)( (uintptr_t)Base + hdr->phoff );
254 const int iSegmentCount = hdr->phentcount;
255 for(int i = 0; i < iSegmentCount; i ++)
257 switch(phtab[i].Type)
260 // Determine linked base address
261 if( iRealBase > phtab[i].VAddr)
262 iRealBase = phtab[i].VAddr;
265 // Find Dynamic Section
267 dynamicTab = (void *) (intptr_t) phtab[i].VAddr;
270 WARNING("elf_relocate: Multiple PT_DYNAMIC segments");
276 // Page Align real base
278 TRACE("True Base = 0x%x, Compiled Base = 0x%x", Base, iRealBase);
280 // Adjust "Real" Base
281 iBaseDiff = (intptr_t)Base - iRealBase;
283 // Check if a PT_DYNAMIC segement was found
285 SysDebug(" elf_relocate: No PT_DYNAMIC segment in image %p, returning", Base);
286 return (void *)(intptr_t)(hdr->entrypoint + iBaseDiff);
289 // Allow writing to read-only segments, just in case they need to be relocated
290 // - Will be reversed at the end of the function
291 for( int i = 0; i < iSegmentCount; i ++ )
293 if(phtab[i].Type == PT_LOAD && !(phtab[i].Flags & PF_W) ) {
294 uintptr_t addr = phtab[i].VAddr + iBaseDiff;
295 uintptr_t end = addr + phtab[i].MemSize;
296 for( ; addr < end; addr += PAGE_SIZE )
297 _SysSetMemFlags(addr, 0, 1); // Unset RO
301 // Adjust Dynamic Table
302 dynamicTab = (void *)( (intptr_t)dynamicTab + iBaseDiff );
304 // === Get Symbol table and String Table ===
305 char *dynstrtab = NULL; // .dynamic String Table
306 Elf32_Sym *dynsymtab = NULL;
307 Elf32_Word *hashtable = NULL;
309 for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
311 const Elf32_Dyn *dt = &dynamicTab[j];
314 // --- Symbol Table ---
316 TRACE("DYNAMIC Symbol Table 0x%x (0x%x)", dt->d_val, dt->d_val + iBaseDiff);
317 dynsymtab = (void*)((intptr_t)dt->d_val + iBaseDiff);
319 // --- String Table ---
321 TRACE("DYNAMIC String Table 0x%x (0x%x)", dt->d_val, dt->d_val + iBaseDiff);
322 dynstrtab = (void*)((intptr_t)dt->d_val + iBaseDiff);
326 TRACE("DYNAMIC Hash table %p (%p)", dt->d_val, dt->d_val + iBaseDiff);
327 hashtable = (void*)((intptr_t)dt->d_val + iBaseDiff);
328 iSymCount = hashtable[1];
333 if(dynsymtab == NULL) {
334 SysDebug("ld-acess.so - WARNING: No Dynamic Symbol table in %p, returning", hdr);
335 return (void *)(intptr_t) (hdr->entrypoint + iBaseDiff);
338 // Apply base offset to locally defined symbols
339 // - #0 is defined as ("" SHN_UNDEF), so skip it
340 for( int i = 1; i < iSymCount; i ++ )
342 Elf32_Sym *sym = &dynsymtab[i];
343 const char *name = dynstrtab + sym->st_name;
345 if( sym->st_shndx == SHN_UNDEF )
347 TRACE("Sym %i'%s' deferred (SHN_UNDEF)", i, name);
349 else if( sym->st_shndx == SHN_ABS )
352 SysDebug("Sym %i'%s' untouched", i, name);
358 if( ELF32_ST_BIND(sym->st_info) != STB_WEAK )
360 TRACE("Sym %i'%s' %p += 0x%x", i, name, sym->st_value, iBaseDiff);
361 sym->st_value += iBaseDiff;
363 else if( !GetSymbol(name, &newval, &newsize, Base) )
365 TRACE("Sym %i'%s' %p += 0x%x (Local weak)", i, name, sym->st_value, iBaseDiff);
366 sym->st_value += iBaseDiff;
370 TRACE("Sym %i'%s' %p = %p+0x%x (Extern weak)", i, name, newval, newsize);
371 sym->st_value = (uintptr_t)newval;
372 sym->st_size = newsize;
377 // === Add to loaded list (can be imported now) ===
378 AddLoaded( Filename, Base );
380 // === Parse Relocation Data ===
381 TRACE("dynamicTab = 0x%x", dynamicTab);
382 for( int j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
384 const Elf32_Dyn *dt = &dynamicTab[j];
387 // --- Shared Library Name ---
389 TRACE(".so Name '%s'", dynstrtab + dt->d_val);
391 // --- Needed Library ---
393 //assert(dt->d_val <= sizeof_dynstrtab);
394 libPath = dynstrtab + dt->d_val;
395 TRACE(" Required Library '%s'", libPath);
396 if(LoadLibrary(libPath, NULL, envp) == 0) {
397 SysDebug("Unable to load required library '%s'", libPath);
400 TRACE(" Lib loaded");
403 // case DT_PLTGOT: pltgot = (void*)(iBaseDiff + dt->d_val); break;
404 case DT_JMPREL: plt = (void*)(iBaseDiff + dt->d_val); break;
405 case DT_PLTREL: pltType = dt->d_val; break;
406 case DT_PLTRELSZ: pltSz = dt->d_val; break;
408 // --- Relocation ---
409 case DT_REL: rel = (void*)(iBaseDiff + dt->d_val); break;
410 case DT_RELSZ: relSz = dt->d_val; break;
411 case DT_RELENT: relEntSz = dt->d_val; break;
412 case DT_RELA: rela = (void*)(iBaseDiff + dt->d_val); break;
413 case DT_RELASZ: relaSz = dt->d_val; break;
414 case DT_RELAENT: relaEntSz = dt->d_val; break;
416 // --- Symbol Table ---
418 // --- Hash Table ---
420 // --- String Table ---
426 if(dt->d_tag > DT_JMPREL) continue;
427 //DEBUGS(" elf_relocate: %i-%i = %s,0x%x",
428 // i,j, csaDT_NAMES[dynamicTab[j].d_tag],dynamicTab[j].d_val);
433 // Resolve symbols (second pass)
434 // - #0 is defined as ("" SHN_UNDEF), so skip it
436 for( int i = 1; i < iSymCount; i ++ )
438 Elf32_Sym *sym = &dynsymtab[i];
439 const char *name = dynstrtab + sym->st_name;
440 if( sym->st_shndx == SHN_UNDEF )
444 if( !GetSymbol(name, &newval, &newsize, Base) ) {
445 if( ELF32_ST_BIND(sym->st_info) != STB_WEAK ) {
446 // Not a weak binding, set fail and move on
447 WARNING("Elf32Relocate: Can't find required symbol '%s' for '%s'",
452 // Leave the symbol value as-is
455 TRACE("Sym %i'%s' bound to %p+0x%x", i, name, newval, newsize);
456 sym->st_value = (intptr_t)newval;
457 sym->st_size = newsize;
460 else if( sym->st_shndx == SHN_ABS )
466 // Handled previously
467 // TODO: What about weak locally-defined symbols?
468 //assert( ELF32_ST_BIND(sym->st_info) != STB_WEAK );
472 WARNING("Relocation of '%s' failed", Filename);
476 TRACE("Beginning Relocation on '%s'", Filename);
479 tElf32RelocFcn *do_relocate;
483 do_relocate = elf_doRelocate_386;
486 do_relocate = elf_doRelocate_arm;
489 SysDebug("Elf32Relocate: Unknown machine type %i", hdr->machine);
490 do_relocate = elf_doRelocate_unk;
495 TRACE("do_relocate = %p (%p or %p)", do_relocate, &elf_doRelocate_386, &elf_doRelocate_arm);
497 #define _doRelocate(r_info, ptr, bRela, addend) \
498 do_relocate(&reloc_info, r_info, ptr, addend, bRela);
500 tElfRelocInfo reloc_info = {
502 .iBaseDiff = iBaseDiff,
507 // Parse Relocation Entries
511 TRACE("rel=0x%x, relSz=0x%x, relEntSz=0x%x", rel, relSz, relEntSz);
512 int max = relSz / relEntSz;
513 for( int i = 0; i < max; i++ )
515 ptr = (void*)(iBaseDiff + rel[i].r_offset);
516 fail |= _doRelocate(rel[i].r_info, ptr, 0, *ptr);
519 // Parse Relocation Entries
523 TRACE("rela=0x%x, relaSz=0x%x, relaEntSz=0x%x", rela, relaSz, relaEntSz);
524 int count = relaSz / relaEntSz;
525 for( int i = 0; i < count; i++ )
527 ptr = (void*)(iBaseDiff + rela[i].r_offset);
528 fail |= _doRelocate(rel[i].r_info, ptr, 1, rela[i].r_addend);
532 // === Process PLT (Procedure Linkage Table) ===
536 TRACE("Relocate PLT, plt=0x%x", plt);
537 if(pltType == DT_REL)
539 Elf32_Rel *pltRel = plt;
540 int count = pltSz / sizeof(Elf32_Rel);
541 TRACE("PLT Reloc Type = Rel, %i entries", count);
542 for(int i = 0; i < count; i ++)
544 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
545 fail |= _doRelocate(pltRel[i].r_info, ptr, 0, *ptr);
550 Elf32_Rela *pltRela = plt;
551 int count = pltSz / sizeof(Elf32_Rela);
552 TRACE("PLT Reloc Type = Rela, %i entries", count);
553 for(int i=0;i<count;i++)
555 ptr = (void*)(iRealBase + pltRela[i].r_offset);
556 fail |= _doRelocate(pltRela[i].r_info, ptr, 1, pltRela[i].r_addend);
562 for( int i = 0; i < iSegmentCount; i ++ )
564 // If load and not writable
565 if(phtab[i].Type == PT_LOAD && !(phtab[i].Flags & PF_W) ) {
566 uintptr_t addr = phtab[i].VAddr + iBaseDiff;
567 uintptr_t end = addr + phtab[i].MemSize;
568 for( ; addr < end; addr += PAGE_SIZE )
569 _SysSetMemFlags(addr, 1, 1); // Unset RO
574 TRACE("ElfRelocate: Failure");
580 TRACE("RETURN 0x%x to %p", hdr->entrypoint + iBaseDiff, __builtin_return_address(0));
581 return (void*)(intptr_t)( hdr->entrypoint + iBaseDiff );
584 int Elf32GetSymbolVars(void *Base, Elf32_Sym** symtab, Elf32_Word** pBuckets, const char **dynstrtab, uintptr_t* piBaseDiff)
586 Elf32_Dyn *dynTab = NULL;
587 uintptr_t iBaseDiff = -1;
588 Elf32_Ehdr *hdr = Base;
589 Elf32_Phdr *phtab = (void*)( (uintptr_t)Base + hdr->phoff );
590 for( int i = 0; i < hdr->phentcount; i ++ )
592 if(phtab[i].Type == PT_LOAD && iBaseDiff > phtab[i].VAddr)
593 iBaseDiff = phtab[i].VAddr;
594 if( phtab[i].Type == PT_DYNAMIC ) {
595 dynTab = (void*)(intptr_t)phtab[i].VAddr;
599 SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
602 iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
603 dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
604 for( int i = 0; dynTab[i].d_tag != DT_NULL; i++)
606 switch(dynTab[i].d_tag)
608 // --- Symbol Table ---
610 *symtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff); // Rebased in Relocate
613 *dynstrtab = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff);
617 *pBuckets = (void*)((intptr_t)dynTab[i].d_val + iBaseDiff);
623 SysDebug("ERRO - No DT_SYMTAB in %p", Base);
627 SysDebug("ERRO - No DT_HASH in %p", Base);
631 SysDebug("ERRO - No DT_STRTAB in %p", Base);
635 // ... ok... maybe they haven't been relocated
636 if( (uintptr_t)*symtab < (uintptr_t)Base )
638 SysDebug("Executable not yet relocated (symtab,pBuckets,dynstrtab = %p,%p,%p + 0x%x)",
639 *symtab,*pBuckets,*dynstrtab, iBaseDiff);
640 *symtab = (void*)( (uintptr_t)*symtab + iBaseDiff );
641 *pBuckets = (void*)( (uintptr_t)*pBuckets + iBaseDiff );
642 *dynstrtab = (void*)( (uintptr_t)*dynstrtab + iBaseDiff );
644 *piBaseDiff = iBaseDiff;
648 int Elf32GetSymbolInfo(void *Base, const char *Name, void **Addr, size_t *Size, int* Section, int *Binding, int *Type)
651 uintptr_t iBaseDiff = -1;
652 Elf32_Sym *symtab = NULL;
653 Elf32_Word *pBuckets = NULL;
654 const char *dynstrtab = NULL;
655 if( Elf32GetSymbolVars(Base, &symtab, &pBuckets, &dynstrtab, &iBaseDiff) )
658 int nbuckets = pBuckets[0];
659 // int iSymCount = pBuckets[1];
660 pBuckets = &pBuckets[2];
661 Elf32_Word* pChains = &pBuckets[ nbuckets ];
665 int iNameHash = ElfHashString(Name);
666 iNameHash %= nbuckets;
669 int idx = pBuckets[ iNameHash ];
671 const Elf32_Sym *sym = &symtab[idx];
673 if( strcmp(dynstrtab + sym->st_name, Name) == 0 )
675 TRACE("*sym = {value:0x%x,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
676 sym->st_value, sym->st_size, sym->st_info,
677 sym->st_other, sym->st_shndx);
678 if(Addr) *Addr = (void*)( sym->st_value );
679 if(Size) *Size = sym->st_size;
680 if(Binding) *Binding = ELF32_ST_BIND(sym->st_info);
681 if(Type) *Type = ELF32_ST_TYPE(sym->st_info);
682 if(Section) *Section = sym->st_shndx;
685 } while( (idx = pChains[idx]) != STN_UNDEF && idx != pBuckets[iNameHash] );
691 int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
694 TRACE("Elf32GetSymbol(%p,%s,...)", Base, Name);
695 if( Elf32GetSymbolInfo(Base, Name, ret, Size, §ion, NULL, NULL) )
697 if( section == SHN_UNDEF ) {
698 TRACE("Elf32GetSymbol: Undefined", *ret, (Size?*Size:0), section);
701 TRACE("Elf32GetSymbol: Found %p+0x%x,section=%i", *ret, (Size?*Size:0), section);
706 typedef int (*t_elf64_doreloc)(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend);
708 int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend)
710 int sym = ELF64_R_SYM(r_info);
711 int type = ELF64_R_TYPE(r_info);
712 const char *symname = strtab + symtab[sym].st_name;
714 //DEBUGS("_Elf64DoReloc: %s", symname);
720 if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
721 *(uint64_t*)ptr = (uintptr_t)symval + addend;
723 case R_X86_64_COPY: {
725 if( !GetSymbol(symname, &symval, &size, NULL) ) return 1;
726 memcpy(ptr, symval, size);
728 case R_X86_64_GLOB_DAT:
729 if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
730 *(uint64_t*)ptr = (uintptr_t)symval;
732 case R_X86_64_JUMP_SLOT:
733 if( !GetSymbol(symname, &symval, NULL, NULL) ) return 1;
734 *(uint64_t*)ptr = (uintptr_t)symval;
736 case R_X86_64_RELATIVE:
737 *(uint64_t*)ptr = (uintptr_t)Base + addend;
740 SysDebug("ld-acess - _Elf64DoReloc: Unknown relocation type %i", type);
743 //DEBUGS("_Elf64DoReloc: - Good");
747 void *Elf64Relocate(void *Base, char **envp, const char *Filename)
750 Elf64_Ehdr *hdr = Base;
752 Elf64_Dyn *dyntab = NULL;
753 Elf64_Addr compiledBase = -1, baseDiff;
754 Elf64_Sym *symtab = NULL;
756 Elf64_Word *hashtab = NULL;
757 Elf64_Rel *rel = NULL;
759 Elf64_Rela *rela = NULL;
762 int plt_size = 0, plt_type = 0;
765 TRACE(" e_ident = '%.16s'", hdr->e_ident);
766 TRACE(" e_type = 0x%x", hdr->e_type);
767 TRACE(" e_machine = 0x%x", hdr->e_machine);
768 TRACE(" e_version = 0x%x", hdr->e_version);
769 TRACE(" e_entry = %p", hdr->e_entry);
770 TRACE(" e_phoff = 0x%llx", hdr->e_phoff);
771 TRACE(" e_shoff = 0x%llx", hdr->e_shoff);
772 TRACE(" e_flags = 0x%x", hdr->e_flags);
773 TRACE(" e_ehsize = 0x%x", hdr->e_ehsize);
774 TRACE(" e_phentsize = 0x%x", hdr->e_phentsize);
775 TRACE(" e_phnum = %i", hdr->e_phnum);
777 // Scan for the dynamic table (and find the compiled base)
778 phtab = (void*)((uintptr_t)Base + (uintptr_t)hdr->e_phoff);
779 for( i = 0; i < hdr->e_phnum; i ++ )
781 if(phtab[i].p_type == PT_DYNAMIC)
782 dyntab = (void *)(intptr_t)phtab[i].p_vaddr;
783 if(phtab[i].p_type == PT_LOAD && compiledBase > phtab[i].p_vaddr)
784 compiledBase = phtab[i].p_vaddr;
787 baseDiff = (uintptr_t)Base - compiledBase;
789 TRACE("baseDiff = %p", baseDiff);
792 SysDebug(" Elf64Relocate: No PT_DYNAMIC segment in image %p, returning", Base);
793 return (void *)(uintptr_t)(hdr->e_entry + baseDiff);
796 dyntab = (void *)(uintptr_t)((uintptr_t)dyntab + baseDiff);
798 // Parse the dynamic table (first pass)
799 // - Search for String, Symbol and Hash tables
800 for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
802 switch(dyntab[i].d_tag)
805 dyntab[i].d_un.d_ptr += baseDiff;
806 symtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
809 dyntab[i].d_un.d_ptr += baseDiff;
810 strtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
813 dyntab[i].d_un.d_ptr += baseDiff;
814 hashtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
819 if( !symtab || !strtab || !hashtab ) {
820 SysDebug("ld-acess - Elf64Relocate: Missing Symbol, string or hash table");
824 // Ready for symbol use
825 AddLoaded( Filename, Base );
827 // Second pass on dynamic table
828 for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
830 TRACE("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag);
831 switch(dyntab[i].d_tag)
833 case DT_SONAME: break;
836 char *libPath = strtab + dyntab[i].d_un.d_val;
837 TRACE("Elf64Relocate: libPath = '%s'", libPath);
838 if(LoadLibrary(libPath, NULL, envp) == 0) {
839 SysDebug("ld-acess - Elf64Relocate: Unable to load '%s'", libPath);
844 // Relocation entries
846 dyntab[i].d_un.d_ptr += baseDiff;
847 rel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
850 rel_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rel);
853 if( dyntab[i].d_un.d_val != sizeof(Elf64_Rel) ) {
854 SysDebug("ld-acess - Elf64Relocate: DT_RELENT(%i) != sizeof(Elf64_Rel)(%i)",
855 dyntab[i].d_un.d_val, sizeof(Elf64_Rel));
860 dyntab[i].d_un.d_ptr += baseDiff;
861 rela = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
864 rela_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rela);
867 if( dyntab[i].d_un.d_val != sizeof(Elf64_Rela) ) {
868 SysDebug("ld-acess - Elf64Relocate: DT_RELAENT(%i) != sizeof(Elf64_Rela)(%i)",
869 dyntab[i].d_un.d_val, sizeof(Elf64_Rela));
874 dyntab[i].d_un.d_ptr += baseDiff;
875 pltrel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
878 plt_type = dyntab[i].d_un.d_val;
881 plt_size = dyntab[i].d_un.d_val;
886 // TODO: Relocate symbols
888 // Relocation function
889 t_elf64_doreloc fpElf64DoReloc = &_Elf64DoReloc_X86_64;
890 #define _Elf64DoReloc(info, ptr, addend) fpElf64DoReloc(Base, strtab, symtab, info, ptr, addend)
895 TRACE("rel_count = %i", rel_count);
896 for( i = 0; i < rel_count; i ++ )
898 uint64_t *ptr = (void *)(uintptr_t)( rel[i].r_offset + baseDiff );
899 fail |= _Elf64DoReloc( rel[i].r_info, ptr, *ptr);
905 TRACE("rela_count = %i", rela_count);
906 for( i = 0; i < rela_count; i ++ )
908 uint64_t *ptr = (void *)(uintptr_t)( rela[i].r_offset + baseDiff );
909 fail |= _Elf64DoReloc( rela[i].r_info, ptr, rela[i].r_addend );
913 if( pltrel && plt_type )
915 if( plt_type == DT_REL ) {
916 Elf64_Rel *plt = pltrel;
917 int count = plt_size / sizeof(Elf64_Rel);
918 TRACE("plt rel count = %i", count);
919 for( i = 0; i < count; i ++ )
921 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
922 fail |= _Elf64DoReloc( plt[i].r_info, ptr, *ptr);
926 Elf64_Rela *plt = pltrel;
927 int count = plt_size / sizeof(Elf64_Rela);
928 TRACE("plt rela count = %i", count);
929 for( i = 0; i < count; i ++ )
931 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
932 fail |= _Elf64DoReloc( plt[i].r_info, ptr, plt[i].r_addend);
943 void *ret = (void *)(uintptr_t)(hdr->e_entry + baseDiff);
944 TRACE("Relocations done, return %p", ret);
949 int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size)
951 Elf64_Ehdr *hdr = Base;
954 // int iSymCount = 0;
956 Elf64_Word *pBuckets;
959 const char *dynstrtab;
960 uintptr_t iBaseDiff = -1;
966 // Catch the current executable
970 Elf64_Dyn *dynTab = NULL;
974 phtab = (void*)( (intptr_t)Base + (uintptr_t)hdr->e_phoff );
975 for( i = 0; i < hdr->e_phnum; i ++ )
977 if(phtab[i].p_type == PT_LOAD && iBaseDiff > phtab[i].p_vaddr)
978 iBaseDiff = phtab[i].p_vaddr;
979 if( phtab[i].p_type == PT_DYNAMIC ) {
980 dynTab = (void*)(intptr_t)phtab[i].p_vaddr;
984 SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
987 iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
988 dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
990 for( j = 0; dynTab[j].d_tag != DT_NULL; j++)
992 switch(dynTab[j].d_tag)
994 // --- Symbol Table ---
996 symtab = (void*)(intptr_t) dynTab[j].d_un.d_val; // Rebased in Relocate
999 dynstrtab = (void*)(intptr_t) dynTab[j].d_un.d_val;
1001 // --- Hash Table --
1003 pBuckets = (void*)(intptr_t) dynTab[j].d_un.d_val;
1009 nbuckets = pBuckets[0];
1010 // iSymCount = pBuckets[1];
1011 pBuckets = &pBuckets[2];
1012 pChains = &pBuckets[ nbuckets ];
1015 iNameHash = ElfHashString(Name);
1016 iNameHash %= nbuckets;
1019 i = pBuckets[ iNameHash ];
1020 if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
1021 *Ret = (void*)( (intptr_t)symtab[i].st_value + iBaseDiff );
1022 if(Size) *Size = symtab[i].st_size;
1023 TRACE("%s = %p", Name, *Ret);
1027 while(pChains[i] != STN_UNDEF)
1030 if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
1031 *Ret = (void*)((intptr_t)symtab[i].st_value + iBaseDiff);
1032 if(Size) *Size = symtab[i].st_size;
1033 TRACE("%s = %p", Name, *Ret);
1042 uint32_t ElfHashString(const char *name)
1047 h = (h << 4) + *(uint8_t*)name++;
1048 if( (g = h & 0xf0000000) )