diff --git a/.gitmodules b/.gitmodules index 61e5bcddd..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +0,0 @@ -[submodule "tools/libraries/fmt"] - path = tools/libraries/fmt - url = https://github.com/fmtlib/fmt.git -[submodule "tools/libraries/excmd"] - path = tools/libraries/excmd - url = https://github.com/exjam/excmd.git -[submodule "tools/libraries/zlib"] - path = tools/libraries/zlib - url = https://github.com/madler/zlib.git diff --git a/.travis.yml b/.travis.yml index bd35ec338..3253c2398 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,9 @@ language: cpp matrix: include: - os: linux + dist: xenial sudo: required - dist: trusty - env: DEPLOY_FILE=wut.linux64.7z - - os: osx - osx_image: xcode9.3 - env: DEPLOY_FILE=wut.macos.7z + env: DEPLOY_FILE=wut.7z addons: apt: @@ -16,28 +13,21 @@ addons: - ubuntu-toolchain-r-test - sourceline: 'ppa:cginternals/backports-ppa' packages: - - gcc-7 - - g++-7 - - zlib1g-dev - p7zip-full cache: directories: - "$HOME/.local" + - "/opt/devkitpro" git: submodules: true install: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 90; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 90; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb -O /tmp/devkitpro-pacman.deb; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo dpkg -i /tmp/devkitpro-pacman.deb; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install p7zip; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman-installer.pkg -O /tmp/devkitpro-pacman-installer.pkg; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sudo installer -pkg /tmp/devkitpro-pacman-installer.pkg -target /; fi - - yes | sudo dkp-pacman -Syu devkitPPC + - wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb -O /tmp/devkitpro-pacman.deb + - sudo dpkg -i /tmp/devkitpro-pacman.deb + - yes | sudo dkp-pacman -Syu devkitPPC wut-tools + - export DEVKITPRO=/opt/devkitpro - export DEVKITPPC=/opt/devkitpro/devkitPPC script: @@ -48,7 +38,6 @@ script: - make -j4 install - export WUT_ROOT=$PWD/wut_install - cd ../ - - chmod +x $WUT_ROOT/bin/elf2rpl # Build tests - cd tests - mkdir build && cd build @@ -73,5 +62,5 @@ deploy: file_glob: true file: $WUT_ROOT/$DEPLOY_FILE on: - repo: decaf-emu/wut + repo: devkitPro/wut tags: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 853d2d366..27b298d51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,10 @@ cmake_minimum_required(VERSION 3.2) -project(wut) -include(ExternalProject) +set(WUT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") +set(ENV{WUT_ROOT} "${WUT_ROOT}") +set(CMAKE_TOOLCHAIN_FILE "${WUT_ROOT}/share/wut.toolchain.cmake") +project(wut) option(WUT_BUILD_DOCS "Build documentation" OFF) -option(WUT_BUILD_TOOLS "Build tools" ON) -option(WUT_BUILD_PPC "Build PPC code using devkitPPC" ON) - -set(WUT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) -set(WUT_STAGING "${CMAKE_BINARY_DIR}/staging") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/lib") @@ -25,39 +22,13 @@ if(WUT_BUILD_DOCS) add_subdirectory(docs) endif() -if(WUT_BUILD_TOOLS) - add_subdirectory(tools) +find_program(WUT_RPLIMPORTGEN NAMES rplimportgen PATHS "${DEVKITPRO}/tools/bin") +if(NOT WUT_RPLIMPORTGEN) + message(FATAL_ERROR "Could not find rplimportgen.") endif() -if(WUT_BUILD_PPC) - if(NOT WUT_BUILD_TOOLS) - message(FATAL_ERROR "WUT_BUILD_PPC requires WUT_BUILD_TOOLS.") - endif() - - set(WUT_TOOLCHAIN "${CMAKE_CURRENT_SOURCE_DIR}/share/wut.toolchain.cmake") - - externalproject_add(cafe - SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cafe" - CMAKE_GENERATOR "Unix Makefiles" - INSTALL_DIR "${WUT_STAGING}" - CMAKE_CACHE_ARGS - -DWUT_ROOT:filepath=${WUT_ROOT} - -DWUT_RPLIMPORTGEN:filepath=$ - -DCMAKE_TOOLCHAIN_FILE:filepath=${WUT_TOOLCHAIN} - -DCMAKE_INSTALL_PREFIX:string= - DEPENDS rplimportgen - BUILD_ALWAYS 1) - - externalproject_add(libraries - SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries" - CMAKE_GENERATOR "Unix Makefiles" - INSTALL_DIR "${WUT_STAGING}" - CMAKE_CACHE_ARGS - -DWUT_ROOT:filepath=${WUT_ROOT} - -DCMAKE_TOOLCHAIN_FILE:filepath=${WUT_TOOLCHAIN} - -DCMAKE_INSTALL_PREFIX:string= - BUILD_ALWAYS 1) -endif() +add_subdirectory(cafe) +add_subdirectory(libraries) install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/" DESTINATION "${CMAKE_INSTALL_PREFIX}/include" @@ -65,6 +36,3 @@ install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/" install(DIRECTORY "${CMAKE_SOURCE_DIR}/share/" DESTINATION "${CMAKE_INSTALL_PREFIX}/share") - -install(DIRECTORY "${CMAKE_BINARY_DIR}/staging/" - DESTINATION "${CMAKE_INSTALL_PREFIX}") diff --git a/README.md b/README.md index 5e70238d7..324a4ed72 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/decaf-emu/wut.svg?branch=rewrite)](https://travis-ci.org/decaf-emu/wut) +[![Build Status](https://travis-ci.org/devkitPro/wut.svg?branch=rewrite)](https://travis-ci.org/devkitPro/wut) # wut Let's try make a Wii U Toolchain / SDK for creating rpx/rpl. @@ -7,11 +7,11 @@ Licensed under the terms of the GNU General Public License, version 2 or later ( ## Install -Grab the latest [release](https://github.com/decaf-emu/wut/releases) extract to a folder, then export that folder as WUT_ROOT. +Grab the latest [release](https://github.com/devkitPro/wut/releases) extract to a folder, then export that folder as WUT_ROOT. For example: ``` -wget https://github.com/decaf-emu/wut/releases/download/1.0.0-alpha/wut.linux64.7z +wget https://github.com/devkitPro/wut/releases/download/1.0.0-alpha/wut.linux64.7z mkdir wut && cd wut 7z x ../wut.linux64.7z export WUT_ROOT=$PWD @@ -51,41 +51,20 @@ make ## Building Requires: -- A modern compiler with C++14/17 support - CMake -- zlib -- [devkitPPC r31+](https://devkitpro.org/wiki/Getting_Started) +- [devkitPro](https://devkitpro.org/wiki/Getting_Started) -### Building on Windows -If you are using devkitPro then you can build wut using the provided msys2 environment: +### Building with devkitPro +Ensure you have the devkitPPC and wut-tools packages from [devkitPro](https://devkitpro.org/wiki/Getting_Started): ``` -export PATH=$PATH:/opt/devkitpro/devkitPPC/bin +sudo dkp-pacman -Syu devkitPPC wut-tools +export DEVKITPRO=/opt/devkitpro export DEVKITPPC=/opt/devkitpro/devkitPPC -pacman -S gcc cmake zlib-devel -git clone --recursive https://github.com/decaf-emu/wut.git -cd wut -mkdir build && cd build -cmake -DCMAKE_INSTALL_PREFIX=/opt/wut ../ -make install -export WUT_ROOT=/opt/wut -``` - -Or use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10) and then follow the Linux instructions after preparing your environment. - -For example, if you installed Ubuntu 18.04 then you might setup your environment like: - -``` -sudo apt install cmake zlib1g-dev gcc g++ build-essential -wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb -sudo dpkg -i devkitpro-pacman.deb -sudo ln -s /proc/mounts /etc/mtab -sudo dkp-pacman -S devkitPPC wiiload ``` -### Building on Linux / MacOS +Then you can build wut like any other CMake project: ``` -export DEVKITPPC=/opt/devkitpro/devkitPPC -git clone --recursive https://github.com/decaf-emu/wut.git +git clone --recursive https://github.com/devkitPro/wut.git cd wut mkdir build && cd build cmake -DCMAKE_INSTALL_PREFIX= ../ @@ -94,10 +73,19 @@ export WUT_ROOT= ``` Then for any wut project you want to build you must use the wut.toolchain.cmake script: - ``` cd ../samples/helloworld mkdir build && cd build cmake -DCMAKE_TOOLCHAIN_FILE=$WUT_ROOT/share/wut.toolchain.cmake ../ make ``` + +### Building with a locally built wut-tools +If you have locally built wut-tools then just add the directory containing the built binaries to PATH and they should be used instead: +``` +export PATH=/path/to/wut-tools/bin:$PATH +cd wut +mkdir build && cd build +cmake ../ +make +``` diff --git a/share/wut.toolchain.cmake b/share/wut.toolchain.cmake index 6aebf02bc..d537ab1ee 100644 --- a/share/wut.toolchain.cmake +++ b/share/wut.toolchain.cmake @@ -5,7 +5,18 @@ set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_SYSTEM_PROCESSOR "ppc") set(CMAKE_CROSSCOMPILING 1) -find_program(DEVKITPPC_GCC NAMES powerpc-eabi-gcc) +# Find DEVKITPRO +if(NOT DEFINED ENV{DEVKITPRO}) + message(FATAL_ERROR "You must have defined DEVKITPRO before calling cmake.") +endif() + +set(DEVKITPRO $ENV{DEVKITPRO}) + +# Find DEVKITPPC +find_program(DEVKITPPC_GCC + NAMES powerpc-eabi-gcc + PATHS "${DEVKITPRO}/devkitPPC/bin") + if(DEVKITPPC_GCC) get_filename_component(DEVKITPPC_BIN ${DEVKITPPC_GCC} DIRECTORY) get_filename_component(DEVKITPPC ${DEVKITPPC_BIN} DIRECTORY) @@ -17,12 +28,29 @@ else() set(DEVKITPPC_BIN "${DEVKITPPC}/bin") endif() +# Find WUT if(NOT DEFINED ENV{WUT_ROOT}) message(FATAL_ERROR "You must have defined WUT_ROOT before calling cmake.") endif() set(WUT_ROOT $ENV{WUT_ROOT}) +# Find elf2rpl +find_program(ELF2RPL_BIN + NAMES elf2rpl + PATHS "${DEVKITPRO}/tools/bin") +if(NOT ELF2RPL_BIN) + message(FATAL_ERROR "Could not find elf2rpl") +endif() + +# Find rplexportgen +find_program(RPLEXPORTGEN_BIN + NAMES rplexportgen + PATHS "${DEVKITPRO}/tools/bin") +if(NOT RPLEXPORTGEN_BIN) + message(FATAL_ERROR "Could not find rplexportgen") +endif() + set(CMAKE_ASM_COMPILER "${DEVKITPPC_BIN}/powerpc-eabi-gcc" CACHE PATH "") set(CMAKE_C_COMPILER "${DEVKITPPC_BIN}/powerpc-eabi-gcc" CACHE PATH "") set(CMAKE_CXX_COMPILER "${DEVKITPPC_BIN}/powerpc-eabi-g++" CACHE PATH "") @@ -40,15 +68,15 @@ set(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc -T \"${WUT_ROOT}/share/wut.ld\" \ include_directories(BEFORE SYSTEM "${WUT_ROOT}/include") # Setup root to exclude host system headers + libraries -set(CMAKE_FIND_ROOT_PATH "${DEVKITPPC}" "${WUT_ROOT}/bin" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share") +set(CMAKE_FIND_ROOT_PATH "${DEVKITPPC}" "${DEVKITPRO}/tools/bin" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # Tools -set(WUT_ELF2RPL "${WUT_ROOT}/bin/elf2rpl" CACHE PATH "") -set(WUT_RPLEXPORTGEN "${WUT_ROOT}/bin/rplexportgen" CACHE PATH "") +set(WUT_ELF2RPL "${ELF2RPL_BIN}" CACHE PATH "") +set(WUT_RPLEXPORTGEN "${RPLEXPORTGEN_BIN}" CACHE PATH "") # Flags set(WUT TRUE) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt deleted file mode 100644 index 8d188cf94..000000000 --- a/tools/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -project(tools) - -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -add_subdirectory(libraries) - -include_directories(common) -add_subdirectory(elf2rpl) -add_subdirectory(readrpl) -add_subdirectory(rplimportgen) -add_subdirectory(rplexportgen) -add_subdirectory(udplogserver) diff --git a/tools/common/be_val.h b/tools/common/be_val.h deleted file mode 100644 index 50d893c98..000000000 --- a/tools/common/be_val.h +++ /dev/null @@ -1,372 +0,0 @@ -#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>::type> - be_val & operator =(const OtherType &other) - { - setValue(value_type { other }); - return *this; - } - - template::value>::type> - be_val & operator =(OtherType &&other) - { - setValue(value_type { std::forward(other) }); - return *this; - } - - template::value>::type> - be_val & operator =(const be_val &other) - { - setValue(value_type { other.value() }); - return *this; - } - - template::value>::type> - be_val & operator =(be_val &&other) - { - setValue(value_type { 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 ->(); - } - -private: - value_type mStorage; -}; diff --git a/tools/common/elf.h b/tools/common/elf.h deleted file mode 100644 index c7f4eabad..000000000 --- a/tools/common/elf.h +++ /dev/null @@ -1,321 +0,0 @@ -#pragma once -#include -#include "be_val.h" -#include "utils.h" - -#pragma pack(push, 1) - -namespace elf -{ - -enum Machine : uint16_t // e_machine -{ - EM_PPC = 20 // PowerPC -}; - -enum Encoding : uint8_t // e_encoding -{ - ELFDATANONE = 0, - ELFDATA2LSB = 1, - ELFDATA2MSB = 2 -}; - -enum Class : uint8_t // e_class -{ - ELFCLASSNONE = 0, - ELFCLASS32 = 1, - ELFCLASS64 = 2 -}; - -enum Version : uint8_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 : uint16_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_EMB_RELSDA = 116, - R_PPC_DIAB_SDA21_LO = 180, - R_PPC_DIAB_SDA21_HI = 181, - R_PPC_DIAB_SDA21_HA = 182, - R_PPC_DIAB_RELSDA_LO = 183, - R_PPC_DIAB_RELSDA_HI = 184, - R_PPC_DIAB_RELSDA_HA = 185, - R_PPC_GHS_REL16_HA = 251, - R_PPC_GHS_REL16_HI = 252, - R_PPC_GHS_REL16_LO = 253, -}; - -enum RplFileInfoFlag : uint32_t -{ - RPL_IS_RPX = 0x2, -}; - -static const unsigned HeaderMagic = 0x7f454c46; - -struct Header -{ - be_val magic; // File identification. - be_val fileClass; // File class. - be_val encoding; // Data encoding. - be_val elfVersion; // File version. - be_val abi; // OS/ABI identification. (EABI_*) - be_val pad[7]; - - be_val type; // Type of file (ET_*) - be_val machine; // Required architecture for this file (EM_*) - be_val version; // Must be equal to 1 - be_val entry; // Address to jump to in order to start program - be_val phoff; // Program header table's file offset, in bytes - be_val shoff; // Section header table's file offset, in bytes - be_val flags; // Processor-specific flags - be_val ehsize; // Size of ELF header, in bytes - be_val phentsize; // Size of an entry in the program header table - be_val phnum; // Number of entries in the program header table - be_val shentsize; // Size of an entry in the section header table - be_val shnum; // Number of entries in the section header table - be_val shstrndx; // Sect hdr table index of sect name string table -}; -CHECK_SIZE(Header, 0x34); - -struct SectionHeader -{ - be_val name; // Section name (index into string table) - be_val type; // Section type (SHT_*) - be_val flags; // Section flags (SHF_*) - be_val addr; // Address where section is to be loaded - be_val offset; // File offset of section data, in bytes - be_val size; // Size of section, in bytes - be_val link; // Section type-specific header table index link - be_val info; // Section type-specific extra information - be_val addralign; // Section address alignment - be_val entsize; // Size of records contained within the section -}; -CHECK_SIZE(SectionHeader, 0x28); - -struct Symbol -{ - be_val name; // Symbol name (index into string table) - be_val value; // Value or address associated with the symbol - be_val size; // Size of the symbol - be_val info; // Symbol's type and binding attributes - be_val other; // Must be zero; reserved - be_val shndx; // Which section (header table index) it's defined in (SHN_*) -}; -CHECK_SIZE(Symbol, 0x10); - -struct Rela -{ - be_val offset; - be_val info; - be_val addend; -}; -CHECK_SIZE(Rela, 0x0C); - -struct RplImport -{ - be_val count; - be_val signature; - char name[1]; -}; - -struct RplExport -{ - struct Export - { - be_val value; - be_val name; - }; - - be_val count; - be_val signature; - Export exports[1]; -}; - -struct RplCrc -{ - be_val crc; -}; -CHECK_SIZE(RplCrc, 0x04); - -struct RplFileInfo -{ - be_val version; - be_val textSize; - be_val textAlign; - be_val dataSize; - be_val dataAlign; - be_val loadSize; - be_val loadAlign; - be_val tempSize; - be_val trampAdjust; - be_val sdaBase; - be_val sda2Base; - be_val stackSize; - be_val filename; - be_val flags; - be_val heapSize; - be_val tagOffset; - be_val minVersion; - be_val compressionLevel; - be_val trampAddition; - be_val fileInfoPad; - be_val cafeSdkVersion; - be_val cafeSdkRevision; - be_val tlsModuleIndex; - be_val tlsAlignShift; - be_val runtimeFileInfoSize; -}; -CHECK_SIZE(RplFileInfo, 0x60); - -} // namespace elf - -#pragma pack(pop) diff --git a/tools/common/type_traits.h b/tools/common/type_traits.h deleted file mode 100644 index 34fa7ecf7..000000000 --- a/tools/common/type_traits.h +++ /dev/null @@ -1,22 +0,0 @@ -#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 deleted file mode 100644 index b97499763..000000000 --- a/tools/common/utils.h +++ /dev/null @@ -1,167 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -#if defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) -#define PLATFORM_WINDOWS -#elif __APPLE__ -#define PLATFORM_APPLE -#define PLATFORM_POSIX -#elif __linux__ -#define PLATFORM_LINUX -#define PLATFORM_POSIX -#endif - -#ifdef PLATFORM_LINUX -#include -#endif - -// reinterpret_cast for value types -template -inline DstType -bit_cast(const SrcType& src) -{ - static_assert(sizeof(SrcType) == sizeof(DstType), "bit_cast must be between same sized types"); - static_assert(std::is_trivially_copyable::value, "SrcType is not trivially copyable."); - static_assert(std::is_trivially_copyable::value, "DstType is not trivially copyable."); - - DstType dst; - std::memcpy(&dst, &src, sizeof(SrcType)); - return dst; -} - -// Utility class to swap endian for types of size 1, 2, 4, 8 -// other type sizes are not supported -template -struct byte_swap_t; - -template -struct byte_swap_t -{ - static Type swap(Type src) - { - return src; - } -}; - -template -struct byte_swap_t -{ - static Type swap(Type src) - { -#ifdef PLATFORM_WINDOWS - return bit_cast(_byteswap_ushort(bit_cast(src))); -#elif defined(PLATFORM_LINUX) - return bit_cast(bswap_16(bit_cast(src))); -#else - const uint16_t data = bit_cast(src); - return bit_cast(static_cast((data >> 8) | (data << 8))); -#endif - } -}; - -template -struct byte_swap_t -{ - static Type swap(Type src) - { -#ifdef PLATFORM_WINDOWS - return bit_cast(_byteswap_ulong(bit_cast(src))); -#elif defined(PLATFORM_APPLE) - return bit_cast(__builtin_bswap32(bit_cast(src))); -#elif defined(PLATFORM_LINUX) - return bit_cast(bswap_32(bit_cast(src))); -#else - const uint32_t data = bit_cast(src); - return bit_cast( - ((data & 0xFF000000u) >> 24) | - ((data & 0x00FF0000u) >> 8) | - ((data & 0x0000FF00u) << 8) | - ((data & 0x000000FFu) << 24) - ); -#endif - } -}; - -template -struct byte_swap_t -{ - static Type swap(Type src) - { -#ifdef PLATFORM_WINDOWS - return bit_cast(_byteswap_uint64(bit_cast(src))); -#elif defined(PLATFORM_APPLE) - return bit_cast(__builtin_bswap64(bit_cast(src))); -#elif defined(PLATFORM_LINUX) - return bit_cast(bswap_64(bit_cast(src))); -#else - uint64_t data = bit_cast(src); - data = ((data & 0x00000000FFFFFFFFull) << 32) | ((data & 0xFFFFFFFF00000000ull) >> 32); - data = ((data & 0x0000FFFF0000FFFFull) << 16) | ((data & 0xFFFF0000FFFF0000ull) >> 16); - data = ((data & 0x00FF00FF00FF00FFull) << 8) | ((data & 0xFF00FF00FF00FF00ull) >> 8); - return bit_cast(data); -#endif - } -}; - -// Swaps endian of src -template -inline Type -byte_swap(Type src) -{ - return byte_swap_t::swap(src); -} - -// Alignment helpers -template -constexpr inline Type -align_up(Type value, size_t alignment) -{ - return static_cast((static_cast(value) + (alignment - 1)) & ~(alignment - 1)); -} - -template -constexpr inline Type -align_down(Type value, size_t alignment) -{ - return static_cast(static_cast(value) & ~(alignment - 1)); -} - -template -constexpr bool -align_check(Type value, size_t alignment) -{ - return (static_cast(value) & (alignment - 1)) == 0; -} - -#define CHECK_SIZE(Type, Size) \ - static_assert(sizeof(Type) == Size, \ - #Type " must be " #Size " bytes") - -// trim from start -// Taken from https://stackoverflow.com/a/217605 -static inline std::string ltrim(std::string s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { - return !std::isspace(ch); - })); - return s; -} - -// trim from end (in place) -static inline std::string rtrim(std::string s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { - return !std::isspace(ch); - }).base(), s.end()); - return s; -} - -// trim from both ends -static inline std::string -trim(std::string s) -{ - return rtrim(ltrim(s)); -} diff --git a/tools/elf2rpl/CMakeLists.txt b/tools/elf2rpl/CMakeLists.txt deleted file mode 100644 index 15700b860..000000000 --- a/tools/elf2rpl/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -project(elf2rpl) - -add_executable(elf2rpl - main.cpp) - -target_link_libraries(elf2rpl - excmd - fmt - zlibstatic) - -install(TARGETS elf2rpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/elf2rpl/main.cpp b/tools/elf2rpl/main.cpp deleted file mode 100644 index 688d47906..000000000 --- a/tools/elf2rpl/main.cpp +++ /dev/null @@ -1,834 +0,0 @@ -#include "elf.h" -#include "utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -constexpr auto DeflateMinSectionSize = 0x18u; -constexpr auto CodeBaseAddress = 0x02000000u; -constexpr auto DataBaseAddress = 0x10000000u; -constexpr auto LoadBaseAddress = 0xC0000000u; - -struct ElfFile -{ - struct Section - { - elf::SectionHeader header; - std::string name; - std::vector data; - }; - - elf::Header header; - std::vector> sections; -}; - -static int -getSectionIndex(ElfFile &file, const char *name) -{ - int index = 0; - for (const auto §ion : file.sections) { - if (section->name == name) { - return index; - } - - ++index; - } - - return -1; -} - - -static ElfFile::Section * -getSectionByType(ElfFile &file, elf::SectionType type) -{ - for (const auto §ion : file.sections) { - if (section->header.type == type) { - return section.get(); - } - } - - return nullptr; -} - - -/** - * Read the .elf file generated by compiler. - */ -static bool -readElf(ElfFile &file, const std::string &filename) -{ - std::ifstream in { filename, std::ifstream::binary }; - if (!in.is_open()) { - fmt::print("Could not open {} for reading\n", filename); - return false; - } - - // Read header - in.read(reinterpret_cast(&file.header), sizeof(elf::Header)); - - if (file.header.magic != elf::HeaderMagic) { - fmt::print("Invalid ELF magic header {:08X}\n", elf::HeaderMagic); - return false; - } - - if (file.header.fileClass != elf::ELFCLASS32) { - fmt::print("Unexpected ELF file class {}, expected {}\n", file.header.fileClass, elf::ELFCLASS32); - return false; - } - - if (file.header.encoding != elf::ELFDATA2MSB) { - fmt::print("Unexpected ELF encoding {}, expected {}\n", file.header.encoding, elf::ELFDATA2MSB); - return false; - } - - if (file.header.machine != elf::EM_PPC) { - fmt::print("Unexpected ELF machine type {}, expected {}\n", file.header.machine, elf::EM_PPC); - return false; - } - - if (file.header.elfVersion != elf::EV_CURRENT) { - fmt::print("Unexpected ELF version {}, expected {}\n", file.header.elfVersion, elf::EV_CURRENT); - return false; - } - - // Read section headers and data - in.seekg(static_cast(file.header.shoff)); - - for (auto i = 0u; i < file.header.shnum; ++i) { - file.sections.emplace_back(std::make_unique()); - auto §ion = *file.sections.back(); - - in.read(reinterpret_cast(§ion.header), sizeof(elf::SectionHeader)); - - if (!section.header.size || section.header.type == elf::SHT_NOBITS) { - continue; - } - - auto pos = in.tellg(); - in.seekg(static_cast(section.header.offset)); - section.data.resize(section.header.size); - in.read(section.data.data(), section.data.size()); - in.seekg(pos); - } - - // Set section header names - auto shStrTab = file.sections[file.header.shstrndx]->data.data(); - - for (auto §ion : file.sections) { - section->name = shStrTab + section->header.name; - } - - return true; -} - - -/** - * Generate SHT_RPL_FILEINFO section. - */ -static bool -generateFileInfoSection(ElfFile &file, - uint32_t flags) -{ - elf::RplFileInfo info; - info.version = 0xCAFE0402u; - info.textSize = 0u; - info.textAlign = 32u; - info.dataSize = 0u; - info.dataAlign = 4096u; - info.loadSize = 0u; - info.loadAlign = 4u; - info.tempSize = 0u; - info.trampAdjust = 0u; - info.trampAddition = 0u; - info.sdaBase = 0u; - info.sda2Base = 0u; - info.stackSize = 0x10000u; - info.heapSize = 0x8000u; - info.filename = 0u; - info.flags = flags; - info.minVersion = 0x5078u; - info.compressionLevel = 6; - info.fileInfoPad = 0u; - info.cafeSdkVersion = 0x5335u; - info.cafeSdkRevision = 0x10D4Bu; - info.tlsAlignShift = uint16_t { 0u }; - info.tlsModuleIndex = uint16_t { 0u }; - info.runtimeFileInfoSize = 0u; - info.tagOffset = 0u; - - // Count file info textSize, dataSize, loadSize - for (auto §ion : file.sections) { - auto size = static_cast(section->data.size()); - - if (section->header.type == elf::SHT_NOBITS) { - size = section->header.size; - } - - if (section->header.addr >= CodeBaseAddress && - section->header.addr < DataBaseAddress) { - auto val = section->header.addr + section->header.size - CodeBaseAddress; - if (val > info.textSize) { - info.textSize = val; - } - } else if (section->header.addr >= DataBaseAddress && - section->header.addr < LoadBaseAddress) { - auto val = section->header.addr + section->header.size - DataBaseAddress; - if (val > info.dataSize) { - info.dataSize = val; - } - } else if (section->header.addr >= LoadBaseAddress) { - auto val = section->header.addr + section->header.size - LoadBaseAddress; - if (val > info.loadSize) { - info.loadSize = val; - } - } else if (section->header.addr == 0 && - section->header.type != elf::SHT_RPL_CRCS && - section->header.type != elf::SHT_RPL_FILEINFO) { - info.tempSize += (size + 128); - } - } - - info.textSize = align_up(info.textSize, info.textAlign); - info.dataSize = align_up(info.dataSize, info.dataAlign); - info.loadSize = align_up(info.loadSize, info.loadAlign); - - auto section = std::make_unique(); - section->header.name = 0u; - section->header.type = elf::SHT_RPL_FILEINFO; - section->header.flags = 0u; - section->header.addr = 0u; - section->header.offset = 0u; - section->header.size = 0u; - section->header.link = 0u; - section->header.info = 0u; - section->header.addralign = 4u; - section->header.entsize = 0u; - section->data.insert(section->data.end(), - reinterpret_cast(&info), - reinterpret_cast(&info + 1)); - file.sections.emplace_back(std::move(section)); - return true; -} - - -/** - * Generate SHT_RPL_CRCS section. - */ -static bool -generateCrcSection(ElfFile &file) -{ - std::vector> crcs; - for (auto §ion : file.sections) { - auto crc = uint32_t { 0u }; - - if (section->data.size()) { - crc = crc32(0, Z_NULL, 0); - crc = crc32(crc, reinterpret_cast(section->data.data()), section->data.size()); - } - - crcs.push_back(crc); - } - - // Insert a 0 crc for this section - crcs.insert(crcs.end() - 1, 0); - - auto section = std::make_unique(); - section->header.name = 0u; - section->header.type = elf::SHT_RPL_CRCS; - section->header.flags = 0u; - section->header.addr = 0u; - section->header.offset = 0u; - section->header.size = 0u; - section->header.link = 0u; - section->header.info = 0u; - section->header.addralign = 4u; - section->header.entsize = 4u; - section->data.insert(section->data.end(), - reinterpret_cast(crcs.data()), - reinterpret_cast(crcs.data() + crcs.size())); - - // Insert before FILEINFO - file.sections.insert(file.sections.end() - 1, std::move(section)); - return true; -} - - -static bool -getSymbol(ElfFile::Section §ion, - size_t index, - elf::Symbol &symbol) -{ - auto symbols = reinterpret_cast(section.data.data()); - auto numSymbols = section.data.size() / sizeof(elf::Symbol); - if (index >= numSymbols) { - return false; - } - - symbol = symbols[index]; - return true; -} - - -/** - * Fix relocations. - * - * The Wii U does not support every type of relocation. - */ -static bool -fixRelocations(ElfFile &file) -{ - std::set unsupportedTypes; - auto result = true; - - for (auto §ion : file.sections) { - std::vector newRelocations; - - if (section->header.type != elf::SHT_RELA) { - continue; - } - - // Clear flags - section->header.flags = 0u; - - auto &symbolSection = file.sections[section->header.link]; - auto &targetSection = file.sections[section->header.info]; - - auto rels = reinterpret_cast(section->data.data()); - auto numRels = section->data.size() / sizeof(elf::Rela); - for (auto i = 0u; i < numRels; ++i) { - auto info = rels[i].info; - auto addend = rels[i].addend; - auto offset = rels[i].offset; - auto index = info >> 8; - auto type = info & 0xFF; - - switch (type) { - case elf::R_PPC_NONE: - case elf::R_PPC_ADDR32: - case elf::R_PPC_ADDR16_LO: - case elf::R_PPC_ADDR16_HI: - case elf::R_PPC_ADDR16_HA: - case elf::R_PPC_REL24: - case elf::R_PPC_REL14: - case elf::R_PPC_DTPMOD32: - case elf::R_PPC_DTPREL32: - case elf::R_PPC_EMB_SDA21: - case elf::R_PPC_EMB_RELSDA: - case elf::R_PPC_DIAB_SDA21_LO: - case elf::R_PPC_DIAB_SDA21_HI: - case elf::R_PPC_DIAB_SDA21_HA: - case elf::R_PPC_DIAB_RELSDA_LO: - case elf::R_PPC_DIAB_RELSDA_HI: - case elf::R_PPC_DIAB_RELSDA_HA: - // All valid relocations on Wii U, do nothing - break; - - /* - * Convert a R_PPC_REL32 into two GHS_REL16 - */ - case elf::R_PPC_REL32: - { - elf::Symbol symbol; - if (!getSymbol(*symbolSection, index, symbol)) { - fmt::print("ERROR: Could not find symbol {} for fixing a R_PPC_REL32 relocation\n", index); - result = false; - } else { - newRelocations.emplace_back(); - auto &newRel = newRelocations.back(); - - // Modify current relocation to R_PPC_GHS_REL16_HI - rels[i].info = (index << 8) | elf::R_PPC_GHS_REL16_HI; - rels[i].addend = addend; - rels[i].offset = offset; - - // Create a R_PPC_GHS_REL16_LO - newRel.info = (index << 8) | elf::R_PPC_GHS_REL16_LO; - newRel.addend = addend + 2; - newRel.offset = offset + 2; - } - - break; - } - - default: - // Only print error once per type - if (!unsupportedTypes.count(type)) { - fmt::print("ERROR: Unsupported relocation type {}\n", type); - unsupportedTypes.insert(type); - } - } - } - - section->data.insert(section->data.end(), - reinterpret_cast(newRelocations.data()), - reinterpret_cast(newRelocations.data() + newRelocations.size())); - } - - return result && unsupportedTypes.size() == 0; -} - - -/** - * Fix file header to look like an RPL file! - */ -static bool -fixFileHeader(ElfFile &file) -{ - file.header.magic = elf::HeaderMagic; - file.header.fileClass = uint8_t { 1 }; - file.header.encoding = elf::ELFDATA2MSB; - file.header.elfVersion = elf::EV_CURRENT; - file.header.abi = elf::EABI_CAFE; - memset(&file.header.pad, 0, 7); - file.header.type = uint16_t { 0xFE01 }; - file.header.machine = elf::EM_PPC; - file.header.version = 1u; - file.header.flags = 0u; - file.header.phoff = 0u; - file.header.phentsize = uint16_t { 0 }; - file.header.phnum = uint16_t { 0 }; - file.header.shoff = align_up(static_cast(sizeof(elf::Header)), 64); - file.header.shnum = static_cast(file.sections.size()); - file.header.shentsize = static_cast(sizeof(elf::SectionHeader)); - file.header.ehsize = static_cast(sizeof(elf::Header)); - file.header.shstrndx = static_cast(getSectionIndex(file, ".shstrtab")); - return true; -} - - -/** - * Relocate a section to a new address. - */ -static bool -relocateSection(ElfFile &file, - ElfFile::Section §ion, - uint32_t sectionIndex, - uint32_t newSectionAddress) -{ - auto sectionSize = section.data.size() ? section.data.size() : static_cast(section.header.size); - auto oldSectionAddress = section.header.addr; - auto oldSectionAddressEnd = section.header.addr + sectionSize; - - // Relocate symbols pointing into this section - for (auto &symSection : file.sections) { - if (symSection->header.type != elf::SectionType::SHT_SYMTAB) { - continue; - } - - auto symbols = reinterpret_cast(symSection->data.data()); - auto numSymbols = symSection->data.size() / sizeof(elf::Symbol); - for (auto i = 0u; i < numSymbols; ++i) { - auto type = symbols[i].info & 0xf; - auto value = symbols[i].value; - - // Only relocate data, func, section symbols - if (type != elf::STT_OBJECT && - type != elf::STT_FUNC && - type != elf::STT_SECTION) { - continue; - } - - if (value >= oldSectionAddress && value <= oldSectionAddressEnd) { - symbols[i].value = (value - oldSectionAddress) + newSectionAddress; - } - } - } - - // Relocate relocations pointing into this section - for (auto &relaSection : file.sections) { - if (relaSection->header.type != elf::SectionType::SHT_RELA || - relaSection->header.info != sectionIndex) { - continue; - } - - auto rela = reinterpret_cast(relaSection->data.data()); - auto numRelas = relaSection->data.size() / sizeof(elf::Rela); - for (auto i = 0u; i < numRelas; ++i) { - auto offset = rela[i].offset; - - if (offset >= oldSectionAddress && offset <= oldSectionAddressEnd) { - rela[i].offset = (offset - oldSectionAddress) + newSectionAddress; - } - } - } - - section.header.addr = newSectionAddress; - return true; -} - - -/** - * Fix the loader virtual addresses. - * - * Linker script won't put symtab & strtab sections in our loader address, so - * we must fix that. - */ -static bool -fixLoaderVirtualAddresses(ElfFile &file) -{ - auto loadMax = LoadBaseAddress; - for (auto §ion : file.sections) { - if (section->header.addr >= loadMax) { - loadMax = section->header.addr + section->data.size(); - } - } - - // Relocate .symtab and .strtab to be in loader memory - for (auto i = 0u; i < file.sections.size(); ++i) { - auto §ion = file.sections[i]; - if (section->header.type == elf::SHT_SYMTAB || - section->header.type == elf::SHT_STRTAB) { - relocateSection(file, *section, i, - align_up(loadMax, section->header.addralign)); - section->header.flags |= elf::SHF_ALLOC; - loadMax += section->data.size(); - } - } - - return true; -} - - -/** - * zlib deflate any suitable section. - */ -static bool -deflateSections(ElfFile &file) -{ - std::vector chunk; - chunk.resize(16 * 1024); - - for (auto §ion : file.sections) { - if (section->data.size() < DeflateMinSectionSize || - section->header.type == elf::SHT_RPL_CRCS || - section->header.type == elf::SHT_RPL_FILEINFO) { - continue; - } - - // Allocate space for the 4 bytes inflated size - std::vector deflated; - deflated.resize(4); - - // Deflate section data - auto stream = z_stream { }; - memset(&stream, 0, sizeof(stream)); - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - deflateInit(&stream, 6); - - stream.avail_in = section->data.size(); - stream.next_in = reinterpret_cast(section->data.data()); - - do { - stream.avail_out = static_cast(chunk.size()); - stream.next_out = reinterpret_cast(chunk.data()); - - auto ret = deflate(&stream, Z_FINISH); - if (ret == Z_STREAM_ERROR) { - deflateEnd(&stream); - return false; - } - - deflated.insert(deflated.end(), - chunk.data(), - reinterpret_cast(stream.next_out)); - } while (stream.avail_out == 0); - deflateEnd(&stream); - - // Set the inflated size at start of section - *reinterpret_cast *>(&deflated[0]) = - static_cast(section->data.size()); - - // Update the section data - section->data = std::move(deflated); - section->header.flags |= elf::SHF_DEFLATED; - } - - return true; -} - - -/** - * Calculate section file offsets. - * - * Expected order: - * RPL_CRCS > RPL_FILEINFO > - * Data sections > Read sections > Text sections > Temp sections - */ -static bool -calculateSectionOffsets(ElfFile &file) -{ - auto offset = file.header.shoff; - offset += align_up(static_cast(file.sections.size() * sizeof(elf::SectionHeader)), 64); - - for (auto §ion : file.sections) { - if (section->header.type == elf::SHT_NOBITS || - section->header.type == elf::SHT_NULL) { - section->header.offset = 0u; - section->data.clear(); - } - } - - for (auto §ion : file.sections) { - if (section->header.type == elf::SHT_RPL_CRCS) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - for (auto §ion : file.sections) { - if (section->header.type == elf::SHT_RPL_FILEINFO) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - // First the "dataMin / dataMax" sections, which are: - // - !(flags & SHF_EXECINSTR) - // - flags & SHF_WRITE - // - flags & SHF_ALLOC - for (auto §ion : file.sections) { - if (section->header.size == 0 || - section->header.type == elf::SHT_RPL_FILEINFO || - section->header.type == elf::SHT_RPL_IMPORTS || - section->header.type == elf::SHT_RPL_CRCS || - section->header.type == elf::SHT_NOBITS) { - continue; - } - - if (!(section->header.flags & elf::SHF_EXECINSTR) && - (section->header.flags & elf::SHF_WRITE) && - (section->header.flags & elf::SHF_ALLOC)) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - // Next the "readMin / readMax" sections, which are: - // - !(flags & SHF_EXECINSTR) || type == SHT_RPL_EXPORTS - // - !(flags & SHF_WRITE) - // - flags & SHF_ALLOC - for (auto §ion : file.sections) { - if (section->header.size == 0 || - section->header.type == elf::SHT_RPL_FILEINFO || - section->header.type == elf::SHT_RPL_IMPORTS || - section->header.type == elf::SHT_RPL_CRCS || - section->header.type == elf::SHT_NOBITS) { - continue; - } - - if ((!(section->header.flags & elf::SHF_EXECINSTR) || - section->header.type == elf::SHT_RPL_EXPORTS) && - !(section->header.flags & elf::SHF_WRITE) && - (section->header.flags & elf::SHF_ALLOC)) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - // Import sections are part of the read sections, but have execinstr flag set - // so let's insert them here to avoid complicating the above logic. - for (auto §ion : file.sections) { - if (section->header.type == elf::SHT_RPL_IMPORTS) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - // Next the "textMin / textMax" sections, which are: - // - flags & SHF_EXECINSTR - // - type != SHT_RPL_EXPORTS - for (auto §ion : file.sections) { - if (section->header.size == 0 || - section->header.type == elf::SHT_RPL_FILEINFO || - section->header.type == elf::SHT_RPL_IMPORTS || - section->header.type == elf::SHT_RPL_CRCS || - section->header.type == elf::SHT_NOBITS) { - continue; - } - - if ((section->header.flags & elf::SHF_EXECINSTR) && - section->header.type != elf::SHT_RPL_EXPORTS) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - // Next the "tempMin / tempMax" sections, which are: - // - !(flags & SHF_EXECINSTR) - // - !(flags & SHF_ALLOC) - for (auto §ion : file.sections) { - if (section->header.size == 0 || - section->header.type == elf::SHT_RPL_FILEINFO || - section->header.type == elf::SHT_RPL_IMPORTS || - section->header.type == elf::SHT_RPL_CRCS || - section->header.type == elf::SHT_NOBITS) { - continue; - } - - if (!(section->header.flags & elf::SHF_EXECINSTR) && - !(section->header.flags & elf::SHF_ALLOC)) { - section->header.offset = offset; - section->header.size = static_cast(section->data.size()); - offset += section->header.size; - } - } - - auto index = 0u; - for (auto §ion : file.sections) { - if (section->header.offset == 0 && - section->header.type != elf::SHT_NULL && - section->header.type != elf::SHT_NOBITS) { - fmt::print("Failed to calculate offset for section {}\n", index); - return false; - } - - ++index; - } - - return true; -} - - -/** - * Write out the final RPL. - */ -static bool -writeRpl(ElfFile &file, const std::string &filename) -{ - auto shoff = file.header.shoff; - - // Write the file out - std::ofstream out { filename, std::ofstream::binary }; - - if (!out.is_open()) { - fmt::print("Could not open {} for writing\n", filename); - return false; - } - - // Write file header - out.seekp(0, std::ios::beg); - out.write(reinterpret_cast(&file.header), sizeof(elf::Header)); - - // Write section headers - out.seekp(shoff, std::ios::beg); - for (const auto §ion : file.sections) { - out.write(reinterpret_cast(§ion->header), sizeof(elf::SectionHeader)); - } - - // Write sections - for (const auto §ion : file.sections) { - if (section->data.size()) { - out.seekp(section->header.offset, std::ios::beg); - out.write(section->data.data(), section->data.size()); - } - } - - return true; -} - -int main(int argc, char **argv) -{ - excmd::parser parser; - excmd::option_state options; - using excmd::description; - using excmd::value; - - try { - parser.global_options() - .add_option("H,help", - description { "Show help." }) - .add_option("r,rpl", - description { "Generate an RPL instead of an RPX" }); - - parser.default_command() - .add_argument("src", - description { "Path to input elf file" }, - value {}) - .add_argument("dst", - description { "Path to output rpl file" }, - value {}); - - options = parser.parse(argc, argv); - } catch (excmd::exception ex) { - fmt::print("Error parsing options: {}\n", ex.what()); - return -1; - } - - if (options.empty() - || options.has("help") - || !options.has("src") - || !options.has("dst")) { - fmt::print("{} src dst\n", argv[0]); - fmt::print("{}\n", parser.format_help(argv[0])); - return 0; - } - - auto src = options.get("src"); - auto dst = options.get("dst"); - auto isRpl = options.has("rpl"); - - // Read elf into memory object! - ElfFile elf; - - if (!readElf(elf, src)) { - fmt::print("ERROR: readElf failed.\n"); - return -1; - } - - if (!fixRelocations(elf)) { - fmt::print("ERROR: fixRelocations failed.\n"); - return -1; - } - - if (!fixLoaderVirtualAddresses(elf)) { - fmt::print("ERROR: fixLoaderVirtualAddresses failed.\n"); - return -1; - } - - if (!generateFileInfoSection(elf, isRpl ? 0 : elf::RPL_IS_RPX)) { - fmt::print("ERROR: generateFileInfoSection failed.\n"); - return -1; - } - - if (!generateCrcSection(elf)) { - fmt::print("ERROR: generateCrcSection failed.\n"); - return -1; - } - - if (!fixFileHeader(elf)) { - fmt::print("ERROR: fixFileHeader faile.\n"); - return -1; - } - - if (!deflateSections(elf)) { - fmt::print("ERROR: deflateSections failed.\n"); - return -1; - } - - if (!calculateSectionOffsets(elf)) { - fmt::print("ERROR: calculateSectionOffsets failed.\n"); - return -1; - } - - if (!writeRpl(elf, dst)) { - fmt::print("ERROR: writeRpl failed.\n"); - return -1; - } - - return 0; -} diff --git a/tools/libraries/CMakeLists.txt b/tools/libraries/CMakeLists.txt deleted file mode 100644 index df5729384..000000000 --- a/tools/libraries/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -include(CheckTypeSize) - -# excmd -add_library(excmd INTERFACE) -target_include_directories(excmd INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/excmd/src") - -# fmt -add_subdirectory(fmt) - -# zlib -find_package(ZLIB QUIET) - -if(NOT ZLIB_FOUND) - # Disable zlib install - set(SKIP_INSTALL_ALL 1) - set(BUILD_SHARED_LIBS OFF) - add_subdirectory(zlib) - - # Fix zlib tool / example includes - target_include_directories(example PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/zlib") - target_include_directories(minigzip PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/zlib") - - check_type_size(off64_t OFF64_T) - if(HAVE_OFF64_T) - target_include_directories(example64 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/zlib") - target_include_directories(minigzip64 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/zlib") - endif() - - target_include_directories(zlibstatic INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/zlib" - "${CMAKE_CURRENT_BINARY_DIR}/zlib") -else() - # Not actually static, but who cares... - add_library(zlibstatic INTERFACE) - target_link_libraries(zlibstatic INTERFACE ${ZLIB_LIBRARIES}) - target_include_directories(zlibstatic INTERFACE ${ZLIB_INCLUDE_DIR}) -endif() diff --git a/tools/libraries/excmd b/tools/libraries/excmd deleted file mode 160000 index b48dab495..000000000 --- a/tools/libraries/excmd +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b48dab4954bdc074d7768e38065171441aaff7ce diff --git a/tools/libraries/fmt b/tools/libraries/fmt deleted file mode 160000 index 5386f1df2..000000000 --- a/tools/libraries/fmt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5386f1df20392a08844f5034e8436c6ec7ce0b03 diff --git a/tools/libraries/zlib b/tools/libraries/zlib deleted file mode 160000 index cacf7f1d4..000000000 --- a/tools/libraries/zlib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cacf7f1d4e3d44d871b605da3b647f07d718623f diff --git a/tools/readrpl/CMakeLists.txt b/tools/readrpl/CMakeLists.txt deleted file mode 100644 index e56006ef8..000000000 --- a/tools/readrpl/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -project(readrpl) - -add_executable(readrpl - generate_exports_def.cpp - generate_exports_def.h - main.cpp - print.cpp - print.h - readrpl.h - verify.cpp - verify.h) - -target_link_libraries(readrpl - excmd - fmt - zlibstatic) - -install(TARGETS readrpl RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/readrpl/generate_exports_def.cpp b/tools/readrpl/generate_exports_def.cpp deleted file mode 100644 index b9099b3ac..000000000 --- a/tools/readrpl/generate_exports_def.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "generate_exports_def.h" - -#include -#include -#include - -static const char * -sExportBlacklist[] = { - "__get_eh_globals", - "__get_eh_init_block", - "__get_eh_mem_manage", - "__get_eh_store_globals", - "__get_eh_store_globals_tdeh", - "__gh_errno_ptr", - "__gh_get_errno", - "__gh_iob_init", - "__gh_lock_init", - "__gh_set_errno", - "__ghsLock", - "__ghsUnlock", - "__ghs_at_exit", - "__ghs_at_exit_cleanup", - "__ghs_flock_create", - "__ghs_flock_destroy", - "__ghs_flock_file", - "__ghs_flock_ptr", - "__ghs_ftrylock_file", - "__ghs_funlock_file", - "__ghs_mtx_dst", - "__ghs_mtx_init", - "__ghs_mtx_lock", - "__ghs_mtx_unlock", - "__tls_get_addr", - "memclr", - "memcpy", - "memmove", - "memset", - "__atexit_cleanup", - "__cpp_exception_cleanup_ptr", - "__cpp_exception_init_ptr", - "__gh_FOPEN_MAX", - "__ghs_cpp_locks", - "__stdio_cleanup", - "_iob", - "_iob_lock", - "environ", - "errno", -}; - -static bool -inBlacklist(const char *name) -{ - for (auto i = 0u; i < sizeof(sExportBlacklist) / sizeof(sExportBlacklist[0]); ++i) { - if (strcmp(name, sExportBlacklist[i]) == 0) { - return true; - } - } - - return false; -} - -bool -generateExportsDef(const Rpl &rpl, - const std::string &rplName, - const std::string &outFileName) -{ - FILE *fh = fopen(outFileName.c_str(), "w"); - if (!fh) { - fmt::print("Failed to open {} for writing!", outFileName); - return false; - } - - fmt::print(fh, ":NAME {}\n", rplName); - - for (auto §ion : rpl.sections) { - if (section.header.type == elf::SHT_RPL_EXPORTS) { - auto exports = reinterpret_cast(section.data.data()); - auto strTab = section.data.data(); - - if (section.header.flags & elf::SHF_EXECINSTR) { - fmt::print(fh, "\n:TEXT\n"); - } else { - fmt::print(fh, "\n:DATA\n"); - } - - for (auto i = 0u; i < exports->count; ++i) { - if (exports->exports[i].name & 0x80000000) { - // Skip TLS exports for now. - continue; - } - - auto name = strTab + (exports->exports[i].name & 0x7FFFFFFF); - - if (inBlacklist(name)) { - fmt::print(fh, "//"); - } - - fmt::print(fh, "{}\n", name); - } - - } - } - - fclose(fh); - return true; -} diff --git a/tools/readrpl/generate_exports_def.h b/tools/readrpl/generate_exports_def.h deleted file mode 100644 index 581fa0fd6..000000000 --- a/tools/readrpl/generate_exports_def.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "readrpl.h" -#include - -bool -generateExportsDef(const Rpl &rpl, - const std::string &rplName, - const std::string &outFileName); diff --git a/tools/readrpl/main.cpp b/tools/readrpl/main.cpp deleted file mode 100644 index 35b501a5c..000000000 --- a/tools/readrpl/main.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include "elf.h" -#include "generate_exports_def.h" -#include "print.h" -#include "verify.h" - -#include -#include -#include -#include -#include -#include - -static std::string -getFileBasename(std::string path) -{ - auto pos = path.find_last_of("\\/"); - if (pos != std::string::npos) { - path.erase(0, pos + 1); - } - - pos = path.rfind('.'); - if (pos != std::string::npos) { - path.erase(pos); - } - - return path; -} - -uint32_t -getSectionIndex(const Rpl &rpl, - const Section §ion) -{ - return static_cast(§ion - &rpl.sections[0]); -} - -bool -readSection(std::ifstream &fh, - Section §ion, - size_t i) -{ - // Read section header - fh.read(reinterpret_cast(§ion.header), sizeof(elf::SectionHeader)); - - if (section.header.type == elf::SHT_NOBITS || !section.header.size) { - return true; - } - - // Read section data - if (section.header.flags & elf::SHF_DEFLATED) { - auto stream = z_stream {}; - auto ret = Z_OK; - - // Read the original size - uint32_t size = 0; - fh.seekg(section.header.offset.value()); - fh.read(reinterpret_cast(&size), sizeof(uint32_t)); - size = byte_swap(size); - section.data.resize(size); - - // Inflate - memset(&stream, 0, sizeof(stream)); - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - - ret = inflateInit(&stream); - - if (ret != Z_OK) { - fmt::print("Couldn't decompress .rpx section because inflateInit returned {}\n", ret); - section.data.clear(); - return false; - } else { - std::vector temp; - temp.resize(section.header.size-sizeof(uint32_t)); - fh.read(temp.data(), temp.size()); - - stream.avail_in = section.header.size; - stream.next_in = reinterpret_cast(temp.data()); - stream.avail_out = static_cast(section.data.size()); - stream.next_out = reinterpret_cast(section.data.data()); - - ret = inflate(&stream, Z_FINISH); - - if (ret != Z_OK && ret != Z_STREAM_END) { - fmt::print("Couldn't decompress .rpx section because inflate returned {}\n", ret); - section.data.clear(); - return false; - } - - inflateEnd(&stream); - } - } else { - section.data.resize(section.header.size); - fh.seekg(section.header.offset.value()); - fh.read(section.data.data(), section.header.size); - } - - return true; -} - -int main(int argc, char **argv) -{ - excmd::parser parser; - excmd::option_state options; - using excmd::description; - using excmd::value; - - try { - parser.global_options() - .add_option("H,help", - description { "Show help." }) - .add_option("a,all", - description { "Equivalent to: -h -S -s -r -i -x -c -f" }) - .add_option("h,file-header", - description { "Display the ELF file header" }) - .add_option("S,sections", - description { "Display the sections' header" }) - .add_option("s,symbols", - description { "Display the symbol table" }) - .add_option("r,relocs", - description { "Display the relocations" }) - .add_option("i,imports", - description { "Display the RPL imports" }) - .add_option("x,exports", - description { "Display the RPL exports" }) - .add_option("c,crc", - description { "Display the RPL crc" }) - .add_option("f,file-info", - description { "Display the RPL file info" }) - .add_option("exports-def", - description { "Generate exports.def for wut library linking" }, - value {}); - - parser.default_command() - .add_argument("path", - description { "Path to RPL file" }, - value {}); - - options = parser.parse(argc, argv); - } catch (excmd::exception ex) { - std::cout << "Error parsing options: " << ex.what() << std::endl; - return -1; - } - - if (options.empty() || options.has("help") || !options.has("path")) { - fmt::print("{} path\n", argv[0]); - fmt::print("{}\n", parser.format_help(argv[0])); - return 0; - } - - auto all = options.has("all"); - - auto dumpElfHeader = all || options.has("file-header"); - auto dumpSectionSummary = all || options.has("sections"); - auto dumpSectionRela = all || options.has("relocs"); - auto dumpSectionSymtab = all || options.has("symbols"); - auto dumpSectionRplExports = all || options.has("exports"); - auto dumpSectionRplImports = all || options.has("imports"); - auto dumpSectionRplCrcs = all || options.has("crc"); - auto dumpSectionRplFileinfo = all || options.has("file-info"); - auto path = options.get("path"); - - // If no options are set (other than "path"), let's default to a summary - if (options.set_options.size() == 1) { - dumpElfHeader = true; - dumpSectionSummary = true; - dumpSectionRplFileinfo = true; - } - - // Read file - std::ifstream fh { path, std::ifstream::binary }; - if (!fh.is_open()) { - fmt::print("Could not open {} for reading\n", path); - return -1; - } - - Rpl rpl; - fh.read(reinterpret_cast(&rpl.header), sizeof(elf::Header)); - - if (rpl.header.magic != elf::HeaderMagic) { - fmt::print("Invalid ELF magic header\n"); - return -1; - } - - // Read sections - for (auto i = 0u; i < rpl.header.shnum; ++i) { - Section section; - fh.seekg(rpl.header.shoff + rpl.header.shentsize * i); - - if (!readSection(fh, section, i)) { - fmt::print("Error reading section {}", i); - return -1; - } - - rpl.sections.push_back(section); - } - - // Set section names - auto shStrTab = reinterpret_cast(rpl.sections[rpl.header.shstrndx].data.data()); - for (auto §ion : rpl.sections) { - section.name = shStrTab + section.header.name; - } - - // Verify rpl format - verifyFile(rpl); - verifyCrcs(rpl); - verifyFileBounds(rpl); - verifyRelocationTypes(rpl); - verifySectionAlignment(rpl); - verifySectionOrder(rpl); - - // Format shit - if (dumpElfHeader) { - printHeader(rpl); - } - - if (dumpSectionSummary) { - printSectionSummary(rpl); - } - - // Print section data - for (auto i = 0u; i < rpl.sections.size(); ++i) { - auto §ion = rpl.sections[i]; - auto printSectionHeader = [&](){ - fmt::print( - "Section {}: {}, {}, {} bytes\n", - i, formatSHT(section.header.type), section.name, section.data.size()); - }; - - switch (section.header.type) { - case elf::SHT_NULL: - case elf::SHT_NOBITS: - // Print nothing - break; - case elf::SHT_RELA: - if (!dumpSectionRela) { - continue; - } - - printSectionHeader(); - printRela(rpl, section); - break; - case elf::SHT_SYMTAB: - if (!dumpSectionSymtab) { - continue; - } - - printSectionHeader(); - printSymTab(rpl, section); - break; - case elf::SHT_STRTAB: - break; - case elf::SHT_PROGBITS: - break; - case elf::SHT_RPL_EXPORTS: - if (!dumpSectionRplExports) { - continue; - } - - printSectionHeader(); - printRplExports(rpl, section); - break; - case elf::SHT_RPL_IMPORTS: - if (!dumpSectionRplImports) { - continue; - } - - printSectionHeader(); - printRplImports(rpl, section); - break; - case elf::SHT_RPL_CRCS: - if (!dumpSectionRplCrcs) { - continue; - } - - printSectionHeader(); - printRplCrcs(rpl, section); - break; - case elf::SHT_RPL_FILEINFO: - if (!dumpSectionRplFileinfo) { - continue; - } - - printSectionHeader(); - printFileInfo(rpl, section); - break; - } - } - - if (options.has("exports-def")) { - auto output = options.get("exports-def"); - if (!generateExportsDef(rpl, getFileBasename(path), output)) { - return -1; - } - } - - return 0; -} diff --git a/tools/readrpl/print.cpp b/tools/readrpl/print.cpp deleted file mode 100644 index cb8f97205..000000000 --- a/tools/readrpl/print.cpp +++ /dev/null @@ -1,477 +0,0 @@ -#include "print.h" -#include -#include - -static std::string -formatET(uint32_t type) -{ - switch (type) { - case elf::ET_NONE: - return "ET_NONE"; - case elf::ET_REL: - return "ET_REL"; - case elf::ET_EXEC: - return "ET_EXEC"; - case elf::ET_DYN: - return "ET_DYN"; - case elf::ET_CORE: - return "ET_CORE"; - case elf::ET_CAFE_RPL: - return "ET_CAFE_RPL"; - default: - return fmt::format("{}", type); - } -} - -static std::string -formatEM(uint32_t machine) -{ - switch (machine) { - case elf::EM_PPC: - return "EM_PPC"; - default: - return fmt::format("{}", machine); - } -} - -static std::string -formatEABI(uint32_t eabi) -{ - switch (eabi) { - case elf::EABI_CAFE: - return "EABI_CAFE"; - default: - return fmt::format("{}", eabi); - } -} - -static std::string -formatSHF(uint32_t flags) -{ - std::string result = ""; - - if (flags & elf::SHF_WRITE) { - result += "W"; - } - - if (flags & elf::SHF_ALLOC) { - result += "A"; - } - - if (flags & elf::SHF_EXECINSTR) { - result += "X"; - } - - if (flags & elf::SHF_DEFLATED) { - result += "Z"; - } - - return result; -} - -std::string -formatSHT(uint32_t type) -{ - switch (type) { - case elf::SHT_NULL: - return "SHT_NULL"; - case elf::SHT_PROGBITS: - return "SHT_PROGBITS"; - case elf::SHT_SYMTAB: - return "SHT_SYMTAB"; - case elf::SHT_STRTAB: - return "SHT_STRTAB"; - case elf::SHT_RELA: - return "SHT_RELA"; - case elf::SHT_HASH: - return "SHT_HASH"; - case elf::SHT_DYNAMIC: - return "SHT_DYNAMIC"; - case elf::SHT_NOTE: - return "SHT_NOTE"; - case elf::SHT_NOBITS: - return "SHT_NOBITS"; - case elf::SHT_REL: - return "SHT_REL"; - case elf::SHT_SHLIB: - return "SHT_SHLIB"; - case elf::SHT_DYNSYM: - return "SHT_DYNSYM"; - case elf::SHT_INIT_ARRAY: - return "SHT_INIT_ARRAY"; - case elf::SHT_FINI_ARRAY: - return "SHT_FINI_ARRAY"; - case elf::SHT_PREINIT_ARRAY: - return "SHT_PREINIT_ARRAY"; - case elf::SHT_GROUP: - return "SHT_GROUP"; - case elf::SHT_SYMTAB_SHNDX: - return "SHT_SYMTAB_SHNDX"; - case elf::SHT_LOPROC: - return "SHT_LOPROC"; - case elf::SHT_HIPROC: - return "SHT_HIPROC"; - case elf::SHT_LOUSER: - return "SHT_LOUSER"; - case elf::SHT_RPL_EXPORTS: - return "SHT_RPL_EXPORTS"; - case elf::SHT_RPL_IMPORTS: - return "SHT_RPL_IMPORTS"; - case elf::SHT_RPL_CRCS: - return "SHT_RPL_CRCS"; - case elf::SHT_RPL_FILEINFO: - return "SHT_RPL_FILEINFO"; - case elf::SHT_HIUSER: - return "SHT_HIUSER"; - default: - return fmt::format("{}", type); - } -} - -static std::string -formatRelType(uint32_t type) -{ - switch (type) { - case elf::R_PPC_NONE: - return "NONE"; - case elf::R_PPC_ADDR32: - return "ADDR32"; - case elf::R_PPC_ADDR16_LO: - return "ADDR16_LO"; - case elf::R_PPC_ADDR16_HI: - return "ADDR16_HI"; - case elf::R_PPC_ADDR16_HA: - return "ADDR16_HA"; - case elf::R_PPC_REL24: - return "REL24"; - case elf::R_PPC_REL14: - return "REL14"; - case elf::R_PPC_DTPMOD32: - return "DTPMOD32"; - case elf::R_PPC_DTPREL32: - return "DTPREL32"; - case elf::R_PPC_EMB_SDA21: - return "EMB_SDA21"; - case elf::R_PPC_EMB_RELSDA: - return "EMB_RELSDA"; - case elf::R_PPC_DIAB_SDA21_LO: - return "DIAB_SDA21_LO"; - case elf::R_PPC_DIAB_SDA21_HI: - return "DIAB_SDA21_HI"; - case elf::R_PPC_DIAB_SDA21_HA: - return "DIAB_SDA21_HA"; - case elf::R_PPC_DIAB_RELSDA_LO: - return "DIAB_RELSDA_LO"; - case elf::R_PPC_DIAB_RELSDA_HI: - return "DIAB_RELSDA_HI"; - case elf::R_PPC_DIAB_RELSDA_HA: - return "DIAB_RELSDA_HA"; - case elf::R_PPC_GHS_REL16_HA: - return "GHS_REL16_HA"; - case elf::R_PPC_GHS_REL16_HI: - return "GHS_REL16_HI"; - case elf::R_PPC_GHS_REL16_LO: - return "GHS_REL16_LO"; - default: - return fmt::format("{}", type); - } -} - -static std::string -formatSymType(uint32_t type) -{ - switch (type) { - case elf::STT_NOTYPE: - return "NOTYPE"; - case elf::STT_OBJECT: - return "OBJECT"; - case elf::STT_FUNC: - return "FUNC"; - case elf::STT_SECTION: - return "SECTION"; - case elf::STT_FILE: - return "FILE"; - case elf::STT_COMMON: - return "COMMON"; - case elf::STT_TLS: - return "TLS"; - case elf::STT_LOOS: - return "LOOS"; - case elf::STT_HIOS: - return "HIOS"; - case elf::STT_GNU_IFUNC: - return "GNU_IFUNC"; - default: - return fmt::format("{}", type); - } -} - -static std::string -formatSymBinding(uint32_t type) -{ - switch (type) { - case elf::STB_LOCAL: - return "LOCAL"; - case elf::STB_GLOBAL: - return "GLOBAL"; - case elf::STB_WEAK: - return "WEAK"; - case elf::STB_GNU_UNIQUE: - return "UNIQUE"; - default: - return fmt::format("{}", type); - } -} - -static std::string -formatSymShndx(uint32_t type) -{ - switch (type) { - case elf::SHN_UNDEF: - return "UND"; - case elf::SHN_ABS: - return "ABS"; - case elf::SHN_COMMON: - return "CMN"; - case elf::SHN_XINDEX: - return "UND"; - default: - return fmt::format("{}", type); - } -} - -void -printHeader(const Rpl &rpl) -{ - const auto &header = rpl.header; - fmt::print("ElfHeader\n"); - fmt::print(" {:<20} = 0x{:08X}\n", "magic", header.magic); - fmt::print(" {:<20} = {}\n", "fileClass", header.fileClass); - fmt::print(" {:<20} = {}\n", "encoding", header.encoding); - fmt::print(" {:<20} = {}\n", "elfVersion", header.elfVersion); - fmt::print(" {:<20} = {} 0x{:04x}\n", "abi", formatEABI(header.abi), header.abi); - fmt::print(" {:<20} = {} 0x{:04X}\n", "type", formatET(header.type), header.type); - fmt::print(" {:<20} = {} {}\n", "machine", formatEM(header.machine), header.machine); - fmt::print(" {:<20} = 0x{:X}\n", "version", header.version); - fmt::print(" {:<20} = 0x{:08X}\n", "entry", header.entry); - fmt::print(" {:<20} = 0x{:X}\n", "phoff", header.phoff); - fmt::print(" {:<20} = 0x{:X}\n", "shoff", header.shoff); - fmt::print(" {:<20} = 0x{:X}\n", "flags", header.flags); - fmt::print(" {:<20} = {}\n", "ehsize", header.ehsize); - fmt::print(" {:<20} = {}\n", "phentsize", header.phentsize); - fmt::print(" {:<20} = {}\n", "phnum", header.phnum); - fmt::print(" {:<20} = {}\n", "shentsize", header.shentsize); - fmt::print(" {:<20} = {}\n", "shnum", header.shnum); - fmt::print(" {:<20} = {}\n", "shstrndx", header.shstrndx); -} - -void -printSectionSummary(const Rpl &rpl) -{ - fmt::print("Sections:\n"); - fmt::print( - " {:<4} {:<20} {:<16} {:<8} {:<6} {:<6} {:<2} {:<4} {:<2} {:<4} {:<5}\n", - "[Nr]", "Name", "Type", "Addr", "Off", "Size", "ES", "Flag", "Lk", "Info", "Align"); - - for (auto i = 0u; i < rpl.sections.size(); ++i) { - auto §ion = rpl.sections[i]; - auto type = formatSHT(section.header.type); - auto flags = formatSHF(section.header.flags); - - fmt::print( - " [{:>2}] {:<20} {:<16} {:08X} {:06X} {:06X} {:02X} {:>4} {:>2} {:>4} {:>5}\n", - i, - section.name, - type, - section.header.addr, - section.header.offset, - section.header.size, - section.header.entsize, - flags, - section.header.link, - section.header.info, - section.header.addralign); - } -} - -void -printFileInfo(const Rpl &rpl, - const Section §ion) -{ - auto &info = *reinterpret_cast(section.data.data()); - fmt::print(" {:<20} = 0x{:08X}\n", "version", info.version); - fmt::print(" {:<20} = 0x{:08X}\n", "textSize", info.textSize); - fmt::print(" {:<20} = 0x{:X}\n", "textAlign", info.textAlign); - fmt::print(" {:<20} = 0x{:08X}\n", "dataSize", info.dataSize); - fmt::print(" {:<20} = 0x{:X}\n", "dataAlign", info.dataAlign); - fmt::print(" {:<20} = 0x{:08X}\n", "loadSize", info.loadSize); - fmt::print(" {:<20} = 0x{:X}\n", "loadAlign", info.loadAlign); - fmt::print(" {:<20} = 0x{:X}\n", "tempSize", info.tempSize); - fmt::print(" {:<20} = 0x{:X}\n", "trampAdjust", info.trampAdjust); - fmt::print(" {:<20} = 0x{:X}\n", "trampAddition", info.trampAddition); - fmt::print(" {:<20} = 0x{:08X}\n", "sdaBase", info.sdaBase); - fmt::print(" {:<20} = 0x{:08X}\n", "sda2Base", info.sda2Base); - fmt::print(" {:<20} = 0x{:08X}\n", "stackSize", info.stackSize); - fmt::print(" {:<20} = 0x{:08X}\n", "heapSize", info.heapSize); - - if (info.filename) { - auto filename = section.data.data() + info.filename; - fmt::print(" {:<20} = {}\n", "filename", filename); - } else { - fmt::print(" {:<20} = 0\n", "filename"); - } - - fmt::print(" {:<20} = 0x{:X}\n", "flags", info.flags); - fmt::print(" {:<20} = 0x{:08X}\n", "minSdkVersion", info.minVersion); - fmt::print(" {:<20} = {}\n", "compressionLevel", info.compressionLevel); - fmt::print(" {:<20} = 0x{:X}\n", "fileInfoPad", info.fileInfoPad); - fmt::print(" {:<20} = 0x{:X}\n", "sdkVersion", info.cafeSdkVersion); - fmt::print(" {:<20} = 0x{:X}\n", "sdkRevision", info.cafeSdkRevision); - fmt::print(" {:<20} = 0x{:X}\n", "tlsModuleIndex", info.tlsModuleIndex); - fmt::print(" {:<20} = 0x{:X}\n", "tlsAlignShift", info.tlsAlignShift); - fmt::print(" {:<20} = 0x{:X}\n", "runtimeFileInfoSize", info.runtimeFileInfoSize); - - if (info.tagOffset) { - const char *tags = section.data.data() + info.tagOffset; - fmt::print(" Tags:\n"); - - while (*tags) { - auto key = tags; - tags += strlen(tags) + 1; - auto value = tags; - tags += strlen(tags) + 1; - - fmt::print(" \"{}\" = \"{}\"\n", key, value); - } - } -} - -void -printRela(const Rpl &rpl, - const Section §ion) -{ - fmt::print( - " {:<8} {:<8} {:<16} {:<8} {}\n", "Offset", "Info", "Type", "Value", "Name + Addend"); - - auto &symSec = rpl.sections[section.header.link]; - auto symbols = reinterpret_cast(symSec.data.data()); - auto &symStrTab = rpl.sections[symSec.header.link]; - - auto relas = reinterpret_cast(section.data.data()); - auto count = section.data.size() / sizeof(elf::Rela); - - for (auto i = 0u; i < count; ++i) { - auto &rela = relas[i]; - - auto index = rela.info >> 8; - auto type = rela.info & 0xff; - auto typeName = formatRelType(type); - - auto symbol = symbols[index]; - auto name = reinterpret_cast(symStrTab.data.data()) + symbol.name; - - fmt::print( - " {:08X} {:08X} {:<16} {:08X} {} + {:X}\n", - rela.offset, - rela.info, - typeName, - symbol.value, - name, - rela.addend); - } -} - -void -printSymTab(const Rpl &rpl, - const Section §ion) -{ - auto strTab = reinterpret_cast(rpl.sections[section.header.link].data.data()); - - fmt::print( - " {:<4} {:<8} {:<6} {:<8} {:<8} {:<3} {}\n", - "Num", "Value", "Size", "Type", "Bind", "Ndx", "Name"); - - auto id = 0u; - auto symbols = reinterpret_cast(section.data.data()); - auto count = section.data.size() / sizeof(elf::Symbol); - - for (auto i = 0u; i < count; ++i) { - auto &symbol = symbols[i]; - - auto name = strTab + symbol.name; - auto binding = symbol.info >> 4; - auto type = symbol.info & 0xf; - auto typeName = formatSymType(type); - auto bindingName = formatSymBinding(binding); - auto ndx = formatSymShndx(symbol.shndx); - - fmt::print( - " {:>4} {:08X} {:>6} {:<8} {:<8} {:>3} {}\n", - id, symbol.value, symbol.size, typeName, bindingName, ndx, name); - - ++id; - } -} - -void -printRplImports(const Rpl &rpl, - const Section §ion) -{ - auto sectionIndex = getSectionIndex(rpl, section); - auto import = reinterpret_cast(section.data.data()); - fmt::print(" {:<20} = {}\n", "name", import->name); - fmt::print(" {:<20} = 0x{:08X}\n", "signature", import->signature); - fmt::print(" {:<20} = {}\n", "count", import->count); - - if (import->count) { - for (auto &symSection : rpl.sections) { - if (symSection.header.type != elf::SHT_SYMTAB) { - continue; - } - - auto symbols = reinterpret_cast(symSection.data.data()); - auto count = symSection.data.size() / sizeof(elf::Symbol); - auto strTab = reinterpret_cast(rpl.sections[symSection.header.link].data.data()); - - for (auto i = 0u; i < count; ++i) { - auto &symbol = symbols[i]; - auto type = symbol.info & 0xf; - - if (symbol.shndx == sectionIndex && - (type == elf::STT_FUNC || type == elf::STT_OBJECT)) { - fmt::print(" {}\n", strTab + symbol.name); - } - } - } - } -} - -void -printRplCrcs(const Rpl &rpl, - const Section §ion) -{ - auto crcs = reinterpret_cast(section.data.data()); - auto count = section.data.size() / sizeof(elf::RplCrc); - - for (auto i = 0u; i < count; ++i) { - fmt::print(" [{:>2}] 0x{:08X} {}\n", i, crcs[i].crc, section.name); - } -} - -void -printRplExports(const Rpl &rpl, - const Section §ion) -{ - auto exports = reinterpret_cast(section.data.data()); - auto strTab = section.data.data(); - fmt::print(" {:<20} = 0x{:08X}\n", "signature", exports->signature); - fmt::print(" {:<20} = {}\n", "count", exports->count); - - for (auto i = 0u; i < exports->count; ++i) { - // TLS exports have the high bit set in name for some unknown reason... - auto name = strTab + (exports->exports[i].name & 0x7FFFFFFF); - auto value = exports->exports[i].value; - - fmt::print(" 0x{:08X} {}\n", value, name); - } -} diff --git a/tools/readrpl/print.h b/tools/readrpl/print.h deleted file mode 100644 index ff1e8b9d2..000000000 --- a/tools/readrpl/print.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "readrpl.h" - -std::string -formatSHT(uint32_t type); - -void -printHeader(const Rpl &rpl); - -void -printSectionSummary(const Rpl &rpl); - -void -printFileInfo(const Rpl &rpl, - const Section §ion); - -void -printRela(const Rpl &rpl, - const Section §ion); - -void -printSymTab(const Rpl &rpl, - const Section §ion); - -void -printRplImports(const Rpl &rpl, - const Section §ion); - -void -printRplCrcs(const Rpl &rpl, - const Section §ion); - -void -printRplExports(const Rpl &rpl, - const Section §ion); diff --git a/tools/readrpl/readrpl.h b/tools/readrpl/readrpl.h deleted file mode 100644 index 683fe7b22..000000000 --- a/tools/readrpl/readrpl.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "elf.h" -#include -#include - -struct Section -{ - elf::SectionHeader header; - std::string name; - std::vector data; -}; - -struct Rpl -{ - elf::Header header; - uint32_t fileSize; - std::vector
sections; -}; - -uint32_t -getSectionIndex(const Rpl &rpl, - const Section §ion); diff --git a/tools/readrpl/verify.cpp b/tools/readrpl/verify.cpp deleted file mode 100644 index e8e43e075..000000000 --- a/tools/readrpl/verify.cpp +++ /dev/null @@ -1,586 +0,0 @@ -#include "verify.h" -#include -#include -#include -#include - -static bool -sValidateRelocsAddTable(const Rpl &rpl, - const Section §ion) -{ - const auto &header = section.header; - if (!header.size) { - return true; - } - - auto entsize = static_cast(header.entsize); - if (!entsize) { - entsize = static_cast(sizeof(elf::Rela)); - } - - if (entsize < sizeof(elf::Rela)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002E); - return false; - } - - auto numRelas = (header.size / entsize); - if (!numRelas) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000A); - return false; - } - - if (!header.link || header.link >= rpl.header.shnum) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000B); - return false; - } - - const auto &symbolSection = rpl.sections[header.link]; - if (symbolSection.header.type != elf::SHT_SYMTAB) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000C); - return false; - } - - auto symEntsize = symbolSection.header.entsize ? - static_cast(symbolSection.header.entsize) : - static_cast(sizeof(elf::Symbol)); - if (symEntsize < sizeof(elf::Symbol)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002F); - return false; - } - - if (header.info >= rpl.header.shnum) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000D); - return false; - } - - const auto &targetSection = rpl.sections[header.info]; - if (targetSection.header.type != elf::SHT_NULL) { - auto numSymbols = symbolSection.data.size() / symEntsize; - for (auto i = 0u; i < numRelas; ++i) { - auto rela = reinterpret_cast(section.data.data() + i * entsize); - if (rela->info && (rela->info >> 8) >= numSymbols) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0000F); - return false; - } - } - } - - return true; -} - -static bool -sValidateSymbolTable(const Rpl &rpl, - const Section §ion) -{ - auto result = true; - const auto &header = section.header; - if (!header.size) { - return true; - } - - const Section *symStrTabSection = nullptr; - if (header.link) { - if (header.link >= rpl.header.shnum) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00001); - return false; - } - - symStrTabSection = &rpl.sections[header.link]; - if (symStrTabSection->header.type != elf::SHT_STRTAB) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00002); - return false; - } - } - - auto entsize = header.entsize ? - static_cast(header.entsize) : - static_cast(sizeof(elf::Symbol)); - if (entsize < sizeof(elf::Symbol)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002D); - return false; - } - - auto numSymbols = header.size / entsize; - if (!numSymbols) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00003); - result = false; - } - - for (auto i = 0u; i < numSymbols; ++i) { - auto symbol = reinterpret_cast(section.data.data() + i * entsize); - - if (symStrTabSection && - symbol->name > symStrTabSection->data.size()) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00004); - } - - auto type = symbol->info & 0xF; - if (symbol->shndx && - symbol->shndx < elf::SHN_LORESERVE && - type != elf::STT_SECTION && - type != elf::STT_FILE) { - if (symbol->shndx >= rpl.header.shnum) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00005); - result = false; - } else if (type == elf::STT_OBJECT) { - const auto &targetSection = rpl.sections[symbol->shndx]; - auto targetSectionSize = targetSection.data.size() ? - static_cast(targetSection.data.size()) : - static_cast(targetSection.header.size); - - if (targetSectionSize && - targetSection.header.flags & elf::SHF_ALLOC) { - if (targetSection.header.type == elf::SHT_NULL) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00006); - result = false; - } - - auto position = symbol->value - targetSection.header.addr; - if (position > targetSectionSize || position + symbol->size > targetSectionSize) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00007); - result = false; - } - } - } else if (type == elf::STT_FUNC) { - const auto &targetSection = rpl.sections[symbol->shndx]; - auto targetSectionSize = targetSection.data.size() ? - static_cast(targetSection.data.size()) : - static_cast(targetSection.header.size); - - if (targetSectionSize && - targetSection.header.flags & elf::SHF_ALLOC) { - if (targetSection.header.type == elf::SHT_NULL) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00008); - result = false; - } - - auto position = symbol->value - targetSection.header.addr; - if (position > targetSectionSize || position + symbol->size > targetSectionSize) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00009); - result = false; - } - } - } - } - } - - return result; -} - -/** - * Equivalent to loader.elf ELFFILE_ValidateAndPrepare - */ -bool -verifyFile(const Rpl &rpl) -{ - const auto &header = rpl.header; - auto result = true; - - if (rpl.fileSize < 0x104) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00018); - return false; - } - - if (header.magic != elf::HeaderMagic) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00019); - result = false; - } - - if (header.fileClass != elf::ELFCLASS32) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001A); - result = false; - } - - if (header.elfVersion > elf::EV_CURRENT) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001B); - result = false; - } - - if (!header.machine) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001C); - result = false; - } - - if (!header.version != 1) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001D); - result = false; - } - - auto ehsize = static_cast(header.ehsize); - if (ehsize) { - if (header.ehsize < sizeof(elf::Header)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001E); - result = false; - } - } else { - ehsize = static_cast(sizeof(elf::Header)); - } - - auto phoff = header.phoff; - if (phoff && (phoff < ehsize || phoff >= rpl.fileSize)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0001F); - result = false; - } - - auto shoff = header.shoff; - if (shoff && (shoff < ehsize || shoff >= rpl.fileSize)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00020); - result = false; - } - - if (header.shstrndx && header.shstrndx >= header.shnum) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00021); - result = false; - } - - auto phentsize = header.phentsize ? - static_cast(header.phentsize) : - static_cast(32); - if (header.phoff && - (header.phoff + phentsize * header.phnum) > rpl.fileSize) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00022); - result = false; - } - - auto shentsize = header.shentsize ? - static_cast(header.shentsize) : - static_cast(sizeof(elf::SectionHeader)); - if (header.shoff && - (header.shoff + shentsize * header.shnum) > rpl.fileSize) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00023); - result = false; - } - - for (auto §ion : rpl.sections) { - if (section.header.size && - section.header.type != elf::SHT_NOBITS) { - if (section.header.offset < ehsize) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00024); - result = false; - } - - if (section.header.offset >= shoff && - section.header.offset < (shoff + header.shnum * shentsize)) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD00027); - result = false; - } - } - } - - if (header.shstrndx) { - const auto &shStrTabSection = rpl.sections[header.shstrndx]; - if (shStrTabSection.header.type != elf::SHT_STRTAB) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002A); - result = false; - } else { - for (auto §ion : rpl.sections) { - if (section.header.name >= shStrTabSection.data.size()) { - fmt::format("*** Failed ELF file checks (err=0x{:08X})\n", 0xBAD0002B); - result = false; - } - } - } - } - - for (const auto §ion : rpl.sections) { - if (section.header.type == elf::SHT_RELA) { - result = sValidateRelocsAddTable(rpl, section) && result; - } else if (section.header.type == elf::SHT_SYMTAB) { - result = sValidateSymbolTable(rpl, section) && result; - } - } - - return result; -} - - -/** - * Verify values in SHT_RPL_CRCS - */ -bool -verifyCrcs(const Rpl &rpl) -{ - const elf::RplCrc *crcs = NULL; - auto result = true; - - for (const auto §ion : rpl.sections) { - if (section.header.type == elf::SHT_RPL_CRCS) { - crcs = reinterpret_cast(section.data.data()); - break; - } - } - - if (!crcs) { - return false; - } - - auto sectionIndex = 0u; - for (const auto §ion : rpl.sections) { - auto crc = uint32_t { 0u }; - if (section.header.type != elf::SHT_RPL_CRCS && - section.data.size()) { - crc = crc32(0, Z_NULL, 0); - crc = crc32(crc, reinterpret_cast(section.data.data()), section.data.size()); - } - - if (crc != crcs[sectionIndex].crc) { - fmt::print("Unexpected crc for section {}, read 0x{:08X} but calculated 0x{:08X}", - sectionIndex, crcs[sectionIndex].crc, crc); - result = false; - } - - sectionIndex++; - } - - return result; -} - - -/** - * Equivalent to loader.elf LiCheckFileBounds - */ -bool -verifyFileBounds(const Rpl &rpl) -{ - auto result = true; - auto dataMin = 0xFFFFFFFFu; - auto dataMax = 0u; - - auto readMin = 0xFFFFFFFFu; - auto readMax = 0u; - - auto textMin = 0xFFFFFFFFu; - auto textMax = 0u; - - auto tempMin = 0xFFFFFFFFu; - auto tempMax = 0u; - - for (const auto §ion : rpl.sections) { - if (section.header.size == 0 || - section.header.type == elf::SHT_RPL_FILEINFO || - section.header.type == elf::SHT_RPL_CRCS || - section.header.type == elf::SHT_NOBITS || - section.header.type == elf::SHT_RPL_IMPORTS) { - continue; - } - - if ((section.header.flags & elf::SHF_EXECINSTR) && - section.header.type != elf::SHT_RPL_EXPORTS) { - textMin = std::min(textMin, section.header.offset); - textMax = std::max(textMax, section.header.offset + section.header.size); - } else { - if (section.header.flags & elf::SHF_ALLOC) { - if (section.header.flags & elf::SHF_WRITE) { - dataMin = std::min(dataMin, section.header.offset); - dataMax = std::max(dataMax, section.header.offset + section.header.size); - } else { - readMin = std::min(readMin, section.header.offset); - readMax = std::max(readMax, section.header.offset + section.header.size); - } - } else { - tempMin = std::min(tempMin, section.header.offset); - tempMax = std::max(tempMax, section.header.offset + section.header.size); - } - } - } - - if (dataMin == 0xFFFFFFFFu) { - dataMin = (rpl.header.shnum * rpl.header.shentsize) + rpl.header.shoff; - dataMax = dataMin; - } - - if (readMin == 0xFFFFFFFFu) { - readMin = dataMax; - readMax = dataMax; - } - - if (textMin == 0xFFFFFFFFu) { - textMin = readMax; - textMax = readMax; - } - - if (tempMin == 0xFFFFFFFFu) { - tempMin = textMax; - tempMax = textMax; - } - - if (dataMin < rpl.header.shoff) { - fmt::print("*** SecHrs, FileInfo, or CRCs in bad spot in file. Return %d.\n", -470026); - result = false; - } - - // Data - if (dataMin > dataMax) { - fmt::print("*** DataMin > DataMax. break.\n"); - result = false; - } - - if (dataMin > readMin) { - fmt::print("*** DataMin > ReadMin. break.\n"); - result = false; - } - - if (dataMax > readMin) { - fmt::print("*** DataMax > ReadMin, break.\n"); - result = false; - } - - // Read - if (readMin > readMax) { - fmt::print("*** ReadMin > ReadMax. break.\n"); - result = false; - } - - if (readMin > textMin) { - fmt::print("*** ReadMin > TextMin. break.\n"); - result = false; - } - - if (readMax > textMin) { - fmt::print("*** ReadMax > TextMin. break.\n"); - result = false; - } - - // Text - if (textMin > textMax) { - fmt::print("*** TextMin > TextMax. break.\n"); - result = false; - } - - if (textMin > tempMin) { - fmt::print("*** TextMin > TempMin. break.\n"); - result = false; - } - - if (textMax > tempMin) { - fmt::print("*** TextMax > TempMin. break.\n"); - result = false; - } - - // Temp - if (tempMin > tempMax) { - fmt::print("*** TempMin > TempMax. break.\n"); - result = false; - } - - if (!result) { - fmt::print("dataMin = 0x{:08X}\n", dataMin); - fmt::print("dataMax = 0x{:08X}\n", dataMax); - fmt::print("readMin = 0x{:08X}\n", readMin); - fmt::print("readMax = 0x{:08X}\n", readMax); - fmt::print("textMin = 0x{:08X}\n", textMin); - fmt::print("textMax = 0x{:08X}\n", textMax); - fmt::print("tempMin = 0x{:08X}\n", tempMin); - fmt::print("tempMax = 0x{:08X}\n", tempMax); - } - - return result; -} - - -/** - * Check that the rpl only uses relocation types which are supported by - * loader.elf - */ -bool -verifyRelocationTypes(const Rpl &rpl) -{ - std::set unsupportedTypes; - - for (auto §ion : rpl.sections) { - if (section.header.type != elf::SHT_RELA) { - continue; - } - - auto &symbolSection = rpl.sections[section.header.link]; - auto &targetSection = rpl.sections[section.header.info]; - auto rels = reinterpret_cast(section.data.data()); - auto numRels = section.data.size() / sizeof(elf::Rela); - - for (auto i = 0u; i < numRels; ++i) { - auto info = rels[i].info; - auto addend = rels[i].addend; - auto offset = rels[i].offset; - auto index = info >> 8; - auto type = info & 0xFF; - - switch (type) { - case elf::R_PPC_NONE: - case elf::R_PPC_ADDR32: - case elf::R_PPC_ADDR16_LO: - case elf::R_PPC_ADDR16_HI: - case elf::R_PPC_ADDR16_HA: - case elf::R_PPC_REL24: - case elf::R_PPC_REL14: - case elf::R_PPC_DTPMOD32: - case elf::R_PPC_DTPREL32: - case elf::R_PPC_EMB_SDA21: - case elf::R_PPC_EMB_RELSDA: - case elf::R_PPC_DIAB_SDA21_LO: - case elf::R_PPC_DIAB_SDA21_HI: - case elf::R_PPC_DIAB_SDA21_HA: - case elf::R_PPC_DIAB_RELSDA_LO: - case elf::R_PPC_DIAB_RELSDA_HI: - case elf::R_PPC_DIAB_RELSDA_HA: - case elf::R_PPC_GHS_REL16_HA: - case elf::R_PPC_GHS_REL16_HI: - case elf::R_PPC_GHS_REL16_LO: - // All valid relocations on Wii U, do nothing - break; - default: - // Only print error once per type - if (!unsupportedTypes.count(type)) { - fmt::print("Unsupported relocation type {}\n", type); - unsupportedTypes.insert(type); - } - } - } - } - - return unsupportedTypes.empty(); -} - - -/** - * Verify that section.addr is aligned by section.addralign - */ -bool -verifySectionAlignment(const Rpl &rpl) -{ - auto result = true; - for (auto §ion : rpl.sections) { - if (!align_check(section.header.addr, section.header.addralign)) { - fmt::print("Unaligned section {}, addr {}, addralign {}", - getSectionIndex(rpl, section), - section.header.addr, - section.header.addralign); - result = false; - } - } - return result; -} - - -bool -verifySectionOrder(const Rpl &rpl) -{ - auto lastSection = rpl.sections[rpl.header.shnum - 1]; - auto penultimateSection = rpl.sections[rpl.header.shnum - 2]; - - - if (lastSection.header.type != elf::SHT_RPL_FILEINFO || - (lastSection.header.flags & elf::SHF_DEFLATED)) { - fmt::print("***shnum-1 section type = 0x{:08X}, flags=0x{:08X}\n", - lastSection.header.type, - lastSection.header.flags); - } - - if (penultimateSection.header.type != elf::SHT_RPL_CRCS || - (penultimateSection.header.flags & elf::SHF_DEFLATED)) { - fmt::print("***shnum-2 section type = 0x{:08X}, flags=0x{:08X}\n", - penultimateSection.header.type, - penultimateSection.header.flags); - } - - return true; -} diff --git a/tools/readrpl/verify.h b/tools/readrpl/verify.h deleted file mode 100644 index 8636f5fbe..000000000 --- a/tools/readrpl/verify.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "readrpl.h" - -bool -verifyFile(const Rpl &rpl); - -bool -verifyCrcs(const Rpl &rpl); - -bool -verifyFileBounds(const Rpl &rpl); - -bool -verifyRelocationTypes(const Rpl &rpl); - -bool -verifySectionAlignment(const Rpl &rpl); - -bool -verifySectionOrder(const Rpl &rpl); diff --git a/tools/rplexportgen/CMakeLists.txt b/tools/rplexportgen/CMakeLists.txt deleted file mode 100644 index 922d0884f..000000000 --- a/tools/rplexportgen/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -project(rplexportgen) - -add_executable(rplexportgen - rplexportgen.cpp) - -target_link_libraries(rplexportgen - zlibstatic) - -install(TARGETS rplexportgen RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/rplexportgen/rplexportgen.cpp b/tools/rplexportgen/rplexportgen.cpp deleted file mode 100644 index d2b9bcf46..000000000 --- a/tools/rplexportgen/rplexportgen.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -.extern __preinit_user - -.section .fexports, "", @0x80000001 -.align 4 - -.long 1 -.long 0x13371337 - -.long __preinit_user -.long 0x10 - -.string "__preinit_user" -.byte 0 - */ - -enum class ReadMode -{ - INVALID, - TEXT, - DATA -}; - -void -writeExports(std::ofstream &out, - bool isData, - const std::vector &exports) -{ - // Calculate signature - uint32_t signature = crc32(0, Z_NULL, 0); - for (const auto &name : exports) { - signature = crc32(signature, reinterpret_cast(name.data()), name.size() + 1); - } - - // Write out .extern to declare the symbols - for (const auto &name : exports) { - out << ".extern " << name << std::endl; - } - out << std::endl; - - // Write out header - if (isData) { - out << ".section .dexports, \"a\", @0x80000001" << std::endl; - } else { - out << ".section .fexports, \"ax\", @0x80000001" << std::endl; - } - - out << ".align 4" << std::endl; - out << std::endl; - - out << ".long " << exports.size() << std::endl; - out << ".long 0x" << std::hex << signature << std::endl; - out << std::endl; - - // Write out each export - auto nameOffset = 8 + 8 * exports.size(); - for (const auto &name : exports) { - out << ".long " << name << std::endl; - out << ".long 0x" << std::hex << nameOffset << std::endl; - nameOffset += name.size() + 1; - } - out << std::endl; - - // Write out the strings - for (const auto &name : exports) { - out << ".string \"" << name << "\"" << std::endl; - out << ".byte 0" << std::endl; - nameOffset += name.size() + 1; - } - out << std::endl; -} - -int main(int argc, char **argv) -{ - std::vector funcExports, dataExports; - ReadMode readMode = ReadMode::INVALID; - - if (argc < 3) { - std::cout << argv[0] << " " << std::endl; - return 0; - } - - { - std::ifstream in; - in.open(argv[1]); - - if (!in.is_open()) { - std::cout << "Could not open file " << argv[1] << " for reading" << std::endl; - return -1; - } - - std::string line; - while (std::getline(in, line)) { - // Trim comments - std::size_t commentOffset = line.find("//"); - if (commentOffset != std::string::npos) { - line = line.substr(0, commentOffset); - } - - // Trim whitespace - line = trim(line); - - // Skip blank lines - if (line.length() == 0) { - continue; - } - - // Look for section headers - if (line[0] == ':') { - if (line.substr(1) == "TEXT") { - readMode = ReadMode::TEXT; - } else if (line.substr(1) == "DATA") { - readMode = ReadMode::DATA; - } else { - std::cout << "Unexpected section type" << std::endl; - return -1; - } - continue; - } - - if (readMode == ReadMode::TEXT) { - funcExports.push_back(line); - } else if (readMode == ReadMode::DATA) { - dataExports.push_back(line); - } else { - std::cout << "Unexpected section data" << std::endl; - return -1; - } - } - } - - // Exports must be in alphabetical order because loader.elf uses binary search - std::sort(funcExports.begin(), funcExports.end()); - std::sort(dataExports.begin(), dataExports.end()); - - { - std::ofstream out; - out.open(argv[2]); - - if (!out.is_open()) { - std::cout << "Could not open file " << argv[2] << " for writing" << std::endl; - return -1; - } - - if (funcExports.size() > 0) { - writeExports(out, false, funcExports); - } - - if (dataExports.size() > 0) { - writeExports(out, true, dataExports); - } - } - - return 0; -} diff --git a/tools/rplimportgen/CMakeLists.txt b/tools/rplimportgen/CMakeLists.txt deleted file mode 100644 index 1e97a6db1..000000000 --- a/tools/rplimportgen/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -project(rplimportgen) - -add_executable(rplimportgen - rplimportgen.cpp) - -target_link_libraries(rplimportgen - zlibstatic) - -install(TARGETS rplimportgen RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/rplimportgen/rplimportgen.cpp b/tools/rplimportgen/rplimportgen.cpp deleted file mode 100644 index 63879ebb0..000000000 --- a/tools/rplimportgen/rplimportgen.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum class ReadMode -{ - INVALID, - TEXT, - DATA -}; - -void -writeExports(std::ofstream &out, - const std::string &moduleName, - bool isData, - const std::vector &exports) -{ - // Align module name up to 8 bytes - auto moduleNameSize = (moduleName.length() + 1 + 7) & ~7; - - // Calculate the data block size - auto exportSecSize = exports.size() * 8; - - if (exportSecSize < moduleNameSize) { - exportSecSize = moduleNameSize; - } - - // Calculate export hash - uint32_t exportsHash = crc32(0, Z_NULL, 0); - - for (auto &exp : exports) { - exportsHash = crc32(exportsHash, reinterpret_cast(exp.data()), exp.size() + 1); - } - - std::array extraHashBytes; - extraHashBytes.fill(0); - exportsHash = crc32(exportsHash, extraHashBytes.data(), extraHashBytes.size()); - - // Setup section data - std::vector secData; - secData.resize(exportSecSize / 4, 0); - memcpy(secData.data(), moduleName.c_str(), moduleName.length()); - - out << std::endl; - - if (isData) { - out << ".section .dimport_" << moduleName << ", \"a\", @0x80000002" << std::endl; - } else { - out << ".section .fimport_" << moduleName << ", \"ax\", @0x80000002" << std::endl; - } - - out << ".align 4" << std::endl; - out << std::endl; - - out << ".long " << exports.size() << std::endl; - out << ".long 0x" << std::hex << exportsHash << std::endl; - out << std::endl; - - const char *type = isData ? "@object" : "@function"; - - for (auto i = 0; i < exportSecSize / 8; ++i) { - if (i < exports.size()) { - out << ".global " << exports[i] << std::endl; - out << ".type " << exports[i] << ", " << type << std::endl; - out << exports[i] << ":" << std::endl; - } - - out << ".long 0x" << std::hex << byte_swap(secData[i * 2 + 0]) << std::endl; - out << ".long 0x" << std::hex << byte_swap(secData[i * 2 + 1]) << std::endl; - out << std::endl; - } -} - -int main(int argc, char **argv) -{ - std::string moduleName; - std::vector funcExports, dataExports; - ReadMode readMode = ReadMode::INVALID; - - if (argc < 3) { - std::cout << argv[0] << " " << std::endl; - return 0; - } - - { - std::ifstream in; - in.open(argv[1]); - - if (!in.is_open()) { - std::cout << "Could not open file " << argv[1] << " for reading" << std::endl; - return -1; - } - - std::string line; - while (std::getline(in, line)) { - // Trim comments - std::size_t commentOffset = line.find("//"); - if (commentOffset != std::string::npos) { - line = line.substr(0, commentOffset); - } - - // Trim whitespace - line = trim(line); - - // Skip blank lines - if (line.length() == 0) { - continue; - } - - // Look for section headers - if (line[0] == ':') { - if (line.substr(1) == "TEXT") { - readMode = ReadMode::TEXT; - } else if (line.substr(1) == "DATA") { - readMode = ReadMode::DATA; - } else if (line.substr(1, 4) == "NAME") { - moduleName = line.substr(6); - } else { - std::cout << "Unexpected section type" << std::endl; - return -1; - } - continue; - } - - if (readMode == ReadMode::TEXT) { - funcExports.push_back(line); - } else if (readMode == ReadMode::DATA) { - dataExports.push_back(line); - } else { - std::cout << "Unexpected section data" << std::endl; - return -1; - } - } - } - - { - std::ofstream out; - out.open(argv[2]); - - if (!out.is_open()) { - std::cout << "Could not open file " << argv[2] << " for writing" << std::endl; - return -1; - } - - if (funcExports.size() > 0) { - writeExports(out, moduleName, false, funcExports); - } - - if (dataExports.size() > 0) { - writeExports(out, moduleName, true, dataExports); - } - } - - return 0; -} diff --git a/tools/udplogserver/CMakeLists.txt b/tools/udplogserver/CMakeLists.txt deleted file mode 100644 index 17e9d1ad0..000000000 --- a/tools/udplogserver/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -project(udplogserver) - -add_executable(udplogserver - main.cpp) - -if(MSVC) - target_link_libraries(udplogserver PRIVATE ws2_32) -endif() - -install(TARGETS udplogserver RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/tools/udplogserver/main.cpp b/tools/udplogserver/main.cpp deleted file mode 100644 index fdec4562b..000000000 --- a/tools/udplogserver/main.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#ifdef _WIN32 -#include -#else -#include -#include -#include -#include -#include -#include -#endif - -#include -#include -#include - -#define SERVER_PORT 4405 - -int main(int argc, char **argv) -{ - struct sockaddr_in addr; - unsigned short port = SERVER_PORT; - - if (argc == 2) { - port = atoi(argv[1]); - } - -#ifdef _WIN32 - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) == SOCKET_ERROR) { - return -1; - } -#endif - - // Create socket - auto fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); -#ifdef _WIN32 - if (fd == INVALID_SOCKET) { - WSACleanup(); -#else - if (fd < 0) { -#endif - return -1; - } - - // Set non blocking -#ifdef _WIN32 - u_long mode = 1; - ioctlsocket(fd, FIONBIO, &mode); -#else - int flags = fcntl(fd, F_GETFL, 0); - fcntl(fd, F_SETFL, flags | O_NONBLOCK); -#endif - - // Bind socket - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(port); - if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -#ifdef _WIN32 - closesocket(fd); - WSACleanup(); -#else - close(fd); -#endif - return -1; - } - - // Receive data - char buffer[2048]; - bool running = true; - - while (running) { - fd_set fdsRead; - FD_ZERO(&fdsRead); - FD_SET(fd, &fdsRead); - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - - if (select(fd + 1, &fdsRead, NULL, NULL, &tv) == 1) { - struct sockaddr_in from; -#ifdef _WIN32 - int fromLen = sizeof(from); -#else - socklen_t fromLen = sizeof(from); -#endif - int recvd = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *) &from, &fromLen); - - if (recvd > 0) { - buffer[recvd] = 0; - std::cout << buffer; - std::cout.flush(); - } - } - } - -#ifdef _WIN32 - closesocket(fd); - WSACleanup(); -#else - close(fd); -#endif - return 0; -}