mirror of https://github.com/stella-emu/stella.git
Port and hook up ELF basic parser.
This commit is contained in:
parent
cccc92020a
commit
be80e6b0f7
1
Makefile
1
Makefile
|
@ -176,6 +176,7 @@ MODULES += \
|
||||||
src/emucore \
|
src/emucore \
|
||||||
src/emucore/tia \
|
src/emucore/tia \
|
||||||
src/emucore/tia/frame-manager \
|
src/emucore/tia/frame-manager \
|
||||||
|
src/emucore/elf \
|
||||||
src/common/repository/sqlite
|
src/common/repository/sqlite
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
|
@ -799,6 +799,7 @@ SRC_LIB="$SRC/lib"
|
||||||
CORE="$SRC/emucore"
|
CORE="$SRC/emucore"
|
||||||
COMMON="$SRC/common"
|
COMMON="$SRC/common"
|
||||||
TIA="$SRC/emucore/tia"
|
TIA="$SRC/emucore/tia"
|
||||||
|
ELF="$SRC/emucore/elf"
|
||||||
TIA_FRAME_MANAGER="$SRC/emucore/tia/frame-manager"
|
TIA_FRAME_MANAGER="$SRC/emucore/tia/frame-manager"
|
||||||
TV="$SRC/common/tv_filters"
|
TV="$SRC/common/tv_filters"
|
||||||
GUI="$SRC/gui"
|
GUI="$SRC/gui"
|
||||||
|
@ -815,7 +816,7 @@ SQLITE_LIB="$SRC_LIB/sqlite"
|
||||||
JSON="$SRC_LIB/json"
|
JSON="$SRC_LIB/json"
|
||||||
HTTP_LIB="$SRC_LIB/httplib"
|
HTTP_LIB="$SRC_LIB/httplib"
|
||||||
|
|
||||||
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$JSON -I$SQLITE_REPO"
|
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$ELF -I$JSON -I$SQLITE_REPO"
|
||||||
|
|
||||||
INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
|
INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
|
||||||
if test "$_build_static" = yes ; then
|
if test "$_build_static" = yes ; then
|
||||||
|
|
|
@ -7,7 +7,8 @@ MODULE_OBJS := \
|
||||||
src/common/audio/HighPass.o
|
src/common/audio/HighPass.o
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
src/emucore/tia
|
src/emucore/tia \
|
||||||
|
src/emucore/elf
|
||||||
|
|
||||||
# Include common rules
|
# Include common rules
|
||||||
include $(srcdir)/common.rules
|
include $(srcdir)/common.rules
|
||||||
|
|
|
@ -58,6 +58,7 @@ using uInt64 = uint64_t;
|
||||||
#include <numbers>
|
#include <numbers>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
using std::cin;
|
using std::cin;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
@ -78,6 +79,7 @@ using std::make_shared;
|
||||||
using std::array;
|
using std::array;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::runtime_error;
|
using std::runtime_error;
|
||||||
|
using std::optional;
|
||||||
|
|
||||||
// Common array types
|
// Common array types
|
||||||
using IntArray = std::vector<Int32>;
|
using IntArray = std::vector<Int32>;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "Logger.hxx"
|
#include "Logger.hxx"
|
||||||
|
|
||||||
|
#include "ElfParser.hxx"
|
||||||
#include "CartDetector.hxx"
|
#include "CartDetector.hxx"
|
||||||
#include "CartMVC.hxx"
|
#include "CartMVC.hxx"
|
||||||
|
|
||||||
|
@ -868,13 +869,13 @@ bool CartDetector::isProbablyELF(const ByteBuffer& image, size_t size) {
|
||||||
if (!searchForBytes(image, 2 * sizeof(signature), signature, sizeof(signature), 1)) return false;
|
if (!searchForBytes(image, 2 * sizeof(signature), signature, sizeof(signature), 1)) return false;
|
||||||
|
|
||||||
// We require little endian
|
// We require little endian
|
||||||
if (image[0x05] != 1) return false;
|
if (image[0x05] != ElfParser::ENDIAN_LITTLE_ENDIAN) return false;
|
||||||
|
|
||||||
// Type must be ET_REL (relocatable ELF)
|
// Type must be ET_REL (relocatable ELF)
|
||||||
if (image[0x10] != 0x01) return false;
|
if (image[0x10] != ElfParser::ET_REL) return false;
|
||||||
|
|
||||||
// Arch must be ARM
|
// Arch must be ARM
|
||||||
if (image[0x12] != 0x28) return false;
|
if (image[0x12] != ElfParser::ARCH_ARM32) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,12 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings, md5), myImageSize(size)
|
: Cartridge(settings, md5), myImageSize(size)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
elfParser.parse(image.get(), size);
|
||||||
|
} catch (ElfParser::EInvalidElf& e) {
|
||||||
|
throw runtime_error("failed to initialize ELF: " + e.getReason());
|
||||||
|
}
|
||||||
|
|
||||||
myImage = make_unique<uInt8[]>(size);
|
myImage = make_unique<uInt8[]>(size);
|
||||||
std::memcpy(myImage.get(), image.get(), size);
|
std::memcpy(myImage.get(), image.get(), size);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "Cart.hxx"
|
#include "Cart.hxx"
|
||||||
|
#include "ElfParser.hxx"
|
||||||
|
|
||||||
class CartridgeELF: public Cartridge {
|
class CartridgeELF: public Cartridge {
|
||||||
public:
|
public:
|
||||||
|
@ -114,6 +115,8 @@ class CartridgeELF: public Cartridge {
|
||||||
|
|
||||||
bool myIsBusDriven{false};
|
bool myIsBusDriven{false};
|
||||||
uInt8 myDriveBusValue{0};
|
uInt8 myDriveBusValue{0};
|
||||||
|
|
||||||
|
ElfParser elfParser;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CARTRIDGE_ELF
|
#endif // CARTRIDGE_ELF
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
#include "ElfParser.hxx"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr uInt32 ELF_MAGIC = 0x7f454c46;
|
||||||
|
constexpr uInt8 ELF_CLASS_32 = 1;
|
||||||
|
constexpr uInt8 ELF_VERSION = 1;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ElfParser::EInvalidElf::EInvalidElf(const string &reason) : reason(reason) {}
|
||||||
|
|
||||||
|
const string &ElfParser::EInvalidElf::getReason() const { return reason; }
|
||||||
|
|
||||||
|
void ElfParser::parse(const uInt8 *elfData, size_t size) {
|
||||||
|
data = elfData;
|
||||||
|
this->size = size;
|
||||||
|
|
||||||
|
sections.resize(0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (read32(0x00) != ELF_MAGIC) throw EInvalidElf("bad magic");
|
||||||
|
if (read8(0x04) != ELF_CLASS_32) throw EInvalidElf("not 32bit ELF");
|
||||||
|
if (read8(0x06) != ELF_VERSION) throw EInvalidElf("invalid ELF version");
|
||||||
|
|
||||||
|
header.endianess = read8(0x05);
|
||||||
|
bigEndian = header.endianess == ENDIAN_BIG_ENDIAN;
|
||||||
|
|
||||||
|
if (read32(0x14) != ELF_VERSION) throw EInvalidElf("inconsistent ELF version");
|
||||||
|
|
||||||
|
header.type = read16(0x10);
|
||||||
|
header.arch = read16(0x12);
|
||||||
|
|
||||||
|
header.shOffset = read32(0x20);
|
||||||
|
header.shSize = read16(0x2e);
|
||||||
|
header.shNum = read16(0x30);
|
||||||
|
header.shstrIndex = read16(0x32);
|
||||||
|
|
||||||
|
if (header.shstrIndex >= header.shNum) throw EInvalidElf(".shstrtab out of range");
|
||||||
|
|
||||||
|
sections.reserve(header.shNum);
|
||||||
|
|
||||||
|
for (uInt32 i = 0; i < header.shNum; i++)
|
||||||
|
sections.push_back(
|
||||||
|
readSection(header.shOffset + i * header.shSize));
|
||||||
|
|
||||||
|
const Section &shrstrtab(sections[header.shstrIndex]);
|
||||||
|
|
||||||
|
if (shrstrtab.type != SHT_STRTAB) throw new EInvalidElf(".shstrtab has wrong type");
|
||||||
|
|
||||||
|
|
||||||
|
for (Section §ion : sections)
|
||||||
|
section.name = getName(shrstrtab, section.nameOffset);
|
||||||
|
|
||||||
|
} catch (const EInvalidElf &e) {
|
||||||
|
throw EInvalidElf("failed to parse ELF: " + e.getReason());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uInt8 *ElfParser::getData() const { return data; }
|
||||||
|
|
||||||
|
size_t ElfParser::getSize() const { return size; }
|
||||||
|
|
||||||
|
const vector<ElfParser::Section> &ElfParser::getSections() const {
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
const optional<ElfParser::Section>
|
||||||
|
ElfParser::getSection(const string &name) const {
|
||||||
|
for (const Section §ion : sections)
|
||||||
|
if (section.name == name)
|
||||||
|
return section;
|
||||||
|
|
||||||
|
return optional<Section>();
|
||||||
|
}
|
||||||
|
|
||||||
|
uInt8 ElfParser::read8(uInt32 offset) {
|
||||||
|
if (offset >= size)
|
||||||
|
throw EInvalidElf("reference beyond bounds");
|
||||||
|
|
||||||
|
return data[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
uInt16 ElfParser::read16(uInt32 offset) {
|
||||||
|
return bigEndian ? ((read8(offset) << 8) | read8(offset + 1))
|
||||||
|
: ((read8(offset + 1) << 8) | read8(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
uInt32 ElfParser::read32(uInt32 offset) {
|
||||||
|
return bigEndian ? ((read8(offset) << 24) | (read8(offset + 1) << 16) |
|
||||||
|
(read8(offset + 2) << 8) | read8(offset + 3))
|
||||||
|
: ((read8(offset + 3) << 24) | (read8(offset + 2) << 16) |
|
||||||
|
(read8(offset + 1) << 8) | read8(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfParser::Section ElfParser::readSection(uInt32 offset) {
|
||||||
|
Section section;
|
||||||
|
|
||||||
|
try {
|
||||||
|
section.nameOffset = read32(offset);
|
||||||
|
section.type = read32(offset + 0x04);
|
||||||
|
section.flags = read32(offset + 0x08);
|
||||||
|
section.virtualAddress = read32(offset + 0x0c);
|
||||||
|
section.offset = read32(offset + 0x10);
|
||||||
|
section.size = read32(offset + 0x14);
|
||||||
|
section.align = read32(offset + 0x20);
|
||||||
|
|
||||||
|
if (section.offset + section.size >= size)
|
||||||
|
throw EInvalidElf("section exceeds bounds");
|
||||||
|
} catch (const EInvalidElf &e) {
|
||||||
|
throw EInvalidElf("failed to parse section: " + e.getReason());
|
||||||
|
}
|
||||||
|
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ElfParser::getName(const Section& section, uInt32 offset)
|
||||||
|
{
|
||||||
|
if (offset >= section.size) throw EInvalidElf("name out of bounds");
|
||||||
|
const uInt32 imageOffset = offset + section.offset;
|
||||||
|
|
||||||
|
const char *name = reinterpret_cast<const char *>(data + imageOffset);
|
||||||
|
|
||||||
|
if (data[imageOffset + strnlen(name, section.size - offset)] != '\0')
|
||||||
|
throw new EInvalidElf("unterminated section name");
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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_PARSER
|
||||||
|
#define ELF_PARSER
|
||||||
|
|
||||||
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
class ElfParser {
|
||||||
|
public:
|
||||||
|
class EInvalidElf {
|
||||||
|
friend ElfParser;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const std::string &getReason() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EInvalidElf(const std::string &reason);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Header {
|
||||||
|
uInt16 type;
|
||||||
|
uInt16 arch;
|
||||||
|
uInt8 endianess;
|
||||||
|
uInt32 shOffset;
|
||||||
|
|
||||||
|
uInt16 shNum;
|
||||||
|
uInt16 shSize;
|
||||||
|
uInt16 shstrIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Section {
|
||||||
|
uInt32 nameOffset;
|
||||||
|
string name;
|
||||||
|
|
||||||
|
uInt32 type;
|
||||||
|
uInt32 flags;
|
||||||
|
|
||||||
|
uInt32 virtualAddress;
|
||||||
|
uInt32 offset;
|
||||||
|
uInt32 size;
|
||||||
|
|
||||||
|
uInt32 align;
|
||||||
|
};
|
||||||
|
|
||||||
|
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_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;
|
||||||
|
|
||||||
|
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<Section>& getSections() const;
|
||||||
|
const optional<Section> getSection(const std::string &name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uInt8 read8(uInt32 offset);
|
||||||
|
uInt16 read16(uInt32 offset);
|
||||||
|
uInt32 read32(uInt32 offset);
|
||||||
|
|
||||||
|
Section readSection(uInt32 offset);
|
||||||
|
const char* getName(const Section& section, uInt32 offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uInt8 *data{nullptr};
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
bool bigEndian{true};
|
||||||
|
|
||||||
|
Header header;
|
||||||
|
vector<Section> sections;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ELF_PARSER
|
|
@ -0,0 +1,10 @@
|
||||||
|
MODULE := src/emucore/elf
|
||||||
|
|
||||||
|
MODULE_OBJS = \
|
||||||
|
src/emucore/elf/ElfParser.o
|
||||||
|
|
||||||
|
MODULE_DIRS += \
|
||||||
|
src/emucore/elf
|
||||||
|
|
||||||
|
# Include common rules
|
||||||
|
include $(srcdir)/common.rules
|
|
@ -790,6 +790,7 @@
|
||||||
<ClCompile Include="..\..\emucore\CartUA.cxx" />
|
<ClCompile Include="..\..\emucore\CartUA.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\CartX07.cxx" />
|
<ClCompile Include="..\..\emucore\CartX07.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\CartELF.cxx" />
|
<ClCompile Include="..\..\emucore\CartELF.cxx" />
|
||||||
|
<ClCompile Include="..\..\emucore\elf\ElfParser.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\Console.cxx" />
|
<ClCompile Include="..\..\emucore\Console.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\Control.cxx" />
|
<ClCompile Include="..\..\emucore\Control.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\Driving.cxx" />
|
<ClCompile Include="..\..\emucore\Driving.cxx" />
|
||||||
|
@ -1788,6 +1789,7 @@
|
||||||
<ClInclude Include="..\..\emucore\CartUA.hxx" />
|
<ClInclude Include="..\..\emucore\CartUA.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\CartX07.hxx" />
|
<ClInclude Include="..\..\emucore\CartX07.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\CartELF.hxx" />
|
<ClInclude Include="..\..\emucore\CartELF.hxx" />
|
||||||
|
<ClInclude Include="..\..\emucore\elf\ElfParser.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\Console.hxx" />
|
<ClInclude Include="..\..\emucore\Console.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\Control.hxx" />
|
<ClInclude Include="..\..\emucore\Control.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\DefProps.hxx" />
|
<ClInclude Include="..\..\emucore\DefProps.hxx" />
|
||||||
|
|
|
@ -234,6 +234,9 @@
|
||||||
<ClCompile Include="..\..\emucore\CartELF.cxx">
|
<ClCompile Include="..\..\emucore\CartELF.cxx">
|
||||||
<Filter>Source Files\emucore</Filter>
|
<Filter>Source Files\emucore</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\emucore\ElfParser.cxx">
|
||||||
|
<Filter>Source Files\emucore</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\emucore\Console.cxx">
|
<ClCompile Include="..\..\emucore\Console.cxx">
|
||||||
<Filter>Source Files\emucore</Filter>
|
<Filter>Source Files\emucore</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1271,6 +1274,9 @@
|
||||||
<ClInclude Include="..\..\emucore\CartELF.hxx">
|
<ClInclude Include="..\..\emucore\CartELF.hxx">
|
||||||
<Filter>Header Files\emucore</Filter>
|
<Filter>Header Files\emucore</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\emucore\elf\ElfParser.hxx">
|
||||||
|
<Filter>Header Files\emucore</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\emucore\CartAR.hxx">
|
<ClInclude Include="..\..\emucore\CartAR.hxx">
|
||||||
<Filter>Header Files\emucore</Filter>
|
<Filter>Header Files\emucore</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
Loading…
Reference in New Issue