123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- #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
- 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
- m_execSpace.allocate_section(program_header.laddr(), program_header.size_in_memory(), program_header.alignment(), program_header.is_readable(), program_header.is_writable());
- });
- m_image->forEachSectionOfType(SHT_PROGBITS, [this, &failed] (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) {
- 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: 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());
- 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;
- });
- }
|