Usermode/ld-acess - Overhaul cleanup of ELF loader
[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  * TODO: Have GetSymbol() return a symbol "strength" on success. Allows STB_WEAK to be overriden by STB_GLOBAL
9  */
10 #ifndef KERNEL_VERSION
11 # define DEBUG  0
12 #endif
13
14 #ifndef PAGE_SIZE
15 # define PAGE_SIZE      4096
16 #endif
17
18 #include "common.h"
19 #include <stdint.h>
20 #include <stdbool.h>
21 #ifndef assert
22 # include <assert.h>
23 #endif
24 #include "elf32.h"
25 #include "elf64.h"
26
27 #if DEBUG
28 # define DEBUG_OUT(...) SysDebug(__VA_ARGS__)
29 #else
30 # define DEBUG_OUT(...) do{}while(0)    //((void)(__VA_ARGS__))
31 #endif
32
33 #define WARNING(f,...)  SysDebug("WARN: "f ,## __VA_ARGS__)     // Malformed file
34 #define NOTICE(f,...)   SysDebug("NOTICE: "f ,## __VA_ARGS__)   // Missing relocation
35 //#define TRACE(f,...)  DEBUG_OUT("TRACE:%s:%i "f, __func__, __LINE__ ,## __VA_ARGS__)  // Debugging trace
36 #define TRACE(f,...)    DEBUG_OUT("TRACE:%s "f, __func__,## __VA_ARGS__)        // Debugging trace
37
38 #ifndef DISABLE_ELF64
39 # define SUPPORT_ELF64
40 #endif
41
42 // === CONSTANTS ===
43 #if DEBUG
44 //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"};
45 //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"};
46 #endif
47
48 #ifdef SUPPORT_ELF64
49 #endif
50
51 // === PROTOTYPES ===
52 void    *ElfRelocate(void *Base, char **envp, const char *Filename);
53  int    ElfGetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
54 void    *Elf32_Relocate(void *Base, char **envp, const char *Filename);
55  int    Elf32_GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
56 #ifdef SUPPORT_ELF64
57 void    *Elf64_Relocate(void *Base, char **envp, const char *Filename);
58  int    Elf64_GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size);
59 #endif
60 uint32_t        ElfHashString(const char *name);
61
62 // === CODE ===
63 /**
64  * \fn int ElfRelocate(void *Base, char **envp, const char *Filename)
65  * \brief Relocates a loaded ELF Executable
66  */
67 void *ElfRelocate(void *Base, char **envp, const char *Filename)
68 {
69         Elf32_Ehdr      *hdr = Base;
70         
71         switch(hdr->e_ident[4])
72         {
73         case ELFCLASS32:
74                 return Elf32_Relocate(Base, envp, Filename);
75 #ifdef SUPPORT_ELF64
76         case ELFCLASS64:
77                 return Elf64_Relocate(Base, envp, Filename);
78 #endif
79         default:
80                 SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
81                 return NULL;
82         }
83 }
84
85 /**
86  * \fn int ElfGetSymbol(Uint Base, const char *name, void **ret)
87  */
88 int ElfGetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
89 {
90         Elf32_Ehdr      *hdr = Base;
91
92         switch(hdr->e_ident[4])
93         {
94         case ELFCLASS32:
95                 return Elf32_GetSymbol(Base, Name, ret, Size);
96 #ifdef SUPPORT_ELF64
97         case ELFCLASS64:
98                 return Elf64_GetSymbol(Base, Name, ret, Size);
99 #endif
100         default:
101                 SysDebug("ld-acess - ElfRelocate: Unknown file class %i", hdr->e_ident[4]);
102                 return 0;
103         }
104 }
105
106 // --------------------------------------------------------------------
107 // Elf32 support
108 // --------------------------------------------------------------------
109 #define ELFTYPE Elf32
110 #include "elf_impl.c"
111 #undef ELFTYPE
112
113 Elf32_RelocFcn  elf_doRelocate_386;
114 Elf32_RelocFcn  elf_doRelocate_arm;
115
116 int elf_doRelocate_386(const Elf32_RelocInfo *Info, Elf32_Word r_info, Elf32_Word* ptr, Elf32_Addr addend, bool bRela)
117 {
118         const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
119         void    *symval = (void*)(intptr_t)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) )
123         {
124         // Standard 32 Bit Relocation (S+A)
125         case R_386_32:
126                 TRACE("R_386_32 *0x%x = %p + 0x%x", ptr, symval, addend);
127                 *ptr = (intptr_t)symval + addend;
128                 break;
129                 
130         // 32 Bit Relocation wrt. Offset (S+A-P)
131         case R_386_PC32:
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);
135                 break;
136
137         // Absolute Value of a symbol (S)
138         case R_386_GLOB_DAT:
139                 TRACE("R_386_GLOB_DAT *0x%x = %p", ptr, symval);        if(0)
140         case R_386_JMP_SLOT:
141                 TRACE("R_386_JMP_SLOT *0x%x = %p", ptr, symval);
142                 *ptr = (intptr_t)symval;
143                 break;
144
145         // Base Address (B+A)
146         case R_386_RELATIVE:
147                 TRACE("R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend);
148                 *ptr = Info->iBaseDiff + addend;
149                 break;
150
151         case R_386_COPY: {
152                 void *old_symval = symval;
153                 GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base);
154                 if( symval == old_symval )
155                 {
156                         if( ELF32_ST_BIND(sym->st_info) != STB_WEAK )
157                         {
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);
161                                 return 1;
162                         }
163                         // Don't bother doing the memcpy
164                         TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
165                 }
166                 else
167                 {
168                         TRACE("R_386_COPY (%p, %p, %i)", ptr, symval, size);
169                         memcpy(ptr, symval, size);
170                 }
171                 break; }
172
173         default:
174                 WARNING("Unknown relocation %i", ELF32_ST_TYPE(r_info));
175                 return 2;
176         }
177         return 0;
178 }
179
180 int elf_doRelocate_arm(const Elf32_RelocInfo *Info, Elf32_Word r_info, Elf32_Word* ptr, Elf32_Addr addend, bool bRela)
181 {
182         const Elf32_Sym *sym = &Info->symtab[ ELF32_R_SYM(r_info) ];
183         void    *symval = (void*)(intptr_t)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) )
188         {
189         // (S + A) | T
190         case R_ARM_ABS32:
191                 TRACE("R_ARM_ABS32 %p (%p + %x)", ptr, symval, addend);
192                 *ptr = val + addend;
193                 break;
194         case R_ARM_GLOB_DAT:
195                 TRACE("R_ARM_GLOB_DAT %p (%p + %x)", ptr, symval, addend);
196                 *ptr = val + addend;
197                 break;
198         case R_ARM_JUMP_SLOT:
199                 if(!bRela)      addend = 0;
200                 TRACE("R_ARM_JUMP_SLOT %p (%p + %x)", ptr, symval, addend);
201                 *ptr = val + addend;
202                 break;
203         // Copy
204         case R_ARM_COPY:
205                 TRACE("R_ARM_COPY (%p, %p, %i)", ptr, symval, size);
206                 memcpy(ptr, symval, size);
207                 break;
208         // Delta between link and runtime locations + A
209         case R_ARM_RELATIVE:
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");
214                         return 2;
215                 }
216                 else {
217                         *ptr = Info->iBaseDiff + addend;
218                 }
219                 break;
220         default:
221                 WARNING("Unknown Relocation, %i", ELF32_R_TYPE(r_info));
222                 return 2;
223         }
224         return 0;
225 }
226
227 Elf32_RelocFcn* Elf32_GetRelocFcn(unsigned Machine)
228 {
229         switch(Machine)
230         {
231         case EM_386:    return elf_doRelocate_386;
232         case EM_ARM:    return elf_doRelocate_arm;
233         default:        return NULL;
234         }
235 }
236
237
238 // --------------------------------------------------------------------
239 // Elf64 support
240 // --------------------------------------------------------------------
241 #ifdef SUPPORT_ELF64
242
243 #define ELFTYPE Elf64
244 #include "elf_impl.c"
245 #undef ELFTYPE
246
247 Elf64_RelocFcn  elf_doRelocate_x86_64;
248
249 int elf_doRelocate_x86_64(const Elf64_RelocInfo *Info, Elf64_Xword r_info, Elf64_Xword* ptr, Elf64_Addr addend, bool bRela)
250 {
251         const Elf64_Sym *sym = &Info->symtab[ ELF64_R_SYM(r_info) ];
252         void    *symval = (void*)(intptr_t)sym->st_value;
253         size_t  size = sym->st_size;
254         TRACE("%i '%s'", ELF64_R_TYPE(r_info), Info->strtab + sym->st_name);
255         switch( ELF64_R_TYPE(r_info) )
256         {
257         case R_X86_64_NONE:
258                 break;
259         case R_X86_64_64:
260                 TRACE("R_X86_64_64 *0x%x = %p + 0x%x", ptr, symval, addend);
261                 *ptr = (intptr_t)symval + addend;
262                 break;
263         // Absolute Value of a symbol (S)
264         case R_X86_64_GLOB_DAT:
265                 TRACE("R_X86_64_GLOB_DAT *0x%x = %p", ptr, symval);     if(0)
266         case R_X86_64_JUMP_SLOT:
267                 TRACE("R_X86_64_JUMP_SLOT *0x%x = %p", ptr, symval);
268                 *ptr = (intptr_t)symval;
269                 break;
270
271         // Base Address (B+A)
272         case R_X86_64_RELATIVE:
273                 TRACE("R_X86_64_RELATIVE *0x%x = 0x%x + 0x%x", ptr, Info->iBaseDiff, addend);
274                 *ptr = Info->iBaseDiff + addend;
275                 break;
276
277         case R_X86_64_COPY: {
278                 void *old_symval = symval;
279                 GetSymbol(Info->strtab + sym->st_name, &symval, &size, Info->Base);
280                 if( symval == old_symval )
281                 {
282                         if( ELF64_ST_BIND(sym->st_info) != STB_WEAK )
283                         {
284                                 WARNING("sym={val:%p,size:0x%x,info:0x%x,other:0x%x,shndx:%i}",
285                                         sym->st_value, sym->st_size, sym->st_info, sym->st_other, sym->st_shndx);
286                                 WARNING("Can't find required external symbol '%s' for R_X86_64_COPY", Info->strtab + sym->st_name);
287                                 return 1;
288                         }
289                         // Don't bother doing the memcpy
290                         TRACE("R_X86_64_COPY (%p, %p, %i)", ptr, symval, size);
291                 }
292                 else
293                 {
294                         TRACE("R_X86_64_COPY (%p, %p, %i)", ptr, symval, size);
295                         memcpy(ptr, symval, size);
296                 }
297                 break; }
298         default:
299                 WARNING("Unknown Relocation, %i", ELF64_R_TYPE(r_info));
300                 return 2;
301         }
302         return 0;
303 }
304
305 Elf64_RelocFcn* Elf64_GetRelocFcn(unsigned Machine)
306 {
307         switch(Machine)
308         {
309         case EM_X86_64: return elf_doRelocate_x86_64;
310         default:        return NULL;
311         }
312 }
313
314 #endif  // SUPPORT_ELF64
315
316
317 #ifdef SUPPORT_ELF64
318 #if 0
319 typedef int (*t_elf64_doreloc)(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend);
320
321 int _Elf64DoReloc_X86_64(void *Base, const char *strtab, Elf64_Sym *symtab, Elf64_Xword r_info, void *ptr, Elf64_Sxword addend)
322 {
323          int    sym = ELF64_R_SYM(r_info);
324          int    type = ELF64_R_TYPE(r_info);
325         const char      *symname = strtab + symtab[sym].st_name;
326         void    *symval;
327         //DEBUGS("_Elf64DoReloc: %s", symname);
328         switch( type )
329         {
330         case R_X86_64_NONE:
331                 break;
332         case R_X86_64_64:
333                 if( !GetSymbol(symname, &symval, NULL, NULL)  ) return 1;
334                 *(uint64_t*)ptr = (uintptr_t)symval + addend;
335                 break;
336         case R_X86_64_COPY: {
337                 size_t  size;
338                 if( !GetSymbol(symname, &symval, &size, NULL)  )        return 1;
339                 memcpy(ptr, symval, size);
340                 } break;
341         case R_X86_64_GLOB_DAT:
342                 if( !GetSymbol(symname, &symval, NULL, NULL)  ) return 1;
343                 *(uint64_t*)ptr = (uintptr_t)symval;
344                 break;
345         case R_X86_64_JUMP_SLOT:
346                 if( !GetSymbol(symname, &symval, NULL, NULL)  ) return 1;
347                 *(uint64_t*)ptr = (uintptr_t)symval;
348                 break;
349         case R_X86_64_RELATIVE:
350                 *(uint64_t*)ptr = (uintptr_t)Base + addend;
351                 break;
352         default:
353                 SysDebug("ld-acess - _Elf64DoReloc: Unknown relocation type %i", type);
354                 return 2;
355         }
356         //DEBUGS("_Elf64DoReloc: - Good");
357         return 0;
358 }
359
360 void *Elf64Relocate(void *Base, char **envp, const char *Filename)
361 {
362          int    i;
363         Elf64_Ehdr      *hdr = Base;
364         Elf64_Phdr      *phtab;
365         Elf64_Dyn       *dyntab = NULL;
366         Elf64_Addr      compiledBase = -1, baseDiff;
367         Elf64_Sym       *symtab = NULL;
368         char    *strtab = NULL;
369         Elf64_Word      *hashtab = NULL;
370         Elf64_Rel       *rel = NULL;
371          int    rel_count = 0;
372         Elf64_Rela      *rela = NULL;
373          int    rela_count = 0;
374         void    *pltrel = NULL;
375          int    plt_size = 0, plt_type = 0;
376
377         TRACE("hdr = {");
378         TRACE(" e_ident = '%.16s'", hdr->e_ident);
379         TRACE(" e_type = 0x%x", hdr->e_type);
380         TRACE(" e_machine = 0x%x", hdr->e_machine);
381         TRACE(" e_version = 0x%x", hdr->e_version);
382         TRACE(" e_entry = %p", hdr->e_entry);
383         TRACE(" e_phoff = 0x%llx", hdr->e_phoff);
384         TRACE(" e_shoff = 0x%llx", hdr->e_shoff);
385         TRACE(" e_flags = 0x%x", hdr->e_flags);
386         TRACE(" e_ehsize = 0x%x", hdr->e_ehsize);
387         TRACE(" e_phentsize = 0x%x", hdr->e_phentsize);
388         TRACE(" e_phnum = %i", hdr->e_phnum);
389
390         // Scan for the dynamic table (and find the compiled base)
391         phtab = (void*)((uintptr_t)Base + (uintptr_t)hdr->e_phoff);
392         for( i = 0; i < hdr->e_phnum; i ++ )
393         {
394                 if(phtab[i].p_type == PT_DYNAMIC)
395                         dyntab = (void *)(intptr_t)phtab[i].p_vaddr;
396                 if(phtab[i].p_type == PT_LOAD && compiledBase > phtab[i].p_vaddr)
397                         compiledBase = phtab[i].p_vaddr;
398         }
399
400         baseDiff = (uintptr_t)Base - compiledBase;
401
402         TRACE("baseDiff = %p", baseDiff);
403
404         if(dyntab == NULL) {
405                 SysDebug(" Elf64Relocate: No PT_DYNAMIC segment in image %p, returning", Base);
406                 return (void *)(uintptr_t)(hdr->e_entry + baseDiff);
407         }
408
409         dyntab = (void *)(uintptr_t)((uintptr_t)dyntab + baseDiff);
410
411         // Parse the dynamic table (first pass)
412         // - Search for String, Symbol and Hash tables
413         for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
414         {
415                 switch(dyntab[i].d_tag)
416                 {
417                 case DT_SYMTAB:
418                         dyntab[i].d_un.d_ptr += baseDiff;
419                         symtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
420                         break;
421                 case DT_STRTAB:
422                         dyntab[i].d_un.d_ptr += baseDiff;
423                         strtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
424                         break;
425                 case DT_HASH:
426                         dyntab[i].d_un.d_ptr += baseDiff;
427                         hashtab = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
428                         break;
429                 }
430         }
431
432         if( !symtab || !strtab || !hashtab ) {
433                 SysDebug("ld-acess - Elf64Relocate: Missing Symbol, string or hash table");
434                 return NULL;
435         }
436
437         // Ready for symbol use 
438         AddLoaded( Filename, Base );
439
440         // Second pass on dynamic table
441         for(i = 0; dyntab[i].d_tag != DT_NULL; i ++)
442         {
443                 TRACE("dyntab[%i].d_tag = %i", i, dyntab[i].d_tag);
444                 switch(dyntab[i].d_tag)
445                 {
446                 case DT_SONAME: break;
447
448                 case DT_NEEDED: {
449                         char *libPath = strtab + dyntab[i].d_un.d_val;
450                         TRACE("Elf64Relocate: libPath = '%s'", libPath);
451                         if(LoadLibrary(libPath, NULL, envp) == 0) {
452                                 SysDebug("ld-acess - Elf64Relocate: Unable to load '%s'", libPath);
453                                 return NULL;
454                         }
455                         } break;
456                 
457                 // Relocation entries
458                 case DT_REL:
459                         dyntab[i].d_un.d_ptr += baseDiff;
460                         rel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
461                         break;
462                 case DT_RELSZ:
463                         rel_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rel);
464                         break;
465                 case DT_RELENT:
466                         if( dyntab[i].d_un.d_val != sizeof(Elf64_Rel) ) {
467                                 SysDebug("ld-acess - Elf64Relocate: DT_RELENT(%i) != sizeof(Elf64_Rel)(%i)",
468                                         dyntab[i].d_un.d_val, sizeof(Elf64_Rel));
469                                 return NULL;
470                         }
471                         break;
472                 case DT_RELA:
473                         dyntab[i].d_un.d_ptr += baseDiff;
474                         rela = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
475                         break;
476                 case DT_RELASZ:
477                         rela_count = dyntab[i].d_un.d_val / sizeof(Elf64_Rela);
478                         break;
479                 case DT_RELAENT:
480                         if( dyntab[i].d_un.d_val != sizeof(Elf64_Rela) ) {
481                                 SysDebug("ld-acess - Elf64Relocate: DT_RELAENT(%i) != sizeof(Elf64_Rela)(%i)",
482                                         dyntab[i].d_un.d_val, sizeof(Elf64_Rela));
483                                 return NULL;
484                         }
485                         break;
486                 case DT_JMPREL:
487                         dyntab[i].d_un.d_ptr += baseDiff;
488                         pltrel = (void *)(uintptr_t)dyntab[i].d_un.d_ptr;
489                         break;
490                 case DT_PLTREL:
491                         plt_type = dyntab[i].d_un.d_val;
492                         break;
493                 case DT_PLTRELSZ:
494                         plt_size = dyntab[i].d_un.d_val;
495                         break;
496                 }
497         }
498
499         // TODO: Relocate symbols
500         
501         // Relocation function
502         t_elf64_doreloc fpElf64DoReloc = &_Elf64DoReloc_X86_64;
503         #define _Elf64DoReloc(info, ptr, addend)        fpElf64DoReloc(Base, strtab, symtab, info, ptr, addend)
504
505         int fail = 0;
506         if( rel )
507         {
508                 TRACE("rel_count = %i", rel_count);
509                 for( i = 0; i < rel_count; i ++ )
510                 {
511                         uint64_t *ptr = (void *)(uintptr_t)( rel[i].r_offset + baseDiff );
512                         fail |= _Elf64DoReloc( rel[i].r_info, ptr, *ptr);
513                 }
514         }
515
516         if( rela )
517         {
518                 TRACE("rela_count = %i", rela_count);
519                 for( i = 0; i < rela_count; i ++ )
520                 {
521                         uint64_t *ptr = (void *)(uintptr_t)( rela[i].r_offset + baseDiff );
522                         fail |= _Elf64DoReloc( rela[i].r_info, ptr, rela[i].r_addend );
523                 }
524         }
525
526         if( pltrel && plt_type )
527         {
528                 if( plt_type == DT_REL ) {
529                         Elf64_Rel       *plt = pltrel;
530                          int    count = plt_size / sizeof(Elf64_Rel);
531                         TRACE("plt rel count = %i", count);
532                         for( i = 0; i < count; i ++ )
533                         {
534                                 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
535                                 fail |= _Elf64DoReloc( plt[i].r_info, ptr, *ptr);
536                         }
537                 }
538                 else {
539                         Elf64_Rela      *plt = pltrel;
540                          int    count = plt_size / sizeof(Elf64_Rela);
541                         TRACE("plt rela count = %i", count);
542                         for( i = 0; i < count; i ++ )
543                         {
544                                 uint64_t *ptr = (void *)(uintptr_t)( plt[i].r_offset + baseDiff );
545                                 fail |= _Elf64DoReloc( plt[i].r_info, ptr, plt[i].r_addend);
546                         }
547                 }
548         }
549
550         if( fail ) {
551                 TRACE("Failure");
552                 return NULL;
553         }
554
555         {
556         void *ret = (void *)(uintptr_t)(hdr->e_entry + baseDiff);
557         TRACE("Relocations done, return %p", ret);
558         return ret;
559         }
560 }
561
562 int Elf64GetSymbol(void *Base, const char *Name, void **Ret, size_t *Size)
563 {
564         Elf64_Ehdr      *hdr = Base;
565         Elf64_Sym       *symtab;
566          int    nbuckets = 0;
567 //       int    iSymCount = 0;
568          int    i;
569         Elf64_Word      *pBuckets;
570         Elf64_Word      *pChains;
571         uint32_t        iNameHash;
572         const char      *dynstrtab;
573         uintptr_t       iBaseDiff = -1;
574
575         dynstrtab = NULL;
576         pBuckets = NULL;
577         symtab = NULL;
578
579         // Catch the current executable
580         if( !pBuckets )
581         {
582                 Elf64_Phdr      *phtab;
583                 Elf64_Dyn       *dynTab = NULL;
584                  int    j;
585                 
586                 // Locate the tables
587                 phtab = (void*)( (intptr_t)Base + (uintptr_t)hdr->e_phoff );
588                 for( i = 0; i < hdr->e_phnum; i ++ )
589                 {
590                         if(phtab[i].p_type == PT_LOAD && iBaseDiff > phtab[i].p_vaddr)
591                                 iBaseDiff = phtab[i].p_vaddr;
592                         if( phtab[i].p_type == PT_DYNAMIC ) {
593                                 dynTab = (void*)(intptr_t)phtab[i].p_vaddr;
594                         }
595                 }
596                 if( !dynTab ) {
597                         SysDebug("ERROR - Unable to find DYNAMIC segment in %p", Base);
598                         return 0;
599                 }
600                 iBaseDiff = (intptr_t)Base - iBaseDiff; // Make iBaseDiff actually the diff
601                 dynTab = (void*)( (intptr_t)dynTab + iBaseDiff );
602                 
603                 for( j = 0; dynTab[j].d_tag != DT_NULL; j++)
604                 {
605                         switch(dynTab[j].d_tag)
606                         {
607                         // --- Symbol Table ---
608                         case DT_SYMTAB:
609                                 symtab = (void*)(intptr_t) dynTab[j].d_un.d_val;        // Rebased in Relocate
610                                 break;
611                         case DT_STRTAB:
612                                 dynstrtab = (void*)(intptr_t) dynTab[j].d_un.d_val;
613                                 break;
614                         // --- Hash Table --
615                         case DT_HASH:
616                                 pBuckets = (void*)(intptr_t) dynTab[j].d_un.d_val;
617                                 break;
618                         }
619                 }
620         }
621
622         nbuckets = pBuckets[0];
623 //      iSymCount = pBuckets[1];
624         pBuckets = &pBuckets[2];
625         pChains = &pBuckets[ nbuckets ];
626         
627         // Get hash
628         iNameHash = ElfHashString(Name);
629         iNameHash %= nbuckets;
630
631         // Walk Chain
632         i = pBuckets[ iNameHash ];
633         if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
634                 *Ret = (void*)( (intptr_t)symtab[i].st_value + iBaseDiff );
635                 if(Size)        *Size = symtab[i].st_size;
636                 TRACE("%s = %p", Name, *Ret);
637                 return 1;
638         }
639         
640         while(pChains[i] != STN_UNDEF)
641         {
642                 i = pChains[i];
643                 if(symtab[i].st_shndx != SHN_UNDEF && strcmp(dynstrtab + symtab[i].st_name, Name) == 0) {
644                         *Ret = (void*)((intptr_t)symtab[i].st_value + iBaseDiff);
645                         if(Size)        *Size = symtab[i].st_size;
646                         TRACE("%s = %p", Name, *Ret);
647                         return 1;
648                 }
649         }
650         
651         return 0;
652 }
653 #endif
654 #endif
655
656 uint32_t ElfHashString(const char *name)
657 {
658         uint32_t        h = 0, g;
659         while(*name)
660         {
661                 h = (h << 4) + *(uint8_t*)name++;
662                 if( (g = h & 0xf0000000) )
663                         h ^= g >> 24;
664                 h &= ~g;
665         }
666         return h;
667 }
668

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