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/tia \
|
||||
src/emucore/tia/frame-manager \
|
||||
src/emucore/elf \
|
||||
src/common/repository/sqlite
|
||||
|
||||
######################################################################
|
||||
|
|
|
@ -799,6 +799,7 @@ SRC_LIB="$SRC/lib"
|
|||
CORE="$SRC/emucore"
|
||||
COMMON="$SRC/common"
|
||||
TIA="$SRC/emucore/tia"
|
||||
ELF="$SRC/emucore/elf"
|
||||
TIA_FRAME_MANAGER="$SRC/emucore/tia/frame-manager"
|
||||
TV="$SRC/common/tv_filters"
|
||||
GUI="$SRC/gui"
|
||||
|
@ -815,7 +816,7 @@ SQLITE_LIB="$SRC_LIB/sqlite"
|
|||
JSON="$SRC_LIB/json"
|
||||
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`"
|
||||
if test "$_build_static" = yes ; then
|
||||
|
|
|
@ -7,7 +7,8 @@ MODULE_OBJS := \
|
|||
src/common/audio/HighPass.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/emucore/tia
|
||||
src/emucore/tia \
|
||||
src/emucore/elf
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/common.rules
|
||||
|
|
|
@ -58,6 +58,7 @@ using uInt64 = uint64_t;
|
|||
#include <numbers>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
|
@ -78,6 +79,7 @@ using std::make_shared;
|
|||
using std::array;
|
||||
using std::vector;
|
||||
using std::runtime_error;
|
||||
using std::optional;
|
||||
|
||||
// Common array types
|
||||
using IntArray = std::vector<Int32>;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "bspf.hxx"
|
||||
#include "Logger.hxx"
|
||||
|
||||
#include "ElfParser.hxx"
|
||||
#include "CartDetector.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;
|
||||
|
||||
// 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)
|
||||
if (image[0x10] != 0x01) return false;
|
||||
if (image[0x10] != ElfParser::ET_REL) return false;
|
||||
|
||||
// Arch must be ARM
|
||||
if (image[0x12] != 0x28) return false;
|
||||
if (image[0x12] != ElfParser::ARCH_ARM32) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,12 @@ CartridgeELF::CartridgeELF(const ByteBuffer& image, size_t size, string_view md5
|
|||
const Settings& settings)
|
||||
: 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);
|
||||
std::memcpy(myImage.get(), image.get(), size);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
#include "ElfParser.hxx"
|
||||
|
||||
class CartridgeELF: public Cartridge {
|
||||
public:
|
||||
|
@ -114,6 +115,8 @@ class CartridgeELF: public Cartridge {
|
|||
|
||||
bool myIsBusDriven{false};
|
||||
uInt8 myDriveBusValue{0};
|
||||
|
||||
ElfParser elfParser;
|
||||
};
|
||||
|
||||
#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
|
|
@ -2,7 +2,7 @@ MODULE := src/emucore
|
|||
|
||||
MODULE_OBJS := \
|
||||
src/emucore/AtariVox.o \
|
||||
src/emucore/Bankswitch.o \
|
||||
src/emucore/Bankswitch.o \
|
||||
src/emucore/Booster.o \
|
||||
src/emucore/Cart.o \
|
||||
src/emucore/CartARM.o \
|
||||
|
|
|
@ -790,6 +790,7 @@
|
|||
<ClCompile Include="..\..\emucore\CartUA.cxx" />
|
||||
<ClCompile Include="..\..\emucore\CartX07.cxx" />
|
||||
<ClCompile Include="..\..\emucore\CartELF.cxx" />
|
||||
<ClCompile Include="..\..\emucore\elf\ElfParser.cxx" />
|
||||
<ClCompile Include="..\..\emucore\Console.cxx" />
|
||||
<ClCompile Include="..\..\emucore\Control.cxx" />
|
||||
<ClCompile Include="..\..\emucore\Driving.cxx" />
|
||||
|
@ -1788,6 +1789,7 @@
|
|||
<ClInclude Include="..\..\emucore\CartUA.hxx" />
|
||||
<ClInclude Include="..\..\emucore\CartX07.hxx" />
|
||||
<ClInclude Include="..\..\emucore\CartELF.hxx" />
|
||||
<ClInclude Include="..\..\emucore\elf\ElfParser.hxx" />
|
||||
<ClInclude Include="..\..\emucore\Console.hxx" />
|
||||
<ClInclude Include="..\..\emucore\Control.hxx" />
|
||||
<ClInclude Include="..\..\emucore\DefProps.hxx" />
|
||||
|
|
|
@ -234,6 +234,9 @@
|
|||
<ClCompile Include="..\..\emucore\CartELF.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\emucore\ElfParser.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\emucore\Console.cxx">
|
||||
<Filter>Source Files\emucore</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1271,6 +1274,9 @@
|
|||
<ClInclude Include="..\..\emucore\CartELF.hxx">
|
||||
<Filter>Header Files\emucore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\emucore\elf\ElfParser.hxx">
|
||||
<Filter>Header Files\emucore</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\emucore\CartAR.hxx">
|
||||
<Filter>Header Files\emucore</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Reference in New Issue