This commit is contained in:
Christian Speckner 2024-07-10 08:28:45 +02:00
parent 135349ed6b
commit 5a7a72c745
4 changed files with 85 additions and 32 deletions

View File

@ -82,16 +82,17 @@ namespace {
}; };
#ifdef DUMP_ELF #ifdef DUMP_ELF
void dumpElf(const ElfParser& elfParser) { void dumpElf(const ElfParser& parser)
{
cout << "ELF sections:" << std::endl << std::endl; cout << "ELF sections:" << std::endl << std::endl;
size_t i = 0; size_t i = 0;
for (auto& section: elfParser.getSections()) { for (auto& section: parser.getSections()) {
if (section.type != 0x00) cout << i << " " << section << std::endl; if (section.type != 0x00) cout << i << " " << section << std::endl;
i++; i++;
} }
auto symbols = elfParser.getSymbols(); auto symbols = parser.getSymbols();
cout << std::endl << "ELF symbols:" << std::endl << std::endl; cout << std::endl << "ELF symbols:" << std::endl << std::endl;
if (symbols.size() > 0) { if (symbols.size() > 0) {
i = 0; i = 0;
@ -100,8 +101,8 @@ namespace {
} }
i = 0; i = 0;
for (auto& section: elfParser.getSections()) { for (auto& section: parser.getSections()) {
auto rels = elfParser.getRelocations(i++); auto rels = parser.getRelocations(i++);
if (!rels) continue; if (!rels) continue;
cout cout
@ -111,6 +112,49 @@ namespace {
for (auto& rel: *rels) cout << rel << std::endl; for (auto& rel: *rels) cout << rel << std::endl;
} }
} }
void dumpLinkage(const ElfParser& parser, const ElfLinker& linker)
{
cout << std::endl << "relocated sections:" << std::endl << std::endl;
cout << std::hex << std::setfill('0');
const auto& sections = parser.getSections();
const auto& relocatedSections = linker.getRelocatedSections();
for (size_t i = 0; i < sections.size(); i++) {
if (!relocatedSections[i]) continue;
cout
<< sections[i].name
<< " @ 0x"<< std::setw(8) << (relocatedSections[i]->offset +
(relocatedSections[i]->type == ElfLinker::SectionType::text ? ADDR_TEXT_BASE : ADDR_DATA_BASE)
)
<< " size 0x" << std::setw(8) << sections[i].size << std::endl;
}
cout << std::endl << "relocated symbols:" << std::endl << std::endl;
const auto& symbols = parser.getSymbols();
const auto& relocatedSymbols = linker.getRelocatedSymbols();
for (size_t i = 0; i < symbols.size(); i++) {
if (!relocatedSymbols[i]) continue;
cout
<< symbols[i].name
<< " = 0x" << std::setw(8) << relocatedSymbols[i]->value;
if (relocatedSymbols[i]->section) {
cout << (*relocatedSymbols[i]->section == ElfLinker::SectionType::text ? " (text)" : " (data)");
} else {
cout << " (abs)";
}
cout << std::endl;
}
cout << std::dec;
}
#endif #endif
} }
@ -153,6 +197,8 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
} }
#ifdef DUMP_ELF #ifdef DUMP_ELF
dumpLinkage(elfParser, elfLinker);
cout cout
<< std::endl << std::endl
<< "ARM entrypoint: 0x" << "ARM entrypoint: 0x"

View File

