Usermode/ld-acess - Added two more ARM relocation types
[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 tBinary *Elf_Load64(int fp, Elf64_Ehdr *hdr);\r
15 tBinary *Elf_Load32(int fp, Elf32_Ehdr *hdr);\r
16  int    Elf_Relocate(void *Base);\r
17  int    Elf_Relocate32(void *Base);\r
18  int    Elf_GetSymbol(void *Base, const char *Name, Uint *ret);\r
19  int    Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base);\r
20 Uint    Elf_Int_HashString(const char *str);\r
21 \r
22 // === GLOBALS ===\r
23 tBinaryType     gELF_Info = {\r
24         NULL,\r
25         0x464C457F, 0xFFFFFFFF, // '\x7FELF'\r
26         "ELF",\r
27         Elf_Load, Elf_Relocate, Elf_GetSymbol\r
28         };\r
29 \r
30 // === CODE ===\r
31 tBinary *Elf_Load(int fp)\r
32 {\r
33         Elf64_Ehdr      hdr;\r
34         \r
35         // Read ELF Header\r
36         VFS_Read(fp, sizeof(hdr), &hdr);\r
37         \r
38         // Check the file type\r
39         if(hdr.e_ident[0] != 0x7F || hdr.e_ident[1] != 'E' || hdr.e_ident[2] != 'L' || hdr.e_ident[3] != 'F') {\r
40                 Log_Warning("ELF", "Non-ELF File was passed to the ELF loader");\r
41                 return NULL;\r
42         }\r
43 \r
44         switch(hdr.e_ident[4])  // EI_CLASS\r
45         {\r
46         case ELFCLASS32:\r
47                 return Elf_Load32(fp, (Elf32_Ehdr*)&hdr);\r
48         case ELFCLASS64:\r
49                 return Elf_Load64(fp, &hdr);\r
50         default:\r
51                 Log_Warning("ELF", "Unknown EI_CLASS value %i", hdr.e_ident[4]);\r
52                 return NULL;\r
53         }\r
54 }\r
55 \r
56 tBinary *Elf_Load64(int FD, Elf64_Ehdr *Header)\r
57 {\r
58         tBinary *ret;\r
59         Elf64_Phdr      phtab[Header->e_phnum];\r
60          int    nLoadSegments;\r
61          int    i, j;\r
62         \r
63         // Sanity check\r
64         if( Header->e_phoff == 0 )\r
65         {\r
66                 Log_Warning("ELF", "No program header, panic!");\r
67                 return NULL;\r
68         }\r
69         if( Header->e_shentsize != sizeof(Elf64_Shdr) ) {\r
70                 Log_Warning("ELF", "Header gives shentsize as %i, my type is %i",\r
71                         Header->e_shentsize, sizeof(Elf64_Shdr) );\r
72         }\r
73         if( Header->e_phentsize != sizeof(Elf64_Phdr) ) {\r
74                 Log_Warning("ELF", "Header gives phentsize as %i, my type is %i",\r
75                         Header->e_phentsize, sizeof(Elf64_Phdr) );\r
76         }\r
77 \r
78         LOG("Header = {");\r
79         LOG("  e_ident = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",\r
80                 Header->e_ident[0], Header->e_ident[1], Header->e_ident[2], Header->e_ident[3],\r
81                 Header->e_ident[4], Header->e_ident[5], Header->e_ident[6], Header->e_ident[7],\r
82                 Header->e_ident[8], Header->e_ident[9], Header->e_ident[10], Header->e_ident[11],\r
83                 Header->e_ident[12], Header->e_ident[13], Header->e_ident[14], Header->e_ident[15]\r
84                 );\r
85         LOG("  e_type = %i", Header->e_type);\r
86         LOG("  e_machine = %i", Header->e_machine);\r
87         LOG("  e_version = %i", Header->e_version);\r
88         LOG("  e_entry   = 0x%llx", Header->e_entry);\r
89         LOG("  e_phoff   = 0x%llx", Header->e_phoff);\r
90         LOG("  e_shoff   = 0x%llx", Header->e_shoff);\r
91         LOG("  e_flags   = 0x%x", Header->e_flags);\r
92         LOG("  e_ehsize  = %i", Header->e_ehsize);\r
93         LOG("  e_phentsize = %i", Header->e_phentsize);\r
94         LOG("  e_phnum   = %i", Header->e_phnum);\r
95         LOG("  e_shentsize = %i", Header->e_shentsize);\r
96         LOG("  e_shnum   = %i", Header->e_shnum);\r
97         LOG("  e_shstrndx = %i", Header->e_shstrndx);\r
98         LOG("}");\r
99 \r
100         // Load Program Header table\r
101         VFS_Seek(FD, Header->e_phoff, SEEK_SET);\r
102         VFS_Read(FD, sizeof(Elf64_Phdr)*Header->e_phnum, phtab);\r
103 \r
104         // Count load segments\r
105         nLoadSegments = 0;\r
106         for( i = 0; i < Header->e_phnum; i ++ )\r
107         {\r
108                 if( phtab[i].p_type != PT_LOAD )        continue ;\r
109                 nLoadSegments ++;\r
110         }\r
111         \r
112         // Allocate Information Structure\r
113         ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*nLoadSegments );\r
114         // Fill Info Struct\r
115         ret->Entry = Header->e_entry;\r
116         ret->Base = -1;         // Set Base to maximum value\r
117         ret->NumSections = nLoadSegments;\r
118         ret->Interpreter = NULL;\r
119 \r
120         j = 0;  // LoadSections[] index\r
121         for( i = 0; i < Header->e_phnum; i ++ )\r
122         {\r
123                 LOG("phtab[%i] = {", i);\r
124                 LOG("  .p_type   = %i", phtab[i].p_type);\r
125                 LOG("  .p_flags  = 0x%x", phtab[i].p_flags);\r
126                 LOG("  .p_offset = 0x%llx", phtab[i].p_offset);\r
127                 LOG("  .p_vaddr  = 0x%llx", phtab[i].p_vaddr);\r
128                 LOG("  .p_paddr  = 0x%llx", phtab[i].p_paddr);\r
129                 LOG("  .p_filesz = 0x%llx", phtab[i].p_filesz);\r
130                 LOG("  .p_memsz  = 0x%llx", phtab[i].p_memsz);\r
131                 LOG("  .p_align  = 0x%llx", phtab[i].p_align);\r
132                 LOG("}");\r
133 \r
134                 // Get Interpreter Name\r
135                 if( phtab[i].p_type == PT_INTERP )\r
136                 {\r
137                         char *tmp;\r
138                         if(ret->Interpreter)    continue;\r
139                         tmp = malloc(phtab[i].p_filesz);\r
140                         VFS_Seek(FD, phtab[i].p_offset, 1);\r
141                         VFS_Read(FD, phtab[i].p_filesz, tmp);\r
142                         ret->Interpreter = Binary_RegInterp(tmp);\r
143                         LOG("Interpreter '%s'", tmp);\r
144                         free(tmp);\r
145                         continue;\r
146                 }\r
147                 \r
148                 if( phtab[i].p_type != PT_LOAD )        continue ;\r
149                 \r
150                 // Find the executable base\r
151                 if( phtab[i].p_vaddr < ret->Base )      ret->Base = phtab[i].p_vaddr;\r
152 \r
153                 ret->LoadSections[j].Offset = phtab[i].p_offset;\r
154                 ret->LoadSections[j].Virtual = phtab[i].p_vaddr;\r
155                 ret->LoadSections[j].FileSize = phtab[i].p_filesz;\r
156                 ret->LoadSections[j].MemSize = phtab[i].p_memsz;\r
157                 \r
158                 ret->LoadSections[j].Flags = 0;\r
159                 if( !(phtab[i].p_flags & PF_W) )\r
160                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
161                 if( phtab[i].p_flags & PF_X )\r
162                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
163                 j ++;\r
164         }\r
165 \r
166         return ret;\r
167 }\r
168 \r
169 tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header)\r
170 {\r
171         tBinary *ret;\r
172         Elf32_Phdr      *phtab;\r
173          int    i, j;\r
174          int    iLoadCount;\r
175 \r
176         ENTER("xFD", FD);\r
177 \r
178         // Check architecture with current CPU\r
179         // - TODO: Support kernel level emulation\r
180         #if ARCH_IS_x86\r
181         if( Header->machine != EM_386 )\r
182         {\r
183                 Log_Warning("ELF", "Unknown architecure on ELF-32");\r
184                 LEAVE_RET('n');\r
185                 return NULL;\r
186         }\r
187         #endif\r
188 \r
189         // Check for a program header\r
190         if(Header->phoff == 0) {\r
191                 #if DEBUG_WARN\r
192                 Log_Warning("ELF", "File does not contain a program header (phoff == 0)");\r
193                 #endif\r
194                 LEAVE('n');\r
195                 return NULL;\r
196         }\r
197         \r
198         // Read Program Header Table\r
199         phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount );\r
200         if( !phtab ) {\r
201                 LEAVE('n');\r
202                 return NULL;\r
203         }\r
204         LOG("hdr.phoff = 0x%08x", Header->phoff);\r
205         VFS_Seek(FD, Header->phoff, SEEK_SET);\r
206         VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab);\r
207         \r
208         // Count Pages\r
209         iLoadCount = 0;\r
210         LOG("Header->phentcount = %i", Header->phentcount);\r
211         for( i = 0; i < Header->phentcount; i++ )\r
212         {\r
213                 // Ignore Non-LOAD types\r
214                 if(phtab[i].Type != PT_LOAD)\r
215                         continue;\r
216                 iLoadCount ++;\r
217                 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);\r
218         }\r
219         \r
220         LOG("iLoadCount = %i", iLoadCount);\r
221         \r
222         // Allocate Information Structure\r
223         ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount );\r
224         // Fill Info Struct\r
225         ret->Entry = Header->entrypoint;\r
226         ret->Base = -1;         // Set Base to maximum value\r
227         ret->NumSections = iLoadCount;\r
228         ret->Interpreter = NULL;\r
229         \r
230         // Load Pages\r
231         j = 0;\r
232         for( i = 0; i < Header->phentcount; i++ )\r
233         {\r
234                 //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
235                 LOG("phtab[%i] = {", i);\r
236                 LOG(" .Type = 0x%08x", phtab[i].Type);\r
237                 LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
238                 LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
239                 LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
240                 LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
241                 LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
242                 LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
243                 LOG(" .Align = 0x%08x", phtab[i].Align);\r
244                 LOG(" }");\r
245                 // Get Interpreter Name\r
246                 if( phtab[i].Type == PT_INTERP )\r
247                 {\r
248                         char *tmp;\r
249                         if(ret->Interpreter)    continue;\r
250                         tmp = malloc(phtab[i].FileSize);\r
251                         VFS_Seek(FD, phtab[i].Offset, 1);\r
252                         VFS_Read(FD, phtab[i].FileSize, tmp);\r
253                         ret->Interpreter = Binary_RegInterp(tmp);\r
254                         LOG("Interpreter '%s'", tmp);\r
255                         free(tmp);\r
256                         continue;\r
257                 }\r
258                 // Ignore non-LOAD types\r
259                 if(phtab[i].Type != PT_LOAD)    continue;\r
260                 \r
261                 // Find Base\r
262                 if(phtab[i].VAddr < ret->Base)  ret->Base = phtab[i].VAddr;\r
263                 \r
264                 LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",\r
265                         i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);\r
266                 \r
267                 ret->LoadSections[j].Offset = phtab[i].Offset;\r
268                 ret->LoadSections[j].FileSize = phtab[i].FileSize;\r
269                 ret->LoadSections[j].Virtual = phtab[i].VAddr;\r
270                 ret->LoadSections[j].MemSize = phtab[i].MemSize;\r
271                 ret->LoadSections[j].Flags = 0;\r
272                 if( !(phtab[i].Flags & PF_W) )\r
273                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO;\r
274                 if( phtab[i].Flags & PF_X )\r
275                         ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC;\r
276                 j ++;\r
277         }\r
278         \r
279         // Clean Up\r
280         free(phtab);\r
281         // Return\r
282         LEAVE('p', ret);\r
283         return ret;\r
284 }\r
285 \r
286 // --- ELF RELOCATION ---\r
287 int Elf_Relocate(void *Base)\r
288 {\r
289         Elf64_Ehdr      *hdr = Base;\r
290         \r
291         switch( hdr->e_ident[EI_CLASS] )\r
292         {\r
293         case ELFCLASS32:\r
294                 return Elf_Relocate32(Base);\r
295         case ELFCLASS64:\r
296                 return 0;\r
297         default:\r
298                 return 1;\r
299         }\r
300 }\r
301 \r
302 \r
303 /**\r
304  * \brief Relocates a loaded ELF Executable\r
305  */\r
306 int Elf_Relocate32(void *Base)\r
307 {\r
308         Elf32_Ehdr      *hdr = Base;\r
309         Elf32_Phdr      *phtab;\r
310          int    i, j;   // Counters\r
311         char    *libPath;\r
312         Uint    iRealBase = -1;\r
313         Uint    iBaseDiff;\r
314          int    iSegmentCount;\r
315          int    iSymCount = 0;\r
316         Elf32_Rel       *rel = NULL;\r
317         Elf32_Rela      *rela = NULL;\r
318         Uint32  *pltgot = NULL;\r
319         void    *plt = NULL;\r
320         Uint32  *ptr;\r
321          int    relSz=0, relEntSz=8;\r
322          int    relaSz=0, relaEntSz=8;\r
323          int    pltSz=0, pltType=0;\r
324         Elf32_Dyn       *dynamicTab = NULL;     // Dynamic Table Pointer\r
325         char    *dynstrtab = NULL;      // .dynamic String Table\r
326         Elf32_Sym       *dynsymtab = NULL;\r
327          int    bFailed = 0;\r
328         \r
329         ENTER("pBase", Base);\r
330         \r
331         // Parse Program Header to get Dynamic Table\r
332         phtab = (void *)( (tVAddr)Base + hdr->phoff );\r
333         iSegmentCount = hdr->phentcount;\r
334         for(i = 0; i < iSegmentCount; i ++ )\r
335         {\r
336                 // Determine linked base address\r
337                 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)\r
338                         iRealBase = phtab[i].VAddr;\r
339                 \r
340                 // Find Dynamic Section\r
341                 if(phtab[i].Type == PT_DYNAMIC) {\r
342                         if(dynamicTab) {\r
343                                 Log_Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
344                                 continue;\r
345                         }\r
346                         dynamicTab = (void *) (tVAddr) phtab[i].VAddr;\r
347                         j = i;  // Save Dynamic Table ID\r
348                         break;\r
349                 }\r
350         }\r
351         \r
352         // Check if a PT_DYNAMIC segement was found\r
353         if(!dynamicTab) {\r
354                 Log_Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
355                 LEAVE('x', 0);\r
356                 return 0;\r
357         }\r
358         \r
359         // Page Align real base\r
360         iRealBase &= ~0xFFF;\r
361         \r
362         // Adjust "Real" Base\r
363         iBaseDiff = (Uint)Base - iRealBase;\r
364         // Adjust Dynamic Table\r
365         dynamicTab = (void *) ((Uint)dynamicTab + iBaseDiff);\r
366         \r
367         // === Get Symbol table and String Table ===\r
368         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
369         {\r
370                 switch(dynamicTab[j].d_tag)\r
371                 {\r
372                 // --- Symbol Table ---\r
373                 case DT_SYMTAB:\r
374                         dynamicTab[j].d_val += iBaseDiff;\r
375                         dynsymtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
376                         hdr->misc.SymTable = dynamicTab[j].d_val;       // Saved in unused bytes of ident\r
377                         break;\r
378                 \r
379                 // --- String Table ---\r
380                 case DT_STRTAB:\r
381                         dynamicTab[j].d_val += iBaseDiff;\r
382                         dynstrtab = (void*) (tVAddr) dynamicTab[j].d_val;\r
383                         break;\r
384                 \r
385                 // --- Hash Table --\r
386                 case DT_HASH:\r
387                         dynamicTab[j].d_val += iBaseDiff;\r
388                         iSymCount = ((Uint*)((tVAddr)dynamicTab[j].d_val))[1];\r
389                         hdr->misc.HashTable = dynamicTab[j].d_val;      // Saved in unused bytes of ident\r
390                         break;\r
391                 }\r
392         }\r
393 \r
394         if( !dynsymtab && iSymCount > 0 ) {\r
395                 Log_Warning("ELF", "Elf_Relocate: No Dynamic symbol table, but count >0");\r
396                 return 0;\r
397         }\r
398 \r
399         // Alter Symbols to true base\r
400         for(i = 0; i < iSymCount; i ++)\r
401         {\r
402                 dynsymtab[i].value += iBaseDiff;\r
403                 dynsymtab[i].nameOfs += (Uint)dynstrtab;\r
404                 //LOG("Sym '%s' = 0x%x (relocated)\n", dynsymtab[i].name, dynsymtab[i].value);\r
405         }\r
406         \r
407         // === Add to loaded list (can be imported now) ===\r
408         //Binary_AddLoaded( (Uint)Base );\r
409 \r
410         // === Parse Relocation Data ===\r
411         for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
412         {\r
413                 switch(dynamicTab[j].d_tag)\r
414                 {\r
415                 // --- Shared Library Name ---\r
416                 case DT_SONAME:\r
417                         LOG(".so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);\r
418                         break;\r
419                 // --- Needed Library ---\r
420                 case DT_NEEDED:\r
421                         libPath = dynstrtab + dynamicTab[j].d_val;\r
422                         Log_Notice("ELF", "%p - Required Library '%s' (Ignored in kernel mode)\n", Base, libPath);\r
423                         break;\r
424                 // --- PLT/GOT ---\r
425                 case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val);        break;\r
426                 case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val);   break;\r
427                 case DT_PLTREL: pltType = dynamicTab[j].d_val;  break;\r
428                 case DT_PLTRELSZ:       pltSz = dynamicTab[j].d_val;    break;\r
429                 \r
430                 // --- Relocation ---\r
431                 case DT_REL:    rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
432                 case DT_RELSZ:  relSz = dynamicTab[j].d_val;    break;\r
433                 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;\r
434                 \r
435                 case DT_RELA:   rela = (void*)(iBaseDiff + dynamicTab[j].d_val);        break;\r
436                 case DT_RELASZ: relaSz = dynamicTab[j].d_val;   break;\r
437                 case DT_RELAENT:        relaEntSz = dynamicTab[j].d_val;        break;\r
438                 }\r
439         }\r
440         \r
441         // Parse Relocation Entries\r
442         if(rel && relSz)\r
443         {\r
444                 j = relSz / relEntSz;\r
445                 for( i = 0; i < j; i++ )\r
446                 {\r
447                         ptr = (void*)(iBaseDiff + rel[i].r_offset);\r
448                         if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {\r
449                                 bFailed = 1;\r
450                         }\r
451                 }\r
452         }\r
453         // Parse Relocation Entries\r
454         if(rela && relaSz)\r
455         {\r
456                 j = relaSz / relaEntSz;\r
457                 for( i = 0; i < j; i++ )\r
458                 {\r
459                         ptr = (void*)(iBaseDiff + rela[i].r_offset);\r
460                         if( !Elf_Int_DoRelocate(rela[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
461                                 bFailed = 1;\r
462                         }\r
463                 }\r
464         }\r
465         \r
466         // === Process PLT (Procedure Linkage Table) ===\r
467         if(plt && pltSz)\r
468         {\r
469                 if(pltType == DT_REL)\r
470                 {\r
471                         Elf32_Rel       *pltRel = plt;\r
472                         j = pltSz / sizeof(Elf32_Rel);\r
473                         LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
474                         for(i = 0; i < j; i++)\r
475                         {\r
476                                 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);\r
477                                 if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {\r
478                                         bFailed = 1;\r
479                                 }\r
480                         }\r
481                 }\r
482                 else\r
483                 {\r
484                         Elf32_Rela      *pltRela = plt;\r
485                         j = pltSz / sizeof(Elf32_Rela);\r
486                         LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)", plt, pltSz, j);\r
487                         for(i=0;i<j;i++)\r
488                         {\r
489                                 ptr = (void*)(iBaseDiff + pltRela[i].r_offset);\r
490                                 if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, (Uint)Base) ) {\r
491                                         bFailed = 1;\r
492                                 }\r
493                         }\r
494                 }\r
495         }\r
496         \r
497         if(bFailed) {\r
498                 LEAVE('i', 0);\r
499                 return 0;\r
500         }\r
501         \r
502         LEAVE('x', 1);\r
503         return 1;\r
504 }\r
505 \r
506 /**\r
507  * \fn void Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)\r
508  * \brief Performs a relocation\r
509  * \param r_info        Field from relocation entry\r
510  * \param ptr   Pointer to location of relocation\r
511  * \param addend        Value to add to symbol\r
512  * \param symtab        Symbol Table\r
513  * \param base  Base of loaded binary\r
514  */\r
515 int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)\r
516 {\r
517         Uint    val;\r
518          int    type = ELF32_R_TYPE(r_info);\r
519          int    sym = ELF32_R_SYM(r_info);\r
520         char    *sSymName = symtab[sym].name;\r
521         \r
522         //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",\r
523         //      r_info, ptr, addend, base);\r
524         \r
525         switch( type )\r
526         {\r
527         // Standard 32 Bit Relocation (S+A)\r
528         case R_386_32:\r
529                 if( !Elf_GetSymbol((void*)base, sSymName, &val) )       // Search this binary first\r
530                         if( !Binary_GetSymbol( sSymName, &val ) )\r
531                                 return 0;\r
532                 LOG("%08x R_386_32 *0x%x += 0x%x('%s')", r_info, ptr, val, sSymName);\r
533                 *ptr = val + addend;\r
534                 break;\r
535                 \r
536         // 32 Bit Relocation wrt. Offset (S+A-P)\r
537         case R_386_PC32:\r
538                 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
539                         if( !Binary_GetSymbol( sSymName, &val ) )\r
540                                 return 0;\r
541                 LOG("%08x R_386_PC32 *0x%x = 0x%x + 0x%x('%s') - 0x%x", r_info, ptr, *ptr, val, sSymName, (Uint)ptr );\r
542                 // TODO: Check if it needs the true value of ptr or the compiled value\r
543                 // NOTE: Testing using true value\r
544                 *ptr = val + addend - (Uint)ptr;\r
545                 break;\r
546 \r
547         // Absolute Value of a symbol (S)\r
548         case R_386_GLOB_DAT:\r
549                 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
550                         if( !Binary_GetSymbol( sSymName, &val ) )\r
551                                 return 0;\r
552                 LOG("%08x R_386_GLOB_DAT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
553                 *ptr = val;\r
554                 break;\r
555         \r
556         // Absolute Value of a symbol (S)\r
557         case R_386_JMP_SLOT:\r
558                 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )\r
559                         if( !Binary_GetSymbol( sSymName, &val ) )\r
560                                 return 0;\r
561                 LOG("%08x R_386_JMP_SLOT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);\r
562                 *ptr = val;\r
563                 break;\r
564 \r
565         // Base Address (B+A)\r
566         case R_386_RELATIVE:\r
567                 LOG("%08x R_386_RELATIVE *0x%x = 0x%x + 0x%x", r_info, ptr, base, addend);\r
568                 *ptr = base + addend;\r
569                 break;\r
570                 \r
571         default:\r
572                 LOG("Rel 0x%x: 0x%x,%i", ptr, sym, type);\r
573                 break;\r
574         }\r
575         return 1;\r
576 }\r
577 \r
578 /**\r
579  * \fn int Elf_GetSymbol(void *Base, const char *name, Uint *ret)\r
580  * \brief Get a symbol from the loaded binary\r
581  */\r
582 int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)\r
583 {\r
584         Elf32_Ehdr      *hdr = (void*)Base;\r
585         Elf32_Sym       *symtab;\r
586          int    nbuckets = 0;\r
587          int    iSymCount = 0;\r
588          int    i;\r
589         Uint    *pBuckets;\r
590         Uint    *pChains;\r
591         Uint    iNameHash;\r
592 \r
593         if(!Base)       return 0;\r
594 \r
595         pBuckets = (void *) hdr->misc.HashTable;\r
596         symtab = (void *) hdr->misc.SymTable;\r
597         \r
598         nbuckets = pBuckets[0];\r
599         iSymCount = pBuckets[1];\r
600         pBuckets = &pBuckets[2];\r
601         pChains = &pBuckets[ nbuckets ];\r
602         \r
603         // Get hash\r
604         iNameHash = Elf_Int_HashString(Name);\r
605         iNameHash %= nbuckets;\r
606 \r
607         // Check Bucket\r
608         i = pBuckets[ iNameHash ];\r
609         if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[i].name, Name) == 0) {\r
610                 if(ret) *ret = symtab[ i ].value;\r
611                 return 1;\r
612         }\r
613         \r
614         // Walk Chain\r
615         while(pChains[i] != STN_UNDEF)\r
616         {\r
617                 i = pChains[i];\r
618                 if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {\r
619                         if(ret) *ret = symtab[ i ].value;\r
620                         return 1;\r
621                 }\r
622         }\r
623         return 0;\r
624 }\r
625 \r
626 /**\r
627  * \fn Uint Elf_Int_HashString(char *str)\r
628  * \brief Hash a string in the ELF format\r
629  * \param str   String to hash\r
630  * \return Hash value\r
631  */\r
632 Uint Elf_Int_HashString(const char *str)\r
633 {\r
634         Uint    h = 0, g;\r
635         while(*str)\r
636         {\r
637                 h = (h << 4) + *str++;\r
638                 if( (g = h & 0xf0000000) )\r
639                         h ^= g >> 24;\r
640                 h &= ~g;\r
641         }\r
642         return h;\r
643 }\r

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