Fixes, load and parse relocations.

This commit is contained in:
Christian Speckner 2024-07-05 23:57:12 +02:00
parent 5fd00ec763
commit dce21239b6
3 changed files with 134 additions and 20 deletions

View File

@ -60,6 +60,38 @@ namespace {
0xd0, 0xfb, // bne WaitForCart
0x4c, 0x00, 0x10 // jmp $1000
};
#ifdef DUMP_ELF
void dumpElf(const ElfParser& elfParser) {
cout << "ELF sections:" << std::endl << std::endl;
size_t i = 0;
for (auto& section: elfParser.getSections()) {
if (section.type != 0x00) cout << i << " " << section << std::endl;
i++;
}
auto symbols = elfParser.getSymbols();
cout << std::endl << "ELF symbols:" << std::endl << std::endl;
if (symbols.size() > 0) {
i = 0;
for (auto& symbol: symbols)
cout << (i++) << " " << symbol << std::endl;
}
i = 0;
for (auto& section: elfParser.getSections()) {
auto rels = elfParser.getRelocations(i++);
if (!rels) continue;
cout
<< std::endl << "ELF relocations for section "
<< section.name << ":" << std::endl << std::endl;
for (auto& rel: *rels) cout << rel << std::endl;
}
}
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -81,23 +113,9 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
createRomAccessArrays(0x1000);
#ifdef DUMP_ELF
cout << "ELF sections:" << std::endl << std::endl;
size_t i = 0;
for (auto& section: elfParser.getSections()) {
if (section.type != 0x00) cout << i << " " << section << std::endl;
i++;
}
auto symbols = elfParser.getSymbols();
cout << std::endl << "ELF symbols:" << std::endl << std::endl;
if (symbols.size() > 0) {
i = 0;
for (auto& symbol: symbols)
cout << (i++) << " " << symbol << std::endl;
}
#endif
#ifdef DUMP_ELF
dumpElf(elfParser);
#endif
}

View File

