3 * ELF Executable Loader Code
\r
10 #define DEBUG_WARN 1
\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
23 tBinaryType gELF_Info = {
\r
25 0x464C457F, 0xFFFFFFFF, // '\x7FELF'
\r
27 Elf_Load, Elf_Relocate, Elf_GetSymbol
\r
31 tBinary *Elf_Load(int fp)
\r
36 VFS_Read(fp, sizeof(hdr), &hdr);
\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
44 switch(hdr.e_ident[4]) // EI_CLASS
\r
47 return Elf_Load32(fp, (Elf32_Ehdr*)&hdr);
\r
49 return Elf_Load64(fp, &hdr);
\r
51 Log_Warning("ELF", "Unknown EI_CLASS value %i", hdr.e_ident[4]);
\r
56 tBinary *Elf_Load64(int FD, Elf64_Ehdr *Header)
\r
59 Elf64_Phdr phtab[Header->e_phnum];
\r
64 if( Header->e_phoff == 0 )
\r
66 Log_Warning("ELF", "No program header, panic!");
\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
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
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
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
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
104 // Count load segments
\r
106 for( i = 0; i < Header->e_phnum; i ++ )
\r
108 if( phtab[i].p_type != PT_LOAD ) continue ;
\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
120 j = 0; // LoadSections[] index
\r
121 for( i = 0; i < Header->e_phnum; i ++ )
\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
134 // Get Interpreter Name
\r
135 if( phtab[i].p_type == PT_INTERP )
\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
148 if( phtab[i].p_type != PT_LOAD ) continue ;
\r
150 // Find the executable base
\r
151 if( phtab[i].p_vaddr < ret->Base ) ret->Base = phtab[i].p_vaddr;
\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
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
169 tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header)
\r
178 // Check architecture with current CPU
\r
179 // - TODO: Support kernel level emulation
\r
181 if( Header->machine != EM_386 )
\r
183 Log_Warning("ELF", "Unknown architecure on ELF-32");
\r
189 // Check for a program header
\r
190 if(Header->phoff == 0) {
\r
192 Log_Warning("ELF", "File does not contain a program header (phoff == 0)");
\r
198 // Read Program Header Table
\r
199 phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount );
\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
210 LOG("Header->phentcount = %i", Header->phentcount);
\r
211 for( i = 0; i < Header->phentcount; i++ )
\r
213 // Ignore Non-LOAD types
\r
214 if(phtab[i].Type != PT_LOAD)
\r
217 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);
\r
220 LOG("iLoadCount = %i", iLoadCount);
\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
232 for( i = 0; i < Header->phentcount; i++ )
\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
245 // Get Interpreter Name
\r
246 if( phtab[i].Type == PT_INTERP )
\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
258 // Ignore non-LOAD types
\r
259 if(phtab[i].Type != PT_LOAD) continue;
\r
262 if(phtab[i].VAddr < ret->Base) ret->Base = phtab[i].VAddr;
\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
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
286 // --- ELF RELOCATION ---
\r
287 int Elf_Relocate(void *Base)
\r
289 Elf64_Ehdr *hdr = Base;
\r
291 switch( hdr->e_ident[EI_CLASS] )
\r
294 return Elf_Relocate32(Base);
\r
304 * \brief Relocates a loaded ELF Executable
\r
306 int Elf_Relocate32(void *Base)
\r
308 Elf32_Ehdr *hdr = Base;
\r
310 int i, j; // Counters
\r
312 Uint iRealBase = -1;
\r
316 Elf32_Rel *rel = NULL;
\r
317 Elf32_Rela *rela = NULL;
\r
318 Uint32 *pltgot = NULL;
\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
329 ENTER("pBase", Base);
\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
336 // Determine linked base address
\r
337 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)
\r
338 iRealBase = phtab[i].VAddr;
\r
340 // Find Dynamic Section
\r
341 if(phtab[i].Type == PT_DYNAMIC) {
\r
343 Log_Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");
\r
346 dynamicTab = (void *) (tVAddr) phtab[i].VAddr;
\r
347 j = i; // Save Dynamic Table ID
\r
352 // Check if a PT_DYNAMIC segement was found
\r
354 Log_Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");
\r
359 // Page Align real base
\r
360 iRealBase &= ~0xFFF;
\r
362 // Adjust "Real" Base
\r
363 iBaseDiff = (Uint)Base - iRealBase;
\r
364 // Adjust Dynamic Table
\r
365 dynamicTab = (void *) ((Uint)dynamicTab + iBaseDiff);
\r
367 // === Get Symbol table and String Table ===
\r
368 for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
\r
370 switch(dynamicTab[j].d_tag)
\r
372 // --- Symbol Table ---
\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
379 // --- String Table ---
\r
381 dynamicTab[j].d_val += iBaseDiff;
\r
382 dynstrtab = (void*) (tVAddr) dynamicTab[j].d_val;
\r
385 // --- Hash Table --
\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
394 if( !dynsymtab && iSymCount > 0 ) {
\r
395 Log_Warning("ELF", "Elf_Relocate: No Dynamic symbol table, but count >0");
\r
399 // Alter Symbols to true base
\r
400 for(i = 0; i < iSymCount; i ++)
\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
407 // === Add to loaded list (can be imported now) ===
\r
408 //Binary_AddLoaded( (Uint)Base );
\r
410 // === Parse Relocation Data ===
\r
411 for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
\r
413 switch(dynamicTab[j].d_tag)
\r
415 // --- Shared Library Name ---
\r
417 LOG(".so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);
\r
419 // --- Needed Library ---
\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
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
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
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
441 // Parse Relocation Entries
\r
444 j = relSz / relEntSz;
\r
445 for( i = 0; i < j; i++ )
\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
453 // Parse Relocation Entries
\r
456 j = relaSz / relaEntSz;
\r
457 for( i = 0; i < j; i++ )
\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
466 // === Process PLT (Procedure Linkage Table) ===
\r
469 if(pltType == DT_REL)
\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
476 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
\r
477 if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {
\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
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
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
515 int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)
\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
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
527 // Standard 32 Bit Relocation (S+A)
\r
529 if( !Elf_GetSymbol((void*)base, sSymName, &val) ) // Search this binary first
\r
530 if( !Binary_GetSymbol( sSymName, &val ) )
\r
532 LOG("%08x R_386_32 *0x%x += 0x%x('%s')", r_info, ptr, val, sSymName);
\r
533 *ptr = val + addend;
\r
536 // 32 Bit Relocation wrt. Offset (S+A-P)
\r
538 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )
\r
539 if( !Binary_GetSymbol( sSymName, &val ) )
\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
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
552 LOG("%08x R_386_GLOB_DAT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);
\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
561 LOG("%08x R_386_JMP_SLOT *0x%x = 0x%x (%s)", r_info, ptr, val, sSymName);
\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
572 LOG("Rel 0x%x: 0x%x,%i", ptr, sym, type);
\r
579 * \fn int Elf_GetSymbol(void *Base, const char *name, Uint *ret)
\r
580 * \brief Get a symbol from the loaded binary
\r
582 int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)
\r
584 Elf32_Ehdr *hdr = (void*)Base;
\r
593 if(!Base) return 0;
\r
595 pBuckets = (void *) hdr->misc.HashTable;
\r
596 symtab = (void *) hdr->misc.SymTable;
\r
598 nbuckets = pBuckets[0];
\r
599 iSymCount = pBuckets[1];
\r
600 pBuckets = &pBuckets[2];
\r
601 pChains = &pBuckets[ nbuckets ];
\r
604 iNameHash = Elf_Int_HashString(Name);
\r
605 iNameHash %= nbuckets;
\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
615 while(pChains[i] != STN_UNDEF)
\r
618 if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {
\r
619 if(ret) *ret = symtab[ i ].value;
\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
632 Uint Elf_Int_HashString(const char *str)
\r
637 h = (h << 4) + *str++;
\r
638 if( (g = h & 0xf0000000) )
\r