mirror of
https://github.com/wiiu-env/wut.git
synced 2025-01-05 21:18:15 +01:00
Add elf2rpl src.
This commit is contained in:
parent
a582c9b61f
commit
397426de37
14
Makefile
14
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
|
||||
|
1
make-tools.bat
Executable file
1
make-tools.bat
Executable file
@ -0,0 +1 @@
|
||||
msbuild tools/tools.sln /p:Configuration=Release
|
@ -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 $@
|
||||
|
79
tools/common/be_val.h
Normal file
79
tools/common/be_val.h
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
#include "utils.h"
|
||||
|
||||
template<typename Type>
|
||||
class be_val
|
||||
{
|
||||
public:
|
||||
static_assert(!std::is_array<Type>::value, "be_val invalid type: array");
|
||||
static_assert(!std::is_pointer<Type>::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<typename Other> std::enable_if_t<std::is_assignable<Type&, Other>::value, be_val&>
|
||||
operator =(const Other &rhs)
|
||||
{
|
||||
mValue = byte_swap(static_cast<Type>(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<typename Other> bool operator == (const Other &rhs) const { return value() == static_cast<Type>(rhs); }
|
||||
template<typename Other> bool operator != (const Other &rhs) const { return value() != static_cast<Type>(rhs); }
|
||||
template<typename Other> bool operator >= (const Other &rhs) const { return value() >= static_cast<Type>(rhs); }
|
||||
template<typename Other> bool operator <= (const Other &rhs) const { return value() <= static_cast<Type>(rhs); }
|
||||
template<typename Other> bool operator > (const Other &rhs) const { return value() > static_cast<Type>(rhs); }
|
||||
template<typename Other> bool operator < (const Other &rhs) const { return value() < static_cast<Type>(rhs); }
|
||||
|
||||
template<typename Other> be_val &operator+=(const Other &rhs) { *this = static_cast<Type>(value() + rhs); return *this; }
|
||||
template<typename Other> be_val &operator-=(const Other &rhs) { *this = static_cast<Type>(value() - rhs); return *this; }
|
||||
template<typename Other> be_val &operator*=(const Other &rhs) { *this = static_cast<Type>(value() * rhs); return *this; }
|
||||
template<typename Other> be_val &operator/=(const Other &rhs) { *this = static_cast<Type>(value() / rhs); return *this; }
|
||||
template<typename Other> be_val &operator%=(const Other &rhs) { *this = static_cast<Type>(value() % rhs); return *this; }
|
||||
template<typename Other> be_val &operator|=(const Other &rhs) { *this = static_cast<Type>(value() | rhs); return *this; }
|
||||
template<typename Other> be_val &operator&=(const Other &rhs) { *this = static_cast<Type>(value() & rhs); return *this; }
|
||||
template<typename Other> be_val &operator^=(const Other &rhs) { *this = static_cast<Type>(value() ^ rhs); return *this; }
|
||||
|
||||
template<typename Other> Type operator+(const Other &rhs) const { return static_cast<Type>(value() + rhs); }
|
||||
template<typename Other> Type operator-(const Other &rhs) const { return static_cast<Type>(value() - rhs); }
|
||||
template<typename Other> Type operator*(const Other &rhs) const { return static_cast<Type>(value() * rhs); }
|
||||
template<typename Other> Type operator/(const Other &rhs) const { return static_cast<Type>(value() / rhs); }
|
||||
template<typename Other> Type operator%(const Other &rhs) const { return static_cast<Type>(value() % rhs); }
|
||||
template<typename Other> Type operator|(const Other &rhs) const { return static_cast<Type>(value() | rhs); }
|
||||
template<typename Other> Type operator&(const Other &rhs) const { return static_cast<Type>(value() & rhs); }
|
||||
template<typename Other> Type operator^(const Other &rhs) const { return static_cast<Type>(value() ^ rhs); }
|
||||
|
||||
protected:
|
||||
Type mValue {};
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const be_val<Type>& val)
|
||||
{
|
||||
return os << static_cast<Type>(val);
|
||||
}
|
295
tools/common/elf.h
Normal file
295
tools/common/elf.h
Normal file
@ -0,0 +1,295 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#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<uint32_t> magic; // File identification.
|
||||
be_val<uint8_t> fileClass; // File class.
|
||||
be_val<uint8_t> encoding; // Data encoding.
|
||||
be_val<uint8_t> elfVersion; // File version.
|
||||
be_val<uint16_t> abi; // OS/ABI identification. (EABI_*)
|
||||
be_val<uint8_t> pad[7];
|
||||
|
||||
be_val<uint16_t> type; // Type of file (ET_*)
|
||||
be_val<uint16_t> machine; // Required architecture for this file (EM_*)
|
||||
be_val<uint32_t> version; // Must be equal to 1
|
||||
be_val<uint32_t> entry; // Address to jump to in order to start program
|
||||
be_val<uint32_t> phoff; // Program header table's file offset, in bytes
|
||||
be_val<uint32_t> shoff; // Section header table's file offset, in bytes
|
||||
be_val<uint32_t> flags; // Processor-specific flags
|
||||
be_val<uint16_t> ehsize; // Size of ELF header, in bytes
|
||||
be_val<uint16_t> phentsize; // Size of an entry in the program header table
|
||||
be_val<uint16_t> phnum; // Number of entries in the program header table
|
||||
be_val<uint16_t> shentsize; // Size of an entry in the section header table
|
||||
be_val<uint16_t> shnum; // Number of entries in the section header table
|
||||
be_val<uint16_t> shstrndx; // Sect hdr table index of sect name string table
|
||||
};
|
||||
CHECK_SIZE(Header, 0x34);
|
||||
|
||||
struct SectionHeader
|
||||
{
|
||||
be_val<uint32_t> name; // Section name (index into string table)
|
||||
be_val<uint32_t> type; // Section type (SHT_*)
|
||||
be_val<uint32_t> flags; // Section flags (SHF_*)
|
||||
be_val<uint32_t> addr; // Address where section is to be loaded
|
||||
be_val<uint32_t> offset; // File offset of section data, in bytes
|
||||
be_val<uint32_t> size; // Size of section, in bytes
|
||||
be_val<uint32_t> link; // Section type-specific header table index link
|
||||
be_val<uint32_t> info; // Section type-specific extra information
|
||||
be_val<uint32_t> addralign; // Section address alignment
|
||||
be_val<uint32_t> entsize; // Size of records contained within the section
|
||||
};
|
||||
CHECK_SIZE(SectionHeader, 0x28);
|
||||
|
||||
struct Symbol
|
||||
{
|
||||
be_val<uint32_t> name; // Symbol name (index into string table)
|
||||
be_val<uint32_t> value; // Value or address associated with the symbol
|
||||
be_val<uint32_t> size; // Size of the symbol
|
||||
be_val<uint8_t> info; // Symbol's type and binding attributes
|
||||
be_val<uint8_t> other; // Must be zero; reserved
|
||||
be_val<uint16_t> shndx; // Which section (header table index) it's defined in (SHN_*)
|
||||
};
|
||||
CHECK_SIZE(Symbol, 0x10);
|
||||
|
||||
struct Rela
|
||||
{
|
||||
be_val<uint32_t> offset;
|
||||
be_val<uint32_t> info;
|
||||
be_val<int32_t> addend;
|
||||
};
|
||||
CHECK_SIZE(Rela, 0x0C);
|
||||
|
||||
struct RplImport
|
||||
{
|
||||
be_val<uint32_t> importCount;
|
||||
be_val<uint32_t> signature;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct RplFileInfo
|
||||
{
|
||||
be_val<uint32_t> version;
|
||||
be_val<uint32_t> textSize;
|
||||
be_val<uint32_t> textAlign;
|
||||
be_val<uint32_t> dataSize;
|
||||
be_val<uint32_t> dataAlign;
|
||||
be_val<uint32_t> loadSize;
|
||||
be_val<uint32_t> loadAlign;
|
||||
be_val<uint32_t> tempSize;
|
||||
be_val<uint32_t> trampAdjust;
|
||||
be_val<uint32_t> sdaBase;
|
||||
be_val<uint32_t> sda2Base;
|
||||
be_val<uint32_t> stackSize;
|
||||
be_val<uint32_t> filename;
|
||||
be_val<uint32_t> flags;
|
||||
be_val<uint32_t> heapSize;
|
||||
be_val<uint32_t> tagOffset;
|
||||
be_val<uint32_t> minVersion;
|
||||
be_val<int32_t> compressionLevel;
|
||||
be_val<uint32_t> trampAddition;
|
||||
be_val<uint32_t> fileInfoPad;
|
||||
be_val<uint32_t> cafeSdkVersion;
|
||||
be_val<uint32_t> cafeSdkRevision;
|
||||
be_val<uint16_t> tlsModuleIndex;
|
||||
be_val<uint16_t> tlsAlignShift;
|
||||
be_val<uint32_t> runtimeFileInfoSize;
|
||||
};
|
||||
CHECK_SIZE(RplFileInfo, 0x60);
|
||||
|
||||
} // namespace elf
|
||||
|
||||
#pragma pack(pop)
|
119
tools/common/utils.h
Normal file
119
tools/common/utils.h
Normal file
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
#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 <byteswap.h>
|
||||
#endif
|
||||
|
||||
// reinterpret_cast for value types
|
||||
template<typename DstType, typename SrcType>
|
||||
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<SrcType>::value, "SrcType is not trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable<DstType>::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<typename Type, unsigned Size = sizeof(Type)>
|
||||
struct byte_swap_t;
|
||||
|
||||
template<typename Type>
|
||||
struct byte_swap_t<Type, 1>
|
||||
{
|
||||
static Type swap(Type src)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct byte_swap_t<Type, 2>
|
||||
{
|
||||
static Type swap(Type src)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
return bit_cast<Type>(_byteswap_ushort(bit_cast<uint16_t>(src)));
|
||||
#elif defined(PLATFORM_APPLE)
|
||||
// Apple has no 16-bit byteswap intrinsic
|
||||
const uint16_t data = bit_cast<uint16_t>(src);
|
||||
return bit_cast<Type>((uint16_t)((data >> 8) | (data << 8)));
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
return bit_cast<Type>(bswap_16(bit_cast<uint16_t>(src)));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct byte_swap_t<Type, 4>
|
||||
{
|
||||
static Type swap(Type src)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
return bit_cast<Type>(_byteswap_ulong(bit_cast<uint32_t>(src)));
|
||||
#elif defined(PLATFORM_APPLE)
|
||||
return bit_cast<Type>(__builtin_bswap32(bit_cast<uint32_t>(src)));
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
return bit_cast<Type>(bswap_32(bit_cast<uint32_t>(src)));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct byte_swap_t<Type, 8>
|
||||
{
|
||||
static Type swap(Type src)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
return bit_cast<Type>(_byteswap_uint64(bit_cast<uint64_t>(src)));
|
||||
#elif defined(PLATFORM_APPLE)
|
||||
return bit_cast<Type>(__builtin_bswap64(bit_cast<uint64_t>(src)));
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
return bit_cast<Type>(bswap_64(bit_cast<uint64_t>(src)));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// Swaps endian of src
|
||||
template<typename Type>
|
||||
inline Type
|
||||
byte_swap(Type src)
|
||||
{
|
||||
return byte_swap_t<Type>::swap(src);
|
||||
}
|
||||
|
||||
// Alignment helpers
|
||||
template<typename Type>
|
||||
constexpr inline Type
|
||||
align_up(Type value, size_t alignment)
|
||||
{
|
||||
return static_cast<Type>((static_cast<size_t>(value) + (alignment - 1)) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
constexpr inline Type
|
||||
align_down(Type value, size_t alignment)
|
||||
{
|
||||
return static_cast<Type>(static_cast<size_t>(value) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
#define CHECK_SIZE(Type, Size) \
|
||||
static_assert(sizeof(Type) == Size, \
|
||||
#Type " must be " #Size " bytes")
|
167
tools/elf2rpl/elf2rpl.vcxproj
Normal file
167
tools/elf2rpl/elf2rpl.vcxproj
Normal file
@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F6442B08-9323-4D98-ABA6-8856467B148B}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>elf2rpl</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>No</GenerateDebugInformation>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>No</GenerateDebugInformation>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\be_val.h" />
|
||||
<ClInclude Include="..\common\elf.h" />
|
||||
<ClInclude Include="..\common\utils.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
33
tools/elf2rpl/elf2rpl.vcxproj.filters
Normal file
33
tools/elf2rpl/elf2rpl.vcxproj.filters
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\be_val.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\elf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
984
tools/elf2rpl/main.cpp
Normal file
984
tools/elf2rpl/main.cpp
Normal file
@ -0,0 +1,984 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "elf.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct RplLibsDef
|
||||
{
|
||||
be_val<uint32_t> name;
|
||||
be_val<uint32_t> stubStart;
|
||||
be_val<uint32_t> 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<char> 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<std::unique_ptr<RplImport>> imports;
|
||||
};
|
||||
|
||||
uint32_t entryPoint;
|
||||
std::vector<std::unique_ptr<DataSection>> dataSections;
|
||||
std::vector<std::unique_ptr<Symbol>> symbols;
|
||||
std::vector<std::unique_ptr<Relocation>> relocations;
|
||||
std::vector<std::unique_ptr<RplImportLibrary>> rplImports;
|
||||
};
|
||||
|
||||
struct InputSection
|
||||
{
|
||||
elf::SectionHeader header;
|
||||
std::vector<char> 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<typename Type>
|
||||
static Type *
|
||||
getLoaderDataPtr(std::vector<InputSection> &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<Type *>(section.data.data() + offset);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static elf::Symbol *
|
||||
getSectionSymbol(InputSection §ion, size_t index)
|
||||
{
|
||||
auto symbols = reinterpret_cast<elf::Symbol *>(section.data.data());
|
||||
return &symbols[index];
|
||||
};
|
||||
|
||||
static bool
|
||||
read(ElfFile &file, const std::string &filename)
|
||||
{
|
||||
std::ifstream in { filename, std::ifstream::binary };
|
||||
std::vector<InputSection> 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<char *>(&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<size_t>(header.shoff));
|
||||
inSections.resize(header.shnum);
|
||||
|
||||
for (auto §ion : inSections) {
|
||||
in.read(reinterpret_cast<char *>(§ion.header), sizeof(elf::SectionHeader));
|
||||
|
||||
if (!section.header.size || section.header.type == elf::SHT_NOBITS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pos = in.tellg();
|
||||
in.seekg(static_cast<size_t>(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<elf::Rela *>(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<uint32_t>(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<elf::SectionFlags>(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<elf::SectionFlags>(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<elf::Symbol *>(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<elf::SymbolType>(sym.info & 0xF);
|
||||
auto binding = static_cast<elf::SymbolBinding>((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<RplLibsDef *>(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<char>(inSections, rpl.name);
|
||||
|
||||
for (auto stubAddr = rpl.stubStart; stubAddr < rpl.stubEnd; stubAddr += 4) {
|
||||
auto import = new ElfFile::RplImport();
|
||||
import->trampAddr = byte_swap(*getLoaderDataPtr<uint32_t>(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<elf::Symbol *>(inSections[section.header.link].data.data());
|
||||
auto relTab = reinterpret_cast<elf::Rela *>(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<elf::RelocationType>(type);
|
||||
file.relocations.emplace_back(relocation);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct OutputSection
|
||||
{
|
||||
std::string name;
|
||||
elf::SectionHeader header;
|
||||
std::vector<char> data;
|
||||
OutputSection *relocationSection = nullptr;
|
||||
ElfFile::Symbol *sectionSymbol = nullptr;
|
||||
};
|
||||
|
||||
template<typename SymbolIterator>
|
||||
SymbolIterator addSection(ElfFile &file, std::vector<OutputSection *> &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<ElfFile::Symbol> { sectionSymbol }) + 1;
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
getSectionIndex(std::vector<OutputSection *> &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<OutputSection *> &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<OutputSection *> 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<elf::RplImport*>(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<char *>(&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<uint32_t>(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<char *>(&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<char *>(&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<uint32_t> 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<char *>(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<char> padding;
|
||||
|
||||
auto padFileToOffset = [&out, &padding](auto offset) {
|
||||
auto pos = static_cast<size_t>(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<char *>(&header), sizeof(elf::Header));
|
||||
|
||||
// Write section headers
|
||||
padFileToOffset(header.shoff);
|
||||
|
||||
for (auto §ion : outSections) {
|
||||
out.write(reinterpret_cast<char *>(§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] << " <src> <dst>" << 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;
|
||||
}
|
28
tools/tools.sln
Normal file
28
tools/tools.sln
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user