2018-10-10 11:53:07 +02:00
|
|
|
#include "ELFLoader.h"
|
2018-10-18 15:03:10 +02:00
|
|
|
#include <AK/kstdio.h>
|
2018-10-10 11:53:07 +02:00
|
|
|
|
2018-10-23 11:03:26 +02:00
|
|
|
//#define ELFLOADER_DEBUG
|
|
|
|
|
2018-11-04 13:52:53 +01:00
|
|
|
ELFLoader::ELFLoader(ByteBuffer&& buffer)
|
2018-10-10 11:53:07 +02:00
|
|
|
{
|
2018-11-04 13:42:44 +01:00
|
|
|
m_image = make<ELFImage>(move(buffer));
|
2018-10-10 11:53:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ELFLoader::~ELFLoader()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ELFLoader::load()
|
|
|
|
{
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-10-10 11:53:07 +02:00
|
|
|
m_image->dump();
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-10-10 11:53:07 +02:00
|
|
|
if (!m_image->isValid())
|
|
|
|
return false;
|
|
|
|
|
2018-10-25 10:00:37 +02:00
|
|
|
if (!layout())
|
|
|
|
return false;
|
2018-10-10 11:53:07 +02:00
|
|
|
exportSymbols();
|
2018-10-25 10:00:37 +02:00
|
|
|
if (!performRelocations())
|
|
|
|
return false;
|
2018-10-10 11:53:07 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-10-25 10:00:37 +02:00
|
|
|
bool ELFLoader::layout()
|
2018-10-10 11:53:07 +02:00
|
|
|
{
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-10-31 20:10:39 +01:00
|
|
|
kprintf("ELFLoader: Layout\n");
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-11-03 10:11:56 +01:00
|
|
|
|
2018-11-03 11:28:23 +01:00
|
|
|
bool failed = false;
|
2018-11-03 10:11:56 +01:00
|
|
|
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
|
2018-11-04 13:52:53 +01:00
|
|
|
allocate_section(program_header.laddr(), program_header.size_in_memory(), program_header.alignment(), program_header.is_readable(), program_header.is_writable());
|
2018-11-03 10:11:56 +01:00
|
|
|
});
|
|
|
|
|
2018-10-25 10:00:37 +02:00
|
|
|
m_image->forEachSectionOfType(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) {
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-11-03 11:28:23 +01:00
|
|
|
kprintf("ELFLoader: Copying progbits section: %s\n", section.name());
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-10-25 10:00:37 +02:00
|
|
|
if (!section.size())
|
|
|
|
return true;
|
2018-11-03 11:28:23 +01:00
|
|
|
char* ptr = (char*)section.address();
|
2018-10-25 10:00:37 +02:00
|
|
|
if (!ptr) {
|
2018-11-04 13:42:44 +01:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
|
|
|
kprintf("ELFLoader: ignoring section '%s' with null address\n", section.name());
|
|
|
|
#endif
|
|
|
|
return true;
|
2018-10-25 10:00:37 +02:00
|
|
|
}
|
2018-10-10 11:53:07 +02:00
|
|
|
memcpy(ptr, section.rawData(), section.size());
|
2018-10-18 15:03:10 +02:00
|
|
|
m_sections.set(section.name(), move(ptr));
|
2018-10-25 10:00:37 +02:00
|
|
|
return true;
|
2018-10-10 11:53:07 +02:00
|
|
|
});
|
2018-10-25 12:06:00 +02:00
|
|
|
m_image->forEachSectionOfType(SHT_NOBITS, [this, &failed] (const ELFImage::Section& section) {
|
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-11-03 11:28:23 +01:00
|
|
|
kprintf("ELFLoader: Copying nobits section: %s\n", section.name());
|
2018-10-25 12:06:00 +02:00
|
|
|
#endif
|
|
|
|
if (!section.size())
|
|
|
|
return true;
|
2018-11-03 11:28:23 +01:00
|
|
|
char* ptr = (char*)section.address();
|
2018-10-25 12:06:00 +02:00
|
|
|
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;
|
|
|
|
});
|
2018-10-25 10:00:37 +02:00
|
|
|
return !failed;
|
2018-10-10 11:53:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void* ELFLoader::lookup(const ELFImage::Symbol& symbol)
|
|
|
|
{
|
|
|
|
if (symbol.section().isUndefined())
|
2018-11-04 13:52:53 +01:00
|
|
|
return symbol_ptr(symbol.name());
|
2018-10-10 11:53:07 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-10-25 10:00:37 +02:00
|
|
|
bool ELFLoader::performRelocations()
|
2018-10-10 11:53:07 +02:00
|
|
|
{
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-10-31 20:10:39 +01:00
|
|
|
kprintf("ELFLoader: Performing relocations\n");
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-10-10 11:53:07 +02:00
|
|
|
|
2018-10-25 10:00:37 +02:00
|
|
|
bool failed = false;
|
|
|
|
|
|
|
|
m_image->forEachSectionOfType(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) -> bool {
|
2018-10-10 11:53:07 +02:00
|
|
|
auto& relocations = section.relocations();
|
|
|
|
if (relocations.isUndefined())
|
2018-10-25 10:00:37 +02:00
|
|
|
return true;
|
|
|
|
relocations.forEachRelocation([this, section, &failed] (const ELFImage::Relocation& relocation) {
|
2018-10-10 11:53:07 +02:00
|
|
|
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);
|
2018-10-25 10:00:37 +02:00
|
|
|
if (!targetPtr) {
|
|
|
|
kprintf("ELFLoader: unresolved symbol '%s'\n", symbol.name());
|
|
|
|
failed = true;
|
|
|
|
return false;
|
|
|
|
}
|
2018-10-10 11:53:07 +02:00
|
|
|
ptrdiff_t relativeOffset = (char*)targetPtr - ((char*)&patchPtr + 4);
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-10-31 20:10:39 +01:00
|
|
|
kprintf("ELFLoader: Relocate PC32: offset=%x, symbol=%u(%s) value=%x target=%p, offset=%d\n",
|
2018-10-10 11:53:07 +02:00
|
|
|
relocation.offset(),
|
|
|
|
symbol.index(),
|
|
|
|
symbol.name(),
|
|
|
|
symbol.value(),
|
|
|
|
targetPtr,
|
|
|
|
relativeOffset
|
|
|
|
);
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-10-10 11:53:07 +02:00
|
|
|
patchPtr = relativeOffset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case R_386_32: {
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-10-31 20:10:39 +01:00
|
|
|
kprintf("ELFLoader: Relocate Abs32: symbol=%u(%s), value=%x, section=%s\n",
|
2018-10-10 11:53:07 +02:00
|
|
|
symbol.index(),
|
|
|
|
symbol.name(),
|
|
|
|
symbol.value(),
|
|
|
|
symbol.section().name()
|
|
|
|
);
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-10-10 11:53:07 +02:00
|
|
|
char* targetPtr = areaForSection(symbol.section()) + symbol.value();
|
|
|
|
patchPtr += (ptrdiff_t)targetPtr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
ASSERT_NOT_REACHED();
|
|
|
|
break;
|
|
|
|
}
|
2018-10-25 10:00:37 +02:00
|
|
|
return true;
|
2018-10-10 11:53:07 +02:00
|
|
|
});
|
2018-10-25 10:00:37 +02:00
|
|
|
return !failed;
|
2018-10-10 11:53:07 +02:00
|
|
|
});
|
2018-10-25 10:00:37 +02:00
|
|
|
return !failed;
|
2018-10-10 11:53:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ELFLoader::exportSymbols()
|
|
|
|
{
|
|
|
|
m_image->forEachSymbol([&] (const ELFImage::Symbol symbol) {
|
2018-10-23 11:03:26 +02:00
|
|
|
#ifdef ELFLOADER_DEBUG
|
2018-10-18 15:38:04 +02:00
|
|
|
kprintf("symbol: %u, type=%u, name=%s, section=%u\n", symbol.index(), symbol.type(), symbol.name(), symbol.sectionIndex());
|
2018-10-23 11:03:26 +02:00
|
|
|
#endif
|
2018-10-27 14:56:52 +02:00
|
|
|
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();
|
2018-11-04 13:52:53 +01:00
|
|
|
add_symbol(symbol.name(), ptr, symbol.size());
|
2018-10-27 14:56:52 +02:00
|
|
|
}
|
2018-10-10 11:53:07 +02:00
|
|
|
// FIXME: What about other symbol types?
|
2018-10-25 10:00:37 +02:00
|
|
|
return true;
|
2018-10-10 11:53:07 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-04 13:52:53 +01:00
|
|
|
char* ELFLoader::symbol_ptr(const char* name)
|
|
|
|
{
|
|
|
|
if (auto it = m_symbols.find(name); it != m_symbols.end()) {
|
|
|
|
auto& symbol = (*it).value;
|
|
|
|
#ifdef EXECSPACE_DEBUG
|
|
|
|
kprintf("[ELFLoader] symbol_ptr(%s) dump:\n", name);
|
|
|
|
disassemble(symbol.ptr, symbol.size);
|
|
|
|
#endif
|
|
|
|
return symbol.ptr;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-%s%s", is_readable ? "r" : "", is_writable ? "w" : "");
|
|
|
|
return alloc_section_hook(laddr, size, alignment, is_readable, is_writable, namebuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ELFLoader::add_symbol(String&& name, char* ptr, unsigned size)
|
|
|
|
{
|
|
|
|
m_symbols.set(move(name), { ptr, size });
|
|
|
|
}
|