From b84d9d26d0cb9f92e5dcbd592ff94936770af3d2 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 20 May 2013 21:09:18 +0200 Subject: [PATCH] Update sortix/elf.cpp to current coding conventions. --- sortix/elf.cpp | 458 +++++++++++++++++++++++++------------------------ sortix/elf.h | 305 ++++++++++++++++---------------- 2 files changed, 390 insertions(+), 373 deletions(-) diff --git a/sortix/elf.cpp b/sortix/elf.cpp index 1cd36d54..3e92ee03 100644 --- a/sortix/elf.cpp +++ b/sortix/elf.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -22,232 +22,248 @@ *******************************************************************************/ -#include -#include -#include +#include + #include #include +#include +#include #include -#include "elf.h" + +#include + +#include #include -#include +#include -namespace Sortix +#include "elf.h" + +namespace Sortix { +namespace ELF { + +static int ToProgramSectionType(int flags) { - namespace ELF + switch ( flags & (PF_X | PF_R | PF_W) ) { - int ToProgramSectionType(int flags) - { - switch ( flags & (PF_X | PF_R | PF_W) ) - { - case 0: - return SEG_NONE; - case PF_X: - case PF_X | PF_R: - case PF_X | PF_W: - case PF_X | PF_R | PF_W: - return SEG_TEXT; - case PF_R: - case PF_W: - case PF_R | PF_W: - default: - return SEG_DATA; - } - } - - addr_t Construct32(Process* process, const void* file, size_t filelen) - { - if ( filelen < sizeof(Header32) ) { return 0; } - const Header32* header = (const Header32*) file; - - // Check for little endian. - if ( header->dataencoding != DATA2LSB ) { return 0; } - if ( header->version != CURRENTVERSION ) { return 0; } - - addr_t entry = header->entry; - - // Find the location of the program headers. - addr_t phtbloffset = header->programheaderoffset; - if ( filelen < phtbloffset ) { return 0; } - addr_t phtblpos = ((addr_t) file) + phtbloffset; - size_t phsize = header->programheaderentrysize; - const ProgramHeader32* phtbl = (const ProgramHeader32*) phtblpos; - - // Validate that all program headers are present. - uint16_t numprogheaders = header->numprogramheaderentries; - size_t neededfilelen = phtbloffset + numprogheaders * phsize; - if ( filelen < neededfilelen ) { return 0; } - - // Prepare the process for execution (clean up address space, etc.) - process->ResetForExecute(); - - // Flush the TLB such that no stale information from the last - // address space is used when creating the new one. - Memory::Flush(); - - // Create all the segments in the final process. - // TODO: Handle errors on bad/malicious input or out-of-mem! - for ( uint16_t i = 0; i < numprogheaders; i++ ) - { - const ProgramHeader32* pht = &(phtbl[i]); - if ( pht->type != PT_LOAD ) { continue; } - addr_t virtualaddr = pht->virtualaddr; - addr_t mapto = Page::AlignDown(virtualaddr); - addr_t mapbytes = virtualaddr - mapto + pht->memorysize; - assert(pht->offset % pht->align == virtualaddr % pht->align); - assert(pht->offset + pht->filesize < filelen); - assert(pht->filesize <= pht->memorysize); - - ProcessSegment* segment = new ProcessSegment; - if ( segment == NULL ) { return 0; } - segment->position = mapto; - segment->size = Page::AlignUp(mapbytes); - segment->type = ToProgramSectionType(pht->flags); - - int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE; - if ( pht->flags & PF_X ) { prot |= PROT_EXEC; } - if ( pht->flags & PF_R ) { prot |= PROT_READ; } - if ( pht->flags & PF_W ) { prot |= PROT_WRITE; } - - if ( segment->Intersects(process->segments) ) - { - delete segment; - return 0; - } - - if ( !Memory::MapRange(mapto, mapbytes, prot)) - { - // TODO: Memory leak of segment? - return 0; - } - - // Insert our newly allocated memory into the processes segment - // list such that it can be reclaimed later. - if ( process->segments ) { process->segments->prev = segment; } - segment->next = process->segments; - process->segments = segment; - - // Copy as much data as possible and memset the rest to 0. - uint8_t* memdest = (uint8_t*) virtualaddr; - uint8_t* memsource = (uint8_t*) ( ((addr_t)file) + pht->offset); - memcpy(memdest, memsource, pht->filesize); - memset(memdest + pht->filesize, 0, pht->memorysize - pht->filesize); - } - - return entry; - } - - addr_t Construct64(Process* process, const void* file, size_t filelen) - { - #ifndef PLATFORM_X64 - (void) process; - (void) file; - (void) filelen; - errno = ENOEXEC; - return 0; - #else - if ( filelen < sizeof(Header64) ) { return 0; } - const Header64* header = (const Header64*) file; - - // Check for little endian. - if ( header->dataencoding != DATA2LSB ) { return 0; } - if ( header->version != CURRENTVERSION ) { return 0; } - - addr_t entry = header->entry; - - // Find the location of the program headers. - addr_t phtbloffset = header->programheaderoffset; - if ( filelen < phtbloffset ) { return 0; } - addr_t phtblpos = ((addr_t) file) + phtbloffset; - size_t phsize = header->programheaderentrysize; - const ProgramHeader64* phtbl = (const ProgramHeader64*) phtblpos; - - // Validate that all program headers are present. - uint16_t numprogheaders = header->numprogramheaderentries; - size_t neededfilelen = phtbloffset + numprogheaders * phsize; - if ( filelen < neededfilelen ) { return 0; } - - // Prepare the process for execution (clean up address space, etc.) - process->ResetForExecute(); - - // Flush the TLB such that no stale information from the last - // address space is used when creating the new one. - Memory::Flush(); - - // Create all the segments in the final process. - // TODO: Handle errors on bad/malicious input or out-of-mem! - for ( uint16_t i = 0; i < numprogheaders; i++ ) - { - const ProgramHeader64* pht = &(phtbl[i]); - if ( pht->type != PT_LOAD ) { continue; } - addr_t virtualaddr = pht->virtualaddr; - addr_t mapto = Page::AlignDown(virtualaddr); - addr_t mapbytes = virtualaddr - mapto + pht->memorysize; - assert(pht->offset % pht->align == virtualaddr % pht->align); - assert(pht->offset + pht->filesize < filelen); - assert(pht->filesize <= pht->memorysize); - - ProcessSegment* segment = new ProcessSegment; - if ( segment == NULL ) { return 0; } - segment->position = mapto; - segment->size = Page::AlignUp(mapbytes); - segment->type = ToProgramSectionType(pht->flags); - - int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE; - if ( pht->flags & PF_X ) { prot |= PROT_EXEC; } - if ( pht->flags & PF_R ) { prot |= PROT_READ; } - if ( pht->flags & PF_W ) { prot |= PROT_WRITE; } - - if ( segment->Intersects(process->segments) ) - { - delete segment; - return 0; - } - - if ( !Memory::MapRange(mapto, mapbytes, prot)) - { - // TODO: Memory leak of segment? - return 0; - } - - // Insert our newly allocated memory into the processes segment - // list such that it can be reclaimed later. - if ( process->segments ) { process->segments->prev = segment; } - segment->next = process->segments; - process->segments = segment; - - // Copy as much data as possible and memset the rest to 0. - uint8_t* memdest = (uint8_t*) virtualaddr; - uint8_t* memsource = (uint8_t*) ( ((addr_t)file) + pht->offset); - memcpy(memdest, memsource, pht->filesize); - memset(memdest + pht->filesize, 0, pht->memorysize - pht->filesize); - } - - return entry; - #endif - } - - addr_t Construct(Process* process, const void* file, size_t filelen) - { - if ( filelen < sizeof(Header) ) { errno = ENOEXEC; return 0; } - const Header* header = (const Header*) file; - - if ( !(header->magic[0] == 0x7F && header->magic[1] == 'E' && - header->magic[2] == 'L' && header->magic[3] == 'F' ) ) - { - errno = ENOEXEC; - return 0; - } - - switch ( header->fileclass ) - { - case CLASS32: - return Construct32(process, file, filelen); - case CLASS64: - return Construct64(process, file, filelen); - default: - return 0; - } - } + case 0: + return SEG_NONE; + case PF_X: + case PF_X | PF_R: + case PF_X | PF_W: + case PF_X | PF_R | PF_W: + return SEG_TEXT; + case PF_R: + case PF_W: + case PF_R | PF_W: + default: + return SEG_DATA; } } + +addr_t Construct32(Process* process, const void* file, size_t filelen) +{ + if ( filelen < sizeof(Header32) ) + return 0; + const Header32* header = (const Header32*) file; + + // Check for little endian. + if ( header->dataencoding != DATA2LSB ) + return 0; + if ( header->version != CURRENTVERSION ) + return 0; + + addr_t entry = header->entry; + + // Find the location of the program headers. + addr_t phtbloffset = header->programheaderoffset; + if ( filelen < phtbloffset ) + return 0; + addr_t phtblpos = ((addr_t) file) + phtbloffset; + size_t phsize = header->programheaderentrysize; + const ProgramHeader32* phtbl = (const ProgramHeader32*) phtblpos; + + // Validate that all program headers are present. + uint16_t numprogheaders = header->numprogramheaderentries; + size_t neededfilelen = phtbloffset + numprogheaders * phsize; + if ( filelen < neededfilelen ) + return 0; + + // Prepare the process for execution (clean up address space, etc.) + process->ResetForExecute(); + + // Flush the TLB such that no stale information from the last + // address space is used when creating the new one. + Memory::Flush(); + + // Create all the segments in the final process. + // TODO: Handle errors on bad/malicious input or out-of-mem! + for ( uint16_t i = 0; i < numprogheaders; i++ ) + { + const ProgramHeader32* pht = &(phtbl[i]); + if ( pht->type != PT_LOAD ) + continue; + addr_t virtualaddr = pht->virtualaddr; + addr_t mapto = Page::AlignDown(virtualaddr); + addr_t mapbytes = virtualaddr - mapto + pht->memorysize; + assert(pht->offset % pht->align == virtualaddr % pht->align); + assert(pht->offset + pht->filesize < filelen); + assert(pht->filesize <= pht->memorysize); + + ProcessSegment* segment = new ProcessSegment; + if ( segment == NULL ) + return 0; + segment->position = mapto; + segment->size = Page::AlignUp(mapbytes); + segment->type = ToProgramSectionType(pht->flags); + + int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE; + if ( pht->flags & PF_X ) { prot |= PROT_EXEC; } + if ( pht->flags & PF_R ) { prot |= PROT_READ; } + if ( pht->flags & PF_W ) { prot |= PROT_WRITE; } + + if ( segment->Intersects(process->segments) ) + { + delete segment; + return 0; + } + + if ( !Memory::MapRange(mapto, mapbytes, prot) ) + // TODO: Memory leak of segment? + return 0; + + // Insert our newly allocated memory into the processes segment + // list such that it can be reclaimed later. + if ( process->segments ) + process->segments->prev = segment; + segment->next = process->segments; + process->segments = segment; + + // Copy as much data as possible and memset the rest to 0. + uint8_t* memdest = (uint8_t*) virtualaddr; + uint8_t* memsource = (uint8_t*) (((addr_t)file) + pht->offset); + memcpy(memdest, memsource, pht->filesize); + memset(memdest + pht->filesize, 0, pht->memorysize - pht->filesize); + } + + return entry; +} + +addr_t Construct64(Process* process, const void* file, size_t filelen) +{ +#ifndef PLATFORM_X64 + (void) process; + (void) file; + (void) filelen; + return errno = ENOEXEC, 0; +#else + if ( filelen < sizeof(Header64) ) + return 0; + const Header64* header = (const Header64*) file; + + // Check for little endian. + if ( header->dataencoding != DATA2LSB ) + return 0; + if ( header->version != CURRENTVERSION ) + return 0; + + addr_t entry = header->entry; + + // Find the location of the program headers. + addr_t phtbloffset = header->programheaderoffset; + if ( filelen < phtbloffset ) + return 0; + addr_t phtblpos = ((addr_t) file) + phtbloffset; + size_t phsize = header->programheaderentrysize; + const ProgramHeader64* phtbl = (const ProgramHeader64*) phtblpos; + + // Validate that all program headers are present. + uint16_t numprogheaders = header->numprogramheaderentries; + size_t neededfilelen = phtbloffset + numprogheaders * phsize; + if ( filelen < neededfilelen ) + return 0; + + // Prepare the process for execution (clean up address space, etc.) + process->ResetForExecute(); + + // Flush the TLB such that no stale information from the last + // address space is used when creating the new one. + Memory::Flush(); + + // Create all the segments in the final process. + // TODO: Handle errors on bad/malicious input or out-of-mem! + for ( uint16_t i = 0; i < numprogheaders; i++ ) + { + const ProgramHeader64* pht = &(phtbl[i]); + if ( pht->type != PT_LOAD ) + continue; + addr_t virtualaddr = pht->virtualaddr; + addr_t mapto = Page::AlignDown(virtualaddr); + addr_t mapbytes = virtualaddr - mapto + pht->memorysize; + assert(pht->offset % pht->align == virtualaddr % pht->align); + assert(pht->offset + pht->filesize < filelen); + assert(pht->filesize <= pht->memorysize); + + ProcessSegment* segment = new ProcessSegment; + if ( segment == NULL ) + return 0; + segment->position = mapto; + segment->size = Page::AlignUp(mapbytes); + segment->type = ToProgramSectionType(pht->flags); + + int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE; + if ( pht->flags & PF_X ) { prot |= PROT_EXEC; } + if ( pht->flags & PF_R ) { prot |= PROT_READ; } + if ( pht->flags & PF_W ) { prot |= PROT_WRITE; } + + if ( segment->Intersects(process->segments) ) + { + delete segment; + return 0; + } + + if ( !Memory::MapRange(mapto, mapbytes, prot) ) + { + // TODO: Memory leak of segment? + return 0; + } + + // Insert our newly allocated memory into the processes segment + // list such that it can be reclaimed later. + if ( process->segments ) + process->segments->prev = segment; + segment->next = process->segments; + process->segments = segment; + + // Copy as much data as possible and memset the rest to 0. + uint8_t* memdest = (uint8_t*) virtualaddr; + uint8_t* memsource = (uint8_t*) (((addr_t)file) + pht->offset); + memcpy(memdest, memsource, pht->filesize); + memset(memdest + pht->filesize, 0, pht->memorysize - pht->filesize); + } + + return entry; +#endif +} + +addr_t Construct(Process* process, const void* file, size_t filelen) +{ + if ( filelen < sizeof(Header) ) + return errno = ENOEXEC, 0; + + const Header* header = (const Header*) file; + + if ( !(header->magic[0] == 0x7F && header->magic[1] == 'E' && + header->magic[2] == 'L' && header->magic[3] == 'F' ) ) + return errno = ENOEXEC, 0; + + switch ( header->fileclass ) + { + case CLASS32: return Construct32(process, file, filelen); + case CLASS64: return Construct64(process, file, filelen); + default: + return 0; + } +} + +} // namespace ELF +} // namespace Sortix diff --git a/sortix/elf.h b/sortix/elf.h index 033c88aa..ed24448e 100644 --- a/sortix/elf.h +++ b/sortix/elf.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of Sortix. @@ -25,171 +25,172 @@ #ifndef SORTIX_ELF_H #define SORTIX_ELF_H -namespace Sortix +namespace Sortix { + +class Process; + +namespace ELF { + +struct Header { - class Process; + unsigned char magic[4]; + unsigned char fileclass; + unsigned char dataencoding; + unsigned char version; + unsigned char osabi; + unsigned char abiversion; + unsigned char padding[7]; +}; - namespace ELF - { - struct Header - { - unsigned char magic[4]; - unsigned char fileclass; - unsigned char dataencoding; - unsigned char version; - unsigned char osabi; - unsigned char abiversion; - unsigned char padding[7]; - }; +const unsigned char CLASSNONE = 0; +const unsigned char CLASS32 = 1; +const unsigned char CLASS64 = 2; +const unsigned char DATA2LSB = 1; +const unsigned char DATA2MSB = 2; +const unsigned char CURRENTVERSION = 1; - const unsigned char CLASSNONE = 0; - const unsigned char CLASS32 = 1; - const unsigned char CLASS64 = 2; - const unsigned char DATA2LSB = 1; - const unsigned char DATA2MSB = 2; - const unsigned char CURRENTVERSION = 1; +struct Header32 : public Header +{ + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t programheaderoffset; + uint32_t sectionheaderoffset; + uint32_t flags; + uint16_t elfheadersize; + uint16_t programheaderentrysize; + uint16_t numprogramheaderentries; + uint16_t sectionheaderentrysize; + uint16_t numsectionheaderentries; + uint16_t sectionheaderstringindex; +}; - struct Header32 : public Header - { - uint16_t type; - uint16_t machine; - uint32_t version; - uint32_t entry; - uint32_t programheaderoffset; - uint32_t sectionheaderoffset; - uint32_t flags; - uint16_t elfheadersize; - uint16_t programheaderentrysize; - uint16_t numprogramheaderentries; - uint16_t sectionheaderentrysize; - uint16_t numsectionheaderentries; - uint16_t sectionheaderstringindex; - }; +struct Header64 : public Header +{ + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry; + uint64_t programheaderoffset; + uint64_t sectionheaderoffset; + uint32_t flags; + uint16_t elfheadersize; + uint16_t programheaderentrysize; + uint16_t numprogramheaderentries; + uint16_t sectionheaderentrysize; + uint16_t numsectionheaderentries; + uint16_t sectionheaderstringindex; +}; - struct Header64 : public Header - { - uint16_t type; - uint16_t machine; - uint32_t version; - uint64_t entry; - uint64_t programheaderoffset; - uint64_t sectionheaderoffset; - uint32_t flags; - uint16_t elfheadersize; - uint16_t programheaderentrysize; - uint16_t numprogramheaderentries; - uint16_t sectionheaderentrysize; - uint16_t numsectionheaderentries; - uint16_t sectionheaderstringindex; - }; +struct SectionHeader32 +{ + uint32_t name; + uint32_t type; + uint32_t flags; + uint32_t addr; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t info; + uint32_t addralign; + uint32_t entsize; +}; - struct SectionHeader32 - { - uint32_t name; - uint32_t type; - uint32_t flags; - uint32_t addr; - uint32_t offset; - uint32_t size; - uint32_t link; - uint32_t info; - uint32_t addralign; - uint32_t entsize; - }; +struct SectionHeader64 +{ + uint32_t name; + uint32_t type; + uint64_t flags; + uint64_t addr; + uint64_t offset; + uint64_t size; + uint32_t link; + uint32_t info; + uint64_t addralign; + uint64_t entsize; +}; - struct SectionHeader64 - { - uint32_t name; - uint32_t type; - uint64_t flags; - uint64_t addr; - uint64_t offset; - uint64_t size; - uint32_t link; - uint32_t info; - uint64_t addralign; - uint64_t entsize; - }; +const uint32_t SHT_NULL = 0; +const uint32_t SHT_PROGBITS = 1; +const uint32_t SHT_SYMTAB = 2; +const uint32_t SHT_STRTAB = 3; +const uint32_t SHT_RELA = 4; +const uint32_t SHT_HASH = 5; +const uint32_t SHT_DYNAMIC = 6; +const uint32_t SHT_NOTE = 7; +const uint32_t SHT_NOBITS = 8; +const uint32_t SHT_REL = 9; +const uint32_t SHT_SHLIB = 10; +const uint32_t SHT_DYNSYM = 11; +const uint32_t SHT_LOPROC = 0x70000000; +const uint32_t SHT_HIPROC = 0x7fffffff; +const uint32_t SHT_LOUSER = 0x80000000; +const uint32_t SHT_HIUSER = 0xffffffff; - const uint32_t SHT_NULL = 0; - const uint32_t SHT_PROGBITS = 1; - const uint32_t SHT_SYMTAB = 2; - const uint32_t SHT_STRTAB = 3; - const uint32_t SHT_RELA = 4; - const uint32_t SHT_HASH = 5; - const uint32_t SHT_DYNAMIC = 6; - const uint32_t SHT_NOTE = 7; - const uint32_t SHT_NOBITS = 8; - const uint32_t SHT_REL = 9; - const uint32_t SHT_SHLIB = 10; - const uint32_t SHT_DYNSYM = 11; - const uint32_t SHT_LOPROC = 0x70000000; - const uint32_t SHT_HIPROC = 0x7fffffff; - const uint32_t SHT_LOUSER = 0x80000000; - const uint32_t SHT_HIUSER = 0xffffffff; +struct ProgramHeader32 +{ + uint32_t type; + uint32_t offset; + uint32_t virtualaddr; + uint32_t physicaladdr; + uint32_t filesize; + uint32_t memorysize; + uint32_t flags; + uint32_t align; +}; - struct ProgramHeader32 - { - uint32_t type; - uint32_t offset; - uint32_t virtualaddr; - uint32_t physicaladdr; - uint32_t filesize; - uint32_t memorysize; - uint32_t flags; - uint32_t align; - }; +struct ProgramHeader64 +{ + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t virtualaddr; + uint64_t physicaladdr; + uint64_t filesize; + uint64_t memorysize; + uint64_t align; +}; - struct ProgramHeader64 - { - uint32_t type; - uint32_t flags; - uint64_t offset; - uint64_t virtualaddr; - uint64_t physicaladdr; - uint64_t filesize; - uint64_t memorysize; - uint64_t align; - }; +const uint32_t PT_NULL = 0; +const uint32_t PT_LOAD = 1; +const uint32_t PT_DYNAMIC = 2; +const uint32_t PT_INTERP = 3; +const uint32_t PT_NOTE = 4; +const uint32_t PT_SHLIB = 5; +const uint32_t PT_PHDR = 6; +const uint32_t PT_LOPROC = 0x70000000; +const uint32_t PT_HIPROC = 0x7FFFFFFF; - const uint32_t PT_NULL = 0; - const uint32_t PT_LOAD = 1; - const uint32_t PT_DYNAMIC = 2; - const uint32_t PT_INTERP = 3; - const uint32_t PT_NOTE = 4; - const uint32_t PT_SHLIB = 5; - const uint32_t PT_PHDR = 6; - const uint32_t PT_LOPROC = 0x70000000; - const uint32_t PT_HIPROC = 0x7FFFFFFF; +const uint32_t PF_X = 1 << 0; +const uint32_t PF_W = 1 << 1; +const uint32_t PF_R = 1 << 2; - const uint32_t PF_X = (1<<0); - const uint32_t PF_W = (1<<1); - const uint32_t PF_R = (1<<2); +struct Symbol32 +{ + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; +}; - struct Symbol32 - { - uint32_t st_name; - uint32_t st_value; - uint32_t st_size; - uint8_t st_info; - uint8_t st_other; - uint16_t st_shndx; - }; +struct Symbol64 +{ + uint32_t st_name; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; + uint64_t st_value; + uint64_t st_size; +}; - struct Symbol64 - { - uint32_t st_name; - uint8_t st_info; - uint8_t st_other; - uint16_t st_shndx; - uint64_t st_value; - uint64_t st_size; - }; +// Reads the elf file into the current address space and returns the entry +// address of the program, or 0 upon failure. +addr_t Construct(Process* process, const void* file, size_t filelen); - // Reads the elf file into the current address space and returns the - // entry address of the program, or 0 upon failure. - addr_t Construct(Process* process, const void* file, size_t filelen); - } -} +} // namespace ELF +} // namespace Sortix #endif