AcessNative - ld-acess - Woking on ELF loading
[tpg/acess2.git] / AcessNative / ld-acess.so_src / elf.c
1 /*\r
2  * Acess v0.1\r
3  * ELF Executable Loader Code\r
4  */\r
5 #define DEBUG   0\r
6 #include <stdlib.h>\r
7 #include <stdio.h>\r
8 #include <string.h>\r
9 #include <unistd.h>\r
10 #include "common.h"\r
11 #include "elf.h"\r
12 \r
13 #define DEBUG_WARN      1\r
14 \r
15 #define ENTER(...)\r
16 #define LOG(...)\r
17 #define LEAVE(...)\r
18 \r
19 // === PROTOTYPES ===\r
20  int    Elf_Load(int fd);\r
21  int    Elf_Relocate(void *Base);\r
22  int    Elf_GetSymbol(void *Base, char *Name, intptr_t *ret);\r
23  int    Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, intptr_t base);\r
24 uint32_t        Elf_Int_HashString(char *str);\r
25 \r
26 // === CODE ===\r
27 int Elf_Load(int FD)\r
28 {\r
29         Elf32_Ehdr      hdr;\r
30         Elf32_Phdr      *phtab;\r
31          int    i, j;\r
32          int    iPageCount;\r
33         uint32_t        max, base = -1;\r
34         uint32_t        addr;\r
35         \r
36         ENTER("xFD", FD);\r
37         \r
38         // Read ELF Header\r
39         read(FD, &hdr, sizeof(hdr));\r
40         \r
41         // Check the file type\r
42         if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') {\r
43                 Warning("Non-ELF File was passed to the ELF loader\n");\r
44                 LEAVE('n');\r
45                 return 1;\r
46         }\r
47         \r
48         // Check for a program header\r
49         if(hdr.phoff == 0) {\r
50                 #if DEBUG_WARN\r
51                 Warning("ELF File does not contain a program header\n");\r
52                 #endif\r
53                 LEAVE('n');\r
54                 return 1;\r
55         }\r
56         \r
57         // Read Program Header Table\r
58         phtab = malloc( sizeof(Elf32_Phdr) * hdr.phentcount );\r
59         if( !phtab ) {\r
60                 LEAVE('n');\r
61                 return 1;\r
62         }\r
63         LOG("hdr.phoff = 0x%08x", hdr.phoff);\r
64         lseek(FD, hdr.phoff, SEEK_SET);\r
65         read(FD, phtab, sizeof(Elf32_Phdr)*hdr.phentcount);\r
66         \r
67         // Count Pages\r
68         iPageCount = 0;\r
69         LOG("hdr.phentcount = %i", hdr.phentcount);\r
70         for( i = 0; i < hdr.phentcount; i++ )\r
71         {\r
72                 // Ignore Non-LOAD types\r
73                 if(phtab[i].Type != PT_LOAD)\r
74                         continue;\r
75                 iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;\r
76                 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
77         }\r
78         \r
79         LOG("iPageCount = %i", iPageCount);\r
80         \r
81         // Allocate Information Structure\r
82         //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
83         // Fill Info Struct\r
84         //ret->Entry = hdr.entrypoint;\r
85         //ret->Base = -1;               // Set Base to maximum value\r
86         //ret->NumPages = iPageCount;\r
87         //ret->Interpreter = NULL;\r
88 \r
89         // Prescan for base and size\r
90         for( i = 0; i < hdr.phentcount; i ++)\r
91         {\r
92                 if( phtab[i].Type != PT_LOAD )\r
93                         continue;\r
94                 if( phtab[i].VAddr < base )\r
95                         base = phtab[i].VAddr;\r
96                 if( phtab[i].VAddr > max )\r
97                         max = phtab[i].VAddr;\r
98         }\r
99 \r
100         LOG("base = %08x, max = %08x", base, max);\r
101         \r
102         // Load Pages\r
103         j = 0;\r
104         for( i = 0; i < hdr.phentcount; i++ )\r
105         {\r
106                 //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
107                 LOG("phtab[%i] = {", i);\r
108                 LOG(" .Type = 0x%08x", phtab[i].Type);\r
109                 LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
110                 LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
111                 LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
112                 LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
113                 LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
114                 LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
115                 LOG(" .Align = 0x%08x", phtab[i].Align);\r
116                 LOG(" }");\r
117                 // Get Interpreter Name\r
118                 if( phtab[i].Type == PT_INTERP )\r
119                 {\r
120                         char *tmp;\r
121                         //if(ret->Interpreter)  continue;\r
122                         tmp = malloc(phtab[i].FileSize);\r
123                         lseek(FD, phtab[i].Offset, 1);\r
124                         read(FD, tmp, phtab[i].FileSize);\r
125                         //ret->Interpreter = Binary_RegInterp(tmp);\r
126                         LOG("Interpreter '%s'", tmp);\r
127                         free(tmp);\r
128                         continue;\r
129                 }\r
130                 // Ignore non-LOAD types\r
131                 if(phtab[i].Type != PT_LOAD)    continue;\r
132                 \r
133                 LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",\r
134                         i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);\r
135                 \r
136                 addr = phtab[i].VAddr;\r
137 \r
138                 AllocateMemory( addr, phtab[i].MemSize );\r
139                 \r
140                 lseek(FD, phtab[i].Offset, SEEK_SET);\r
141                 read(FD, (void*)(intptr_t)addr, phtab[i].FileSize);\r
142                 memset( (char*)(intptr_t)addr + phtab[i].FileSize, 0, phtab[i].MemSize - phtab[i].FileSize);\r
143         }\r
144         \r
145         // Clean Up\r
146         free(phtab);\r
147         // Return\r
148         LEAVE('i', 0);\r
149         return 0;\r
150 }\r
151 \r
152 // --- ELF RELOCATION ---\r
153 /**\r
154  \fn int Elf_Relocate(void *Base)\r
155  \brief Relocates a loaded ELF Executable\r
156 */\r
157 int Elf_Relocate(void *Base)\r
158 {\r
159         Elf32_Ehdr      *hdr = Base;\r
160         Elf32_Phdr      *phtab;\r
161          int    i, j;   // Counters\r
162         char    *libPath;\r
163         uint32_t        iRealBase = -1;\r
164         intptr_t        iBaseDiff;\r
165          int    iSegmentCount;\r
166          int    iSymCount = 0;\r
167         Elf32_Rel       *rel = NULL;\r
168         Elf32_Rela      *rela = NULL;\r
169         uint32_t        *pltgot = NULL;\r
170         void    *plt = NULL;\r
171         uint32_t        *ptr;\r
172          int    relSz=0, relEntSz=8;\r
173          int    relaSz=0, relaEntSz=8;\r
174          int    pltSz=0, pltType=0;\r
175         Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer\r
176         char    *dynstrtab = NULL;      // .dynamic String Table\r
177         Elf32_Sym       *dynsymtab = NULL;\r
178          int    bFailed = 0;\r
179         \r
180         ENTER("pBase", Base);\r
181         \r
182         // Parse Program Header to get Dynamic Table\r
183         phtab = Base + hdr->phoff;\r
184         iSegmentCount = hdr->phentcount;\r
185         for(i = 0; i < iSegmentCount; i ++ )\r
186         {\r
187                 // Determine linked base address\r
188                 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)\r
189                         iRealBase = phtab[i].VAddr;\r
190                 \r
191                 // Find Dynamic Section\r
192                 if(phtab[i].Type == PT_DYNAMIC) {\r
193                         if(dynamicTab) {\r
194                                 Warning("Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
195                                 continue;\r
196                         }\r
197                         dynamicTab = (void *) (intptr_t) phtab[i].VAddr;\r
198                         j = i;  // Save Dynamic Table ID\r
199                         break;\r
200                 }\r
201         }\r
202         \r
203         // Check if a PT_DYNAMIC segement was found\r
204         if(!dynamicTab) {\r
205                 Warning("Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
206                 LEAVE('x', hdr->entrypoint);\r
207                 return hdr->entrypoint;\r
208         }\r
209         \r
210         // Page Align real base\r
211         iRealBase &= ~0xFFF;\r
212         \r
213         // Adjust "Real" Base\r
214         iBaseDiff = (intptr_t)Base - iRealBase;\r
215         // Adjust Dynamic Table\r
216         dynamicTab = (void *) ((intptr_t)dynamicTab + iBaseDiff);\r
217         \r
218         // === Get Symbol table and String Table ===\r
219         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
220         {\r
221                 switch(dynamicTab[j].d_tag)\r
222                 {\r
223                 // --- Symbol Table ---\r
224                 case DT_SYMTAB:\r
225                         dynamicTab[j].d_val += iBaseDiff;\r
226                         dynsymtab = (void*) (intptr_t) dynamicTab[j].d_val;\r
227                         hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident\r
228                         break;\r
229                 \r
230                 // --- String Table ---\r
231                 case DT_STRTAB:\r
232                         dynamicTab[j].d_val += iBaseDiff;\r
233                         dynstrtab = (void*) (intptr_t) dynamicTab[j].d_val;\r
234                         break;\r
235                 \r
236                 // --- Hash Table --\r
237                 case DT_HASH:\r
238                         dynamicTab[j].d_val += iBaseDiff;\r
239                         iSymCount = ((uint32_t*)((intptr_t)dynamicTab[j].d_val))[1];\r
240                         hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident\r
241                         break;\r
242                 }\r
243         }\r
244 \r
245 \r
246         // Alter Symbols to true base\r
247         for(i = 0; i < iSymCount; i ++)\r
248         {\r
249                 dynsymtab[i].value += iBaseDiff;\r
250                 dynsymtab[i].nameOfs += (intptr_t)dynstrtab;\r
251                 //LOG("Sym '%s' = 0x%x (relocated)\n", dynsymtab[i].name, dynsymtab[i].value);\r
252         }\r
253         \r
254         // === Add to loaded list (can be imported now) ===\r
255         //Binary_AddLoaded( (intptr_t)Base );\r
256 \r
257         // === Parse Relocation Data ===\r
258         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
259         {\r
260                 switch(dynamicTab[j].d_tag)\r
261                 {\r
262                 // --- Shared Library Name ---\r
263                 case DT_SONAME:\r
264                         LOG(".so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);\r
265                         break;\r
266                 // --- Needed Library ---\r
267                 case DT_NEEDED:\r
268                         libPath = dynstrtab + dynamicTab[j].d_val;\r
269                         Notice("%p - Required Library '%s' - TODO load DT_NEEDED\n", Base, libPath);\r
270                         break;\r
271                 // --- PLT/GOT ---\r
272                 case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val);        break;\r
273                 case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val);   break;\r
274                 case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;\r
275                 case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;\r
276                 \r
277                 // --- Relocation ---\r
278                 case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
279                 case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;\r
280                 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;\r
281                 \r
282                 case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;\r
283                 case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;\r
284                 case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;\r
285                 }\r
286         }\r
287         \r
288         // Parse Relocation Entries\r
289         if(rel && relSz)\r
290         {\r
291                 j = relSz / relEntSz;\r
292                 for( i = 0; i < j; i++ )\r
293                 {\r
294                         ptr = (void*)(iBaseDiff + rel[i].r_offset);\r
295                         if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, (intptr_t)Base) ) {\r
296                                 bFailed = 1;\r
297                         }\r
298                 }\r
299         }\r
300         // Parse Relocation Entries\r
301         if(rela && relaSz)\r
302         {\r
303                 j = relaSz / relaEntSz;\r
304                 for( i = 0; i < j; i++ )\r
305                 {\r
306                         ptr = (void*)(iBaseDiff + rela[i].r_offset);\r
307                         if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, (intptr_t)Base) ) {\r
308                                 bFailed = 1;\r
309                         }\r
310                 }\r
311         }\r
312         \r
313         // === Process PLT (Procedure Linkage Table) ===\r
314         if(plt && pltSz)\r
315         {\r
316                 if(pltType == DT_REL)\r
317                 {\r
318                         Elf32_Rel       *pltRel = plt;\r
319                         j = pltSz / sizeof(Elf32_Rel);\r
320                         LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
321                         for(i = 0; i < j; i++)\r
322                         {\r
323                                 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);\r
324                                 if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, (intptr_t)Base) ) {\r
325                                         bFailed = 1;\r
326                                 }\r
327                         }\r
328                 }\r
329                 else\r
330                 {\r
331                         Elf32_Rela      *pltRela = plt;\r
332                         j = pltSz / sizeof(Elf32_Rela);\r
333                         LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
334                         for(i=0;i<j;i++)\r
335                         {\r
336                                 ptr = (void*)(iBaseDiff + pltRela[i].r_offset);\r
337                                 if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, (intptr_t)Base) ) {\r
338                                         bFailed = 1;\r
339                                 }\r
340                         }\r
341                 }\r
342         }\r
343         \r
344         if(bFailed) {\r
345                 LEAVE('i', 0);\r
346                 return 0;\r
347         }\r
348         \r
349         LEAVE('x', hdr->entrypoint);\r
350         return hdr->entrypoint;\r
351 }\r
352 \r
353 /**\r
354  * \fn void Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, uint32_t base)\r
355  * \brief Performs a relocation\r
356  * \param r_info        Field from relocation entry\r
357  * \param ptr   Pointer to location of relocation\r
358  * \param addend        Value to add to symbol\r
359  * \param symtab        Symbol Table\r
360  * \param base  Base of loaded binary\r
361  */\r
362 int Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, intptr_t base)\r
363 {\r
364         intptr_t        val;\r
365          int    type = ELF32_R_TYPE(r_info);\r
366          int    sym = ELF32_R_SYM(r_info);\r
367         char    *sSymName = symtab[sym].name;\r
368         \r
369         //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",\r
370         //      r_info, ptr, addend, base);\r
371         \r
372         switch( type )\r
373         {\r
374         // Standard 32 Bit Relocation (S+A)\r
375         case R_386_32:\r
376                 if( !Elf_GetSymbol((void*)base, sSymName, &val) )       // Search this binary first\r
377                         if( !Binary_GetSymbol( sSymName, &val ) )\r
378                                 return 0;\r
379                 LOG("%08x R_386_32 *0x%x += 0x%x('%s')", r_info, ptr, val, sSymName);\r
380                 *ptr = val + addend;\r
381                 break;\r
382                 \r
383         // 32 Bit Relocation wrt. Offset (S+A-P)\r
384         case R_386_PC32:\r
385                 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
386                         if( !Binary_GetSymbol( sSymName, &val ) )\r
387                                 return 0;\r
388                 LOG("%08x R_386_PC32 *0x%x = 0x%x + 0x%x('%s') - %p", r_info, ptr, *ptr, val, sSymName, ptr );\r
389                 // TODO: Check if it needs the true value of ptr or the compiled value\r
390                 // NOTE: Testing using true value\r
391                 *ptr = val + addend - (intptr_t)ptr;\r
392                 break;\r
393 \r
394         // Absolute Value of a symbol (S)\r
395         case R_386_GLOB_DAT:\r
396                 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
397                         if( !Binary_GetSymbol( sSymName, &val ) )\r
398                                 return 0;\r
399                 LOG("%08x R_386_GLOB_DAT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
400                 *ptr = val;\r
401                 break;\r
402         \r
403         // Absolute Value of a symbol (S)\r
404         case R_386_JMP_SLOT:\r
405                 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
406                         if( !Binary_GetSymbol( sSymName, &val ) )\r
407                                 return 0;\r
408                 LOG("%08x R_386_JMP_SLOT %p = 0x%x (%s)", r_info, ptr, val, sSymName);\r
409                 *ptr = val;\r
410                 break;\r
411 \r
412         // Base Address (B+A)\r
413         case R_386_RELATIVE:\r
414                 LOG("%08x R_386_RELATIVE %p = 0x%x + 0x%x", r_info, ptr, base, addend);\r
415                 *ptr = base + addend;\r
416                 break;\r
417                 \r
418         default:\r
419                 LOG("Rel 0x%x: 0x%x,%i", ptr, sym, type);\r
420                 break;\r
421         }\r
422         return 1;\r
423 }\r
424 \r
425 /**\r
426  * \fn int Elf_GetSymbol(void *Base, char *name, intptr_t *ret)\r
427  * \brief Get a symbol from the loaded binary\r
428  */\r
429 int Elf_GetSymbol(void *Base, char *Name, intptr_t *ret)\r
430 {\r
431         Elf32_Ehdr      *hdr = (void*)Base;\r
432         Elf32_Sym       *symtab;\r
433          int    nbuckets = 0;\r
434          int    iSymCount = 0;\r
435          int    i;\r
436         uint32_t        *pBuckets;\r
437         uint32_t        *pChains;\r
438         uint32_t        iNameHash;\r
439 \r
440         if(!Base)       return 0;\r
441 \r
442         pBuckets = (void *)(intptr_t) hdr->misc.HashTable;\r
443         symtab = (void *)(intptr_t) hdr->misc.SymTable;\r
444         \r
445         nbuckets = pBuckets[0];\r
446         iSymCount = pBuckets[1];\r
447         pBuckets = &pBuckets[2];\r
448         pChains = &pBuckets[ nbuckets ];\r
449         \r
450         // Get hash\r
451         iNameHash = Elf_Int_HashString(Name);\r
452         iNameHash %= nbuckets;\r
453 \r
454         // Check Bucket\r
455         i = pBuckets[ iNameHash ];\r
456         if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[i].name, Name) == 0) {\r
457                 if(ret) *ret = symtab[ i ].value;\r
458                 return 1;\r
459         }\r
460         \r
461         // Walk Chain\r
462         while(pChains[i] != STN_UNDEF)\r
463         {\r
464                 i = pChains[i];\r
465                 if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {\r
466                         if(ret) *ret = symtab[ i ].value;\r
467                         return 1;\r
468                 }\r
469         }\r
470         return 0;\r
471 }\r
472 \r
473 /**\r
474  * \fn uint32_t Elf_Int_HashString(char *str)\r
475  * \brief Hash a string in the ELF format\r
476  * \param str   String to hash\r
477  * \return Hash value\r
478  */\r
479 uint32_t Elf_Int_HashString(char *str)\r
480 {\r
481         uint32_t        h = 0, g;\r
482         while(*str)\r
483         {\r
484                 h = (h << 4) + *str++;\r
485                 if( (g = h & 0xf0000000) )\r
486                         h ^= g >> 24;\r
487                 h &= ~g;\r
488         }\r
489         return h;\r
490 }\r

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