ladybird/ELFLoader/ELFLoader.cpp
Andreas Kling 56ed448424 Move ELFLoader debug output behind flags.
The logging spam was out of control.
2018-10-23 11:03:26 +02:00

133 lines
3.8 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;
layout();
exportSymbols();
performRelocations();
return true;
}
void ELFLoader::layout()
{
#ifdef ELFLOADER_DEBUG
kprintf("[ELFLoader] Layout\n");
#endif
m_image->forEachSectionOfType(SHT_PROGBITS, [this] (const ELFImage::Section& section) {
#ifdef ELFLOADER_DEBUG
kprintf("[ELFLoader] Allocating progbits section: %s\n", section.name());
#endif
char* ptr = m_execSpace.allocateArea(section.name(), section.size());
memcpy(ptr, section.rawData(), section.size());
m_sections.set(section.name(), move(ptr));
});
}
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;
}
void ELFLoader::performRelocations()
{
#ifdef ELFLOADER_DEBUG
kprintf("[ELFLoader] Performing relocations\n");
#endif
m_image->forEachSectionOfType(SHT_PROGBITS, [this] (const ELFImage::Section& section) {
auto& relocations = section.relocations();
if (relocations.isUndefined())
return;
relocations.forEachRelocation([this, section] (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);
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;
}
});
});
}
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)
m_execSpace.addSymbol(symbol.name(), areaForSection(symbol.section()) + symbol.value(), symbol.size());
// FIXME: What about other symbol types?
});
}