Usermode/ld-acess - Reworked build structure and syscall files
[tpg/acess2.git] / Usermode / Libraries / ld-acess.so_src / elf.c
1 /*
2  * AcessOS 1 - Dynamic Loader
3  * By thePowersGang
4  */
5 #include "common.h"
6 #include <stdint.h>
7 #include "elf32.h"
8
9 #define DEBUG   0
10
11 #if DEBUG
12 # define        DEBUGS(v...)    SysDebug(v)
13 #else
14 # define        DEBUGS(...)     
15 #endif
16
17 // === CONSTANTS ===
18 #if DEBUG
19 //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"};
20 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"};
21 #endif
22
23 // === PROTOTYPES ===
24 void elf_doRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base);
25 Uint ElfHashString(char *name);
26
27 // === CODE ===
28 /**
29  \fn int ElfRelocate(void *Base, char **envp, char *Filename)
30  \brief Relocates a loaded ELF Executable
31 */
32 void *ElfRelocate(void *Base, char **envp, char *Filename)
33 {
34         Elf32_Ehdr      *hdr = Base;
35         Elf32_Phdr      *phtab;
36          int    i, j;   // Counters
37         char    *libPath;
38         Uint    iRealBase = -1;
39         Uint    iBaseDiff;
40          int    iSegmentCount;
41          int    iSymCount;
42         Elf32_Rel       *rel = NULL;
43         Elf32_Rela      *rela = NULL;
44         Uint32  *pltgot = NULL;
45         void    *plt = NULL;
46          int    relSz=0, relEntSz=8;
47          int    relaSz=0, relaEntSz=8;
48          int    pltSz=0, pltType=0;
49         Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer
50         char    *dynstrtab = NULL;      // .dynamic String Table
51         Elf32_Sym       *dynsymtab;
52         
53         DEBUGS("ElfRelocate: (Base=0x%x)\n", Base);
54         
55         // Check magic header
56         
57         
58         // Parse Program Header to get Dynamic Table
59         phtab = Base + hdr->phoff;
60         iSegmentCount = hdr->phentcount;
61         for(i=0;i<iSegmentCount;i++)
62         {
63                 // Determine linked base address
64                 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)
65                         iRealBase = phtab[i].VAddr;
66                 
67                 // Find Dynamic Section
68                 if(phtab[i].Type == PT_DYNAMIC) {
69                         if(dynamicTab) {
70                                 DEBUGS(" WARNING - elf_relocate: Multiple PT_DYNAMIC segments\n");
71                                 continue;
72                         }
73                         dynamicTab = (void *) (intptr_t) phtab[i].VAddr;
74                         j = i;  // Save Dynamic Table ID
75                 }
76         }
77         
78         // Page Align real base
79         iRealBase &= ~0xFFF;
80         DEBUGS(" elf_relocate: True Base = 0x%x, Compiled Base = 0x%x\n", Base, iRealBase);
81         
82         // Adjust "Real" Base
83         iBaseDiff = (intptr_t)Base - iRealBase;
84         
85         hdr->entrypoint += iBaseDiff;   // Adjust Entrypoint
86         
87         // Check if a PT_DYNAMIC segement was found
88         if(!dynamicTab) {
89                 SysDebug(" elf_relocate: No PT_DYNAMIC segment in image, returning\n");
90                 return (void *)hdr->entrypoint;
91         }
92         
93         // Adjust Dynamic Table
94         dynamicTab = (void *)( (intptr_t)dynamicTab + iBaseDiff );
95         
96         // === Get Symbol table and String Table ===
97         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
98         {
99                 switch(dynamicTab[j].d_tag)
100                 {
101                 // --- Symbol Table ---
102                 case DT_SYMTAB:
103                         DEBUGS(" elf_relocate: DYNAMIC Symbol Table 0x%x (0x%x)\n",
104                                 dynamicTab[j].d_val, dynamicTab[j].d_val + iBaseDiff);
105                         dynamicTab[j].d_val += iBaseDiff;
106                         dynsymtab = (void*)(dynamicTab[j].d_val);
107                         hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident
108                         break;
109                 // --- String Table ---
110                 case DT_STRTAB:
111                         DEBUGS(" elf_relocate: DYNAMIC String Table 0x%x (0x%x)\n",
112                                 dynamicTab[j].d_val, dynamicTab[j].d_val + iBaseDiff);
113                         dynamicTab[j].d_val += iBaseDiff;
114                         dynstrtab = (void*)(dynamicTab[j].d_val);
115                         break;
116                 // --- Hash Table --
117                 case DT_HASH:
118                         dynamicTab[j].d_val += iBaseDiff;
119                         iSymCount = ((Uint*)(dynamicTab[j].d_val))[1];
120                         hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident
121                         break;
122                 }
123         }
124
125         if(dynsymtab == NULL) {
126                 SysDebug("ld-acess.so - WARNING: No Dynamic Symbol table, returning\n");
127                 return (void *) hdr->entrypoint;
128         }
129         
130         // Alter Symbols to true base
131         for(i=0;i<iSymCount;i++)
132         {
133                 dynsymtab[i].value += iBaseDiff;
134                 dynsymtab[i].nameOfs += (intptr_t)dynstrtab;
135                 //DEBUGS("elf_relocate: Sym '%s' = 0x%x (relocated)\n", dynsymtab[i].name, dynsymtab[i].value);
136         }
137         
138         // === Add to loaded list (can be imported now) ===
139         AddLoaded( Filename, Base );
140
141         // === Parse Relocation Data ===
142         DEBUGS(" elf_relocate: dynamicTab = 0x%x\n", dynamicTab);
143         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
144         {
145                 switch(dynamicTab[j].d_tag)
146                 {
147                 // --- Shared Library Name ---
148                 case DT_SONAME:
149                         DEBUGS(" elf_relocate: .so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);
150                         break;
151                 // --- Needed Library ---
152                 case DT_NEEDED:
153                         libPath = dynstrtab + dynamicTab[j].d_val;
154                         DEBUGS(" Required Library '%s'\n", libPath);
155                         if(LoadLibrary(libPath, NULL, envp) == 0) {
156                                 #if DEBUG
157                                         DEBUGS(" elf_relocate: Unable to load '%s'\n", libPath);
158                                 #else
159                                 SysDebug("Unable to load required library '%s'\n", libPath);
160                                 #endif
161                                 return 0;
162                         }
163                         break;
164                 // --- PLT/GOT ---
165                 case DT_PLTGOT: pltgot = (void*)(iBaseDiff + dynamicTab[j].d_val);      break;
166                 case DT_JMPREL: plt = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
167                 case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;
168                 case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;
169                 
170                 // --- Relocation ---
171                 case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
172                 case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;
173                 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;
174                 case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;
175                 case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;
176                 case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;
177                 
178                 // --- Symbol Table ---
179                 case DT_SYMTAB:
180                 // --- Hash Table ---
181                 case DT_HASH:
182                 // --- String Table ---
183                 case DT_STRTAB:
184                         break;
185                 
186                 // --- Unknown ---
187                 default:
188                         if(dynamicTab[j].d_tag > DT_JMPREL)     continue;
189                         //DEBUGS(" elf_relocate: %i-%i = %s,0x%x\n",
190                         //      i,j, csaDT_NAMES[dynamicTab[j].d_tag],dynamicTab[j].d_val);
191                         break;
192                 }
193         }
194         
195         DEBUGS(" elf_relocate: Beginning Relocation\n");
196         
197         // Parse Relocation Entries
198         if(rel && relSz)
199         {
200                 Uint32  *ptr;
201                 DEBUGS(" elf_relocate: rel=0x%x, relSz=0x%x, relEntSz=0x%x\n", rel, relSz, relEntSz);
202                 j = relSz / relEntSz;
203                 for( i = 0; i < j; i++ )
204                 {
205                         //DEBUGS("  Rel %i: 0x%x+0x%x\n", i, iBaseDiff, rel[i].r_offset);
206                         ptr = (void*)(iBaseDiff + rel[i].r_offset);
207                         elf_doRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, iBaseDiff);
208                 }
209         }
210         // Parse Relocation Entries
211         if(rela && relaSz)
212         {
213                 Uint32  *ptr;
214                 DEBUGS(" elf_relocate: rela=0x%x, relaSz=0x%x, relaEntSz=0x%x\n", rela, relaSz, relaEntSz);
215                 j = relaSz / relaEntSz;
216                 for( i = 0; i < j; i++ )
217                 {
218                         ptr = (void*)(iBaseDiff + rela[i].r_offset);
219                         elf_doRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, iBaseDiff);
220                 }
221         }
222         
223         // === Process PLT (Procedure Linkage Table) ===
224         if(plt && pltSz)
225         {
226                 Uint32  *ptr;
227                 DEBUGS(" elf_relocate: Relocate PLT, plt=0x%x\n", plt);
228                 if(pltType == DT_REL)
229                 {
230                         Elf32_Rel       *pltRel = plt;
231                         j = pltSz / sizeof(Elf32_Rel);
232                         DEBUGS(" elf_relocate: PLT Reloc Type = Rel, %i entries\n", j);
233                         for(i=0;i<j;i++)
234                         {
235                                 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
236                                 elf_doRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, iRealBase);
237                         }
238                 }
239                 else
240                 {
241                         Elf32_Rela      *pltRela = plt;
242                         j = pltSz / sizeof(Elf32_Rela);
243                         DEBUGS(" elf_relocate: PLT Reloc Type = Rela, %i entries\n", j);
244                         for(i=0;i<j;i++)
245                         {
246                                 ptr = (void*)(iRealBase + pltRela[i].r_offset);
247                                 elf_doRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, iRealBase);
248                         }
249                 }
250         }
251         
252         DEBUGS("ElfRelocate: RETURN 0x%x", hdr->entrypoint);
253         return (void*)hdr->entrypoint;
254 }
255
256 void elf_doRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)
257 {
258          int    type = ELF32_R_TYPE(r_info);
259          int    sym = ELF32_R_SYM(r_info);
260         Uint32  val;
261         switch( type )
262         {
263         // Standard 32 Bit Relocation (S+A)
264         case R_386_32:
265                 val = (intptr_t) GetSymbol( symtab[sym].name );
266                 DEBUGS(" elf_doRelocate: R_386_32 *0x%x += 0x%x('%s')\n",
267                         ptr, val, symtab[sym].name);
268                 *ptr = val + addend;
269                 break;
270                 
271         // 32 Bit Relocation wrt. Offset (S+A-P)
272         case R_386_PC32:
273                 DEBUGS(" elf_doRelocate: #%i: '%s'\n", sym, symtab[sym].name);
274                 val = (intptr_t) GetSymbol( symtab[sym].name );
275                 DEBUGS(" elf_doRelocate: R_386_PC32 *0x%x = 0x%x + 0x%x - 0x%x\n",
276                         ptr, *ptr, val, (Uint)ptr );
277                 *ptr = val + addend - (intptr_t)ptr;
278                 //*ptr = val + addend - ((Uint)ptr - base);
279                 break;
280
281         // Absolute Value of a symbol (S)
282         case R_386_GLOB_DAT:
283         case R_386_JMP_SLOT:
284                 DEBUGS(" elf_doRelocate: #%i: '%s'\n", sym, symtab[sym].name);
285                 val = (intptr_t) GetSymbol( symtab[sym].name );
286                 DEBUGS(" elf_doRelocate: %s *0x%x = 0x%x\n", csaR_NAMES[type], ptr, val);
287                 *ptr = val;
288                 break;
289
290         // Base Address (B+A)
291         case R_386_RELATIVE:
292                 DEBUGS(" elf_doRelocate: R_386_RELATIVE *0x%x = 0x%x + 0x%x\n", ptr, base, addend);
293                 *ptr = base + addend;
294                 break;
295                 
296         default:
297                 DEBUGS(" elf_doRelocate: Rel 0x%x: 0x%x,%s\n", ptr, sym, csaR_NAMES[type]);
298                 break;
299         }
300         
301 }
302
303 /**
304  * \fn int ElfGetSymbol(Uint Base, char *name, void **ret)
305  */
306 int ElfGetSymbol(void *Base, char *Name, void **ret)
307 {
308         Elf32_Ehdr      *hdr = Base;
309         Elf32_Sym       *symtab;
310          int    nbuckets = 0;
311          int    iSymCount = 0;
312          int    i;
313         Uint    *pBuckets;
314         Uint    *pChains;
315         Uint    iNameHash;
316
317         //DEBUGS("ElfGetSymbol: (Base=0x%x, Name='%s')\n", Base, Name);
318
319         // Catch the current executable
320         #if 0
321         if( !hdr->misc.HashTable )
322         {
323                 Elf32_Phdr      *phtab;
324                 Elf32_Dyn       *dynTab = NULL;
325                  int    j;
326                 
327                 // Locate the tables
328                 phtab = (void*)( Base + hdr->phoff );
329                 for( i = 0; i < hdr->phentcount; i ++ )
330                 {
331                         if( phtab[i].Type == PT_DYNAMIC ) {
332                                 dynTab = (void*)phtab[i].VAddr;
333                                 break ;
334                         }
335                 }
336                 if( !dynTab ) {
337                         SysDebug("ERROR - Unable to find DYNAMIC segment in %p", (void*)Base);
338                         return 0;
339                 }
340                 
341                 for( j = 0; dynTab[j].d_tag != DT_NULL; j++)
342                 {
343                         switch(dynTab[j].d_tag)
344                         {
345                         // --- Symbol Table ---
346                         case DT_SYMTAB:
347                                 hdr->misc.SymTable = dynTab[j].d_val;
348                                 break;
349                         // --- Hash Table --
350                         case DT_HASH:
351                                 hdr->misc.HashTable = dynTab[j].d_val;
352                                 break;
353                         }
354                 }
355         }
356         #endif
357         
358         if( !hdr->misc.SymTable || !hdr->misc.HashTable ) {
359                 return 0;
360         }
361
362         pBuckets = (void *) (intptr_t) hdr->misc.HashTable;
363         symtab = (void *) (intptr_t) hdr->misc.SymTable;
364         
365         nbuckets = pBuckets[0];
366         iSymCount = pBuckets[1];
367         pBuckets = &pBuckets[2];
368         pChains = &pBuckets[ nbuckets ];
369         
370         // Get hash
371         iNameHash = ElfHashString(Name);
372         iNameHash %= nbuckets;
373         //DEBUGS(" ElfGetSymbol: iNameHash = 0x%x\n", iNameHash);
374
375         // Walk Chain
376         i = pBuckets[ iNameHash ];
377         //DEBUGS(" ElfGetSymbol: strcmp(Name, \"%s\")\n", symtab[i].name);
378         if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[i].name, Name) == 0) {
379                 *ret = (void*) (intptr_t) symtab[ i ].value;
380                 return 1;
381         }
382         
383         //DEBUGS(" ElfGetSymbol: Hash of first = 0x%x\n", ElfHashString( symtab[i].name ) % nbuckets);
384         while(pChains[i] != STN_UNDEF)
385         {
386                 //DEBUGS(" pChains[%i] = %i\n", i, pChains[i]);
387                 i = pChains[i];
388                 //DEBUGS(" ElfGetSymbol: strcmp(Name, \"%s\")\n", symtab[ i ].name);
389                 if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {
390                         //DEBUGS("ElfGetSymbol: RETURN 1, '%s' = 0x%x\n", symtab[ i ].name, symtab[ i ].value);
391                         *ret = (void*)(intptr_t)symtab[ i ].value;
392                         return 1;
393                 }
394         }
395         
396         //DEBUGS("ElfGetSymbol: RETURN 0, Symbol '%s' not found\n", Name);
397         return 0;
398 }
399
400 Uint ElfHashString(char *name)
401 {
402         Uint    h = 0, g;
403         while(*name)
404         {
405                 h = (h << 4) + *name++;
406                 if( (g = h & 0xf0000000) )
407                         h ^= g >> 24;
408                 h &= ~g;
409         }
410         return h;
411 }
412
413 #if 0
414 unsigned long elf_hash(const unsigned char *name)
415 {
416         unsigned long   h = 0, g;
417         while (*name)
418         {
419                 h = (h << 4) + *name++;
420                 if (g = h & 0xf0000000)
421                         h ^= g >> 24;
422                 h &= ~g;
423         }
424         return h;
425 }
426 #endif

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