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

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