-/*\r
- * Acess v0.1\r
- * ELF Executable Loader Code\r
- */\r
-#define DEBUG 0\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-#include "common.h"\r
-#include "elf.h"\r
-\r
-#define DEBUG_WARN 1\r
-\r
-#define MKPTR(_type,_val) ((_type*)(uintptr_t)(_val))\r
-#define PTRMK(_type,_val) MKPTR(_type,_val)\r
-#define PTR(_val) ((void*)(uintptr_t)(_val))\r
-\r
-#if DEBUG\r
-# define ENTER(...)\r
-# define LOG(s, ...) printf("%s: " s, __func__, __VA_ARGS__)\r
-# define LOGS(s) printf("%s: " s, __func__)\r
-# define LEAVE(...)\r
-#else\r
-# define ENTER(...)\r
-# define LOG(...)\r
-# define LOGS(...)\r
-# define LEAVE(...)\r
-#endif\r
-\r
-// === PROTOTYPES ===\r
-void *Elf_Load(int FD);\r
-uintptr_t Elf_Relocate(void *Base);\r
- int Elf_GetSymbol(void *Base, char *Name, uintptr_t *ret);\r
- int Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *Base);\r
-uint32_t Elf_Int_HashString(char *str);\r
-\r
-// === CODE ===\r
-void *Elf_Load(int FD)\r
-{\r
- Elf32_Ehdr hdr;\r
- Elf32_Phdr *phtab;\r
- int i, j;\r
- int iPageCount;\r
- uint32_t max, base;\r
- uint32_t addr;\r
- uint32_t baseDiff = 0;\r
- \r
- ENTER("iFD", FD);\r
- \r
- // Read ELF Header\r
- acess_read(FD, sizeof(hdr), &hdr);\r
- \r
- // Check the file type\r
- if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') {\r
- Warning("Non-ELF File was passed to the ELF loader\n");\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Check for a program header\r
- if(hdr.phoff == 0) {\r
- #if DEBUG_WARN\r
- Warning("ELF File does not contain a program header\n");\r
- #endif\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Read Program Header Table\r
- phtab = malloc( sizeof(Elf32_Phdr) * hdr.phentcount );\r
- if( !phtab ) {\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- LOG("hdr.phoff = 0x%08x\n", hdr.phoff);\r
- acess_seek(FD, hdr.phoff, ACESS_SEEK_SET);\r
- acess_read(FD, sizeof(Elf32_Phdr) * hdr.phentcount, phtab);\r
- \r
- // Count Pages\r
- iPageCount = 0;\r
- LOG("hdr.phentcount = %i\n", hdr.phentcount);\r
- for( i = 0; i < hdr.phentcount; i++ )\r
- {\r
- // Ignore Non-LOAD types\r
- if(phtab[i].Type != PT_LOAD)\r
- continue;\r
- iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12;\r
- LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}\n", i, phtab[i].VAddr, phtab[i].MemSize);\r
- }\r
- \r
- LOG("iPageCount = %i\n", iPageCount);\r
- \r
- // Allocate Information Structure\r
- //ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount );\r
- // Fill Info Struct\r
- //ret->Entry = hdr.entrypoint;\r
- //ret->Base = -1; // Set Base to maximum value\r
- //ret->NumPages = iPageCount;\r
- //ret->Interpreter = NULL;\r
-\r
- // Prescan for base and size\r
- max = 0;\r
- base = 0xFFFFFFFF;\r
- for( i = 0; i < hdr.phentcount; i ++)\r
- {\r
- if( phtab[i].Type != PT_LOAD )\r
- continue;\r
- if( phtab[i].VAddr < base )\r
- base = phtab[i].VAddr;\r
- if( phtab[i].VAddr + phtab[i].MemSize > max )\r
- max = phtab[i].VAddr + phtab[i].MemSize;\r
- }\r
-\r
- LOG("base = %08x, max = %08x\n", base, max);\r
-\r
- if( base == 0 ) {\r
- // Find a nice space (31 address bits allowed)\r
- base = FindFreeRange( max, 31 );\r
- LOG("new base = %08x\n", base);\r
- if( base == 0 ) return NULL;\r
- baseDiff = base;\r
- }\r
- \r
- // Load Pages\r
- j = 0;\r
- for( i = 0; i < hdr.phentcount; i++ )\r
- {\r
- //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
- LOG("phtab[%i] = {\n", i);\r
- LOG(" .Type = 0x%08x\n", phtab[i].Type);\r
- LOG(" .Offset = 0x%08x\n", phtab[i].Offset);\r
- LOG(" .VAddr = 0x%08x\n", phtab[i].VAddr);\r
- LOG(" .PAddr = 0x%08x\n", phtab[i].PAddr);\r
- LOG(" .FileSize = 0x%08x\n", phtab[i].FileSize);\r
- LOG(" .MemSize = 0x%08x\n", phtab[i].MemSize);\r
- LOG(" .Flags = 0x%08x\n", phtab[i].Flags);\r
- LOG(" .Align = 0x%08x\n", phtab[i].Align);\r
- LOGS(" }\n");\r
- // Get Interpreter Name\r
- if( phtab[i].Type == PT_INTERP )\r
- {\r
- char *tmp;\r
- //if(ret->Interpreter) continue;\r
- tmp = malloc(phtab[i].FileSize);\r
- acess_seek(FD, phtab[i].Offset, ACESS_SEEK_SET);\r
- acess_read(FD, phtab[i].FileSize, tmp);\r
- //ret->Interpreter = Binary_RegInterp(tmp);\r
- LOG("Interpreter '%s'\n", tmp);\r
- free(tmp);\r
- continue;\r
- }\r
- // Ignore non-LOAD types\r
- if(phtab[i].Type != PT_LOAD) continue;\r
- \r
- LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}\n",\r
- i, phtab[i].VAddr+baseDiff, phtab[i].Offset, phtab[i].FileSize);\r
- \r
- addr = phtab[i].VAddr + baseDiff;\r
-\r
- if( AllocateMemory( addr, phtab[i].MemSize ) ) {\r
- fprintf(stderr, "Elf_Load: Unable to map memory at %x (0x%x bytes)\n",\r
- addr, phtab[i].MemSize);\r
- free( phtab );\r
- return NULL;\r
- }\r
- \r
- acess_seek(FD, phtab[i].Offset, ACESS_SEEK_SET);\r
- acess_read(FD, phtab[i].FileSize, PTRMK(void, addr) );\r
- memset( PTRMK(char, addr) + phtab[i].FileSize, 0, phtab[i].MemSize - phtab[i].FileSize );\r
- }\r
- \r
- // Clean Up\r
- free(phtab);\r
- // Return\r
- LEAVE('p', base);\r
- return PTRMK(void, base);\r
-}\r
-\r
-// --- ELF RELOCATION ---\r
-/**\r
- * \brief Relocates a loaded ELF Executable\r
- */\r
-uintptr_t Elf_Relocate(void *Base)\r
-{\r
- Elf32_Ehdr *hdr = Base;\r
- Elf32_Phdr *phtab;\r
- int i, j; // Counters\r
- char *libPath;\r
- uint32_t iRealBase = -1;\r
- uintptr_t iBaseDiff;\r
- int iSegmentCount;\r
- int iSymCount = 0;\r
- Elf32_Rel *rel = NULL;\r
- Elf32_Rela *rela = NULL;\r
- uint32_t *pltgot = NULL;\r
- void *plt = NULL;\r
- uint32_t *ptr;\r
- int relSz=0, relEntSz=8;\r
- int relaSz=0, relaEntSz=8;\r
- int pltSz=0, pltType=0;\r
- Elf32_Dyn *dynamicTab = NULL; // Dynamic Table Pointer\r
- char *dynstrtab = NULL; // .dynamic String Table\r
- Elf32_Sym *dynsymtab = NULL;\r
- int bFailed = 0;\r
- \r
- ENTER("pBase", Base);\r
- LOG("Base = %p\n", Base);\r
- \r
- // Parse Program Header to get Dynamic Table\r
- phtab = Base + hdr->phoff;\r
- iSegmentCount = hdr->phentcount;\r
- for(i = 0; i < iSegmentCount; i ++ )\r
- {\r
- // Determine linked base address\r
- if(phtab[i].Type == PT_LOAD && iRealBase > phtab[i].VAddr)\r
- iRealBase = phtab[i].VAddr;\r
- \r
- // Find Dynamic Section\r
- if(phtab[i].Type == PT_DYNAMIC) {\r
- if(dynamicTab) {\r
- Warning("Elf_Relocate - Multiple PT_DYNAMIC segments\n");\r
- continue;\r
- }\r
- dynamicTab = MKPTR(void, phtab[i].VAddr);\r
- j = i; // Save Dynamic Table ID\r
- break;\r
- }\r
- }\r
- \r
- // Check if a PT_DYNAMIC segement was found\r
- if(!dynamicTab) {\r
- Warning("Elf_Relocate: No PT_DYNAMIC segment in image, returning\n");\r
- LEAVE('x', hdr->entrypoint);\r
- return hdr->entrypoint;\r
- }\r
- \r
- // Page Align real base\r
- iRealBase &= ~0xFFF;\r
- \r
- LOG("dynamicTab = %p\n", dynamicTab);\r
- // Adjust "Real" Base\r
- iBaseDiff = (uintptr_t)Base - iRealBase;\r
- LOG("iBaseDiff = %p\n", (void*)iBaseDiff);\r
- // Adjust Dynamic Table\r
- dynamicTab = PTR( (uintptr_t)dynamicTab + iBaseDiff);\r
- LOG("dynamicTab = %p\n", dynamicTab);\r
-\r
- hdr->entrypoint += iBaseDiff;\r
- \r
- hdr->misc.SymTable = 0;\r
- hdr->misc.HashTable = 0;\r
- \r
- // === Get Symbol table and String Table ===\r
- for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
- {\r
- switch(dynamicTab[j].d_tag)\r
- {\r
- // --- Symbol Table ---\r
- case DT_SYMTAB:\r
- dynamicTab[j].d_val += iBaseDiff;\r
- dynsymtab = PTRMK(void, dynamicTab[j].d_val);\r
- hdr->misc.SymTable = dynamicTab[j].d_val; // Saved in unused bytes of ident\r
- break;\r
- \r
- // --- String Table ---\r
- case DT_STRTAB:\r
- dynamicTab[j].d_val += iBaseDiff;\r
- dynstrtab = PTRMK(void, dynamicTab[j].d_val);\r
- break;\r
- \r
- // --- Hash Table --\r
- case DT_HASH:\r
- dynamicTab[j].d_val += iBaseDiff;\r
- iSymCount = (PTRMK(uint32_t, dynamicTab[j].d_val))[1];\r
- hdr->misc.HashTable = dynamicTab[j].d_val; // Saved in unused bytes of ident\r
- break;\r
- }\r
- }\r
- \r
- LOG("hdr->misc.SymTable = %x, hdr->misc.HashTable = %x",\r
- hdr->misc.SymTable, hdr->misc.HashTable);\r
-\r
-\r
- // Alter Symbols to true base\r
- for(i = 0; i < iSymCount; i ++)\r
- {\r
- dynsymtab[i].nameOfs += (uintptr_t)dynstrtab;\r
- if( dynsymtab[i].shndx == SHN_UNDEF )\r
- {\r
- LOG("Sym '%s' = UNDEF\n", MKPTR(char,dynsymtab[i].name));\r
- }\r
- else\r
- {\r
- dynsymtab[i].value += iBaseDiff;\r
- LOG("Sym '%s' = 0x%x (relocated)\n", MKPTR(char,dynsymtab[i].name), dynsymtab[i].value);\r
- }\r
- }\r
- \r
- // === Add to loaded list (can be imported now) ===\r
- Binary_SetReadyToUse( Base );\r
-\r
- // === Parse Relocation Data ===\r
- for( j = 0; dynamicTab[j].d_tag != DT_NULL; j++)\r
- {\r
- switch(dynamicTab[j].d_tag)\r
- {\r
- // --- Shared Library Name ---\r
- case DT_SONAME:\r
- LOG(".so Name '%s'\n", dynstrtab + dynamicTab[j].d_val);\r
- break;\r
- // --- Needed Library ---\r
- case DT_NEEDED:\r
- libPath = dynstrtab + dynamicTab[j].d_val;\r
- Binary_LoadLibrary(libPath);\r
- break;\r
- // --- PLT/GOT ---\r
- case DT_PLTGOT: pltgot = (void*)(iBaseDiff+dynamicTab[j].d_val); break;\r
- case DT_JMPREL: plt = (void*)(iBaseDiff+dynamicTab[j].d_val); break;\r
- case DT_PLTREL: pltType = dynamicTab[j].d_val; break;\r
- case DT_PLTRELSZ: pltSz = dynamicTab[j].d_val; break;\r
- \r
- // --- Relocation ---\r
- case DT_REL: rel = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
- case DT_RELSZ: relSz = dynamicTab[j].d_val; break;\r
- case DT_RELENT: relEntSz = dynamicTab[j].d_val; break;\r
- \r
- case DT_RELA: rela = (void*)(iBaseDiff + dynamicTab[j].d_val); break;\r
- case DT_RELASZ: relaSz = dynamicTab[j].d_val; break;\r
- case DT_RELAENT: relaEntSz = dynamicTab[j].d_val; break;\r
- }\r
- }\r
- \r
- // Parse Relocation Entries\r
- if(rel && relSz)\r
- {\r
- j = relSz / relEntSz;\r
- for( i = 0; i < j; i++ )\r
- {\r
- ptr = (void*)(iBaseDiff + rel[i].r_offset);\r
- if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, *ptr, dynsymtab, Base) ) {\r
- bFailed = 1;\r
- }\r
- }\r
- }\r
- // Parse Relocation Entries\r
- if(rela && relaSz)\r
- {\r
- j = relaSz / relaEntSz;\r
- for( i = 0; i < j; i++ )\r
- {\r
- ptr = (void*)(iBaseDiff + rela[i].r_offset);\r
- if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, Base) ) {\r
- bFailed = 1;\r
- }\r
- }\r
- }\r
- \r
- // === Process PLT (Procedure Linkage Table) ===\r
- if(plt && pltSz)\r
- {\r
- if(pltType == DT_REL)\r
- {\r
- Elf32_Rel *pltRel = plt;\r
- j = pltSz / sizeof(Elf32_Rel);\r
- LOG("PLT Rel - plt = %p, pltSz = %i (%i ents)\n", plt, pltSz, j);\r
- for(i = 0; i < j; i++)\r
- {\r
- ptr = (void*)(iBaseDiff + pltRel[i].r_offset);\r
- if( !Elf_Int_DoRelocate(pltRel[i].r_info, ptr, *ptr, dynsymtab, Base) ) {\r
- bFailed = 1;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- Elf32_Rela *pltRela = plt;\r
- j = pltSz / sizeof(Elf32_Rela);\r
- LOG("PLT RelA - plt = %p, pltSz = %i (%i ents)\n", plt, pltSz, j);\r
- for(i=0;i<j;i++)\r
- {\r
- ptr = (void*)(iBaseDiff + pltRela[i].r_offset);\r
- if( !Elf_Int_DoRelocate(pltRela[i].r_info, ptr, pltRela[i].r_addend, dynsymtab, Base) ) {\r
- bFailed = 1;\r
- }\r
- }\r
- }\r
- }\r
- \r
- if(bFailed) {\r
- LEAVE('i', 0);\r
- return 0;\r
- }\r
- \r
- LEAVE('x', hdr->entrypoint);\r
- return hdr->entrypoint;\r
-}\r
-\r
-/**\r
- * \fn void Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *base)\r
- * \brief Performs a relocation\r
- * \param r_info Field from relocation entry\r
- * \param ptr Pointer to location of relocation\r
- * \param addend Value to add to symbol\r
- * \param symtab Symbol Table\r
- * \param base Base of loaded binary\r
- */\r
-int Elf_Int_DoRelocate(uint32_t r_info, uint32_t *ptr, uint32_t addend, Elf32_Sym *symtab, void *base)\r
-{\r
- uintptr_t val;\r
- int type = ELF32_R_TYPE(r_info);\r
- int sym = ELF32_R_SYM(r_info);\r
- char *sSymName = PTRMK(char, symtab[sym].name);\r
- \r
- //LogF("Elf_Int_DoRelocate: (r_info=0x%x, ptr=0x%x, addend=0x%x, .., base=0x%x)\n",\r
- // r_info, ptr, addend, base);\r
- \r
- switch( type )\r
- {\r
- // Standard 32 Bit Relocation (S+A)\r
- case R_386_32:\r
- if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
- Warning("Unable to find symbol '%s'", sSymName);\r
- return 0;\r
- }\r
- LOG("%08x R_386_32 *%p += %p('%s')\n", r_info, ptr, (void*)val, sSymName);\r
- *ptr = val + addend;\r
- break;\r
- \r
- // 32 Bit Relocation wrt. Offset (S+A-P)\r
- case R_386_PC32:\r
- if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
- Warning("Unable to find symbol '%s'", sSymName);\r
- return 0;\r
- }\r
- LOG("%08x R_386_PC32 *%p = 0x%x + %p('%s') - %p\n", r_info, ptr, *ptr, (void*)val, sSymName, ptr );\r
- // TODO: Check if it needs the true value of ptr or the compiled value\r
- // NOTE: Testing using true value\r
- *ptr = val + addend - (uintptr_t)ptr;\r
- break;\r
-\r
- // Absolute Value of a symbol (S)\r
- case R_386_GLOB_DAT:\r
- if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
- Warning("Unable to find symbol '%s'", sSymName);\r
- return 0; \r
- }\r
- LOG("%08x R_386_GLOB_DAT *%p = 0x%x(%s)\n", r_info, ptr, (unsigned int)val, sSymName);\r
- *ptr = val;\r
- break;\r
- \r
- // Absolute Value of a symbol (S)\r
- case R_386_JMP_SLOT:\r
- if( !Elf_GetSymbol( base, sSymName, &val ) && !Binary_GetSymbol( sSymName, &val ) ) {\r
- Warning("Unable to find symbol '%s'", sSymName);\r
- return 0;\r
- }\r
- LOG("%08x R_386_JMP_SLOT *%p = 0x%x (%s)\n", r_info, ptr, (unsigned int)val, sSymName);\r
- *ptr = val;\r
- break;\r
-\r
- // Base Address (B+A)\r
- case R_386_RELATIVE:\r
- LOG("%08x R_386_RELATIVE *%p = %p + 0x%x\n", r_info, ptr, base, addend);\r
- *ptr = (uintptr_t)base + addend;\r
- break;\r
- \r
- default:\r
- LOG("Rel %p: 0x%x,%i\n", ptr, sym, type);\r
- break;\r
- }\r
- return 1;\r
-}\r
-\r
-/**\r
- * \fn int Elf_GetSymbol(void *Base, char *name, uintptr_t *ret)\r
- * \brief Get a symbol from the loaded binary\r
- */\r
-int Elf_GetSymbol(void *Base, char *Name, uintptr_t *ret)\r
-{\r
- Elf32_Ehdr *hdr = (void*)Base;\r
- Elf32_Sym *symtab;\r
- int nbuckets = 0;\r
- int iSymCount = 0;\r
- int i;\r
- uint32_t *pBuckets;\r
- uint32_t *pChains;\r
- uint32_t iNameHash;\r
-\r
- if(!Base) return 0;\r
-\r
- pBuckets = PTR(hdr->misc.HashTable);\r
- symtab = PTR(hdr->misc.SymTable);\r
- \r
-// LOG("Base = %p : pBuckets = %p, symtab = %p\n", Base, pBuckets, symtab);\r
- \r
- if(!pBuckets || !symtab)\r
- return 0;\r
- \r
- nbuckets = pBuckets[0];\r
- iSymCount = pBuckets[1];\r
- pBuckets = &pBuckets[2];\r
- pChains = &pBuckets[ nbuckets ];\r
- \r
- // Get hash\r
- iNameHash = Elf_Int_HashString(Name);\r
- iNameHash %= nbuckets;\r
-\r
- // Check Bucket\r
- i = pBuckets[ iNameHash ];\r
- if(symtab[i].shndx != SHN_UNDEF && strcmp(MKPTR(char,symtab[i].name), Name) == 0) {\r
- if(ret) *ret = symtab[ i ].value;\r
- return 1;\r
- }\r
- \r
- // Walk Chain\r
- while(pChains[i] != STN_UNDEF)\r
- {\r
- i = pChains[i];\r
- if(symtab[i].shndx != SHN_UNDEF && strcmp(MKPTR(char,symtab[i].name), Name) == 0) {\r
- if(ret) *ret = symtab[ i ].value;\r
- return 1;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-/**\r
- * \fn uint32_t Elf_Int_HashString(char *str)\r
- * \brief Hash a string in the ELF format\r
- * \param str String to hash\r
- * \return Hash value\r
- */\r
-uint32_t Elf_Int_HashString(char *str)\r
-{\r
- uint32_t h = 0, g;\r
- while(*str)\r
- {\r
- h = (h << 4) + *str++;\r
- if( (g = h & 0xf0000000) )\r
- h ^= g >> 24;\r
- h &= ~g;\r
- }\r
- return h;\r
-}\r
+#include "common.h"
+#define _COMMON_H
+// stops real ld-acess.so common.h being included
+#include "../../Usermode/Libraries/ld-acess.so_src/elf.c"