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
|
0xd0, 0xfb, // bne WaitForCart
|
||||||
0x4c, 0x00, 0x10 // jmp $1000
|
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);
|
createRomAccessArrays(0x1000);
|
||||||
|
|
||||||
#ifdef DUMP_ELF
|
#ifdef DUMP_ELF
|
||||||
cout << "ELF sections:" << std::endl << std::endl;
|
dumpElf(elfParser);
|
||||||
|
#endif
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ namespace {
|
||||||
constexpr uInt8 ELF_CLASS_32 = 1;
|
constexpr uInt8 ELF_CLASS_32 = 1;
|
||||||
constexpr uInt8 ELF_VERSION = 1;
|
constexpr uInt8 ELF_VERSION = 1;
|
||||||
constexpr uInt32 SYMBOL_ENTRY_SIZE = 16;
|
constexpr uInt32 SYMBOL_ENTRY_SIZE = 16;
|
||||||
|
constexpr uInt32 REL_ENTRY_SIZE = 8;
|
||||||
|
constexpr uInt32 RELA_ENTRY_SIZE = 12;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ElfParser::parse(const uInt8 *elfData, size_t size)
|
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);
|
section.name = getName(shrstrtab, section.nameOffset);
|
||||||
|
|
||||||
const Section* symtab = getSymtab();
|
const Section* symtab = getSymtab();
|
||||||
|
|
||||||
if (symtab) {
|
if (symtab) {
|
||||||
const Section* strtab = getStrtab();
|
const Section* strtab = getStrtab();
|
||||||
if (!strtab) EInvalidElf::raise("no string table to resolve symbol names");
|
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++)
|
for (size_t i = 0; i < symtab->size / SYMBOL_ENTRY_SIZE; i++)
|
||||||
symbols.push_back(readSymbol(i, *symtab, *strtab));
|
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) {
|
} catch (const EInvalidElf &e) {
|
||||||
EInvalidElf::raise("failed to parse ELF: " + string(e.what()));
|
EInvalidElf::raise("failed to parse ELF: " + string(e.what()));
|
||||||
}
|
}
|
||||||
|
@ -87,6 +109,11 @@ ElfParser::getSection(const string &name) const {
|
||||||
return optional<Section>();
|
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
|
uInt8 ElfParser::read8(uInt32 offset) const
|
||||||
{
|
{
|
||||||
if (offset >= size)
|
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
|
ElfParser::Symbol ElfParser::readSymbol(uInt32 index, const Section& symSec, const Section& strSec) const
|
||||||
{
|
{
|
||||||
Symbol sym;
|
|
||||||
|
|
||||||
uInt32 offset = index * SYMBOL_ENTRY_SIZE;
|
uInt32 offset = index * SYMBOL_ENTRY_SIZE;
|
||||||
if (offset + SYMBOL_ENTRY_SIZE > symSec.size) EInvalidElf::raise("symbol is beyond section");
|
if (offset + SYMBOL_ENTRY_SIZE > symSec.size) EInvalidElf::raise("symbol is beyond section");
|
||||||
offset += symSec.offset;
|
offset += symSec.offset;
|
||||||
|
|
||||||
|
Symbol sym;
|
||||||
|
|
||||||
sym.nameOffset = read32(offset);
|
sym.nameOffset = read32(offset);
|
||||||
sym.value = read32(offset + 0x04);
|
sym.value = read32(offset + 0x04);
|
||||||
sym.size = read32(offset + 0x08);
|
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.visibility = read8(offset + 0x0d);
|
||||||
sym.section = read16(offset + 0x0e);
|
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.bind = sym.info >> 4;
|
||||||
sym.type = sym.info & 0x0f;
|
sym.type = sym.info & 0x0f;
|
||||||
|
|
||||||
|
sym.name = sym.type == STT_SECTION ? sections[sym.section].name : getName(strSec, sym.nameOffset);
|
||||||
|
|
||||||
return sym;
|
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
|
const char* ElfParser::getName(const Section& section, uInt32 offset) const
|
||||||
{
|
{
|
||||||
if (offset >= section.size) EInvalidElf::raise("name out of bounds");
|
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);
|
reset.copyfmt(os);
|
||||||
|
|
||||||
os
|
os
|
||||||
|
<< symbol.nameOffset << " "
|
||||||
<< symbol.name
|
<< symbol.name
|
||||||
<< std::hex << std::setw(4) << std::setfill('0')
|
<< std::hex << std::setw(4) << std::setfill('0')
|
||||||
<< " value=0x" << symbol.value
|
<< " value=0x" << symbol.value
|
||||||
|
@ -234,3 +292,23 @@ ostream& operator<<(ostream& os, const ElfParser::Symbol symbol)
|
||||||
|
|
||||||
return os;
|
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
|
#ifndef ELF_PARSER
|
||||||
#define ELF_PARSER
|
#define ELF_PARSER
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
class ElfParser {
|
class ElfParser {
|
||||||
|
@ -78,6 +80,16 @@ class ElfParser {
|
||||||
uInt8 type;
|
uInt8 type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Relocation {
|
||||||
|
uInt32 address;
|
||||||
|
uInt32 info;
|
||||||
|
uInt32 addend;
|
||||||
|
|
||||||
|
uInt32 symbol;
|
||||||
|
uInt8 type;
|
||||||
|
string symbolName;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr uInt8 ENDIAN_LITTLE_ENDIAN = 0x01;
|
static constexpr uInt8 ENDIAN_LITTLE_ENDIAN = 0x01;
|
||||||
static constexpr uInt8 ENDIAN_BIG_ENDIAN = 0x02;
|
static constexpr uInt8 ENDIAN_BIG_ENDIAN = 0x02;
|
||||||
|
@ -99,6 +111,8 @@ class ElfParser {
|
||||||
static constexpr uInt32 SHN_ABS = 0xfff1;
|
static constexpr uInt32 SHN_ABS = 0xfff1;
|
||||||
static constexpr uInt32 SHN_UND = 0x00;
|
static constexpr uInt32 SHN_UND = 0x00;
|
||||||
|
|
||||||
|
static constexpr uInt32 STT_SECTION = 0x03;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ElfParser() = default;
|
ElfParser() = default;
|
||||||
|
|
||||||
|
@ -111,6 +125,7 @@ class ElfParser {
|
||||||
const vector<Section>& getSections() const;
|
const vector<Section>& getSections() const;
|
||||||
const vector<Symbol>& getSymbols() const;
|
const vector<Symbol>& getSymbols() const;
|
||||||
const optional<Section> getSection(const std::string &name) const;
|
const optional<Section> getSection(const std::string &name) const;
|
||||||
|
const optional<vector<Relocation>> getRelocations(size_t section) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uInt8 read8(uInt32 offset) const;
|
uInt8 read8(uInt32 offset) const;
|
||||||
|
@ -119,6 +134,7 @@ class ElfParser {
|
||||||
|
|
||||||
Section readSection(uInt32 offset) const;
|
Section readSection(uInt32 offset) const;
|
||||||
Symbol readSymbol(uInt32 index, const Section& symSec, const Section& strSec) 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 char* getName(const Section& section, uInt32 offset) const;
|
||||||
|
|
||||||
const Section* getSymtab() const;
|
const Section* getSymtab() const;
|
||||||
|
@ -133,9 +149,11 @@ class ElfParser {
|
||||||
Header header;
|
Header header;
|
||||||
vector<Section> sections;
|
vector<Section> sections;
|
||||||
vector<Symbol> symbols;
|
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::Section& section);
|
||||||
ostream& operator<<(ostream& os, const ElfParser::Symbol symbol);
|
ostream& operator<<(ostream& os, const ElfParser::Symbol symbol);
|
||||||
|
ostream& operator<<(ostream& os, const ElfParser::Relocation relocation);
|
||||||
|
|
||||||
#endif // ELF_PARSER
|
#endif // ELF_PARSER
|
||||||
|
|
Loading…
Reference in New Issue