mirror of
https://github.com/fergalmoran/ladybird.git
synced 2025-12-29 12:49:08 +00:00
We don't do anything useful with the data yet, but I'm gonna rewrite the layout code to run off of the program header table instead. This will allow us to map .text and .rodata sections in read-only memory.
203 lines
6.3 KiB
C++
203 lines
6.3 KiB
C++
#include "ELFLoader.h"
|
|
#include <AK/kstdio.h>
|
|
|
|
//#define ELFLOADER_DEBUG
|
|
|
|
#ifdef SERENITY
|
|
ELFLoader::ELFLoader(ExecSpace& execSpace, ByteBuffer&& file)
|
|
#else
|
|
ELFLoader::ELFLoader(ExecSpace& execSpace, MappedFile&& file)
|
|
#endif
|
|
: m_execSpace(execSpace)
|
|
{
|
|
m_image = make<ELFImage>(move(file));
|
|
}
|
|
|
|
ELFLoader::~ELFLoader()
|
|
{
|
|
}
|
|
|
|
bool ELFLoader::load()
|
|
{
|
|
#ifdef ELFLOADER_DEBUG
|
|
m_image->dump();
|
|
#endif
|
|
if (!m_image->isValid())
|
|
return false;
|
|
|
|
if (!layout())
|
|
return false;
|
|
exportSymbols();
|
|
if (!performRelocations())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ELFLoader::layout()
|
|
{
|
|
#ifdef ELFLOADER_DEBUG
|
|
kprintf("ELFLoader: Layout\n");
|
|
#endif
|
|
|
|
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
|
|
});
|
|
|
|
bool failed = false;
|
|
dword highestOffset = 0;
|
|
dword sizeNeeded = 0;
|
|
m_image->forEachSection([&] (auto& section) {
|
|
if (section.offset() > highestOffset) {
|
|
highestOffset = section.offset();
|
|
sizeNeeded = highestOffset + section.size();
|
|
}
|
|
});
|
|
#ifdef ELFLOADER_DEBUG
|
|
kprintf("ELFLoader: Highest section offset: %u, Size needed: %u\n", highestOffset, sizeNeeded);
|
|
#endif
|
|
m_execSpace.allocateUniverse(sizeNeeded);
|
|
|
|
m_image->forEachSectionOfType(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) {
|
|
#ifdef ELFLOADER_DEBUG
|
|
kprintf("ELFLoader: Allocating progbits section: %s\n", section.name());
|
|
#endif
|
|
if (!section.size())
|
|
return true;
|
|
char* ptr = m_execSpace.allocateArea(section.name(), section.size(), section.offset(), LinearAddress(section.address()));
|
|
if (!ptr) {
|
|
kprintf("ELFLoader: failed to allocate section '%s'\n", section.name());
|
|
failed = true;
|
|
return false;
|
|
}
|
|
memcpy(ptr, section.rawData(), section.size());
|
|
m_sections.set(section.name(), move(ptr));
|
|
return true;
|
|
});
|
|
m_image->forEachSectionOfType(SHT_NOBITS, [this, &failed] (const ELFImage::Section& section) {
|
|
#ifdef ELFLOADER_DEBUG
|
|
kprintf("ELFLoader: Allocating nobits section: %s\n", section.name());
|
|
#endif
|
|
if (!section.size())
|
|
return true;
|
|
char* ptr = m_execSpace.allocateArea(section.name(), section.size(), section.offset(), LinearAddress(section.address()));
|
|
if (!ptr) {
|
|
kprintf("ELFLoader: failed to allocate section '%s'\n", section.name());
|
|
failed = true;
|
|
return false;
|
|
}
|
|
memset(ptr, 0, section.size());
|
|
m_sections.set(section.name(), move(ptr));
|
|
return true;
|
|
});
|
|
return !failed;
|
|
}
|
|
|
|
void* ELFLoader::lookup(const ELFImage::Symbol& symbol)
|
|
{
|
|
if (symbol.section().isUndefined())
|
|
return m_execSpace.symbolPtr(symbol.name());
|
|
return areaForSection(symbol.section()) + symbol.value();
|
|
}
|
|
|
|
char* ELFLoader::areaForSection(const ELFImage::Section& section)
|
|
{
|
|
return areaForSectionName(section.name());
|
|
}
|
|
|
|
char* ELFLoader::areaForSectionName(const char* name)
|
|
{
|
|
if (auto it = m_sections.find(name); it != m_sections.end())
|
|
return (*it).value;
|
|
ASSERT_NOT_REACHED();
|
|
return nullptr;
|
|
}
|
|
|
|
bool ELFLoader::performRelocations()
|
|
{
|
|
#ifdef ELFLOADER_DEBUG
|
|
kprintf("ELFLoader: Performing relocations\n");
|
|
#endif
|
|
|
|
bool failed = false;
|
|
|
|
m_image->forEachSectionOfType(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) -> bool {
|
|
auto& relocations = section.relocations();
|
|
if (relocations.isUndefined())
|
|
return true;
|
|
relocations.forEachRelocation([this, section, &failed] (const ELFImage::Relocation& relocation) {
|
|
auto symbol = relocation.symbol();
|
|
auto& patchPtr = *reinterpret_cast<ptrdiff_t*>(areaForSection(section) + relocation.offset());
|
|
|
|
switch (relocation.type()) {
|
|
case R_386_PC32: {
|
|
char* targetPtr = (char*)lookup(symbol);
|
|
if (!targetPtr) {
|
|
kprintf("ELFLoader: unresolved symbol '%s'\n", symbol.name());
|
|
failed = true;
|
|
return false;
|
|
}
|
|
ptrdiff_t relativeOffset = (char*)targetPtr - ((char*)&patchPtr + 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(),
|
|
targetPtr,
|
|
relativeOffset
|
|
);
|
|
#endif
|
|
patchPtr = 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* targetPtr = areaForSection(symbol.section()) + symbol.value();
|
|
patchPtr += (ptrdiff_t)targetPtr;
|
|
break;
|
|
}
|
|
default:
|
|
ASSERT_NOT_REACHED();
|
|
break;
|
|
}
|
|
return true;
|
|
});
|
|
return !failed;
|
|
});
|
|
return !failed;
|
|
}
|
|
|
|
void ELFLoader::exportSymbols()
|
|
{
|
|
m_image->forEachSymbol([&] (const ELFImage::Symbol symbol) {
|
|
#ifdef ELFLOADER_DEBUG
|
|
kprintf("symbol: %u, type=%u, name=%s, section=%u\n", symbol.index(), symbol.type(), symbol.name(), symbol.sectionIndex());
|
|
#endif
|
|
if (symbol.type() == STT_FUNC) {
|
|
char* ptr;
|
|
if (m_image->isExecutable())
|
|
ptr = (char*)symbol.value();
|
|
else if (m_image->isRelocatable())
|
|
ptr = areaForSection(symbol.section()) + symbol.value();
|
|
else
|
|
ASSERT_NOT_REACHED();
|
|
m_execSpace.addSymbol(symbol.name(), ptr, symbol.size());
|
|
}
|
|
// FIXME: What about other symbol types?
|
|
return true;
|
|
});
|
|
}
|
|
|