3 ELF Executable Loader Code
\r
10 #define DEBUG_WARN 1
\r
13 # define DEBUGS(v...) Log(v)
\r
15 # define DEBUGS(v...)
\r
25 // === PROTOTYPES ===
\r
26 tBinary *Elf_Load(int fp);
\r
27 int Elf_Relocate(void *Base);
\r
28 int Elf_GetSymbol(void *Base, char *Name, Uint *ret);
\r
29 int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base);
\r
30 Uint Elf_Int_HashString(char *str);
\r
33 tBinaryType gELF_Info = {
\r
35 0x464C457F, 0xFFFFFFFF, // '\x7FELF'
\r
37 Elf_Load, Elf_Relocate, Elf_GetSymbol
\r
41 tBinary *Elf_Load(int fp)
\r
53 VFS_Read(fp, sizeof(hdr), &hdr);
\r
55 // Check the file type
\r
56 if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') {
\r
57 Warning("Non-ELF File was passed to the ELF loader\n");
\r
62 // Check for a program header
\r
63 if(hdr.phoff == 0) {
\r
65 Warning("ELF File does not contain a program header\n");
\r
71 // Read Program Header Table
\r
72 phtab = malloc(sizeof(Elf32_Phdr)*hdr.phentcount);
\r
73 VFS_Seek(fp, hdr.phoff, SEEK_SET);
\r
74 VFS_Read(fp, sizeof(Elf32_Phdr)*hdr.phentcount, phtab);
\r
78 LOG("hdr.phentcount = %i", hdr.phentcount);
\r
79 for( i = 0; i < hdr.phentcount; i++ )
\r
81 // Ignore Non-LOAD types
\r
82 if(phtab[i].Type != PT_LOAD)
\r
84 iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;
\r
85 LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize);
\r
88 LOG("iPageCount = %i", iPageCount);
\r
90 // Allocate Information Structure
\r
91 ret = malloc( sizeof(tBinary) + 3*sizeof(Uint)*iPageCount );
\r
93 ret->Entry = hdr.entrypoint;
\r
94 ret->Base = -1; // Set Base to maximum value
\r
95 ret->NumPages = iPageCount;
\r
96 ret->Interpreter = NULL;
\r
100 for( i = 0; i < hdr.phentcount; i++ )
\r
103 LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);
\r
104 // Get Interpreter Name
\r
105 if( phtab[i].Type == PT_INTERP )
\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
117 // Ignore non-LOAD types
\r
118 if(phtab[i].Type != PT_LOAD) continue;
\r
121 if(phtab[i].VAddr < ret->Base) ret->Base = phtab[i].VAddr;
125 LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}",
\r
126 i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize);
\r
128 if( (phtab[i].FileSize & 0xFFF) < 0x1000 - (phtab[i].VAddr & 0xFFF) )
\r
129 lastSize = phtab[i].FileSize;
\r
131 lastSize = (phtab[i].FileSize & 0xFFF) + (phtab[i].VAddr & 0xFFF);
\r
134 LOG("lastSize = 0x%x", lastSize);
\r
137 count = ( (phtab[i].VAddr&0xFFF) + phtab[i].FileSize + 0xFFF) >> 12;
\r
140 ret->Pages[j+k].Virtual = phtab[i].VAddr + (k<<12);
\r
141 ret->Pages[j+k].Physical = phtab[i].Offset + (k<<12); // Store the offset in the physical address
\r
143 ret->Pages[j+k].Physical -= ret->Pages[j+k].Virtual&0xFFF;
\r
144 ret->Pages[j+k].Virtual &= ~0xFFF;
\r
147 ret->Pages[j+k].Size = lastSize; // Byte count in page
\r
149 ret->Pages[j+k].Size = 4096 - (phtab[i].VAddr&0xFFF);
\r
151 ret->Pages[j+k].Size = 4096;
\r
152 LOG("ret->Pages[%i].Size = 0x%x", j+k, ret->Pages[j+k].Size);
\r
153 ret->Pages[j+k].Flags = 0;
\r
155 count = (phtab[i].MemSize + 0xFFF) >> 12;
\r
158 ret->Pages[j+k].Virtual = phtab[i].VAddr + (k<<12);
\r
159 ret->Pages[j+k].Physical = -1; // -1 = Fill with zeros
\r
160 if(k != 0) ret->Pages[j+k].Virtual &= ~0xFFF;
\r
161 if(k == count-1 && (phtab[i].MemSize & 0xFFF))
\r
162 ret->Pages[j+k].Size = phtab[i].MemSize & 0xFFF; // Byte count in page
\r
164 ret->Pages[j+k].Size = 4096;
\r
165 ret->Pages[j+k].Flags = 0;
\r
166 LOG("%i - 0x%x => 0x%x - 0x%x", j+k,
\r
167 ret->Pages[j+k].Physical, ret->Pages[j+k].Virtual, ret->Pages[j+k].Size);
\r
173 LOG("Cleaning up overlaps");
\r
174 // Clear up Overlaps
\r
183 tmpRgns = malloc(sizeof(*tmpRgns)*count);
\r
185 for(i=0;i<count;i++) {
\r
186 tmpRgns[i].V = ret->Pages[i].Virtual;
\r
187 tmpRgns[i].P = ret->Pages[i].Physical;
\r
188 tmpRgns[i].S = ret->Pages[i].Size;
\r
189 tmpRgns[i].F = ret->Pages[i].Flags;
\r
192 for(i=1,j=0; i < count; i++)
\r
194 if( tmpRgns[j].F == tmpRgns[i].F
\r
195 && tmpRgns[j].V + tmpRgns[j].S == tmpRgns[i].V
\r
196 && ((tmpRgns[j].P == -1 && tmpRgns[i].P == -1)
\r
197 || (tmpRgns[j].P + tmpRgns[j].S == tmpRgns[i].P)) )
\r
199 tmpRgns[j].S += tmpRgns[i].S;
\r
202 tmpRgns[j].V = tmpRgns[i].V;
\r
203 tmpRgns[j].P = tmpRgns[i].P;
\r
204 tmpRgns[j].F = tmpRgns[i].F;
\r
205 tmpRgns[j].S = tmpRgns[i].S;
\r
211 for(i=0;i<count;i++) {
\r
212 //LogF(" Elf_Load: %i - 0x%x => 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S);
\r
213 tmpRgns[i].S += tmpRgns[i].V & 0xFFF;
\r
214 if(tmpRgns[i].P != -1) tmpRgns[i].P -= tmpRgns[i].V & 0xFFF;
\r
215 tmpRgns[i].V &= ~0xFFF;
\r
216 j += (tmpRgns[i].S + 0xFFF) >> 12;
\r
217 //LogF(" Elf_Load: %i - 0x%x => 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S);
\r
220 ret = realloc( ret, sizeof(tBinary) + 3*sizeof(Uint)*j );
\r
222 Warning("BIN", "ElfLoad: Unable to reallocate return structure");
\r
228 for(i=0;i<count;i++) {
\r
229 for( j = 0; j < (tmpRgns[i].S + 0xFFF) >> 12; j++,k++ ) {
\r
230 ret->Pages[k].Flags = tmpRgns[i].F;
\r
231 ret->Pages[k].Virtual = tmpRgns[i].V + (j<<12);
\r
232 if(tmpRgns[i].P != -1) {
\r
233 ret->Pages[k].Physical = tmpRgns[i].P + (j<<12);
\r
235 ret->Pages[k].Physical = -1;
\r
236 ret->Pages[k].Size = tmpRgns[i].S - (j << 12);
\r
237 // Clamp to page size
\r
238 if(ret->Pages[k].Size > 0x1000) ret->Pages[k].Size = 0x1000;
\r
253 // --- ELF RELOCATION ---
\r
254 // Taken from 'ld-acess.so'
\r
256 \fn int Elf_Relocate(void *Base)
\r
257 \brief Relocates a loaded ELF Executable
\r
259 int Elf_Relocate(void *Base)
\r
261 Elf32_Ehdr *hdr = Base;
\r
263 int i, j; // Counters
\r
265 Uint iRealBase = -1;
\r
269 Elf32_Rel *rel = NULL;
\r
270 Elf32_Rela *rela = NULL;
\r
271 Uint32 *pltgot = NULL;
\r
274 int relSz=0, relEntSz=8;
\r
275 int relaSz=0, relaEntSz=8;
\r
276 int pltSz=0, pltType=0;
\r
277 Elf32_Dyn *dynamicTab = NULL; // Dynamic Table Pointer
\r
278 char *dynstrtab = NULL; // .dynamic String Table
\r
279 Elf32_Sym *dynsymtab = NULL;
\r
281 ENTER("pBase", Base);
\r
283 // Parse Program Header to get Dynamic Table
\r
284 phtab = Base + hdr->phoff;
\r
285 iSegmentCount = hdr->phentcount;
\r
286 for(i=0;i<iSegmentCount;i++)
\r
288 // Determine linked base address
\r
289 if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)
\r
290 iRealBase = phtab[i].VAddr;
\r
292 // Find Dynamic Section
\r
293 if(phtab[i].Type == PT_DYNAMIC) {
\r
295 Warning("ELF", "Elf_Relocate - Multiple PT_DYNAMIC segments\n");
\r
298 dynamicTab = (void *) phtab[i].VAddr;
\r
299 j = i; // Save Dynamic Table ID
\r
304 // Check if a PT_DYNAMIC segement was found
\r
306 Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");
\r
307 LEAVE('x', hdr->entrypoint);
\r
308 return hdr->entrypoint;
\r
311 // Page Align real base
\r
312 iRealBase &= ~0xFFF;
\r
314 // Adjust "Real" Base
\r
315 iBaseDiff = (Uint)Base - iRealBase;
\r
316 // Adjust Dynamic Table
\r
317 dynamicTab = (void *) ((Uint)dynamicTab + iBaseDiff);
\r
319 // === Get Symbol table and String Table ===
\r
320 for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
\r
322 switch(dynamicTab[j].d_tag)
\r
324 // --- Symbol Table ---
\r
326 dynamicTab[j].d_val += iBaseDiff;
\r
327 dynsymtab = (void*)(dynamicTab[j].d_val);
\r
328 hdr->misc.SymTable = dynamicTab[j].d_val; // Saved in unused bytes of ident
\r
331 // --- String Table ---
\r
333 dynamicTab[j].d_val += iBaseDiff;
\r
334 dynstrtab = (void*)(dynamicTab[j].d_val);
\r
337 // --- Hash Table --
\r
339 dynamicTab[j].d_val += iBaseDiff;
\r
340 iSymCount = ((Uint*)(dynamicTab[j].d_val))[1];
\r
341 hdr->misc.HashTable = dynamicTab[j].d_val; // Saved in unused bytes of ident
\r
347 // Alter Symbols to true base
\r
348 for(i=0;i<iSymCount;i++)
\r
350 dynsymtab[i].value += iBaseDiff;
\r
351 dynsymtab[i].nameOfs += (Uint)dynstrtab;
\r
352 //LOG("Sym '%s' = 0x%x (relocated)\n", dynsymtab[i].name, dynsymtab[i].value);
\r
355 // === Add to loaded list (can be imported now) ===
\r
356 //Binary_AddLoaded( (Uint)Base );
\r
358 // === Parse Relocation Data ===
\r
359 for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)
\r
361 switch(dynamicTab[j].d_tag)
\r
363 // --- Shared Library Name ---
\r
365 LOG(".so Name '%s'\n", dynstrtab+dynamicTab[j].d_val);
\r
367 // --- Needed Library ---
\r
369 libPath = dynstrtab + dynamicTab[j].d_val;
\r
370 LOG("Required Library '%s' (IGNORED in kernel mode)\n", libPath);
\r
373 case DT_PLTGOT: pltgot = (void*)iBaseDiff+(dynamicTab[j].d_val); break;
\r
374 case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val); break;
\r
375 case DT_PLTREL: pltType = dynamicTab[j].d_val; break;
\r
376 case DT_PLTRELSZ: pltSz = dynamicTab[j].d_val; break;
\r
378 // --- Relocation ---
\r
379 case DT_REL: rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
\r
380 case DT_RELSZ: relSz = dynamicTab[j].d_val; break;
\r
381 case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;
\r
382 case DT_RELA: rela = (void*)(iBaseDiff + dynamicTab[j].d_val); break;
\r
383 case DT_RELASZ: relaSz = dynamicTab[j].d_val; break;
\r
384 case DT_RELAENT: relaEntSz = dynamicTab[j].d_val; break;
\r
388 // Parse Relocation Entries
\r
391 j = relSz / relEntSz;
\r
392 for( i = 0; i < j; i++ )
\r
394 ptr = (void*)(iBaseDiff + rel[i].r_offset);
\r
395 if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {
\r
401 // Parse Relocation Entries
\r
404 j = relaSz / relaEntSz;
\r
405 for( i = 0; i < j; i++ )
\r
407 ptr = (void*)(iBaseDiff + rela[i].r_offset);
\r
408 if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) {
\r
415 // === Process PLT (Procedure Linkage Table) ===
\r
418 if(pltType == DT_REL)
\r
420 Elf32_Rel *pltRel = plt;
\r
421 j = pltSz / sizeof(Elf32_Rel);
\r
422 for(i = 0; i < j; i++)
\r
424 ptr = (void*)(iBaseDiff + pltRel[i].r_offset);
\r
425 if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, (Uint)Base) ) {
\r
433 Elf32_Rela *pltRela = plt;
\r
434 j = pltSz / sizeof(Elf32_Rela);
\r
437 ptr = (void*)((Uint)Base + pltRela[i].r_offset);
\r
438 if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, (Uint)Base) ) {
\r
446 LEAVE('x', hdr->entrypoint);
\r
447 return hdr->entrypoint;
\r
451 * \fn void Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)
\r
452 * \brief Performs a relocation
\r
453 * \param r_info Field from relocation entry
\r
454 * \param ptr Pointer to location of relocation
\r
455 * \param addend Value to add to symbol
\r
456 * \param symtab Symbol Table
\r
457 * \param base Base of loaded binary
\r
459 int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base)
\r
462 int type = ELF32_R_TYPE(r_info);
\r
463 int sym = ELF32_R_SYM(r_info);
\r
464 char *sSymName = symtab[sym].name;
\r
466 //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",
\r
467 // r_info, ptr, addend, base);
\r
471 // Standard 32 Bit Relocation (S+A)
\r
473 if( !Elf_GetSymbol((void*)base, sSymName, &val) ) // Search this binary first
\r
474 if( !Binary_GetSymbol( sSymName, &val ) )
\r
476 //LOG("R_386_32 *0x%x += 0x%x('%s')", ptr, val, sSymName);
\r
477 *ptr = val + addend;
\r
480 // 32 Bit Relocation wrt. Offset (S+A-P)
\r
482 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )
\r
483 if( !Binary_GetSymbol( sSymName, &val ) )
\r
485 //LOG("R_386_PC32 *0x%x = 0x%x + 0x%x('%s') - 0x%x", ptr, *ptr, val, sSymName, (Uint)ptr );
\r
486 // TODO: Check if it needs the true value of ptr or the compiled value
\r
487 // NOTE: Testing using true value
\r
488 *ptr = val + addend - (Uint)ptr;
\r
491 // Absolute Value of a symbol (S)
\r
492 case R_386_GLOB_DAT:
\r
493 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )
\r
494 if( !Binary_GetSymbol( sSymName, &val ) )
\r
496 //LOG("R_386_GLOB_DAT *0x%x = 0x%x (%s)", ptr, val, sSymName);
\r
500 // Absolute Value of a symbol (S)
\r
501 case R_386_JMP_SLOT:
\r
502 if( !Elf_GetSymbol( (void*)base, sSymName, &val ) )
\r
503 if( !Binary_GetSymbol( sSymName, &val ) )
\r
505 //LOG("R_386_JMP_SLOT *0x%x = 0x%x (%s)", ptr, val, sSymName);
\r
509 // Base Address (B+A)
\r
510 case R_386_RELATIVE:
\r
511 //LOG("R_386_RELATIVE *0x%x = 0x%x + 0x%x", ptr, base, addend);
\r
512 *ptr = base + addend;
\r
516 LOG("Rel 0x%x: 0x%x,%i", ptr, sym, type);
\r
523 * \fn int Elf_GetSymbol(void *Base, char *name, Uint *ret)
\r
524 * \brief Get a symbol from the loaded binary
\r
526 int Elf_GetSymbol(void *Base, char *Name, Uint *ret)
\r
528 Elf32_Ehdr *hdr = (void*)Base;
\r
537 if(!Base) return 0;
\r
539 pBuckets = (void *) hdr->misc.HashTable;
\r
540 symtab = (void *) hdr->misc.SymTable;
\r
542 nbuckets = pBuckets[0];
\r
543 iSymCount = pBuckets[1];
\r
544 pBuckets = &pBuckets[2];
\r
545 pChains = &pBuckets[ nbuckets ];
\r
548 iNameHash = Elf_Int_HashString(Name);
\r
549 iNameHash %= nbuckets;
\r
552 i = pBuckets[ iNameHash ];
\r
553 if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[i].name, Name) == 0) {
\r
554 *ret = symtab[ i ].value;
\r
559 while(pChains[i] != STN_UNDEF)
\r
562 if(symtab[i].shndx != SHN_UNDEF && strcmp(symtab[ i ].name, Name) == 0) {
\r
563 *ret = symtab[ i ].value;
\r
571 * \fn Uint Elf_Int_HashString(char *str)
\r
572 * \brief Hash a string in the ELF format
\r
573 * \param str String to hash
\r
574 * \return Hash value
\r
576 Uint Elf_Int_HashString(char *str)
\r
581 h = (h << 4) + *str++;
\r
582 if( (g = h & 0xf0000000) )
\r