From 4d722c4622ee871c8019b5bef9db3315dec30c29 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sat, 13 Jul 2024 22:05:02 +0200 Subject: [PATCH] Refactor to prepare for unit tests. --- src/emucore/CartELF.cxx | 10 +-- src/emucore/elf/ElfFile.hxx | 104 ++++++++++++++++++++++++++ src/emucore/elf/ElfLinker.cxx | 76 +++++++++---------- src/emucore/elf/ElfLinker.hxx | 8 +- src/emucore/elf/ElfParser.cxx | 10 --- src/emucore/elf/ElfParser.hxx | 98 ++++-------------------- src/os/windows/Stella.vcxproj | 1 + src/os/windows/Stella.vcxproj.filters | 3 + 8 files changed, 170 insertions(+), 140 deletions(-) create mode 100644 src/emucore/elf/ElfFile.hxx diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index 41064fd53..4370f5ca6 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -33,17 +33,17 @@ namespace { constexpr size_t TRANSACTION_QUEUE_CAPACITY = 16384; #ifdef DUMP_ELF - void dumpElf(const ElfParser& parser) + void dumpElf(const ElfFile& elf) { cout << std::endl << "ELF sections:" << std::endl << std::endl; size_t i = 0; - for (auto& section: parser.getSections()) { + for (auto& section: elf.getSections()) { if (section.type != 0x00) cout << i << " " << section << std::endl; i++; } - auto symbols = parser.getSymbols(); + auto symbols = elf.getSymbols(); cout << std::endl << "ELF symbols:" << std::endl << std::endl; if (symbols.size() > 0) { i = 0; @@ -52,8 +52,8 @@ namespace { } i = 0; - for (auto& section: parser.getSections()) { - auto rels = parser.getRelocations(i++); + for (auto& section: elf.getSections()) { + auto rels = elf.getRelocations(i++); if (!rels) continue; cout diff --git a/src/emucore/elf/ElfFile.hxx b/src/emucore/elf/ElfFile.hxx new file mode 100644 index 000000000..9cb145d15 --- /dev/null +++ b/src/emucore/elf/ElfFile.hxx @@ -0,0 +1,104 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef ELF_FILE +#define ELF_FILE + +#include "bspf.hxx" + +class ElfFile { + public: + struct Section { + uInt32 nameOffset; + string name; + + uInt32 type; + uInt32 flags; + + uInt32 virtualAddress; + uInt32 offset; + uInt32 size; + + uInt32 info; + uInt32 align; + }; + + struct Symbol { + uInt32 nameOffset; + uInt32 value; + uInt32 size; + uInt8 info; + uInt8 visibility; + uInt16 section; + + string name; + uInt8 bind; + uInt8 type; + }; + + struct Relocation { + uInt32 offset; + uInt32 info; + optional addend; + + uInt32 symbol; + uInt8 type; + string symbolName; + }; + + public: + virtual ~ElfFile() = default; + + virtual const uInt8 *getData() const = 0; + virtual size_t getSize() const = 0; + + virtual const vector
& getSections() const = 0; + virtual const vector& getSymbols() const = 0; + virtual const optional> getRelocations(size_t section) const = 0; + + public: + static constexpr uInt8 ENDIAN_LITTLE_ENDIAN = 0x01; + static constexpr uInt8 ENDIAN_BIG_ENDIAN = 0x02; + + static constexpr uInt16 ET_REL = 0x01; + + static constexpr uInt16 ARCH_ARM32 = 0x28; + + static constexpr uInt32 SHT_NULL = 0x00; + static constexpr uInt32 SHT_PROGBITS = 0x01; + static constexpr uInt32 SHT_SYMTAB = 0x02; + static constexpr uInt32 SHT_STRTAB = 0x03; + static constexpr uInt32 SHT_RELA = 0x04; + static constexpr uInt32 SHT_NOBITS = 0x08; + static constexpr uInt32 SHT_REL = 0x09; + static constexpr uInt32 SHT_INIT_ARRAY = 0x0e; + static constexpr uInt32 SHT_PREINIT_ARRAY = 0x10; + + static constexpr uInt32 SHN_ABS = 0xfff1; + static constexpr uInt32 SHN_UND = 0x00; + + static constexpr uInt32 STT_SECTION = 0x03; + + static constexpr uInt32 R_ARM_ABS32 = 0x02; + static constexpr uInt32 R_ARM_THM_CALL = 0x0a; + static constexpr uInt32 R_ARM_THM_JUMP24 = 0x1e; + static constexpr uInt32 R_ARM_TARGET1 = 0x26; + + static constexpr uInt32 STT_FUNC = 0x02; +}; + +#endif // ELF_FILE diff --git a/src/emucore/elf/ElfLinker.cxx b/src/emucore/elf/ElfLinker.cxx index 54f6a9ccb..69c69c85c 100644 --- a/src/emucore/elf/ElfLinker.cxx +++ b/src/emucore/elf/ElfLinker.cxx @@ -24,17 +24,17 @@ namespace { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - std::optional determineSegmentType(const ElfParser::Section& section) + std::optional determineSegmentType(const ElfFile::Section& section) { switch (section.type) { - case ElfParser::SHT_PROGBITS: + case ElfFile::SHT_PROGBITS: if (section.name.starts_with(".text")) return ElfLinker::SegmentType::text; if (section.name.starts_with(".rodata")) return ElfLinker::SegmentType::rodata; return ElfLinker::SegmentType::data; - case ElfParser::SHT_NOBITS: + case ElfFile::SHT_NOBITS: return ElfLinker::SegmentType::data; default: @@ -49,8 +49,8 @@ namespace { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -ElfLinker::ElfLinker(uInt32 textBase, uInt32 dataBase, uInt32 rodataBase, const ElfParser& parser) - : myTextBase(textBase), myDataBase(dataBase), myRodataBase(rodataBase), myParser(parser) +ElfLinker::ElfLinker(uInt32 textBase, uInt32 dataBase, uInt32 rodataBase, const ElfFile& elf) + : myTextBase(textBase), myDataBase(dataBase), myRodataBase(rodataBase), myElf(elf) {} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -148,7 +148,7 @@ const vector& ElfLinker::getPreinitArray() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ElfLinker::RelocatedSymbol ElfLinker::findRelocatedSymbol(string_view name) const { - const auto& symbols = myParser.getSymbols(); + const auto& symbols = myElf.getSymbols(); for (size_t i = 0; i < symbols.size(); i++) { if (symbols[i].name != name) continue; @@ -212,7 +212,7 @@ unique_ptr& ElfLinker::getSegmentDataRef(SegmentType type) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ElfLinker::relocateSections() { - auto& sections = myParser.getSections(); + auto& sections = myElf.getSections(); myRelocatedSections.resize(sections.size(), std::nullopt); // relocate everything that is not .bss @@ -220,7 +220,7 @@ void ElfLinker::relocateSections() const auto& section = sections[i]; const auto segmentType = determineSegmentType(section); - if (!segmentType || section.type == ElfParser::SHT_NOBITS) continue; + if (!segmentType || section.type == ElfFile::SHT_NOBITS) continue; uInt32& segmentSize = getSegmentSizeRef(*segmentType); @@ -235,7 +235,7 @@ void ElfLinker::relocateSections() for (size_t i = 0; i < sections.size(); i++) { const auto& section = sections[i]; - if (section.type == ElfParser::SHT_NOBITS) { + if (section.type == ElfFile::SHT_NOBITS) { if (myDataSize % section.align) myDataSize = (myDataSize / section.align + 1) * section.align; @@ -269,14 +269,14 @@ void ElfLinker::relocateSections() if (!relocatedSection) continue; const auto& section = sections[i]; - if (section.type == ElfParser::SHT_NOBITS) continue; + if (section.type == ElfFile::SHT_NOBITS) continue; const auto segmentType = determineSegmentType(section); if (!segmentType) continue; std::memcpy( getSegmentDataRef(*segmentType).get() + relocatedSection->offset, - myParser.getData() + section.offset, + myElf.getData() + section.offset, section.size ); } @@ -285,7 +285,7 @@ void ElfLinker::relocateSections() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ElfLinker::relocateInitArrays() { - const auto& sections = myParser.getSections(); + const auto& sections = myElf.getSections(); uInt32 initArraySize = 0; uInt32 preinitArraySize = 0; @@ -297,7 +297,7 @@ void ElfLinker::relocateInitArrays() const auto& section = sections[i]; switch (section.type) { - case ElfParser::SHT_INIT_ARRAY: + case ElfFile::SHT_INIT_ARRAY: if (section.size % 4) ElfLinkError::raise("invalid init array"); relocatedInitArrays[i] = initArraySize; @@ -305,7 +305,7 @@ void ElfLinker::relocateInitArrays() break; - case ElfParser::SHT_PREINIT_ARRAY: + case ElfFile::SHT_PREINIT_ARRAY: if (section.size % 4) ElfLinkError::raise("invalid preinit array"); relocatedPreinitArrays[i] = preinitArraySize; @@ -321,8 +321,8 @@ void ElfLinker::relocateInitArrays() copyInitArrays(myInitArray, relocatedInitArrays); copyInitArrays(myPreinitArray, relocatedPreinitArrays); - applyRelocationsToInitArrays(ElfParser::SHT_INIT_ARRAY, myInitArray, relocatedInitArrays); - applyRelocationsToInitArrays(ElfParser::SHT_PREINIT_ARRAY, myPreinitArray, relocatedPreinitArrays); + applyRelocationsToInitArrays(ElfFile::SHT_INIT_ARRAY, myInitArray, relocatedInitArrays); + applyRelocationsToInitArrays(ElfFile::SHT_PREINIT_ARRAY, myPreinitArray, relocatedPreinitArrays); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -334,19 +334,19 @@ void ElfLinker::relocateSymbols(const vector& externalSymbols) externalSymbolLookup[externalSymbol.name] = &externalSymbol; // relocate symbols - const auto& symbols = myParser.getSymbols(); + const auto& symbols = myElf.getSymbols(); myRelocatedSymbols.resize(symbols.size(), std::nullopt); for (size_t i = 0; i < symbols.size(); i++) { const auto& symbol = symbols[i]; - if (symbol.section == ElfParser::SHN_ABS) { + if (symbol.section == ElfFile::SHN_ABS) { myRelocatedSymbols[i] = {std::nullopt, symbol.value, false}; continue; } - if (symbol.section == ElfParser::SHN_UND) { + if (symbol.section == ElfFile::SHN_UND) { if (externalSymbolLookup.contains(symbol.name)) myRelocatedSymbols[i] = {std::nullopt, externalSymbolLookup[symbol.name]->value, false}; @@ -360,7 +360,7 @@ void ElfLinker::relocateSymbols(const vector& externalSymbols) if (!relocatedSection) continue; uInt32 value = getSegmentBase(relocatedSection->segment) + relocatedSection->offset; - if (symbol.type != ElfParser::STT_SECTION) value += symbol.value; + if (symbol.type != ElfFile::STT_SECTION) value += symbol.value; myRelocatedSymbols[i] = {relocatedSection->segment, value, false}; } @@ -369,11 +369,11 @@ void ElfLinker::relocateSymbols(const vector& externalSymbols) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ElfLinker::applyRelocationsToSections() { - auto& sections = myParser.getSections(); + auto& sections = myElf.getSections(); // apply relocations for (size_t iSection = 0; iSection < sections.size(); iSection++) { - const auto& relocations = myParser.getRelocations(iSection); + const auto& relocations = myElf.getRelocations(iSection); if (!relocations) continue; if (!myRelocatedSections[iSection]) continue; @@ -385,8 +385,8 @@ void ElfLinker::applyRelocationsToSections() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ElfLinker::copyInitArrays(vector& initArray, std::unordered_map relocatedInitArrays) { - const uInt8* elfData = myParser.getData(); - const auto& sections = myParser.getSections(); + const uInt8* elfData = myElf.getData(); + const auto& sections = myElf.getSections(); // Copy init arrays for (const auto [iSection, offset]: relocatedInitArrays) { @@ -398,11 +398,11 @@ void ElfLinker::copyInitArrays(vector& initArray, std::unordered_mapvalue + relocation.addend.value_or(read32(target)); - write32(target, value | (symbol.type == ElfParser::STT_FUNC ? 0x01 : 0)); + write32(target, value | (symbol.type == ElfFile::STT_FUNC ? 0x01 : 0)); break; } - case ElfParser::R_ARM_THM_CALL: - case ElfParser::R_ARM_THM_JUMP24: + case ElfFile::R_ARM_THM_CALL: + case ElfFile::R_ARM_THM_JUMP24: { const uInt32 op = read32(target); @@ -444,7 +444,7 @@ void ElfLinker::applyRelocationToSection(const ElfParser::Relocation& relocation if ((offset >> 24) != -1 && (offset >> 24) != 0) 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 == ElfFile::R_ARM_THM_CALL)); } } } @@ -453,18 +453,18 @@ void ElfLinker::applyRelocationToSection(const ElfParser::Relocation& relocation void ElfLinker::applyRelocationsToInitArrays(uInt8 initArrayType, vector& initArray, const std::unordered_map& relocatedInitArrays) { - const auto& symbols = myParser.getSymbols(); - const auto& sections = myParser.getSections(); + const auto& symbols = myElf.getSymbols(); + const auto& sections = myElf.getSections(); for (size_t iSection = 0; iSection < sections.size(); iSection++) { const auto& section = sections[iSection]; if (section.type != initArrayType) continue; - const auto& relocations = myParser.getRelocations(iSection); + const auto& relocations = myElf.getRelocations(iSection); if (!relocations) continue; for (const auto& relocation: *relocations) { - if (relocation.type != ElfParser::R_ARM_ABS32 && relocation.type != ElfParser::R_ARM_TARGET1) + if (relocation.type != ElfFile::R_ARM_ABS32 && relocation.type != ElfFile::R_ARM_TARGET1) ElfLinkError::raise("unsupported relocation for init array"); const auto& relocatedSymbol = myRelocatedSymbols[relocation.symbol]; @@ -481,7 +481,7 @@ void ElfLinker::applyRelocationsToInitArrays(uInt8 initArrayType, vector const uInt32 index = (relocatedInitArrays.at(iSection) + relocation.offset) >> 2; const uInt32 value = relocatedSymbol->value + relocation.addend.value_or(initArray[index]); - initArray[index] = value | (symbols[relocation.symbol].type == ElfParser::STT_FUNC ? 1 : 0); + initArray[index] = value | (symbols[relocation.symbol].type == ElfFile::STT_FUNC ? 1 : 0); } } } diff --git a/src/emucore/elf/ElfLinker.hxx b/src/emucore/elf/ElfLinker.hxx index 91370441b..bf7f53f3a 100644 --- a/src/emucore/elf/ElfLinker.hxx +++ b/src/emucore/elf/ElfLinker.hxx @@ -19,7 +19,7 @@ #define ELF_LINKER #include "bspf.hxx" -#include "ElfParser.hxx" +#include "ElfFile.hxx" class ElfLinker { public: @@ -76,7 +76,7 @@ class ElfLinker { }; public: - ElfLinker(uInt32 textBase, uInt32 dataBase, uInt32 rodataBase, const ElfParser& parser); + ElfLinker(uInt32 textBase, uInt32 dataBase, uInt32 rodataBase, const ElfFile& elf); ElfLinker& setUndefinedSymbolDefault(uInt32 defaultValue); void link(const vector& externalSymbols); @@ -103,7 +103,7 @@ class ElfLinker { void applyRelocationsToSections(); void copyInitArrays(vector& initArray, std::unordered_map relocatedInitArrays); - void applyRelocationToSection(const ElfParser::Relocation& relocation, size_t iSection); + void applyRelocationToSection(const ElfFile::Relocation& relocation, size_t iSection); void applyRelocationsToInitArrays(uInt8 initArrayType, vector& initArray, const std::unordered_map& relocatedInitArrays); @@ -116,7 +116,7 @@ class ElfLinker { const uInt32 myTextBase{0}; const uInt32 myDataBase{0}; const uInt32 myRodataBase{0}; - const ElfParser& myParser; + const ElfFile& myElf; uInt32 myTextSize{0}; uInt32 myDataSize{0}; diff --git a/src/emucore/elf/ElfParser.cxx b/src/emucore/elf/ElfParser.cxx index 644b93ddd..0d46e36e2 100644 --- a/src/emucore/elf/ElfParser.cxx +++ b/src/emucore/elf/ElfParser.cxx @@ -126,16 +126,6 @@ const vector& ElfParser::getSymbols() const return mySymbols; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const optional -ElfParser::getSection(const string &name) const { - for (const Section §ion : mySections) - if (section.name == name) - return section; - - return optional
(); -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const optional> ElfParser::getRelocations(size_t section) const { diff --git a/src/emucore/elf/ElfParser.hxx b/src/emucore/elf/ElfParser.hxx index b6021622b..2e8900f1f 100644 --- a/src/emucore/elf/ElfParser.hxx +++ b/src/emucore/elf/ElfParser.hxx @@ -20,9 +20,10 @@ #include +#include "ElfFile.hxx" #include "bspf.hxx" -class ElfParser { +class ElfParser : public ElfFile { public: class ElfParseError : public std::exception { friend ElfParser; @@ -41,6 +42,19 @@ class ElfParser { const string myReason; }; + public: + ElfParser() = default; + + void parse(const uInt8 *elfData, size_t size); + + const uInt8 *getData() const override; + size_t getSize() const override; + + const vector
& getSections() const override; + const vector& getSymbols() const override; + const optional> getRelocations(size_t section) const override; + + private: struct Header { uInt16 type; uInt16 arch; @@ -52,88 +66,6 @@ class ElfParser { uInt16 shstrIndex; }; - struct Section { - uInt32 nameOffset; - string name; - - uInt32 type; - uInt32 flags; - - uInt32 virtualAddress; - uInt32 offset; - uInt32 size; - - uInt32 info; - uInt32 align; - }; - - struct Symbol { - uInt32 nameOffset; - uInt32 value; - uInt32 size; - uInt8 info; - uInt8 visibility; - uInt16 section; - - string name; - uInt8 bind; - uInt8 type; - }; - - struct Relocation { - uInt32 offset; - uInt32 info; - optional addend; - - uInt32 symbol; - uInt8 type; - string symbolName; - }; - - public: - static constexpr uInt8 ENDIAN_LITTLE_ENDIAN = 0x01; - static constexpr uInt8 ENDIAN_BIG_ENDIAN = 0x02; - - static constexpr uInt16 ET_REL = 0x01; - - static constexpr uInt16 ARCH_ARM32 = 0x28; - - static constexpr uInt32 SHT_NULL = 0x00; - static constexpr uInt32 SHT_PROGBITS = 0x01; - static constexpr uInt32 SHT_SYMTAB = 0x02; - static constexpr uInt32 SHT_STRTAB = 0x03; - static constexpr uInt32 SHT_RELA = 0x04; - static constexpr uInt32 SHT_NOBITS = 0x08; - static constexpr uInt32 SHT_REL = 0x09; - static constexpr uInt32 SHT_INIT_ARRAY = 0x0e; - static constexpr uInt32 SHT_PREINIT_ARRAY = 0x10; - - static constexpr uInt32 SHN_ABS = 0xfff1; - static constexpr uInt32 SHN_UND = 0x00; - - static constexpr uInt32 STT_SECTION = 0x03; - - static constexpr uInt32 R_ARM_ABS32 = 0x02; - static constexpr uInt32 R_ARM_THM_CALL = 0x0a; - static constexpr uInt32 R_ARM_THM_JUMP24 = 0x1e; - static constexpr uInt32 R_ARM_TARGET1 = 0x26; - - static constexpr uInt32 STT_FUNC = 0x02; - - public: - ElfParser() = default; - - void parse(const uInt8 *elfData, size_t size); - - const uInt8 *getData() const; - size_t getSize() const; - - const Header& getHeader() const; - const vector
& getSections() const; - const vector& getSymbols() const; - const optional
getSection(const std::string &name) const; - const optional> getRelocations(size_t section) const; - private: uInt8 read8(uInt32 offset) const; uInt16 read16(uInt32 offset) const; diff --git a/src/os/windows/Stella.vcxproj b/src/os/windows/Stella.vcxproj index 074115320..b26a30983 100755 --- a/src/os/windows/Stella.vcxproj +++ b/src/os/windows/Stella.vcxproj @@ -1665,6 +1665,7 @@ + diff --git a/src/os/windows/Stella.vcxproj.filters b/src/os/windows/Stella.vcxproj.filters index 449fb4834..bfb6759fd 100644 --- a/src/os/windows/Stella.vcxproj.filters +++ b/src/os/windows/Stella.vcxproj.filters @@ -2531,6 +2531,9 @@ Header Files\debugger\gui + + Header Files\emucore\elf + Header Files\emucore\elf