[elf] Ressurect elf library

Resurrect the existing but unused ELF library in libraries/elf, and use
it instead of boot/elf.h for parsing ELF files in the bootloader.

Also adds a const version of offset_iterator called
const_offset_iterator.
This commit is contained in:
Justin C. Miller
2021-07-31 15:10:03 -07:00
parent 5e2cfab7ba
commit 363d30eadc
9 changed files with 189 additions and 250 deletions

View File

@@ -1,50 +0,0 @@
#include "elf/elf.h"
#include "elf/headers.h"
#include "kutil/memory.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

View File

@@ -0,0 +1,45 @@
#include "elf/file.h"
#include "elf/headers.h"
#include "pointer_manipulation.h"
static const uint32_t expected_magic = 0x464c457f; // "\x7f" "ELF"
namespace elf {
inline const file_header * fh(const void *data) { return reinterpret_cast<const file_header*>(data); }
file::file(const void *data, size_t size) :
m_programs(offset_ptr<program_header>(data, fh(data)->ph_offset), fh(data)->ph_entsize, fh(data)->ph_num),
m_sections(offset_ptr<section_header>(data, fh(data)->sh_offset), fh(data)->sh_entsize, fh(data)->sh_num),
m_data(data),
m_size(size)
{
}
bool
file::valid() const
{
if (m_size < sizeof(file_header))
return false;
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;
}
uintptr_t
file::entrypoint() const
{
return static_cast<uintptr_t>(header()->entrypoint);
}
} // namespace elf

View File

@@ -1,61 +0,0 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "elf/headers.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 uintptr_t entrypoint() const
{
return static_cast<uintptr_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,75 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "pointer_manipulation.h"
namespace elf {
struct file_header;
struct program_header;
struct section_header;
template <typename T>
class subheaders
{
public:
using iterator = const_offset_iterator<T>;
subheaders(const T *start, size_t size, unsigned count) :
m_start(start), m_size(size), m_count(count) {}
inline size_t size() const { return m_size; }
inline unsigned count() const { return m_count; }
inline const T & operator [] (int i) const { return *offset_ptr<T>(m_start, m_size*i); }
inline const iterator begin() const { return iterator(m_start, m_size); }
inline const iterator end() const { return offset_ptr<T>(m_start, m_size*m_count); }
private:
const T *m_start;
size_t m_size;
unsigned m_count;
};
/// Represents a full ELF file's data
class file
{
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
file(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
uintptr_t entrypoint() const;
/// Get the base address of the program in memory
inline uintptr_t base() const {
return reinterpret_cast<uintptr_t>(m_data);
}
/// Get the ELF program headers
inline const subheaders<program_header> & programs() const { return m_programs; }
/// Get the ELF section headers
inline const subheaders<section_header> & sections() const { return m_sections; }
inline const file_header * header() const {
return reinterpret_cast<const file_header *>(m_data);
}
private:
subheaders<program_header> m_programs;
subheaders<section_header> m_sections;
const void *m_data;
size_t m_size;
};
}

View File

@@ -0,0 +1,6 @@
name = "elf"
kind = "lib"
includes = [ "src/libraries/elf/include" ]
sources = [
"file.cpp",
]