/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
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 .
elf.h
Constructs processes from ELF files.
******************************************************************************/
#include "platform.h"
#include
#include "elf.h"
#include "memorymanagement.h"
#include "log.h" // DEBUG
namespace Sortix
{
namespace ELF
{
addr_t Construct32(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 first section header.
addr_t shtbloffset = header->sectionheaderoffset;
addr_t shtblpos = ((addr_t) file) + shtbloffset;
size_t shsize = header->sectionheaderentrysize;
// Validate that all sections are present.
uint16_t numsections = header->numsectionheaderentries;
size_t neededfilelen = shtbloffset + numsections * shsize;
if ( filelen < neededfilelen ) { return 0; }
addr_t memlower = SIZE_MAX;
addr_t memupper = 0;
// Valid all the data we need is in the file.
for ( uint16_t i = 0; i < numsections; i++ )
{
addr_t shoffset = i * shsize;
addr_t shpos = shtblpos + shoffset;
const SectionHeader32* sh = (const SectionHeader32*) shpos;
if ( sh->addr == 0 ) { continue; }
if ( sh->type == SHT_PROGBITS )
{
size_t sectionendsat = sh->offset + sh->size;
if ( filelen < sectionendsat ) { return 0; }
}
if ( sh->type == SHT_PROGBITS || sh->type == SHT_NOBITS )
{
if ( sh->addr < memlower ) { memlower = sh->addr; }
if ( memupper < sh->addr + sh->size ) { memupper = sh->addr + sh->size; }
}
}
if ( memupper < memlower ) { return entry; }
// HACK: For now just put it in the same continious block. This is
// very wasteful and not very intelligent.
addr_t mapto = Page::AlignDown(memlower);
addr_t mapbytes = memupper - mapto;
// TODO: Validate that we actually may map here!
if ( !VirtualMemory::MapRangeUser(mapto, mapbytes) )
{
return 0;
}
// Create all the sections in the final process.
for ( uint16_t i = 0; i < numsections; i++ )
{
addr_t shoffset = i * shsize;
addr_t shpos = shtblpos + shoffset;
const SectionHeader32* sh = (const SectionHeader32*) shpos;
if ( sh->type != SHT_PROGBITS && sh->type != SHT_NOBITS )
{
continue;
}
if ( sh->addr == 0 ) { continue; }
if ( sh->type == SHT_PROGBITS )
{
void* memdest = (void*) sh->addr;
void* memsource = (void*) ( ((addr_t) file) + sh->offset );
Maxsi::Memory::Copy(memdest, memsource, sh->size);
}
}
// MEMORY LEAK: There is no system in place to delete the sections
// once the process has terminated.
return entry;
}
addr_t Construct64(const void* /*file*/, size_t /*filelen*/)
{
return 0;
}
addr_t Construct(const void* file, size_t filelen)
{
if ( filelen < sizeof(Header) ) { 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' ) )
{
return 0;
}
switch ( header->fileclass )
{
case CLASS32:
return Construct32(file, filelen);
case CLASS64:
return Construct64(file, filelen);
default:
return 0;
}
}
}
}