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

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