mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:27:45 +00:00
Move ELFLoader code into Kernel/.
This commit is contained in:
parent
ac7a60225e
commit
44036f32bc
10 changed files with 5 additions and 27 deletions
211
Kernel/ELFImage.cpp
Normal file
211
Kernel/ELFImage.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
#include "ELFImage.h"
|
||||
#include <AK/kstdio.h>
|
||||
|
||||
ELFImage::ELFImage(const byte* buffer)
|
||||
: m_buffer(buffer)
|
||||
{
|
||||
m_valid = parse();
|
||||
}
|
||||
|
||||
ELFImage::~ELFImage()
|
||||
{
|
||||
}
|
||||
|
||||
static const char* objectFileTypeToString(Elf32_Half type)
|
||||
{
|
||||
switch (type) {
|
||||
case ET_NONE: return "None";
|
||||
case ET_REL: return "Relocatable";
|
||||
case ET_EXEC: return "Executable";
|
||||
case ET_DYN: return "Shared object";
|
||||
case ET_CORE: return "Core";
|
||||
default: return "(?)";
|
||||
}
|
||||
}
|
||||
|
||||
const char* ELFImage::section_index_to_string(unsigned index)
|
||||
{
|
||||
if (index == SHN_UNDEF)
|
||||
return "Undefined";
|
||||
if (index >= SHN_LORESERVE)
|
||||
return "Reserved";
|
||||
return section(index).name();
|
||||
}
|
||||
|
||||
unsigned ELFImage::symbol_count() const
|
||||
{
|
||||
return section(m_symbol_table_section_index).entry_count();
|
||||
}
|
||||
|
||||
void ELFImage::dump()
|
||||
{
|
||||
kprintf("ELFImage{%p} {\n", this);
|
||||
kprintf(" isValid: %u\n", is_valid());
|
||||
|
||||
if (!is_valid()) {
|
||||
kprintf("}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
kprintf(" type: %s\n", objectFileTypeToString(header().e_type));
|
||||
kprintf(" machine: %u\n", header().e_machine);
|
||||
kprintf(" entry: %x\n", header().e_entry);
|
||||
kprintf(" shoff: %u\n", header().e_shoff);
|
||||
kprintf(" shnum: %u\n", header().e_shnum);
|
||||
kprintf(" shstrndx: %u\n", header().e_shstrndx);
|
||||
|
||||
for (unsigned i = 0; i < header().e_shnum; ++i) {
|
||||
auto& section = this->section(i);
|
||||
kprintf(" Section %u: {\n", i);
|
||||
kprintf(" name: %s\n", section.name());
|
||||
kprintf(" type: %x\n", section.type());
|
||||
kprintf(" offset: %x\n", section.offset());
|
||||
kprintf(" size: %u\n", section.size());
|
||||
kprintf(" \n");
|
||||
kprintf(" }\n");
|
||||
}
|
||||
|
||||
kprintf("Symbol count: %u (table is %u)\n", symbol_count(), m_symbol_table_section_index);
|
||||
for (unsigned i = 1; i < symbol_count(); ++i) {
|
||||
auto& sym = symbol(i);
|
||||
kprintf("Symbol @%u:\n", i);
|
||||
kprintf(" Name: %s\n", sym.name());
|
||||
kprintf(" In section: %s\n", section_index_to_string(sym.section_index()));
|
||||
kprintf(" Value: %x\n", sym.value());
|
||||
kprintf(" Size: %u\n", sym.size());
|
||||
}
|
||||
|
||||
kprintf("}\n");
|
||||
}
|
||||
|
||||
unsigned ELFImage::section_count() const
|
||||
{
|
||||
return header().e_shnum;
|
||||
}
|
||||
|
||||
unsigned ELFImage::program_header_count() const
|
||||
{
|
||||
return header().e_phnum;
|
||||
}
|
||||
|
||||
bool ELFImage::parse()
|
||||
{
|
||||
// We only support i386.
|
||||
if (header().e_machine != 3)
|
||||
return false;
|
||||
|
||||
// First locate the string tables.
|
||||
for (unsigned i = 0; i < section_count(); ++i) {
|
||||
auto& sh = section_header(i);
|
||||
if (sh.sh_type == SHT_SYMTAB) {
|
||||
ASSERT(!m_symbol_table_section_index);
|
||||
m_symbol_table_section_index = i;
|
||||
}
|
||||
if (sh.sh_type == SHT_STRTAB && i != header().e_shstrndx) {
|
||||
ASSERT(!m_string_table_section_index);
|
||||
m_string_table_section_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
// Then create a name-to-index map.
|
||||
for (unsigned i = 0; i < section_count(); ++i) {
|
||||
auto& section = this->section(i);
|
||||
m_sections.set(section.name(), move(i));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ELFImage::section_header_table_string(unsigned offset) const
|
||||
{
|
||||
auto& sh = section_header(header().e_shstrndx);
|
||||
if (sh.sh_type != SHT_STRTAB)
|
||||
return nullptr;
|
||||
return raw_data(sh.sh_offset + offset);
|
||||
}
|
||||
|
||||
const char* ELFImage::table_string(unsigned offset) const
|
||||
{
|
||||
auto& sh = section_header(m_string_table_section_index);
|
||||
if (sh.sh_type != SHT_STRTAB)
|
||||
return nullptr;
|
||||
return raw_data(sh.sh_offset + offset);
|
||||
}
|
||||
|
||||
const char* ELFImage::raw_data(unsigned offset) const
|
||||
{
|
||||
return reinterpret_cast<const char*>(m_buffer) + offset;
|
||||
}
|
||||
|
||||
const Elf32_Ehdr& ELFImage::header() const
|
||||
{
|
||||
return *reinterpret_cast<const Elf32_Ehdr*>(raw_data(0));
|
||||
}
|
||||
|
||||
const Elf32_Phdr& ELFImage::program_header_internal(unsigned index) const
|
||||
{
|
||||
ASSERT(index < header().e_phnum);
|
||||
return *reinterpret_cast<const Elf32_Phdr*>(raw_data(header().e_phoff + (index * sizeof(Elf32_Phdr))));
|
||||
}
|
||||
|
||||
const Elf32_Shdr& ELFImage::section_header(unsigned index) const
|
||||
{
|
||||
ASSERT(index < header().e_shnum);
|
||||
return *reinterpret_cast<const Elf32_Shdr*>(raw_data(header().e_shoff + (index * sizeof(Elf32_Shdr))));
|
||||
}
|
||||
|
||||
const ELFImage::Symbol ELFImage::symbol(unsigned index) const
|
||||
{
|
||||
ASSERT(index < symbol_count());
|
||||
auto* rawSyms = reinterpret_cast<const Elf32_Sym*>(raw_data(section(m_symbol_table_section_index).offset()));
|
||||
return Symbol(*this, index, rawSyms[index]);
|
||||
}
|
||||
|
||||
const ELFImage::Section ELFImage::section(unsigned index) const
|
||||
{
|
||||
ASSERT(index < section_count());
|
||||
return Section(*this, index);
|
||||
}
|
||||
|
||||
const ELFImage::ProgramHeader ELFImage::program_header(unsigned index) const
|
||||
{
|
||||
ASSERT(index < program_header_count());
|
||||
return ProgramHeader(*this, index);
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
const ELFImage::Relocation ELFImage::RelocationSection::relocation(unsigned index) const
|
||||
{
|
||||
ASSERT(index < relocation_count());
|
||||
auto* rels = reinterpret_cast<const Elf32_Rel*>(m_image.raw_data(offset()));
|
||||
return Relocation(m_image, rels[index]);
|
||||
}
|
||||
|
||||
const ELFImage::RelocationSection ELFImage::Section::relocations() const
|
||||
{
|
||||
// FIXME: This is ugly.
|
||||
char relocationSectionName[128];
|
||||
ksprintf(relocationSectionName, ".rel%s", name());
|
||||
|
||||
#ifdef ELFIMAGE_DEBUG
|
||||
kprintf("looking for '%s'\n", relocationSectionName);
|
||||
#endif
|
||||
auto relocationSection = m_image.lookupSection(relocationSectionName);
|
||||
if (relocationSection.type() != SHT_REL)
|
||||
return static_cast<const RelocationSection>(m_image.section(0));
|
||||
|
||||
#ifdef ELFIMAGE_DEBUG
|
||||
kprintf("Found relocations for %s in %s\n", name(), relocationSection.name());
|
||||
#endif
|
||||
return static_cast<const RelocationSection>(relocationSection);
|
||||
}
|
||||
|
||||
const ELFImage::Section ELFImage::lookupSection(const char* name) const
|
||||
{
|
||||
if (auto it = m_sections.find(name); it != m_sections.end())
|
||||
return section((*it).value);
|
||||
return section(0);
|
||||
}
|
||||
#endif
|
||||
|
221
Kernel/ELFImage.h
Normal file
221
Kernel/ELFImage.h
Normal file
|
@ -0,0 +1,221 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/String.h>
|
||||
#include "elf.h"
|
||||
#include "types.h"
|
||||
|
||||
class ELFImage {
|
||||
public:
|
||||
explicit ELFImage(const byte*);
|
||||
~ELFImage();
|
||||
void dump();
|
||||
bool is_valid() const { return m_valid; }
|
||||
bool parse();
|
||||
|
||||
class Section;
|
||||
class RelocationSection;
|
||||
class Symbol;
|
||||
class Relocation;
|
||||
|
||||
class Symbol {
|
||||
public:
|
||||
Symbol(const ELFImage& image, unsigned index, const Elf32_Sym& sym)
|
||||
: m_image(image)
|
||||
, m_sym(sym)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
~Symbol() { }
|
||||
|
||||
const char* name() const { return m_image.table_string(m_sym.st_name); }
|
||||
unsigned section_index() const { return m_sym.st_shndx; }
|
||||
unsigned value() const { return m_sym.st_value; }
|
||||
unsigned size() const { return m_sym.st_size; }
|
||||
unsigned index() const { return m_index; }
|
||||
unsigned type() const { return ELF32_ST_TYPE(m_sym.st_info); }
|
||||
const Section section() const { return m_image.section(section_index()); }
|
||||
|
||||
private:
|
||||
const ELFImage& m_image;
|
||||
const Elf32_Sym& m_sym;
|
||||
const unsigned m_index;
|
||||
};
|
||||
|
||||
class ProgramHeader {
|
||||
public:
|
||||
ProgramHeader(const ELFImage& image, unsigned program_header_index)
|
||||
: m_program_header(image.program_header_internal(program_header_index))
|
||||
, m_program_header_index(program_header_index)
|
||||
{
|
||||
}
|
||||
~ProgramHeader() { }
|
||||
|
||||
unsigned index() const { return m_program_header_index; }
|
||||
dword type() const { return m_program_header.p_type; }
|
||||
dword flags() const { return m_program_header.p_flags; }
|
||||
dword offset() const { return m_program_header.p_offset; }
|
||||
LinearAddress laddr() const { return LinearAddress(m_program_header.p_vaddr); }
|
||||
dword size_in_memory() const { return m_program_header.p_memsz; }
|
||||
dword size_in_image() const { return m_program_header.p_filesz; }
|
||||
dword alignment() const { return m_program_header.p_align; }
|
||||
bool is_readable() const { return flags() & PF_R; }
|
||||
bool is_writable() const { return flags() & PF_W; }
|
||||
bool is_executable() const { return flags() & PF_X; }
|
||||
private:
|
||||
const Elf32_Phdr& m_program_header;
|
||||
unsigned m_program_header_index { 0 };
|
||||
};
|
||||
|
||||
class Section {
|
||||
public:
|
||||
Section(const ELFImage& image, unsigned sectionIndex)
|
||||
: m_image(image)
|
||||
, m_section_header(image.section_header(sectionIndex))
|
||||
, m_section_index(sectionIndex)
|
||||
{
|
||||
}
|
||||
~Section() { }
|
||||
|
||||
const char* name() const { return m_image.section_header_table_string(m_section_header.sh_name); }
|
||||
unsigned type() const { return m_section_header.sh_type; }
|
||||
unsigned offset() const { return m_section_header.sh_offset; }
|
||||
unsigned size() const { return m_section_header.sh_size; }
|
||||
unsigned entry_size() const { return m_section_header.sh_entsize; }
|
||||
unsigned entry_count() const { return size() / entry_size(); }
|
||||
dword address() const { return m_section_header.sh_addr; }
|
||||
const char* raw_data() const { return m_image.raw_data(m_section_header.sh_offset); }
|
||||
bool is_undefined() const { return m_section_index == SHN_UNDEF; }
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
const RelocationSection relocations() const;
|
||||
#endif
|
||||
dword flags() const { return m_section_header.sh_flags; }
|
||||
bool is_writable() const { return flags() & SHF_WRITE; }
|
||||
bool is_executable() const { return flags() & PF_X; }
|
||||
|
||||
protected:
|
||||
friend class RelocationSection;
|
||||
const ELFImage& m_image;
|
||||
const Elf32_Shdr& m_section_header;
|
||||
unsigned m_section_index;
|
||||
};
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
class RelocationSection : public Section {
|
||||
public:
|
||||
RelocationSection(const Section& section)
|
||||
: Section(section.m_image, section.m_section_index)
|
||||
{
|
||||
}
|
||||
unsigned relocation_count() const { return entry_count(); }
|
||||
const Relocation relocation(unsigned index) const;
|
||||
template<typename F> void for_each_relocation(F) const;
|
||||
};
|
||||
|
||||
class Relocation {
|
||||
public:
|
||||
Relocation(const ELFImage& image, const Elf32_Rel& rel)
|
||||
: m_image(image)
|
||||
, m_rel(rel)
|
||||
{
|
||||
}
|
||||
|
||||
~Relocation() { }
|
||||
|
||||
unsigned offset() const { return m_rel.r_offset; }
|
||||
unsigned type() const { return ELF32_R_TYPE(m_rel.r_info); }
|
||||
unsigned symbol_index() const { return ELF32_R_SYM(m_rel.r_info); }
|
||||
const Symbol symbol() const { return m_image.symbol(symbol_index()); }
|
||||
|
||||
private:
|
||||
const ELFImage& m_image;
|
||||
const Elf32_Rel& m_rel;
|
||||
};
|
||||
#endif
|
||||
|
||||
unsigned symbol_count() const;
|
||||
unsigned section_count() const;
|
||||
unsigned program_header_count() const;
|
||||
|
||||
const Symbol symbol(unsigned) const;
|
||||
const Section section(unsigned) const;
|
||||
const ProgramHeader program_header(unsigned const) const;
|
||||
|
||||
template<typename F> void for_each_section(F) const;
|
||||
template<typename F> void for_each_section_of_type(unsigned, F) const;
|
||||
template<typename F> void for_each_symbol(F) const;
|
||||
template<typename F> void for_each_program_header(F) const;
|
||||
|
||||
// NOTE: Returns section(0) if section with name is not found.
|
||||
// FIXME: I don't love this API.
|
||||
const Section lookupSection(const char* name) const;
|
||||
|
||||
bool is_executable() const { return header().e_type == ET_EXEC; }
|
||||
bool is_relocatable() const { return header().e_type == ET_REL; }
|
||||
|
||||
private:
|
||||
bool parseHeader();
|
||||
const char* raw_data(unsigned offset) const;
|
||||
const Elf32_Ehdr& header() const;
|
||||
const Elf32_Shdr& section_header(unsigned) const;
|
||||
const Elf32_Phdr& program_header_internal(unsigned) const;
|
||||
const char* table_string(unsigned offset) const;
|
||||
const char* section_header_table_string(unsigned offset) const;
|
||||
const char* section_index_to_string(unsigned index);
|
||||
|
||||
const byte* m_buffer { nullptr };
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
HashMap<String, unsigned> m_sections;
|
||||
#endif
|
||||
bool m_valid { false };
|
||||
unsigned m_symbol_table_section_index { 0 };
|
||||
unsigned m_string_table_section_index { 0 };
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
inline void ELFImage::for_each_section(F func) const
|
||||
{
|
||||
for (unsigned i = 0; i < section_count(); ++i)
|
||||
func(section(i));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void ELFImage::for_each_section_of_type(unsigned type, F func) const
|
||||
{
|
||||
for (unsigned i = 0; i < section_count(); ++i) {
|
||||
auto& section = this->section(i);
|
||||
if (section.type() == type) {
|
||||
if (!func(section))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
template<typename F>
|
||||
inline void ELFImage::RelocationSection::for_each_relocation(F func) const
|
||||
{
|
||||
for (unsigned i = 0; i < relocation_count(); ++i) {
|
||||
if (!func(relocation(i)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename F>
|
||||
inline void ELFImage::for_each_symbol(F func) const
|
||||
{
|
||||
for (unsigned i = 0; i < symbol_count(); ++i) {
|
||||
if (!func(symbol(i)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void ELFImage::for_each_program_header(F func) const
|
||||
{
|
||||
for (unsigned i = 0; i < program_header_count(); ++i)
|
||||
func(program_header(i));
|
||||
}
|
219
Kernel/ELFLoader.cpp
Normal file
219
Kernel/ELFLoader.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
#include "ELFLoader.h"
|
||||
#include <AK/kstdio.h>
|
||||
|
||||
//#define ELFLOADER_DEBUG
|
||||
//#define SUPPORT_RELOCATIONS
|
||||
|
||||
ELFLoader::ELFLoader(const byte* buffer)
|
||||
: m_image(buffer)
|
||||
{
|
||||
}
|
||||
|
||||
ELFLoader::~ELFLoader()
|
||||
{
|
||||
}
|
||||
|
||||
bool ELFLoader::load()
|
||||
{
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
m_image.dump();
|
||||
#endif
|
||||
if (!m_image.is_valid())
|
||||
return false;
|
||||
|
||||
if (!layout())
|
||||
return false;
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
if (!perform_relocations())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ELFLoader::layout()
|
||||
{
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: Layout\n");
|
||||
#endif
|
||||
|
||||
bool failed = false;
|
||||
m_image.for_each_program_header([&] (const ELFImage::ProgramHeader& program_header) {
|
||||
if (program_header.type() != PT_LOAD)
|
||||
return;
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("PH: L%x %u r:%u w:%u\n", program_header.laddr().get(), program_header.size_in_memory(), program_header.is_readable(), program_header.is_writable());
|
||||
#endif
|
||||
if (program_header.is_writable()) {
|
||||
allocate_section(program_header.laddr(), program_header.size_in_memory(), program_header.alignment(), program_header.is_readable(), program_header.is_writable());
|
||||
} else {
|
||||
map_section(program_header.laddr(), program_header.size_in_memory(), program_header.alignment(), program_header.offset(), program_header.is_readable(), program_header.is_writable());
|
||||
}
|
||||
});
|
||||
|
||||
m_image.for_each_section_of_type(SHT_PROGBITS, [] (const ELFImage::Section& section) {
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: Copying progbits section: %s\n", section.name());
|
||||
#endif
|
||||
if (!section.size())
|
||||
return true;
|
||||
char* ptr = (char*)section.address();
|
||||
if (!ptr) {
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: ignoring section '%s' with null address\n", section.name());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
// If this section isn't writable, it's already mmapped.
|
||||
if (section.is_writable())
|
||||
memcpy(ptr, section.raw_data(), section.size());
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
m_sections.set(section.name(), move(ptr));
|
||||
#endif
|
||||
return true;
|
||||
});
|
||||
m_image.for_each_section_of_type(SHT_NOBITS, [&failed] (const ELFImage::Section& section) {
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: Copying nobits section: %s\n", section.name());
|
||||
#endif
|
||||
if (!section.size())
|
||||
return true;
|
||||
char* ptr = (char*)section.address();
|
||||
if (!ptr) {
|
||||
kprintf("ELFLoader: failed to allocate section '%s'\n", section.name());
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
memset(ptr, 0, section.size());
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
m_sections.set(section.name(), move(ptr));
|
||||
#endif
|
||||
return true;
|
||||
});
|
||||
return !failed;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
void* ELFLoader::lookup(const ELFImage::Symbol& symbol)
|
||||
{
|
||||
if (symbol.section().is_undefined())
|
||||
return symbol_ptr(symbol.name());
|
||||
return area_for_section(symbol.section()) + symbol.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
char* ELFLoader::area_for_section(const ELFImage::Section& section)
|
||||
{
|
||||
return area_for_section_name(section.name());
|
||||
}
|
||||
|
||||
char* ELFLoader::area_for_section_name(const char* name)
|
||||
{
|
||||
if (auto it = m_sections.find(name); it != m_sections.end())
|
||||
return (*it).value;
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
bool ELFLoader::perform_relocations()
|
||||
{
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: Performing relocations\n");
|
||||
#endif
|
||||
|
||||
bool failed = false;
|
||||
|
||||
m_image.for_each_section_of_type(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) -> bool {
|
||||
auto& relocations = section.relocations();
|
||||
if (relocations.is_undefined())
|
||||
return true;
|
||||
relocations.for_each_relocation([this, section, &failed] (const ELFImage::Relocation& relocation) {
|
||||
auto symbol = relocation.symbol();
|
||||
auto& patch_ptr = *reinterpret_cast<ptrdiff_t*>(area_for_section(section) + relocation.offset());
|
||||
|
||||
switch (relocation.type()) {
|
||||
case R_386_PC32: {
|
||||
char* target_ptr = (char*)lookup(symbol);
|
||||
if (!target_ptr) {
|
||||
kprintf("ELFLoader: unresolved symbol '%s'\n", symbol.name());
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
ptrdiff_t relativeOffset = (char*)target_ptr - ((char*)&patch_ptr + 4);
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: Relocate PC32: offset=%x, symbol=%u(%s) value=%x target=%p, offset=%d\n",
|
||||
relocation.offset(),
|
||||
symbol.index(),
|
||||
symbol.name(),
|
||||
symbol.value(),
|
||||
target_ptr,
|
||||
relativeOffset
|
||||
);
|
||||
#endif
|
||||
patch_ptr = relativeOffset;
|
||||
break;
|
||||
}
|
||||
case R_386_32: {
|
||||
#ifdef ELFLOADER_DEBUG
|
||||
kprintf("ELFLoader: Relocate Abs32: symbol=%u(%s), value=%x, section=%s\n",
|
||||
symbol.index(),
|
||||
symbol.name(),
|
||||
symbol.value(),
|
||||
symbol.section().name()
|
||||
);
|
||||
#endif
|
||||
char* target_ptr = area_for_section(symbol.section()) + symbol.value();
|
||||
patch_ptr += (ptrdiff_t)target_ptr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return !failed;
|
||||
});
|
||||
return !failed;
|
||||
}
|
||||
#endif
|
||||
|
||||
char* ELFLoader::symbol_ptr(const char* name)
|
||||
{
|
||||
char* found_ptr = nullptr;
|
||||
m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
|
||||
if (symbol.type() != STT_FUNC)
|
||||
return true;
|
||||
if (strcmp(symbol.name(), name))
|
||||
return true;
|
||||
if (m_image.is_executable())
|
||||
found_ptr = (char*)symbol.value();
|
||||
#ifdef SUPPORT_RELOCATIONS
|
||||
else if (m_image.is_relocatable())
|
||||
found_ptr = area_for_section(symbol.section()) + symbol.value();
|
||||
#endif
|
||||
else
|
||||
ASSERT_NOT_REACHED();
|
||||
return false;
|
||||
});
|
||||
return found_ptr;
|
||||
}
|
||||
|
||||
bool ELFLoader::allocate_section(LinearAddress laddr, size_t size, size_t alignment, bool is_readable, bool is_writable)
|
||||
{
|
||||
ASSERT(alloc_section_hook);
|
||||
char namebuf[16];
|
||||
ksprintf(namebuf, "elf-alloc-%s%s", is_readable ? "r" : "", is_writable ? "w" : "");
|
||||
return alloc_section_hook(laddr, size, alignment, is_readable, is_writable, namebuf);
|
||||
}
|
||||
|
||||
bool ELFLoader::map_section(LinearAddress laddr, size_t size, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable)
|
||||
{
|
||||
ASSERT(alloc_section_hook);
|
||||
char namebuf[16];
|
||||
ksprintf(namebuf, "elf-map-%s%s", is_readable ? "r" : "", is_writable ? "w" : "");
|
||||
return map_section_hook(laddr, size, alignment, offset_in_image, is_readable, is_writable, namebuf);
|
||||
}
|
43
Kernel/ELFLoader.h
Normal file
43
Kernel/ELFLoader.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Vector.h>
|
||||
#include "ELFImage.h"
|
||||
|
||||
class ELFLoader {
|
||||
public:
|
||||
explicit ELFLoader(const byte*);
|
||||
~ELFLoader();
|
||||
|
||||
bool load();
|
||||
Function<void*(LinearAddress, size_t, size_t, bool, bool, const String&)> alloc_section_hook;
|
||||
Function<void*(LinearAddress, size_t, size_t, size_t, bool, bool, const String&)> map_section_hook;
|
||||
char* symbol_ptr(const char* name);
|
||||
bool allocate_section(LinearAddress, size_t, size_t alignment, bool is_readable, bool is_writable);
|
||||
bool map_section(LinearAddress, size_t, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable);
|
||||
|
||||
private:
|
||||
bool layout();
|
||||
bool perform_relocations();
|
||||
void* lookup(const ELFImage::Symbol&);
|
||||
char* area_for_section(const ELFImage::Section&);
|
||||
char* area_for_section_name(const char*);
|
||||
|
||||
struct PtrAndSize {
|
||||
PtrAndSize() { }
|
||||
PtrAndSize(char* p, unsigned s)
|
||||
: ptr(p)
|
||||
, size(s)
|
||||
{
|
||||
}
|
||||
|
||||
char* ptr { nullptr };
|
||||
unsigned size { 0 };
|
||||
};
|
||||
ELFImage m_image;
|
||||
|
||||
HashMap<String, char*> m_sections;
|
||||
};
|
||||
|
|
@ -20,7 +20,9 @@ KERNEL_OBJS = \
|
|||
TTY.o \
|
||||
VirtualConsole.o \
|
||||
FIFO.o \
|
||||
Scheduler.o
|
||||
Scheduler.o \
|
||||
ELFImage.o \
|
||||
ELFLoader.o
|
||||
|
||||
VFS_OBJS = \
|
||||
../VirtualFileSystem/DiskDevice.o \
|
||||
|
@ -37,10 +39,6 @@ VFS_OBJS = \
|
|||
../VirtualFileSystem/FileDescriptor.o \
|
||||
../VirtualFileSystem/SyntheticFileSystem.o
|
||||
|
||||
ELFLOADER_OBJS = \
|
||||
../ELFLoader/ELFImage.o \
|
||||
../ELFLoader/ELFLoader.o
|
||||
|
||||
AK_OBJS = \
|
||||
../AK/String.o \
|
||||
../AK/StringImpl.o \
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "system.h"
|
||||
#include <VirtualFileSystem/FileDescriptor.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <ELFLoader/ELFLoader.h>
|
||||
#include "ELFLoader.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "errno.h"
|
||||
#include "i8253.h"
|
||||
|
|
2645
Kernel/elf.h
Normal file
2645
Kernel/elf.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -19,7 +19,7 @@
|
|||
#include <VirtualFileSystem/FileDescriptor.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include "MemoryManager.h"
|
||||
#include <ELFLoader/ELFLoader.h>
|
||||
#include "ELFLoader.h"
|
||||
#include "Console.h"
|
||||
#include "ProcFileSystem.h"
|
||||
#include "RTC.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue