3 * ELF Executable Loader Code
\r
13 #define DEBUG_WARN 1
\r
15 #define MKPTR(_type,_val) ((_type*)(uintptr_t)(_val))
\r
16 #define PTRMK(_type,_val) MKPTR(_type,_val)
\r
17 #define PTR(_val) ((void*)(uintptr_t)(_val))
\r
21 # define LOG(s, ...) printf("%s: " s, __func__, __VA_ARGS__)
\r
22 # define LOGS(s) printf("%s: " s, __func__)
\r
31 // === PROTOTYPES ===
\r
32 void *Elf_Load(int FD);
\r
33 uintptr_t Elf_Relocate(void *Base);
\r
34 int Elf_GetSymbol(void *Base, char *Name, uintptr_t *ret);
\r
35 int Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *Base);
\r
36 uint32_t Elf_Int_HashString(char *str);
\r
39 void *Elf_Load(int FD)
\r
47 uint32_t baseDiff = 0;
\r
52 acess_read(FD, sizeof(hdr), &hdr);
\r
54 // Check the file type
\r
55 if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') {
\r
56 Warning("Non-ELF File was passed to the ELF loader\n");
\r
61 // Check for a program header
\r
62 if(hdr.phoff == 0) {
\r
64 Warning("ELF File does not contain a program header\n");
\r
70 // Read Program Header Table
\r
71 phtab = malloc( sizeof(Elf32_Phdr) * hdr.phentcount );
\r
76 LOG("hdr.phoff = 0x%08x\n", hdr.phoff);
\r
77 acess_seek(FD, hdr.phoff, ACESS_SEEK_SET);
\r
78 acess_read(FD, sizeof(Elf32_Phdr) * hdr.phentcount, phtab);
\r
82 LOG("hdr.phentcount = %i\n", hdr.phentcount);
\r
83 for( i = 0; i < hdr.phentcount; i++ )
\r
85 // Ignore Non-LOAD types
\r
86 if(phtab[i].Type != PT_LOAD)
\r
88 iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;
\r
89 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}\n", i, phtab[i].VAddr, phtab[i].MemSize);
\r
92 LOG("iPageCount = %i\n", iPageCount);
\r
94 // Allocate Information Structure
\r
95 //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );
\r
97 //ret->Entry = hdr.entrypoint;
\r
98 //ret->Base = -1; // Set Base to maximum value
\r
99 //ret->NumPages = iPageCount;
\r
100 //ret->Interpreter = NULL;
\r
102 // Prescan for base and size
\r
105 for( i = 0; i < hdr.phentcount; i ++)
\r
107 if( phtab[i].Type != PT_LOAD )
\r
109 if( phtab[i].VAddr < base )
\r
110 base = phtab[i].VAddr;
\r
111 if( phtab[i].VAddr > max )
\r
112 max = phtab[i].VAddr;
\r
115 LOG("base = %08x, max = %08x\n", base, max);
\r
118 // Find a nice space (31 address bits allowed)
\r
119 base = FindFreeRange( max, 31 );
\r
120 LOG("new base = %08x\n", base);
\r
121 if( base == 0 ) return NULL;
\r
127 for( i = 0; i < hdr.phentcount; i++ )
\r
129 //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);
\r
130 LOG("phtab[%i] = {\n", i);
\r
131 LOG(" .Type = 0x%08x\n", phtab[i].Type);
\r
132 LOG(" .Offset = 0x%08x\n", phtab[i].Offset);
\r
133 LOG(" .VAddr = 0x%08x\n", phtab[i].VAddr);
\r
134 LOG(" .PAddr = 0x%08x\n", phtab[i].PAddr);
\r
135 LOG(" .FileSize = 0x%08x\n", phtab[i].FileSize);
\r
136 LOG(" .MemSize = 0x%08x\n", phtab[i].MemSize);
\r
137 LOG(" .Flags = 0x%08x\n", phtab[i].Flags);
\r
138 LOG(" .Align = 0x%08x\n", phtab[i].Align);
\r
140 // Get Interpreter Name
\r
141 if( phtab[i].Type == PT_INTERP )
\r
144 //if(ret->Interpreter) continue;
\r
145 tmp = malloc(phtab[i].FileSize);
\r
146 acess_seek(FD, phtab[i].Offset, ACESS_SEEK_SET);
\r
147 acess_read(FD, phtab[i].FileSize, tmp);
\r
148 //ret->Interpreter = Binary_RegInterp(tmp);
\r
149 LOG("Interpreter '%s'\n", tmp);
\r
153 // Ignore non-LOAD types
\r
154 if(phtab[i].Type != PT_LOAD) continue;
\r
156 LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}\n",
\r
157 i, phtab[i].VAddr+baseDiff, phtab[i].Offset, phtab[i].FileSize);
\r
159 addr = phtab[i].VAddr + baseDiff;
\r
161 if( AllocateMemory( addr, phtab[i].MemSize ) ) {
\r
162 fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n",
\r
163 addr, phtab[i].MemSize);
\r
168 acess_seek(FD, phtab[i].Offset, ACESS_SEEK_SET);
\r
169 acess_read(FD, phtab[i].FileSize, PTRMK(void, addr) );
\r
170 memset( PTRMK(char, addr) + phtab[i].FileSize, 0, phtab[i].MemSize - phtab[i].FileSize );
\r
177 return PTRMK(void, base);
\r
180 // --- ELF RELOCATION ---
\r
182 * \brief Relocates a loaded ELF Executable
\r
184 uintptr_t Elf_Relocate(void *Base)
\r
186 Elf32_Ehdr *hdr = Base;
\r
188 int i, j; // Counters
\r
190 uint32_t iRealBase = -1;
\r
191 uintptr_t iBaseDiff;
\r
194 Elf32_Rel *rel = NULL;
\r
195 Elf32_Rela *rela = NULL;
\r
196 uint32_t *pltgot = NULL;
\r
199 int relSz=0, relEntSz=8;
\r
200 int relaSz=0, relaEntSz=8;
\r
201 int pltSz=0, pltType=0;
\r
202 Elf32_Dyn *dynamicTab = NULL; // Dynamic Table Pointer
\r
203 char *dynstrtab = NULL; // .dynamic String Table
\r
204 Elf32_Sym *dynsymtab = NULL;
\r
207 ENTER("pBase", Base);
\r
208 LOG("Base = %p\n", Base);
\r
210 // Parse Program Header to get Dynamic Table
\r
211 phtab = Base + hdr->phoff;
\r
212 iSegmentCount = hdr->phentcount;
\r
213 for(i = 0; i < iSegmentCount; i ++ )
\r
215 // Determine linked base address
\r
216 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)
\r
217 iRealBase = phtab[i].VAddr;
\r
219 // Find Dynamic Section
\r
220 if(phtab[i].Type == PT_DYNAMIC) {
\r
222 Warning("Elf_Relocate - Multiple PT_DYNAMIC segments\n");
\r
225 dynamicTab = MKPTR(void, phtab[i].VAddr);
\r
226 j = i; // Save Dynamic Table ID
\r
231 // Check if a PT_DYNAMIC segement was found
\r
233 Warning("Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");
\r
234 LEAVE('x', hdr->entrypoint);
\r
235 return hdr->entrypoint;
\r
238 // Page Align real base
\r
239 iRealBase &= ~0xFFF;
\r
241 LOG("dynamicTab = %p\n", dynamicTab);
\r
242 // Adjust "Real" Base
\r
243 iBaseDiff = (uintptr_t)Base - iRealBase;
\r
244 LOG("iBaseDiff = %p\n", (void*)iBaseDiff);
\r
245 // Adjust Dynamic Table
\r
246 dynamicTab = PTR( (uintptr_t)dynamicTab + iBaseDiff);
\r
247 LOG("dynamicTab = %p\n", dynamicTab);
\r
249 hdr->entrypoint += iBaseDiff;
\r
251 hdr->misc.SymTable = 0;
\r
252 hdr->misc.HashTable = 0;
\r
254 // === Get Symbol table and String Table ===
\r
255 for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
\r
257 switch(dynamicTab[j].d_tag)
\r
259 // --- Symbol Table ---
\r
261 dynamicTab[j].d_val += iBaseDiff;
\r
262 dynsymtab = PTRMK(void, dynamicTab[j].d_val);
\r
263 hdr->misc.SymTable = dynamicTab[j].d_val; // Saved in unused bytes of ident
\r
266 // --- String Table ---
\r
268 dynamicTab[j].d_val += iBaseDiff;
\r
269 dynstrtab = PTRMK(void, dynamicTab[j].d_val);
\r
272 // --- Hash Table --
\r
274 dynamicTab[j].d_val += iBaseDiff;
\r
275 iSymCount = (PTRMK(uint32_t, dynamicTab[j].d_val))[1];
\r
276 hdr->misc.HashTable = dynamicTab[j].d_val; // Saved in unused bytes of ident
\r
281 LOG("hdr->misc.SymTable = %x, hdr->misc.HashTable = %x",
\r
282 hdr->misc.SymTable, hdr->misc.HashTable);
\r
285 // Alter Symbols to true base
\r
286 for(i = 0; i < iSymCount; i ++)
\r
288 dynsymtab[i].nameOfs += (uintptr_t)dynstrtab;
\r
289 if( dynsymtab[i].shndx == SHN_UNDEF )
\r
291 LOG("Sym '%s' = UNDEF\n", MKPTR(char,dynsymtab[i].name));
\r
295 dynsymtab[i].value += iBaseDiff;
\r
296 LOG("Sym '%s' = 0x%x (relocated)\n", MKPTR(char,dynsymtab[i].name), dynsymtab[i].value);
\r
300 // === Add to loaded list (can be imported now) ===
\r
301 Binary_SetReadyToUse( Base );
\r
303 // === Parse Relocation Data ===
\r
304 for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
\r
306 switch(dynamicTab[j].d_tag)
\r
308 // --- Shared Library Name ---
\r
310 LOG(".so Name '%s'\n", dynstrtab + dynamicTab[j].d_val);
\r
312 // --- Needed Library ---
\r
314 libPath = dynstrtab + dynamicTab[j].d_val;
\r
315 Binary_LoadLibrary(libPath);
\r
318 case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val); break;
\r
319 case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val); break;
\r
320 case DT_PLTREL: pltType = dynamicTab[j].d_val; break;
\r
321 case DT_PLTRELSZ: pltSz = dynamicTab[j].d_val; break;
\r
323 // --- Relocation ---
\r
324 case DT_REL: rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
\r
325 case DT_RELSZ: relSz = dynamicTab[j].d_val; break;
\r
326 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;
\r
328 case DT_RELA: rela = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
\r
329 case DT_RELASZ: relaSz = dynamicTab[j].d_val; break;
\r
330 case DT_RELAENT: relaEntSz = dynamicTab[j].d_val; break;
\r
334 // Parse Relocation Entries
\r
337 j = relSz / relEntSz;
\r
338 for( i = 0; i < j; i++ )
\r
340 ptr = (void*)(iBaseDiff + rel[i].r_offset);
\r
341 if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, Base) ) {
\r
346 // Parse Relocation Entries
\r
349 j = relaSz / relaEntSz;
\r
350 for( i = 0; i < j; i++ )
\r
352 ptr = (void*)(iBaseDiff + rela[i].r_offset);
\r
353 if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, Base) ) {
\r
359 // === Process PLT (Procedure Linkage Table) ===
\r
362 if(pltType == DT_REL)
\r
364 Elf32_Rel *pltRel = plt;
\r
365 j = pltSz / sizeof(Elf32_Rel);
\r
366 LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)\n", plt, pltSz, j);
\r
367 for(i = 0; i < j; i++)
\r
369 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
\r
370 if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, Base) ) {
\r
377 Elf32_Rela *pltRela = plt;
\r
378 j = pltSz / sizeof(Elf32_Rela);
\r
379 LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)\n", plt, pltSz, j);
\r
382 ptr = (void*)(iBaseDiff + pltRela[i].r_offset);
\r
383 if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, Base) ) {
\r
395 LEAVE('x', hdr->entrypoint);
\r
396 return hdr->entrypoint;
\r
400 * \fn void Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *base)
\r
401 * \brief Performs a relocation
\r
402 * \param r_info Field from relocation entry
\r
403 * \param ptr Pointer to location of relocation
\r
404 * \param addend Value to add to symbol
\r
405 * \param symtab Symbol Table
\r
406 * \param base Base of loaded binary
\r
408 int Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *base)
\r
411 int type = ELF32_R_TYPE(r_info);
\r
412 int sym = ELF32_R_SYM(r_info);
\r
413 char *sSymName = PTRMK(char, symtab[sym].name);
\r
415 //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",
\r
416 // r_info, ptr, addend, base);
\r
420 // Standard 32 Bit Relocation (S+A)
\r
422 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {
\r
423 Warning("Unable to find symbol '%s'", sSymName);
\r
426 LOG("%08x R_386_32 *%p += %p('%s')\n", r_info, ptr, (void*)val, sSymName);
\r
427 *ptr = val + addend;
\r
430 // 32 Bit Relocation wrt. Offset (S+A-P)
\r
432 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {
\r
433 Warning("Unable to find symbol '%s'", sSymName);
\r
436 LOG("%08x R_386_PC32 *%p = 0x%x + %p('%s') - %p\n", r_info, ptr, *ptr, (void*)val, sSymName, ptr );
\r
437 // TODO: Check if it needs the true value of ptr or the compiled value
\r
438 // NOTE: Testing using true value
\r
439 *ptr = val + addend - (uintptr_t)ptr;
\r
442 // Absolute Value of a symbol (S)
\r
443 case R_386_GLOB_DAT:
\r
444 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {
\r
445 Warning("Unable to find symbol '%s'", sSymName);
\r
448 LOG("%08x R_386_GLOB_DAT *%p = 0x%x(%s)\n", r_info, ptr, (unsigned int)val, sSymName);
\r
452 // Absolute Value of a symbol (S)
\r
453 case R_386_JMP_SLOT:
\r
454 if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {
\r
455 Warning("Unable to find symbol '%s'", sSymName);
\r
458 LOG("%08x R_386_JMP_SLOT *%p = 0x%x (%s)\n", r_info, ptr, (unsigned int)val, sSymName);
\r
462 // Base Address (B+A)
\r
463 case R_386_RELATIVE:
\r
464 LOG("%08x R_386_RELATIVE *%p = %p + 0x%x\n", r_info, ptr, base, addend);
\r
465 *ptr = (uintptr_t)base + addend;
\r
469 LOG("Rel %p: 0x%x,%i\n", ptr, sym, type);
\r
476 * \fn int Elf_GetSymbol(void *Base, char *name, uintptr_t *ret)
\r
477 * \brief Get a symbol from the loaded binary
\r
479 int Elf_GetSymbol(void *Base, char *Name, uintptr_t *ret)
\r
481 Elf32_Ehdr *hdr = (void*)Base;
\r
486 uint32_t *pBuckets;
\r
488 uint32_t iNameHash;
\r
490 if(!Base) return 0;
\r
492 pBuckets = PTR(hdr->misc.HashTable);
\r
493 symtab = PTR(hdr->misc.SymTable);
\r
495 if(!pBuckets || !symtab)
\r
498 nbuckets = pBuckets[0];
\r
499 iSymCount = pBuckets[1];
\r
500 pBuckets = &pBuckets[2];
\r
501 pChains = &pBuckets[ nbuckets ];
\r
504 iNameHash = Elf_Int_HashString(Name);
\r
505 iNameHash %= nbuckets;
\r
508 i = pBuckets[ iNameHash ];
\r
509 if(symtab[i].shndx != SHN_UNDEF && strcmp(MKPTR(char,symtab[i].name), Name) == 0) {
\r
510 if(ret) *ret = symtab[ i ].value;
\r
515 while(pChains[i] != STN_UNDEF)
\r
518 if(symtab[i].shndx != SHN_UNDEF && strcmp(MKPTR(char,symtab[i].name), Name) == 0) {
\r
519 if(ret) *ret = symtab[ i ].value;
\r
527 * \fn uint32_t Elf_Int_HashString(char *str)
\r
528 * \brief Hash a string in the ELF format
\r
529 * \param str String to hash
\r
530 * \return Hash value
\r
532 uint32_t Elf_Int_HashString(char *str)
\r
537 h = (h << 4) + *str++;
\r
538 if( (g = h & 0xf0000000) )
\r