Rewrite program loader.
This commit is contained in:
parent
261b95e0a6
commit
bbf454e164
768
kernel/elf.cpp
768
kernel/elf.cpp
|
@ -18,460 +18,382 @@
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
elf.cpp
|
elf.cpp
|
||||||
Constructs processes from ELF files.
|
Load a program in the Executable and Linkable Format into this process.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <system-elf.h>
|
||||||
|
|
||||||
|
#include <__/wordsize.h>
|
||||||
|
|
||||||
#include <sortix/elf-note.h>
|
|
||||||
#include <sortix/mman.h>
|
#include <sortix/mman.h>
|
||||||
|
|
||||||
|
#include <sortix/kernel/elf.h>
|
||||||
#include <sortix/kernel/kernel.h>
|
#include <sortix/kernel/kernel.h>
|
||||||
#include <sortix/kernel/memorymanagement.h>
|
#include <sortix/kernel/memorymanagement.h>
|
||||||
#include <sortix/kernel/process.h>
|
#include <sortix/kernel/process.h>
|
||||||
#include <sortix/kernel/segment.h>
|
#include <sortix/kernel/segment.h>
|
||||||
#include <sortix/kernel/symbol.h>
|
#include <sortix/kernel/symbol.h>
|
||||||
|
|
||||||
#include "elf.h"
|
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
namespace ELF {
|
namespace ELF {
|
||||||
|
|
||||||
// TODO: This code doesn't respect that the size of program headers and section
|
static bool is_power_of_two(uintptr_t value)
|
||||||
// headers may vary depending on the ELF header and that using a simple
|
|
||||||
// table indexation isn't enough.
|
|
||||||
|
|
||||||
addr_t Construct32(Process* process, const uint8_t* file, size_t filelen,
|
|
||||||
Auxiliary* aux)
|
|
||||||
{
|
{
|
||||||
if ( filelen < sizeof(Header32) )
|
for ( uintptr_t i = 0; i < sizeof(uintptr_t) * 8; i++ )
|
||||||
return 0;
|
if ( (uintptr_t) 1 << i == value )
|
||||||
const Header32* header = (const Header32*) file;
|
return true;
|
||||||
|
return false;
|
||||||
// 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_TLS )
|
|
||||||
{
|
|
||||||
aux->tls_file_offset = pht->offset;
|
|
||||||
aux->tls_file_size = pht->filesize;
|
|
||||||
aux->tls_mem_size = pht->memorysize;
|
|
||||||
aux->tls_mem_align = pht->align;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( pht->type == PT_NOTE )
|
|
||||||
{
|
|
||||||
uintptr_t notes_addr = (uintptr_t) file + pht->offset;
|
|
||||||
size_t notes_offset = 0;
|
|
||||||
while ( notes_offset < pht->filesize )
|
|
||||||
{
|
|
||||||
uintptr_t note = notes_addr + notes_offset;
|
|
||||||
uint32_t namesz = *(uint32_t*) (note + 0);
|
|
||||||
uint32_t descsz = *(uint32_t*) (note + 4);
|
|
||||||
uint32_t type = *(uint32_t*) (note + 8);
|
|
||||||
uint32_t namesz_aligned = -(-namesz & ~(4U - 1));
|
|
||||||
uint32_t descsz_aligned = -(-descsz & ~(4U - 1));
|
|
||||||
size_t note_size = 12 + namesz_aligned + descsz_aligned;
|
|
||||||
notes_offset += note_size;
|
|
||||||
const char* name = (const char*) (note + 12);
|
|
||||||
uintptr_t desc = note + 12 + namesz_aligned;
|
|
||||||
if ( strcmp(name, "Sortix") == 0 )
|
|
||||||
{
|
|
||||||
if ( type == ELF_NOTE_SORTIX_UTHREAD_SIZE )
|
|
||||||
{
|
|
||||||
aux->uthread_size = *(uint32_t*) (desc + 0);
|
|
||||||
aux->uthread_align = *(uint32_t*) (desc + 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
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; }
|
|
||||||
|
|
||||||
struct segment segment;
|
|
||||||
segment.addr = mapto;
|
|
||||||
segment.size = Page::AlignUp(mapbytes);
|
|
||||||
segment.prot = prot;
|
|
||||||
|
|
||||||
kthread_mutex_lock(&process->segment_lock);
|
|
||||||
|
|
||||||
if ( !IsUserspaceSegment(&segment) ||
|
|
||||||
IsSegmentOverlapping(process, &segment) )
|
|
||||||
{
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
process->ResetAddressSpace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(process == CurrentProcess());
|
|
||||||
|
|
||||||
if ( !Memory::MapRange(segment.addr, segment.size, prot, PAGE_USAGE_USER_SPACE) )
|
|
||||||
{
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
process->ResetAddressSpace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !AddSegment(process, &segment) )
|
|
||||||
{
|
|
||||||
Memory::UnmapRange(segment.addr, segment.size, PAGE_USAGE_USER_SPACE);
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
process->ResetAddressSpace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the location of the section headers.
|
|
||||||
addr_t shtblpos = (addr_t) file + header->sectionheaderoffset;
|
|
||||||
const SectionHeader32* shtbl = (const SectionHeader32*) shtblpos;
|
|
||||||
|
|
||||||
const SectionHeader32* section_names_section = shtbl + header->sectionheaderstringindex;
|
|
||||||
const char* section_names = (const char*) (file + section_names_section->offset);
|
|
||||||
|
|
||||||
// Find the string table.
|
|
||||||
const SectionHeader32* string_table_section = NULL;
|
|
||||||
for ( size_t i = 0; i < header->numsectionheaderentries; i++ )
|
|
||||||
if ( !strcmp(section_names + shtbl[i].name, ".strtab") )
|
|
||||||
{
|
|
||||||
string_table_section = shtbl + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the symbol table.
|
|
||||||
const SectionHeader32* symbol_table_section = NULL;
|
|
||||||
for ( size_t i = 0; i < header->numsectionheaderentries; i++ )
|
|
||||||
if ( !strcmp(section_names + shtbl[i].name, ".symtab") )
|
|
||||||
{
|
|
||||||
symbol_table_section = shtbl + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !string_table_section || !symbol_table_section )
|
|
||||||
return entry;
|
|
||||||
|
|
||||||
// Prepare copying debug information.
|
|
||||||
const char* elf_string_table = (const char*) (file + string_table_section->offset);
|
|
||||||
size_t elf_string_table_size = string_table_section->size;
|
|
||||||
const Symbol32* elf_symbols = (const Symbol32*) (file + symbol_table_section->offset);
|
|
||||||
size_t elf_symbol_count = symbol_table_section->size / sizeof(Symbol32);
|
|
||||||
|
|
||||||
// Duplicate the string table.
|
|
||||||
char* string_table = new char[elf_string_table_size];
|
|
||||||
if ( !string_table )
|
|
||||||
return entry;
|
|
||||||
memcpy(string_table, elf_string_table, elf_string_table_size);
|
|
||||||
|
|
||||||
// Duplicate the symbol table.
|
|
||||||
Symbol* symbol_table = new Symbol[elf_symbol_count-1];
|
|
||||||
if ( !symbol_table )
|
|
||||||
{
|
|
||||||
delete[] string_table;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy all entires except the leading null entry.
|
|
||||||
for ( size_t i = 1; i < elf_symbol_count; i++ )
|
|
||||||
{
|
|
||||||
symbol_table[i-1].address = elf_symbols[i].st_value;
|
|
||||||
symbol_table[i-1].size = elf_symbols[i].st_size;
|
|
||||||
symbol_table[i-1].name = string_table + elf_symbols[i].st_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
process->string_table = string_table;
|
|
||||||
process->string_table_length = elf_string_table_size;
|
|
||||||
process->symbol_table = symbol_table;
|
|
||||||
process->symbol_table_length = elf_symbol_count-1;
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t Construct64(Process* process, const uint8_t* file, size_t filelen,
|
uintptr_t Load(const void* file_ptr, size_t file_size, Auxiliary* aux)
|
||||||
Auxiliary* aux)
|
|
||||||
{
|
{
|
||||||
#if !defined(__x86_64__)
|
|
||||||
(void) process;
|
|
||||||
(void) file;
|
|
||||||
(void) filelen;
|
|
||||||
(void) aux;
|
|
||||||
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_TLS )
|
|
||||||
{
|
|
||||||
aux->tls_file_offset = pht->offset;
|
|
||||||
aux->tls_file_size = pht->filesize;
|
|
||||||
aux->tls_mem_size = pht->memorysize;
|
|
||||||
aux->tls_mem_align = pht->align;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( pht->type == PT_NOTE )
|
|
||||||
{
|
|
||||||
uintptr_t notes_addr = (uintptr_t) file + pht->offset;
|
|
||||||
size_t notes_offset = 0;
|
|
||||||
while ( notes_offset < pht->filesize )
|
|
||||||
{
|
|
||||||
uintptr_t note = notes_addr + notes_offset;
|
|
||||||
uint32_t namesz = *(uint32_t*) (note + 0);
|
|
||||||
uint32_t descsz = *(uint32_t*) (note + 4);
|
|
||||||
uint32_t type = *(uint32_t*) (note + 8);
|
|
||||||
uint32_t namesz_aligned = -(-namesz & ~(4U - 1));
|
|
||||||
uint32_t descsz_aligned = -(-descsz & ~(4U - 1));
|
|
||||||
size_t note_size = 12 + namesz_aligned + descsz_aligned;
|
|
||||||
notes_offset += note_size;
|
|
||||||
const char* name = (const char*) (note + 12);
|
|
||||||
uintptr_t desc = note + 12 + namesz_aligned;
|
|
||||||
if ( strcmp(name, "Sortix") == 0 )
|
|
||||||
{
|
|
||||||
if ( type == ELF_NOTE_SORTIX_UTHREAD_SIZE )
|
|
||||||
{
|
|
||||||
uint64_t size_low = *((uint32_t*) (desc + 0));
|
|
||||||
uint64_t size_high = *((uint32_t*) (desc + 4));
|
|
||||||
aux->uthread_size = size_low << 0 | size_high << 32;
|
|
||||||
uint64_t align_low = *((uint32_t*) (desc + 8));
|
|
||||||
uint64_t align_high = *((uint32_t*) (desc + 12));
|
|
||||||
aux->uthread_align = align_low << 0 | align_high << 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
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; }
|
|
||||||
|
|
||||||
struct segment segment;
|
|
||||||
segment.addr = mapto;
|
|
||||||
segment.size = Page::AlignUp(mapbytes);
|
|
||||||
segment.prot = prot;
|
|
||||||
|
|
||||||
kthread_mutex_lock(&process->segment_lock);
|
|
||||||
|
|
||||||
if ( !IsUserspaceSegment(&segment) ||
|
|
||||||
IsSegmentOverlapping(process, &segment) )
|
|
||||||
{
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
process->ResetAddressSpace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(process == CurrentProcess());
|
|
||||||
|
|
||||||
if ( !Memory::MapRange(segment.addr, segment.size, prot, PAGE_USAGE_USER_SPACE) )
|
|
||||||
{
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
process->ResetAddressSpace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !AddSegment(process, &segment) )
|
|
||||||
{
|
|
||||||
Memory::UnmapRange(segment.addr, segment.size, PAGE_USAGE_USER_SPACE);
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
process->ResetAddressSpace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
kthread_mutex_unlock(&process->segment_lock);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the location of the section headers.
|
|
||||||
addr_t shtblpos = (addr_t) file + header->sectionheaderoffset;
|
|
||||||
const SectionHeader64* shtbl = (const SectionHeader64*) shtblpos;
|
|
||||||
|
|
||||||
const SectionHeader64* section_names_section = shtbl + header->sectionheaderstringindex;
|
|
||||||
const char* section_names = (const char*) (file + section_names_section->offset);
|
|
||||||
|
|
||||||
// Find the string table.
|
|
||||||
const SectionHeader64* string_table_section = NULL;
|
|
||||||
for ( size_t i = 0; i < header->numsectionheaderentries; i++ )
|
|
||||||
if ( !strcmp(section_names + shtbl[i].name, ".strtab") )
|
|
||||||
{
|
|
||||||
string_table_section = shtbl + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the symbol table.
|
|
||||||
const SectionHeader64* symbol_table_section = NULL;
|
|
||||||
for ( size_t i = 0; i < header->numsectionheaderentries; i++ )
|
|
||||||
if ( !strcmp(section_names + shtbl[i].name, ".symtab") )
|
|
||||||
{
|
|
||||||
symbol_table_section = shtbl + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !string_table_section || !symbol_table_section )
|
|
||||||
return entry;
|
|
||||||
|
|
||||||
// Prepare copying debug information.
|
|
||||||
const char* elf_string_table = (const char*) (file + string_table_section->offset);
|
|
||||||
size_t elf_string_table_size = string_table_section->size;
|
|
||||||
const Symbol64* elf_symbols = (const Symbol64*) (file + symbol_table_section->offset);
|
|
||||||
size_t elf_symbol_count = symbol_table_section->size / sizeof(Symbol64);
|
|
||||||
|
|
||||||
// Duplicate the string table.
|
|
||||||
char* string_table = new char[elf_string_table_size];
|
|
||||||
if ( !string_table )
|
|
||||||
return entry;
|
|
||||||
memcpy(string_table, elf_string_table, elf_string_table_size);
|
|
||||||
|
|
||||||
// Duplicate the symbol table.
|
|
||||||
Symbol* symbol_table = new Symbol[elf_symbol_count-1];
|
|
||||||
if ( !symbol_table )
|
|
||||||
{
|
|
||||||
delete[] string_table;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy all entires except the leading null entry.
|
|
||||||
for ( size_t i = 1; i < elf_symbol_count; i++ )
|
|
||||||
{
|
|
||||||
symbol_table[i-1].address = elf_symbols[i].st_value;
|
|
||||||
symbol_table[i-1].size = elf_symbols[i].st_size;
|
|
||||||
symbol_table[i-1].name = string_table + elf_symbols[i].st_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
process->string_table = string_table;
|
|
||||||
process->string_table_length = elf_string_table_size;
|
|
||||||
process->symbol_table = symbol_table;
|
|
||||||
process->symbol_table_length = elf_symbol_count-1;
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_t Construct(Process* process, const void* file, size_t filelen,
|
|
||||||
Auxiliary* aux)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
memset(aux, 0, sizeof(*aux));
|
memset(aux, 0, sizeof(*aux));
|
||||||
|
|
||||||
switch ( header->fileclass )
|
Process* process = CurrentProcess();
|
||||||
|
|
||||||
|
uintptr_t userspace_addr;
|
||||||
|
size_t userspace_size;
|
||||||
|
Memory::GetUserVirtualArea(&userspace_addr, &userspace_size);
|
||||||
|
uintptr_t userspace_end = userspace_addr + userspace_size;
|
||||||
|
|
||||||
|
const unsigned char* file = (const unsigned char*) file_ptr;
|
||||||
|
|
||||||
|
if ( file_size < EI_NIDENT )
|
||||||
|
return errno = ENOEXEC, 0;
|
||||||
|
|
||||||
|
if ( memcmp(file, ELFMAG, SELFMAG) != 0 )
|
||||||
|
return errno = ENOEXEC, 0;
|
||||||
|
|
||||||
|
#if __WORDSIZE == 32
|
||||||
|
if ( file[EI_CLASS] != ELFCLASS32 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#elif __WORDSIZE == 64
|
||||||
|
if ( file[EI_CLASS] != ELFCLASS64 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#else
|
||||||
|
#error "You need to add support for your elf class."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
if ( file[EI_DATA] != ELFDATA2LSB )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
if ( file[EI_DATA] != ELFDATA2MSB )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#else
|
||||||
|
#error "You need to add support for your endian."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( file[EI_VERSION] != EV_CURRENT )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( file[EI_OSABI] != ELFOSABI_SORTIX )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( file[EI_ABIVERSION] != 0 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( file_size < sizeof(Elf_Ehdr) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
if ( (uintptr_t) file & (alignof(Elf_Ehdr) - 1) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
const Elf_Ehdr* header = (const Elf_Ehdr*) file;
|
||||||
|
|
||||||
|
if ( header->e_ehsize < sizeof(Elf_Ehdr) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( file_size < header->e_ehsize )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
if ( header->e_machine != EM_386 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
if ( header->e_machine != EM_X86_64 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#else
|
||||||
|
#error "Please recognize your processor in e_machine."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( header->e_type != ET_EXEC )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( header->e_entry == 0 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( file_size < header->e_phoff )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( file_size < header->e_shoff )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( header->e_phentsize < sizeof(Elf_Phdr) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( header->e_shentsize < sizeof(Elf_Shdr) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
process->ResetForExecute();
|
||||||
|
|
||||||
|
if ( header->e_phnum == (Elf_Half) -1 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
if ( header->e_shnum == (Elf_Half) -1 )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
for ( Elf32_Half i = 0; i < header->e_phnum; i++ )
|
||||||
{
|
{
|
||||||
case CLASS32: return Construct32(process, (const uint8_t*) file, filelen, aux);
|
size_t max_phs = (file_size - header->e_phoff) / header->e_phentsize;
|
||||||
case CLASS64: return Construct64(process, (const uint8_t*) file, filelen, aux);
|
if ( max_phs <= i )
|
||||||
default:
|
return errno = EINVAL, 0;
|
||||||
return 0;
|
size_t pheader_offset = header->e_phoff + i * header->e_phentsize;
|
||||||
|
if ( (uintptr_t) (file + pheader_offset) & (alignof(Elf_Phdr) - 1) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
Elf_Phdr* pheader = (Elf_Phdr*) (file + pheader_offset);
|
||||||
|
|
||||||
|
switch ( pheader->p_type )
|
||||||
|
{
|
||||||
|
case PT_TLS: break;
|
||||||
|
case PT_NOTE: break;
|
||||||
|
case PT_LOAD: break;
|
||||||
|
default: continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( !is_power_of_two(pheader->p_align) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
if ( file_size < pheader->p_offset )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
if ( file_size - pheader->p_offset < pheader->p_filesz )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
if ( pheader->p_type == PT_TLS )
|
||||||
|
{
|
||||||
|
if ( pheader->p_memsz < pheader->p_filesz )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
aux->tls_file_offset = pheader->p_offset;
|
||||||
|
aux->tls_file_size = pheader->p_filesz;
|
||||||
|
aux->tls_mem_size = pheader->p_memsz;
|
||||||
|
aux->tls_mem_align = pheader->p_align;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pheader->p_type == PT_NOTE )
|
||||||
|
{
|
||||||
|
size_t notes_offset = 0;
|
||||||
|
while ( notes_offset < pheader->p_filesz )
|
||||||
|
{
|
||||||
|
size_t available = pheader->p_filesz - notes_offset;
|
||||||
|
size_t note_header_size = 3 * sizeof(uint32_t);
|
||||||
|
if ( available < note_header_size )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
available -= note_header_size;
|
||||||
|
size_t file_offset = pheader->p_offset + notes_offset;
|
||||||
|
if ( ((uintptr_t) file + file_offset) & (alignof(uint32_t) - 1) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
const unsigned char* note = file + file_offset;
|
||||||
|
uint32_t* note_header = (uint32_t*) note;
|
||||||
|
uint32_t namesz = note_header[0];
|
||||||
|
uint32_t descsz = note_header[1];
|
||||||
|
uint32_t type = note_header[2];
|
||||||
|
uint32_t namesz_aligned = -(-namesz & ~(sizeof(uint32_t) - 1));
|
||||||
|
uint32_t descsz_aligned = -(-descsz & ~(sizeof(uint32_t) - 1));
|
||||||
|
if ( available < namesz_aligned )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
available -= namesz_aligned;
|
||||||
|
if ( available < descsz_aligned )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
available -= descsz_aligned;
|
||||||
|
notes_offset += note_header_size + namesz_aligned + descsz_aligned;
|
||||||
|
|
||||||
|
const char* name = (const char*) (note + note_header_size);
|
||||||
|
if ( strnlen(name, namesz_aligned) == namesz_aligned )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
const unsigned char* desc = note + note_header_size + namesz_aligned;
|
||||||
|
const uint32_t* desc_32bits = (const uint32_t*) desc;
|
||||||
|
|
||||||
|
if ( strcmp(name, ELF_NOTE_SORTIX) == 0 )
|
||||||
|
{
|
||||||
|
if ( type == ELF_NOTE_SORTIX_UTHREAD_SIZE )
|
||||||
|
{
|
||||||
|
if ( descsz_aligned != 2 * sizeof(size_t) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
#if __WORDSIZE == 32
|
||||||
|
aux->uthread_size = desc_32bits[0];
|
||||||
|
aux->uthread_align = desc_32bits[1];
|
||||||
|
#elif __WORDSIZE == 64 && BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
aux->uthread_size = (uint64_t) desc_32bits[0] << 0 |
|
||||||
|
(uint64_t) desc_32bits[1] << 32;
|
||||||
|
aux->uthread_align = (uint64_t) desc_32bits[2] << 0 |
|
||||||
|
(uint64_t) desc_32bits[3] << 32;
|
||||||
|
#elif __WORDSIZE == 64 && BYTE_ORDER == BIG_ENDIAN
|
||||||
|
aux->uthread_size = (uint64_t) desc_32bits[1] << 0 |
|
||||||
|
(uint64_t) desc_32bits[0] << 32;
|
||||||
|
aux->uthread_align = (uint64_t) desc_32bits[3] << 0 |
|
||||||
|
(uint64_t) desc_32bits[2] << 32;
|
||||||
|
#else
|
||||||
|
#error "You need to correctly read the uthread note"
|
||||||
|
#endif
|
||||||
|
if ( !is_power_of_two(aux->uthread_align) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pheader->p_type == PT_LOAD )
|
||||||
|
{
|
||||||
|
if ( pheader->p_filesz &&
|
||||||
|
pheader->p_vaddr % pheader->p_align !=
|
||||||
|
pheader->p_offset % pheader->p_align )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
int prot = PROT_FORK | PROT_KREAD | PROT_KWRITE;
|
||||||
|
if ( pheader->p_flags & PF_X )
|
||||||
|
prot |= PROT_EXEC;
|
||||||
|
if ( pheader->p_flags & PF_R )
|
||||||
|
prot |= PROT_READ;
|
||||||
|
if ( pheader->p_flags & PF_W )
|
||||||
|
prot |= PROT_WRITE;
|
||||||
|
|
||||||
|
if ( pheader->p_vaddr < userspace_addr )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
if ( userspace_end < pheader->p_vaddr )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
if ( userspace_end - pheader->p_vaddr < pheader->p_memsz )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
|
||||||
|
uintptr_t map_start = Page::AlignDown(pheader->p_vaddr);
|
||||||
|
uintptr_t map_end = Page::AlignUp(pheader->p_vaddr + pheader->p_memsz);
|
||||||
|
size_t map_size = map_end - map_start;
|
||||||
|
|
||||||
|
struct segment segment;
|
||||||
|
segment.addr = map_start;
|
||||||
|
segment.size = map_size;
|
||||||
|
segment.prot = prot;
|
||||||
|
|
||||||
|
assert(IsUserspaceSegment(&segment));
|
||||||
|
|
||||||
|
kthread_mutex_lock(&process->segment_lock);
|
||||||
|
|
||||||
|
if ( IsSegmentOverlapping(process, &segment) )
|
||||||
|
{
|
||||||
|
kthread_mutex_unlock(&process->segment_lock);
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !Memory::MapRange(segment.addr, segment.size, prot, PAGE_USAGE_USER_SPACE) )
|
||||||
|
{
|
||||||
|
kthread_mutex_unlock(&process->segment_lock);
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !AddSegment(process, &segment) )
|
||||||
|
{
|
||||||
|
Memory::UnmapRange(segment.addr, segment.size, PAGE_USAGE_USER_SPACE);
|
||||||
|
kthread_mutex_unlock(&process->segment_lock);
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kthread_mutex_unlock(&process->segment_lock);
|
||||||
|
|
||||||
|
memset((void*) segment.addr, 0, segment.size);
|
||||||
|
memcpy((void*) pheader->p_vaddr, file + pheader->p_offset, pheader->p_filesz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SECURITY: TODO: Insecure.
|
||||||
|
Elf_Shdr* section_string_table_section = (Elf_Shdr*) (file + header->e_shoff + header->e_shstrndx * header->e_shentsize);
|
||||||
|
const char* section_string_table = (const char*) (file + section_string_table_section->sh_offset);
|
||||||
|
//size_t section_string_table_size = section_string_table_section->sh_size;
|
||||||
|
|
||||||
|
const char* string_table = NULL;
|
||||||
|
size_t string_table_size = 0;
|
||||||
|
|
||||||
|
for ( Elf32_Half i = 0; i < header->e_shnum; i++ )
|
||||||
|
{
|
||||||
|
size_t max_shs = (file_size - header->e_shoff) / header->e_shentsize;
|
||||||
|
if ( max_shs <= i )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
size_t sheader_offset = header->e_shoff + i * header->e_shentsize;
|
||||||
|
if ( (uintptr_t) (file + sheader_offset) & (alignof(Elf_Shdr) - 1) )
|
||||||
|
return errno = EINVAL, 0;
|
||||||
|
Elf_Shdr* sheader = (Elf_Shdr*) (file + sheader_offset);
|
||||||
|
|
||||||
|
// SECURITY: TODO: Insecure.
|
||||||
|
const char* section_name = section_string_table + sheader->sh_name;
|
||||||
|
|
||||||
|
if ( !strcmp(section_name, ".strtab") )
|
||||||
|
{
|
||||||
|
// SECURITY: TODO: Insecure.
|
||||||
|
string_table = (const char*) (file + sheader->sh_offset);
|
||||||
|
string_table_size = sheader->sh_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( Elf32_Half i = 0; i < header->e_shnum; i++ )
|
||||||
|
{
|
||||||
|
size_t sheader_offset = header->e_shoff + i * header->e_shentsize;
|
||||||
|
Elf_Shdr* sheader = (Elf_Shdr*) (file + sheader_offset);
|
||||||
|
|
||||||
|
// SECURITY: TODO: Insecure.
|
||||||
|
const char* section_name = section_string_table + sheader->sh_name;
|
||||||
|
|
||||||
|
if ( !strcmp(section_name, ".symtab") )
|
||||||
|
{
|
||||||
|
if ( process->symbol_table )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// SECURITY: TODO: Insecure.
|
||||||
|
Elf_Sym* symbols = (Elf_Sym*) (file + sheader->sh_offset);
|
||||||
|
size_t symbols_length = sheader->sh_size / sizeof(Elf_Sym);
|
||||||
|
|
||||||
|
if ( symbols_length == 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
symbols++;
|
||||||
|
symbols_length--;
|
||||||
|
|
||||||
|
char* string_table_copy = new char[string_table_size];
|
||||||
|
if ( !string_table_copy )
|
||||||
|
continue;
|
||||||
|
memcpy(string_table_copy, string_table, string_table_size);
|
||||||
|
|
||||||
|
Symbol* symbols_copy = new Symbol[symbols_length];
|
||||||
|
if ( !symbols_copy )
|
||||||
|
{
|
||||||
|
delete[] string_table_copy;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < symbols_length; i++ )
|
||||||
|
{
|
||||||
|
memset(&symbols_copy[i], 0, sizeof(symbols_copy[i]));
|
||||||
|
symbols_copy[i].address = symbols[i].st_value;
|
||||||
|
symbols_copy[i].size = symbols[i].st_size;
|
||||||
|
// SECURITY: TODO: Insecure.
|
||||||
|
symbols_copy[i].name = string_table_copy + symbols[i].st_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
process->string_table = string_table_copy;
|
||||||
|
process->string_table_length = string_table_size;
|
||||||
|
process->symbol_table = symbols_copy;
|
||||||
|
process->symbol_table_length = symbols_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return header->e_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ELF
|
} // namespace ELF
|
||||||
|
|
211
kernel/elf.h
211
kernel/elf.h
|
@ -1,211 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
|
||||||
|
|
||||||
This file is part of Sortix.
|
|
||||||
|
|
||||||
Sortix is free software: you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
elf.h
|
|
||||||
Constructs processes from ELF files.
|
|
||||||
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef SORTIX_ELF_H
|
|
||||||
#define SORTIX_ELF_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
namespace Sortix {
|
|
||||||
|
|
||||||
class Process;
|
|
||||||
|
|
||||||
namespace ELF {
|
|
||||||
|
|
||||||
struct Auxiliary
|
|
||||||
{
|
|
||||||
size_t tls_file_offset;
|
|
||||||
size_t tls_file_size;
|
|
||||||
size_t tls_mem_size;
|
|
||||||
size_t tls_mem_align;
|
|
||||||
size_t uthread_size;
|
|
||||||
size_t uthread_align;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 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_TLS = 7;
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
Auxiliary* aux);
|
|
||||||
|
|
||||||
} // namespace ELF
|
|
||||||
} // namespace Sortix
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -17,20 +17,35 @@
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
sortix/elf-note.h
|
sortix/kernel/elf.h
|
||||||
Declares type constants for the Sortix ELF notes.
|
Executable and Linkable Format.
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#ifndef INCLUDE_SORTIX_ELF_NOTE_H
|
#ifndef INCLUDE_SORTIX_KERNEL_ELF_H
|
||||||
#define INCLUDE_SORTIX_ELF_NOTE_H
|
#define INCLUDE_SORTIX_KERNEL_ELF_H
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
__BEGIN_DECLS
|
namespace Sortix {
|
||||||
|
namespace ELF {
|
||||||
|
|
||||||
#define ELF_NOTE_SORTIX_UTHREAD_SIZE 0x10
|
struct Auxiliary
|
||||||
|
{
|
||||||
|
size_t tls_file_offset;
|
||||||
|
size_t tls_file_size;
|
||||||
|
size_t tls_mem_size;
|
||||||
|
size_t tls_mem_align;
|
||||||
|
size_t uthread_size;
|
||||||
|
size_t uthread_align;
|
||||||
|
};
|
||||||
|
|
||||||
__END_DECLS
|
// Reads the elf file into the current address space and returns the entry
|
||||||
|
// address of the program, or 0 upon failure.
|
||||||
|
uintptr_t Load(const void* file, size_t filelen, Auxiliary* aux);
|
||||||
|
|
||||||
|
} // namespace ELF
|
||||||
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <brand.h>
|
#include <brand.h>
|
||||||
|
#include <elf.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -69,7 +70,6 @@
|
||||||
|
|
||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "com.h"
|
#include "com.h"
|
||||||
#include "elf.h"
|
|
||||||
#include "fs/full.h"
|
#include "fs/full.h"
|
||||||
#include "fs/kram.h"
|
#include "fs/kram.h"
|
||||||
#include "fs/null.h"
|
#include "fs/null.h"
|
||||||
|
@ -306,11 +306,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SECTION(num) ((ELF::SectionHeader32*) ((uintptr_t) elf_sec->addr + (uintptr_t) elf_sec->size * (uintptr_t) (num)))
|
#define SECTION(num) ((Elf32_Shdr*) ((uintptr_t) elf_sec->addr + (uintptr_t) elf_sec->size * (uintptr_t) (num)))
|
||||||
|
|
||||||
// Verify the section name section.
|
// Verify the section name section.
|
||||||
ELF::SectionHeader32* section_string_section = SECTION(elf_sec->shndx);
|
Elf32_Shdr* section_string_section = SECTION(elf_sec->shndx);
|
||||||
if ( !BELOW_4MIB(section_string_section->addr, section_string_section->size) )
|
if ( !BELOW_4MIB(section_string_section->sh_addr, section_string_section->sh_size) )
|
||||||
{
|
{
|
||||||
Log::PrintF("Warning: the section string table was loaded inappropriately by the boot loader, kernel debugging symbols will not be available.\n");
|
Log::PrintF("Warning: the section string table was loaded inappropriately by the boot loader, kernel debugging symbols will not be available.\n");
|
||||||
break;
|
break;
|
||||||
|
@ -319,39 +319,39 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
if ( !section_string_section )
|
if ( !section_string_section )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const char* section_string_table = (const char*) (uintptr_t) section_string_section->addr;
|
const char* section_string_table = (const char*) (uintptr_t) section_string_section->sh_addr;
|
||||||
|
|
||||||
// Find the symbol table.
|
// Find the symbol table.
|
||||||
ELF::SectionHeader32* symbol_table_section = NULL;
|
Elf32_Shdr* symbol_table_section = NULL;
|
||||||
for ( unsigned i = 0; i < elf_sec->num && !symbol_table_section; i++ )
|
for ( unsigned i = 0; i < elf_sec->num && !symbol_table_section; i++ )
|
||||||
{
|
{
|
||||||
ELF::SectionHeader32* section = SECTION(i);
|
Elf32_Shdr* section = SECTION(i);
|
||||||
if ( !strcmp(section_string_table + section->name, ".symtab") )
|
if ( !strcmp(section_string_table + section->sh_name, ".symtab") )
|
||||||
symbol_table_section = section;
|
symbol_table_section = section;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !symbol_table_section )
|
if ( !symbol_table_section )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( !BELOW_4MIB(symbol_table_section->addr, symbol_table_section->size) )
|
if ( !BELOW_4MIB(symbol_table_section->sh_addr, symbol_table_section->sh_size) )
|
||||||
{
|
{
|
||||||
Log::PrintF("Warning: the symbol table was loaded inappropriately by the boot loader, kernel debugging symbols will not be available.\n");
|
Log::PrintF("Warning: the symbol table was loaded inappropriately by the boot loader, kernel debugging symbols will not be available.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the symbol string table.
|
// Find the symbol string table.
|
||||||
ELF::SectionHeader32* string_table_section = NULL;
|
Elf32_Shdr* string_table_section = NULL;
|
||||||
for ( unsigned i = 0; i < elf_sec->num && !string_table_section; i++ )
|
for ( unsigned i = 0; i < elf_sec->num && !string_table_section; i++ )
|
||||||
{
|
{
|
||||||
ELF::SectionHeader32* section = SECTION(i);
|
Elf32_Shdr* section = SECTION(i);
|
||||||
if ( !strcmp(section_string_table + section->name, ".strtab") )
|
if ( !strcmp(section_string_table + section->sh_name, ".strtab") )
|
||||||
string_table_section = section;
|
string_table_section = section;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !string_table_section )
|
if ( !string_table_section )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( !BELOW_4MIB(string_table_section->addr, string_table_section->size) )
|
if ( !BELOW_4MIB(string_table_section->sh_addr, string_table_section->sh_size) )
|
||||||
{
|
{
|
||||||
Log::PrintF("Warning: the symbol string table was loaded inappropriately by the boot loader, kernel debugging symbols will not be available.\n");
|
Log::PrintF("Warning: the symbol string table was loaded inappropriately by the boot loader, kernel debugging symbols will not be available.\n");
|
||||||
break;
|
break;
|
||||||
|
@ -359,10 +359,10 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
|
||||||
|
|
||||||
// Duplicate the data structures and convert them to the kernel symbol
|
// Duplicate the data structures and convert them to the kernel symbol
|
||||||
// table format and register it for later debugging.
|
// table format and register it for later debugging.
|
||||||
const char* elf_string_table = (const char*) (uintptr_t) string_table_section->addr;
|
const char* elf_string_table = (const char*) (uintptr_t) string_table_section->sh_addr;
|
||||||
size_t elf_string_table_size = string_table_section->size;
|
size_t elf_string_table_size = string_table_section->sh_size;
|
||||||
ELF::Symbol32* elf_symbols = (ELF::Symbol32*) (uintptr_t) symbol_table_section->addr;
|
Elf32_Sym* elf_symbols = (Elf32_Sym*) (uintptr_t) symbol_table_section->sh_addr;
|
||||||
size_t elf_symbol_count = symbol_table_section->size / sizeof(ELF::Symbol32);
|
size_t elf_symbol_count = symbol_table_section->sh_size / sizeof(Elf32_Sym);
|
||||||
|
|
||||||
if ( !elf_symbol_count || elf_symbol_count == 1 /* null symbol */)
|
if ( !elf_symbol_count || elf_symbol_count == 1 /* null symbol */)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include <sortix/kernel/copy.h>
|
#include <sortix/kernel/copy.h>
|
||||||
#include <sortix/kernel/descriptor.h>
|
#include <sortix/kernel/descriptor.h>
|
||||||
#include <sortix/kernel/dtable.h>
|
#include <sortix/kernel/dtable.h>
|
||||||
|
#include <sortix/kernel/elf.h>
|
||||||
#include <sortix/kernel/ioctx.h>
|
#include <sortix/kernel/ioctx.h>
|
||||||
#include <sortix/kernel/kernel.h>
|
#include <sortix/kernel/kernel.h>
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
|
@ -66,8 +67,6 @@
|
||||||
#include <sortix/kernel/time.h>
|
#include <sortix/kernel/time.h>
|
||||||
#include <sortix/kernel/worker.h>
|
#include <sortix/kernel/worker.h>
|
||||||
|
|
||||||
#include "elf.h"
|
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
#include "x86-family/float.h"
|
#include "x86-family/float.h"
|
||||||
#include "x86-family/gdt.h"
|
#include "x86-family/gdt.h"
|
||||||
|
@ -836,7 +835,7 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
||||||
|
|
||||||
ELF::Auxiliary aux;
|
ELF::Auxiliary aux;
|
||||||
|
|
||||||
addr_t entry = ELF::Construct(CurrentProcess(), program, programsize, &aux);
|
addr_t entry = ELF::Load(program, programsize, &aux);
|
||||||
if ( !entry ) { delete[] programname_clone; return -1; }
|
if ( !entry ) { delete[] programname_clone; return -1; }
|
||||||
|
|
||||||
delete[] program_image_path;
|
delete[] program_image_path;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,94 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||||
|
|
||||||
|
This file is part of the Sortix C Library.
|
||||||
|
|
||||||
|
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
option) any later version.
|
||||||
|
|
||||||
|
The Sortix C Library is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
system-elf.h
|
||||||
|
Executable and Linkable Format for the local system.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef INCLUDE_SYSTEM_ELF_H
|
||||||
|
#define INCLUDE_SYSTEM_ELF_H
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
|
||||||
|
#include <__/wordsize.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#if __WORDSIZE == 32
|
||||||
|
typedef Elf32_Half Elf_Half;
|
||||||
|
typedef Elf32_Word Elf_Word;
|
||||||
|
typedef Elf32_Sword Elf_Sword;
|
||||||
|
typedef Elf32_Xword Elf_Xword;
|
||||||
|
typedef Elf32_Sxword Elf_Sxword;
|
||||||
|
typedef Elf32_Addr Elf_Addr;
|
||||||
|
typedef Elf32_Off Elf_Off;
|
||||||
|
typedef Elf32_Section Elf_Section;
|
||||||
|
typedef Elf32_Versym Elf_Versym;
|
||||||
|
typedef Elf32_Ehdr Elf_Ehdr;
|
||||||
|
typedef Elf32_Shdr Elf_Shdr;
|
||||||
|
typedef Elf32_Sym Elf_Sym;
|
||||||
|
typedef Elf32_Syminfo Elf_Syminfo;
|
||||||
|
typedef Elf32_Rel Elf_Rel;
|
||||||
|
typedef Elf32_Rela Elf_Rela;
|
||||||
|
typedef Elf32_Phdr Elf_Phdr;
|
||||||
|
typedef Elf32_Dyn Elf_Dyn;
|
||||||
|
typedef Elf32_Verdef Elf_Verdef;
|
||||||
|
typedef Elf32_Verdaux Elf_Verdaux;
|
||||||
|
typedef Elf32_Verneed Elf_Verneed;
|
||||||
|
typedef Elf32_Vernaux Elf_Vernaux;
|
||||||
|
typedef Elf32_auxv_t Elf_auxv_t;
|
||||||
|
typedef Elf32_Nhdr Elf_Nhdr;
|
||||||
|
typedef Elf32_Move Elf_Move;
|
||||||
|
typedef Elf32_Lib Elf_Lib;
|
||||||
|
#elif __WORDSIZE == 64
|
||||||
|
typedef Elf64_Half Elf_Half;
|
||||||
|
typedef Elf64_Word Elf_Word;
|
||||||
|
typedef Elf64_Sword Elf_Sword;
|
||||||
|
typedef Elf64_Xword Elf_Xword;
|
||||||
|
typedef Elf64_Sxword Elf_Sxword;
|
||||||
|
typedef Elf64_Addr Elf_Addr;
|
||||||
|
typedef Elf64_Off Elf_Off;
|
||||||
|
typedef Elf64_Section Elf_Section;
|
||||||
|
typedef Elf64_Versym Elf_Versym;
|
||||||
|
typedef Elf64_Ehdr Elf_Ehdr;
|
||||||
|
typedef Elf64_Shdr Elf_Shdr;
|
||||||
|
typedef Elf64_Sym Elf_Sym;
|
||||||
|
typedef Elf64_Syminfo Elf_Syminfo;
|
||||||
|
typedef Elf64_Rel Elf_Rel;
|
||||||
|
typedef Elf64_Rela Elf_Rela;
|
||||||
|
typedef Elf64_Phdr Elf_Phdr;
|
||||||
|
typedef Elf64_Dyn Elf_Dyn;
|
||||||
|
typedef Elf64_Verdef Elf_Verdef;
|
||||||
|
typedef Elf64_Verdaux Elf_Verdaux;
|
||||||
|
typedef Elf64_Verneed Elf_Verneed;
|
||||||
|
typedef Elf64_Vernaux Elf_Vernaux;
|
||||||
|
typedef Elf64_auxv_t Elf_auxv_t;
|
||||||
|
typedef Elf64_Nhdr Elf_Nhdr;
|
||||||
|
typedef Elf64_Move Elf_Move;
|
||||||
|
typedef Elf64_Lib Elf_Lib;
|
||||||
|
#else
|
||||||
|
#error "You need to typedef these to the types of your platform."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
@ -31,8 +32,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <sortix/elf-note.h>
|
|
||||||
|
|
||||||
extern "C" { pthread_mutex_t __pthread_keys_lock =
|
extern "C" { pthread_mutex_t __pthread_keys_lock =
|
||||||
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; }
|
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; }
|
||||||
extern "C" { struct pthread_key* __pthread_keys = NULL; }
|
extern "C" { struct pthread_key* __pthread_keys = NULL; }
|
||||||
|
|
Loading…
Reference in New Issue