mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
Wii U: elf2rpl rewritten in C89
elf2rpl, the host tool that turns the linked Wii U ELF into an RPL, is now a single C89 file, os/wiiu/wut/elf2rpl/main.c, in place of the C++ sources, their own ELF header, CRC-32 and endian helpers, and the Visual Studio project files. Big-endian fields go through retro_endianness.h; the byte swap the old be_val.h picked by PLATFORM_WINDOWS/PLATFORM_APPLE/PLATFORM_LINUX is gone with it, along with those defines - it did not build on any other host and swapped wrongly on a big-endian one. Section CRCs and import signatures come from libretro-common's encoding_crc32 instead of the bundled bytewise table. The input is read once and its sections used where they lie; symbol and import lookups by address are hash tables; the output is laid out in one buffer and written with one call. On a 7 MB core ELF with 41k relocations the RPL comes out byte for byte as before, and so does the log at every -v level, in about a quarter of the time (15 ms against 52 ms; 47 ms against 104 ms at -v -v -v -v). Malformed input now ends in an error instead of a crash: header, section, symbol and relocation offsets are checked against the file, a stub with no symbol behind it is reported, and an unknown option is refused rather than taken for the input file. The tool is built with the host C compiler (HOST_CC, gcc by default), which an exported devkitPPC CC no longer reaches. samples/frontend/wiiu_elf2rpl builds the C tool and adds checks that every section's SHT_RPL_CRCS entry is the zlib CRC-32 of its contents, and that truncated ELFs and an unknown option fail cleanly; it no longer needs the leak and alignment sanitizer exemptions the C++ tool did.
This commit is contained in:
1 parent
d164f9ab0b
commit
3c0c49e3ce
14 files changed
+2398
-2598
No files matched your search
@@ -126,6 +126,7 @@ shaders/shaders_slang
|
||||
*.rpx
|
||||
*.last
|
||||
os/wiiu/wut/elf2rpl/elf2rpl
|
||||
os/wiiu/wut/elf2rpl/elf2rpl.exe
|
||||
/pkg/wiiu/retroarch
|
||||
/pkg/wiiu/wiiu
|
||||
/pkg/wiiu/rpx
|
||||
|
||||
+1
-1
@@ -365,7 +365,7 @@ $(BUILD_DIR)/%.o: %.s %.depend
|
||||
%.depend: ;
|
||||
%.last: ;
|
||||
|
||||
$(ELF2RPL): os/wiiu/wut/elf2rpl/main.cpp os/wiiu/wut/elf2rpl/elf.h
|
||||
$(ELF2RPL): os/wiiu/wut/elf2rpl/main.c os/wiiu/wut/elf2rpl/Makefile
|
||||
@$(if $(Q), echo MAKE $@,)
|
||||
$(Q)$(MAKE) -C os/wiiu/wut/elf2rpl/
|
||||
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
# elf2rpl runs on the build host, so it is built with the host's C
|
||||
# compiler (HOST_CC=... to pick another), never the devkitPPC one.
|
||||
TARGET := elf2rpl
|
||||
|
||||
CXX := g++
|
||||
LD := g++
|
||||
LIBRETRO_COMM_DIR := ../../../../libretro-common
|
||||
|
||||
OBJS := main.o
|
||||
INCLUDES := -I.
|
||||
HOST_CC ?= gcc
|
||||
|
||||
CFLAGS := -O3 -Wall -std=c++14 -DNDEBUG
|
||||
SOURCES := main.c \
|
||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
|
||||
$(LIBRETRO_COMM_DIR)/features/features_cpu.c \
|
||||
$(LIBRETRO_COMM_DIR)/time/rtime.c
|
||||
|
||||
CFLAGS := -O2 -Wall -std=gnu89 -DNDEBUG -I$(LIBRETRO_COMM_DIR)/include
|
||||
LDFLAGS :=
|
||||
|
||||
ifneq ($(findstring Linux,$(shell uname -a)),)
|
||||
@@ -18,10 +23,9 @@ endif
|
||||
all: $(TARGET)
|
||||
|
||||
clean:
|
||||
@rm -rf $(TARGET) $(OBJS)
|
||||
@rm -f $(TARGET)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -o $@ $< $(CFLAGS) $(INCLUDES)
|
||||
$(TARGET): $(SOURCES)
|
||||
$(HOST_CC) $(CFLAGS) -o $@ $(SOURCES) $(LDFLAGS)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(LD) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
.PHONY: all clean
|
||||
@@ -1,72 +0,0 @@
|
||||
#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 {};
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
/* Self-contained CRC-32 (IEEE 802.3, poly 0xEDB88320) for elf2rpl.
|
||||
*
|
||||
* Provides a drop-in replacement for the single zlib symbol this tool
|
||||
* used (crc32), so elf2rpl no longer depends on zlib at all. The
|
||||
* seed-and-accumulate contract matches zlib exactly:
|
||||
*
|
||||
* crc = crc32(0, NULL, 0); // seed
|
||||
* crc = crc32(crc, buf, len); // accumulate
|
||||
*
|
||||
* Output is bit-identical to zlib's crc32() for these inputs.
|
||||
*/
|
||||
#ifndef ELF2RPL_CRC32_H
|
||||
#define ELF2RPL_CRC32_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned long uLong;
|
||||
typedef unsigned char Bytef;
|
||||
typedef unsigned int uInt;
|
||||
|
||||
#ifndef Z_NULL
|
||||
#define Z_NULL 0
|
||||
#endif
|
||||
|
||||
static uLong crc32(uLong crc, const Bytef *buf, uInt len)
|
||||
{
|
||||
static uLong table[256];
|
||||
static int have_table = 0;
|
||||
|
||||
if (!have_table)
|
||||
{
|
||||
uLong c;
|
||||
int n, k;
|
||||
for (n = 0; n < 256; n++)
|
||||
{
|
||||
c = (uLong)n;
|
||||
for (k = 0; k < 8; k++)
|
||||
c = (c & 1) ? (0xEDB88320UL ^ (c >> 1)) : (c >> 1);
|
||||
table[n] = c;
|
||||
}
|
||||
have_table = 1;
|
||||
}
|
||||
|
||||
if (!buf)
|
||||
return 0UL;
|
||||
|
||||
crc = crc ^ 0xFFFFFFFFUL;
|
||||
while (len--)
|
||||
crc = table[(crc ^ *buf++) & 0xFF] ^ (crc >> 8);
|
||||
return crc ^ 0xFFFFFFFFUL;
|
||||
}
|
||||
|
||||
#endif /* ELF2RPL_CRC32_H */
|
||||
@@ -1,314 +0,0 @@
|
||||
#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,
|
||||
};
|
||||
|
||||
static const unsigned HeaderMagic = 0x7f454c46;
|
||||
|
||||
struct Header
|
||||
{
|
||||
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> count;
|
||||
be_val<uint32_t> signature;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct RplExport
|
||||
{
|
||||
struct Export
|
||||
{
|
||||
be_val<uint32_t> value;
|
||||
be_val<uint32_t> name;
|
||||
};
|
||||
|
||||
be_val<uint32_t> count;
|
||||
be_val<uint32_t> signature;
|
||||
Export exports[1];
|
||||
};
|
||||
|
||||
struct RplCrc
|
||||
{
|
||||
be_val<uint32_t> crc;
|
||||
};
|
||||
CHECK_SIZE(RplCrc, 0x04);
|
||||
|
||||
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)
|
||||
@@ -1,172 +0,0 @@
|
||||
<?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>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
</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="crc32.h" />
|
||||
<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>
|
||||
@@ -1,36 +0,0 @@
|
||||
<?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="crc32.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<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>
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,119 +0,0 @@
|
||||
#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")
|
||||
@@ -1,3 +1,4 @@
|
||||
/wiiu_elf2rpl_tool
|
||||
/wiiu_elf2rpl_in.tmp
|
||||
/wiiu_elf2rpl_out.tmp
|
||||
/wiiu_elf2rpl_trunc.tmp
|
||||
@@ -1,28 +1,29 @@
|
||||
# os/wiiu/wut/elf2rpl, the host tool that turns the linked Wii U ELF
|
||||
# into an RPL, run on a linked ELF the test writes itself in the shape
|
||||
# a -pie link gives it. No PowerPC toolchain is needed. Builds for Linux
|
||||
# and, with CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
|
||||
# EXE=.exe RUNNER=wine, for Windows.
|
||||
# a -pie link gives it, then on truncated copies of it. No PowerPC
|
||||
# toolchain is needed. Builds for Linux and, with
|
||||
# CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine, for Windows.
|
||||
TARGET := wiiu_elf2rpl_test$(EXE)
|
||||
TOOL := wiiu_elf2rpl_tool$(EXE)
|
||||
CORE_DIR := ../../..
|
||||
ELF2RPL := $(CORE_DIR)/os/wiiu/wut/elf2rpl
|
||||
LIBRETRO_COMM_DIR := $(CORE_DIR)/libretro-common
|
||||
|
||||
# The tool and the libretro-common units it links, as its own Makefile
|
||||
# lists them
|
||||
TOOL_SOURCES := $(ELF2RPL)/main.c \
|
||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
|
||||
$(LIBRETRO_COMM_DIR)/features/features_cpu.c \
|
||||
$(LIBRETRO_COMM_DIR)/time/rtime.c
|
||||
|
||||
CXX ?= g++
|
||||
CFLAGS += -std=c89 -Wall -g1 -O1 -DELF2RPL='"$(if $(EXE),,./)$(TOOL)"'
|
||||
TFLAGS := -O2 -std=c++14 -I$(ELF2RPL) -Wno-class-memaccess
|
||||
TFLAGS := -std=gnu89 -Wall -g1 -O2 -I$(LIBRETRO_COMM_DIR)/include
|
||||
|
||||
ifneq ($(SANITIZER),)
|
||||
CFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)
|
||||
LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)
|
||||
TFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(TFLAGS)
|
||||
# The tool reads and writes ELF headers through packed big-endian
|
||||
# fields, and keeps its section graph to exit, as a one-shot tool
|
||||
# may; its other undefined behaviour and memory errors still show.
|
||||
ifneq ($(findstring undefined,$(SANITIZER)),)
|
||||
TFLAGS += -fno-sanitize=alignment
|
||||
endif
|
||||
CFLAGS += -DELF2RPL_ENV='"ASAN_OPTIONS=detect_leaks=0 "'
|
||||
TFLAGS := -fsanitize=$(SANITIZER) -fno-sanitize-recover=all \
|
||||
-fno-omit-frame-pointer $(TFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(EXE),.exe)
|
||||
@@ -31,8 +32,8 @@ endif
|
||||
|
||||
all: $(TARGET) $(TOOL)
|
||||
|
||||
$(TOOL): $(ELF2RPL)/main.cpp
|
||||
$(CXX) $(TFLAGS) -o $@ $<
|
||||
$(TOOL): $(TOOL_SOURCES)
|
||||
$(CC) $(TFLAGS) -o $@ $(TOOL_SOURCES)
|
||||
|
||||
$(TARGET): wiiu_elf2rpl_test.c
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||
@@ -43,6 +44,7 @@ check: all
|
||||
clean:
|
||||
rm -f wiiu_elf2rpl_test wiiu_elf2rpl_test.exe \
|
||||
wiiu_elf2rpl_tool wiiu_elf2rpl_tool.exe \
|
||||
wiiu_elf2rpl_in.tmp wiiu_elf2rpl_out.tmp
|
||||
wiiu_elf2rpl_in.tmp wiiu_elf2rpl_out.tmp \
|
||||
wiiu_elf2rpl_trunc.tmp
|
||||
|
||||
.PHONY: all check clean
|
||||
@@ -9,21 +9,26 @@
|
||||
* symbol - the Cafe OS loader cannot resolve one, and a 24-bit branch
|
||||
* to address zero is out of reach from the code area - while every
|
||||
* relocation against a resolved target survives, and the instruction
|
||||
* the link wrote at the weak branch is left as it was. */
|
||||
* the link wrote at the weak branch is left as it was.
|
||||
*
|
||||
* Every section's entry in SHT_RPL_CRCS must be the zlib CRC-32 of its
|
||||
* contents, which the loader checks; and a truncated ELF, or an option
|
||||
* the tool does not know, must end in its error, not a crash. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifndef ELF2RPL
|
||||
#define ELF2RPL "./wiiu_elf2rpl_tool"
|
||||
#endif
|
||||
#ifndef ELF2RPL_ENV
|
||||
#define ELF2RPL_ENV ""
|
||||
#endif
|
||||
|
||||
#define IN_PATH "wiiu_elf2rpl_in.tmp"
|
||||
#define OUT_PATH "wiiu_elf2rpl_out.tmp"
|
||||
#define IN_PATH "wiiu_elf2rpl_in.tmp"
|
||||
#define OUT_PATH "wiiu_elf2rpl_out.tmp"
|
||||
#define TRUNC_PATH "wiiu_elf2rpl_trunc.tmp"
|
||||
|
||||
#define CODE 0x02000000u
|
||||
#define DATA 0x10000000u
|
||||
@@ -233,13 +238,75 @@ static unsigned char *read_all(const char *path, long *len)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* zlib's CRC-32, a bit at a time, to check the tool's against */
|
||||
static unsigned long crc32_ref(const unsigned char *p, unsigned long n)
|
||||
{
|
||||
unsigned long crc = 0xFFFFFFFFul;
|
||||
while (n--)
|
||||
{
|
||||
int k;
|
||||
crc ^= *p++;
|
||||
for (k = 0; k < 8; k++)
|
||||
crc = (crc >> 1) ^ (0xEDB88320ul & (0ul - (crc & 1ul)));
|
||||
}
|
||||
return crc ^ 0xFFFFFFFFul;
|
||||
}
|
||||
|
||||
/* The tool gave up with its own error (exit -1), rather than crashing
|
||||
* or being stopped by a sanitizer. */
|
||||
static int failed_cleanly(int rc)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return rc == -1 || rc == 255;
|
||||
#else
|
||||
return rc != -1 && WIFEXITED(rc) && WEXITSTATUS(rc) == 255;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int bad_input_rejected(const unsigned char *elf, long elf_len)
|
||||
{
|
||||
static const long cuts[] = { 0, 4, 20, 51, 52, 60, 200, 400, 1000, -1 };
|
||||
char cmd[256];
|
||||
int ok = 1, c;
|
||||
|
||||
for (c = 0; cuts[c] >= 0; c++)
|
||||
{
|
||||
long cut = cuts[c] < elf_len ? cuts[c] : elf_len - 1;
|
||||
FILE *f = fopen(TRUNC_PATH, "wb");
|
||||
int rc;
|
||||
if (!f)
|
||||
return 0;
|
||||
if (cut && fwrite(elf, 1, (size_t)cut, f) != (size_t)cut)
|
||||
ok = 0;
|
||||
fclose(f);
|
||||
sprintf(cmd, "%s %s %s", ELF2RPL, TRUNC_PATH, OUT_PATH);
|
||||
rc = system(cmd);
|
||||
if (!failed_cleanly(rc))
|
||||
{
|
||||
fprintf(stderr, "ELF cut to %ld bytes: elf2rpl returned %d\n", cut, rc);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
remove(TRUNC_PATH);
|
||||
remove(OUT_PATH);
|
||||
|
||||
sprintf(cmd, "%s -x %s %s", ELF2RPL, IN_PATH, OUT_PATH);
|
||||
if (!failed_cleanly(system(cmd)))
|
||||
{
|
||||
fprintf(stderr, "elf2rpl took an unknown option\n");
|
||||
ok = 0;
|
||||
}
|
||||
remove(OUT_PATH);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned char *rpl;
|
||||
long len = 0;
|
||||
unsigned long shoff;
|
||||
unsigned char *rpl, *elf;
|
||||
long len = 0, elf_len = 0;
|
||||
unsigned long shoff, crc_off = 0, crc_count = 0;
|
||||
unsigned shnum, i;
|
||||
int kept = 0, undef = 0, rel24 = 0, branch_ok = 0;
|
||||
int kept = 0, undef = 0, rel24 = 0, branch_ok = 0, crc_bad = 0;
|
||||
char cmd[256];
|
||||
|
||||
if (!write_input())
|
||||
@@ -247,7 +314,7 @@ int main(void)
|
||||
fprintf(stderr, "FAIL could not write %s\n", IN_PATH);
|
||||
return 1;
|
||||
}
|
||||
sprintf(cmd, "%s%s %s %s", ELF2RPL_ENV, ELF2RPL, IN_PATH, OUT_PATH);
|
||||
sprintf(cmd, "%s %s %s", ELF2RPL, IN_PATH, OUT_PATH);
|
||||
remove(OUT_PATH);
|
||||
CHECK(system(cmd) == 0);
|
||||
if (!(rpl = read_all(OUT_PATH, &len)))
|
||||
@@ -268,6 +335,12 @@ int main(void)
|
||||
unsigned long sh_size = get32(sh + 20);
|
||||
unsigned long sh_link = get32(sh + 24);
|
||||
|
||||
if (type == 0x80000003ul)
|
||||
{
|
||||
crc_off = sh_off;
|
||||
crc_count = sh_size / 4;
|
||||
}
|
||||
|
||||
/* The weak branch the link wrote, still as it was. */
|
||||
if (type == 1 && sh_addr == CODE && sh_size >= 12)
|
||||
branch_ok = get32(rpl + sh_off + 8) == 0x48000000ul;
|
||||
@@ -301,7 +374,32 @@ int main(void)
|
||||
CHECK(kept == 3); /* table@ha, table@l and &main survive */
|
||||
CHECK(branch_ok);
|
||||
|
||||
/* One CRC per section, its own and empty ones zero */
|
||||
CHECK(crc_count == shnum);
|
||||
for (i = 0; i < shnum && crc_count == shnum; i++)
|
||||
{
|
||||
const unsigned char *sh = rpl + shoff + (unsigned long)i * 40;
|
||||
unsigned long type = get32(sh + 4);
|
||||
unsigned long size = get32(sh + 20);
|
||||
unsigned long want = (type == 0x80000003ul || type == 8 || !size)
|
||||
? 0 : crc32_ref(rpl + get32(sh + 16), size);
|
||||
if (get32(rpl + crc_off + i * 4) != want)
|
||||
{
|
||||
fprintf(stderr, "section %u CRC %08lx, want %08lx\n", i,
|
||||
get32(rpl + crc_off + i * 4), want);
|
||||
crc_bad++;
|
||||
}
|
||||
}
|
||||
CHECK(crc_bad == 0);
|
||||
free(rpl);
|
||||
|
||||
CHECK((elf = read_all(IN_PATH, &elf_len)) != NULL);
|
||||
if (elf)
|
||||
{
|
||||
CHECK(bad_input_rejected(elf, elf_len));
|
||||
free(elf);
|
||||
}
|
||||
|
||||
remove(IN_PATH);
|
||||
remove(OUT_PATH);
|
||||
if (failures)
|
||||
|
||||
Reference in new issue
Block a user