@ -7,6 +7,8 @@ namespace {
constexpr uInt8 ELF_CLASS_32 = 1;
constexpr uInt8 ELF_VERSION = 1;
constexpr uInt32 SYMBOL_ENTRY_SIZE = 16;
constexpr uInt32 REL_ENTRY_SIZE = 8;
constexpr uInt32 RELA_ENTRY_SIZE = 12;
} // namespace
void ElfParser::parse(const uInt8 *elfData, size_t size)
@ -50,6 +52,7 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
section.name = getName(shrstrtab, section.nameOffset);
const Section* symtab = getSymtab();
if (symtab) {
const Section* strtab = getStrtab();
if (!strtab) EInvalidElf::raise("no string table to resolve symbol names");
@ -59,6 +62,25 @@ void ElfParser::parse(const uInt8 *elfData, size_t size)
for (size_t i = 0; i < symtab->size / SYMBOL_ENTRY_SIZE; i++)
symbols.push_back(readSymbol(i, *symtab, *strtab));
}
for (auto& section: sections) {
if (section.type != SHT_REL && section.type != SHT_RELA) continue;
if (section.info >= sections.size()) EInvalidElf::raise("relocation table for invalid section");
vector<Relocation> rels;
rels.reserve(section.size / (section.type == SHT_REL ? REL_ENTRY_SIZE : RELA_ENTRY_SIZE));
for (size_t i = 0; i < rels.capacity(); i++) {
Relocation rel = readRelocation(i, section);
if (rel.symbol >= symbols.size()) EInvalidElf::raise("invalid relocation symbol");
rel.symbolName = symbols[rel.symbol].name;
rels.push_back(rel);
}
relocations[section.info] = rels;
}
} catch (const EInvalidElf &e) {
EInvalidElf::raise("failed to parse ELF: " + string(e.what()));
}
@ -87,6 +109,11 @@ ElfParser::getSection(const string &name) const {
return optional<Section>();
}
const optional<vector<ElfParser::Relocation>> ElfParser::getRelocations(size_t section) const
{
return relocations.contains(section) ? relocations.at(section) : optional<vector<ElfParser::Relocation>>();
}
uInt8 ElfParser::read8(uInt32 offset) const
{
if (offset >= size)
@ -133,12 +160,12 @@ ElfParser::Section ElfParser::readSection(uInt32 offset) const {
ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const
{
Symbol sym;
uInt32 offset = index * SYMBOL_ENTRY_SIZE;
if (offset + SYMBOL_ENTRY_SIZE > symSec.size) EInvalidElf::raise("symbol is beyond section");
offset += symSec.offset;
Symbol sym;
sym.nameOffset = read32(offset);
sym.value = read32(offset + 0x04);
sym.size = read32(offset + 0x08);
@ -146,13 +173,43 @@ ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, con
sym.visibility = read8(offset + 0x0d);
sym.section = read16(offset + 0x0e);
sym.name = getName(strSec, sym.nameOffset);
if (
((sym.section != SHN_ABS && sym.section != SHN_UND) || sym.type == STT_SECTION) &&
sym.section >= sections.size()
)
EInvalidElf::raise("symbol: section index out of range");
sym.bind = sym.info >> 4;
sym.type = sym.info & 0x0f;
sym.name = sym.type == STT_SECTION ? sections[sym.section].name : getName(strSec, sym.nameOffset);
return sym;
}
ElfParser::Relocation ElfParser::readRelocation(uInt32 index, const Section& sec) const
{
if (sec.type != SHT_REL && sec.type != SHT_RELA)
throw runtime_error("section is not RELA or REL");
const size_t size = sec.type == SHT_REL ? REL_ENTRY_SIZE : RELA_ENTRY_SIZE;
uInt32 offset = index * size;
if (offset + size > sec.size) EInvalidElf::raise("relocation is beyond bounds");
offset += sec.offset;
Relocation rel;
rel.address = read32(offset);
rel.info = read32(offset + 0x04);
rel.addend = sec.type == SHT_RELA ? read32(offset + 0x08) : 0;
rel.symbol = rel.info >> 8;
rel.type = rel.info & 0x0f;
return rel;
}
const char* ElfParser::getName(const Section& section, uInt32 offset) const
{
if (offset >= section.size) EInvalidElf::raise("name out of bounds");
@ -220,6 +277,7 @@ ostream& operator<<(ostream& os, const ElfParser::Symbol symbol)
reset.copyfmt(os);
os
<< symbol.nameOffset << " "
<< symbol.name
<< std::hex << std::setw(4) << std::setfill('0')
<< " value=0x" << symbol.value
@ -234,3 +292,23 @@ ostream& operator<<(ostream& os, const ElfParser::Symbol symbol)
return os;
}
ostream& operator<<(ostream& os, const ElfParser::Relocation rel)
{
std::ios reset(nullptr);
reset.copyfmt(os);
os
<< rel.symbolName << " :"
<< std::hex << std::setw(4) << std::setfill('0')
<< " address=0x" << rel.address
<< " info=0x" << rel.info
<< " addend=0x" << rel.addend
<< " type=0x" << (int)rel.type;
os.copyfmt(reset);
os << " symbol=" << (int)rel.symbol;
return os;
}

View File

@ -18,6 +18,8 @@
#ifndef ELF_PARSER
#define ELF_PARSER
#include <unordered_map>
#include "bspf.hxx"
class ElfParser {
@ -78,6 +80,16 @@ class ElfParser {
uInt8 type;
};
struct Relocation {
uInt32 address;
uInt32 info;
uInt32 addend;
uInt32 symbol;
uInt8 type;
string symbolName;
};
public:
static constexpr uInt8 ENDIAN_LITTLE_ENDIAN = 0x01;
static constexpr uInt8 ENDIAN_BIG_ENDIAN = 0x02;
@ -99,6 +111,8 @@ class ElfParser {
static constexpr uInt32 SHN_ABS = 0xfff1;
static constexpr uInt32 SHN_UND = 0x00;
static constexpr uInt32 STT_SECTION = 0x03;
public:
ElfParser() = default;
@ -111,6 +125,7 @@ class ElfParser {
const vector<Section>& getSections() const;
const vector<Symbol>& getSymbols() const;
const optional<Section> getSection(const std::string &name) const;
const optional<vector<Relocation>> getRelocations(size_t section) const;
private:
uInt8 read8(uInt32 offset) const;
@ -119,6 +134,7 @@ class ElfParser {
Section readSection(uInt32 offset) const;
Symbol readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const;
Relocation readRelocation(uInt32 index, const Section& sec) const;
const char* getName(const Section& section, uInt32 offset) const;
const Section* getSymtab() const;
@ -133,9 +149,11 @@ class ElfParser {
Header header;
vector<Section> sections;
vector<Symbol> symbols;
std::unordered_map<size_t, vector<Relocation>> relocations;
};
ostream& operator<<(ostream& os, const ElfParser::Section& section);
ostream& operator<<(ostream& os, const ElfParser::Symbol symbol);
ostream& operator<<(ostream& os, const ElfParser::Relocation relocation);
#endif // ELF_PARSER