From 97e48eb598fa9cd87a395e4c072f93b7c77a6f4d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 8 Sep 2011 08:20:26 +0800 Subject: [PATCH] Kernel - Updated ELF loader to support ELF64 --- Kernel/bin/elf.c | 211 ++++++++++++++++++++++++++++++++++++++++------- Kernel/bin/elf.h | 76 ++++++++++++++++- 2 files changed, 255 insertions(+), 32 deletions(-) diff --git a/Kernel/bin/elf.c b/Kernel/bin/elf.c index 73154c14..1ae19560 100644 --- a/Kernel/bin/elf.c +++ b/Kernel/bin/elf.c @@ -2,7 +2,7 @@ * Acess v0.1 * ELF Executable Loader Code */ -#define DEBUG 0 +#define DEBUG 1 #include #include #include "elf.h" @@ -11,7 +11,10 @@ // === 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_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(const char *str); @@ -27,26 +30,164 @@ tBinaryType gELF_Info = { // === CODE === tBinary *Elf_Load(int fp) { - tBinary *ret; - Elf32_Ehdr hdr; - Elf32_Phdr *phtab; - int i, j; - int iLoadCount; - - 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') { + 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"); - LEAVE('n'); 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 Log_Warning("ELF", "File does not contain a program header (phoff == 0)"); #endif @@ -55,19 +196,19 @@ tBinary *Elf_Load(int fp) } // 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 iLoadCount = 0; - LOG("hdr.phentcount = %i", hdr.phentcount); - for( i = 0; i < hdr.phentcount; i++ ) + LOG("Header->phentcount = %i", Header->phentcount); + for( i = 0; i < Header->phentcount; i++ ) { // Ignore Non-LOAD types if(phtab[i].Type != PT_LOAD) @@ -81,14 +222,14 @@ tBinary *Elf_Load(int fp) // Allocate Information Structure 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->NumSections = iLoadCount; ret->Interpreter = NULL; // Load Pages j = 0; - for( i = 0; i < hdr.phentcount; i++ ) + for( i = 0; i < Header->phentcount; i++ ) { //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type); LOG("phtab[%i] = {", i); @@ -107,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); @@ -143,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; @@ -197,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 diff --git a/Kernel/bin/elf.h b/Kernel/bin/elf.h index b038766b..13b5373f 100644 --- a/Kernel/bin/elf.h +++ b/Kernel/bin/elf.h @@ -5,6 +5,30 @@ #ifndef _BIN_ELF_H #define _BIN_ELF_H +typedef Uint16 Elf64_Half; +typedef Uint32 Elf64_Word; +typedef Uint64 Elf64_Addr; +typedef Uint64 Elf64_Off; +typedef Uint64 Elf64_Xword; + +enum e_ident_values +{ + EI_MAG0, + EI_MAG1, + EI_MAG2, + EI_MAG3, + EI_CLASS, + EI_DATA, + EI_VERSION, + EI_OSABI, + EI_ABIVERSION, + EI_PAD, + EI_NIDENT = 16, +}; + +#define ELFCLASS32 1 +#define ELFCLASS64 2 + /** * \brief ELF File Header */ @@ -34,6 +58,24 @@ struct sElf32_Ehdr Uint16 shstrindex; //!< Section Header String Table Index } __attribute__ ((packed)); +typedef struct +{ + unsigned char e_ident[16]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + /** * \brief Executable Types */ @@ -54,10 +96,10 @@ enum eElf32_ExecTypes */ #define SHN_UNDEF 0 //!< Undefined Section #define SHN_LORESERVE 0xFF00 //!< Low Reserved -#define SHN_LOPROC 0xFF00 //!< Low Impl Defined -#define SHN_HIPROC 0xFF1F //!< High Impl Defined -#define SHN_ABS 0xFFF1 //!< Absolute Address (Base: 0, Size: -1) -#define SHN_COMMON 0xFFF2 //!< Common +#define SHN_LOPROC 0xFF00 //!< Low Impl Defined +#define SHN_HIPROC 0xFF1F //!< High Impl Defined +#define SHN_ABS 0xFFF1 //!< Absolute Address (Base: 0, Size: -1) +#define SHN_COMMON 0xFFF2 //!< Common #define SHN_HIRESERVE 0xFFFF //!< High Reserved //! \} @@ -103,6 +145,20 @@ struct sElf32_Shent { Uint32 entsize; } __attribute__ ((packed)); //sizeof = 40 +typedef struct +{ + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + struct elf_sym_s { union { Uint32 nameOfs; @@ -139,6 +195,18 @@ struct sElf32_Phdr { Uint32 Align; } __attribute__ ((packed)); +typedef struct +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + #define PF_X 1 #define PF_W 2 #define PF_R 4 -- 2.20.1