Simple ELF program loader

Now any initrd file is treated like a program image and passed to the
loader to load as a process. Very rudimentary elf loading just allocates
pages, copies sections, and sets the ELF's entrypoint as the RIP to
iretq to.
This commit is contained in:
Justin C. Miller
2018-09-06 01:31:47 -07:00
parent 3d0b262435
commit 585abe9a18
13 changed files with 321 additions and 51 deletions

49
src/libraries/elf/elf.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "elf/elf.h"
#include "elf/headers.h"
static const uint32_t expected_magic = 0x464c457f; // "\x7f" "ELF"
namespace elf {
elf::elf(const void *data, size_t size) :
m_data(data),
m_size(size)
{
}
bool
elf::valid() const
{
const file_header *fheader = header();
return
fheader->magic == expected_magic &&
fheader->word_size == wordsize::bits64 &&
fheader->endianness == encoding::lsb &&
fheader->os_abi == osabi::sysV &&
fheader->file_type == filetype::executable &&
fheader->machine_type == machine::x64 &&
fheader->ident_version == 1 &&
fheader->version == 1;
}
const program_header *
elf::program(unsigned index) const
{
const file_header *fheader = header();
uint64_t off = fheader->ph_offset + (index * fheader->ph_entsize);
const void *pheader = kutil::offset_pointer(m_data, off);
return reinterpret_cast<const program_header *>(pheader);
}
const section_header *
elf::section(unsigned index) const
{
const file_header *fheader = header();
uint64_t off = fheader->sh_offset + (index * fheader->sh_entsize);
const void *sheader = kutil::offset_pointer(m_data, off);
return reinterpret_cast<const section_header *>(sheader);
}
} // namespace elf

61
src/libraries/elf/elf.h Normal file
View File

@@ -0,0 +1,61 @@
#pragma once
#include <stddef.h>
#include "elf/headers.h"
#include "kutil/memory.h"
namespace elf {
class elf
{
public:
/// Constructor: Create an elf object out of ELF data in memory
/// \arg data The ELF data to read
/// \arg size Size of the ELF data, in bytes
elf(const void *data, size_t size);
/// Check the validity of the ELF data
/// \returns true for valid ELF data
bool valid() const;
/// Get the entrypoint address of the program image
/// \returns A pointer to the entrypoint of the program
inline addr_t entrypoint() const
{
return static_cast<addr_t>(header()->entrypoint);
}
/// Get the number of program sections in the image
/// \returns The number of program section entries
inline unsigned program_count() const
{
return header()->ph_num;
}
/// Get a program header
/// \arg index The index number of the program header
/// \returns A pointer to the program header data
const program_header * program(unsigned index) const;
/// Get the number of data sections in the image
/// \returns The number of section entries
inline unsigned section_count() const
{
return header()->sh_num;
}
/// Get a section header
/// \arg index The index number of the section header
/// \returns A pointer to the section header data
const section_header * section(unsigned index) const;
private:
inline const file_header *header() const
{
return reinterpret_cast<const file_header *>(m_data);
}
const void *m_data;
size_t m_size;
};
}

View File

@@ -0,0 +1,98 @@
#pragma once
#include <stdint.h>
#include "kutil/enum_bitfields.h"
namespace elf {
enum class wordsize : uint8_t { invalid, bits32, bits64 };
enum class encoding : uint8_t { invalid, lsb, msb };
enum class osabi : uint8_t { sysV, hpux, standalone = 255 };
enum class machine : uint16_t { none, x64 = 0x3e };
enum class filetype : uint16_t
{
none,
relocatable,
executable,
shared,
core
};
struct file_header
{
uint32_t magic;
wordsize word_size;
encoding endianness;
uint8_t ident_version;
osabi os_abi;
uint64_t reserved;
filetype file_type;
machine machine_type;
uint32_t version;
uint64_t entrypoint;
uint64_t ph_offset;
uint64_t sh_offset;
uint32_t flags;
uint16_t eh_size;
uint16_t ph_entsize;
uint16_t ph_num;
uint16_t sh_entsize;
uint16_t sh_num;
uint16_t sh_str_idx;
} __attribute__ ((packed));
enum class segment_type : uint32_t { null, load, dynamic, interpreter, note };
struct program_header
{
segment_type type;
uint32_t flags;
uint64_t offset;
uint64_t vaddr;
uint64_t paddr;
uint64_t file_size;
uint64_t mem_size;
uint64_t align;
} __attribute__ ((packed));
enum class section_type : uint32_t { null, progbits };
enum class section_flags : uint64_t
{
write = 0x01,
alloc = 0x02,
exec = 0x04,
};
struct section_header
{
uint32_t name_offset;
section_type type;
section_flags flags;
uint64_t addr;
uint64_t offset;
uint64_t size;
uint32_t link;
uint32_t info;
uint64_t align;
uint64_t entry_size;
} __attribute__ ((packed));
} // namespace elf
IS_BITFIELD(elf::section_flags);

14
src/libraries/elf/wscript Normal file
View File

@@ -0,0 +1,14 @@
def configure(ctx):
pass
def build(bld):
sources = bld.path.ant_glob("**/*.cpp")
bld.stlib(
source = sources,
name = 'elf',
target = 'elf',
)
# vim: ft=python et

View File

@@ -17,9 +17,9 @@ memset(void *s, uint8_t v, size_t n)
}
void *
memcpy(void *dest, void *src, size_t n)
memcpy(void *dest, const void *src, size_t n)
{
uint8_t *s = reinterpret_cast<uint8_t *>(src);
const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
uint8_t *d = reinterpret_cast<uint8_t *>(dest);
for (size_t i = 0; i < n; ++i) d[i] = s[i];
return d;

View File

@@ -35,7 +35,7 @@ void * memset(void *p, uint8_t v, size_t n);
/// \src The memory to copy from
/// \n The number of bytes to copy
/// \returns A pointer to the destination memory
void * memcpy(void *dest, void *src, size_t n);
void * memcpy(void *dest, const void *src, size_t n);
/// Read a value of type T from a location in memory
/// \arg p The location in memory to read