@ -78,7 +78,7 @@ void ElfLinker::link(const vector<ExternalSymbol>& externalSymbols)
for (size_t i = 0; i < sections.size(); i++) { for (size_t i = 0; i < sections.size(); i++) {
const auto& relocatedSection = myRelocatedSections[i]; const auto& relocatedSection = myRelocatedSections[i];
if (!relocatedSection.has_value()) continue; if (!relocatedSection) continue;
const auto& section = sections[i]; const auto& section = sections[i];
if (section.type != ElfParser::SHT_PROGBITS) continue; if (section.type != ElfParser::SHT_PROGBITS) continue;
@ -192,6 +192,16 @@ ElfLinker::RelocatedSymbol ElfLinker::findRelocatedSymbol(string_view name) cons
ElfSymbolResolutionError::raise("symbol not found"); ElfSymbolResolutionError::raise("symbol not found");
} }
const vector<std::optional<ElfLinker::RelocatedSection>>& ElfLinker::getRelocatedSections() const
{
return myRelocatedSections;
}
const vector<std::optional<ElfLinker::RelocatedSymbol>>& ElfLinker::getRelocatedSymbols() const
{
return myRelocatedSymbols;
}
void ElfLinker::applyRelocation(const ElfParser::Relocation& relocation, size_t iSection) void ElfLinker::applyRelocation(const ElfParser::Relocation& relocation, size_t iSection)
{ {
const auto& targetSection = myParser.getSections()[iSection]; const auto& targetSection = myParser.getSections()[iSection];
@ -204,6 +214,11 @@ void ElfLinker::applyRelocation(const ElfParser::Relocation& relocation, size_t
"unable to relocate " + symbol.name + " in " + targetSection.name + ": symbol could not be relocated" "unable to relocate " + symbol.name + " in " + targetSection.name + ": symbol could not be relocated"
); );
if (relocation.offset + 4 > targetSection.size)
ElfLinkError::raise(
"unable to relocate " + symbol.name + " in " + targetSection.name + ": target out of range"
);
uInt8* target = uInt8* target =
(targetSectionRelocated.type == SectionType::text ? myTextData : myDataData).get() + (targetSectionRelocated.type == SectionType::text ? myTextData : myDataData).get() +
targetSectionRelocated.offset + relocation.offset; targetSectionRelocated.offset + relocation.offset;
@ -212,11 +227,6 @@ void ElfLinker::applyRelocation(const ElfParser::Relocation& relocation, size_t
case ElfParser::R_ARM_ABS32: case ElfParser::R_ARM_ABS32:
case ElfParser::R_ARM_TARGET1: case ElfParser::R_ARM_TARGET1:
{ {
if (relocation.offset + 4 > targetSection.size)
ElfLinkError::raise(
"unable to relocate " + symbol.name + " in " + targetSection.name + ": target out of range"
);
const uInt32 value = relocatedSymbol->value + relocation.addend.value_or(read32(target)); const uInt32 value = relocatedSymbol->value + relocation.addend.value_or(read32(target));
write32(target, value | (symbol.type == ElfParser::STT_FUNC ? 0x01 : 0)); write32(target, value | (symbol.type == ElfParser::STT_FUNC ? 0x01 : 0));
@ -226,18 +236,13 @@ void ElfLinker::applyRelocation(const ElfParser::Relocation& relocation, size_t
case ElfParser::R_ARM_THM_CALL: case ElfParser::R_ARM_THM_CALL:
case ElfParser::R_ARM_THM_JUMP24: case ElfParser::R_ARM_THM_JUMP24:
{ {
if (relocation.offset + 4 > targetSection.size)
ElfLinkError::raise(
"unable to relocate " + symbol.name + " in " + targetSection.name + ": target out of range"
);
const uInt32 op = read32(target); const uInt32 op = read32(target);
Int32 offset = relocatedSymbol->value + relocation.addend.value_or(elfUtil::decode_B_BL(op)) - Int32 offset = relocatedSymbol->value + relocation.addend.value_or(elfUtil::decode_B_BL(op)) -
(targetSectionRelocated.type == SectionType::text ? myTextBase : myDataBase) - (targetSectionRelocated.type == SectionType::text ? myTextBase : myDataBase) -
targetSectionRelocated.offset - relocation.offset - 4; targetSectionRelocated.offset - relocation.offset - 4;
if ((offset >> 25) != -1 && (offset >> 25) != 0) if ((offset >> 24) != -1 && (offset >> 24) != 0)
ElfLinkError::raise("unable to relocate jump: offset out of bounds"); ElfLinkError::raise("unable to relocate jump: offset out of bounds");
write32(target, elfUtil::encode_B_BL(offset, relocation.type == ElfParser::R_ARM_THM_CALL)); write32(target, elfUtil::encode_B_BL(offset, relocation.type == ElfParser::R_ARM_THM_CALL));

View File

@ -59,6 +59,11 @@ class ElfLinker {
enum class SectionType: uInt8 { text, data }; enum class SectionType: uInt8 { text, data };
struct RelocatedSection {
SectionType type;
uInt32 offset;
};
struct RelocatedSymbol { struct RelocatedSymbol {
optional<SectionType> section; optional<SectionType> section;
uInt32 value; uInt32 value;
@ -87,11 +92,8 @@ class ElfLinker {
RelocatedSymbol findRelocatedSymbol(string_view name) const; RelocatedSymbol findRelocatedSymbol(string_view name) const;
private: const vector<std::optional<RelocatedSection>>& getRelocatedSections() const;
struct RelocatedSection { const vector<std::optional<RelocatedSymbol>>& getRelocatedSymbols() const;
SectionType type;
uInt32 offset;
};
private: private:
void applyRelocation(const ElfParser::Relocation& relocation, size_t iSection); void applyRelocation(const ElfParser::Relocation& relocation, size_t iSection);

View File

@ -329,12 +329,12 @@ ostream& operator<<(ostream& os, const ElfParser::Symbol symbol)
os os
<< symbol.nameOffset << " " << symbol.nameOffset << " "
<< symbol.name << symbol.name
<< std::hex << std::setw(4) << std::setfill('0') << std::hex << std::setfill('0')
<< " value=0x" << symbol.value << " value=0x" << std::setw(8) << symbol.value
<< " size=0x" << symbol.size << " size=0x" << std::setw(8) << symbol.size
<< std::setw(1) << std::setw(1)
<< " bind=0x" << (int)symbol.bind << " bind=0x" << std::setw(2) << (int)symbol.bind
<< " type=0x" << (int)symbol.type; << " type=0x" << std::setw(2) << (int)symbol.type;
os.copyfmt(reset); os.copyfmt(reset);
@ -351,13 +351,13 @@ ostream& operator<<(ostream& os, const ElfParser::Relocation rel)
os os
<< rel.symbolName << " :" << rel.symbolName << " :"
<< std::hex << std::setw(4) << std::setfill('0') << std::hex << std::setfill('0')
<< " offset=0x" << rel.offset << " offset=0x" << std::setw(8) << rel.offset
<< " info=0x" << rel.info << " info=0x" << std::setw(8) << rel.info
<< " type=0x" << (int)rel.type; << " type=0x" << std::setw(2) << (int)rel.type;
if (rel.addend.has_value()) if (rel.addend.has_value())
os << " addend=0x" << *rel.addend; os << " addend=0x" << std::setw(8) << *rel.addend;
os.copyfmt(reset); os.copyfmt(reset);