Add elf2rpl src.

This commit is contained in:
James Benton 2016-01-04 13:17:43 +00:00
parent a582c9b61f
commit 397426de37
10 changed files with 1719 additions and 3 deletions

View File

@ -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
View File

@ -0,0 +1 @@
msbuild tools/tools.sln /p:Configuration=Release

View File

@ -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
View 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
View 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
View 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")

View 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>

View 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
View 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 &section : 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 &section, 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 &section : inSections) {
in.read(reinterpret_cast<char *>(&section.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 &section : 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 &section : 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 &section : 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 &section : 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 &section : 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 &section = 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 &section = 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 &section : 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 &section : 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 &section : 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 &section : 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 &section : 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 &section : 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 &section : 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 &section : outSections) {
out.write(reinterpret_cast<char *>(&section->header), sizeof(elf::SectionHeader));
}
// Write section data
for (auto &section : 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
View 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