From 09606f873e326b84b0e4e8a78271ca4135668a52 Mon Sep 17 00:00:00 2001 From: James Benton Date: Wed, 23 May 2018 11:10:23 +0100 Subject: [PATCH] tools: Add be_val.h --- tools/common/be_val.h | 419 +++++++++++++++++++++++++++++++++++++ tools/common/elf.h | 141 ++++++------- tools/common/type_traits.h | 22 ++ tools/common/utils.h | 1 + tools/elf2rpl/main.cpp | 126 ++--------- tools/rplgen/rplgen.cpp | 11 +- 6 files changed, 534 insertions(+), 186 deletions(-) create mode 100644 tools/common/be_val.h create mode 100644 tools/common/type_traits.h diff --git a/tools/common/be_val.h b/tools/common/be_val.h new file mode 100644 index 0000000..58262c0 --- /dev/null +++ b/tools/common/be_val.h @@ -0,0 +1,419 @@ +#pragma once +#include "utils.h" +#include "type_traits.h" +#include + +template +class be_val +{ +public: + static_assert(!std::is_array::value, + "be_val invalid type: array"); + + static_assert(!std::is_pointer::value, + "be_val invalid type: pointer"); + + static_assert(sizeof(Type) == 1 || sizeof(Type) == 2 || sizeof(Type) == 4 || sizeof(Type) == 8, + "be_val invalid type size"); + + using value_type = Type; + + be_val() = default; + + be_val(const value_type &value) : + mStorage(byte_swap(value)) + { + } + + value_type value() const + { + return byte_swap(mStorage); + } + + void setValue(value_type value) + { + mStorage = byte_swap(value); + } + + operator value_type() const + { + return value(); + } + + template::value || + std::is_constructible::value + >::type> + explicit operator bool() const + { + return static_cast(value()); + } + + template::value || + std::is_constructible::value || + std::is_convertible::type>::value + >::type> + explicit operator OtherType() const + { + return static_cast(value()); + } + + template::value || + std::is_convertible::value>::type> + be_val & operator =(const OtherType &other) + { + if constexpr (std::is_constructible::value) { + setValue(value_type { other }); + } else { + setValue(static_cast(other)); + } + + return *this; + } + + template::value || + std::is_convertible::value>::type> + be_val & operator =(OtherType &&other) + { + if constexpr (std::is_constructible::value) { + setValue(value_type { std::forward(other) }); + } else { + setValue(static_cast(std::forward(other))); + } + + return *this; + } + + template::value || + std::is_constructible::value>::type> + be_val & operator =(const be_val &other) + { + if constexpr (std::is_constructible::value) { + setValue(value_type { other.value() }); + } else { + setValue(static_cast(other.value())); + } + + return *this; + } + + template::value || + std::is_constructible::value>::type> + be_val & operator =(be_val &&other) + { + if constexpr (std::is_constructible::value) { + setValue(value_type { other.value() }); + } else { + setValue(static_cast(other.value())); + } + + return *this; + } + + template + auto operator ==(const OtherType &other) + -> decltype(std::declval().operator ==(std::declval())) const + { + return value() == other; + } + + template + auto operator !=(const OtherType &other) + -> decltype(std::declval().operator !=(std::declval())) const + { + return value() != other; + } + + template + auto operator >=(const OtherType &other) + -> decltype(std::declval().operator >=(std::declval())) const + { + return value() >= other; + } + + template + auto operator <=(const OtherType &other) + -> decltype(std::declval().operator <=(std::declval())) const + { + return value() <= other; + } + + template + auto operator >(const OtherType &other) + -> decltype(std::declval().operator >(std::declval())) const + { + return value() > other; + } + + template + auto operator <(const OtherType &other) + -> decltype(std::declval().operator <(std::declval())) const + { + return value() < other; + } + + template + auto operator +() + -> decltype(std::declval(). operator+()) const + { + return +value(); + } + + template + auto operator -() + -> decltype(std::declval(). operator-()) const + { + return -value(); + } + + template + auto operator +(const OtherType &other) + -> decltype(std::declval().operator +(std::declval())) const + { + return value() + other; + } + + template + auto operator -(const OtherType &other) + -> decltype(std::declval().operator -(std::declval())) const + { + return value() - other; + } + + template + auto operator *(const OtherType &other) + -> decltype(std::declval().operator *(std::declval())) const + { + return value() * other; + } + + template + auto operator /(const OtherType &other) + -> decltype(std::declval().operator /(std::declval())) const + { + return value() / other; + } + + template + auto operator %(const OtherType &other) + -> decltype(std::declval().operator %(std::declval())) const + { + return value() % other; + } + + template + auto operator |(const OtherType &other) + -> decltype(std::declval().operator |(std::declval())) const + { + return value() | other; + } + + template + auto operator &(const OtherType &other) + -> decltype(std::declval().operator &(std::declval())) const + { + return value() & other; + } + + template + auto operator ^(const OtherType &other) + -> decltype(std::declval().operator ^(std::declval())) const + { + return value() ^ other; + } + + template + auto operator <<(const OtherType &other) + -> decltype(std::declval().operator <<(std::declval())) const + { + return value() << other; + } + + template + auto operator >>(const OtherType &other) + -> decltype(std::declval().operator >>(std::declval())) const + { + return value() >> other; + } + + template() + std::declval())> + be_val &operator +=(const OtherType &other) + { + *this = value() + other; + return *this; + } + + template() - std::declval())> + be_val &operator -=(const OtherType &other) + { + *this = value() - other; + return *this; + } + + template() * std::declval())> + be_val &operator *=(const OtherType &other) + { + *this = value() * other; + return *this; + } + + template() / std::declval())> + be_val &operator /=(const OtherType &other) + { + *this = value() / other; + return *this; + } + + template() % std::declval())> + be_val &operator %=(const OtherType &other) + { + *this = value() % other; + return *this; + } + + template() | std::declval())> + be_val &operator |=(const OtherType &other) + { + *this = static_cast(value() | other); + return *this; + } + + template() & std::declval())> + be_val &operator &=(const OtherType &other) + { + *this = static_cast(value() & other); + return *this; + } + + template() ^ std::declval())> + be_val &operator ^=(const OtherType &other) + { + *this = static_cast(value() ^ other); + return *this; + } + + template() << std::declval())> + be_val &operator <<=(const OtherType &other) + { + *this = value() << other; + return *this; + } + + template() >> std::declval())> + be_val &operator >>=(const OtherType &other) + { + *this = value() >> other; + return *this; + } + + template() + 1)> + be_val &operator ++() + { + setValue(value() + 1); + return *this; + } + + template() + 1)> + be_val operator ++(int) + { + auto before = *this; + setValue(value() + 1); + return before; + } + + template() - 1)> + be_val &operator --() + { + setValue(value() - 1); + return *this; + } + + template() - 1)> + be_val operator --(int) + { + auto before = *this; + setValue(value() - 1); + return before; + } + + template + auto operator [](const IndexType &index) + -> decltype(std::declval().operator [](std::declval())) + { + return value().operator [](index); + } + + template + auto operator ->() + -> decltype(std::declval().operator ->()) + { + return value().operator ->(); + } + + template + auto operator ->() const + -> decltype(std::declval().operator ->()) + { + return value().operator ->(); + } + + template + auto operator *() + -> decltype(std::declval().operator *()) + { + return value().operator *(); + } + + template + auto operator *() const + -> decltype(std::declval().operator *()) + { + return value().operator ->(); + } + + // Helper to access FunctionPointer::getAddress + template + auto getAddress() + -> decltype(std::declval().getAddress()) const + { + return value().getAddress(); + } + + // Helper to access Pointer::getRawPointer + template + auto getRawPointer() + -> decltype(std::declval().getRawPointer()) const + { + return value().getRawPointer(); + } + + // Please use virt_addrof or phys_addrof instead + auto operator &() = delete; + + friend std::ostream &operator<<(std::ostream &os, const be_val &b) { + return os << b.value(); + } + +private: + value_type mStorage; +}; diff --git a/tools/common/elf.h b/tools/common/elf.h index e831413..0cbf7ca 100644 --- a/tools/common/elf.h +++ b/tools/common/elf.h @@ -1,5 +1,6 @@ #pragma once #include +#include "be_val.h" #include "utils.h" #pragma pack(push, 1) @@ -202,67 +203,67 @@ static const unsigned HeaderMagic = 0x7f454c46; struct Header { - uint32_t magic; // File identification. - uint8_t fileClass; // File class. - uint8_t encoding; // Data encoding. - uint8_t elfVersion; // File version. - uint16_t abi; // OS/ABI identification. (EABI_*) - uint8_t pad[7]; + be_val magic; // File identification. + be_val fileClass; // File class. + be_val encoding; // Data encoding. + be_val elfVersion; // File version. + be_val abi; // OS/ABI identification. (EABI_*) + be_val pad[7]; - uint16_t type; // Type of file (ET_*) - uint16_t machine; // Required architecture for this file (EM_*) - uint32_t version; // Must be equal to 1 - uint32_t entry; // Address to jump to in order to start program - uint32_t phoff; // Program header table's file offset, in bytes - uint32_t shoff; // Section header table's file offset, in bytes - uint32_t flags; // Processor-specific flags - uint16_t ehsize; // Size of ELF header, in bytes - uint16_t phentsize; // Size of an entry in the program header table - uint16_t phnum; // Number of entries in the program header table - uint16_t shentsize; // Size of an entry in the section header table - uint16_t shnum; // Number of entries in the section header table - uint16_t shstrndx; // Sect hdr table index of sect name string table + be_val type; // Type of file (ET_*) + be_val machine; // Required architecture for this file (EM_*) + be_val version; // Must be equal to 1 + be_val entry; // Address to jump to in order to start program + be_val phoff; // Program header table's file offset, in bytes + be_val shoff; // Section header table's file offset, in bytes + be_val flags; // Processor-specific flags + be_val ehsize; // Size of ELF header, in bytes + be_val phentsize; // Size of an entry in the program header table + be_val phnum; // Number of entries in the program header table + be_val shentsize; // Size of an entry in the section header table + be_val shnum; // Number of entries in the section header table + be_val shstrndx; // Sect hdr table index of sect name string table }; CHECK_SIZE(Header, 0x34); struct SectionHeader { - uint32_t name; // Section name (index into string table) - uint32_t type; // Section type (SHT_*) - uint32_t flags; // Section flags (SHF_*) - uint32_t addr; // Address where section is to be loaded - uint32_t offset; // File offset of section data, in bytes - uint32_t size; // Size of section, in bytes - uint32_t link; // Section type-specific header table index link - uint32_t info; // Section type-specific extra information - uint32_t addralign; // Section address alignment - uint32_t entsize; // Size of records contained within the section + be_val name; // Section name (index into string table) + be_val type; // Section type (SHT_*) + be_val flags; // Section flags (SHF_*) + be_val addr; // Address where section is to be loaded + be_val offset; // File offset of section data, in bytes + be_val size; // Size of section, in bytes + be_val link; // Section type-specific header table index link + be_val info; // Section type-specific extra information + be_val addralign; // Section address alignment + be_val entsize; // Size of records contained within the section }; CHECK_SIZE(SectionHeader, 0x28); struct Symbol { - uint32_t name; // Symbol name (index into string table) - uint32_t value; // Value or address associated with the symbol - uint32_t size; // Size of the symbol - uint8_t info; // Symbol's type and binding attributes - uint8_t other; // Must be zero; reserved - uint16_t shndx; // Which section (header table index) it's defined in (SHN_*) + be_val name; // Symbol name (index into string table) + be_val value; // Value or address associated with the symbol + be_val size; // Size of the symbol + be_val info; // Symbol's type and binding attributes + be_val other; // Must be zero; reserved + be_val shndx; // Which section (header table index) it's defined in (SHN_*) }; CHECK_SIZE(Symbol, 0x10); struct Rela { - uint32_t offset; - uint32_t info; - int32_t addend; + be_val offset; + be_val info; + be_val addend; }; CHECK_SIZE(Rela, 0x0C); struct RplImport { - uint32_t count; - uint32_t signature; + be_val count; + be_val signature; char name[1]; }; @@ -270,48 +271,48 @@ struct RplExport { struct Export { - uint32_t value; - uint32_t name; + be_val value; + be_val name; }; - uint32_t count; - uint32_t signature; + be_val count; + be_val signature; Export exports[1]; }; struct RplCrc { - uint32_t crc; + be_val crc; }; CHECK_SIZE(RplCrc, 0x04); struct RplFileInfo { - uint32_t version; - uint32_t textSize; - uint32_t textAlign; - uint32_t dataSize; - uint32_t dataAlign; - uint32_t loadSize; - uint32_t loadAlign; - uint32_t tempSize; - uint32_t trampAdjust; - uint32_t sdaBase; - uint32_t sda2Base; - uint32_t stackSize; - uint32_t filename; - uint32_t flags; - uint32_t heapSize; - uint32_t tagOffset; - uint32_t minVersion; - int32_t compressionLevel; - uint32_t trampAddition; - uint32_t fileInfoPad; - uint32_t cafeSdkVersion; - uint32_t cafeSdkRevision; - uint16_t tlsModuleIndex; - uint16_t tlsAlignShift; - uint32_t runtimeFileInfoSize; + be_val version; + be_val textSize; + be_val textAlign; + be_val dataSize; + be_val dataAlign; + be_val loadSize; + be_val loadAlign; + be_val tempSize; + be_val trampAdjust; + be_val sdaBase; + be_val sda2Base; + be_val stackSize; + be_val filename; + be_val flags; + be_val heapSize; + be_val tagOffset; + be_val minVersion; + be_val compressionLevel; + be_val trampAddition; + be_val fileInfoPad; + be_val cafeSdkVersion; + be_val cafeSdkRevision; + be_val tlsModuleIndex; + be_val tlsAlignShift; + be_val runtimeFileInfoSize; }; CHECK_SIZE(RplFileInfo, 0x60); diff --git a/tools/common/type_traits.h b/tools/common/type_traits.h new file mode 100644 index 0000000..34fa7ec --- /dev/null +++ b/tools/common/type_traits.h @@ -0,0 +1,22 @@ +#pragma once +#include + +// Same as std::underlying_type but works for non-enum Types +template::value> +struct safe_underlying_type : std::underlying_type { }; + +template +struct safe_underlying_type +{ + using type = T; +}; + +// Maps bool value to a std::bool_constant type +template +struct is_true; + +template<> +struct is_true : std::false_type { }; + +template<> +struct is_true : std::true_type { }; diff --git a/tools/common/utils.h b/tools/common/utils.h index 817dff3..a20e0e6 100644 --- a/tools/common/utils.h +++ b/tools/common/utils.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include diff --git a/tools/elf2rpl/main.cpp b/tools/elf2rpl/main.cpp index efb9ffb..2c22d45 100644 --- a/tools/elf2rpl/main.cpp +++ b/tools/elf2rpl/main.cpp @@ -27,73 +27,6 @@ struct ElfFile std::vector> sections; }; -static void -byte_swap(elf::Header &header) -{ - header.magic = byte_swap(header.magic); - header.abi = byte_swap(header.abi); - header.type = byte_swap(header.type); - header.machine = byte_swap(header.machine); - header.version = byte_swap(header.version); - header.entry = byte_swap(header.entry); - header.phoff = byte_swap(header.phoff); - header.shoff = byte_swap(header.shoff); - header.flags = byte_swap(header.flags); - header.ehsize = byte_swap(header.ehsize); - header.phentsize = byte_swap(header.phentsize); - header.phnum = byte_swap(header.phnum); - header.shentsize = byte_swap(header.shentsize); - header.shnum = byte_swap(header.shnum); - header.shstrndx = byte_swap(header.shstrndx); -} - - -static void -byte_swap(elf::SectionHeader &header) -{ - header.name = byte_swap(header.name); - header.type = byte_swap(header.type); - header.flags = byte_swap(header.flags); - header.addr = byte_swap(header.addr); - header.offset = byte_swap(header.offset); - header.size = byte_swap(header.size); - header.link = byte_swap(header.link); - header.info = byte_swap(header.info); - header.addralign = byte_swap(header.addralign); - header.entsize = byte_swap(header.entsize); -} - - -static void -byte_swap(elf::RplFileInfo &info) -{ - info.version = byte_swap(info.version); - info.textSize = byte_swap(info.textSize); - info.textAlign = byte_swap(info.textAlign); - info.dataSize = byte_swap(info.dataSize); - info.dataAlign = byte_swap(info.dataAlign); - info.loadSize = byte_swap(info.loadSize); - info.loadAlign = byte_swap(info.loadAlign); - info.tempSize = byte_swap(info.tempSize); - info.trampAdjust = byte_swap(info.trampAdjust); - info.sdaBase = byte_swap(info.sdaBase); - info.sda2Base = byte_swap(info.sda2Base); - info.stackSize = byte_swap(info.stackSize); - info.filename = byte_swap(info.filename); - info.flags = byte_swap(info.flags); - info.heapSize = byte_swap(info.heapSize); - info.tagOffset = byte_swap(info.tagOffset); - info.minVersion = byte_swap(info.minVersion); - info.compressionLevel = byte_swap(info.compressionLevel); - info.trampAddition = byte_swap(info.trampAddition); - info.fileInfoPad = byte_swap(info.fileInfoPad); - info.cafeSdkVersion = byte_swap(info.cafeSdkVersion); - info.cafeSdkRevision = byte_swap(info.cafeSdkRevision); - info.tlsModuleIndex = byte_swap(info.tlsModuleIndex); - info.tlsAlignShift = byte_swap(info.tlsAlignShift); - info.runtimeFileInfoSize = byte_swap(info.runtimeFileInfoSize); -} - static int getSectionIndex(ElfFile &file, const char *name) { @@ -158,7 +91,6 @@ readElf(ElfFile &file, const std::string &filename) // Read header in.read(reinterpret_cast(&file.header), sizeof(elf::Header)); - byte_swap(file.header); if (file.header.magic != elf::HeaderMagic) { fmt::print("Invalid ELF magic header {:08X}", elf::HeaderMagic); @@ -193,7 +125,6 @@ readElf(ElfFile &file, const std::string &filename) auto §ion = *file.sections.back(); in.read(reinterpret_cast(§ion.header), sizeof(elf::SectionHeader)); - byte_swap(section.header); if (!section.header.size || section.header.type == elf::SHT_NOBITS) { continue; @@ -373,9 +304,9 @@ reorderSectionIndex(ElfFile &file) auto symbols = reinterpret_cast(section->data.data()); auto numSymbols = section->data.size() / sizeof(elf::Symbol); for (auto i = 0u; i < numSymbols; ++i) { - auto shndx = byte_swap(symbols[i].shndx); + auto shndx = symbols[i].shndx; if (shndx < elf::SHN_LORESERVE) { - symbols[i].shndx = byte_swap(mapOldToNew[shndx]); + symbols[i].shndx = mapOldToNew[shndx]; } } } @@ -449,8 +380,6 @@ generateFileInfoSection(ElfFile &file) } } - byte_swap(info); - auto section = std::make_unique(); section->header.name = 0; section->header.type = elf::SHT_RPL_FILEINFO; @@ -485,7 +414,7 @@ generateCrcSection(ElfFile &file) crc = crc32(crc, reinterpret_cast(section->data.data()), section->data.size()); } - crcs.push_back(byte_swap(crc)); + crcs.push_back(crc); } auto section = std::make_unique(); @@ -517,12 +446,7 @@ getSymbol(ElfFile::Section §ion, size_t index, elf::Symbol &symbol) return false; } - symbol.name = byte_swap(symbols[index].name); - symbol.value = byte_swap(symbols[index].value); - symbol.size = byte_swap(symbols[index].size); - symbol.info = byte_swap(symbols[index].info); - symbol.other = byte_swap(symbols[index].other); - symbol.shndx = byte_swap(symbols[index].shndx); + symbol = symbols[index]; return true; } @@ -554,9 +478,9 @@ fixRelocations(ElfFile &file) auto rels = reinterpret_cast(section->data.data()); auto numRels = section->data.size() / sizeof(elf::Rela); for (auto i = 0u; i < numRels; ++i) { - auto info = byte_swap(rels[i].info); - auto addend = byte_swap(rels[i].addend); - auto offset = byte_swap(rels[i].offset); + auto info = rels[i].info; + auto addend = rels[i].addend; + auto offset = rels[i].offset; auto index = info >> 8; auto type = info & 0xFF; @@ -595,14 +519,14 @@ fixRelocations(ElfFile &file) auto &newRel = newRelocations.back(); // Modify current relocation to R_PPC_GHS_REL16_LO - rels[i].info = byte_swap((index << 8) | elf::R_PPC_GHS_REL16_LO); - rels[i].addend = byte_swap(addend); - rels[i].offset = byte_swap(offset); + rels[i].info = (index << 8) | elf::R_PPC_GHS_REL16_LO; + rels[i].addend = addend; + rels[i].offset = offset; // Create a R_PPC_GHS_REL16_HI - newRel.info = byte_swap((index << 8) | elf::R_PPC_GHS_REL16_HI); - newRel.addend = byte_swap(addend + 2); - newRel.offset = byte_swap(offset + 2); + newRel.info = (index << 8) | elf::R_PPC_GHS_REL16_HI; + newRel.addend = addend + 2; + newRel.offset = offset + 2; } break; @@ -692,8 +616,8 @@ relocateSection(ElfFile &file, auto symbols = reinterpret_cast(symSection->data.data()); auto numSymbols = symSection->data.size() / sizeof(elf::Symbol); for (auto i = 0u; i < numSymbols; ++i) { - auto type = byte_swap(symbols[i].info) & 0xf; - auto value = byte_swap(symbols[i].value); + auto type = symbols[i].info & 0xf; + auto value = symbols[i].value; // Only relocate data, func, section symbols if (type != elf::STT_OBJECT && @@ -703,7 +627,7 @@ relocateSection(ElfFile &file, } if (value >= oldSectionAddress && value <= oldSectionAddressEnd) { - symbols[i].value = byte_swap((value - oldSectionAddress) + newSectionAddress); + symbols[i].value = (value - oldSectionAddress) + newSectionAddress; } } } @@ -717,10 +641,10 @@ relocateSection(ElfFile &file, auto rela = reinterpret_cast(relaSection->data.data()); auto numRelas = relaSection->data.size() / sizeof(elf::Rela); for (auto i = 0u; i < numRelas; ++i) { - auto offset = byte_swap(rela[i].offset); + auto offset = rela[i].offset; if (offset >= oldSectionAddress && offset <= oldSectionAddressEnd) { - rela[i].offset = byte_swap((offset - oldSectionAddress) + newSectionAddress); + rela[i].offset = (offset - oldSectionAddress) + newSectionAddress; } } } @@ -925,13 +849,6 @@ writeRpl(ElfFile &file, const std::string &filename) { auto shoff = file.header.shoff; - // Swap back file & section header to big endian before writing - byte_swap(file.header); - - for (auto §ion : file.sections) { - byte_swap(section->header); - } - // Write the file out std::ofstream out { filename, std::ofstream::binary }; @@ -953,7 +870,7 @@ writeRpl(ElfFile &file, const std::string &filename) // Write sections for (const auto §ion : file.sections) { if (section->data.size()) { - out.seekp(byte_swap(section->header.offset), std::ios::beg); + out.seekp(section->header.offset, std::ios::beg); out.write(section->data.data(), section->data.size()); } } @@ -979,11 +896,6 @@ int main(int argc, const char **argv) return -1; } - /* - * From here onwards file.header and section.header is in little endian, - * everything else remains in big endian! - */ - if (!fixBssNoBits(elf)) { fmt::print("ERROR: fixBssNoBits failed"); return -1; diff --git a/tools/rplgen/rplgen.cpp b/tools/rplgen/rplgen.cpp index 138fc7c..8431b21 100644 --- a/tools/rplgen/rplgen.cpp +++ b/tools/rplgen/rplgen.cpp @@ -1,3 +1,5 @@ +#include "utils.h" + #include #include #include @@ -34,15 +36,6 @@ trim(std::string &s) rtrim(s); } -uint32_t -byte_swap(uint32_t v) -{ - return ((v >> 24) & 0xff) | - ((v << 8) & 0xff0000) | - ((v >> 8) & 0xff00) | - ((v << 24) & 0xff000000); -} - enum class ReadMode { INVALID,