From 397426de37a5be9a06fe9c854b5966969e05bce5 Mon Sep 17 00:00:00 2001 From: James Benton Date: Mon, 4 Jan 2016 13:17:43 +0000 Subject: [PATCH] Add elf2rpl src. --- Makefile | 14 +- make-tools.bat | 1 + samples/helloworld/Makefile | 2 +- tools/common/be_val.h | 79 +++ tools/common/elf.h | 295 ++++++++ tools/common/utils.h | 119 ++++ tools/elf2rpl/elf2rpl.vcxproj | 167 +++++ tools/elf2rpl/elf2rpl.vcxproj.filters | 33 + tools/elf2rpl/main.cpp | 984 ++++++++++++++++++++++++++ tools/tools.sln | 28 + 10 files changed, 1719 insertions(+), 3 deletions(-) create mode 100755 make-tools.bat create mode 100644 tools/common/be_val.h create mode 100644 tools/common/elf.h create mode 100644 tools/common/utils.h create mode 100644 tools/elf2rpl/elf2rpl.vcxproj create mode 100644 tools/elf2rpl/elf2rpl.vcxproj.filters create mode 100644 tools/elf2rpl/main.cpp create mode 100644 tools/tools.sln diff --git a/Makefile b/Makefile index 70b80f1..b8ef211 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,18 @@ TARGETS := crt rpl all: @for dir in $(TARGETS); do \ echo; \ - echo Entering Directory $$dir; \ + echo "Entering Directory $$dir"; \ $(MAKE) --no-print-directory -C $$dir; \ - echo Leaving Directory $$dir; \ + echo "Leaving Directory $$dir"; \ done +ifeq ($(OS),Windows_NT) + @echo "Please build tools with make-tools.bat" +else + @echo \ + @echo "Entering Directory tools" + @$(MAKE) --no-print-directory -C tools + @echo "Leaving Directory tools" +endif clean: @rm -rf lib @@ -17,10 +25,12 @@ clean: done install: + @mkdir -p bin @mkdir -p lib @for dir in $(TARGETS); do \ echo Installing $$dir; \ $(MAKE) --no-print-directory -C $$dir install; \ done + @cp tools/bin/* bin/ .PHONY: all clean install diff --git a/make-tools.bat b/make-tools.bat new file mode 100755 index 0000000..8063d23 --- /dev/null +++ b/make-tools.bat @@ -0,0 +1 @@ +msbuild tools/tools.sln /p:Configuration=Release diff --git a/samples/helloworld/Makefile b/samples/helloworld/Makefile index a81d712..ec2b79b 100644 --- a/samples/helloworld/Makefile +++ b/samples/helloworld/Makefile @@ -41,7 +41,7 @@ export OFILES := $(CFILES:.c=.o) \ export INCLUDES := $(foreach dir,$(INCLUDE),-I$(CURDIR)/$(dir)) \ -I$(CURDIR)/$(BUILD) -.PHONY: $(BUILD) clean pkg run +.PHONY: $(BUILD) clean $(BUILD): @[ -d $@ ] || mkdir -p $@ diff --git a/tools/common/be_val.h b/tools/common/be_val.h new file mode 100644 index 0000000..a1ae1ea --- /dev/null +++ b/tools/common/be_val.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include "utils.h" + +template +class be_val +{ +public: + static_assert(!std::is_array::value, "be_val invalid type: array"); + static_assert(!std::is_pointer::value, "be_val invalid type: pointer"); + static_assert(sizeof(Type) == 1 || sizeof(Type) == 2 || sizeof(Type) == 4 || sizeof(Type) == 8, "be_val invalid type size"); + + be_val() + { + } + + be_val(Type value) + { + *this = value; + } + + Type value() const + { + return byte_swap(mValue); + } + + operator Type() const + { + return value(); + } + + template std::enable_if_t::value, be_val&> + operator =(const Other &rhs) + { + mValue = byte_swap(static_cast(rhs)); + return *this; + } + + be_val &operator++() { *this = value() + 1; return *this; } + be_val &operator--() { *this = value() - 1; return *this; } + be_val operator--(int) { auto old = *this; *this = value() - 1; return old; } + be_val operator++(int) { auto old = *this; *this = value() + 1; return old; } + + template bool operator == (const Other &rhs) const { return value() == static_cast(rhs); } + template bool operator != (const Other &rhs) const { return value() != static_cast(rhs); } + template bool operator >= (const Other &rhs) const { return value() >= static_cast(rhs); } + template bool operator <= (const Other &rhs) const { return value() <= static_cast(rhs); } + template bool operator > (const Other &rhs) const { return value() > static_cast(rhs); } + template bool operator < (const Other &rhs) const { return value() < static_cast(rhs); } + + template be_val &operator+=(const Other &rhs) { *this = static_cast(value() + rhs); return *this; } + template be_val &operator-=(const Other &rhs) { *this = static_cast(value() - rhs); return *this; } + template be_val &operator*=(const Other &rhs) { *this = static_cast(value() * rhs); return *this; } + template be_val &operator/=(const Other &rhs) { *this = static_cast(value() / rhs); return *this; } + template be_val &operator%=(const Other &rhs) { *this = static_cast(value() % rhs); return *this; } + template be_val &operator|=(const Other &rhs) { *this = static_cast(value() | rhs); return *this; } + template be_val &operator&=(const Other &rhs) { *this = static_cast(value() & rhs); return *this; } + template be_val &operator^=(const Other &rhs) { *this = static_cast(value() ^ rhs); return *this; } + + template Type operator+(const Other &rhs) const { return static_cast(value() + rhs); } + template Type operator-(const Other &rhs) const { return static_cast(value() - rhs); } + template Type operator*(const Other &rhs) const { return static_cast(value() * rhs); } + template Type operator/(const Other &rhs) const { return static_cast(value() / rhs); } + template Type operator%(const Other &rhs) const { return static_cast(value() % rhs); } + template Type operator|(const Other &rhs) const { return static_cast(value() | rhs); } + template Type operator&(const Other &rhs) const { return static_cast(value() & rhs); } + template Type operator^(const Other &rhs) const { return static_cast(value() ^ rhs); } + +protected: + Type mValue {}; +}; + +template +inline std::ostream& +operator<<(std::ostream& os, const be_val& val) +{ + return os << static_cast(val); +} diff --git a/tools/common/elf.h b/tools/common/elf.h new file mode 100644 index 0000000..c7c3dea --- /dev/null +++ b/tools/common/elf.h @@ -0,0 +1,295 @@ +#pragma once +#include +#include "be_val.h" + +#pragma pack(push, 1) + +namespace elf +{ + +enum Machine : uint32_t // e_machine +{ + EM_PPC = 20 // PowerPC +}; + +enum Encoding : uint32_t // e_encoding +{ + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2 +}; + +enum Class : uint32_t // e_class +{ + ELFCLASSNONE = 0, + ELFCLASS32 = 1, + ELFCLASS64 = 2 +}; + +enum Version : uint32_t // e_elf_version +{ + EV_NONE = 0, + EV_CURRENT = 1, +}; + +enum FileType : uint32_t // e_type +{ + ET_NONE = 0, // No file type + ET_REL = 1, // Relocatable file + ET_EXEC = 2, // Executable file + ET_DYN = 3, // Shared object file + ET_CORE = 4, // Core file + ET_LOPROC = 0xff00, // Beginning of processor-specific codes + ET_CAFE_RPL = 0xff01, // Cafe RPL file + ET_HIPROC = 0xffff // Processor-specific +}; + +enum EABI : uint32_t // e_abi +{ + EABI_CAFE = 0xcafe // WiiU CafeOS +}; + +enum SectionFlags : uint32_t // sh_flags +{ + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_DEFLATED = 0x08000000, + SHF_MASKPROC = 0xF0000000, +}; + +enum SectionType : uint32_t // sh_type +{ + SHT_NULL = 0, // No associated section (inactive entry). + SHT_PROGBITS = 1, // Program-defined contents. + SHT_SYMTAB = 2, // Symbol table. + SHT_STRTAB = 3, // String table. + SHT_RELA = 4, // Relocation entries; explicit addends. + SHT_HASH = 5, // Symbol hash table. + SHT_DYNAMIC = 6, // Information for dynamic linking. + SHT_NOTE = 7, // Information about the file. + SHT_NOBITS = 8, // Data occupies no space in the file. + SHT_REL = 9, // Relocation entries; no explicit addends. + SHT_SHLIB = 10, // Reserved. + SHT_DYNSYM = 11, // Symbol table. + SHT_INIT_ARRAY = 14, // Pointers to initialization functions. + SHT_FINI_ARRAY = 15, // Pointers to termination functions. + SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions. + SHT_GROUP = 17, // Section group. + SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries. + SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type. + SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. + SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. + SHT_RPL_EXPORTS = 0x80000001, // RPL Exports + SHT_RPL_IMPORTS = 0x80000002, // RPL Imports + SHT_RPL_CRCS = 0x80000003, // RPL CRCs + SHT_RPL_FILEINFO = 0x80000004,// RPL FileInfo + SHT_HIUSER = 0xffffffff // Highest type reserved for applications. +}; + +enum SymbolBinding : uint32_t // st_info >> 4 +{ + STB_LOCAL = 0, // Local symbol, not visible outside obj file containing def + STB_GLOBAL = 1, // Global symbol, visible to all object files being combined + STB_WEAK = 2, // Weak symbol, like global but lower-precedence + STB_GNU_UNIQUE = 10, + STB_LOOS = 10, // Lowest operating system-specific binding type + STB_HIOS = 12, // Highest operating system-specific binding type + STB_LOPROC = 13, // Lowest processor-specific binding type + STB_HIPROC = 15 // Highest processor-specific binding type +}; + +enum SymbolType : uint32_t // st_info & f +{ + STT_NOTYPE = 0, // Symbol's type is not specified + STT_OBJECT = 1, // Symbol is a data object (variable, array, etc.) + STT_FUNC = 2, // Symbol is executable code (function, etc.) + STT_SECTION = 3, // Symbol refers to a section + STT_FILE = 4, // Local, absolute symbol that refers to a file + STT_COMMON = 5, // An uninitialized common block + STT_TLS = 6, // Thread local data object + STT_LOOS = 7, // Lowest operating system-specific symbol type + STT_HIOS = 8, // Highest operating system-specific symbol type + STT_GNU_IFUNC = 10, // GNU indirect function + STT_LOPROC = 13, // Lowest processor-specific symbol type + STT_HIPROC = 15 // Highest processor-specific symbol type +}; + +enum SectionIndex : uint16_t // st_shndx +{ + SHN_UNDEF = 0, // Undefined + SHN_LORESERVE = 0xff00, // Reserved range + SHN_ABS = 0xfff1, // Absolute symbols + SHN_COMMON = 0xfff2, // Common symbols + SHN_XINDEX = 0xffff, // Escape -- index stored elsewhere + SHN_HIRESERVE = 0xffff +}; + +enum RelocationType : uint32_t // r_info & 0xff +{ + R_PPC_NONE = 0, + R_PPC_ADDR32 = 1, + R_PPC_ADDR24 = 2, + R_PPC_ADDR16 = 3, + R_PPC_ADDR16_LO = 4, + R_PPC_ADDR16_HI = 5, + R_PPC_ADDR16_HA = 6, + R_PPC_ADDR14 = 7, + R_PPC_ADDR14_BRTAKEN = 8, + R_PPC_ADDR14_BRNTAKEN = 9, + R_PPC_REL24 = 10, + R_PPC_REL14 = 11, + R_PPC_REL14_BRTAKEN = 12, + R_PPC_REL14_BRNTAKEN = 13, + R_PPC_GOT16 = 14, + R_PPC_GOT16_LO = 15, + R_PPC_GOT16_HI = 16, + R_PPC_GOT16_HA = 17, + R_PPC_PLTREL24 = 18, + R_PPC_JMP_SLOT = 21, + R_PPC_RELATIVE = 22, + R_PPC_LOCAL24PC = 23, + R_PPC_REL32 = 26, + R_PPC_TLS = 67, + R_PPC_DTPMOD32 = 68, + R_PPC_TPREL16 = 69, + R_PPC_TPREL16_LO = 70, + R_PPC_TPREL16_HI = 71, + R_PPC_TPREL16_HA = 72, + R_PPC_TPREL32 = 73, + R_PPC_DTPREL16 = 74, + R_PPC_DTPREL16_LO = 75, + R_PPC_DTPREL16_HI = 76, + R_PPC_DTPREL16_HA = 77, + R_PPC_DTPREL32 = 78, + R_PPC_GOT_TLSGD16 = 79, + R_PPC_GOT_TLSGD16_LO = 80, + R_PPC_GOT_TLSGD16_HI = 81, + R_PPC_GOT_TLSGD16_HA = 82, + R_PPC_GOT_TLSLD16 = 83, + R_PPC_GOT_TLSLD16_LO = 84, + R_PPC_GOT_TLSLD16_HI = 85, + R_PPC_GOT_TLSLD16_HA = 86, + R_PPC_GOT_TPREL16 = 87, + R_PPC_GOT_TPREL16_LO = 88, + R_PPC_GOT_TPREL16_HI = 89, + R_PPC_GOT_TPREL16_HA = 90, + R_PPC_GOT_DTPREL16 = 91, + R_PPC_GOT_DTPREL16_LO = 92, + R_PPC_GOT_DTPREL16_HI = 93, + R_PPC_GOT_DTPREL16_HA = 94, + R_PPC_TLSGD = 95, + R_PPC_TLSLD = 96, + R_PPC_EMB_SDA21 = 109, + R_PPC_REL16 = 249, + R_PPC_REL16_LO = 250, + R_PPC_REL16_HI = 251, + R_PPC_REL16_HA = 252, +}; + +enum RplFileInfoFlag : uint32_t +{ + RPL_IS_RPX = 0x2, +}; + +struct Header +{ + static const unsigned Magic = 0x7f454c46; + + be_val magic; // File identification. + be_val fileClass; // File class. + be_val encoding; // Data encoding. + be_val elfVersion; // File version. + be_val abi; // OS/ABI identification. (EABI_*) + be_val pad[7]; + + be_val type; // Type of file (ET_*) + be_val machine; // Required architecture for this file (EM_*) + be_val version; // Must be equal to 1 + be_val entry; // Address to jump to in order to start program + be_val phoff; // Program header table's file offset, in bytes + be_val shoff; // Section header table's file offset, in bytes + be_val flags; // Processor-specific flags + be_val ehsize; // Size of ELF header, in bytes + be_val phentsize; // Size of an entry in the program header table + be_val phnum; // Number of entries in the program header table + be_val shentsize; // Size of an entry in the section header table + be_val shnum; // Number of entries in the section header table + be_val shstrndx; // Sect hdr table index of sect name string table +}; +CHECK_SIZE(Header, 0x34); + +struct SectionHeader +{ + be_val name; // Section name (index into string table) + be_val type; // Section type (SHT_*) + be_val flags; // Section flags (SHF_*) + be_val addr; // Address where section is to be loaded + be_val offset; // File offset of section data, in bytes + be_val size; // Size of section, in bytes + be_val link; // Section type-specific header table index link + be_val info; // Section type-specific extra information + be_val addralign; // Section address alignment + be_val entsize; // Size of records contained within the section +}; +CHECK_SIZE(SectionHeader, 0x28); + +struct Symbol +{ + be_val name; // Symbol name (index into string table) + be_val value; // Value or address associated with the symbol + be_val size; // Size of the symbol + be_val info; // Symbol's type and binding attributes + be_val other; // Must be zero; reserved + be_val shndx; // Which section (header table index) it's defined in (SHN_*) +}; +CHECK_SIZE(Symbol, 0x10); + +struct Rela +{ + be_val offset; + be_val info; + be_val addend; +}; +CHECK_SIZE(Rela, 0x0C); + +struct RplImport +{ + be_val importCount; + be_val signature; + char name[1]; +}; + +struct RplFileInfo +{ + be_val version; + be_val textSize; + be_val textAlign; + be_val dataSize; + be_val dataAlign; + be_val loadSize; + be_val loadAlign; + be_val tempSize; + be_val trampAdjust; + be_val sdaBase; + be_val sda2Base; + be_val stackSize; + be_val filename; + be_val flags; + be_val heapSize; + be_val tagOffset; + be_val minVersion; + be_val compressionLevel; + be_val trampAddition; + be_val fileInfoPad; + be_val cafeSdkVersion; + be_val cafeSdkRevision; + be_val tlsModuleIndex; + be_val tlsAlignShift; + be_val runtimeFileInfoSize; +}; +CHECK_SIZE(RplFileInfo, 0x60); + +} // namespace elf + +#pragma pack(pop) diff --git a/tools/common/utils.h b/tools/common/utils.h new file mode 100644 index 0000000..817dff3 --- /dev/null +++ b/tools/common/utils.h @@ -0,0 +1,119 @@ +#pragma once +#include +#include + +#if defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) +#define PLATFORM_WINDOWS +#elif __APPLE__ +#define PLATFORM_APPLE +#define PLATFORM_POSIX +#elif __linux__ +#define PLATFORM_LINUX +#define PLATFORM_POSIX +#endif + +#ifdef PLATFORM_LINUX +#include +#endif + +// reinterpret_cast for value types +template +inline DstType +bit_cast(const SrcType& src) +{ + static_assert(sizeof(SrcType) == sizeof(DstType), "bit_cast must be between same sized types"); + static_assert(std::is_trivially_copyable::value, "SrcType is not trivially copyable."); + static_assert(std::is_trivially_copyable::value, "DstType is not trivially copyable."); + + DstType dst; + std::memcpy(&dst, &src, sizeof(SrcType)); + return dst; +} + +// Utility class to swap endian for types of size 1, 2, 4, 8 +// other type sizes are not supported +template +struct byte_swap_t; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { + return src; + } +}; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { +#ifdef PLATFORM_WINDOWS + return bit_cast(_byteswap_ushort(bit_cast(src))); +#elif defined(PLATFORM_APPLE) + // Apple has no 16-bit byteswap intrinsic + const uint16_t data = bit_cast(src); + return bit_cast((uint16_t)((data >> 8) | (data << 8))); +#elif defined(PLATFORM_LINUX) + return bit_cast(bswap_16(bit_cast(src))); +#endif + } +}; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { +#ifdef PLATFORM_WINDOWS + return bit_cast(_byteswap_ulong(bit_cast(src))); +#elif defined(PLATFORM_APPLE) + return bit_cast(__builtin_bswap32(bit_cast(src))); +#elif defined(PLATFORM_LINUX) + return bit_cast(bswap_32(bit_cast(src))); +#endif + } +}; + +template +struct byte_swap_t +{ + static Type swap(Type src) + { +#ifdef PLATFORM_WINDOWS + return bit_cast(_byteswap_uint64(bit_cast(src))); +#elif defined(PLATFORM_APPLE) + return bit_cast(__builtin_bswap64(bit_cast(src))); +#elif defined(PLATFORM_LINUX) + return bit_cast(bswap_64(bit_cast(src))); +#endif + } +}; + +// Swaps endian of src +template +inline Type +byte_swap(Type src) +{ + return byte_swap_t::swap(src); +} + +// Alignment helpers +template +constexpr inline Type +align_up(Type value, size_t alignment) +{ + return static_cast((static_cast(value) + (alignment - 1)) & ~(alignment - 1)); +} + +template +constexpr inline Type +align_down(Type value, size_t alignment) +{ + return static_cast(static_cast(value) & ~(alignment - 1)); +} + +#define CHECK_SIZE(Type, Size) \ + static_assert(sizeof(Type) == Size, \ + #Type " must be " #Size " bytes") diff --git a/tools/elf2rpl/elf2rpl.vcxproj b/tools/elf2rpl/elf2rpl.vcxproj new file mode 100644 index 0000000..a30e1ab --- /dev/null +++ b/tools/elf2rpl/elf2rpl.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {F6442B08-9323-4D98-ABA6-8856467B148B} + Win32Proj + elf2rpl + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\bin\ + + + true + $(SolutionDir)\bin\ + + + false + $(SolutionDir)\bin\ + + + false + $(SolutionDir)\bin\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + UseLinkTimeCodeGeneration + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + UseLinkTimeCodeGeneration + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + true + No + UseLinkTimeCodeGeneration + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\common;%(AdditionalIncludeDirectories) + + + Console + true + true + No + UseLinkTimeCodeGeneration + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/elf2rpl/elf2rpl.vcxproj.filters b/tools/elf2rpl/elf2rpl.vcxproj.filters new file mode 100644 index 0000000..a770f47 --- /dev/null +++ b/tools/elf2rpl/elf2rpl.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/tools/elf2rpl/main.cpp b/tools/elf2rpl/main.cpp new file mode 100644 index 0000000..a202d23 --- /dev/null +++ b/tools/elf2rpl/main.cpp @@ -0,0 +1,984 @@ +#include +#include +#include +#include +#include +#include +#include +#include "elf.h" + +#pragma pack(push, 1) + +struct RplLibsDef +{ + be_val name; + be_val stubStart; + be_val stubEnd; +}; + +#pragma pack(pop) + +static const uint32_t LoadAddress = 0x01000000; +static const uint32_t CodeAddress = 0x02000000; +static const uint32_t DataAddress = 0x10000000; +static const uint32_t WiiuLoadAddress = 0xC0000000; + +struct ElfFile +{ + struct Symbol + { + std::string name; + uint32_t address; + uint32_t size; + elf::SymbolType type; + elf::SymbolBinding binding; + uint32_t outNamePos; + }; + + struct Relocation + { + uint32_t target; + elf::RelocationType type; + + Symbol *symbol; + uint32_t addend; + }; + + struct DataSection + { + std::string name; + uint32_t address; + elf::SectionType type; + elf::SectionFlags flags; + + // Data used if type == SHT_PROGBITS + std::vector data; + + // Size used if type == SHT_NOBITS + uint32_t size; + }; + + struct RplImport + { + Symbol *trampSymbol; + Symbol *stubSymbol; + uint32_t stubAddr; + uint32_t trampAddr; + }; + + struct RplImportLibrary + { + std::string name; + std::vector> imports; + }; + + uint32_t entryPoint; + std::vector> dataSections; + std::vector> symbols; + std::vector> relocations; + std::vector> rplImports; +}; + +struct InputSection +{ + elf::SectionHeader header; + std::vector data; +}; + +static ElfFile::Symbol * +findSymbol(ElfFile &file, uint32_t address) +{ + for (auto &symbol : file.symbols) { + if (symbol->address == address) { + return symbol.get(); + } + } + + return nullptr; +} + +static ElfFile::RplImport * +findImport(ElfFile &file, uint32_t address) +{ + for (auto &lib : file.rplImports) { + for (auto &import : lib->imports) { + if (import->stubAddr == address || import->trampAddr == address) { + return import.get(); + } + } + } + + return nullptr; +} + +template +static Type * +getLoaderDataPtr(std::vector &inSections, uint32_t address) +{ + for (auto §ion : inSections) { + auto start = section.header.addr; + auto end = start + section.data.size(); + + if (start <= address && end > address) { + auto offset = address - start; + return reinterpret_cast(section.data.data() + offset); + } + } + + return nullptr; +} + +static elf::Symbol * +getSectionSymbol(InputSection §ion, size_t index) +{ + auto symbols = reinterpret_cast(section.data.data()); + return &symbols[index]; +}; + +static bool +read(ElfFile &file, const std::string &filename) +{ + std::ifstream in { filename, std::ifstream::binary }; + std::vector inSections; + + if (!in.is_open()) { + std::cout << "Could not open " << filename << " for reading" << std::endl; + return false; + } + + // Read header + elf::Header header; + in.read(reinterpret_cast(&header), sizeof(elf::Header)); + + if (header.magic != elf::Header::Magic) { + std::cout << "Invalid ELF magic header" << std::endl; + return false; + } + + if (header.fileClass != elf::ELFCLASS32) { + std::cout << "Unexpected ELF file class" << std::endl; + return false; + } + + if (header.encoding != elf::ELFDATA2MSB) { + std::cout << "Unexpected ELF encoding" << std::endl; + return false; + } + + if (header.machine != elf::EM_PPC) { + std::cout << "Unexpected ELF machine type" << std::endl; + return false; + } + + if (header.elfVersion != elf::EV_CURRENT) { + std::cout << "Unexpected ELF version" << std::endl; + return false; + } + + file.entryPoint = header.entry; + + // Read section headers and data + in.seekg(static_cast(header.shoff)); + inSections.resize(header.shnum); + + for (auto §ion : inSections) { + in.read(reinterpret_cast(§ion.header), sizeof(elf::SectionHeader)); + + if (!section.header.size || section.header.type == elf::SHT_NOBITS) { + continue; + } + + auto pos = in.tellg(); + in.seekg(static_cast(section.header.offset)); + section.data.resize(section.header.size); + in.read(section.data.data(), section.data.size()); + in.seekg(pos); + } + + auto shStrTab = inSections[header.shstrndx].data.data(); + + // Process any loader relocations + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_RELA) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".rela.dyn") != 0) { + continue; + } + + auto symSection = inSections[section.header.link]; + auto relas = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Rela); + + for (auto i = 0u; i < count; ++i) { + auto &rela = relas[i]; + auto index = rela.info >> 8; + auto symbol = getSectionSymbol(symSection, index); + auto addr = symbol->value + rela.addend; + + auto type = rela.info & 0xff; + auto ptr = getLoaderDataPtr(inSections, rela.offset); + + if (!ptr) { + std::cout << "Unexpected relocation offset in .rela.dyn section" << std::endl; + return false; + } + + switch (type) { + case elf::R_PPC_RELATIVE: + *ptr = byte_swap(addr); + break; + default: + std::cout << "Unexpected relocation type in .rela.dyn section" << std::endl; + return false; + } + } + } + + // Read text/data sections + for (auto §ion : inSections) { + if (section.header.addr >= LoadAddress && section.header.addr < CodeAddress) { + // Skip any load sections + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (section.header.type == elf::SHT_PROGBITS) { + auto data = new ElfFile::DataSection(); + data->type = elf::SHT_PROGBITS; + data->flags = static_cast(section.header.flags.value()); + data->name = shStrTab + section.header.name; + data->address = section.header.addr; + data->data = section.data; + file.dataSections.emplace_back(data); + } else if (section.header.type == elf::SHT_NOBITS) { + auto bss = new ElfFile::DataSection(); + bss->type = elf::SHT_NOBITS; + bss->flags = static_cast(section.header.flags.value()); + bss->name = shStrTab + section.header.name; + bss->address = section.header.addr; + bss->size = section.header.size; + file.dataSections.emplace_back(bss); + } + } + + // Default symbols + auto symNull = new ElfFile::Symbol(); + symNull->address = 0; + symNull->size = 0; + symNull->type = elf::STT_NOTYPE; + symNull->binding = elf::STB_LOCAL; + file.symbols.emplace_back(symNull); + + auto symText = new ElfFile::Symbol(); + symText->name = "$TEXT"; + symText->address = CodeAddress; + symText->size = 0; + symText->type = elf::STT_SECTION; + symText->binding = elf::STB_LOCAL; + file.symbols.emplace_back(symText); + + auto symData = new ElfFile::Symbol(); + symData->name = "$DATA"; + symData->address = DataAddress; + symData->size = 0; + symData->type = elf::STT_SECTION; + symData->binding = elf::STB_LOCAL; + file.symbols.emplace_back(symData); + + auto symUndef = new ElfFile::Symbol(); + symUndef->name = "$UNDEF"; + symUndef->address = 0; + symUndef->size = 0; + symUndef->type = elf::STT_OBJECT; + symUndef->binding = elf::STB_GLOBAL; + file.symbols.emplace_back(symUndef); + + // Read symbols + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_SYMTAB) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".symtab") != 0) { + std::cout << "Unexpected symbol section " << name << std::endl; + return false; + } + + auto strTab = inSections[section.header.link].data.data(); + auto symTab = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Symbol); + + for (auto i = 0u; i < count; ++i) { + auto &sym = symTab[i]; + + if (sym.value >= LoadAddress && sym.value < CodeAddress) { + // Skip any load symbols + continue; + } + + auto type = static_cast(sym.info & 0xF); + auto binding = static_cast((sym.info >> 4) & 0xF); + + if (type == elf::STT_NOTYPE && sym.value == 0) { + // Skip null symbol + continue; + } + + if (type == elf::STT_FILE || type == elf::STT_SECTION) { + // Skip file, section symbols + continue; + } + + auto symbol = new ElfFile::Symbol(); + symbol->name = strTab + sym.name; + symbol->address = sym.value; + symbol->size = sym.size; + symbol->type = type; + symbol->binding = binding; + file.symbols.emplace_back(symbol); + } + } + + // Read RPL imports + for (auto §ion : inSections) { + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".lib.rplLibs") != 0) { + continue; + } + + auto rplTab = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(RplLibsDef); + + for (auto i = 0u; i < count; ++i) { + auto &rpl = rplTab[i]; + auto lib = new ElfFile::RplImportLibrary(); + lib->name = getLoaderDataPtr(inSections, rpl.name); + + for (auto stubAddr = rpl.stubStart; stubAddr < rpl.stubEnd; stubAddr += 4) { + auto import = new ElfFile::RplImport(); + import->trampAddr = byte_swap(*getLoaderDataPtr(inSections, stubAddr)); + import->stubAddr = stubAddr; + + // Get the tramp symbol + import->trampSymbol = findSymbol(file, import->trampAddr); + + // Create a new symbol to use for the import + auto stubSymbol = new ElfFile::Symbol(); + import->stubSymbol = stubSymbol; + stubSymbol->name = import->trampSymbol->name; + stubSymbol->address = 0; + stubSymbol->size = 0; + stubSymbol->binding = elf::STB_GLOBAL; + stubSymbol->type = elf::STT_FUNC; + file.symbols.emplace_back(stubSymbol); + + // Rename tramp symbol + import->trampSymbol->name += "_tramp"; + + lib->imports.emplace_back(import); + } + + file.rplImports.emplace_back(lib); + } + } + + // Read relocations + for (auto §ion : inSections) { + if (section.header.type != elf::SHT_RELA) { + continue; + } + + auto name = std::string { shStrTab + section.header.name }; + + if (name.compare(".rela.dyn") == 0) { + // Skip dyn relocations + continue; + } + + auto symTab = reinterpret_cast(inSections[section.header.link].data.data()); + auto relTab = reinterpret_cast(section.data.data()); + auto count = section.data.size() / sizeof(elf::Rela); + + for (auto i = 0u; i < count; ++i) { + auto relocation = new ElfFile::Relocation(); + auto &rela = relTab[i]; + + auto type = rela.info & 0xff; + auto index = rela.info >> 8; + auto &sym = symTab[index]; + auto symType = sym.info & 0xf; + + if (symType == elf::STT_NOTYPE && sym.value == 0) { + if (rela.offset < DataAddress) { + std::cout << "Unexpected symbol referenced in relocation section " << name << std::endl; + return false; + } + } else if (symType == elf::STT_SECTION && sym.value == CodeAddress) { + if (rela.offset < CodeAddress || rela.offset >= DataAddress) { + std::cout << "Unexpected symbol referenced in relocation section " << name << std::endl; + return false; + } + } else { + std::cout << "Unexpected symbol referenced in relocation section " << name << std::endl; + return false; + } + + if (auto symbol = findSymbol(file, rela.addend)) { + relocation->symbol = symbol; + relocation->addend = 0; + } else if (auto import = findImport(file, rela.addend)) { + relocation->symbol = import->stubSymbol; + relocation->addend = 0; + } else { + std::cout << "Unexpected addend referenced in relocation section " << name << std::endl; + return false; + } + + relocation->target = rela.offset; + relocation->type = static_cast(type); + file.relocations.emplace_back(relocation); + } + } + + return true; +} + +struct OutputSection +{ + std::string name; + elf::SectionHeader header; + std::vector data; + OutputSection *relocationSection = nullptr; + ElfFile::Symbol *sectionSymbol = nullptr; +}; + +template +SymbolIterator addSection(ElfFile &file, std::vector &outSections, SymbolIterator symbolIterator, OutputSection *section) +{ + auto sectionSymbol = new ElfFile::Symbol(); + sectionSymbol->name = section->name; + sectionSymbol->address = section->header.addr; + sectionSymbol->size = -1; + sectionSymbol->type = elf::STT_SECTION; + sectionSymbol->binding = elf::STB_LOCAL; + section->sectionSymbol = sectionSymbol; + outSections.push_back(section); + return file.symbols.insert(symbolIterator, std::unique_ptr { sectionSymbol }) + 1; +}; + +static uint32_t +getSectionIndex(std::vector &outSections, uint32_t address) +{ + for (auto i = 0u; i < outSections.size(); ++i) { + auto §ion = outSections[i]; + auto start = section->header.addr; + auto end = start + section->header.size; + + if (address >= start && address <= end) { + return i; + } + } + + return -1; +} + +static uint32_t +getSectionIndex(std::vector &outSections, const std::string &name) +{ + for (auto i = 0u; i < outSections.size(); ++i) { + auto §ion = outSections[i]; + + if (section->name.compare(name) == 0) { + return i; + } + } + + return -1; +} + +static bool +write(ElfFile &file, const std::string &filename) +{ + std::vector outSections; + auto sectionSymbolItr = file.symbols.begin() + 4; + + // Create NULL section + auto nullSection = new OutputSection(); + memset(&nullSection->header, 0, sizeof(elf::SectionHeader)); + outSections.push_back(nullSection); + + // Create text/data sections + for (auto §ion : file.dataSections) { + auto out = new OutputSection(); + out->header.name = -1; + out->header.type = elf::SHT_PROGBITS; + out->header.flags = section->flags; + out->header.addr = section->address; + out->header.offset = -1; + + if (section->type == elf::SHT_NOBITS) { + out->header.size = section->size; + } else { + out->header.size = section->data.size(); + } + + out->header.link = 0; + out->header.info = 0; + + if (section->type == elf::SHT_NOBITS) { + out->header.addralign = 256; + } else if (section->address == DataAddress) { + out->header.addralign = 4096; + } else { + out->header.addralign = 32; + } + + out->header.entsize = 0; + + // Add section + out->name = section->name; + out->data = section->data; + sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + } + + // Create relocation sections + for (auto &relocation : file.relocations) { + OutputSection *targetSection = nullptr; + + for (auto §ion : outSections) { + auto start = section->header.addr; + auto end = start + section->header.size; + + if (relocation->target >= start && relocation->target < end) { + targetSection = section; + break; + } + } + + if (!targetSection) { + std::cout << "Error could not find section for relocation" << std::endl; + return false; + } + + if (!targetSection->relocationSection) { + // Create new relocation section + auto out = new OutputSection(); + out->header.name = -1; + out->header.type = elf::SHT_RELA; + out->header.flags = 0; + out->header.addr = 0; + out->header.offset = -1; + out->header.size = -1; + out->header.link = -1; + out->header.info = getSectionIndex(outSections, targetSection->header.addr); + out->header.addralign = 4; + out->header.entsize = sizeof(elf::Rela); + + // Add section + out->name = ".rela" + targetSection->name; + sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + targetSection->relocationSection = out; + } + } + + // Create RPL import sections, .fimport_*, .dimport_* + auto loadAddress = 0xC0000000; + + for (auto &lib : file.rplImports) { + auto out = new OutputSection(); + out->header.name = 0; // TODO: Section names + out->header.type = elf::SHT_RPL_IMPORTS; + out->header.flags = elf::SHF_ALLOC | elf::SHF_EXECINSTR; + out->header.addr = loadAddress; + out->header.offset = 0; // TODO: Data offset in file + out->header.link = 0; + out->header.info = 0; + out->header.addralign = 4; + out->header.entsize = 0; + out->name = ".fimport_" + lib->name; + + // Calculate size + auto nameSize = align_up(8 + lib->name.size(), 8); + auto stubSize = 8 + 8 * lib->imports.size(); + out->header.size = std::max(nameSize, stubSize); + out->data.resize(out->header.size); + + // Setup data + auto imports = reinterpret_cast(out->data.data()); + imports->importCount = lib->imports.size(); + imports->signature = 0; // TODO: SHT_RPL_IMPORTS Signature + memcpy(imports->name, lib->name.data(), lib->name.size()); + imports->name[lib->name.size()] = 0; + + // Update address of import symbols + for (auto i = 0u; i < lib->imports.size(); ++i) { + lib->imports[i]->stubSymbol->address = loadAddress + 8 + i * 8; + } + + loadAddress = align_up(loadAddress + out->header.size, 4); + + // Add section + sectionSymbolItr = addSection(file, outSections, sectionSymbolItr, out); + } + + // NOTICE: FROM NOW ON DO NOT MODIFY mSymbols + + // Convert relocations + for (auto &relocation : file.relocations) { + OutputSection *targetSection = nullptr; + + for (auto §ion : outSections) { + auto start = section->header.addr; + auto end = start + section->header.size; + + if (relocation->target >= start && relocation->target < end) { + targetSection = section; + break; + } + } + + if (!targetSection || !targetSection->relocationSection) { + std::cout << "Error could not find section for relocation" << std::endl; + return false; + } + + // Get address of relocation->target + auto relocationSection = targetSection->relocationSection; + + // Find symbol this relocation points to + auto itr = std::find_if(file.symbols.begin(), file.symbols.end(), [&relocation](auto &val) { + return val.get() == relocation->symbol; + }); + + if (itr == file.symbols.end()) { + std::cout << "Could not find matching symbol for relocation" << std::endl; + return false; + } + + auto idx = itr - file.symbols.begin(); + + // Create relocation + elf::Rela rela; + rela.info = relocation->type | idx << 8; + rela.addend = relocation->addend; + rela.offset = relocation->target; + + // Append to relocation section data + char *relaData = reinterpret_cast(&rela); + relocationSection->data.insert(relocationSection->data.end(), relaData, relaData + sizeof(elf::Rela)); + } + + // String + Symbol sections + auto symTabSection = new OutputSection(); + auto strTabSection = new OutputSection(); + auto shStrTabSection = new OutputSection(); + + symTabSection->name = ".symtab"; + strTabSection->name = ".strtab"; + shStrTabSection->name = ".shstrtab"; + + auto symTabIndex = outSections.size(); + outSections.push_back(symTabSection); + + auto strTabIndex = outSections.size(); + outSections.push_back(strTabSection); + + auto shStrTabIndex = outSections.size(); + outSections.push_back(shStrTabSection); + + // Update relocation sections to link to symtab + for (auto §ion : outSections) { + if (section->header.type == elf::SHT_RELA) { + section->header.link = symTabIndex; + } + + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (section->sectionSymbol) { + section->sectionSymbol->address = section->header.addr; + section->sectionSymbol->size = section->header.size; + } + } + + // Create .strtab + strTabSection->header.name = 0; + strTabSection->header.type = elf::SHT_STRTAB; + strTabSection->header.flags = elf::SHF_ALLOC; + strTabSection->header.addr = 0; + strTabSection->header.offset = -1; + strTabSection->header.size = -1; + strTabSection->header.link = 0; + strTabSection->header.info = 0; + strTabSection->header.addralign = 1; + strTabSection->header.entsize = 0; + + // Add all symbol names to data, update symbol->outNamePos + strTabSection->data.push_back(0); + + for (auto &symbol : file.symbols) { + if (symbol->name.empty()) { + symbol->outNamePos = 0; + } else { + symbol->outNamePos = static_cast(strTabSection->data.size()); + std::copy(symbol->name.begin(), symbol->name.end(), std::back_inserter(strTabSection->data)); + strTabSection->data.push_back(0); + } + } + + // Create .symtab + symTabSection->header.name = 0; + symTabSection->header.type = elf::SHT_SYMTAB; + symTabSection->header.flags = elf::SHF_ALLOC; + symTabSection->header.addr = 0; + symTabSection->header.offset = -1; + symTabSection->header.size = -1; + symTabSection->header.link = strTabIndex; + symTabSection->header.info = 0; + symTabSection->header.addralign = 4; + symTabSection->header.entsize = sizeof(elf::Symbol); + + for (auto &symbol : file.symbols) { + elf::Symbol sym; + auto shndx = getSectionIndex(outSections, symbol->address); + + if (symbol->type == elf::STT_SECTION && symbol->address == 0) { + shndx = getSectionIndex(outSections, symbol->name); + } + + if (shndx == -1) { + std::cout << "Could not find section for symbol" << std::endl; + return false; + } + + sym.name = symbol->outNamePos; + sym.value = symbol->address; + sym.size = symbol->size; + sym.info = symbol->type | (symbol->binding << 4); + sym.other = 0; + sym.shndx = shndx; + + // Append to symtab data + char *symData = reinterpret_cast(&sym); + symTabSection->data.insert(symTabSection->data.end(), symData, symData + sizeof(elf::Symbol)); + } + + // Create .shstrtab + shStrTabSection->header.name = 0; + shStrTabSection->header.type = elf::SHT_STRTAB; + shStrTabSection->header.flags = elf::SHF_ALLOC; + shStrTabSection->header.addr = 0; + shStrTabSection->header.offset = -1; + shStrTabSection->header.size = -1; + shStrTabSection->header.link = 0; + shStrTabSection->header.info = 0; + shStrTabSection->header.addralign = 1; + shStrTabSection->header.entsize = 0; + + // Add all section header names to data, update section->header.name + shStrTabSection->data.push_back(0); + + for (auto §ion : outSections) { + if (section->name.empty()) { + section->header.name = 0; + } else { + section->header.name = shStrTabSection->data.size(); + std::copy(section->name.begin(), section->name.end(), std::back_inserter(shStrTabSection->data)); + shStrTabSection->data.push_back(0); + } + } + + // Update symtab, strtab, shstrtab section addresses + symTabSection->header.addr = loadAddress; + symTabSection->header.size = symTabSection->data.size(); + + loadAddress = align_up(symTabSection->header.addr + symTabSection->header.size, 4); + strTabSection->header.addr = loadAddress; + strTabSection->header.size = strTabSection->data.size(); + + loadAddress = align_up(strTabSection->header.addr + strTabSection->header.size, 4); + shStrTabSection->header.addr = loadAddress; + shStrTabSection->header.size = shStrTabSection->data.size(); + + // Create SHT_RPL_FILEINFO section + auto fileInfoSection = new OutputSection(); + fileInfoSection->header.name = 0; + fileInfoSection->header.type = elf::SHT_RPL_FILEINFO; + fileInfoSection->header.flags = 0; + fileInfoSection->header.addr = 0; + fileInfoSection->header.offset = -1; + fileInfoSection->header.size = -1; + fileInfoSection->header.link = 0; + fileInfoSection->header.info = 0; + fileInfoSection->header.addralign = 4; + fileInfoSection->header.entsize = 0; + + elf::RplFileInfo fileInfo; + fileInfo.version = 0xCAFE0402; + fileInfo.textSize = 0; // TODO: Sum of text sections (with align) + fileInfo.textAlign = 32; + fileInfo.dataSize = 0; // TODO: Sum of data sections (with align) + fileInfo.dataAlign = 4096; + fileInfo.loadSize = 0; // TODO: Sum of load sections (with align) + fileInfo.loadAlign = 4; + fileInfo.tempSize = 0; // TODO: Figure out what to do with temp size + fileInfo.trampAdjust = 0; + fileInfo.trampAddition = 0; + fileInfo.sdaBase = 0; + fileInfo.sda2Base = 0; + fileInfo.stackSize = 0x10000; + fileInfo.heapSize = 0x8000; + fileInfo.filename = 0; + fileInfo.flags = elf::RPL_IS_RPX; + fileInfo.minVersion = 0x5078; + fileInfo.compressionLevel = -1; + fileInfo.fileInfoPad = 0; + fileInfo.cafeSdkVersion = 0x51BA; + fileInfo.cafeSdkRevision = 0xCCD1; + fileInfo.tlsAlignShift = 0; + fileInfo.tlsModuleIndex = 0; + fileInfo.runtimeFileInfoSize = 0; + fileInfo.tagOffset = 0; + + char *fileInfoData = reinterpret_cast(&fileInfo); + fileInfoSection->data.insert(fileInfoSection->data.end(), fileInfoData, fileInfoData + sizeof(elf::RplFileInfo)); + + // Create SHT_RPL_CRCS section + auto crcSection = new OutputSection(); + crcSection->header.name = 0; + crcSection->header.type = elf::SHT_RPL_CRCS; + crcSection->header.flags = 0; + crcSection->header.addr = 0; + crcSection->header.offset = -1; + crcSection->header.size = -1; + crcSection->header.link = 0; + crcSection->header.info = 0; + crcSection->header.addralign = 4; + crcSection->header.entsize = 4; + + outSections.push_back(crcSection); + outSections.push_back(fileInfoSection); + + std::vector sectionCRCs; + + for (auto §ion : outSections) { + auto crc = 0u; + + if (!section->data.empty()) { + // TODO: Calculate crc of section->data + crc = 0xBEEFB00B; + } + + sectionCRCs.push_back(crc); + } + + char *crcData = reinterpret_cast(sectionCRCs.data()); + crcSection->data.insert(crcSection->data.end(), crcData, crcData + sizeof(uint32_t) * sectionCRCs.size()); + + // Update section sizes and offsets + auto shoff = align_up(sizeof(elf::Header), 64); + auto dataOffset = align_up(shoff + outSections.size() * sizeof(elf::SectionHeader), 64); + + for (auto §ion : outSections) { + if (section->header.type != elf::SHT_NOBITS) { + section->header.size = section->data.size(); + } + + if (!section->data.empty()) { + section->header.offset = dataOffset; + dataOffset = align_up(section->header.offset + section->data.size(), 64); + } else { + section->header.offset = 0; + } + } + + // Write to file + std::ofstream out { filename, std::ofstream::binary }; + std::vector padding; + + auto padFileToOffset = [&out, &padding](auto offset) { + auto pos = static_cast(out.tellp()); + + if (pos < offset) { + padding.resize(offset - pos, 0); + out.write(padding.data(), padding.size()); + } else if (pos > offset) { + throw std::logic_error("You dumb person"); + } + }; + + if (!out.is_open()) { + std::cout << "Could not open " << filename << " for writing" << std::endl; + return false; + } + + elf::Header header; + header.magic = elf::Header::Magic; + header.fileClass = 1; + header.encoding = elf::ELFDATA2MSB; + header.elfVersion = elf::EV_CURRENT; + header.abi = elf::EABI_CAFE; + memset(&header.pad, 0, 7); + header.type = 0xFE01; + header.machine = elf::EM_PPC; + header.version = 1; + header.entry = file.entryPoint; + header.phoff = 0; + header.phentsize = 0; + header.phnum = 0; + header.shoff = shoff; + header.shnum = outSections.size(); + header.shentsize = sizeof(elf::SectionHeader); + header.flags = 0; + header.ehsize = sizeof(elf::Header); + header.shstrndx = shStrTabIndex; + out.write(reinterpret_cast(&header), sizeof(elf::Header)); + + // Write section headers + padFileToOffset(header.shoff); + + for (auto §ion : outSections) { + out.write(reinterpret_cast(§ion->header), sizeof(elf::SectionHeader)); + } + + // Write section data + for (auto §ion : outSections) { + if (!section->data.empty()) { + padFileToOffset(section->header.offset); + out.write(section->data.data(), section->data.size()); + } + } + + return true; +} + +int main(int argc, char **argv) +{ + if (argc < 3) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + ElfFile elf; + auto src = argv[1]; + auto dst = argv[2]; + + if (!read(elf, src)) { + return -1; + } + + if (!write(elf, dst)) { + return -1; + } + + return 0; +} diff --git a/tools/tools.sln b/tools/tools.sln new file mode 100644 index 0000000..8f9a7c5 --- /dev/null +++ b/tools/tools.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "elf2rpl", "elf2rpl\elf2rpl.vcxproj", "{F6442B08-9323-4D98-ABA6-8856467B148B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F6442B08-9323-4D98-ABA6-8856467B148B}.Debug|x64.ActiveCfg = Debug|x64 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Debug|x64.Build.0 = Debug|x64 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Debug|x86.ActiveCfg = Debug|Win32 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Debug|x86.Build.0 = Debug|Win32 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Release|x64.ActiveCfg = Release|x64 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Release|x64.Build.0 = Release|x64 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Release|x86.ActiveCfg = Release|Win32 + {F6442B08-9323-4D98-ABA6-8856467B148B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal