diff --git a/Makefile b/Makefile index a5654dfe2..31986582e 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ LDFLAGS := -pthread INCLUDES := LIBS := OBJS := +OBJS_TEST := PROF := MODULES := diff --git a/common.rules b/common.rules index 2838c0e5d..a609da742 100644 --- a/common.rules +++ b/common.rules @@ -9,4 +9,4 @@ MODULE_TEST_OBJS-$(MODULE) := $(MODULE_TEST_OBJS) # If not building as a plugin, add the object files to the main OBJS list #OBJS += $(MODULE_LIB-$(MODULE)) OBJS += $(MODULE_OBJS) -OBJS_TEST := $(MODULE_TEST_OBJS) +OBJS_TEST += $(MODULE_TEST_OBJS) diff --git a/src/cheat/module.mk b/src/cheat/module.mk index 2b454e45c..5064f6e65 100644 --- a/src/cheat/module.mk +++ b/src/cheat/module.mk @@ -7,8 +7,10 @@ MODULE_OBJS := \ src/cheat/BankRomCheat.o \ src/cheat/RamCheat.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/cheat -# Include common rules +# Include common rules include $(srcdir)/common.rules diff --git a/src/common/audio/module.mk b/src/common/audio/module.mk index 91961a13b..d3986e63d 100644 --- a/src/common/audio/module.mk +++ b/src/common/audio/module.mk @@ -6,6 +6,8 @@ MODULE_OBJS := \ src/common/audio/LanczosResampler.o \ src/common/audio/HighPass.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/emucore/tia \ src/emucore/elf diff --git a/src/common/module.mk b/src/common/module.mk index 4b29556e8..58bee6d5d 100644 --- a/src/common/module.mk +++ b/src/common/module.mk @@ -4,7 +4,7 @@ MODULE_OBJS := \ src/common/AudioQueue.o \ src/common/AudioSettings.o \ src/common/Base.o \ - src/common/Bezel.o \ + src/common/Bezel.o \ src/common/DevSettingsHandler.o \ src/common/EventHandlerSDL2.o \ src/common/FBBackendSDL2.o \ @@ -41,6 +41,9 @@ MODULE_OBJS := \ src/common/repository/CompositeKVRJsonAdapter.o \ src/common/repository/CompositeKeyValueRepository.o +MODULE_TEST_OBJS = \ + src/common/Logger.o + MODULE_DIRS += \ src/common diff --git a/src/common/repository/sqlite/module.mk b/src/common/repository/sqlite/module.mk index 2bf7f680c..695908839 100644 --- a/src/common/repository/sqlite/module.mk +++ b/src/common/repository/sqlite/module.mk @@ -9,6 +9,8 @@ MODULE_OBJS := \ src/common/repository/sqlite/SqliteStatement.o \ src/common/repository/sqlite/SqliteTransaction.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/common/repository/sqlite diff --git a/src/common/tv_filters/module.mk b/src/common/tv_filters/module.mk index 02fedb50b..8f2cc535d 100644 --- a/src/common/tv_filters/module.mk +++ b/src/common/tv_filters/module.mk @@ -4,6 +4,8 @@ MODULE_OBJS := \ src/common/tv_filters/NTSCFilter.o \ src/common/tv_filters/AtariNTSC.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/common/tv_filters diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index d52f9ecbe..f7fb85c5c 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -90,6 +90,8 @@ MODULE_OBJS := \ src/debugger/gui/ToggleWidget.o \ src/debugger/gui/TrakBallWidget.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/debugger/gui diff --git a/src/debugger/module.mk b/src/debugger/module.mk index 6356aad6a..5999938b1 100644 --- a/src/debugger/module.mk +++ b/src/debugger/module.mk @@ -11,6 +11,8 @@ MODULE_OBJS := \ src/debugger/TIADebug.o \ src/debugger/TimerMap.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/debugger diff --git a/src/debugger/yacc/module.mk b/src/debugger/yacc/module.mk index 9f51bb344..38e523dc7 100644 --- a/src/debugger/yacc/module.mk +++ b/src/debugger/yacc/module.mk @@ -3,6 +3,8 @@ MODULE := src/debugger/yacc MODULE_OBJS := \ src/debugger/yacc/YaccParser.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/debugger/yacc diff --git a/src/emucore/elf/ElfParser.cxx b/src/emucore/elf/ElfParser.cxx index 0d46e36e2..06bc3edf9 100644 --- a/src/emucore/elf/ElfParser.cxx +++ b/src/emucore/elf/ElfParser.cxx @@ -129,7 +129,7 @@ const vector& ElfParser::getSymbols() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const optional> ElfParser::getRelocations(size_t section) const { - return myRelocations.contains(section) ? myRelocations.at(section) : optional>(); + return myRelocations.contains(section) ? myRelocations.at(section) : optional>(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/elf/LinkerTest.cxx b/src/emucore/elf/LinkerTest.cxx new file mode 100644 index 000000000..5095930cb --- /dev/null +++ b/src/emucore/elf/LinkerTest.cxx @@ -0,0 +1,244 @@ +//============================================================================ +// +// 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. +//============================================================================ + +#include +#include + +#include "bspf.hxx" +#include "ElfFile.hxx" +#include "ElfLinker.hxx" + +namespace { + + class ElfFixture: public ElfFile { + public: + explicit ElfFixture(size_t size) : mySize(size) { + myData = make_unique(mySize); + } + + const uInt8 *getData() const override { + return myData.get(); + } + + size_t getSize() const override { + return mySize; + } + + const vector
& getSections() const override { + return mySections; + } + + const vector& getSymbols() const override { + return mySymbols; + } + + const optional> getRelocations(size_t section) const override { + return myRelocations.contains(section) ? myRelocations.at(section) : optional>(); + } + + ElfFixture& addSection(string_view name, uInt32 type, uInt32 offset, uInt32 size, uInt32 align = 4) { + mySections.push_back({ + .nameOffset = 0, + .name = string(name), + .type = type, + .flags = 0, + .virtualAddress = 0, + .offset = offset, + .size = size, + .info = 0, + .align = align + }); + + return *this; + } + + ElfFixture& write8(size_t address, uInt8 value) { + myData[address] = value; + + return *this; + } + + public: + size_t mySize; + unique_ptr myData; + + vector
mySections; + vector mySymbols; + std::unordered_map> myRelocations; + }; + + TEST(ElfLinker, HasEmptySegmentsForAnEmptyELF) { + ElfFixture fixture(0); + ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture); + + linker.link({}); + + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::text), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast(0)); + } + + TEST(ElfLinker, TextSegmentsGoToText) { + ElfFixture fixture(1000); + ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture); + + fixture + .addSection(".text.1", ElfFile::SHT_PROGBITS, 0, 10, 4) + .write8(0, 0x01) + .addSection(".text.2", ElfFile::SHT_PROGBITS, 10, 21, 4) + .write8(10, 0x02) + .addSection(".text.3", ElfFile::SHT_PROGBITS, 31, 33, 2) + .write8(31, 0x03) + .addSection(".text.4", ElfFile::SHT_PROGBITS, 64, 11, 1) + .write8(64, 0x04); + + linker.link({}); + + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::text), static_cast(78)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast(0)); + + EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast(0)); + EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::text); + + EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast(12)); + EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::text); + + EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast(34)); + EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::text); + + EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast(67)); + EXPECT_EQ(linker.getRelocatedSections()[3]->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) { + ElfFixture fixture(1000); + ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture); + + fixture + .addSection(".data.1", ElfFile::SHT_PROGBITS, 0, 10, 4) + .write8(0, 0x01) + .addSection(".data.2", ElfFile::SHT_PROGBITS, 10, 21, 4) + .write8(10, 0x02) + .addSection(".data.3", ElfFile::SHT_PROGBITS, 31, 33, 2) + .write8(31, 0x03) + .addSection(".data.4", ElfFile::SHT_PROGBITS, 64, 11, 1) + .write8(64, 0x04); + + linker.link({}); + + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::text), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast(78)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast(0)); + + EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast(0)); + EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::data); + + EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast(12)); + EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::data); + + EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast(34)); + EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::data); + + EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast(67)); + EXPECT_EQ(linker.getRelocatedSections()[3]->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) { + ElfFixture fixture(1000); + ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture); + + fixture + .addSection(".rodata.1", ElfFile::SHT_PROGBITS, 0, 10, 4) + .write8(0, 0x01) + .addSection(".rodata.2", ElfFile::SHT_PROGBITS, 10, 21, 4) + .write8(10, 0x02) + .addSection(".rodata.3", ElfFile::SHT_PROGBITS, 31, 33, 2) + .write8(31, 0x03) + .addSection(".rodata.4", ElfFile::SHT_PROGBITS, 64, 11, 1) + .write8(64, 0x04); + + linker.link({}); + + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::text), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast(78)); + + EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast(0)); + EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::rodata); + + EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast(12)); + EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::rodata); + + EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast(34)); + EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::rodata); + + EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast(67)); + EXPECT_EQ(linker.getRelocatedSections()[3]->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); + EXPECT_EQ(linker.getSegmentData(ElfLinker::SegmentType::rodata)[67], 0x04); + } + + TEST(ElfLinker, BssSectionsGoToTheEndOfData) { + ElfFixture fixture(1000); + ElfLinker linker(0x00100000, 0x00200000, 0x00300000, fixture); + + fixture + .addSection(".data.1", ElfFile::SHT_PROGBITS, 0, 10, 4) + .write8(0, 0x01) + .addSection(".bss", ElfFile::SHT_NOBITS, 0, 21, 4) + .addSection(".data.2", ElfFile::SHT_PROGBITS, 10, 33, 2) + .write8(10, 0x02) + .addSection(".noinit", ElfFile::SHT_NOBITS, 0, 11, 1); + + linker.link({}); + + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::text), static_cast(0)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::data), static_cast(76)); + EXPECT_EQ(linker.getSegmentSize(ElfLinker::SegmentType::rodata), static_cast(0)); + + EXPECT_EQ(linker.getRelocatedSections()[0]->offset, static_cast(0)); + EXPECT_EQ(linker.getRelocatedSections()[0]->segment, ElfLinker::SegmentType::data); + + EXPECT_EQ(linker.getRelocatedSections()[1]->offset, static_cast(44)); + EXPECT_EQ(linker.getRelocatedSections()[1]->segment, ElfLinker::SegmentType::data); + + EXPECT_EQ(linker.getRelocatedSections()[2]->offset, static_cast(10)); + EXPECT_EQ(linker.getRelocatedSections()[2]->segment, ElfLinker::SegmentType::data); + + EXPECT_EQ(linker.getRelocatedSections()[3]->offset, static_cast(65)); + EXPECT_EQ(linker.getRelocatedSections()[3]->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); + } +} diff --git a/src/emucore/elf/module.mk b/src/emucore/elf/module.mk index 1fe5fd51f..21dfc746b 100644 --- a/src/emucore/elf/module.mk +++ b/src/emucore/elf/module.mk @@ -8,10 +8,12 @@ MODULE_OBJS = \ MODULE_TEST_OBJS = \ src/emucore/elf/ElfUtil.o \ - src/emucore/elf/EncodingTest.o + src/emucore/elf/ElfLinker.o \ + src/emucore/elf/EncodingTest.o \ + src/emucore/elf/LinkerTest.o MODULE_DIRS += \ - src/emucore/elf/EncodingTest.o + src/emucore/elf # Include common rules include $(srcdir)/common.rules diff --git a/src/emucore/module.mk b/src/emucore/module.mk index b9e542dbd..d356d09e1 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -99,6 +99,8 @@ MODULE_OBJS := \ src/emucore/TIASurface.o \ src/emucore/Thumbulator.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/emucore diff --git a/src/emucore/tia/frame-manager/module.mk b/src/emucore/tia/frame-manager/module.mk index b4f8fdcdb..53ef04139 100644 --- a/src/emucore/tia/frame-manager/module.mk +++ b/src/emucore/tia/frame-manager/module.mk @@ -6,6 +6,8 @@ MODULE_OBJS := \ src/emucore/tia/frame-manager/FrameLayoutDetector.o \ src/emucore/tia/frame-manager/JitterEmulation.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/emucore/tia/frame-manager diff --git a/src/emucore/tia/module.mk b/src/emucore/tia/module.mk index 3b88dce3a..f136b5480 100644 --- a/src/emucore/tia/module.mk +++ b/src/emucore/tia/module.mk @@ -13,6 +13,8 @@ MODULE_OBJS := \ src/emucore/tia/Audio.o \ src/emucore/tia/AudioChannel.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/emucore/tia diff --git a/src/gui/module.mk b/src/gui/module.mk index 0e693ecbc..91c48d171 100644 --- a/src/gui/module.mk +++ b/src/gui/module.mk @@ -64,6 +64,8 @@ MODULE_OBJS := \ src/gui/WhatsNewDialog.o \ src/gui/Widget.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/gui diff --git a/src/lib/libpng/module.mk b/src/lib/libpng/module.mk index d450711b5..73e222c15 100644 --- a/src/lib/libpng/module.mk +++ b/src/lib/libpng/module.mk @@ -17,6 +17,8 @@ MODULE_OBJS := \ src/lib/libpng/pngwtran.o \ src/lib/libpng/pngwutil.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/lib/libpng diff --git a/src/lib/sqlite/module.mk b/src/lib/sqlite/module.mk index bfb143ca9..92c28e2d4 100644 --- a/src/lib/sqlite/module.mk +++ b/src/lib/sqlite/module.mk @@ -3,6 +3,8 @@ MODULE := src/lib/sqlite MODULE_OBJS := \ src/lib/sqlite/sqlite3.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/lib/sqlite diff --git a/src/lib/tinyexif/module.mk b/src/lib/tinyexif/module.mk index 1d59efe84..8b044479a 100644 --- a/src/lib/tinyexif/module.mk +++ b/src/lib/tinyexif/module.mk @@ -3,6 +3,8 @@ MODULE := src/lib/tinyexif MODULE_OBJS := \ src/lib/tinyexif/tinyexif.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/lib/tinyexif diff --git a/src/lib/zlib/module.mk b/src/lib/zlib/module.mk index f536747ab..0adf9d2f2 100644 --- a/src/lib/zlib/module.mk +++ b/src/lib/zlib/module.mk @@ -17,6 +17,8 @@ MODULE_OBJS := \ src/lib/zlib/inftrees.o \ src/lib/zlib/inffast.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/lib/zlib diff --git a/src/os/unix/module.mk b/src/os/unix/module.mk index 782d3e98a..a6eb05c16 100644 --- a/src/os/unix/module.mk +++ b/src/os/unix/module.mk @@ -5,6 +5,8 @@ MODULE_OBJS := \ src/os/unix/OSystemUNIX.o \ src/os/unix/SerialPortUNIX.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/os/unix diff --git a/src/os/unix/r77/module.mk b/src/os/unix/r77/module.mk index 95463ddbc..5c6763cc7 100644 --- a/src/os/unix/r77/module.mk +++ b/src/os/unix/r77/module.mk @@ -4,6 +4,8 @@ MODULE_OBJS := \ src/os/unix/r77/OSystemR77.o \ src/os/unix/r77/SettingsR77.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/os/unix/r77 diff --git a/src/os/windows/module.mk b/src/os/windows/module.mk index a4745ed0b..b2a767cb0 100644 --- a/src/os/windows/module.mk +++ b/src/os/windows/module.mk @@ -7,6 +7,8 @@ MODULE_OBJS := \ src/os/windows/SettingsWINDOWS.o \ src/os/windows/stella_icon.o +MODULE_TEST_OBJS = + MODULE_DIRS += \ src/os/windows