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

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