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

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