mirror of https://github.com/stella-emu/stella.git
Introduce a separate segment for rodata.
This commit is contained in:
parent
e8cbfabb79
commit
21c80981cd
|
@ -70,9 +70,11 @@ namespace {
|
|||
|
||||
cout
|
||||
<< std::endl
|
||||
<< "text segment size: 0x" << std::setw(8) << linker.getTextSize()
|
||||
<< "text segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::text)
|
||||
<< std::endl
|
||||
<< "data segment size: 0x" << std::setw(8) << linker.getDataSize()
|
||||
<< "data segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::data)
|
||||
<< std::endl
|
||||
<< "rodata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::rodata)
|
||||
<< std::endl;
|
||||
|
||||
cout << std::endl << "relocated sections:" << std::endl << std::endl;
|
||||
|
@ -85,9 +87,8 @@ namespace {
|
|||
|
||||
cout
|
||||
<< sections[i].name
|
||||
<< " @ 0x"<< std::setw(8) << (relocatedSections[i]->offset +
|
||||
(relocatedSections[i]->segment == ElfLinker::SegmentType::text ? ADDR_TEXT_BASE : ADDR_DATA_BASE)
|
||||
)
|
||||
<< " @ 0x"<< std::setw(8)
|
||||
<< (relocatedSections[i]->offset + linker.getSegmentBase(relocatedSections[i]->segment))
|
||||
<< " size 0x" << std::setw(8) << sections[i].size << std::endl;
|
||||
}
|
||||
|
||||
|
@ -104,7 +105,19 @@ namespace {
|
|||
<< " = 0x" << std::setw(8) << relocatedSymbols[i]->value;
|
||||
|
||||
if (relocatedSymbols[i]->segment) {
|
||||
cout << (*relocatedSymbols[i]->segment == ElfLinker::SegmentType::text ? " (text)" : " (data)");
|
||||
switch (*relocatedSymbols[i]->segment) {
|
||||
case ElfLinker::SegmentType::text:
|
||||
cout << " (text)";
|
||||
break;
|
||||
|
||||
case ElfLinker::SegmentType::data:
|
||||
cout << " (data)";
|
||||
break;
|
||||
|
||||
case ElfLinker::SegmentType::rodata:
|
||||
cout << " (rodata)";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cout << " (abs)";
|
||||
}
|
||||
|
@ -159,7 +172,7 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
|
|||
dumpElf(elfParser);
|
||||
#endif
|
||||
|
||||
ElfLinker elfLinker(ADDR_TEXT_BASE, ADDR_DATA_BASE, elfParser);
|
||||
ElfLinker elfLinker(ADDR_TEXT_BASE, ADDR_DATA_BASE, ADDR_RODATA_BASE, elfParser);
|
||||
try {
|
||||
elfLinker.link(externalSymbols(Palette::ntsc));
|
||||
} catch (const ElfLinker::ElfLinkError& e) {
|
||||
|
@ -299,6 +312,7 @@ void CartridgeELF::vcsCopyOverblankToRiotRam()
|
|||
vcsWrite5(0x80 + i, OVERBLANK_PROGRAM[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeELF::vcsStartOverblank()
|
||||
{
|
||||
myTransactionQueue.injectROM(0x4c);
|
||||
|
@ -307,12 +321,14 @@ void CartridgeELF::vcsStartOverblank()
|
|||
myTransactionQueue.yield(0x0080);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeELF::BusTransaction CartridgeELF::BusTransaction::transactionYield(uInt16 address)
|
||||
{
|
||||
address &= 0x1fff;
|
||||
return {.address = address, .value = 0, .yield = true};
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeELF::BusTransaction CartridgeELF::BusTransaction::transactionDrive(uInt16 address, uInt8 value)
|
||||
{
|
||||
address &= 0x1fff;
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
namespace elfEnvironment {
|
||||
constexpr uInt32 ADDR_TEXT_BASE = 0x00100000;
|
||||
constexpr uInt32 ADDR_DATA_BASE = 0x00200000;
|
||||
constexpr uInt32 ADDR_TABLES_BASE = 0x00300000;
|
||||
constexpr uInt32 ADDR_RODATA_BASE = 0x00300000;
|
||||
constexpr uInt32 ADDR_TABLES_BASE = 0x00400000;
|
||||
|
||||
constexpr uInt32 ADDR_ADDR_IDR = 0xf0000000;
|
||||
constexpr uInt32 ADDR_DATA_IDR = 0xf0000004;
|
||||
|
|
|
@ -22,9 +22,35 @@
|
|||
|
||||
#include "ElfLinker.hxx"
|
||||
|
||||
namespace {
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
std::optional<ElfLinker::SegmentType> determineSegmentType(const ElfParser::Section& section)
|
||||
{
|
||||
switch (section.type) {
|
||||
case ElfParser::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:
|
||||
return ElfLinker::SegmentType::data;
|
||||
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool checkSegmentOverlap(uInt32 segmentBase1, uInt32 segmentSize1, uInt32 segmentBase2, uInt32 segmentSize2) {
|
||||
return !(segmentBase1 + segmentSize1 <= segmentBase2 || segmentBase2 + segmentSize2 <= segmentBase1);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ElfLinker::ElfLinker(uInt32 textBase, uInt32 dataBase, const ElfParser& parser)
|
||||
: myTextBase(textBase), myDataBase(dataBase), myParser(parser)
|
||||
ElfLinker::ElfLinker(uInt32 textBase, uInt32 dataBase, uInt32 rodataBase, const ElfParser& parser)
|
||||
: myTextBase(textBase), myDataBase(dataBase), myRodataBase(rodataBase), myParser(parser)
|
||||
{}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -38,9 +64,10 @@ ElfLinker& ElfLinker::setUndefinedSymbolDefault(uInt32 defaultValue)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ElfLinker::link(const vector<ExternalSymbol>& externalSymbols)
|
||||
{
|
||||
myTextSize = myDataSize = 0;
|
||||
myTextSize = myDataSize = myRodataSize = 0;
|
||||
myTextData.reset();
|
||||
myDataData.reset();
|
||||
myRodataData.reset();
|
||||
myRelocatedSections.resize(0);
|
||||
myRelocatedSymbols.resize(0);
|
||||
myInitArray.resize(0);
|
||||
|
@ -53,39 +80,57 @@ void ElfLinker::link(const vector<ExternalSymbol>& externalSymbols)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 ElfLinker::getTextBase() const
|
||||
uInt32 ElfLinker::getSegmentSize(SegmentType type) const
|
||||
{
|
||||
return myTextBase;
|
||||
switch (type) {
|
||||
case SegmentType::text:
|
||||
return myTextSize;
|
||||
|
||||
case SegmentType::data:
|
||||
return myDataSize;
|
||||
|
||||
case SegmentType::rodata:
|
||||
return myRodataSize;
|
||||
|
||||
default:
|
||||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 ElfLinker::getTextSize() const
|
||||
const uInt8* ElfLinker::getSegmentData(SegmentType type) const
|
||||
{
|
||||
return myTextSize;
|
||||
switch (type) {
|
||||
case SegmentType::text:
|
||||
return myTextData.get();
|
||||
|
||||
case SegmentType::data:
|
||||
return myDataData.get();
|
||||
|
||||
case SegmentType::rodata:
|
||||
return myRodataData.get();
|
||||
|
||||
default:
|
||||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* ElfLinker::getTextData() const
|
||||
uInt32 ElfLinker::getSegmentBase(SegmentType type) const
|
||||
{
|
||||
return myTextData ? myTextData.get() : nullptr;
|
||||
}
|
||||
switch (type) {
|
||||
case SegmentType::text:
|
||||
return myTextBase;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 ElfLinker::getDataBase() const
|
||||
{
|
||||
return myDataBase;
|
||||
}
|
||||
case SegmentType::data:
|
||||
return myDataBase;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 ElfLinker::getDataSize() const
|
||||
{
|
||||
return myDataSize;
|
||||
}
|
||||
case SegmentType::rodata:
|
||||
return myRodataBase;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* ElfLinker::getDataData() const
|
||||
{
|
||||
return myDataData ? myDataData.get() : nullptr;
|
||||
default:
|
||||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -128,26 +173,62 @@ const vector<std::optional<ElfLinker::RelocatedSymbol>>& ElfLinker::getRelocated
|
|||
return myRelocatedSymbols;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32& ElfLinker::getSegmentSizeRef(SegmentType type)
|
||||
{
|
||||
switch (type) {
|
||||
case SegmentType::text:
|
||||
return myTextSize;
|
||||
|
||||
case SegmentType::data:
|
||||
return myDataSize;
|
||||
|
||||
case SegmentType::rodata:
|
||||
return myRodataSize;
|
||||
|
||||
default:
|
||||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
unique_ptr<uInt8[]>& ElfLinker::getSegmentDataRef(SegmentType type)
|
||||
{
|
||||
switch (type) {
|
||||
case SegmentType::text:
|
||||
return myTextData;
|
||||
|
||||
case SegmentType::data:
|
||||
return myDataData;
|
||||
|
||||
case SegmentType::rodata:
|
||||
return myRodataData;
|
||||
|
||||
default:
|
||||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ElfLinker::relocateSections()
|
||||
{
|
||||
auto& sections = myParser.getSections();
|
||||
myRelocatedSections.resize(sections.size(), std::nullopt);
|
||||
|
||||
// relocate all .text and .data sections
|
||||
// relocate everything that is not .bss
|
||||
for (size_t i = 0; i < sections.size(); i++) {
|
||||
const auto& section = sections[i];
|
||||
|
||||
if (section.type == ElfParser::SHT_PROGBITS) {
|
||||
const bool isText = section.name.starts_with(".text");
|
||||
uInt32& segmentSize = isText ? myTextSize : myDataSize;
|
||||
const auto segmentType = determineSegmentType(section);
|
||||
if (!segmentType || section.type == ElfParser::SHT_NOBITS) continue;
|
||||
|
||||
if (segmentSize % section.align)
|
||||
segmentSize = (segmentSize / section.align + 1) * section.align;
|
||||
uInt32& segmentSize = getSegmentSizeRef(*segmentType);
|
||||
|
||||
myRelocatedSections[i] = {isText ? SegmentType::text : SegmentType::data, segmentSize};
|
||||
segmentSize += section.size;
|
||||
}
|
||||
if (segmentSize % section.align)
|
||||
segmentSize = (segmentSize / section.align + 1) * section.align;
|
||||
|
||||
myRelocatedSections[i] = {*segmentType, segmentSize};
|
||||
segmentSize += section.size;
|
||||
}
|
||||
|
||||
// relocate all .bss sections
|
||||
|
@ -164,27 +245,37 @@ void ElfLinker::relocateSections()
|
|||
}
|
||||
|
||||
// ensure that the segments don't overlap
|
||||
if (!(myTextBase + myTextSize <= myDataBase || myDataBase + myDataSize <= myTextBase))
|
||||
if (
|
||||
checkSegmentOverlap(myTextBase, myTextSize, myDataBase, myDataSize) ||
|
||||
checkSegmentOverlap(myTextBase, myTextSize, myRodataBase, myRodataSize) ||
|
||||
checkSegmentOverlap(myDataBase, myDataSize, myRodataBase, myRodataSize)
|
||||
)
|
||||
ElfLinkError::raise("segments overlap");
|
||||
|
||||
// allocate and copy section data
|
||||
myTextData = make_unique<uInt8[]>(myTextSize);
|
||||
myDataData = make_unique<uInt8[]>(myDataSize);
|
||||
// allocate segment data
|
||||
for (SegmentType segmentType: {SegmentType::text, SegmentType::data, SegmentType::rodata}) {
|
||||
const uInt32 segmentSize = getSegmentSize(segmentType);
|
||||
if (segmentSize == 0) continue;
|
||||
|
||||
std::memset(myTextData.get(), 0, myTextSize);
|
||||
std::memset(myDataData.get(), 0, myDataSize);
|
||||
auto& segmentData = getSegmentDataRef(segmentType);
|
||||
|
||||
segmentData = make_unique<uInt8[]>(segmentSize);
|
||||
std::memset(segmentData.get(), 0, segmentSize);
|
||||
}
|
||||
|
||||
// copy segment data
|
||||
for (size_t i = 0; i < sections.size(); i++) {
|
||||
const auto& relocatedSection = myRelocatedSections[i];
|
||||
if (!relocatedSection) continue;
|
||||
|
||||
const auto& section = sections[i];
|
||||
if (section.type != ElfParser::SHT_PROGBITS) continue;
|
||||
if (section.type == ElfParser::SHT_NOBITS) continue;
|
||||
|
||||
const bool isText = section.name.starts_with(".text");
|
||||
const auto segmentType = determineSegmentType(section);
|
||||
if (!segmentType) continue;
|
||||
|
||||
std::memcpy(
|
||||
(isText ? myTextData : myDataData).get() + relocatedSection->offset,
|
||||
getSegmentDataRef(*segmentType).get() + relocatedSection->offset,
|
||||
myParser.getData() + section.offset,
|
||||
section.size
|
||||
);
|
||||
|
@ -268,8 +359,7 @@ void ElfLinker::relocateSymbols(const vector<ExternalSymbol>& externalSymbols)
|
|||
const auto& relocatedSection = myRelocatedSections[symbol.section];
|
||||
if (!relocatedSection) continue;
|
||||
|
||||
uInt32 value = relocatedSection->segment == SegmentType::text ? myTextBase : myDataBase;
|
||||
value += relocatedSection->offset;
|
||||
uInt32 value = getSegmentBase(relocatedSection->segment) + relocatedSection->offset;
|
||||
if (symbol.type != ElfParser::STT_SECTION) value += symbol.value;
|
||||
|
||||
myRelocatedSymbols[i] = {relocatedSection->segment, value, false};
|
||||
|
@ -327,8 +417,9 @@ void ElfLinker::applyRelocationToSection(const ElfParser::Relocation& relocation
|
|||
);
|
||||
|
||||
uInt8* target =
|
||||
(targetSectionRelocated.segment == SegmentType::text ? myTextData : myDataData).get() +
|
||||
targetSectionRelocated.offset + relocation.offset;
|
||||
getSegmentDataRef(targetSectionRelocated.segment).get() +
|
||||
targetSectionRelocated.offset +
|
||||
relocation.offset;
|
||||
|
||||
switch (relocation.type) {
|
||||
case ElfParser::R_ARM_ABS32:
|
||||
|
@ -346,8 +437,9 @@ void ElfLinker::applyRelocationToSection(const ElfParser::Relocation& relocation
|
|||
const uInt32 op = read32(target);
|
||||
|
||||
Int32 offset = relocatedSymbol->value + relocation.addend.value_or(elfUtil::decode_B_BL(op)) -
|
||||
(targetSectionRelocated.segment == SegmentType::text ? myTextBase : myDataBase) -
|
||||
targetSectionRelocated.offset - relocation.offset - 4;
|
||||
getSegmentBase(targetSectionRelocated.segment) -
|
||||
targetSectionRelocated.offset -
|
||||
relocation.offset - 4;
|
||||
|
||||
if ((offset >> 24) != -1 && (offset >> 24) != 0)
|
||||
ElfLinkError::raise("unable to relocate jump: offset out of bounds");
|
||||
|
|
|
@ -57,7 +57,7 @@ class ElfLinker {
|
|||
const string myReason;
|
||||
};
|
||||
|
||||
enum class SegmentType: uInt8 { text, data };
|
||||
enum class SegmentType: uInt8 { text, data, rodata };
|
||||
|
||||
struct RelocatedSection {
|
||||
SegmentType segment;
|
||||
|
@ -76,18 +76,14 @@ class ElfLinker {
|
|||
};
|
||||
|
||||
public:
|
||||
ElfLinker(uInt32 textBase, uInt32 dataBase, const ElfParser& parser);
|
||||
ElfLinker(uInt32 textBase, uInt32 dataBase, uInt32 rodataBase, const ElfParser& parser);
|
||||
|
||||
ElfLinker& setUndefinedSymbolDefault(uInt32 defaultValue);
|
||||
void link(const vector<ExternalSymbol>& externalSymbols);
|
||||
|
||||
uInt32 getTextBase() const;
|
||||
uInt32 getTextSize() const;
|
||||
const uInt8* getTextData() const;
|
||||
|
||||
uInt32 getDataBase() const;
|
||||
uInt32 getDataSize() const;
|
||||
const uInt8* getDataData() const;
|
||||
uInt32 getSegmentSize(SegmentType type) const;
|
||||
const uInt8* getSegmentData(SegmentType type) const;
|
||||
uInt32 getSegmentBase(SegmentType type) const;
|
||||
|
||||
const vector<uInt32>& getInitArray() const;
|
||||
const vector<uInt32>& getPreinitArray() const;
|
||||
|
@ -98,6 +94,9 @@ class ElfLinker {
|
|||
const vector<std::optional<RelocatedSymbol>>& getRelocatedSymbols() const;
|
||||
|
||||
private:
|
||||
uInt32& getSegmentSizeRef(SegmentType type);
|
||||
unique_ptr<uInt8[]>& getSegmentDataRef(SegmentType type);
|
||||
|
||||
void relocateSections();
|
||||
void relocateInitArrays();
|
||||
void relocateSymbols(const vector<ExternalSymbol>& externalSymbols);
|
||||
|
@ -116,12 +115,15 @@ class ElfLinker {
|
|||
|
||||
const uInt32 myTextBase{0};
|
||||
const uInt32 myDataBase{0};
|
||||
const uInt32 myRodataBase{0};
|
||||
const ElfParser& myParser;
|
||||
|
||||
uInt32 myTextSize{0};
|
||||
uInt32 myDataSize{0};
|
||||
uInt32 myRodataSize{0};
|
||||
unique_ptr<uInt8[]> myTextData;
|
||||
unique_ptr<uInt8[]> myDataData;
|
||||
unique_ptr<uInt8[]> myRodataData;
|
||||
|
||||
vector<optional<RelocatedSection>> myRelocatedSections;
|
||||
vector<optional<RelocatedSymbol>> myRelocatedSymbols;
|
||||
|
|
Loading…
Reference in New Issue