Common/ELF Loader - Debug fixes and detection for no-relocated binaries
[tpg/acess2.git] / Usermode / Libraries / ld-acess.so_src / elf.c
1 /*
2  * Acess2 Dynamic Linker
3  * - By John Hodge (thePowersGang)
4  *
5  * elf.c
6  * - ELF32/ELF64 relocation
7  */
8 #ifndef DEBUG   // This code is #include'd from the kernel, so DEBUG may already be defined
9 # define DEBUG  0
10 #endif
11
12 #include "common.h"
13 #include <stdint.h>
14 #include "elf32.h"
15 #include "elf64.h"
16
17 #if DEBUG
18 # define        DEBUGS(v...)    SysDebug("ld-acess - " v)
19 #else
20 # define        DEBUGS(...)     
21 #endif
22
23 #ifndef DISABLE_ELF64
24 # define SUPPORT_ELF64
25 #endif
26
27 // === CONSTANTS ===
28 #if DEBUG
29 //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"};
30 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"};
31 #endif
32
33 // === PROTOTYPES ===
34 void    *ElfRelocate(void *Base, char **envp, const char *Filename);
35  int    ElfGetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
36 void    *Elf32Relocate(void *Base, char **envp, const char *Filename);
37  int    Elf32GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
38 void    elf_doRelocate_386(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff);
39 void    elf_doRelocate_arm(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff);
40 #ifdef SUPPORT_ELF64
41 void    *Elf64Relocate(void *Base, char **envp, const char *Filename);
42  int    Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
43 #endif
44 uint32_t        ElfHashString(const char *name);
45
46 // === CODE ===
47 /**
48  * \fn int ElfRelocate(void *Base, char **envp, const char *Filename)
49  * \brief Relocates a loaded ELF Executable
50  */
51 void *ElfRelocate(void *Base, char **envp, const char *Filename)
52 {
53         Elf32_Ehdr      *hdr = Base;
54         
55         switch(hdr->e_ident[4])
56         {
57         case ELFCLASS32:
58                 return Elf32Relocate(Base, envp, Filename);
59 #ifdef SUPPORT_ELF64
60         case ELFCLASS64:
61                 return Elf64Relocate(Base, envp, Filename);
62 #endif
63         default:
64                 SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
65                 return NULL;
66         }
67 }
68
69 /**
70  * \fn int ElfGetSymbol(Uint Base, const char *name, void **ret)
71  */
72 int ElfGetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
73 {
74         Elf32_Ehdr      *hdr = Base;
75
76         switch(hdr->e_ident[4])
77         {
78         case ELFCLASS32:
79                 return Elf32GetSymbol(Base, Name, ret, Size);
80 #ifdef SUPPORT_ELF64
81         case ELFCLASS64:
82                 return Elf64GetSymbol(Base, Name, ret, Size);
83 #endif
84         default:
85                 SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
86                 return 0;
87         }
88 }
89
90 void elf_doRelocate_386(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff)
91 {
92         intptr_t        val;
93         switch( type )
94         {
95         // Standard 32 Bit Relocation (S+A)
96         case R_386_32:
97                 val = (intptr_t) GetSymbol(Sym, NULL);
98                 DEBUGS(" elf_doRelocate: R_386_32 *0x%x += 0x%x('%s')",
99                                 ptr, val, Sym);
100                 *ptr = val + addend;
101                 break;
102                 
103         // 32 Bit Relocation wrt. Offset (S+A-P)
104         case R_386_PC32:
105                 DEBUGS(" elf_doRelocate: '%s'", Sym);
106                 val = (intptr_t) GetSymbol(Sym, NULL);
107                 DEBUGS(" elf_doRelocate: R_386_PC32 *0x%x = 0x%x + 0x%x - 0x%x",
108                         ptr, *ptr, val, (intptr_t)ptr );
109                 *ptr = val + addend - (intptr_t)ptr;
110                 //*ptr = val + addend - ((Uint)ptr - iBaseDiff);
111                 break;
112
113         // Absolute Value of a symbol (S)
114         case R_386_GLOB_DAT:
115         case R_386_JMP_SLOT:
116                 DEBUGS(" elf_doRelocate: '%s'", Sym);
117                 val = (intptr_t) GetSymbol( Sym, NULL );
118                 DEBUGS(" elf_doRelocate: %s *0x%x = 0x%x", csaR_NAMES[type], ptr, val);
119                 *ptr = val;
120                 break;
121
122         // Base Address (B+A)
123         case R_386_RELATIVE:
124                 DEBUGS(" elf_doRelocate: R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, iBaseDiff, addend);
125                 *ptr = iBaseDiff + addend;
126                 break;
127
128         case R_386_COPY: {
129                 size_t  size;
130                 void    *src = GetSymbol(Sym, &size);
131                 DEBUGS(" elf_doRelocate_386: R_386_COPY (%p, %p, %i)", ptr, src, size);
132                 memcpy(ptr, src, size);
133                 break; }
134
135         default:
136                 SysDebug("elf_doRelocate_386: Unknown relocation %i", type);
137                 break;
138         }
139 }
140
141 void elf_doRelocate_arm(uint32_t r_info, uint32_t *ptr, Elf32_Addr addend, int type, int bRela, const char *Sym, intptr_t iBaseDiff)
142 {
143         uint32_t        val;
144         switch(type)
145         {
146         // (S + A) | T
147         case R_ARM_ABS32:
148                 DEBUGS(" elf_doRelocate_arm: R_ARM_ABS32 %p (%s + %x)", ptr, Sym, addend);
149                 val = (intptr_t)GetSymbol(Sym, NULL);
150                 *ptr = val + addend;
151                 break;
152         case R_ARM_GLOB_DAT:
153                 DEBUGS(" elf_doRelocate_arm: R_ARM_GLOB_DAT %p (%s + %x)", ptr, Sym, addend);
154                 val = (intptr_t)GetSymbol(Sym, NULL);
155                 *ptr = val + addend;
156                 break;
157         case R_ARM_JUMP_SLOT:
158                 if(!bRela)      addend = 0;
159                 DEBUGS(" elf_doRelocate_arm: R_ARM_JUMP_SLOT %p (%s + %x)", ptr, Sym, addend);
160                 val = (intptr_t)GetSymbol(Sym, NULL);
161                 *ptr = val + addend;
162                 break;
163         // Copy
164         case R_ARM_COPY: {
165                 size_t  size;
166                 void    *src = GetSymbol(Sym, &size);
167                 DEBUGS(" elf_doRelocate_arm: R_ARM_COPY (%p, %p, %i)", ptr, src, size);
168                 memcpy(ptr, src, size);
169                 break; }
170         // Delta between link and runtime locations + A
171         case R_ARM_RELATIVE:
172                 if(Sym[0] != '\0') {
173                         // TODO: Get delta for a symbol
174                         SysDebug("elf_doRelocate_arm: TODO - Implment R_ARM_RELATIVE for symbols");
175                 }
176                 else {
177                         *ptr = iBaseDiff + addend;
178                 }
179                 break;
180         default:
181                 SysDebug("elf_doRelocate_arm: Unknown Relocation, %i", type);
182                 break;
183         }
184 }
185
186 void *Elf32Relocate(void *Base, char **envp, const char *Filename)
187 {
188         Elf32_Ehdr      *hdr = Base;
189         Elf32_Phdr      *phtab;
190          int    i, j;   // Counters
191         char    *libPath;
192         intptr_t        iRealBase = -1;
193         intptr_t        iBaseDiff;
194          int    iSegmentCount;
195 //       int    iSymCount;
196         Elf32_Rel       *rel = NULL;
197         Elf32_Rela      *rela = NULL;
198         void    *plt = NULL;
199          int    relSz=0, relEntSz=8;
200          int    relaSz=0, relaEntSz=8;
201          int    pltSz=0, pltType=0;
202         Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer
203         char    *dynstrtab = NULL;      // .dynamic String Table
204         Elf32_Sym       *dynsymtab;
205         void    (*do_relocate)(uint32_t t_info, uint32_t *ptr, Elf32_Addr addend, int Type, int bRela, const char *Sym, intptr_t iBaseDiff);
206         auto void _doRelocate(uint32_t r_info, uint32_t *ptr, int bRela, Elf32_Addr addend);
207         
208         DEBUGS("ElfRelocate: (Base=0x%x)", Base);
209         
210         // Check magic header
211         
212         
213         // Parse Program Header to get Dynamic Table
214         phtab = (void*)( (uintptr_t)Base + hdr->phoff );
215         iSegmentCount = hdr->phentcount;
216         for(i=0;i<iSegmentCount;i++)
217         {
218                 // Determine linked base address
219                 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)
220                         iRealBase = phtab[i].VAddr;
221                 
222                 // Find Dynamic Section
223                 if(phtab[i].Type == PT_DYNAMIC) {
224                         if(dynamicTab) {
225                                 DEBUGS(" WARNING - elf_relocate: Multiple PT_DYNAMIC segments");
226                                 continue;
227                         }
228                         dynamicTab = (void *) (intptr_t) phtab[i].VAddr;
229                         j = i;  // Save Dynamic Table ID
230                 }
231         }
232         
233         // Page Align real base
234         iRealBase &= ~0xFFF;
235         DEBUGS(" elf_relocate: True Base = 0x%x, Compiled Base = 0x%x", Base, iRealBase);
236         
237         // Adjust "Real" Base
238         iBaseDiff = (intptr_t)Base - iRealBase;
239         
240 //      hdr->entrypoint += iBaseDiff;   // Adjust Entrypoint
241         
242         // Check if a PT_DYNAMIC segement was found
243         if(!dynamicTab) {
244                 SysDebug(" elf_relocate: No PT_DYNAMIC segment in image %p, returning", Base);
245                 return (void *)(intptr_t)(hdr->entrypoint + iBaseDiff);
246         }
247         
248         // Adjust Dynamic Table
249         dynamicTab = (void *)( (intptr_t)dynamicTab + iBaseDiff );
250         
251         // === Get Symbol table and String Table ===
252         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
253         {
254                 switch(dynamicTab[j].d_tag)
255                 {
256                 // --- Symbol Table ---
257                 case DT_SYMTAB:
258                         DEBUGS(" elf_relocate: DYNAMIC Symbol Table 0x%x (0x%x)",
259                                 dynamicTab[j].d_val, dynamicTab[j].d_val + iBaseDiff);
260                         if(iBaseDiff != 0)      dynamicTab[j].d_val += iBaseDiff;
261                         dynsymtab = (void*)(intptr_t)dynamicTab[j].d_val;
262                         break;
263                 // --- String Table ---
264                 case DT_STRTAB:
265                         DEBUGS(" elf_relocate: DYNAMIC String Table 0x%x (0x%x)",
266                                 dynamicTab[j].d_val, dynamicTab[j].d_val + iBaseDiff);
267                         if(iBaseDiff != 0)      dynamicTab[j].d_val += iBaseDiff;
268                         dynstrtab = (void*)(intptr_t)dynamicTab[j].d_val;
269                         break;
270                 // --- Hash Table --
271                 case DT_HASH:
272                         if(iBaseDiff != 0)      dynamicTab[j].d_val += iBaseDiff;
273 //                      iSymCount = ((Elf32_Word*)(intptr_t)dynamicTab[j].d_val)[1];
274                         break;
275                 }
276         }
277
278         if(dynsymtab == NULL) {
279                 SysDebug("ld-acess.so - WARNING: No Dynamic Symbol table in %p, returning", hdr);
280                 return (void *)(intptr_t) (hdr->entrypoint + iBaseDiff);
281         }
282
283         // === Add to loaded list (can be imported now) ===
284         AddLoaded( Filename, Base );
285
286         // === Parse Relocation Data ===
287         DEBUGS(" elf_relocate: dynamicTab = 0x%x", dynamicTab);
288         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
289         {
290                 switch(dynamicTab[j].d_tag)
291                 {
292                 // --- Shared Library Name ---
293                 case DT_SONAME:
294                         DEBUGS(" elf_relocate: .so Name '%s'", dynstrtab+dynamicTab[j].d_val);
295                         break;
296                 // --- Needed Library ---
297                 case DT_NEEDED:
298                         libPath = dynstrtab + dynamicTab[j].d_val;
299                         DEBUGS(" Required Library '%s'", libPath);
300                         if(LoadLibrary(libPath, NULL, envp) == 0) {
301                                 #if DEBUG
302                                 DEBUGS(" elf_relocate: Unable to load '%s'", libPath);
303                                 #else
304                                 SysDebug("Unable to load required library '%s'", libPath);
305                                 #endif
306                                 return 0;
307                         }
308                         DEBUGS(" Lib loaded");
309                         break;
310                 // --- PLT/GOT ---
311 //              case DT_PLTGOT: pltgot = (void*)(iBaseDiff + dynamicTab[j].d_val);      break;
312                 case DT_JMPREL: plt = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
313                 case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;
314                 case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;
315                 
316                 // --- Relocation ---
317                 case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
318                 case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;
319                 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;
320                 case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;
321                 case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;
322                 case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;
323                 
324                 // --- Symbol Table ---
325                 case DT_SYMTAB:
326                 // --- Hash Table ---
327                 case DT_HASH:
328                 // --- String Table ---
329                 case DT_STRTAB:
330                         break;
331                 
332                 // --- Unknown ---
333                 default:
334                         if(dynamicTab[j].d_tag > DT_JMPREL)     continue;
335                         //DEBUGS(" elf_relocate: %i-%i = %s,0x%x",
336                         //      i,j, csaDT_NAMES[dynamicTab[j].d_tag],dynamicTab[j].d_val);
337                         break;
338                 }
339         }
340         
341         DEBUGS(" elf_relocate: Beginning Relocation");
342
343         void _doRelocate(uint32_t r_info, uint32_t *ptr, int bRela, Elf32_Addr addend)
344         {
345                  int    type = ELF32_R_TYPE(r_info);
346                  int    sym = ELF32_R_SYM(r_info);
347                 const char      *symname = dynstrtab + dynsymtab[sym].nameOfs;
348                 do_relocate(r_info, ptr, addend, type, bRela, symname, iBaseDiff);
349         }
350
351         switch(hdr->machine)
352         {
353         case EM_386:
354                 do_relocate = elf_doRelocate_386;
355                 break;
356         case EM_ARM:
357                 do_relocate = elf_doRelocate_arm;
358                 break;
359         default:
360                 SysDebug("Elf32Relocate: Unknown machine type %i", hdr->machine);
361                 break;
362         }
363         
364         DEBUGS("do_relocate = %p (%p or %p)", do_relocate, &elf_doRelocate_386, &elf_doRelocate_arm);
365
366         // Parse Relocation Entries
367         if(rel && relSz)
368         {
369                 Elf32_Word      *ptr;
370                 DEBUGS(" elf_relocate: rel=0x%x, relSz=0x%x, relEntSz=0x%x", rel, relSz, relEntSz);
371                 j = relSz / relEntSz;
372                 for( i = 0; i < j; i++ )
373                 {
374                         //DEBUGS("  Rel %i: 0x%x+0x%x", i, iBaseDiff, rel[i].r_offset);
375                         ptr = (void*)(iBaseDiff + rel[i].r_offset);
376                         _doRelocate(rel[i].r_info, ptr, 0, *ptr);
377                 }
378         }
379         // Parse Relocation Entries
380         if(rela && relaSz)
381         {
382                 Elf32_Word      *ptr;
383                 DEBUGS(" elf_relocate: rela=0x%x, relaSz=0x%x, relaEntSz=0x%x", rela, relaSz, relaEntSz);
384                 j = relaSz / relaEntSz;
385                 for( i = 0; i < j; i++ )
386                 {
387                         ptr = (void*)(iBaseDiff + rela[i].r_offset);
388                         _doRelocate(rel[i].r_info, ptr, 1, rela[i].r_addend);
389                 }
390         }
391         
392         // === Process PLT (Procedure Linkage Table) ===
393         if(plt && pltSz)
394         {
395                 Elf32_Word      *ptr;
396                 DEBUGS(" elf_relocate: Relocate PLT, plt=0x%x", plt);
397                 if(pltType == DT_REL)
398                 {
399                         Elf32_Rel       *pltRel = plt;
400                         j = pltSz / sizeof(Elf32_Rel);
401                         DEBUGS(" elf_relocate: PLT Reloc Type = Rel, %i entries", j);
402                         for(i=0;i<j;i++)
403                         {
404                                 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
405                                 _doRelocate(pltRel[i].r_info, ptr, 0, *ptr);
406                         }
407                 }
408                 else
409                 {
410                         Elf32_Rela      *pltRela = plt;
411                         j = pltSz / sizeof(Elf32_Rela);
412                         DEBUGS(" elf_relocate: PLT Reloc Type = Rela, %i entries", j);
413                         for(i=0;i<j;i++)
414                         {
415                                 ptr = (void*)(iRealBase + pltRela[i].r_offset);
416                                 _doRelocate(pltRela[i].r_info, ptr, 1, pltRela[i].r_addend);
417                         }
418                 }
419         }
420         
421         DEBUGS("ElfRelocate: RETURN 0x%x to %p", hdr->entrypoint + iBaseDiff, __builtin_return_address(0));
422         return (void*)(intptr_t)( hdr->entrypoint + iBaseDiff );
423 }
424
425 int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
426 {
427         Elf32_Ehdr      *hdr = Base;
428         Elf32_Sym       *symtab = NULL;
429          int    nbuckets = 0;
430         Elf32_Word      *pBuckets = NULL;
431         Elf32_Word      *pChains;
432         uint32_t        iNameHash;
433         const char      *dynstrtab = NULL;
434         uintptr_t       iBaseDiff = -1;
435         Elf32_Phdr      *phtab;
436         Elf32_Dyn       *dynTab = NULL;
437          int    i;
438
439         // Locate the tables
440         phtab = (void*)( (uintptr_t)Base + hdr->phoff );
441         for( i = 0; i < hdr->phentcount; i ++ )
442         {
443                 if(phtab[i].Type == PT_LOAD && iBaseDiff > phtab[i].VAddr)
444                         iBaseDiff = phtab[i].VAddr;
445                 if( phtab[i].Type == PT_DYNAMIC ) {
446                         dynTab = (void*)(intptr_t)phtab[i].VAddr;
447                 }
448         }
449         if( !dynTab ) {
450                 SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
451                 return 0;
452         }
453         iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
454         dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
455         for( i = 0; dynTab[i].d_tag != DT_NULL; i++)
456         {
457                 switch(dynTab[i].d_tag)
458                 {
459                 // --- Symbol Table ---
460                 case DT_SYMTAB:
461                         symtab = (void*)(intptr_t) dynTab[i].d_val;     // Rebased in Relocate
462                         break;
463                 case DT_STRTAB:
464                         dynstrtab = (void*)(intptr_t) dynTab[i].d_val;
465                         break;
466                 // --- Hash Table --
467                 case DT_HASH:
468                         pBuckets = (void*)(intptr_t) dynTab[i].d_val;
469                         break;
470                 }
471         }
472         
473         if( !symtab ) {
474                 SysDebug("ERRO - No DT_SYMTAB in %p", Base);
475                 return 0;
476         }
477         if( !pBuckets ) {
478                 SysDebug("ERRO - No DT_HASH in %p", Base);
479                 return 0;
480         }
481         if( !dynstrtab ) {
482                 SysDebug("ERRO - No DT_STRTAB in %p", Base);
483                 return 0;
484         }
485
486         // ... ok... maybe they haven't been relocated
487         if( (uintptr_t)symtab < (uintptr_t)Base )
488         {
489                 symtab    = (void*)( (uintptr_t)symtab    + iBaseDiff );
490                 pBuckets  = (void*)( (uintptr_t)pBuckets  + iBaseDiff );
491                 dynstrtab = (void*)( (uintptr_t)dynstrtab + iBaseDiff );
492                 SysDebug("Executable not yet relocated");
493         }
494
495         nbuckets = pBuckets[0];
496 //      iSymCount = pBuckets[1];
497         pBuckets = &pBuckets[2];
498         pChains = &pBuckets[ nbuckets ];
499
500         // Get hash
501         iNameHash = ElfHashString(Name);
502         iNameHash %= nbuckets;
503
504         // Walk Chain
505         i = pBuckets[ iNameHash ];
506         if(symtab[i].shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].nameOfs, Name) == 0) {
507                 *ret = (void*)( (uintptr_t) symtab[ i ].value + iBaseDiff );
508                 if(Size)        *Size = symtab[i].size;
509                 return 1;
510         }
511         
512         while(pChains[i] != STN_UNDEF)
513         {
514                 i = pChains[i];
515                 if(symtab[i].shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[ i ].nameOfs, Name) == 0) {
516                         *ret = (void*)( (uintptr_t)symtab[ i ].value + iBaseDiff );
517                         if(Size)        *Size = symtab[i].size;
518                         return 1;
519                 }
520         }
521         
522         return 0;
523 }
524
525 #ifdef SUPPORT_ELF64
526 void *Elf64Relocate(void *Base, char **envp, const char *Filename)
527 {
528          int    i;
529         Elf64_Ehdr      *hdr = Base;
530         Elf64_Phdr      *phtab;
531         Elf64_Dyn       *dyntab;
532         Elf64_Addr      compiledBase = -1, baseDiff;
533         Elf64_Sym       *symtab = NULL;
534         char    *strtab = NULL;
535         Elf64_Word      *hashtab = NULL;
536         Elf64_Rel       *rel = NULL;
537          int    rel_count = 0;
538         Elf64_Rela      *rela = NULL;
539          int    rela_count = 0;
540         void    *pltrel = NULL;
541          int    plt_size = 0, plt_type = 0;
542
543         DEBUGS("Elf64Relocate: hdr = {");
544         DEBUGS("Elf64Relocate:  e_ident = '%.16s'", hdr->e_ident);
545         DEBUGS("Elf64Relocate:  e_type = 0x%x", hdr->e_type);
546         DEBUGS("Elf64Relocate:  e_machine = 0x%x", hdr->e_machine);
547         DEBUGS("Elf64Relocate:  e_version = 0x%x", hdr->e_version);
548         DEBUGS("Elf64Relocate:  e_entry = %p", hdr->e_entry);
549         DEBUGS("Elf64Relocate:  e_phoff = 0x%llx", hdr->e_phoff);
550         DEBUGS("Elf64Relocate:  e_shoff = 0x%llx", hdr->e_shoff);
551         DEBUGS("Elf64Relocate:  e_flags = 0x%x", hdr->e_flags);
552         DEBUGS("Elf64Relocate:  e_ehsize = 0x%x", hdr->e_ehsize);
553         DEBUGS("Elf64Relocate:  e_phentsize = 0x%x", hdr->e_phentsize);
554         DEBUGS("Elf64Relocate:  e_phnum = %i", hdr->e_phnum);
555
556         // Scan for the dynamic table (and find the compiled base)
557         phtab = Base + hdr->e_phoff;
558         for( i = 0; i < hdr->e_phnum; i ++ )
559         {
560                 if(phtab[i].p_type == PT_DYNAMIC)
561                         dyntab = (void *)(intptr_t)phtab[i].p_vaddr;
562                 if(phtab[i].p_type == PT_LOAD && compiledBase > phtab[i].p_vaddr)
563                         compiledBase = phtab[i].p_vaddr;
564         }
565
566         baseDiff = (uintptr_t)Base - compiledBase;
567
568         DEBUGS("baseDiff = %p", baseDiff);
569
570         if(dyntab == NULL) {
571                 SysDebug(" Elf64Relocate: No PT_DYNAMIC segment in image %p, returning", Base);
572                 return (void *)(uintptr_t)(hdr->e_entry + baseDiff);
573         }
574
575         dyntab = (void *)(uintptr_t)((uintptr_t)dyntab + baseDiff);
576
577         // Parse the dynamic table (first pass)
578         // - Search for String, Symbol and Hash tables
579         for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
580         {
581                 switch(dyntab[i].d_tag)
582                 {
583                 case DT_SYMTAB:
584                         dyntab[i].d_un.d_ptr += baseDiff;
585                         symtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
586                         break;
587                 case DT_STRTAB:
588                         dyntab[i].d_un.d_ptr += baseDiff;
589                         strtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
590                         break;
591                 case DT_HASH:
592                         dyntab[i].d_un.d_ptr += baseDiff;
593                         hashtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
594                         break;
595                 }
596         }
597
598         if( !symtab || !strtab || !hashtab ) {
599                 SysDebug("ld-acess - Elf64Relocate: Missing Symbol, string or hash table");
600                 return NULL;
601         }
602
603         // Ready for symbol use 
604         AddLoaded( Filename, Base );
605
606         // Second pass on dynamic table
607         for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
608         {
609                 DEBUGS("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag);
610                 switch(dyntab[i].d_tag)
611                 {
612                 case DT_SONAME: break;
613
614                 case DT_NEEDED: {
615                         char *libPath = strtab + dyntab[i].d_un.d_val;
616                         DEBUGS("Elf64Relocate: libPath = '%s'", libPath);
617                         if(LoadLibrary(libPath, NULL, envp) == 0) {
618                                 SysDebug("ld-acess - Elf64Relocate: Unable to load '%s'", libPath);
619                                 return NULL;
620                         }
621                         } break;
622                 
623                 // Relocation entries
624                 case DT_REL:
625                         dyntab[i].d_un.d_ptr += baseDiff;
626                         rel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
627                         break;
628                 case DT_RELSZ:
629                         rel_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rel);
630                         break;
631                 case DT_RELENT:
632                         if( dyntab[i].d_un.d_val != sizeof(Elf64_Rel) ) {
633                                 SysDebug("ld-acess - Elf64Relocate: DT_RELENT(%i) != sizeof(Elf64_Rel)(%i)",
634                                         dyntab[i].d_un.d_val, sizeof(Elf64_Rel));
635                                 return NULL;
636                         }
637                         break;
638                 case DT_RELA:
639                         dyntab[i].d_un.d_ptr += baseDiff;
640                         rela = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
641                         break;
642                 case DT_RELASZ:
643                         rela_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rela);
644                         break;
645                 case DT_RELAENT:
646                         if( dyntab[i].d_un.d_val != sizeof(Elf64_Rela) ) {
647                                 SysDebug("ld-acess - Elf64Relocate: DT_RELAENT(%i) != sizeof(Elf64_Rela)(%i)",
648                                         dyntab[i].d_un.d_val, sizeof(Elf64_Rela));
649                                 return NULL;
650                         }
651                         break;
652                 case DT_JMPREL:
653                         dyntab[i].d_un.d_ptr += baseDiff;
654                         pltrel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
655                         break;
656                 case DT_PLTREL:
657                         plt_type = dyntab[i].d_un.d_val;
658                         break;
659                 case DT_PLTRELSZ:
660                         plt_size = dyntab[i].d_un.d_val;
661                         break;
662                 }
663         }
664
665         // Relocation function
666         void _Elf64DoReloc(Elf64_Xword r_info, void *ptr, Elf64_Sxword addend)
667         {
668                  int    sym = ELF64_R_SYM(r_info);
669                  int    type = ELF64_R_TYPE(r_info);
670                 const char      *symname = strtab + symtab[sym].st_name;
671                 switch( type )
672                 {
673                 case R_X86_64_NONE:
674                         break;
675                 case R_X86_64_64:
676                         *(uint64_t*)ptr = (uintptr_t)GetSymbol(symname, NULL) + addend;
677                         break;
678                 case R_X86_64_COPY: {
679                         size_t  size;
680                         void    *sym = GetSymbol(symname, &size);
681                         memcpy(ptr, sym, size);
682                         } break;
683                 case R_X86_64_GLOB_DAT:
684                         *(uint64_t*)ptr = (uintptr_t)GetSymbol(symname, NULL);
685                         break;
686                 case R_X86_64_JUMP_SLOT:
687                         *(uint64_t*)ptr = (uintptr_t)GetSymbol(symname, NULL);
688                         break;
689                 case R_X86_64_RELATIVE:
690                         *(uint64_t*)ptr = (uintptr_t)Base + addend;
691                         break;
692                 default:
693                         SysDebug("ld-acess - _Elf64DoReloc: Unknown relocation type %i", type);
694                         break;
695                 }
696         }
697
698         if( rel )
699         {
700                 DEBUGS("rel_count = %i", rel_count);
701                 for( i = 0; i < rel_count; i ++ )
702                 {
703                         uint64_t *ptr = (void *)(uintptr_t)( rel[i].r_offset + baseDiff );
704                         _Elf64DoReloc( rel[i].r_info, ptr, *ptr);
705                 }
706         }
707
708         if( rela )
709         {
710                 DEBUGS("rela_count = %i", rela_count);
711                 for( i = 0; i < rela_count; i ++ )
712                 {
713                         uint64_t *ptr = (void *)(uintptr_t)( rela[i].r_offset + baseDiff );
714                         _Elf64DoReloc( rela[i].r_info, ptr, rela[i].r_addend );
715                 }
716         }
717
718         if( pltrel && plt_type )
719         {
720                 if( plt_type == DT_REL ) {
721                         Elf64_Rel       *plt = pltrel;
722                          int    count = plt_size / sizeof(Elf64_Rel);
723                         DEBUGS("plt rel count = %i", count);
724                         for( i = 0; i < count; i ++ )
725                         {
726                                 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
727                                 _Elf64DoReloc( plt[i].r_info, ptr, *ptr);
728                         }
729                 }
730                 else {
731                         Elf64_Rela      *plt = pltrel;
732                          int    count = plt_size / sizeof(Elf64_Rela);
733                         DEBUGS("plt rela count = %i", count);
734                         for( i = 0; i < count; i ++ )
735                         {
736                                 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
737                                 _Elf64DoReloc( plt[i].r_info, ptr, plt[i].r_addend);
738                         }
739                 }
740         }
741
742         {
743         void *ret = (void *)(uintptr_t)(hdr->e_entry + baseDiff);
744         DEBUGS("Elf64Relocate: Relocations done, return %p", ret);
745         return ret;
746         }
747 }
748
749 int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size)
750 {
751         Elf64_Ehdr      *hdr = Base;
752         Elf64_Sym       *symtab;
753          int    nbuckets = 0;
754 //       int    iSymCount = 0;
755          int    i;
756         Elf64_Word      *pBuckets;
757         Elf64_Word      *pChains;
758         uint32_t        iNameHash;
759         const char      *dynstrtab;
760         uintptr_t       iBaseDiff = -1;
761
762         dynstrtab = NULL;
763         pBuckets = NULL;
764         symtab = NULL;
765
766         // Catch the current executable
767         if( !pBuckets )
768         {
769                 Elf64_Phdr      *phtab;
770                 Elf64_Dyn       *dynTab = NULL;
771                  int    j;
772                 
773                 // Locate the tables
774                 phtab = (void*)( (intptr_t)Base + hdr->e_phoff );
775                 for( i = 0; i < hdr->e_phnum; i ++ )
776                 {
777                         if(phtab[i].p_type == PT_LOAD && iBaseDiff > phtab[i].p_vaddr)
778                                 iBaseDiff = phtab[i].p_vaddr;
779                         if( phtab[i].p_type == PT_DYNAMIC ) {
780                                 dynTab = (void*)(intptr_t)phtab[i].p_vaddr;
781                         }
782                 }
783                 if( !dynTab ) {
784                         SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
785                         return 0;
786                 }
787                 iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
788                 dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
789                 
790                 for( j = 0; dynTab[j].d_tag != DT_NULL; j++)
791                 {
792                         switch(dynTab[j].d_tag)
793                         {
794                         // --- Symbol Table ---
795                         case DT_SYMTAB:
796                                 symtab = (void*)(intptr_t) dynTab[j].d_un.d_val;        // Rebased in Relocate
797                                 break;
798                         case DT_STRTAB:
799                                 dynstrtab = (void*)(intptr_t) dynTab[j].d_un.d_val;
800                                 break;
801                         // --- Hash Table --
802                         case DT_HASH:
803                                 pBuckets = (void*)(intptr_t) dynTab[j].d_un.d_val;
804                                 break;
805                         }
806                 }
807         }
808
809         nbuckets = pBuckets[0];
810 //      iSymCount = pBuckets[1];
811         pBuckets = &pBuckets[2];
812         pChains = &pBuckets[ nbuckets ];
813         
814         // Get hash
815         iNameHash = ElfHashString(Name);
816         iNameHash %= nbuckets;
817
818         // Walk Chain
819         i = pBuckets[ iNameHash ];
820         if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
821                 *Ret = (void*)( (intptr_t)symtab[i].st_value + iBaseDiff );
822                 if(Size)        *Size = symtab[i].st_size;
823                 DEBUGS("%s = %p", Name, *Ret);
824                 return 1;
825         }
826         
827         while(pChains[i] != STN_UNDEF)
828         {
829                 i = pChains[i];
830                 if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
831                         *Ret = (void*)((intptr_t)symtab[i].st_value + iBaseDiff);
832                         if(Size)        *Size = symtab[i].st_size;
833                         DEBUGS("%s = %p", Name, *Ret);
834                         return 1;
835                 }
836         }
837         
838         return 0;
839 }
840 #endif
841
842
843 uint32_t ElfHashString(const char *name)
844 {
845         uint32_t        h = 0, g;
846         while(*name)
847         {
848                 h = (h << 4) + *(uint8_t*)name++;
849                 if( (g = h & 0xf0000000) )
850                         h ^= g >> 24;
851                 h &= ~g;
852         }
853         return h;
854 }
855

UCC git Repository :: git.ucc.asn.au