mirror of https://github.com/stella-emu/stella.git
More linker tests.
This commit is contained in:
parent
428d36943e
commit
92d5478e02
|
@ -92,6 +92,7 @@ class ElfFile {
|
|||
static constexpr uInt32 SHN_UND = 0x00;
|
||||
|
||||
static constexpr uInt32 STT_SECTION = 0x03;
|
||||
static constexpr uInt32 STT_NOTYPE = 0x00;
|
||||
|
||||
static constexpr uInt32 R_ARM_ABS32 = 0x02;
|
||||
static constexpr uInt32 R_ARM_THM_CALL = 0x0a;
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace {
|
|||
public:
|
||||
explicit ElfFixture(size_t size) : mySize(size) {
|
||||
myData = make_unique<uInt8[]>(mySize);
|
||||
|
||||
addSection("", 0, 0, 0);
|
||||
}
|
||||
|
||||
const uInt8 *getData() const override {
|
||||
|
@ -66,6 +68,22 @@ namespace {
|
|||
return *this;
|
||||
}
|
||||
|
||||
ElfFixture& addSymbol(string_view name, uInt32 value, uInt16 section, uInt8 type = ElfFile::STT_NOTYPE) {
|
||||
mySymbols.push_back({
|
||||
.nameOffset = 0,
|
||||
.value = value,
|
||||
.size = 0,
|
||||
.info = 0,
|
||||
.visibility = 0,
|
||||
.section = section,
|
||||
.name = string(name),
|
||||
.bind = 0,
|
||||
.type = type
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ElfFixture& write8(size_t address, uInt8 value) {
|
||||
myData[address] = value;
|
||||
|
||||
|
@ -92,7 +110,7 @@ namespace {
|
|||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast<uInt32>(0));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, TextSegmentsGoToText) {
|
||||
TEST(ElfLinker, TextSectionsGoToText) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
|
@ -112,25 +130,25 @@ namespace {
|
|||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast<uInt32>(0));
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::text);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(12));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::text);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(34));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(12));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::text);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(67));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(34));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->segment, ElfLinker::SegmentType::text);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->offset, static_cast<uInt32>(67));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->segment, ElfLinker::SegmentType::text);
|
||||
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::text)[0], 0x01);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::text)[12], 0x02);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::text)[34], 0x03);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::text)[67], 0x04);
|
||||
}
|
||||
|
||||
TEST(ElfLinker, DataSegmentsGoToData) {
|
||||
TEST(ElfLinker, DataSectionsGoToData) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
|
@ -150,25 +168,25 @@ namespace {
|
|||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast<uInt32>(78));
|
||||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast<uInt32>(0));
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(12));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(34));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(12));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(67));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(34));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->offset, static_cast<uInt32>(67));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[0], 0x01);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[12], 0x02);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[34], 0x03);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[67], 0x04);
|
||||
}
|
||||
|
||||
TEST(ElfLinker, RodataSegmentsGoToRodata) {
|
||||
TEST(ElfLinker, RodataSectionsGoToRodata) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
|
@ -188,18 +206,18 @@ TEST(ElfLinker, RodataSegmentsGoToRodata) {
|
|||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast<uInt32>(78));
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::rodata);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(12));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::rodata);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(34));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(12));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::rodata);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(67));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(34));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->segment, ElfLinker::SegmentType::rodata);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->offset, static_cast<uInt32>(67));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->segment, ElfLinker::SegmentType::rodata);
|
||||
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::rodata)[0], 0x01);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::rodata)[12], 0x02);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::rodata)[34], 0x03);
|
||||
|
@ -224,21 +242,205 @@ TEST(ElfLinker, RodataSegmentsGoToRodata) {
|
|||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast<uInt32>(76));
|
||||
EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast<uInt32>(0));
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(44));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast<uInt32>(0));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(10));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast<uInt32>(44));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(65));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast<uInt32>(10));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[3]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->offset, static_cast<uInt32>(65));
|
||||
EXPECT_EQ(linker.getRelocatedSections()[4]->segment, ElfLinker::SegmentType::data);
|
||||
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[0], 0x01);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[10], 0x02);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[44], 0);
|
||||
EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::data)[65], 0);
|
||||
}
|
||||
|
||||
TEST(ElfLinker, SegmentsMayEndNextToEachOther) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(100, 200, 300, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 100, 4)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 100, 4)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 100, 4);
|
||||
|
||||
EXPECT_NO_THROW(linker.link({}));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, OverlappingTextAndDataSegmentsThrow) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(100, 200, 300, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 101, 4)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 100, 4)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 100, 4);
|
||||
|
||||
EXPECT_THROW(linker.link({}), ElfLinker::ElfLinkError);
|
||||
}
|
||||
|
||||
TEST(ElfLinker, OverlappingTextAndRodataSegmentsThrow) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(100, 300, 200, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 101, 4)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 100, 4)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 100, 4);
|
||||
|
||||
EXPECT_THROW(linker.link({}), ElfLinker::ElfLinkError);
|
||||
}
|
||||
|
||||
TEST(ElfLinker, OverlappingDataAndRodataSegmentsThrow) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(100, 200, 300, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 100, 4)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 101, 4)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 100, 4);
|
||||
|
||||
EXPECT_THROW(linker.link({}), ElfLinker::ElfLinkError);
|
||||
}
|
||||
|
||||
TEST(ElfLinker, ABSSymbolsAreAcceptedUnchanged) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSymbol("foo", 0x12345678, ElfFile::SHN_ABS);
|
||||
|
||||
linker.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x12345678));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, UNDSymbolesAreTakenFromExternals) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSymbol("foo", 0, ElfFile::SHN_UND);
|
||||
|
||||
linker.link({{"foo", 0x12345678}});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x12345678));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, UNDSymbolsAreResolvedWithTheDefaultIfSet) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSymbol("foo", 0, ElfFile::SHN_UND);
|
||||
|
||||
linker
|
||||
.setUndefinedSymbolDefault(0x12345678)
|
||||
.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x12345678));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, UNDSymbolsAreIgnoredIfTheyCannotBeResolved) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSymbol("foo", 0, ElfFile::SHN_UND);
|
||||
|
||||
linker.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0].has_value());
|
||||
}
|
||||
|
||||
TEST(ElfLinker, SymbolsThatReferToTextAreResolvedRelativeToText) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text.1", ElfFile::SHT_PROGBITS, 0, 0x10)
|
||||
.addSection(".text.2", ElfFile::SHT_PROGBITS, 0, 0xef)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSymbol("foo", 0x42, 2);
|
||||
|
||||
linker.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x00100052));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, SymbolsThatReferToDataAreResolvedRelativeToData) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSection(".data.1", ElfFile::SHT_PROGBITS, 0, 0x10)
|
||||
.addSection(".data.2", ElfFile::SHT_PROGBITS, 0, 0xef)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSymbol("foo", 0x42, 3);
|
||||
|
||||
linker.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x00200052));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, SymbolsThatReferToRodataAreResolvedRelativeToRodata) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSection(".rodata.1", ElfFile::SHT_PROGBITS, 0, 0x10)
|
||||
.addSection(".rodata.2", ElfFile::SHT_PROGBITS, 0, 0xef)
|
||||
.addSymbol("foo", 0x42, 4);
|
||||
|
||||
linker.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x00300052));
|
||||
}
|
||||
|
||||
TEST(ElfLinker, SymbolsThatReferToBssAreResolvedRelativeToBss) {
|
||||
ElfFixture fixture(1000);
|
||||
ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture);
|
||||
|
||||
fixture
|
||||
.addSection(".text", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSection(".data", ElfFile::SHT_PROGBITS, 0, 0x10)
|
||||
.addSection(".bss", ElfFile::SHT_PROGBITS, 0, 0xef)
|
||||
.addSection(".rodata", ElfFile::SHT_PROGBITS, 0, 0xff)
|
||||
.addSymbol("foo", 0x42, 3);
|
||||
|
||||
linker.link({});
|
||||
|
||||
EXPECT_EQ(linker.getRelocatedSymbols().size(), static_cast<size_t>(1));
|
||||
EXPECT_TRUE(linker.getRelocatedSymbols()[0].has_value());
|
||||
EXPECT_FALSE(linker.getRelocatedSymbols()[0]->undefined);
|
||||
EXPECT_EQ(linker.getRelocatedSymbols()[0]->value, static_cast<uInt32>(0x00200052));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue