mirror of https://github.com/stella-emu/stella.git
Fixes, load and parse relocations.
This commit is contained in:
parent
5fd00ec763
commit
dce21239b6
|
@ -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
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -82,21 +114,7 @@ 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;
|
||||
}
|
||||
dumpElf(elfParser);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue