More linker tests.

This commit is contained in:
Christian Speckner 2024-07-14 11:22:30 +02:00
parent 428d36943e
commit 92d5478e02
2 changed files with 230 additions and 27 deletions

View File

@ -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;

View File

@ -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));
}
}