X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fbin%2Felf.c;h=1ae19560eab2c6a64413f6bc9cc9a7fd25274a70;hb=97e48eb598fa9cd87a395e4c072f93b7c77a6f4d;hp=90a092f63736f7f876f80f6f3353ac0948327bd5;hpb=630e15108b5938d3443acdbaa58b6461fb06dac3;p=tpg%2Facess2.git diff --git a/Kernel/bin/elf.c b/Kernel/bin/elf.c index 90a092f6..1ae19560 100644 --- a/Kernel/bin/elf.c +++ b/Kernel/bin/elf.c @@ -2,20 +2,22 @@ * Acess v0.1 * ELF Executable Loader Code */ -#define DEBUG 0 +#define DEBUG 1 #include #include #include "elf.h" #define DEBUG_WARN 1 - // === PROTOTYPES === tBinary *Elf_Load(int fp); +tBinary *Elf_Load64(int fp, Elf64_Ehdr *hdr); +tBinary *Elf_Load32(int fp, Elf32_Ehdr *hdr); int Elf_Relocate(void *Base); - int Elf_GetSymbol(void *Base, char *Name, Uint *ret); + int Elf_Relocate32(void *Base); + int Elf_GetSymbol(void *Base, const char *Name, Uint *ret); int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symtab, Uint base); -Uint Elf_Int_HashString(char *str); +Uint Elf_Int_HashString(const char *str); // === GLOBALS === tBinaryType gELF_Info = { @@ -28,71 +30,207 @@ tBinaryType gELF_Info = { // === CODE === tBinary *Elf_Load(int fp) { - tBinary *ret; - Elf32_Ehdr hdr; - Elf32_Phdr *phtab; - int i, j, k; - int iPageCount; - int count; - - ENTER("xfp", fp); + Elf64_Ehdr hdr; // Read ELF Header VFS_Read(fp, sizeof(hdr), &hdr); // Check the file type - if(hdr.ident[0] != 0x7F || hdr.ident[1] != 'E' || hdr.ident[2] != 'L' || hdr.ident[3] != 'F') { - Warning("Non-ELF File was passed to the ELF loader\n"); - LEAVE('n'); + if(hdr.e_ident[0] != 0x7F || hdr.e_ident[1] != 'E' || hdr.e_ident[2] != 'L' || hdr.e_ident[3] != 'F') { + Log_Warning("ELF", "Non-ELF File was passed to the ELF loader"); return NULL; } + + switch(hdr.e_ident[4]) // EI_CLASS + { + case ELFCLASS32: + return Elf_Load32(fp, (Elf32_Ehdr*)&hdr); + case ELFCLASS64: + return Elf_Load64(fp, &hdr); + default: + Log_Warning("ELF", "Unknown EI_CLASS value %i", hdr.e_ident[4]); + return NULL; + } +} + +tBinary *Elf_Load64(int FD, Elf64_Ehdr *Header) +{ + tBinary *ret; + Elf64_Phdr phtab[Header->e_phnum]; + int nLoadSegments; + int i, j; + + // Sanity check + if( Header->e_phoff == 0 ) + { + Log_Warning("ELF", "No program header, panic!"); + return NULL; + } + if( Header->e_shentsize != sizeof(Elf64_Shdr) ) { + Log_Warning("ELF", "Header gives shentsize as %i, my type is %i", + Header->e_shentsize, sizeof(Elf64_Shdr) ); + } + if( Header->e_phentsize != sizeof(Elf64_Phdr) ) { + Log_Warning("ELF", "Header gives phentsize as %i, my type is %i", + Header->e_phentsize, sizeof(Elf64_Phdr) ); + } + + LOG("Header = {"); + LOG(" e_ident = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + Header->e_ident[0], Header->e_ident[1], Header->e_ident[2], Header->e_ident[3], + Header->e_ident[4], Header->e_ident[5], Header->e_ident[6], Header->e_ident[7], + Header->e_ident[8], Header->e_ident[9], Header->e_ident[10], Header->e_ident[11], + Header->e_ident[12], Header->e_ident[13], Header->e_ident[14], Header->e_ident[15] + ); + LOG(" e_type = %i", Header->e_type); + LOG(" e_machine = %i", Header->e_machine); + LOG(" e_version = %i", Header->e_version); + LOG(" e_entry = 0x%llx", Header->e_entry); + LOG(" e_phoff = 0x%llx", Header->e_phoff); + LOG(" e_shoff = 0x%llx", Header->e_shoff); + LOG(" e_flags = 0x%x", Header->e_flags); + LOG(" e_ehsize = %i", Header->e_ehsize); + LOG(" e_phentsize = %i", Header->e_phentsize); + LOG(" e_phnum = %i", Header->e_phnum); + LOG(" e_shentsize = %i", Header->e_shentsize); + LOG(" e_shnum = %i", Header->e_shnum); + LOG(" e_shstrndx = %i", Header->e_shstrndx); + LOG("}"); + + // Load Program Header table + VFS_Seek(FD, Header->e_phoff, SEEK_SET); + VFS_Read(FD, sizeof(Elf64_Phdr)*Header->e_phnum, phtab); + + // Count load segments + nLoadSegments = 0; + for( i = 0; i < Header->e_phnum; i ++ ) + { + if( phtab[i].p_type != PT_LOAD ) continue ; + nLoadSegments ++; + } + // Allocate Information Structure + ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*nLoadSegments ); + // Fill Info Struct + ret->Entry = Header->e_entry; + ret->Base = -1; // Set Base to maximum value + ret->NumSections = nLoadSegments; + ret->Interpreter = NULL; + + j = 0; // LoadSections[] index + for( i = 0; i < Header->e_phnum; i ++ ) + { + LOG("phtab[%i] = {", i); + LOG(" .p_type = %i", phtab[i].p_type); + LOG(" .p_flags = 0x%x", phtab[i].p_flags); + LOG(" .p_offset = 0x%llx", phtab[i].p_offset); + LOG(" .p_vaddr = 0x%llx", phtab[i].p_vaddr); + LOG(" .p_paddr = 0x%llx", phtab[i].p_paddr); + LOG(" .p_filesz = 0x%llx", phtab[i].p_filesz); + LOG(" .p_memsz = 0x%llx", phtab[i].p_memsz); + LOG(" .p_align = 0x%llx", phtab[i].p_align); + LOG("}"); + + // Get Interpreter Name + if( phtab[i].p_type == PT_INTERP ) + { + char *tmp; + if(ret->Interpreter) continue; + tmp = malloc(phtab[i].p_filesz); + VFS_Seek(FD, phtab[i].p_offset, 1); + VFS_Read(FD, phtab[i].p_filesz, tmp); + ret->Interpreter = Binary_RegInterp(tmp); + LOG("Interpreter '%s'", tmp); + free(tmp); + continue; + } + + if( phtab[i].p_type != PT_LOAD ) continue ; + + // Find the executable base + if( phtab[i].p_vaddr < ret->Base ) ret->Base = phtab[i].p_vaddr; + + ret->LoadSections[j].Offset = phtab[i].p_offset; + ret->LoadSections[j].Virtual = phtab[i].p_vaddr; + ret->LoadSections[j].FileSize = phtab[i].p_filesz; + ret->LoadSections[j].MemSize = phtab[i].p_memsz; + + ret->LoadSections[j].Flags = 0; + if( !(phtab[i].p_flags & PF_W) ) + ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO; + if( phtab[i].p_flags & PF_X ) + ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC; + j ++; + } + + return ret; +} + +tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header) +{ + tBinary *ret; + Elf32_Phdr *phtab; + int i, j; + int iLoadCount; + + ENTER("xFD", FD); + + // Check architecture with current CPU + // - TODO: Support kernel level emulation + #if ARCH_IS_x86 + if( Header->machine != EM_386 ) + { + Log_Warning("ELF", "Unknown architecure on ELF-32"); + LEAVE_RET('n'); + return NULL; + } + #endif + // Check for a program header - if(hdr.phoff == 0) { + if(Header->phoff == 0) { #if DEBUG_WARN - Warning("ELF File does not contain a program header\n"); + Log_Warning("ELF", "File does not contain a program header (phoff == 0)"); #endif LEAVE('n'); return NULL; } // Read Program Header Table - phtab = malloc( sizeof(Elf32_Phdr) * hdr.phentcount ); + phtab = malloc( sizeof(Elf32_Phdr) * Header->phentcount ); if( !phtab ) { LEAVE('n'); return NULL; } - LOG("hdr.phoff = 0x%08x", hdr.phoff); - VFS_Seek(fp, hdr.phoff, SEEK_SET); - VFS_Read(fp, sizeof(Elf32_Phdr)*hdr.phentcount, phtab); + LOG("hdr.phoff = 0x%08x", Header->phoff); + VFS_Seek(FD, Header->phoff, SEEK_SET); + VFS_Read(FD, sizeof(Elf32_Phdr)*Header->phentcount, phtab); // Count Pages - iPageCount = 0; - LOG("hdr.phentcount = %i", hdr.phentcount); - for( i = 0; i < hdr.phentcount; i++ ) + iLoadCount = 0; + LOG("Header->phentcount = %i", Header->phentcount); + for( i = 0; i < Header->phentcount; i++ ) { // Ignore Non-LOAD types if(phtab[i].Type != PT_LOAD) continue; - iPageCount += ((phtab[i].VAddr&0xFFF) + phtab[i].MemSize + 0xFFF) >> 12; + iLoadCount ++; LOG("phtab[%i] = {VAddr:0x%x, MemSize:0x%x}", i, phtab[i].VAddr, phtab[i].MemSize); } - LOG("iPageCount = %i", iPageCount); + LOG("iLoadCount = %i", iLoadCount); // Allocate Information Structure - ret = malloc( sizeof(tBinary) + sizeof(tBinaryPage)*iPageCount ); + ret = malloc( sizeof(tBinary) + sizeof(tBinarySection)*iLoadCount ); // Fill Info Struct - ret->Entry = hdr.entrypoint; + ret->Entry = Header->entrypoint; ret->Base = -1; // Set Base to maximum value - ret->NumPages = iPageCount; + ret->NumSections = iLoadCount; ret->Interpreter = NULL; // Load Pages j = 0; - for( i = 0; i < hdr.phentcount; i++ ) + for( i = 0; i < Header->phentcount; i++ ) { - int lastSize; //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type); LOG("phtab[%i] = {", i); LOG(" .Type = 0x%08x", phtab[i].Type); @@ -110,8 +248,8 @@ tBinary *Elf_Load(int fp) char *tmp; if(ret->Interpreter) continue; tmp = malloc(phtab[i].FileSize); - VFS_Seek(fp, phtab[i].Offset, 1); - VFS_Read(fp, phtab[i].FileSize, tmp); + VFS_Seek(FD, phtab[i].Offset, 1); + VFS_Read(FD, phtab[i].FileSize, tmp); ret->Interpreter = Binary_RegInterp(tmp); LOG("Interpreter '%s'", tmp); free(tmp); @@ -126,126 +264,17 @@ tBinary *Elf_Load(int fp) LOG("phtab[%i] = {VAddr:0x%x,Offset:0x%x,FileSize:0x%x}", i, phtab[i].VAddr, phtab[i].Offset, phtab[i].FileSize); - //if( (phtab[i].FileSize & 0xFFF) < 0x1000 - (phtab[i].VAddr & 0xFFF) ) - // lastSize = phtab[i].FileSize; - //else - lastSize = (phtab[i].FileSize & 0xFFF) + (phtab[i].VAddr & 0xFFF); - //lastSize &= 0xFFF; - - //LOG("lastSize = 0x%x", lastSize); - - lastSize = phtab[i].FileSize; - - // Get Pages - count = ( (phtab[i].VAddr&0xFFF) + phtab[i].FileSize + 0xFFF) >> 12; - for( k = 0; k < count; k ++ ) - { - ret->Pages[j+k].Virtual = phtab[i].VAddr + (k<<12); - ret->Pages[j+k].Physical = phtab[i].Offset + (k<<12); // Store the offset in the physical address - if(k != 0) { - ret->Pages[j+k].Physical -= ret->Pages[j+k].Virtual&0xFFF; - ret->Pages[j+k].Virtual &= ~0xFFF; - } - if(k == count-1) - ret->Pages[j+k].Size = lastSize; // Byte count in page - else if(k == 0) - ret->Pages[j+k].Size = 4096 - (phtab[i].VAddr&0xFFF); - else - ret->Pages[j+k].Size = 4096; - LOG("ret->Pages[%i].Size = 0x%x", j+k, ret->Pages[j+k].Size); - ret->Pages[j+k].Flags = 0; - lastSize -= ret->Pages[j+k].Size; - } - count = (phtab[i].MemSize + 0xFFF) >> 12; - for(;kPages[j+k].Virtual = phtab[i].VAddr + (k<<12); - ret->Pages[j+k].Physical = -1; // -1 = Fill with zeros - if(k != 0) ret->Pages[j+k].Virtual &= ~0xFFF; - if(k == count-1 && (phtab[i].MemSize & 0xFFF)) - ret->Pages[j+k].Size = phtab[i].MemSize & 0xFFF; // Byte count in page - else - ret->Pages[j+k].Size = 4096; - ret->Pages[j+k].Flags = 0; - LOG("%i - 0x%x => 0x%x - 0x%x", j+k, - ret->Pages[j+k].Physical, ret->Pages[j+k].Virtual, ret->Pages[j+k].Size); - } - j += count; - } - - #if 0 - LOG("Cleaning up overlaps"); - // Clear up Overlaps - { - struct { - Uint V; - Uint P; - Uint S; - Uint F; - } *tmpRgns; - count = j; - tmpRgns = malloc(sizeof(*tmpRgns)*count); - // Copy - for(i=0;iPages[i].Virtual; - tmpRgns[i].P = ret->Pages[i].Physical; - tmpRgns[i].S = ret->Pages[i].Size; - tmpRgns[i].F = ret->Pages[i].Flags; - } - // Compact - for(i=1,j=0; i < count; i++) - { - if( tmpRgns[j].F == tmpRgns[i].F - && tmpRgns[j].V + tmpRgns[j].S == tmpRgns[i].V - && ((tmpRgns[j].P == -1 && tmpRgns[i].P == -1) - || (tmpRgns[j].P + tmpRgns[j].S == tmpRgns[i].P)) ) - { - tmpRgns[j].S += tmpRgns[i].S; - } else { - j ++; - tmpRgns[j].V = tmpRgns[i].V; - tmpRgns[j].P = tmpRgns[i].P; - tmpRgns[j].F = tmpRgns[i].F; - tmpRgns[j].S = tmpRgns[i].S; - } - } + ret->LoadSections[j].Offset = phtab[i].Offset; + ret->LoadSections[j].FileSize = phtab[i].FileSize; + ret->LoadSections[j].Virtual = phtab[i].VAddr; + ret->LoadSections[j].MemSize = phtab[i].MemSize; + ret->LoadSections[j].Flags = 0; + if( !(phtab[i].Flags & PF_W) ) + ret->LoadSections[j].Flags |= BIN_SECTFLAG_RO; + if( phtab[i].Flags & PF_X ) + ret->LoadSections[j].Flags |= BIN_SECTFLAG_EXEC; j ++; - // Count - count = j; j = 0; - for(i=0;i 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S); - tmpRgns[i].S += tmpRgns[i].V & 0xFFF; - if(tmpRgns[i].P != -1) tmpRgns[i].P -= tmpRgns[i].V & 0xFFF; - tmpRgns[i].V &= ~0xFFF; - j += (tmpRgns[i].S + 0xFFF) >> 12; - //LogF(" Elf_Load: %i - 0x%x => 0x%x - 0x%x\n", i, tmpRgns[i].P, tmpRgns[i].V, tmpRgns[i].S); - } - // Reallocate - ret = realloc( ret, sizeof(tBinary) + 3*sizeof(Uint)*j ); - if(!ret) { - Warning("BIN", "ElfLoad: Unable to reallocate return structure"); - return NULL; - } - ret->NumPages = j; - // Split - k = 0; - for(i=0;i> 12; j++,k++ ) { - ret->Pages[k].Flags = tmpRgns[i].F; - ret->Pages[k].Virtual = tmpRgns[i].V + (j<<12); - if(tmpRgns[i].P != -1) { - ret->Pages[k].Physical = tmpRgns[i].P + (j<<12); - } else - ret->Pages[k].Physical = -1; - ret->Pages[k].Size = tmpRgns[i].S - (j << 12); - // Clamp to page size - if(ret->Pages[k].Size > 0x1000) ret->Pages[k].Size = 0x1000; - } - } - // Free Temp - free(tmpRgns); } - #endif // Clean Up free(phtab); @@ -255,12 +284,26 @@ tBinary *Elf_Load(int fp) } // --- ELF RELOCATION --- -// Taken from 'ld-acess.so' -/** - \fn int Elf_Relocate(void *Base) - \brief Relocates a loaded ELF Executable -*/ int Elf_Relocate(void *Base) +{ + Elf64_Ehdr *hdr = Base; + + switch( hdr->e_ident[EI_CLASS] ) + { + case ELFCLASS32: + return Elf_Relocate32(Base); + case ELFCLASS64: + return 0; + default: + return 1; + } +} + + +/** + * \brief Relocates a loaded ELF Executable + */ +int Elf_Relocate32(void *Base) { Elf32_Ehdr *hdr = Base; Elf32_Phdr *phtab; @@ -286,7 +329,7 @@ int Elf_Relocate(void *Base) ENTER("pBase", Base); // Parse Program Header to get Dynamic Table - phtab = Base + hdr->phoff; + phtab = (void *)( (tVAddr)Base + hdr->phoff ); iSegmentCount = hdr->phentcount; for(i = 0; i < iSegmentCount; i ++ ) { @@ -309,8 +352,8 @@ int Elf_Relocate(void *Base) // Check if a PT_DYNAMIC segement was found if(!dynamicTab) { Log_Warning("ELF", "Elf_Relocate: No PT_DYNAMIC segment in image, returning\n"); - LEAVE('x', hdr->entrypoint); - return hdr->entrypoint; + LEAVE('x', 0); + return 0; } // Page Align real base @@ -348,6 +391,10 @@ int Elf_Relocate(void *Base) } } + if( !dynsymtab && iSymCount > 0 ) { + Log_Warning("ELF", "Elf_Relocate: No Dynamic symbol table, but count >0"); + return 0; + } // Alter Symbols to true base for(i = 0; i < iSymCount; i ++) @@ -410,7 +457,7 @@ int Elf_Relocate(void *Base) for( i = 0; i < j; i++ ) { ptr = (void*)(iBaseDiff + rela[i].r_offset); - if( !Elf_Int_DoRelocate(rel[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) { + if( !Elf_Int_DoRelocate(rela[i].r_info, ptr, rela[i].r_addend, dynsymtab, (Uint)Base) ) { bFailed = 1; } } @@ -452,8 +499,8 @@ int Elf_Relocate(void *Base) return 0; } - LEAVE('x', hdr->entrypoint); - return hdr->entrypoint; + LEAVE('x', 1); + return 1; } /** @@ -529,10 +576,10 @@ int Elf_Int_DoRelocate(Uint r_info, Uint32 *ptr, Uint32 addend, Elf32_Sym *symta } /** - * \fn int Elf_GetSymbol(void *Base, char *name, Uint *ret) + * \fn int Elf_GetSymbol(void *Base, const char *name, Uint *ret) * \brief Get a symbol from the loaded binary */ -int Elf_GetSymbol(void *Base, char *Name, Uint *ret) +int Elf_GetSymbol(void *Base, const char *Name, Uint *ret) { Elf32_Ehdr *hdr = (void*)Base; Elf32_Sym *symtab; @@ -582,7 +629,7 @@ int Elf_GetSymbol(void *Base, char *Name, Uint *ret) * \param str String to hash * \return Hash value */ -Uint Elf_Int_HashString(char *str) +Uint Elf_Int_HashString(const char *str) { Uint h = 0, g; while(*str)