From b1b99343d6e9be18fac4e0a18705e228fad24efb Mon Sep 17 00:00:00 2001 From: Maschell Date: Sat, 7 May 2022 21:12:18 +0200 Subject: [PATCH] Rewrite of the WUMSLoader to simplify the code and have more memory for modules --- .github/workflows/ci.yml | 2 +- .github/workflows/pr.yml | 13 +- Dockerfile | 4 +- Makefile | 25 +- README.md | 6 +- relocator/src/DynamicLinkingHelper.cpp | 108 ------- relocator/src/DynamicLinkingHelper.h | 66 ---- relocator/src/ModuleDataMinimal.h | 87 ------ relocator/src/ModuleDataPersistence.cpp | 71 ----- relocator/src/ModuleDataPersistence.h | 10 - relocator/src/entry.cpp | 264 ---------------- relocator/src/globals.cpp | 4 - relocator/src/globals.h | 7 - relocator/src/hooks.h | 13 - relocator/src/link.ld | 33 -- relocator/src/utils/logger.c | 141 --------- relocator/src/utils/logger.h | 42 --- source/ElfUtils.cpp | 196 +----------- source/ElfUtils.h | 50 +-- source/fs/CFile.cpp | 173 ----------- source/fs/CFile.hpp | 71 ----- source/globals.h | 15 - source/kernel.cpp | 6 +- source/kernel.h | 4 +- source/main.cpp | 45 +-- source/module/DynamicLinkingHelper.cpp | 111 ------- source/module/DynamicLinkingHelper.h | 65 ---- source/module/ModuleData.cpp | 10 - source/module/ModuleDataPersistence.cpp | 181 ----------- source/module/ModuleDataPersistence.h | 11 - source/module/RelocationData.cpp | 7 - source/pc.s | 9 - source/utils/FileUtils.h | 3 - source/utils/StringTools.cpp | 289 ------------------ source/utils/logger.h | 36 ++- source/utils/utils.c | 38 --- source/utils/utils.h | 41 --- {relocator => wumsloader}/.gitignore | 0 {relocator => wumsloader}/Makefile | 45 +-- {relocator => wumsloader}/README.md | 3 +- .../src}/elfio/elf_types.hpp | 0 {source => wumsloader/src}/elfio/elfio.hpp | 0 .../src}/elfio/elfio_dump.hpp | 0 .../src}/elfio/elfio_dynamic.hpp | 0 .../src}/elfio/elfio_header.hpp | 0 .../src}/elfio/elfio_note.hpp | 0 .../src}/elfio/elfio_relocation.hpp | 0 .../src}/elfio/elfio_section.hpp | 4 +- .../src}/elfio/elfio_segment.hpp | 0 .../src}/elfio/elfio_strings.hpp | 0 .../src}/elfio/elfio_symbols.hpp | 0 .../src}/elfio/elfio_utils.hpp | 0 wumsloader/src/entry.cpp | 189 ++++++++++++ wumsloader/src/entry.h | 7 + {source => wumsloader/src}/fs/DirList.cpp | 0 {source => wumsloader/src}/fs/DirList.h | 0 .../utils => wumsloader/src/fs}/FileUtils.cpp | 17 +- wumsloader/src/fs/FileUtils.h | 4 + wumsloader/src/globals.cpp | 7 + wumsloader/src/globals.h | 25 ++ wumsloader/src/link.ld | 95 ++++++ .../src}/module/ExportData.h | 6 +- .../src}/module/FunctionSymbolData.h | 9 +- {source => wumsloader/src}/module/HookData.h | 0 .../src}/module/ImportRPLInformation.h | 40 +-- .../src}/module/ModuleData.h | 89 +++--- .../src}/module/ModuleDataFactory.cpp | 232 +++++++------- .../src}/module/ModuleDataFactory.h | 15 +- .../src/module/ModuleDataPersistence.cpp | 211 +++++++++++++ wumsloader/src/module/ModuleDataPersistence.h | 15 + .../src}/module/RelocationData.h | 6 +- .../src}/module/SectionInfo.h | 8 +- .../src => wumsloader/src/utils}/ElfUtils.cpp | 46 +-- .../src => wumsloader/src/utils}/ElfUtils.h | 0 wumsloader/src/utils/RelocationUtils.cpp | 102 +++++++ wumsloader/src/utils/RelocationUtils.h | 12 + wumsloader/src/utils/StringTools.cpp | 51 ++++ .../src}/utils/StringTools.h | 63 ++-- {relocator => wumsloader}/src/utils/dynamic.c | 16 + {relocator => wumsloader}/src/utils/dynamic.h | 0 .../src => wumsloader/src/utils}/hooks.cpp | 34 +-- wumsloader/src/utils/hooks.h | 14 + .../src/utils/import_stub.S | 0 {relocator => wumsloader}/src/utils/imports.h | 47 +++ wumsloader/src/utils/logger.c | 38 +++ wumsloader/src/utils/logger.h | 57 ++++ .../src/utils/memory.cpp | 11 +- {relocator => wumsloader}/src/utils/memory.h | 0 88 files changed, 1299 insertions(+), 2476 deletions(-) delete mode 100644 relocator/src/DynamicLinkingHelper.cpp delete mode 100644 relocator/src/DynamicLinkingHelper.h delete mode 100644 relocator/src/ModuleDataMinimal.h delete mode 100644 relocator/src/ModuleDataPersistence.cpp delete mode 100644 relocator/src/ModuleDataPersistence.h delete mode 100644 relocator/src/entry.cpp delete mode 100644 relocator/src/globals.cpp delete mode 100644 relocator/src/globals.h delete mode 100644 relocator/src/hooks.h delete mode 100644 relocator/src/link.ld delete mode 100644 relocator/src/utils/logger.c delete mode 100644 relocator/src/utils/logger.h delete mode 100644 source/fs/CFile.cpp delete mode 100644 source/fs/CFile.hpp delete mode 100644 source/globals.h delete mode 100644 source/module/DynamicLinkingHelper.cpp delete mode 100644 source/module/DynamicLinkingHelper.h delete mode 100644 source/module/ModuleData.cpp delete mode 100644 source/module/ModuleDataPersistence.cpp delete mode 100644 source/module/ModuleDataPersistence.h delete mode 100644 source/module/RelocationData.cpp delete mode 100644 source/pc.s delete mode 100644 source/utils/FileUtils.h delete mode 100644 source/utils/StringTools.cpp delete mode 100644 source/utils/utils.c delete mode 100644 source/utils/utils.h rename {relocator => wumsloader}/.gitignore (100%) rename {relocator => wumsloader}/Makefile (91%) rename {relocator => wumsloader}/README.md (56%) rename {source => wumsloader/src}/elfio/elf_types.hpp (100%) rename {source => wumsloader/src}/elfio/elfio.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_dump.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_dynamic.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_header.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_note.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_relocation.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_section.hpp (98%) rename {source => wumsloader/src}/elfio/elfio_segment.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_strings.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_symbols.hpp (100%) rename {source => wumsloader/src}/elfio/elfio_utils.hpp (100%) create mode 100644 wumsloader/src/entry.cpp create mode 100644 wumsloader/src/entry.h rename {source => wumsloader/src}/fs/DirList.cpp (100%) rename {source => wumsloader/src}/fs/DirList.h (100%) rename {source/utils => wumsloader/src/fs}/FileUtils.cpp (74%) create mode 100644 wumsloader/src/fs/FileUtils.h create mode 100644 wumsloader/src/globals.cpp create mode 100644 wumsloader/src/globals.h create mode 100644 wumsloader/src/link.ld rename {source => wumsloader/src}/module/ExportData.h (70%) rename {source => wumsloader/src}/module/FunctionSymbolData.h (84%) rename {source => wumsloader/src}/module/HookData.h (100%) rename {source => wumsloader/src}/module/ImportRPLInformation.h (51%) rename {source => wumsloader/src}/module/ModuleData.h (63%) rename {source => wumsloader/src}/module/ModuleDataFactory.cpp (63%) rename {source => wumsloader/src}/module/ModuleDataFactory.h (63%) create mode 100644 wumsloader/src/module/ModuleDataPersistence.cpp create mode 100644 wumsloader/src/module/ModuleDataPersistence.h rename {source => wumsloader/src}/module/RelocationData.h (91%) rename {source => wumsloader/src}/module/SectionInfo.h (87%) rename {relocator/src => wumsloader/src/utils}/ElfUtils.cpp (71%) rename {relocator/src => wumsloader/src/utils}/ElfUtils.h (100%) create mode 100644 wumsloader/src/utils/RelocationUtils.cpp create mode 100644 wumsloader/src/utils/RelocationUtils.h create mode 100644 wumsloader/src/utils/StringTools.cpp rename {source => wumsloader/src}/utils/StringTools.h (51%) rename {relocator => wumsloader}/src/utils/dynamic.c (62%) rename {relocator => wumsloader}/src/utils/dynamic.h (100%) rename {relocator/src => wumsloader/src/utils}/hooks.cpp (61%) create mode 100644 wumsloader/src/utils/hooks.h rename {relocator => wumsloader}/src/utils/import_stub.S (100%) rename {relocator => wumsloader}/src/utils/imports.h (51%) create mode 100644 wumsloader/src/utils/logger.c create mode 100644 wumsloader/src/utils/logger.h rename {relocator => wumsloader}/src/utils/memory.cpp (94%) rename {relocator => wumsloader}/src/utils/memory.h (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index deeabd5..b1f5919 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - name: clang-format run: | - docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src + docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src build-binary: runs-on: ubuntu-18.04 needs: clang-format diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d08a892..8d38578 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -9,7 +9,18 @@ jobs: - uses: actions/checkout@v2 - name: clang-format run: | - docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src + docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src + check-build-with-logging: + runs-on: ubuntu-18.04 + needs: clang-format + steps: + - uses: actions/checkout@v2 + - name: build binary with logging + run: | + docker build . -t builder + docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE + docker run --rm -v ${PWD}:/project builder make clean + docker run --rm -v ${PWD}:/project builder make DEBUG=1 build-binary: runs-on: ubuntu-18.04 needs: clang-format diff --git a/Dockerfile b/Dockerfile index 9ec7aa1..e452bbe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -FROM wiiuenv/devkitppc:20211229 +FROM wiiuenv/devkitppc:20220507 -COPY --from=wiiuenv/wiiumodulesystem:20220127 /artifacts $DEVKITPRO +COPY --from=wiiuenv/wiiumodulesystem:20220507 /artifacts $DEVKITPRO WORKDIR project \ No newline at end of file diff --git a/Makefile b/Makefile index 95443f9..deb8d10 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ INCLUDES := source #------------------------------------------------------------------------------- # options for code generation #------------------------------------------------------------------------------- -CFLAGS := -Wall -O2 -ffunction-sections \ +CFLAGS := -Wall -Os -ffunction-sections \ $(MACHDEP) CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ @@ -42,10 +42,17 @@ ASFLAGS := -g $(ARCH) LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map) ifeq ($(DEBUG),1) +export DEBUG=1 CXXFLAGS += -DDEBUG -g CFLAGS += -DDEBUG -g endif +ifeq ($(DEBUG),VERBOSE) +export DEBUG=VERBOSE +CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +endif + LIBS := -lwut -lz #------------------------------------------------------------------------------- @@ -91,7 +98,7 @@ endif export OFILES_BIN := $(addsuffix .o,$(BINFILES)) export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export OFILES := $(OFILES_BIN) $(OFILES_SRC) relocator.elf.o +export OFILES := $(OFILES_BIN) $(OFILES_SRC) wumsloader.elf.o export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ @@ -107,13 +114,13 @@ all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @$(MAKE) --no-print-directory -C relocator + @$(MAKE) --no-print-directory -C wumsloader @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #------------------------------------------------------------------------------- clean: @echo clean ... - make clean -C relocator + make clean -C wumsloader @rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf #------------------------------------------------------------------------------- @@ -126,16 +133,16 @@ DEPENDS := $(OFILES:.o=.d) # main targets #------------------------------------------------------------------------------- -relocator_elf := ../relocator/relocator.elf +wumsloader_elf := ../wumsloader/wumsloader.elf all : $(OUTPUT).rpx -$(relocator_elf): - make -C ../relocator +$(wumsloader_elf): + make -C ../wumsloader $(OUTPUT).rpx : $(OUTPUT).elf $(OUTPUT).elf : $(OFILES) -$(OFILES) : relocator_elf.h +$(OFILES) : wumsloader_elf.h $(OFILES_SRC) : $(HFILES_BIN) @@ -152,7 +159,7 @@ $(OFILES_SRC) : $(HFILES_BIN) @echo $(notdir $<) @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) -relocator_elf.h: $(relocator_elf) +wumsloader_elf.h: $(wumsloader_elf) bin2s -a 32 -H `(echo $( - -dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) { - if (data == nullptr) { - return nullptr; - } - if (functionName == nullptr) { - return nullptr; - } - dyn_linking_function_t *result = nullptr; - for (auto &function : data->functions) { - dyn_linking_function_t *curEntry = &function; - if (strlen(curEntry->functionName) == 0) { - if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) { - DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n"); - return nullptr; - } - strncpy(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH); - result = curEntry; - break; - } - if (strncmp(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH) == 0) { - result = curEntry; - break; - } - } - return result; -} - -dyn_linking_import_t *DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName) { - return getOrAddImport(data, importName, false); -} - -dyn_linking_import_t *DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName) { - return getOrAddImport(data, importName, true); -} - -dyn_linking_import_t *DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData) { - if (importName == nullptr || data == nullptr) { - return nullptr; - } - dyn_linking_import_t *result = nullptr; - for (auto &import : data->imports) { - dyn_linking_import_t *curEntry = &import; - if (strlen(curEntry->importName) == 0) { - if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) { - DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n"); - return nullptr; - } - strncpy(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH); - curEntry->isData = isData; - result = curEntry; - break; - } - if (strncmp(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry->isData == isData)) { - return curEntry; - } - } - return result; -} - -bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, - const std::shared_ptr &relocationData) { - return addRelocationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(), - relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(), - relocationData->getName(), - relocationData->getImportRPLInformation()); -} - -bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, - int32_t addend, void *destination, - const std::string &name, const std::shared_ptr &rplInfo) { - dyn_linking_import_t *importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(), rplInfo->isData()); - if (importInfoGbl == nullptr) { - DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d rpl files to import reached.\n", DYN_LINK_IMPORT_LIST_LENGTH); - return false; - } - - dyn_linking_function_t *functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str()); - if (functionInfo == nullptr) { - DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d function to be relocated reached.\n", DYN_LINK_FUNCTION_LIST_LENGTH); - return false; - } - - return addRelocationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo, - importInfoGbl); -} - -bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, - dyn_linking_function_t *functionName, - dyn_linking_import_t *importInfo) { - for (uint32_t i = 0; i < linking_entry_length; i++) { - dyn_linking_relocation_entry_t *curEntry = &(linking_entries[i]); - if (curEntry->functionEntry != nullptr) { - continue; - } - curEntry->type = type; - curEntry->offset = offset; - curEntry->addend = addend; - curEntry->destination = destination; - curEntry->functionEntry = functionName; - curEntry->importEntry = importInfo; - - return true; - } - return false; -} diff --git a/relocator/src/DynamicLinkingHelper.h b/relocator/src/DynamicLinkingHelper.h deleted file mode 100644 index ea02c95..0000000 --- a/relocator/src/DynamicLinkingHelper.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "../../source/module/RelocationData.h" -#include "utils/logger.h" -#include -#include -#include - -class DynamicLinkingHelper { -public: - /** - Gets the function entry for a given function name. If the function name is not present in the list, it will be added. - - \param functionName Name of the function - \return Returns a pointer to the entry which contains the functionName. Null on error or if the list full. - **/ - static dyn_linking_function_t *getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName); - - /** - Gets the function import entry for a given function name. If the import is not present in the list, it will be added. - This will return entries for _function_ imports. - - \param importName Name of the function - \return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full. - **/ - static dyn_linking_import_t *getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName); - - - /** - Gets the data import entry for a given data name. If the import is not present in the list, it will be added. - This will return entries for _data_ imports. - - \param importName Name of the data - \return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full. - **/ - static dyn_linking_import_t *getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName); - - - /** - Gets the import entry for a given data name and type. If the import is not present in the list, it will be added. - This will return entries for _data_ and _function_ imports, depending on the isData parameter. - - \param importName Name of the data - \param isData Set this to true to return a data import - - \return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full. - **/ - static dyn_linking_import_t *getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData); - - static bool addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, - const std::shared_ptr &relocationData); - - static bool - addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, - void *destination, const std::string &name, - const std::shared_ptr &rplInfo); - - static bool - addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, - dyn_linking_function_t *functionName, dyn_linking_import_t *importInfo); - -private: - DynamicLinkingHelper() = default; - - ~DynamicLinkingHelper() = default; -}; diff --git a/relocator/src/ModuleDataMinimal.h b/relocator/src/ModuleDataMinimal.h deleted file mode 100644 index 464d2e1..0000000 --- a/relocator/src/ModuleDataMinimal.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2018-2021 Maschell - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - ****************************************************************************/ - -#include "../../source/module/HookData.h" -#include "../../source/module/RelocationData.h" -#include - -#pragma once - -class ModuleDataMinimal { -public: - ModuleDataMinimal() = default; - - ~ModuleDataMinimal() = default; - - void setExportName(const std::string &name) { - this->export_name = name; - } - - [[nodiscard]] std::string getExportName() const { - return this->export_name; - } - - void addRelocationData(const std::shared_ptr &relocation_data) { - relocation_data_list.push_back(relocation_data); - } - - [[nodiscard]] const std::vector> &getRelocationDataList() const { - return relocation_data_list; - } - - void addHookData(const std::shared_ptr &data) { - hook_data_list.push_back(data); - } - - [[nodiscard]] const std::vector> &getHookDataList() const { - return hook_data_list; - } - - void setEntrypoint(uint32_t addr) { - this->entrypoint = addr; - } - - [[nodiscard]] uint32_t getEntrypoint() const { - return entrypoint; - } - - [[nodiscard]] bool isInitBeforeRelocationDoneHook() const { - return this->initBeforeRelocationDoneHook; - } - - void setInitBeforeRelocationDoneHook(bool value) { - this->initBeforeRelocationDoneHook = value; - } - - [[nodiscard]] bool isSkipInitFini() const { - return this->skipInitFini; - } - - void setSkipInitFini(bool value) { - this->skipInitFini = value; - } - - bool relocationsDone = false; - -private: - std::vector> relocation_data_list; - std::vector> hook_data_list; - std::string export_name; - uint32_t entrypoint = 0; - bool initBeforeRelocationDoneHook = false; - bool skipInitFini = false; -}; diff --git a/relocator/src/ModuleDataPersistence.cpp b/relocator/src/ModuleDataPersistence.cpp deleted file mode 100644 index 136a83f..0000000 --- a/relocator/src/ModuleDataPersistence.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "ModuleDataPersistence.h" -#include "DynamicLinkingHelper.h" -#include -#include - -std::vector> ModuleDataPersistence::loadModuleData(module_information_t *moduleInformation) { - std::vector> result; - if (moduleInformation == nullptr) { - DEBUG_FUNCTION_LINE("moduleInformation == NULL\n"); - return result; - } - DCFlushRange((void *) moduleInformation, sizeof(module_information_t)); - ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t)); - - int32_t module_count = moduleInformation->number_used_modules; - - if (module_count > MAXIMUM_MODULES) { - DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n", module_count, MAXIMUM_MODULES, MAXIMUM_MODULES); - module_count = MAXIMUM_MODULES; - } - - for (int32_t i = 0; i < module_count; i++) { - // Copy data from struct. - module_information_single_t *module_data = &(moduleInformation->module_data[i]); - auto moduleData = std::make_shared(); - - moduleData->setEntrypoint(module_data->entrypoint); - moduleData->setInitBeforeRelocationDoneHook(module_data->initBeforeRelocationDoneHook); - moduleData->setSkipInitFini(module_data->skipInitFini); - moduleData->setExportName(module_data->module_export_name); - - for (auto &hook_entry : module_data->hook_entries) { - if (hook_entry.target == 0) { - continue; - } - moduleData->addHookData(std::make_shared(static_cast(hook_entry.type), reinterpret_cast(hook_entry.target))); - } - - for (auto &linking_entry : module_data->linking_entries) { - if (linking_entry.destination == nullptr) { - break; - } - dyn_linking_import_t *importEntry = linking_entry.importEntry; - if (importEntry == nullptr) { - DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n"); - continue; - } - if (importEntry->importName == nullptr) { - DEBUG_FUNCTION_LINE("importEntry->importName was NULL, skipping relocation entry\n"); - continue; - } - dyn_linking_function_t *functionEntry = linking_entry.functionEntry; - - if (functionEntry == nullptr) { - DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n"); - continue; - } - if (functionEntry->functionName == nullptr) { - DEBUG_FUNCTION_LINE("functionEntry->functionName was NULL, skipping relocation entry\n"); - continue; - } - auto rplInfo = std::make_shared(importEntry->importName, importEntry->isData); - auto reloc = std::make_shared(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionEntry->functionName, rplInfo); - - moduleData->addRelocationData(reloc); - } - - result.push_back(moduleData); - } - return result; -} diff --git a/relocator/src/ModuleDataPersistence.h b/relocator/src/ModuleDataPersistence.h deleted file mode 100644 index 7b4a9fd..0000000 --- a/relocator/src/ModuleDataPersistence.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "ModuleDataMinimal.h" -#include -#include - -class ModuleDataPersistence { -public: - static std::vector> loadModuleData(module_information_t *moduleInformation); -}; diff --git a/relocator/src/entry.cpp b/relocator/src/entry.cpp deleted file mode 100644 index cec6add..0000000 --- a/relocator/src/entry.cpp +++ /dev/null @@ -1,264 +0,0 @@ -#include "../../source/module/RelocationData.h" -#include "ElfUtils.h" -#include "ModuleDataPersistence.h" -#include "globals.h" -#include "hooks.h" -#include "utils/dynamic.h" -#include "utils/logger.h" -#include "utils/memory.h" -#include -#include -#include -#include -#include -#include -#include -#include - -MEMHeapHandle gHeapHandle __attribute__((section(".data"))) = nullptr; -uint8_t gFunctionsPatched __attribute__((section(".data"))) = 0; -uint8_t gInitCalled __attribute__((section(".data"))) = 0; - -extern "C" void socket_lib_init(); - -std::vector> OrderModulesByDependencies(const std::vector> &loadedModules); - -void CallInitHooksForModule(const std::shared_ptr &curModule); - -extern "C" void doStart(int argc, char **argv); -// We need to wrap it to make sure the main function is called AFTER our code. -// The compiler tries to optimize this otherwise and calling the main function earlier -extern "C" int _start(int argc, char **argv) { - InitFunctionPointers(); - - static uint8_t ucSetupRequired = 1; - if (ucSetupRequired) { - gHeapHandle = MEMCreateExpHeapEx((void *) (MEMORY_REGION_USABLE_HEAP_START), MEMORY_REGION_USABLE_HEAP_END - MEMORY_REGION_USABLE_HEAP_START, 1); - ucSetupRequired = 0; - } - - socket_lib_init(); - log_init(); - - doStart(argc, argv); - - DEBUG_FUNCTION_LINE_VERBOSE("Call real one\n"); - log_deinit(); - - return ((int (*)(int, char **))(*(unsigned int *) 0x1005E040))(argc, argv); -} - -bool doRelocation(std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, bool skipAllocReplacement) { - std::map moduleCache; - for (auto const &curReloc : relocData) { - std::string functionName = curReloc->getName(); - std::string rplName = curReloc->getImportRPLInformation()->getName(); - uint32_t functionAddress = 0; - - for (uint32_t i = 0; i < MAXIMUM_MODULES; i++) { - if (rplName == gModuleData->module_data[i].module_export_name) { - export_data_t *exportEntries = gModuleData->module_data[i].export_entries; - for (uint32_t j = 0; j < EXPORT_ENTRY_LIST_LENGTH; j++) { - if (functionName == exportEntries[j].name) { - functionAddress = (uint32_t) exportEntries[j].address; - } - } - } - } - - if (!skipAllocReplacement) { - if (functionName == "MEMAllocFromDefaultHeap") { - functionAddress = reinterpret_cast(&MEMAlloc); - } else if (functionName == "MEMAllocFromDefaultHeapEx") { - functionAddress = reinterpret_cast(&MEMAllocEx); - } else if (functionName == "MEMFreeToDefaultHeap") { - functionAddress = reinterpret_cast(&MEMFree); - } - } - - if (functionAddress == 0) { - int32_t isData = curReloc->getImportRPLInformation()->isData(); - OSDynLoad_Module rplHandle = nullptr; - if (moduleCache.count(rplName) == 0) { - OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle); - if (err != OS_DYNLOAD_OK || rplHandle == nullptr) { - DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded\n", rplName.c_str()); - // only acquire if not already loaded. - err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle); - if (err != OS_DYNLOAD_OK) { - DEBUG_FUNCTION_LINE("Failed to acquire %s\n", rplName.c_str()); - //return false; - } - } - moduleCache[rplName] = rplHandle; - } - rplHandle = moduleCache.at(rplName); - - OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress); - if (functionAddress == 0) { - OSFatal_printf("Failed to find export %s of %s", functionName.c_str(), rplName.c_str()); - return false; - } - } - if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length, - RELOC_TYPE_IMPORT)) { - DEBUG_FUNCTION_LINE("Relocation failed\n"); - return false; - } - } - - DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t)); - ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t)); - return true; -} - -bool ResolveRelocations(std::vector> &loadedModules, bool skipMemoryMappingModule) { - bool wasSuccessful = true; - - for (auto &curModule : loadedModules) { - DEBUG_FUNCTION_LINE_VERBOSE("Let's do the relocations for %s\n", curModule->getExportName().c_str()); - if (wasSuccessful) { - auto relocData = curModule->getRelocationDataList(); - - // On first usage we can't redirect the alloc functions to our custom heap - // because threads can't run it on it. In order to patch the kernel - // to fully support our memory region, we have to run the FunctionPatcher and MemoryMapping - // once with the default heap. Afterwards we can just rely on the custom heap. - bool skipAllocFunction = skipMemoryMappingModule && (curModule->getExportName() == "homebrew_memorymapping" || curModule->getExportName() == "homebrew_functionpatcher"); - DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d\n", skipAllocFunction); - if (!doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLINE_LIST_LENGTH, skipAllocFunction)) { - DEBUG_FUNCTION_LINE("FAIL\n"); - wasSuccessful = false; - curModule->relocationsDone = false; - } - curModule->relocationsDone = true; - } - } - DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE); - ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE); - return wasSuccessful; -} - -extern "C" void doStart(int argc, char **argv) { - if (!gFunctionsPatched) { - gFunctionsPatched = 1; - } - DEBUG_FUNCTION_LINE("Loading module data\n"); - auto loadedModulesUnordered = ModuleDataPersistence::loadModuleData(gModuleData); - auto loadedModules = OrderModulesByDependencies(loadedModulesUnordered); - - bool applicationEndHookLoaded = false; - for (auto &curModule : loadedModules) { - if (curModule->getExportName() == "homebrew_applicationendshook") { - DEBUG_FUNCTION_LINE_VERBOSE("We have ApplicationEndsHook Module!\n"); - applicationEndHookLoaded = true; - break; - } - } - - // Make sure WUMS_HOOK_APPLICATION_ENDS and WUMS_HOOK_FINI_WUT are called - for (auto &curModule : loadedModules) { - for (auto &curHook : curModule->getHookDataList()) { - if (curHook->getType() == WUMS_HOOK_APPLICATION_ENDS || curHook->getType() == WUMS_HOOK_FINI_WUT_DEVOPTAB) { - if (!applicationEndHookLoaded) { - OSFatal_printf("%s requires module homebrew_applicationendshook", curModule->getExportName().c_str()); - } - } - } - } - - DEBUG_FUNCTION_LINE_VERBOSE("Number of modules %d\n", gModuleData->number_used_modules); - if (!gInitCalled) { - gInitCalled = 1; - - DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions\n"); - ResolveRelocations(loadedModules, true); - - for (auto &curModule : loadedModules) { - if (curModule->isInitBeforeRelocationDoneHook()) { - CallInitHooksForModule(curModule); - } - } - - DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook\n"); - CallHook(loadedModules, WUMS_HOOK_RELOCATIONS_DONE); - - for (auto &curModule : loadedModules) { - if (!curModule->isInitBeforeRelocationDoneHook()) { - CallInitHooksForModule(curModule); - } - } - } else { - DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations and replace alloc functions\n"); - ResolveRelocations(loadedModules, false); - CallHook(loadedModules, WUMS_HOOK_RELOCATIONS_DONE); - } - - CallHook(loadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB); - CallHook(loadedModules, WUMS_HOOK_INIT_WUT_SOCKETS); - CallHook(loadedModules, WUMS_HOOK_APPLICATION_STARTS); -} - -void CallInitHooksForModule(const std::shared_ptr &curModule) { - CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC); - CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB); - CallHook(curModule, WUMS_HOOK_INIT_WUT_STDCPP); - CallHook(curModule, WUMS_HOOK_INIT_WUT_DEVOPTAB); - CallHook(curModule, WUMS_HOOK_INIT_WUT_SOCKETS); - CallHook(curModule, WUMS_HOOK_INIT_WRAPPER, !curModule->isSkipInitFini()); - CallHook(curModule, WUMS_HOOK_INIT); -} - -std::vector> OrderModulesByDependencies(const std::vector> &loadedModules) { - std::vector> finalOrder; - std::vector loadedModulesExportNames; - std::vector loadedModulesEntrypoints; - - while (true) { - bool canBreak = true; - bool weDidSomething = false; - for (auto const &curModule : loadedModules) { - if (std::find(loadedModulesEntrypoints.begin(), loadedModulesEntrypoints.end(), curModule->getEntrypoint()) != loadedModulesEntrypoints.end()) { - // DEBUG_FUNCTION_LINE("%s [%08X] is already loaded\n", curModule->getExportName().c_str(), curModule->getEntrypoint()); - continue; - } - canBreak = false; - DEBUG_FUNCTION_LINE_VERBOSE("Check if we can load %s\n", curModule->getExportName().c_str()); - std::vector importsFromOtherModules; - for (const auto &curReloc : curModule->getRelocationDataList()) { - std::string curRPL = curReloc->getImportRPLInformation()->getName(); - if (curRPL.rfind("homebrew", 0) == 0) { - if (std::find(importsFromOtherModules.begin(), importsFromOtherModules.end(), curRPL) != importsFromOtherModules.end()) { - // is already in vector - } else { - DEBUG_FUNCTION_LINE_VERBOSE("%s is importing from %s\n", curModule->getExportName().c_str(), curRPL.c_str()); - importsFromOtherModules.push_back(curRPL); - } - } - } - bool canLoad = true; - for (auto &curImportRPL : importsFromOtherModules) { - if (std::find(loadedModulesExportNames.begin(), loadedModulesExportNames.end(), curImportRPL) != loadedModulesExportNames.end()) { - - } else { - DEBUG_FUNCTION_LINE_VERBOSE("We can't load the module, because %s is not loaded yet\n", curImportRPL.c_str()); - canLoad = false; - break; - } - } - if (canLoad) { - weDidSomething = true; - DEBUG_FUNCTION_LINE_VERBOSE("We can load: %s\n", curModule->getExportName().c_str()); - finalOrder.push_back(curModule); - loadedModulesExportNames.push_back(curModule->getExportName()); - loadedModulesEntrypoints.push_back(curModule->getEntrypoint()); - } - } - if (canBreak) { - break; - } else if (!weDidSomething) { - OSFatal_printf("Failed to resolve dependencies."); - } - } - return finalOrder; -} \ No newline at end of file diff --git a/relocator/src/globals.cpp b/relocator/src/globals.cpp deleted file mode 100644 index c386250..0000000 --- a/relocator/src/globals.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "globals.h" - -uint32_t MemoryMappingEffectiveToPhysicalPTR = 0; -uint32_t MemoryMappingPhysicalToEffectivePTR = 0; \ No newline at end of file diff --git a/relocator/src/globals.h b/relocator/src/globals.h deleted file mode 100644 index 92cb3f7..0000000 --- a/relocator/src/globals.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "../../source/globals.h" -#include - -extern uint32_t MemoryMappingEffectiveToPhysicalPTR; -extern uint32_t MemoryMappingPhysicalToEffectivePTR; \ No newline at end of file diff --git a/relocator/src/hooks.h b/relocator/src/hooks.h deleted file mode 100644 index 341aae7..0000000 --- a/relocator/src/hooks.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "ModuleDataMinimal.h" -#include -#include - -void CallHook(const std::vector> &modules, wums_hook_type_t type, bool condition); - -void CallHook(const std::vector> &modules, wums_hook_type_t type); - -void CallHook(const std::shared_ptr &module, wums_hook_type_t type, bool condition); - -void CallHook(const std::shared_ptr &module, wums_hook_type_t type); diff --git a/relocator/src/link.ld b/relocator/src/link.ld deleted file mode 100644 index c6da198..0000000 --- a/relocator/src/link.ld +++ /dev/null @@ -1,33 +0,0 @@ -OUTPUT(loader.elf); - -ENTRY(_start); - -SECTIONS { - . = 0x00809000; - .text : { - *(.kernel_code*); - *(.text*); - /* Tell linker to not garbage collect this section as it is not referenced anywhere */ - KEEP(*(.kernel_code*)); - } - .sdata : { - *(.sdata*) - } - .data : { - *(.data*) - } - .rodata : { - *(.rodata*) - } - .sbss : { - *(.sbss*) - } - .bss : { - *(.bss*) - } - /DISCARD/ : { - *(*); - } -} - -ASSERT((SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.sdata) + SIZEOF(.rodata) + SIZEOF(.sbss) + SIZEOF(.bss)) < 0x77000, "Memory overlapping with modules."); diff --git a/relocator/src/utils/logger.c b/relocator/src/utils/logger.c deleted file mode 100644 index fa73f31..0000000 --- a/relocator/src/utils/logger.c +++ /dev/null @@ -1,141 +0,0 @@ -#include "logger.h" -#include -#include -#include -#include -#include -#include -#include -#include - -static int log_socket __attribute__((section(".data"))) = -1; -static struct sockaddr_in connect_addr __attribute__((section(".data"))); -static volatile int log_lock __attribute__((section(".data"))) = 0; - -#define SOL_SOCKET -1 - - -#define SOCK_DGRAM 2 - - -#define INADDR_ANY 0 -#define INADDR_BROADCAST 0xFFFFFFFF - -#define PF_UNSPEC 0 -#define PF_INET 2 -#define PF_INET6 23 - -#define AF_UNSPEC PF_UNSPEC -#define AF_INET PF_INET -#define AF_INET6 PF_INET6 - -#define IPPROTO_UDP 17 - -#define SO_BROADCAST 0x0020 // broadcast - -typedef uint16_t sa_family_t; - -struct in_addr { - unsigned int s_addr; -}; - -struct sockaddr { - sa_family_t sa_family; - char sa_data[]; -}; - -struct sockaddr_in { - unsigned short sin_family; - unsigned short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; -}; - -typedef uint32_t socklen_t; - -extern int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); - -extern int socket(int domain, int type, int protocol); - -extern int socketclose(int sockfd); - -extern int sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); - -extern uint32_t htonl(uint32_t val); - -void log_init() { - int broadcastEnable = 1; - log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (log_socket < 0) - return; - - setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); - - memset(&connect_addr, 0, sizeof(struct sockaddr_in)); - connect_addr.sin_family = AF_INET; - connect_addr.sin_port = 4405; - connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); -} - -void log_deinit() { - if (log_socket < 0) { - return; - } - if (socketclose(log_socket) != 0) { - return; - } -} - -void log_print(const char *str) { - OSReport(str); - // socket is always 0 initially as it is in the BSS - if (log_socket < 0) { - return; - } - - while (log_lock) { - OSSleepTicks(OSMicrosecondsToTicks(1000)); - } - log_lock = 1; - - int len = strlen(str); - int ret; - while (len > 0) { - int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet - ret = sendto(log_socket, str, block, 0, (struct sockaddr *) &connect_addr, sizeof(struct sockaddr_in)); - if (ret < 0) - break; - - len -= ret; - str += ret; - } - - log_lock = 0; -} - -void OSFatal_printf(const char *format, ...) { - char tmp[512]; - tmp[0] = 0; - va_list va; - va_start(va, format); - if ((vsprintf(tmp, format, va) >= 0)) { - OSFatal(tmp); - } - va_end(va); -} - -void log_printf(const char *format, ...) { - if (log_socket < 0) { - return; - } - - char tmp[512]; - tmp[0] = 0; - - va_list va; - va_start(va, format); - if ((vsprintf(tmp, format, va) >= 0)) { - log_print(tmp); - } - va_end(va); -} diff --git a/relocator/src/utils/logger.h b/relocator/src/utils/logger.h deleted file mode 100644 index cd5c631..0000000 --- a/relocator/src/utils/logger.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __LOGGER_H_ -#define __LOGGER_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -void log_init(); - -void log_deinit(void); - -void log_print(const char *str); - -void log_printf(const char *format, ...); - -void OSFatal_printf(const char *format, ...); - -#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) - -#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \ - do { \ - OSFatal_printf("[%s]%s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0) - -#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \ - do { \ - log_printf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0) - -#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) \ - do { \ - log_printf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/ElfUtils.cpp b/source/ElfUtils.cpp index 4c8692c..8e7217d 100644 --- a/source/ElfUtils.cpp +++ b/source/ElfUtils.cpp @@ -1,53 +1,6 @@ +#include "../wumsloader/src/elfio/elf_types.hpp" #include "utils/logger.h" #include -#include -#include -#include -#include -#include - -#include "ElfUtils.h" -#include "elfio/elfio.hpp" - -int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut) { - char path[256]; - int result = 0; - char *sdRootPath = nullptr; - if (!WHBMountSdCard()) { - DEBUG_FUNCTION_LINE("Failed to mount SD Card..."); - result = -1; - goto exit; - } - - sdRootPath = WHBGetSdCardMountPath(); - sprintf(path, "%s/%s", sdRootPath, relativefilepath); - - DEBUG_FUNCTION_LINE("Loading file %s.", path); - - *fileOut = WHBReadWholeFile(path, sizeOut); - if (!(*fileOut)) { - result = -2; - DEBUG_FUNCTION_LINE("WHBReadWholeFile(%s) returned NULL", path); - goto exit; - } - -exit: - WHBUnmountSdCard(); - return result; -} - -uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath) { - char *elf_data = nullptr; - uint32_t fileSize = 0; - if (LoadFileToMem(relativePath, &elf_data, &fileSize) != 0) { - OSFatal("Failed to load hook_payload.elf from the SD Card."); - } - uint32_t result = load_loader_elf(baseAddress, elf_data, fileSize); - - MEMFreeToDefaultHeap((void *) elf_data); - - return result; -} uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize) { ELFIO::Elf32_Ehdr *ehdr; @@ -105,149 +58,4 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi } return ehdr->e_entry; -} - -// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144 -bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, - RelocationType reloc_type) { - if (type == R_PPC_NONE) { - return true; - } - auto target = destination + offset; - auto value = symbol_addr + addend; - - - auto relValue = value - static_cast(target); - - switch (type) { - case R_PPC_NONE: - break; - case R_PPC_ADDR32: - *((uint32_t *) (target)) = value; - break; - case R_PPC_ADDR16_LO: - *((uint16_t *) (target)) = static_cast(value & 0xFFFF); - break; - case R_PPC_ADDR16_HI: - *((uint16_t *) (target)) = static_cast(value >> 16); - break; - case R_PPC_ADDR16_HA: - *((uint16_t *) (target)) = static_cast((value + 0x8000) >> 16); - break; - case R_PPC_DTPMOD32: - DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n"); - //*((int32_t *)(target)) = tlsModuleIndex; - break; - case R_PPC_DTPREL32: - *((uint32_t *) (target)) = value; - break; - case R_PPC_GHS_REL16_HA: - *((uint16_t *) (target)) = static_cast((relValue + 0x8000) >> 16); - break; - case R_PPC_GHS_REL16_HI: - *((uint16_t *) (target)) = static_cast(relValue >> 16); - break; - case R_PPC_GHS_REL16_LO: - *((uint16_t *) (target)) = static_cast(relValue & 0xFFFF); - break; - case R_PPC_REL14: { - auto distance = static_cast(value) - static_cast(target); - if (distance > 0x7FFC || distance < -0x7FFC) { - DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target."); - return false; - } - - if (distance & 3) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040); - return false; - } - - if ((distance >= 0 && (distance & 0xFFFF8000)) || - (distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040); - return false; - } - - *(int32_t *) target = (*(int32_t *) target & 0xFFBF0003) | (distance & 0x0000fffc); - break; - } - case R_PPC_REL24: { - // if (isWeakSymbol && !symbolValue) { - // symbolValue = static_cast(target); - // value = symbolValue + addend; - // } - auto distance = static_cast(value) - static_cast(target); - if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) { - if (trampoline_data == nullptr) { - DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n"); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance); - return false; - } else { - relocation_trampoline_entry_t *freeSlot = nullptr; - for (uint32_t i = 0; i < trampoline_data_length; i++) { - // We want to override "old" relocations of imports - // Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS. - // When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE - // so they can be overridden/updated/reused on the next application launch. - // - // Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded. - if (trampoline_data[i].status == RELOC_TRAMP_FREE || - trampoline_data[i].status == RELOC_TRAMP_IMPORT_DONE) { - freeSlot = &(trampoline_data[i]); - break; - } - } - if (freeSlot == nullptr) { - DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n"); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0]))); - return false; - } - if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) { - DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer)."); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0]))); - return false; - } - - freeSlot->trampoline[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h - freeSlot->trampoline[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l - freeSlot->trampoline[2] = 0x7D6903A6; // mtctr r11 - freeSlot->trampoline[3] = 0x4E800420; // bctr - DCFlushRange((void *) freeSlot->trampoline, sizeof(freeSlot->trampoline)); - ICInvalidateRange((unsigned char *) freeSlot->trampoline, sizeof(freeSlot->trampoline)); - - if (reloc_type == RELOC_TYPE_FIXED) { - freeSlot->status = RELOC_TRAMP_FIXED; - } else { - // Relocations for the imports may be overridden - freeSlot->status = RELOC_TRAMP_IMPORT_DONE; - } - auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]); - value = symbolValue + addend; - distance = static_cast(value) - static_cast(target); - } - } - - if (distance & 3) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022); - return false; - } - - if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040); - return false; - } - - if (distance >= 0 && (distance & 0xFE000000)) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040); - return false; - } - - *(int32_t *) target = (*(int32_t *) target & 0xfc000003) | (distance & 0x03fffffc); - break; - } - default: - DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type); - return false; - } - return true; -} +} \ No newline at end of file diff --git a/source/ElfUtils.h b/source/ElfUtils.h index f66ed8e..bbcb6f5 100644 --- a/source/ElfUtils.h +++ b/source/ElfUtils.h @@ -1,52 +1,6 @@ #pragma once -#include -#include -#include +#include +#include -#ifdef __cplusplus -extern "C" { -#endif - -int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut); -uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath); uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize); - -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 -#define R_PPC_ADDR16_LO 4 -#define R_PPC_ADDR16_HI 5 -#define R_PPC_ADDR16_HA 6 -#define R_PPC_REL24 10 -#define R_PPC_REL14 11 -#define R_PPC_DTPMOD32 68 -#define R_PPC_DTPREL32 78 -#define R_PPC_EMB_SDA21 109 -#define R_PPC_EMB_RELSDA 116 -#define R_PPC_DIAB_SDA21_LO 180 -#define R_PPC_DIAB_SDA21_HI 181 -#define R_PPC_DIAB_SDA21_HA 182 -#define R_PPC_DIAB_RELSDA_LO 183 -#define R_PPC_DIAB_RELSDA_HI 184 -#define R_PPC_DIAB_RELSDA_HA 185 -#define R_PPC_GHS_REL16_HA 251 -#define R_PPC_GHS_REL16_HI 252 -#define R_PPC_GHS_REL16_LO 253 - -// Masks for manipulating Power PC relocation targets -#define PPC_WORD32 0xFFFFFFFF -#define PPC_WORD30 0xFFFFFFFC -#define PPC_LOW24 0x03FFFFFC -#define PPC_LOW14 0x0020FFFC -#define PPC_HALF16 0xFFFF - -#ifdef __cplusplus -} -#endif - -class ElfUtils { - -public: - static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, - RelocationType reloc_type); -}; diff --git a/source/fs/CFile.cpp b/source/fs/CFile.cpp deleted file mode 100644 index eb63a80..0000000 --- a/source/fs/CFile.cpp +++ /dev/null @@ -1,173 +0,0 @@ - -#include -#include -#include -#include -#include - -CFile::CFile() { - iFd = -1; - mem_file = NULL; - filesize = 0; - pos = 0; -} - -CFile::CFile(const std::string &filepath, eOpenTypes mode) { - iFd = -1; - this->open(filepath, mode); -} - -CFile::CFile(const uint8_t *mem, int32_t size) { - iFd = -1; - this->open(mem, size); -} - -CFile::~CFile() { - this->close(); -} - -int32_t CFile::open(const std::string &filepath, eOpenTypes mode) { - this->close(); - int32_t openMode = 0; - - // This depend on the devoptab implementation. - // see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference - - switch (mode) { - default: - case ReadOnly: // file must exist - openMode = O_RDONLY; - break; - case WriteOnly: // file will be created / zerod - openMode = O_TRUNC | O_CREAT | O_WRONLY; - break; - case ReadWrite: // file must exist - openMode = O_RDWR; - break; - case Append: // append to file, file will be created if missing. write only - openMode = O_CREAT | O_APPEND | O_WRONLY; - break; - } - - //! Using fopen works only on the first launch as expected - //! on the second launch it causes issues because we don't overwrite - //! the .data sections which is needed for a normal application to re-init - //! this will be added with launching as RPX - iFd = ::open(filepath.c_str(), openMode); - if (iFd < 0) - return iFd; - - - filesize = ::lseek(iFd, 0, SEEK_END); - ::lseek(iFd, 0, SEEK_SET); - - return 0; -} - -int32_t CFile::open(const uint8_t *mem, int32_t size) { - this->close(); - - mem_file = mem; - filesize = size; - - return 0; -} - -void CFile::close() { - if (iFd >= 0) - ::close(iFd); - - iFd = -1; - mem_file = NULL; - filesize = 0; - pos = 0; -} - -int32_t CFile::read(uint8_t *ptr, size_t size) { - if (iFd >= 0) { - int32_t ret = ::read(iFd, ptr, size); - if (ret > 0) - pos += ret; - return ret; - } - - int32_t readsize = size; - - if (readsize > (int64_t) (filesize - pos)) - readsize = filesize - pos; - - if (readsize <= 0) - return readsize; - - if (mem_file != NULL) { - memcpy(ptr, mem_file + pos, readsize); - pos += readsize; - return readsize; - } - - return -1; -} - -int32_t CFile::write(const uint8_t *ptr, size_t size) { - if (iFd >= 0) { - size_t done = 0; - while (done < size) { - int32_t ret = ::write(iFd, ptr, size - done); - if (ret <= 0) - return ret; - - ptr += ret; - done += ret; - pos += ret; - } - return done; - } - - return -1; -} - -int32_t CFile::seek(long int offset, int32_t origin) { - int32_t ret = 0; - int64_t newPos = pos; - - if (origin == SEEK_SET) { - newPos = offset; - } else if (origin == SEEK_CUR) { - newPos += offset; - } else if (origin == SEEK_END) { - newPos = filesize + offset; - } - - if (newPos < 0) { - pos = 0; - } else { - pos = newPos; - } - - if (iFd >= 0) - ret = ::lseek(iFd, pos, SEEK_SET); - - if (mem_file != NULL) { - if (pos > filesize) { - pos = filesize; - } - } - - return ret; -} - -int32_t CFile::fwrite(const char *format, ...) { - char tmp[512]; - tmp[0] = 0; - int32_t result = -1; - - va_list va; - va_start(va, format); - if ((vsprintf(tmp, format, va) >= 0)) { - result = this->write((uint8_t *) tmp, strlen(tmp)); - } - va_end(va); - - - return result; -} diff --git a/source/fs/CFile.hpp b/source/fs/CFile.hpp deleted file mode 100644 index 2bc9dfc..0000000 --- a/source/fs/CFile.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef CFILE_HPP_ -#define CFILE_HPP_ - -#include -#include -#include -#include -#include -#include - -class CFile { -public: - enum eOpenTypes { - ReadOnly, - WriteOnly, - ReadWrite, - Append - }; - - CFile(); - - CFile(const std::string &filepath, eOpenTypes mode); - - CFile(const uint8_t *memory, int32_t memsize); - - virtual ~CFile(); - - int32_t open(const std::string &filepath, eOpenTypes mode); - - int32_t open(const uint8_t *memory, int32_t memsize); - - BOOL isOpen() const { - if (iFd >= 0) - return true; - - if (mem_file) - return true; - - return false; - } - - void close(); - - int32_t read(uint8_t *ptr, size_t size); - - int32_t write(const uint8_t *ptr, size_t size); - - int32_t fwrite(const char *format, ...); - - int32_t seek(long int offset, int32_t origin); - - uint64_t tell() { - return pos; - }; - - uint64_t size() { - return filesize; - }; - - void rewind() { - this->seek(0, SEEK_SET); - }; - -protected: - int32_t iFd; - const uint8_t *mem_file; - uint64_t filesize; - uint64_t pos; -}; - -#endif diff --git a/source/globals.h b/source/globals.h deleted file mode 100644 index 17bd5c5..0000000 --- a/source/globals.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include - -#define MEMORY_REGION_START 0x00800000 -#define MEMORY_REGION_SIZE 0x00800000 - -#define MEMORY_REGION_USABLE_HEAP_START (MEMORY_REGION_START + 0x00080000) // We don't want to override the relocator -#define MEMORY_REGION_USABLE_HEAP_END (MEMORY_REGION_USABLE_HEAP_START + 0x00080000) // heap size is 512 KiB for now - -#define MEMORY_REGION_USABLE_START MEMORY_REGION_USABLE_HEAP_END -#define MEMORY_REGION_USABLE_END 0x00FFF000 // The last 0x1000 bytes are reserved kernel hook - -#define gModuleData ((module_information_t *) (MEMORY_REGION_USABLE_START)) \ No newline at end of file diff --git a/source/kernel.cpp b/source/kernel.cpp index 85e7800..d960542 100644 --- a/source/kernel.cpp +++ b/source/kernel.cpp @@ -1,20 +1,20 @@ #include "kernel.h" #include "ElfUtils.h" -#include "relocator_elf.h" +#include "wumsloader_elf.h" #include #include extern "C" void SCKernelCopyData(uint32_t addr, uint32_t src, uint32_t len); extern "C" void SC_KernelCopyData(uint32_t addr, uint32_t src, uint32_t len); -void SetupRelocator() { +void SetupWUMSLoader() { kern_write((void *) (KERN_SYSCALL_TBL_1 + (0x25 * 4)), (unsigned int) SCKernelCopyData); kern_write((void *) (KERN_SYSCALL_TBL_2 + (0x25 * 4)), (unsigned int) SCKernelCopyData); kern_write((void *) (KERN_SYSCALL_TBL_3 + (0x25 * 4)), (unsigned int) SCKernelCopyData); kern_write((void *) (KERN_SYSCALL_TBL_4 + (0x25 * 4)), (unsigned int) SCKernelCopyData); kern_write((void *) (KERN_SYSCALL_TBL_5 + (0x25 * 4)), (unsigned int) SCKernelCopyData); - uint32_t entryPoint = load_loader_elf(0, (char *) relocator_elf, relocator_elf_size); + uint32_t entryPoint = load_loader_elf(0, (char *) wumsloader_elf, wumsloader_elf_size); unsigned int repl_addr = ADDRESS_main_entry_hook; KernelWriteU32(repl_addr, 0x48000003 | entryPoint); diff --git a/source/kernel.h b/source/kernel.h index c6314df..3d1bd03 100644 --- a/source/kernel.h +++ b/source/kernel.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #define ADDRESS_main_entry_hook 0x0101C56C @@ -10,7 +10,7 @@ #define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL) -void SetupRelocator(); +void SetupWUMSLoader(); void KernelWriteU32(uint32_t addr, uint32_t value); diff --git a/source/main.cpp b/source/main.cpp index 1bd8996..aaea277 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,51 +1,26 @@ -#include - -#include +#include "../wumsloader/src/globals.h" +#include "kernel.h" +#include "utils/logger.h" #include #include -#include "ElfUtils.h" -#include "fs/DirList.h" -#include "globals.h" -#include "kernel.h" -#include "module/ModuleDataFactory.h" -#include "module/ModuleDataPersistence.h" - -extern "C" uint32_t textStart(); extern "C" void __fini(); - int main(int argc, char **argv) { initLogging(); - // We subtract 0x100 to be safe. - uint32_t textSectionStart = textStart() - 0x100; - - memset((void *) gModuleData, 0, sizeof(module_information_t)); - gModuleData->version = MODULE_INFORMATION_VERSION; - std::string basePath = "fs:/vol/external01/wiiu"; if (argc >= 1) { basePath = argv[0]; } - DirList modules(basePath + "/modules", ".wms", DirList::Files, 1); - modules.SortList(); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#pragma GCC diagnostic ignored "-Wstringop-overflow=" + strncpy(ENVRIONMENT_STRING, basePath.c_str(), ENVIRONMENT_PATH_LENGTH - 1); +#pragma GCC diagnostic pop - uint32_t destination_address = ((uint32_t) gModuleData + (sizeof(module_information_t) + 0x0000FFFF)) & 0xFFFF0000; - for (int i = 0; i < modules.GetFilecount(); i++) { - DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i)); - auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i), &destination_address, textSectionStart - destination_address, gModuleData->trampolines, - DYN_LINK_TRAMPOLINE_LIST_LENGTH); - if (moduleData) { - DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i)); - ModuleDataPersistence::saveModuleData(gModuleData, moduleData.value()); - } else { - DEBUG_FUNCTION_LINE("Failed to load %s", modules.GetFilepath(i)); - } - } - - DEBUG_FUNCTION_LINE("Setup relocator"); - SetupRelocator(); + DEBUG_FUNCTION_LINE("Setup wumsloader"); + SetupWUMSLoader(); nn::act::Initialize(); nn::act::SlotNo slot = nn::act::GetSlotNo(); diff --git a/source/module/DynamicLinkingHelper.cpp b/source/module/DynamicLinkingHelper.cpp deleted file mode 100644 index 8b25dfc..0000000 --- a/source/module/DynamicLinkingHelper.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "DynamicLinkingHelper.h" -#include "utils/logger.h" -#include -#include -#include -#include - -dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) { - if (data == nullptr) { - return nullptr; - } - if (functionName == nullptr) { - return nullptr; - } - dyn_linking_function_t *result = nullptr; - for (auto &function : data->functions) { - dyn_linking_function_t *curEntry = &function; - if (strlen(curEntry->functionName) == 0) { - if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) { - DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n"); - return nullptr; - } - strncpy(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH); - result = curEntry; - break; - } - if (strncmp(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH) == 0) { - result = curEntry; - break; - } - } - return result; -} - -dyn_linking_import_t *DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName) { - return getOrAddImport(data, importName, false); -} - -dyn_linking_import_t *DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName) { - return getOrAddImport(data, importName, true); -} - -dyn_linking_import_t *DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData) { - if (importName == nullptr || data == nullptr) { - return nullptr; - } - dyn_linking_import_t *result = nullptr; - for (auto &import : data->imports) { - dyn_linking_import_t *curEntry = &import; - if (strlen(curEntry->importName) == 0) { - if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) { - DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n"); - return nullptr; - } - strncpy(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH); - curEntry->isData = isData; - result = curEntry; - break; - } - if (strncmp(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry->isData == isData)) { - return curEntry; - } - } - return result; -} - -bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, - const std::shared_ptr &relocationData) { - return addReloationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(), relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(), - relocationData->getName(), - relocationData->getImportRPLInformation()); -} - -bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, - int32_t addend, void *destination, - const std::string &name, const std::shared_ptr &rplInfo) { - dyn_linking_import_t *importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(), rplInfo->isData()); - if (importInfoGbl == nullptr) { - DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d rpl files to import reached.\n", DYN_LINK_IMPORT_LIST_LENGTH); - return false; - } - - dyn_linking_function_t *functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str()); - if (functionInfo == nullptr) { - DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d function to be relocated reached.\n", DYN_LINK_FUNCTION_LIST_LENGTH); - return false; - } - - return addRelocationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo, - importInfoGbl); -} - -bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, - dyn_linking_function_t *functionName, - dyn_linking_import_t *importInfo) { - for (uint32_t i = 0; i < linking_entry_length; i++) { - dyn_linking_relocation_entry_t *curEntry = &(linking_entries[i]); - if (curEntry->functionEntry != nullptr) { - continue; - } - curEntry->type = type; - curEntry->offset = offset; - curEntry->addend = addend; - curEntry->destination = destination; - curEntry->functionEntry = functionName; - curEntry->importEntry = importInfo; - - return true; - } - return false; -} diff --git a/source/module/DynamicLinkingHelper.h b/source/module/DynamicLinkingHelper.h deleted file mode 100644 index a00d493..0000000 --- a/source/module/DynamicLinkingHelper.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "RelocationData.h" -#include "utils/logger.h" -#include -#include -#include - -class DynamicLinkingHelper { -public: - /** - Gets the function entry for a given function name. If the function name is not present in the list, it will be added. - - \param functionName Name of the function - \return Returns a pointer to the entry which contains the functionName. Null on error or if the list full. - **/ - static dyn_linking_function_t *getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName); - - /** - Gets the function import entry for a given function name. If the import is not present in the list, it will be added. - This will return entries for _function_ imports. - - \param importName Name of the function - \return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full. - **/ - static dyn_linking_import_t *getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName); - - - /** - Gets the data import entry for a given data name. If the import is not present in the list, it will be added. - This will return entries for _data_ imports. - - \param importName Name of the data - \return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full. - **/ - static dyn_linking_import_t *getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName); - - - /** - Gets the import entry for a given data name and type. If the import is not present in the list, it will be added. - This will return entries for _data_ and _function_ imports, depending on the isData parameter. - - \param importName Name of the data - \param isData Set this to true to return a data import - - \return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full. - **/ - static dyn_linking_import_t *getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData); - - static bool addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, - const std::shared_ptr &relocationData); - - static bool addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, - void *destination, const std::string &name, - const std::shared_ptr &rplInfo); - - static bool - addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination, - dyn_linking_function_t *functionName, dyn_linking_import_t *importInfo); - -private: - DynamicLinkingHelper() = default; - - ~DynamicLinkingHelper() = default; -}; diff --git a/source/module/ModuleData.cpp b/source/module/ModuleData.cpp deleted file mode 100644 index 5e50930..0000000 --- a/source/module/ModuleData.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "ModuleData.h" -#include "utils/StringTools.h" - -std::string ModuleData::toString() const { - std::string res = StringTools::strfmt("Entrypoint %08X, bss: %08X (%d), bss: %08X (%d)\n", getEntrypoint(), getBSSAddr(), getBSSSize(), getSBSSAddr(), getSBSSSize()); - for (auto const &reloc : relocation_data_list) { - res += reloc->toString(); - } - return res; -} diff --git a/source/module/ModuleDataPersistence.cpp b/source/module/ModuleDataPersistence.cpp deleted file mode 100644 index 3923e3b..0000000 --- a/source/module/ModuleDataPersistence.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "ModuleDataPersistence.h" -#include "DynamicLinkingHelper.h" -#include - -bool ModuleDataPersistence::saveModuleData(module_information_t *moduleInformation, const std::shared_ptr &module) { - int32_t module_count = moduleInformation->number_used_modules; - - if (module_count >= MAXIMUM_MODULES) { - DEBUG_FUNCTION_LINE("Reached maximum module count of %d", MAXIMUM_MODULES); - return false; - } - // Copy data to global struct. - module_information_single_t *module_data = &(moduleInformation->module_data[module_count]); - - DEBUG_FUNCTION_LINE("Saving relocation data for module at %08X", module->getEntrypoint()); - // Relocation - auto relocationData = module->getRelocationDataList(); - for (auto const &reloc : relocationData) { - if (!DynamicLinkingHelper::addRelocationEntry(&(moduleInformation->linking_data), module_data->linking_entries, - DYN_LINK_RELOCATION_LIST_LENGTH, reloc)) { - DEBUG_FUNCTION_LINE("Failed to add relocation entry\n"); - return false; - } - } - - auto exportData = module->getExportDataList(); - for (auto const &curExport : exportData) { - bool found = false; - for (auto &export_entry : module_data->export_entries) { - if (export_entry.address == 0) { - export_entry.type = curExport->getType(); - export_entry.name[0] = '\0'; - strncat(export_entry.name, curExport->getName().c_str(), sizeof(export_entry.name) - 1); - export_entry.address = (uint32_t) curExport->getAddress(); - found = true; - break; - } - } - if (!found) { - DEBUG_FUNCTION_LINE("Failed to found enough exports slots"); - break; - } - } - - auto hookData = module->getHookDataList(); - for (auto const &curHook : hookData) { - bool found = false; - for (auto &hook_entry : module_data->hook_entries) { - if (hook_entry.target == 0) { - hook_entry.type = curHook->getType(); - hook_entry.target = (uint32_t) curHook->getTarget(); - found = true; - break; - } - } - if (!found) { - DEBUG_FUNCTION_LINE("Failed to found enough hook slots"); - break; - } - } - - strncpy(module_data->module_export_name, module->getExportName().c_str(), MAXIMUM_EXPORT_MODULE_NAME_LENGTH); - - uint32_t entryCount = module->getFunctionSymbolDataList().size(); - if (entryCount > 0) { - auto ptr = &moduleInformation->function_symbols[moduleInformation->number_used_function_symbols]; - module_data->function_symbol_entries = ptr; - - uint32_t sym_offset = 0; - for (auto &curFuncSym : module->getFunctionSymbolDataList()) { - if (moduleInformation->number_used_function_symbols >= FUNCTION_SYMBOL_LIST_LENGTH) { - DEBUG_FUNCTION_LINE("Function symbol list is full"); - break; - } - module_data->function_symbol_entries[sym_offset].address = curFuncSym->getAddress(); - module_data->function_symbol_entries[sym_offset].name = (char *) curFuncSym->getName(); - module_data->function_symbol_entries[sym_offset].size = curFuncSym->getSize(); - - sym_offset++; - moduleInformation->number_used_function_symbols++; - } - module_data->number_used_function_symbols = sym_offset; - } else { - module_data->function_symbol_entries = nullptr; - module_data->number_used_function_symbols = 0; - } - - module_data->bssAddr = module->getBSSAddr(); - module_data->bssSize = module->getBSSSize(); - module_data->sbssAddr = module->getSBSSAddr(); - module_data->sbssSize = module->getSBSSSize(); - module_data->startAddress = module->getStartAddress(); - module_data->endAddress = module->getEndAddress(); - module_data->entrypoint = module->getEntrypoint(); - module_data->skipInitFini = module->isSkipInitFini(); - module_data->initBeforeRelocationDoneHook = module->isInitBeforeRelocationDoneHook(); - - moduleInformation->number_used_modules++; - - DCFlushRange((void *) moduleInformation, sizeof(module_information_t)); - ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t)); - - return true; -} - -std::vector> ModuleDataPersistence::loadModuleData(module_information_t *moduleInformation) { - std::vector> result; - if (moduleInformation == nullptr) { - DEBUG_FUNCTION_LINE("moduleInformation == NULL\n"); - return result; - } - DCFlushRange((void *) moduleInformation, sizeof(module_information_t)); - ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t)); - - int32_t module_count = moduleInformation->number_used_modules; - if (module_count > MAXIMUM_MODULES) { - DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n", module_count, MAXIMUM_MODULES, MAXIMUM_MODULES); - module_count = MAXIMUM_MODULES; - } - for (int32_t i = 0; i < module_count; i++) { - // Copy data from struct. - module_information_single_t *module_data = &(moduleInformation->module_data[i]); - auto moduleData = std::make_shared(); - moduleData->setBSSLocation(module_data->bssAddr, module_data->bssSize); - moduleData->setSBSSLocation(module_data->sbssAddr, module_data->sbssSize); - moduleData->setEntrypoint(module_data->entrypoint); - moduleData->setStartAddress(module_data->startAddress); - moduleData->setEndAddress(module_data->endAddress); - moduleData->setExportName(module_data->module_export_name); - moduleData->setSkipInitFini(module_data->skipInitFini); - moduleData->setInitBeforeRelocationDoneHook(module_data->initBeforeRelocationDoneHook); - - for (auto &export_entrie : module_data->export_entries) { - export_data_t *export_entry = &export_entrie; - if (export_entry->address == 0) { - continue; - } - auto exportData = std::make_shared(static_cast(export_entry->type), export_entry->name, reinterpret_cast(export_entry->address)); - moduleData->addExportData(exportData); - } - - for (auto &hook_entry : module_data->hook_entries) { - if (hook_entry.target == 0) { - continue; - } - auto hookData = std::make_shared(static_cast(hook_entry.type), reinterpret_cast(hook_entry.target)); - moduleData->addHookData(hookData); - } - - for (auto &linking_entry : module_data->linking_entries) { - if (linking_entry.destination == nullptr) { - break; - } - dyn_linking_import_t *importEntry = linking_entry.importEntry; - if (importEntry == nullptr) { - DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n"); - continue; - } - dyn_linking_function_t *functionEntry = linking_entry.functionEntry; - - if (functionEntry == nullptr) { - DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n"); - continue; - } - auto rplInfo = std::make_shared(importEntry->importName, importEntry->isData); - auto reloc = std::make_shared(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionEntry->functionName, rplInfo); - - moduleData->addRelocationData(reloc); - } - - if (module_data->function_symbol_entries != nullptr && module_data->number_used_function_symbols > 0) { - for (uint32_t j = 0; j < module_data->number_used_function_symbols; j++) { - auto symbol = &module_data->function_symbol_entries[j]; - auto functionSymbolData = std::make_shared(symbol->name, symbol->address, symbol->size); - moduleData->addFunctionSymbolData(functionSymbolData); - } - } - result.push_back(moduleData); - } - return result; -} diff --git a/source/module/ModuleDataPersistence.h b/source/module/ModuleDataPersistence.h deleted file mode 100644 index 2bf4515..0000000 --- a/source/module/ModuleDataPersistence.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "ModuleData.h" -#include - -class ModuleDataPersistence { -public: - static bool saveModuleData(module_information_t *moduleInformation, const std::shared_ptr &module); - - static std::vector> loadModuleData(module_information_t *moduleInformation); -}; diff --git a/source/module/RelocationData.cpp b/source/module/RelocationData.cpp deleted file mode 100644 index 5d91c68..0000000 --- a/source/module/RelocationData.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "RelocationData.h" -#include "utils/StringTools.h" - -std::string RelocationData::toString() const { - return StringTools::strfmt("%s destination: %08X offset: %08X type: %02X addend: %d rplName: %s isData: %d \n", name.c_str(), destination, offset, type, addend, rplInfo->getName().c_str(), - rplInfo->isData()); -} diff --git a/source/pc.s b/source/pc.s deleted file mode 100644 index baa1a0f..0000000 --- a/source/pc.s +++ /dev/null @@ -1,9 +0,0 @@ -.section ".crt0" - .global textStart -textStart: - mflr 4; - bl a - mflr 3; - mtlr 4; - subi 3,3,0x8 -a: blr diff --git a/source/utils/FileUtils.h b/source/utils/FileUtils.h deleted file mode 100644 index e9b0bc7..0000000 --- a/source/utils/FileUtils.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size); \ No newline at end of file diff --git a/source/utils/StringTools.cpp b/source/utils/StringTools.cpp deleted file mode 100644 index 726264c..0000000 --- a/source/utils/StringTools.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - * - * for WiiXplorer 2010 - ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -BOOL StringTools::EndsWith(const std::string &a, const std::string &b) { - if (b.size() > a.size()) - return false; - return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin()); -} - -const char *StringTools::byte_to_binary(int32_t x) { - static char b[9]; - b[0] = '\0'; - - int32_t z; - for (z = 128; z > 0; z >>= 1) { - strcat(b, ((x & z) == z) ? "1" : "0"); - } - - return b; -} - -std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) { - std::string output = input; - size_t position; - while (1) { - position = output.find(toBeRemoved); - if (position == std::string::npos) - break; - output.erase(position, 1); - } - return output; -} - -const char *StringTools::fmt(const char *format, ...) { - static char strChar[512]; - strChar[0] = 0; - - va_list va; - va_start(va, format); - if ((vsprintf(strChar, format, va) >= 0)) { - va_end(va); - return (const char *) strChar; - } - va_end(va); - - return NULL; -} - -const wchar_t *StringTools::wfmt(const char *format, ...) { - static char tmp[512]; - static wchar_t strWChar[512]; - strWChar[0] = 0; - tmp[0] = 0; - - if (!format) - return (const wchar_t *) strWChar; - - if (strcmp(format, "") == 0) - return (const wchar_t *) strWChar; - - va_list va; - va_start(va, format); - if ((vsprintf(tmp, format, va) >= 0)) { - int bt; - int32_t strlength = strlen(tmp); - bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512); - - if (bt > 0) { - strWChar[bt] = 0; - return (const wchar_t *) strWChar; - } - } - va_end(va); - - return NULL; -} - -int32_t StringTools::strprintf(std::string &str, const char *format, ...) { - static char tmp[512]; - tmp[0] = 0; - int32_t result = 0; - - va_list va; - va_start(va, format); - if ((vsprintf(tmp, format, va) >= 0)) { - str = tmp; - result = str.size(); - } - va_end(va); - - return result; -} - -std::string StringTools::strfmt(const char *format, ...) { - std::string str; - static char tmp[512]; - tmp[0] = 0; - - va_list va; - va_start(va, format); - if ((vsprintf(tmp, format, va) >= 0)) { - str = tmp; - } - va_end(va); - - return str; -} - -BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) { - if (!strChar || !dest) - return false; - - int bt; - bt = mbstowcs(dest, strChar, strlen(strChar)); - if (bt > 0) { - dest[bt] = 0; - return true; - } - - return false; -} - -int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) { - if (!string || !compare) - return -1; - - char TokCopy[512]; - strncpy(TokCopy, compare, sizeof(TokCopy)); - TokCopy[511] = '\0'; - - char *strTok = strtok(TokCopy, separator); - - while (strTok != NULL) { - if (strcasecmp(string, strTok) == 0) { - return 0; - } - strTok = strtok(NULL, separator); - } - - return -1; -} - -int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) { - if (!string || !extension) - return -1; - - char *ptr = strrchr(string, seperator); - if (!ptr) - return -1; - - return strcasecmp(ptr + 1, extension); -} - - -std::vector StringTools::stringSplit(const std::string &inValue, const std::string &splitter) { - std::string value = inValue; - std::vector result; - while (true) { - uint32_t index = value.find(splitter); - if (index == std::string::npos) { - result.push_back(value); - break; - } - std::string first = value.substr(0, index); - result.push_back(first); - if (index + splitter.size() == value.length()) { - result.push_back(""); - break; - } - if (index + splitter.size() > value.length()) { - break; - } - value = value.substr(index + splitter.size(), value.length()); - } - return result; -} - - -const char *StringTools::FullpathToFilename(const char *path) { - if (!path) - return path; - - const char *ptr = path; - const char *Filename = ptr; - - while (*ptr != '\0') { - if (ptr[0] == '/' && ptr[1] != '\0') - Filename = ptr + 1; - - ++ptr; - } - - return Filename; -} - -void StringTools::RemoveDoubleSlashs(std::string &str) { - uint32_t length = str.size(); - - //! clear path of double slashes - for (uint32_t i = 1; i < length; ++i) { - if (str[i - 1] == '/' && str[i] == '/') { - str.erase(i, 1); - i--; - length--; - } - } -} - - -// You must free the result if result is non-NULL. -char *StringTools::str_replace(char *orig, char *rep, char *with) { - char *result; // the return string - char *ins; // the next insert point - char *tmp; // varies - int len_rep; // length of rep (the string to remove) - int len_with; // length of with (the string to replace rep with) - int len_front; // distance between rep and end of last rep - int count; // number of replacements - - // sanity checks and initialization - if (!orig || !rep) - return NULL; - len_rep = strlen(rep); - if (len_rep == 0) - return NULL; // empty rep causes infinite loop during count - if (!with) - with = (char *) ""; - len_with = strlen(with); - - // count the number of replacements needed - ins = orig; - for (count = 0; (tmp = strstr(ins, rep)); ++count) { - ins = tmp + len_rep; - } - - tmp = result = (char *) malloc(strlen(orig) + (len_with - len_rep) * count + 1); - - if (!result) - return NULL; - - // first time through the loop, all the variable are set correctly - // from here on, - // tmp points to the end of the result string - // ins points to the next occurrence of rep in orig - // orig points to the remainder of orig after "end of rep" - while (count--) { - ins = strstr(orig, rep); - len_front = ins - orig; - tmp = strncpy(tmp, orig, len_front) + len_front; - tmp = strcpy(tmp, with) + len_with; - orig += len_front + len_rep; // move to next "end of rep" - } - strcpy(tmp, orig); - return result; -} diff --git a/source/utils/logger.h b/source/utils/logger.h index 061d52e..2c80edd 100644 --- a/source/utils/logger.h +++ b/source/utils/logger.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -7,22 +8,33 @@ extern "C" { #endif +#define LOG_APP_TYPE "M" +#define LOG_APP_NAME "WUMSInstaller" + +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) + +#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS) + +#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \ + do { \ + LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ + } while (0) + + #ifdef DEBUG -#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) - +#ifdef VERBOSE_DEBUG +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS) +#else #define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0) +#endif -#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \ - do { \ - WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0) +#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \ - do { \ - WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ - } while (0) +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS) #else @@ -32,6 +44,8 @@ extern "C" { #define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0) +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS) + #endif void initLogging(); diff --git a/source/utils/utils.c b/source/utils/utils.c deleted file mode 100644 index e5a7dcd..0000000 --- a/source/utils/utils.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "utils/logger.h" -#include -#include -#include - -// https://gist.github.com/ccbrown/9722406 -void dumpHex(const void *data, size_t size) { - char ascii[17]; - size_t i, j; - ascii[16] = '\0'; - DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x0000): ", data); - for (i = 0; i < size; ++i) { - WHBLogWritef("%02X ", ((unsigned char *) data)[i]); - if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') { - ascii[i % 16] = ((unsigned char *) data)[i]; - } else { - ascii[i % 16] = '.'; - } - if ((i + 1) % 8 == 0 || i + 1 == size) { - WHBLogWritef(" "); - if ((i + 1) % 16 == 0) { - WHBLogPrintf("| %s ", ascii); - if (i + 1 < size) { - DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x%04X); ", data + i + 1, i + 1); - } - } else if (i + 1 == size) { - ascii[(i + 1) % 16] = '\0'; - if ((i + 1) % 16 <= 8) { - WHBLogWritef(" "); - } - for (j = (i + 1) % 16; j < 16; ++j) { - WHBLogWritef(" "); - } - WHBLogPrintf("| %s ", ascii); - } - } - } -} diff --git a/source/utils/utils.h b/source/utils/utils.h deleted file mode 100644 index 2890779..0000000 --- a/source/utils/utils.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __UTILS_H_ -#define __UTILS_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define LIMIT(x, min, max) \ - ({ \ - typeof(x) _x = x; \ - typeof(min) _min = min; \ - typeof(max) _max = max; \ - (((_x) < (_min)) ? (_min) : ((_x) > (_max)) ? (_max) \ - : (_x)); \ - }) - -#define DegToRad(a) ((a) *0.01745329252f) -#define RadToDeg(a) ((a) *57.29577951f) - -#define ALIGN4(x) (((x) + 3) & ~3) -#define ALIGN32(x) (((x) + 31) & ~31) - -// those work only in powers of 2 -#define ROUNDDOWN(val, align) ((val) & ~(align - 1)) -#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align) - - -#define le16(i) ((((uint16_t) ((i) &0xFF)) << 8) | ((uint16_t) (((i) &0xFF00) >> 8))) -#define le32(i) ((((uint32_t) le16((i) &0xFFFF)) << 16) | ((uint32_t) le16(((i) &0xFFFF0000) >> 16))) -#define le64(i) ((((uint64_t) le32((i) &0xFFFFFFFFLL)) << 32) | ((uint64_t) le32(((i) &0xFFFFFFFF00000000LL) >> 32))) - -//Needs to have log_init() called beforehand. -void dumpHex(const void *data, size_t size); - -#ifdef __cplusplus -} -#endif - -#endif // __UTILS_H_ diff --git a/relocator/.gitignore b/wumsloader/.gitignore similarity index 100% rename from relocator/.gitignore rename to wumsloader/.gitignore diff --git a/relocator/Makefile b/wumsloader/Makefile similarity index 91% rename from relocator/Makefile rename to wumsloader/Makefile index 3230afa..d79b164 100644 --- a/relocator/Makefile +++ b/wumsloader/Makefile @@ -23,6 +23,7 @@ export AR := $(PREFIX)ar export OBJCOPY := $(PREFIX)objcopy WUMS_ROOT := $(DEVKITPRO)/wums +WUT_ROOT := $(DEVKITPRO)/wut #--------------------------------------------------------------------------------- # TARGET is the name of the output @@ -30,10 +31,14 @@ WUMS_ROOT := $(DEVKITPRO)/wums # SOURCES is a list of directories containing source code # INCLUDES is a list of directories containing extra header files #--------------------------------------------------------------------------------- -TARGET := relocator +TARGET := wumsloader BUILD := build BUILD_DBG := $(TARGET)_dbg -SOURCES := src src/utils src/kernel +SOURCES := src \ + src/utils \ + src/kernel \ + src/fs \ + src/module DATA := data @@ -42,10 +47,22 @@ INCLUDES := src #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS := -g -Wall -O3 -ffunction-sections $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__ +CFLAGS := -g -Wall -O0 -ffunction-sections $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__ CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti ASFLAGS := -mregnames -LDFLAGS := -nostartfiles -Wl,--gc-sections +LDFLAGS := -Wl,--gc-sections,--allow-multiple-definition + +ifeq ($(DEBUG),1) +export DEBUG=1 +CXXFLAGS += -DDEBUG -g +CFLAGS += -DDEBUG -g +endif + +ifeq ($(DEBUG),VERBOSE) +export DEBUG=VERBOSE +CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +endif #--------------------------------------------------------------------------------- Q := @ @@ -53,18 +70,13 @@ MAKEFLAGS += --no-print-directory #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -lwums +LIBS := -lwums -lwut -lz #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- -LIBDIRS := $(CURDIR) \ - $(DEVKITPPC)/lib \ - $(DEVKITPRO)/wut \ - $(WUMS_ROOT) \ - $(DEVKITPPC)/lib/gcc/powerpc-eabi/$(GCC_VER) - +LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT) #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional @@ -104,15 +116,10 @@ export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ # build a list of include paths #--------------------------------------------------------------------------------- export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ - -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) -#--------------------------------------------------------------------------------- -# build a list of library paths -#--------------------------------------------------------------------------------- -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ - -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) export OUTPUT := $(CURDIR)/$(TARGET) .PHONY: $(BUILD) clean install diff --git a/relocator/README.md b/wumsloader/README.md similarity index 56% rename from relocator/README.md rename to wumsloader/README.md index 4545692..6517938 100644 --- a/relocator/README.md +++ b/wumsloader/README.md @@ -1,5 +1,4 @@ -# Setup payload - relocator -This is a payload that is bundled with the SetupPayload that handled the relocations for the imports. +# WUMSLoader ## Credits - maschell diff --git a/source/elfio/elf_types.hpp b/wumsloader/src/elfio/elf_types.hpp similarity index 100% rename from source/elfio/elf_types.hpp rename to wumsloader/src/elfio/elf_types.hpp diff --git a/source/elfio/elfio.hpp b/wumsloader/src/elfio/elfio.hpp similarity index 100% rename from source/elfio/elfio.hpp rename to wumsloader/src/elfio/elfio.hpp diff --git a/source/elfio/elfio_dump.hpp b/wumsloader/src/elfio/elfio_dump.hpp similarity index 100% rename from source/elfio/elfio_dump.hpp rename to wumsloader/src/elfio/elfio_dump.hpp diff --git a/source/elfio/elfio_dynamic.hpp b/wumsloader/src/elfio/elfio_dynamic.hpp similarity index 100% rename from source/elfio/elfio_dynamic.hpp rename to wumsloader/src/elfio/elfio_dynamic.hpp diff --git a/source/elfio/elfio_header.hpp b/wumsloader/src/elfio/elfio_header.hpp similarity index 100% rename from source/elfio/elfio_header.hpp rename to wumsloader/src/elfio/elfio_header.hpp diff --git a/source/elfio/elfio_note.hpp b/wumsloader/src/elfio/elfio_note.hpp similarity index 100% rename from source/elfio/elfio_note.hpp rename to wumsloader/src/elfio/elfio_note.hpp diff --git a/source/elfio/elfio_relocation.hpp b/wumsloader/src/elfio/elfio_relocation.hpp similarity index 100% rename from source/elfio/elfio_relocation.hpp rename to wumsloader/src/elfio/elfio_relocation.hpp diff --git a/source/elfio/elfio_section.hpp b/wumsloader/src/elfio/elfio_section.hpp similarity index 98% rename from source/elfio/elfio_section.hpp rename to wumsloader/src/elfio/elfio_section.hpp index 52d3102..d7dd808 100644 --- a/source/elfio/elfio_section.hpp +++ b/wumsloader/src/elfio/elfio_section.hpp @@ -270,7 +270,7 @@ class section_impl : public section ret = inflate(&s, Z_FINISH); if (ret != Z_OK && ret != Z_STREAM_END){ - DEBUG_FUNCTION_LINE("NOOOO"); + DEBUG_FUNCTION_LINE_ERR("inflate section failed."); } inflateEnd(&s); @@ -288,7 +288,7 @@ class section_impl : public section } }else{ set_size(0); - DEBUG_FUNCTION_LINE("Failed to allocate memory."); + DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory."); } } } diff --git a/source/elfio/elfio_segment.hpp b/wumsloader/src/elfio/elfio_segment.hpp similarity index 100% rename from source/elfio/elfio_segment.hpp rename to wumsloader/src/elfio/elfio_segment.hpp diff --git a/source/elfio/elfio_strings.hpp b/wumsloader/src/elfio/elfio_strings.hpp similarity index 100% rename from source/elfio/elfio_strings.hpp rename to wumsloader/src/elfio/elfio_strings.hpp diff --git a/source/elfio/elfio_symbols.hpp b/wumsloader/src/elfio/elfio_symbols.hpp similarity index 100% rename from source/elfio/elfio_symbols.hpp rename to wumsloader/src/elfio/elfio_symbols.hpp diff --git a/source/elfio/elfio_utils.hpp b/wumsloader/src/elfio/elfio_utils.hpp similarity index 100% rename from source/elfio/elfio_utils.hpp rename to wumsloader/src/elfio/elfio_utils.hpp diff --git a/wumsloader/src/entry.cpp b/wumsloader/src/entry.cpp new file mode 100644 index 0000000..d10222e --- /dev/null +++ b/wumsloader/src/entry.cpp @@ -0,0 +1,189 @@ +#include "entry.h" +#include "fs/DirList.h" +#include "globals.h" +#include "module/ModuleDataFactory.h" +#include "module/ModuleDataPersistence.h" +#include "utils/ElfUtils.h" +#include "utils/RelocationUtils.h" +#include "utils/dynamic.h" +#include "utils/hooks.h" +#include "utils/logger.h" +#include +#include +#include + +void CallInitHooksForModule(const std::shared_ptr &curModule); + +std::vector> OrderModulesByDependencies(const std::vector> &loadedModules); + +// We need to wrap it to make sure the main function is called AFTER our code. +// The compiler tries to optimize this otherwise and calling the main function earlier +extern "C" int _start(int argc, char **argv) { + InitFunctionPointers(); + static uint8_t ucSetupRequired = 1; + if (ucSetupRequired) { + gHeapHandle = MEMCreateExpHeapEx((void *) (MEMORY_REGION_USABLE_HEAP_START), MEMORY_REGION_USABLE_HEAP_END - MEMORY_REGION_USABLE_HEAP_START, 1); + if (!gHeapHandle) { + OSFatal("Failed to alloc heap"); + } + + __init(); + ucSetupRequired = 0; + } + + doStart(argc, argv); + + return ((int (*)(int, char **))(*(unsigned int *) 0x1005E040))(argc, argv); +} + +void doStart(int argc, char **argv) { + __init_wut(); + initLogging(); + + if (!gInitCalled) { + gInitCalled = 1; + + std::string basePath = ENVRIONMENT_STRING; + DEBUG_FUNCTION_LINE("We need to load the modules. basePath %s", basePath.c_str()); + DirList modules(basePath + "/modules", ".wms", DirList::Files, 1); + modules.SortList(); + for (int i = 0; i < modules.GetFilecount(); i++) { + DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i)); + auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i)); + if (moduleData) { + DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i)); + gLoadedModules.push_back(std::move(moduleData.value())); + } else { + DEBUG_FUNCTION_LINE_ERR("Failed to load %s", modules.GetFilepath(i)); + } + } + + gModuleInformation = {.version = MODULE_INFORMATION_VERSION}; + ModuleDataPersistence::saveModuleData(&gModuleInformation, gLoadedModules); + + auto orderedModules = OrderModulesByDependencies(gLoadedModules); + + // make sure the plugin backend module is at the end. + auto it = std::find_if(gLoadedModules.begin(), + gLoadedModules.end(), + [](auto &cur) { return std::string_view(cur->getExportName()) == "homebrew_wupsbackend"; }); + if (it != gLoadedModules.end()) { + auto module = *it; + gLoadedModules.erase(it); + gLoadedModules.push_back(module); + } + + bool applicationEndHookLoaded = false; + for (auto &curModule : gLoadedModules) { + if (std::string_view(curModule->getExportName()) == "homebrew_applicationendshook") { + DEBUG_FUNCTION_LINE_VERBOSE("We have ApplicationEndsHook Module!"); + applicationEndHookLoaded = true; + break; + } + } + + // Make sure WUMS_HOOK_APPLICATION_ENDS and WUMS_HOOK_FINI_WUT are called + for (auto &curModule : gLoadedModules) { + for (auto &curHook : curModule->getHookDataList()) { + if (curHook->getType() == WUMS_HOOK_APPLICATION_ENDS || curHook->getType() == WUMS_HOOK_FINI_WUT_DEVOPTAB) { + if (!applicationEndHookLoaded) { + DEBUG_FUNCTION_LINE_ERR("%s requires module homebrew_applicationendshook", curModule->getExportName().c_str()); + OSFatal("module requires module homebrew_applicationendshook"); + } + } + } + } + + DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions"); + ResolveRelocations(gLoadedModules, true); + + for (auto &curModule : gLoadedModules) { + if (curModule->isInitBeforeRelocationDoneHook()) { + CallInitHooksForModule(curModule); + } + } + + DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook"); + CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE); + + for (auto &curModule : gLoadedModules) { + if (!curModule->isInitBeforeRelocationDoneHook()) { + CallInitHooksForModule(curModule); + } + } + } else { + DEBUG_FUNCTION_LINE("Resolve relocations and replace alloc functions"); + ResolveRelocations(gLoadedModules, false); + CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE); + } + + CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB); + CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_SOCKETS); + CallHook(gLoadedModules, WUMS_HOOK_APPLICATION_STARTS); + + deinitLogging(); + __fini_wut(); +} + +void CallInitHooksForModule(const std::shared_ptr &curModule) { + CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC); + CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB); + CallHook(curModule, WUMS_HOOK_INIT_WUT_STDCPP); + CallHook(curModule, WUMS_HOOK_INIT_WUT_DEVOPTAB); + CallHook(curModule, WUMS_HOOK_INIT_WUT_SOCKETS); + CallHook(curModule, WUMS_HOOK_INIT_WRAPPER, !curModule->isSkipInitFini()); + CallHook(curModule, WUMS_HOOK_INIT); +} + +std::vector> OrderModulesByDependencies(const std::vector> &loadedModules) { + std::vector> finalOrder; + std::vector loadedModulesExportNames; + std::vector loadedModulesEntrypoints; + + while (true) { + bool canBreak = true; + bool weDidSomething = false; + for (auto const &curModule : loadedModules) { + if (std::find(loadedModulesEntrypoints.begin(), loadedModulesEntrypoints.end(), curModule->getEntrypoint()) != loadedModulesEntrypoints.end()) { + // DEBUG_FUNCTION_LINE("%s [%08X] is already loaded" curModule->getExportName().c_str(), curModule->getEntrypoint()); + continue; + } + canBreak = false; + DEBUG_FUNCTION_LINE_VERBOSE("Check if we can load %s", curModule->getExportName()); + std::vector importsFromOtherModules; + for (const auto &curReloc : curModule->getRelocationDataList()) { + std::string_view curRPL = curReloc->getImportRPLInformation()->getRPLName(); + if (curRPL == "homebrew_wupsbackend") { + OSFatal("Error: module depends on homebrew_wupsbackend, this is not supported"); + } + if (curRPL.starts_with("homebrew")) { + if (std::find(importsFromOtherModules.begin(), importsFromOtherModules.end(), curRPL) == importsFromOtherModules.end()) { + DEBUG_FUNCTION_LINE_VERBOSE("%s is importing from %s", curModule->getExportName(), curRPL.begin()); + importsFromOtherModules.push_back(curRPL); + } + } + } + bool canLoad = true; + for (auto &curImportRPL : importsFromOtherModules) { + if (std::find(loadedModulesExportNames.begin(), loadedModulesExportNames.end(), curImportRPL) == loadedModulesExportNames.end()) { + DEBUG_FUNCTION_LINE_VERBOSE("We can't load the module, because %s is not loaded yet", curImportRPL.begin()); + canLoad = false; + break; + } + } + if (canLoad) { + weDidSomething = true; + DEBUG_FUNCTION_LINE_VERBOSE("We can load: %s", curModule->getExportName()); + finalOrder.push_back(curModule); + loadedModulesExportNames.emplace_back(curModule->getExportName()); + loadedModulesEntrypoints.push_back(curModule->getEntrypoint()); + } + } + if (canBreak) { + break; + } else if (!weDidSomething) { + OSFatal("Failed to resolve dependencies."); + } + } + return finalOrder; +} \ No newline at end of file diff --git a/wumsloader/src/entry.h b/wumsloader/src/entry.h new file mode 100644 index 0000000..8c36dbc --- /dev/null +++ b/wumsloader/src/entry.h @@ -0,0 +1,7 @@ +#pragma once + +extern "C" void __init(); +extern "C" void __init_wut(); +extern "C" void __fini_wut(); + +void doStart(int argc, char **argv); \ No newline at end of file diff --git a/source/fs/DirList.cpp b/wumsloader/src/fs/DirList.cpp similarity index 100% rename from source/fs/DirList.cpp rename to wumsloader/src/fs/DirList.cpp diff --git a/source/fs/DirList.h b/wumsloader/src/fs/DirList.h similarity index 100% rename from source/fs/DirList.h rename to wumsloader/src/fs/DirList.h diff --git a/source/utils/FileUtils.cpp b/wumsloader/src/fs/FileUtils.cpp similarity index 74% rename from source/utils/FileUtils.cpp rename to wumsloader/src/fs/FileUtils.cpp index aa9b2fa..9bb10fa 100644 --- a/source/utils/FileUtils.cpp +++ b/wumsloader/src/fs/FileUtils.cpp @@ -1,21 +1,22 @@ +#include "utils/logger.h" +#include +#include #include #include -#include -#include -#include +#include #include #define ROUNDDOWN(val, align) ((val) & ~(align - 1)) #define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align) -int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) { +int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size) { //! always initialze input - *inbuffer = NULL; + *inbuffer = nullptr; if (size) { *size = 0; } - int32_t iFd = open(filepath, O_RDONLY); + int32_t iFd = open(filepath.c_str(), O_RDONLY); if (iFd < 0) { return -1; } @@ -23,7 +24,7 @@ int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) uint32_t filesize = lseek(iFd, 0, SEEK_END); lseek(iFd, 0, SEEK_SET); - auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40)); + auto *buffer = (uint8_t *) MEMAllocFromDefaultHeapEx(ROUNDUP(filesize, 0x40), 0x40); if (buffer == nullptr) { close(iFd); return -2; @@ -59,4 +60,4 @@ int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) } return filesize; -} +} \ No newline at end of file diff --git a/wumsloader/src/fs/FileUtils.h b/wumsloader/src/fs/FileUtils.h new file mode 100644 index 0000000..ac6b2cc --- /dev/null +++ b/wumsloader/src/fs/FileUtils.h @@ -0,0 +1,4 @@ +#pragma once +#include + +int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size); \ No newline at end of file diff --git a/wumsloader/src/globals.cpp b/wumsloader/src/globals.cpp new file mode 100644 index 0000000..b220c8f --- /dev/null +++ b/wumsloader/src/globals.cpp @@ -0,0 +1,7 @@ +#include "globals.h" + +MEMHeapHandle gHeapHandle __attribute__((section(".data"))) = nullptr; +uint8_t gInitCalled __attribute__((section(".data"))) = 0; +module_information_t gModuleInformation __attribute__((section(".data"))); +std::vector> gLoadedModules __attribute__((section(".data"))); +std::unique_ptr gModuleDataInfo __attribute__((section(".data"))); diff --git a/wumsloader/src/globals.h b/wumsloader/src/globals.h new file mode 100644 index 0000000..9005f37 --- /dev/null +++ b/wumsloader/src/globals.h @@ -0,0 +1,25 @@ +#pragma once + +#include "module/ModuleData.h" +#include +#include +#include + +extern uint8_t gInitCalled; +extern MEMHeapHandle gHeapHandle; +extern module_information_t gModuleInformation; +extern std::vector> gLoadedModules; +extern std::unique_ptr gModuleDataInfo; + +#define MEMORY_REGION_START 0x00800000 +#define MEMORY_REGION_SIZE 0x00800000 + +#define CUSTOM_RPX_LOADER_RETURN_CODE 0x00009000 // We have to skip the first 0x00009000 bytes because it's still used +#define RELOCATOR_SIZE 0x130000 // Maximum size of the wumsloader, needs to match the one defined in link.ld +#define ENVIRONMENT_PATH_LENGTH 0x100 // Length of the EnvironmentPath. + +#define MEMORY_REGION_ENVIRONMENT_STRING_ADRR (MEMORY_REGION_START + CUSTOM_RPX_LOADER_RETURN_CODE + RELOCATOR_SIZE) +#define MEMORY_REGION_USABLE_HEAP_START (MEMORY_REGION_ENVIRONMENT_STRING_ADRR + ENVIRONMENT_PATH_LENGTH) +#define MEMORY_REGION_USABLE_HEAP_END (0x00FFF000) // We need to leave space for the BAT hook + +#define ENVRIONMENT_STRING ((char *) MEMORY_REGION_ENVIRONMENT_STRING_ADRR) diff --git a/wumsloader/src/link.ld b/wumsloader/src/link.ld new file mode 100644 index 0000000..cf3a42b --- /dev/null +++ b/wumsloader/src/link.ld @@ -0,0 +1,95 @@ +OUTPUT(loader.elf); + +ENTRY(_start); + +SECTIONS { + . = 0x00809000; + .text ALIGN(32) : { + KEEP (*(.crt0)) + KEEP (*(SORT_NONE(.init))) + + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.gnu.warning) + *(.glink) + + KEEP (*(SORT_NONE(.fini))) + } + + .rodata : { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + + *(.gcc_except_table .gcc_except_table.*) + *(.gnu_extab*) + + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP (*(.jcr)) + *(.fixup) + *(.got1) + *(.got2) + *(.branch_lt) + *(.got) + *(.plt) + *(.tm_clone_table) + } + + .eh_frame : { + *(.eh_frame_hdr) + *(.eh_frame_entry .eh_frame_entry.*) + + KEEP (*(.eh_frame)) + *(.eh_frame.*) + } + + .data : { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + *(.data1) + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + + .bss (NOLOAD) : { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } + /DISCARD/ : { + *(*); + } +} + +ASSERT((SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata) + SIZEOF(.eh_frame) + SIZEOF(.bss)) < 0x130000, "Memory overlapping with modules."); diff --git a/source/module/ExportData.h b/wumsloader/src/module/ExportData.h similarity index 70% rename from source/module/ExportData.h rename to wumsloader/src/module/ExportData.h index af322b2..1ad1d9f 100644 --- a/source/module/ExportData.h +++ b/wumsloader/src/module/ExportData.h @@ -6,9 +6,9 @@ class ExportData { public: - ExportData(wums_entry_type_t type, const std::string &name, const void *address) { + ExportData(wums_entry_type_t type, std::string name, const void *address) { this->type = type; - this->name = name; + this->name = std::move(name); this->address = address; } @@ -20,7 +20,7 @@ public: return address; } - [[nodiscard]] const std::string getName() const { + [[nodiscard]] const std::string &getName() const { return name; } diff --git a/source/module/FunctionSymbolData.h b/wumsloader/src/module/FunctionSymbolData.h similarity index 84% rename from source/module/FunctionSymbolData.h rename to wumsloader/src/module/FunctionSymbolData.h index c873f75..2bb074a 100644 --- a/source/module/FunctionSymbolData.h +++ b/wumsloader/src/module/FunctionSymbolData.h @@ -24,7 +24,7 @@ class FunctionSymbolData { public: FunctionSymbolData(const FunctionSymbolData &o2) = default; - FunctionSymbolData(const char *name, void *address, uint32_t size) : name(name), + FunctionSymbolData(std::string name, void *address, uint32_t size) : name(std::move(name)), address(address), size(size) { } @@ -32,10 +32,10 @@ public: virtual ~FunctionSymbolData() = default; bool operator<(const FunctionSymbolData &rhs) const { - return (uint32_t) address < (uint32_t) rhs.address; //assume that you compare the record based on a + return (uint32_t) address < (uint32_t) rhs.address; } - [[nodiscard]] const char *getName() const { + [[nodiscard]] const std::string &getName() const { return name; } @@ -47,9 +47,8 @@ public: return size; } - private: - const char *name; + std::string name; void *address; uint32_t size; }; \ No newline at end of file diff --git a/source/module/HookData.h b/wumsloader/src/module/HookData.h similarity index 100% rename from source/module/HookData.h rename to wumsloader/src/module/HookData.h diff --git a/source/module/ImportRPLInformation.h b/wumsloader/src/module/ImportRPLInformation.h similarity index 51% rename from source/module/ImportRPLInformation.h rename to wumsloader/src/module/ImportRPLInformation.h index 4e3c42f..0c19bb4 100644 --- a/source/module/ImportRPLInformation.h +++ b/wumsloader/src/module/ImportRPLInformation.h @@ -18,6 +18,7 @@ #pragma once #include "utils/logger.h" +#include #include #include #include @@ -26,44 +27,27 @@ class ImportRPLInformation { public: - explicit ImportRPLInformation(std::string name, bool isData = false) { - this->name = std::move(name); - this->_isData = isData; + explicit ImportRPLInformation(std::string rawSectionName) { + this->name = std::move(rawSectionName); } ~ImportRPLInformation() = default; - static std::optional> createImportRPLInformation(std::string rawSectionName) { - std::string fimport = ".fimport_"; - std::string dimport = ".dimport_"; - - bool data = false; - - std::string rplName; - - if (rawSectionName.size() < fimport.size()) { - return std::nullopt; - } else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) { - rplName = rawSectionName.substr(fimport.size()); - } else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) { - rplName = rawSectionName.substr(dimport.size()); - data = true; - } else { - DEBUG_FUNCTION_LINE("invalid section name\n"); - return std::nullopt; - } - return std::make_shared(rplName, data); - } - - [[nodiscard]] std::string getName() const { + [[nodiscard]] const std::string &getName() const { return name; } + [[nodiscard]] const char *getRPLName() const { + if (name.max_size() < strlen("._import_") + 1) { + OSFatal("Invalid RPLName, is too short to be valid"); + } + return name.c_str() + strlen("._import_"); + } + [[nodiscard]] bool isData() const { - return _isData; + return name.starts_with(".dimport_"); } private: std::string name; - bool _isData = false; }; diff --git a/source/module/ModuleData.h b/wumsloader/src/module/ModuleData.h similarity index 63% rename from source/module/ModuleData.h rename to wumsloader/src/module/ModuleData.h index 94b9a99..c09b260 100644 --- a/source/module/ModuleData.h +++ b/wumsloader/src/module/ModuleData.h @@ -54,51 +54,43 @@ public: this->entrypoint = addr; } - void setStartAddress(uint32_t addr) { - this->startAddress = addr; + void addRelocationData(std::unique_ptr relocation_data) { + relocation_data_list.push_back(std::move(relocation_data)); } - void setEndAddress(uint32_t _endAddress) { - this->endAddress = _endAddress; - } - - void addRelocationData(const std::shared_ptr &relocation_data) { - relocation_data_list.push_back(relocation_data); - } - - [[nodiscard]] const std::vector> &getRelocationDataList() const { + [[nodiscard]] const std::vector> &getRelocationDataList() const { return relocation_data_list; } - void addExportData(const std::shared_ptr &data) { - export_data_list.push_back(data); + void addExportData(std::unique_ptr data) { + export_data_list.push_back(std::move(data)); } - [[nodiscard]] const std::vector> &getExportDataList() const { + [[nodiscard]] const std::vector> &getExportDataList() const { return export_data_list; } - void addHookData(const std::shared_ptr &data) { - hook_data_list.push_back(data); + void addHookData(std::unique_ptr data) { + hook_data_list.push_back(std::move(data)); } - [[nodiscard]] const std::vector> &getHookDataList() const { + [[nodiscard]] const std::vector> &getHookDataList() const { return hook_data_list; } - void addSectionInfo(const std::shared_ptr §ionInfo) { - section_info_list[sectionInfo->getName()] = sectionInfo; + void addSectionInfo(std::shared_ptr sectionInfo) { + section_info_list[sectionInfo->getName()] = std::move(sectionInfo); } - void addFunctionSymbolData(const std::shared_ptr &symbol_data) { - symbol_data_list.insert(symbol_data); + void addFunctionSymbolData(std::shared_ptr symbol_data) { + symbol_data_list.insert(std::move(symbol_data)); } [[nodiscard]] const std::set, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const { return symbol_data_list; } - [[nodiscard]] const std::map> &getSectionInfoList() const { + [[nodiscard]] const std::map> &getSectionInfoList() const { return section_info_list; } @@ -106,10 +98,10 @@ public: if (getSectionInfoList().count(sectionName) > 0) { return section_info_list.at(sectionName); } - return std::nullopt; + return {}; } - [[nodiscard]] uint32_t getBSSAddr() const { + [[nodiscard]] uint32_t getBSSAddress() const { return bssAddr; } @@ -117,7 +109,7 @@ public: return bssSize; } - [[nodiscard]] uint32_t getSBSSAddr() const { + [[nodiscard]] uint32_t getSBSSAddress() const { return sbssAddr; } @@ -125,25 +117,23 @@ public: return sbssSize; } + [[nodiscard]] uint32_t getStartAddress() const { + return reinterpret_cast(dataPtr.get()); + } + + [[nodiscard]] uint32_t getEndAddress() const { + return reinterpret_cast(dataPtr.get()) + this->totalSize; + } + [[nodiscard]] uint32_t getEntrypoint() const { return entrypoint; } - [[nodiscard]] uint32_t getStartAddress() const { - return startAddress; + void setExportName(std::string name) { + this->export_name = std::move(name); } - [[nodiscard]] uint32_t getEndAddress() const { - return endAddress; - } - - [[nodiscard]] std::string toString() const; - - void setExportName(const std::string &name) { - this->export_name = name; - } - - [[nodiscard]] std::string getExportName() const { + [[nodiscard]] const std::string &getExportName() const { return this->export_name; } @@ -163,24 +153,33 @@ public: this->skipInitFini = value; } - bool relocationsDone = false; + void setDataPtr(std::unique_ptr ptr, uint32_t size) { + this->dataPtr = std::move(ptr); + this->totalSize = size; + } + + std::unique_ptr hookDataStruct; + std::unique_ptr exportDataStruct; + std::unique_ptr functionSymbolDataStruct; + std::unique_ptr rplDataStruct; + std::unique_ptr relocationDataStruct; private: - std::vector> relocation_data_list; - std::vector> export_data_list; - std::vector> hook_data_list; + std::vector> relocation_data_list; + std::vector> export_data_list; + std::vector> hook_data_list; std::set, FunctionSymbolDataComparator> symbol_data_list; - std::map> section_info_list; + std::map> section_info_list; + std::unique_ptr dataPtr; std::string export_name; uint32_t bssAddr = 0; uint32_t bssSize = 0; uint32_t sbssAddr = 0; uint32_t sbssSize = 0; - uint32_t startAddress = 0; - uint32_t endAddress = 0; uint32_t entrypoint = 0; + uint32_t totalSize = 0; bool initBeforeRelocationDoneHook = false; bool skipInitFini = false; }; diff --git a/source/module/ModuleDataFactory.cpp b/wumsloader/src/module/ModuleDataFactory.cpp similarity index 63% rename from source/module/ModuleDataFactory.cpp rename to wumsloader/src/module/ModuleDataFactory.cpp index e0d063f..c653fd5 100644 --- a/source/module/ModuleDataFactory.cpp +++ b/wumsloader/src/module/ModuleDataFactory.cpp @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (C) 2018 Maschell + * Copyright (C) 2022 Maschell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,54 +16,86 @@ ****************************************************************************/ #include "ModuleDataFactory.h" -#include "ElfUtils.h" -#include "utils/FileUtils.h" -#include "utils/utils.h" +#include "fs/FileUtils.h" +#include "utils/ElfUtils.h" +#include "utils/logger.h" #include +#include #include #include -#include #include using namespace ELFIO; -std::optional> -ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_ptr, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) { +std::optional> ModuleDataFactory::load(const std::string &path) { elfio reader; - std::shared_ptr moduleData = std::make_shared(); + auto moduleData = std::make_shared(); + if (!moduleData) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc module data"); + return {}; + } uint8_t *buffer = nullptr; uint32_t fsize = 0; - if (LoadFileToMem(path.c_str(), &buffer, &fsize) < 0) { - DEBUG_FUNCTION_LINE("Failed to load file"); + if (LoadFileToMem(path, &buffer, &fsize) < 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to load file"); return {}; } // Load ELF data if (!reader.load(reinterpret_cast(buffer), fsize)) { - DEBUG_FUNCTION_LINE("Can't find or process %s", path.c_str()); - free(buffer); + DEBUG_FUNCTION_LINE_ERR("Can't find or process %s", path.c_str()); + MEMFreeToDefaultHeap(buffer); + return {}; + } + uint32_t sec_num = reader.sections.size(); + + auto destinations = std::make_unique(sec_num); + if (!destinations) { + DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array"); + MEMFreeToDefaultHeap(buffer); return {}; } - uint32_t sec_num = reader.sections.size(); + uint32_t totalSize = 0; - auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num); + uint32_t text_size = 0; + uint32_t data_size = 0; - if (!destinations) { - DEBUG_FUNCTION_LINE("Failed to alloc memory for destinations"); - free(buffer); + for (uint32_t i = 0; i < sec_num; ++i) { + auto *psec = reader.sections[i]; + if (psec->get_type() == 0x80000002) { + continue; + } + + if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { + uint32_t sectionSize = psec->get_size(); + auto address = (uint32_t) psec->get_address(); + if ((address >= 0x02000000) && address < 0x10000000) { + text_size += sectionSize; + } else if ((address >= 0x10000000) && address < 0xC0000000) { + data_size += sectionSize; + } + if (psec->get_name().rfind(".wums.", 0) == 0) { + data_size += sectionSize; + } + } } - uint32_t baseOffset = *destination_address_ptr; + auto data = std::make_unique(text_size + data_size); + if (!data) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size); + MEMFreeToDefaultHeap(buffer); + return {}; + } - uint32_t offset_text = baseOffset; - uint32_t offset_data = offset_text; + DEBUG_FUNCTION_LINE("Allocated %d kb", (text_size + data_size) / 1024); - uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000; + void *text_data = data.get(); + void *data_data = (void *) ((uint32_t) data.get() + text_size); + auto baseOffset = (uint32_t) data.get(); - uint32_t totalSize = 0; - uint32_t endAddress = 0; + uint32_t entrypoint = (uint32_t) text_data + (uint32_t) reader.get_entry() - 0x02000000; for (uint32_t i = 0; i < sec_num; ++i) { section *psec = reader.sections[i]; @@ -75,12 +107,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p uint32_t sectionSize = psec->get_size(); totalSize += sectionSize; - if (totalSize > maximum_size) { - DEBUG_FUNCTION_LINE("Couldn't load setup module because it's too big."); - free(destinations); - free(buffer); - return {}; - } auto address = (uint32_t) psec->get_address(); @@ -91,7 +117,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p destination -= 0x02000000; destinations[psec->get_index()] -= 0x02000000; baseOffset += sectionSize; - offset_data += sectionSize; } else if ((address >= 0x10000000) && address < 0xC0000000) { destination -= 0x10000000; destinations[psec->get_index()] -= 0x10000000; @@ -99,9 +124,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p destination -= 0xC0000000; destinations[psec->get_index()] -= 0xC0000000; } else { - DEBUG_FUNCTION_LINE("Unhandled case"); - free(destinations); - free(buffer); + DEBUG_FUNCTION_LINE_ERR("Unhandled case"); + MEMFreeToDefaultHeap(buffer); return std::nullopt; } @@ -115,10 +139,10 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p memcpy((void *) destination, p, sectionSize); } - //nextAddress = ROUNDUP(destination + sectionSize, 0x100); if (psec->get_name() == ".bss") { moduleData->setBSSLocation(destination, sectionSize); memset(reinterpret_cast(destination), 0, sectionSize); + } else if (psec->get_name() == ".sbss") { moduleData->setSBSSLocation(destination, sectionSize); memset(reinterpret_cast(destination), 0, sectionSize); @@ -127,10 +151,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p moduleData->addSectionInfo(sectionInfo); DEBUG_FUNCTION_LINE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize); - if (endAddress < destination + sectionSize) { - endAddress = destination + sectionSize; - } - DCFlushRange((void *) destination, sectionSize); ICInvalidateRange((void *) destination, sectionSize); } @@ -140,19 +160,14 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p section *psec = reader.sections[i]; if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str()); - if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) { - DEBUG_FUNCTION_LINE("elfLink failed"); - free(destinations); - free(buffer); + if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data, (uint32_t) data_data, nullptr, 0)) { + DEBUG_FUNCTION_LINE_ERR("elfLink failed"); + MEMFreeToDefaultHeap(buffer); return std::nullopt; } } } - auto relocationData = getImportRelocationData(reader, destinations); - - for (auto const &reloc : relocationData) { - moduleData->addRelocationData(reloc); - } + getImportRelocationData(moduleData, reader, destinations.get()); auto secInfo = moduleData->getSectionInfo(".wums.exports"); if (secInfo && secInfo.value()->getSize() > 0) { @@ -161,9 +176,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p if (entries != nullptr) { for (size_t j = 0; j < entries_count; j++) { wums_entry_t *exp = &entries[j]; - DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X" /*,pluginData.getPluginInformation()->getName().c_str()*/, exp->type, exp->name, (void *) exp->address); - auto exportData = std::make_shared(exp->type, exp->name, exp->address); - moduleData->addExportData(exportData); + DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X", exp->type, exp->name, exp->address); + auto exportData = std::make_unique(exp->type, exp->name, exp->address); + if (!exportData) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc ExportData"); + } + moduleData->addExportData(std::move(exportData)); } } } @@ -175,9 +193,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p if (hooks != nullptr) { for (size_t j = 0; j < entries_count; j++) { wums_hook_t *hook = &hooks[j]; - DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X" /*,pluginData.getPluginInformation()->getName().c_str()*/, hook->type, hook->target); - auto hookData = std::make_shared(hook->type, hook->target); - moduleData->addHookData(hookData); + DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X", hook->type, hook->target); + auto hookData = std::make_unique(hook->type, hook->target); + if (!hookData) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc HookData"); + } + moduleData->addHookData(std::move(hookData)); } } } @@ -201,7 +222,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p std::string value(curEntry + firstFound + 1); if (key == "export_name") { - DEBUG_FUNCTION_LINE("export_name = %s", value.c_str()); moduleData->setExportName(value); } else if (key == "skipInitFini") { if (value == "true") { @@ -219,9 +239,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p } } else if (key == "wums") { if (value != "0.3") { - DEBUG_FUNCTION_LINE("Warning: Ignoring module - Unsupported WUMS version: %s.\n", value.c_str()); - free(destinations); - free(buffer); + DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring module - Unsupported WUMS version: %s.", value.c_str()); + MEMFreeToDefaultHeap(buffer); return std::nullopt; } } @@ -231,9 +250,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p } } - char *strTable = (char *) endAddress; - uint32_t strOffset = 0; - // Get the symbol for functions. Elf_Half n = reader.sections.size(); for (Elf_Half i = 0; i < n; ++i) { @@ -258,14 +274,13 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p if (!sectionOpt.has_value()) { continue; } - auto finalAddress = offsetVal + sectionOpt.value()->getAddress(); - - uint32_t stringSize = name.size() + 1; - memcpy(strTable + strOffset, name.c_str(), stringSize); - moduleData->addFunctionSymbolData(std::make_shared(strTable + strOffset, (void *) finalAddress, (uint32_t) size)); - strOffset += stringSize; - totalSize += stringSize; - endAddress += stringSize; + auto finalAddress = offsetVal + sectionOpt.value()->getAddress(); + auto functionSymbolData = std::make_shared(name, (void *) finalAddress, (uint32_t) size); + if (!functionSymbolData) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc FunctionSymbolData"); + } else { + moduleData->addFunctionSymbolData(std::move(functionSymbolData)); + } } } } @@ -274,41 +289,44 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p } } - DCFlushRange((void *) *destination_address_ptr, totalSize); - ICInvalidateRange((void *) *destination_address_ptr, totalSize); + DCFlushRange((void *) text_data, text_size); + ICInvalidateRange((void *) text_data, text_size); + DCFlushRange((void *) data_data, data_size); + ICInvalidateRange((void *) data_data, data_size); - free(destinations); - free(buffer); + if (totalSize > text_size + data_size) { + DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!"); + OSFatal("We didn't allocate enough memory!!"); + } + moduleData->setDataPtr(std::move(data), totalSize); moduleData->setEntrypoint(entrypoint); - moduleData->setStartAddress(*destination_address_ptr); - moduleData->setEndAddress(endAddress); DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint); - DEBUG_FUNCTION_LINE("Saved startAddress as %08X", *destination_address_ptr); - DEBUG_FUNCTION_LINE("Saved endAddress as %08X", endAddress); + DEBUG_FUNCTION_LINE("Saved startAddress as %08X", (uint32_t) data.get()); + DEBUG_FUNCTION_LINE("Saved endAddress as %08X", (uint32_t) data.get() + totalSize); - *destination_address_ptr = (*destination_address_ptr + totalSize + 0x100) & 0xFFFFFF00; + DEBUG_FUNCTION_LINE("Loaded %s size: %d kilobytes", path.c_str(), totalSize / 1024); + + MEMFreeToDefaultHeap(buffer); return moduleData; } -std::vector> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) { - std::vector> result; - std::map infoMap; +void ModuleDataFactory::getImportRelocationData(std::shared_ptr &moduleData, ELFIO::elfio &reader, uint8_t **destinations) { + std::map> infoMap; uint32_t sec_num = reader.sections.size(); for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + auto *psec = reader.sections[i]; if (psec->get_type() == 0x80000002) { - infoMap[i] = psec->get_name(); + infoMap[i] = std::make_shared(psec->get_name()); } } for (uint32_t i = 0; i < sec_num; ++i) { section *psec = reader.sections[i]; if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) { - DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str()); relocation_section_accessor rel(reader, psec); for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) { Elf64_Addr offset; @@ -319,30 +337,39 @@ std::vector> ModuleDataFactory::getImportRelocat Elf_Half sym_section_index; if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) { - DEBUG_FUNCTION_LINE("Failed to get relocation"); + DEBUG_FUNCTION_LINE_ERR("Failed to get relocation"); + OSFatal("Failed to get relocation"); break; } - // uint32_t adjusted_sym_value = (uint32_t) sym_value; - if (infoMap.count(sym_section_index) == 0) { + auto adjusted_sym_value = (uint32_t) sym_value; + if (adjusted_sym_value < 0xC0000000) { continue; } - auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]); - if (!rplInfo) { - DEBUG_FUNCTION_LINE("Failed to create import information"); - break; - } uint32_t section_index = psec->get_info(); + if (!infoMap.contains(sym_section_index)) { + DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str()); + OSFatal("Relocation is referencing a unknown section."); + } - // When these relocations are performed, we don't need the 0xC0000000 offset anymore. - auto relocationData = std::make_shared(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value()); - //relocationData->printInformation(); - result.push_back(relocationData); + auto relocationData = std::make_unique(type, + offset - 0x02000000, + addend, + (void *) (destinations[section_index] + 0x02000000), + sym_name, + infoMap[sym_section_index]); + + if (!relocationData) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc relocation data"); + OSFatal("Failed to alloc relocation data"); + continue; + } + + moduleData->addRelocationData(std::move(relocationData)); } } } - return result; } bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data, @@ -352,7 +379,7 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3 for (uint32_t i = 0; i < sec_num; ++i) { section *psec = reader.sections[i]; if (psec->get_info() == section_index) { - DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str()); + DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str()); relocation_section_accessor rel(reader, psec); for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) { Elf64_Addr offset; @@ -363,7 +390,8 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3 Elf_Half sym_section_index; if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) { - DEBUG_FUNCTION_LINE("Failed to get relocation"); + DEBUG_FUNCTION_LINE_ERR("Failed to get relocation"); + OSFatal("Failed to get relocation"); break; } @@ -380,23 +408,21 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3 } else if (adjusted_sym_value == 0x0) { // } else { - DEBUG_FUNCTION_LINE("Unhandled case %08X", adjusted_sym_value); + DEBUG_FUNCTION_LINE_ERR("Unhandled case %08X", adjusted_sym_value); return false; } if (sym_section_index == SHN_ABS) { // } else if (sym_section_index > SHN_LORESERVE) { - DEBUG_FUNCTION_LINE("NOT IMPLEMENTED: %04X", sym_section_index); + DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index); return false; } - if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) { - DEBUG_FUNCTION_LINE("Link failed"); + DEBUG_FUNCTION_LINE_ERR("Link failed"); return false; } } - DEBUG_FUNCTION_LINE("done"); } } return true; diff --git a/source/module/ModuleDataFactory.h b/wumsloader/src/module/ModuleDataFactory.h similarity index 63% rename from source/module/ModuleDataFactory.h rename to wumsloader/src/module/ModuleDataFactory.h index 0fba3a9..c938ed1 100644 --- a/source/module/ModuleDataFactory.h +++ b/wumsloader/src/module/ModuleDataFactory.h @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (C) 2019 Maschell + * Copyright (C) 2022 Maschell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "ModuleData.h" #include "elfio/elfio.hpp" +#include #include #include #include @@ -26,11 +27,15 @@ class ModuleDataFactory { public: - static std::optional> - load(const std::string &path, uint32_t *destination_address_ptr, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length); + static std::optional> load(const std::string &path); - static bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data, + static bool linkSection(ELFIO::elfio &reader, + uint32_t section_index, + uint32_t destination, + uint32_t base_text, + uint32_t base_data, + relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length); - static std::vector> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations); + static void getImportRelocationData(std::shared_ptr &moduleData, ELFIO::elfio &reader, uint8_t **destinations); }; diff --git a/wumsloader/src/module/ModuleDataPersistence.cpp b/wumsloader/src/module/ModuleDataPersistence.cpp new file mode 100644 index 0000000..b088662 --- /dev/null +++ b/wumsloader/src/module/ModuleDataPersistence.cpp @@ -0,0 +1,211 @@ +#include "ModuleDataPersistence.h" +#include "globals.h" +#include + +bool ModuleDataPersistence::saveModuleData(module_information_t *moduleInformation, const std::vector> &moduleList) { + auto module_data_list = std::make_unique(moduleList.size()); + if (!module_data_list) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory to persist module data"); + return false; + } + + moduleInformation->modules = module_data_list.get(); + + uint32_t i = 0; + for (auto &module : moduleList) { + auto &module_data = module_data_list[i]; + module_data = {}; + if (!saveModuleData(module_data, module)) { + module->relocationDataStruct.reset(); + module->hookDataStruct.reset(); + module->exportDataStruct.reset(); + module->functionSymbolDataStruct.reset(); + module->rplDataStruct.reset(); + DEBUG_FUNCTION_LINE_ERR("Failed to persist data for module. No memory?"); + OSFatal("Failed to persist data for module. No memory?"); + continue; + } else { + moduleInformation->number_modules++; + i++; + } + } + + gModuleDataInfo = std::move(module_data_list); + OSMemoryBarrier(); + + return true; +} + +bool ModuleDataPersistence::saveModuleData(module_information_single_t &module_data, const std::shared_ptr &module) { + if (!saveRelocationDataForModule(module_data, module)) { + DEBUG_FUNCTION_LINE_ERR("Failed to store relocation data of module"); + return false; + } + + if (!saveHookDataForModule(module_data, module)) { + DEBUG_FUNCTION_LINE_ERR("Failed to store hook data of module"); + return false; + } + + if (!saveExportDataForModule(module_data, module)) { + DEBUG_FUNCTION_LINE_ERR("Failed to store export data of module"); + return false; + } + + if (!saveFunctionSymbolDataForModule(module_data, module)) { + DEBUG_FUNCTION_LINE_ERR("Failed to store function symbol data of module"); + return false; + } + + module_data.module_export_name = (char *) module->getExportName().c_str(); + + module_data.bssAddr = module->getBSSAddress(); + module_data.bssSize = module->getBSSSize(); + module_data.sbssAddr = module->getSBSSAddress(); + module_data.sbssSize = module->getSBSSSize(); + module_data.startAddress = module->getStartAddress(); + module_data.endAddress = module->getEndAddress(); + module_data.entrypoint = module->getEntrypoint(); + module_data.skipInitFini = module->isSkipInitFini(); + module_data.initBeforeRelocationDoneHook = module->isInitBeforeRelocationDoneHook(); + return true; +} + +bool ModuleDataPersistence::saveFunctionSymbolDataForModule(module_information_single_t &module_data, const std::shared_ptr &module) { + uint32_t entryCount = module->getFunctionSymbolDataList().size(); + auto function_symbol_data = std::make_unique(entryCount); + if (!function_symbol_data) { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the function symbol data."); + return false; + } + uint32_t i = 0; + for (auto &curFuncSym : module->getFunctionSymbolDataList()) { + if (i >= entryCount) { + DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for."); + OSFatal("We tried to write more entries than we have space for."); + } + function_symbol_data[i].address = curFuncSym->getAddress(); + function_symbol_data[i].name = (char *) curFuncSym->getName().c_str(); + function_symbol_data[i].size = curFuncSym->getSize(); + i++; + } + module_data.function_symbol_entries = function_symbol_data.get(); + module_data.number_function_symbols = i; + + module->functionSymbolDataStruct = std::move(function_symbol_data); + + return true; +} + +bool ModuleDataPersistence::saveExportDataForModule(module_information_single_t &module_data, const std::shared_ptr &module) { + auto export_data = std::make_unique(module->getExportDataList().size()); + if (!export_data) { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the export data."); + return false; + } + + uint32_t exportCount = 0; + for (auto const &export_ : module->getExportDataList()) { + if (exportCount >= module->getExportDataList().size()) { + DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for."); + OSFatal("We tried to write more entries than we have space for."); + } + auto *curExport = &export_data[exportCount++]; + curExport->type = export_->getType(); + curExport->name = export_->getName().c_str(); + curExport->address = (uint32_t) export_->getAddress(); + } + module_data.export_entries = export_data.get(); + module_data.number_export_entries = exportCount; + + module->exportDataStruct = std::move(export_data); + + return true; +} + +bool ModuleDataPersistence::saveHookDataForModule(module_information_single_t &module_data, const std::shared_ptr &module) { + auto hook_data = std::make_unique(module->getHookDataList().size()); + if (!hook_data) { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the hook data."); + return false; + } + + uint32_t hookCount = 0; + for (auto const &hook : module->getHookDataList()) { + if (hookCount >= module->getHookDataList().size()) { + DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for."); + OSFatal("We tried to write more entries than we have space for."); + } + auto *curHook = &hook_data[hookCount++]; + curHook->type = hook->getType(); + curHook->target = (uint32_t) hook->getTarget(); + } + module_data.hook_entries = hook_data.get(); + module_data.number_hook_entries = hookCount; + + module->hookDataStruct = std::move(hook_data); + + return true; +} + +bool ModuleDataPersistence::saveRelocationDataForModule(module_information_single_t &module_data, const std::shared_ptr &module) { + auto relocation_data = std::make_unique(module->getRelocationDataList().size()); + if (!relocation_data) { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the relocation data."); + return false; + } + + // Determine how many dyn_linking_import_t entries we need. + std::set rplInfoCountSet; + for (auto const &reloc : module->getRelocationDataList()) { + rplInfoCountSet.insert(reloc->getImportRPLInformation()->getName()); + } + + uint32_t rplInfoTotalCount = rplInfoCountSet.size(); + rplInfoCountSet.clear(); + + auto rpl_data = std::make_unique(rplInfoTotalCount); + if (!rpl_data) { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the RPLInfos."); + return false; + } + + uint32_t relocationCount = 0; + uint32_t rplInfoCount = 0; + std::map rplInfoMap; + for (auto const &reloc : module->getRelocationDataList()) { + if (relocationCount >= module->getRelocationDataList().size()) { + DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for."); + OSFatal("We tried to write more entries than we have space for."); + } + auto *curReloc = &relocation_data[relocationCount++]; + curReloc->destination = reloc->getDestination(); + curReloc->offset = reloc->getOffset(); + curReloc->addend = reloc->getAddend(); + curReloc->type = reloc->getType(); + curReloc->functionName = reloc->getName().c_str(); + auto &rplInfo = reloc->getImportRPLInformation(); + + auto rplIt = rplInfoMap.find(rplInfo->getName()); + if (rplIt != rplInfoMap.end()) { + curReloc->importEntry = rplIt->second; + } else { + if (rplInfoCount >= rplInfoTotalCount) { + DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for."); + OSFatal("We tried to write more entries than we have space for."); + } + auto *rplInfoPtr = &rpl_data[rplInfoCount++]; + rplInfoPtr->isData = rplInfo->isData(); + rplInfoPtr->importName = rplInfo->getName().c_str(); + rplInfoMap[rplInfo->getName()] = rplInfoPtr; + curReloc->importEntry = rplInfoPtr; + } + } + module_data.linking_entries = relocation_data.get(); + module_data.number_linking_entries = relocationCount; + + module->relocationDataStruct = std::move(relocation_data); + module->rplDataStruct = std::move(rpl_data); + + return true; +} diff --git a/wumsloader/src/module/ModuleDataPersistence.h b/wumsloader/src/module/ModuleDataPersistence.h new file mode 100644 index 0000000..1b7260b --- /dev/null +++ b/wumsloader/src/module/ModuleDataPersistence.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ModuleData.h" +#include +#include + +class ModuleDataPersistence { +public: + static bool saveModuleData(module_information_t *moduleInformation, const std::vector> &moduleList); + static bool saveModuleData(module_information_single_t &module_data, const std::shared_ptr &module); + static bool saveRelocationDataForModule(module_information_single_t &module_data, const std::shared_ptr &module); + static bool saveExportDataForModule(module_information_single_t &module_data, const std::shared_ptr &module); + static bool saveHookDataForModule(module_information_single_t &module_data, const std::shared_ptr &module); + static bool saveFunctionSymbolDataForModule(module_information_single_t &module_data, const std::shared_ptr &module); +}; diff --git a/source/module/RelocationData.h b/wumsloader/src/module/RelocationData.h similarity index 91% rename from source/module/RelocationData.h rename to wumsloader/src/module/RelocationData.h index 06cf5c2..0c66255 100644 --- a/source/module/RelocationData.h +++ b/wumsloader/src/module/RelocationData.h @@ -51,16 +51,14 @@ public: return destination; } - [[nodiscard]] std::string getName() const { + [[nodiscard]] const std::string &getName() const { return name; } - [[nodiscard]] std::shared_ptr getImportRPLInformation() const { + [[nodiscard]] const std::shared_ptr &getImportRPLInformation() const { return rplInfo; } - [[nodiscard]] std::string toString() const; - private: char type; size_t offset; diff --git a/source/module/SectionInfo.h b/wumsloader/src/module/SectionInfo.h similarity index 87% rename from source/module/SectionInfo.h rename to wumsloader/src/module/SectionInfo.h index 0ca09e9..d96fa54 100644 --- a/source/module/SectionInfo.h +++ b/wumsloader/src/module/SectionInfo.h @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (C) 2019 Maschell + * Copyright (C) 2022 Maschell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,14 +30,10 @@ public: SectionInfo() = default; - SectionInfo(const SectionInfo &o2) : name(o2.name), - address(o2.address), - sectionSize(o2.sectionSize) { - } + SectionInfo(const SectionInfo &o2) = default; SectionInfo &operator=(const SectionInfo &other) = default; - virtual ~SectionInfo() = default; [[nodiscard]] const std::string &getName() const { diff --git a/relocator/src/ElfUtils.cpp b/wumsloader/src/utils/ElfUtils.cpp similarity index 71% rename from relocator/src/ElfUtils.cpp rename to wumsloader/src/utils/ElfUtils.cpp index b8ff7a3..9807db4 100644 --- a/relocator/src/ElfUtils.cpp +++ b/wumsloader/src/utils/ElfUtils.cpp @@ -1,4 +1,5 @@ #include +#include #include "ElfUtils.h" #include "utils/logger.h" @@ -9,6 +10,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des if (type == R_PPC_NONE) { return true; } + auto target = destination + offset; auto value = symbol_addr + addend; @@ -30,7 +32,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des *((uint16_t *) (target)) = static_cast((value + 0x8000) >> 16); break; case R_PPC_DTPMOD32: - DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n"); + DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME"); //*((int32_t *)(target)) = tlsModuleIndex; break; case R_PPC_DTPREL32: @@ -48,18 +50,18 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des case R_PPC_REL14: { auto distance = static_cast(value) - static_cast(target); if (distance > 0x7FFC || distance < -0x7FFC) { - DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target."); + DEBUG_FUNCTION_LINE_ERR("***14-bit relative branch cannot hit target."); return false; } if (distance & 3) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040); + DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040); return false; } if ((distance >= 0 && (distance & 0xFFFF8000)) || (distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040); + DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040); return false; } @@ -74,8 +76,8 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des auto distance = static_cast(value) - static_cast(target); if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) { if (trampoline_data == nullptr) { - DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n"); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance); + DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided"); + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance); return false; } else { relocation_trampoline_entry_t *freeSlot = nullptr; @@ -93,14 +95,20 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des } } if (freeSlot == nullptr) { - DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n"); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0]))); - + DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full"); + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) & (freeSlot->trampoline[0])); return false; } - if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) { - DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer)."); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0]))); + auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]); + auto newValue = symbolValue + addend; + auto newDistance = static_cast(newValue) - static_cast(target); + if (newDistance > 0x1FFFFFC || newDistance < -0x1FFFFFC) { + DEBUG_FUNCTION_LINE_ERR("**Cannot link 24-bit jump (too far to tramp buffer)."); + if (newDistance < 0) { + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance -%08X", newValue, target, abs(newDistance)); + } else { + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", newValue, target, newDistance); + } return false; } @@ -117,24 +125,22 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des // Relocations for the imports may be overridden freeSlot->status = RELOC_TRAMP_IMPORT_DONE; } - auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]); - value = symbolValue + addend; - distance = static_cast(value) - static_cast(target); + distance = newDistance; } } if (distance & 3) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022); + DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022); return false; } if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040); + DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040); return false; } if (distance >= 0 && (distance & 0xFE000000)) { - DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040); + DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040); return false; } @@ -142,8 +148,10 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des break; } default: - DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type); + DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type); return false; } + ICInvalidateRange(reinterpret_cast(target), 4); + DCFlushRange(reinterpret_cast(target), 4); return true; } diff --git a/relocator/src/ElfUtils.h b/wumsloader/src/utils/ElfUtils.h similarity index 100% rename from relocator/src/ElfUtils.h rename to wumsloader/src/utils/ElfUtils.h diff --git a/wumsloader/src/utils/RelocationUtils.cpp b/wumsloader/src/utils/RelocationUtils.cpp new file mode 100644 index 0000000..62cf9f7 --- /dev/null +++ b/wumsloader/src/utils/RelocationUtils.cpp @@ -0,0 +1,102 @@ +#include "RelocationUtils.h" +#include "globals.h" +#include "utils/ElfUtils.h" +#include "utils/memory.h" +#include +#include + +bool ResolveRelocations(std::vector> &loadedModules, bool skipMemoryMappingModule) { + bool wasSuccessful = true; + + for (auto &curModule : loadedModules) { + DEBUG_FUNCTION_LINE("Let's do the relocations for %s", curModule->getExportName().c_str()); + + auto &relocData = curModule->getRelocationDataList(); + + // On first usage we can't redirect the alloc functions to our custom heap + // because threads can't run it on it. In order to patch the kernel + // to fully support our memory region, we have to run the MemoryMapping once with the default heap. + // Afterwards we can just rely on the custom heap. + bool skipAllocFunction = skipMemoryMappingModule && (std::string_view(curModule->getExportName()) == "homebrew_memorymapping"); + DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d", skipAllocFunction); + if (!doRelocation(gLoadedModules, relocData, nullptr, 0, skipAllocFunction)) { + wasSuccessful = false; + DEBUG_FUNCTION_LINE_ERR("Failed to do Relocations for %s", curModule->getExportName().c_str()); + OSFatal("Failed to do Reloations"); + } + } + DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE); + ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE); + return wasSuccessful; +} + + +bool doRelocation(const std::vector> &moduleList, + const std::vector> &relocData, + relocation_trampoline_entry_t *tramp_data, + uint32_t tramp_length, + bool skipAllocReplacement) { + std::map moduleCache; + for (auto const &curReloc : relocData) { + auto &functionName = curReloc->getName(); + std::string rplName = curReloc->getImportRPLInformation()->getRPLName(); + uint32_t functionAddress = 0; + + for (auto &module : moduleList) { + if (rplName == module->getExportName()) { + for (auto &exportData : module->getExportDataList()) { + if (functionName == exportData->getName()) { + functionAddress = (uint32_t) exportData->getAddress(); + } + } + } + } + + if (!skipAllocReplacement) { + if (functionName == "MEMAllocFromDefaultHeap") { + functionAddress = reinterpret_cast(&MEMAlloc); + } else if (functionName == "MEMAllocFromDefaultHeapEx") { + functionAddress = reinterpret_cast(&MEMAllocEx); + } else if (functionName == "MEMFreeToDefaultHeap") { + functionAddress = reinterpret_cast(&MEMFree); + } + } + + if (functionAddress == 0) { + int32_t isData = curReloc->getImportRPLInformation()->isData(); + OSDynLoad_Module rplHandle = nullptr; + if (moduleCache.count(rplName) == 0) { + OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle); + if (err != OS_DYNLOAD_OK || rplHandle == nullptr) { + DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded", rplName.c_str()); + // only acquire if not already loaded. + err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle); + if (err != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_ERR("Failed to acquire %s", rplName.c_str()); + return false; + } + } + moduleCache[rplName] = rplHandle; + } + rplHandle = moduleCache.at(rplName); + + OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress); + if (functionAddress == 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to find export %s of %s", functionName.begin(), rplName.c_str()); + OSFatal("Failed to find export"); + return false; + } + } + + if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length, + RELOC_TYPE_IMPORT)) { + DEBUG_FUNCTION_LINE_ERR("Relocation failed"); + return false; + } + } + if (tramp_data != nullptr) { + DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t)); + ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t)); + } + return true; +} \ No newline at end of file diff --git a/wumsloader/src/utils/RelocationUtils.h b/wumsloader/src/utils/RelocationUtils.h new file mode 100644 index 0000000..d9d4ab6 --- /dev/null +++ b/wumsloader/src/utils/RelocationUtils.h @@ -0,0 +1,12 @@ +#pragma once +#include "module/ModuleData.h" +#include + +bool ResolveRelocations(std::vector> &loadedModules, + bool skipMemoryMappingModule); + +bool doRelocation(const std::vector> &moduleList, + const std::vector> &relocData, + relocation_trampoline_entry_t *tramp_data, + uint32_t tramp_length, + bool skipAllocReplacement); \ No newline at end of file diff --git a/wumsloader/src/utils/StringTools.cpp b/wumsloader/src/utils/StringTools.cpp new file mode 100644 index 0000000..3fa643a --- /dev/null +++ b/wumsloader/src/utils/StringTools.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** +* Copyright (C) 2010 +* by Dimok +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any +* damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any +* purpose, including commercial applications, and to alter it and +* redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you +* must not claim that you wrote the original software. If you use +* this software in a product, an acknowledgment in the product +* documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and +* must not be misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source +* distribution. +* +* for WiiXplorer 2010 +***************************************************************************/ + +#include +#include +#include +#include +#include + +int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) { + if (!string || !compare) + return -1; + + char TokCopy[512]; + strncpy(TokCopy, compare, sizeof(TokCopy)); + TokCopy[511] = '\0'; + + char *strTok = strtok(TokCopy, separator); + + while (strTok != nullptr) { + if (strcasecmp(string, strTok) == 0) { + return 0; + } + strTok = strtok(nullptr, separator); + } + + return -1; +} diff --git a/source/utils/StringTools.h b/wumsloader/src/utils/StringTools.h similarity index 51% rename from source/utils/StringTools.h rename to wumsloader/src/utils/StringTools.h index d1a1570..3a2bdda 100644 --- a/source/utils/StringTools.h +++ b/wumsloader/src/utils/StringTools.h @@ -23,42 +23,55 @@ * * for WiiXplorer 2010 ***************************************************************************/ -#ifndef __STRING_TOOLS_H -#define __STRING_TOOLS_H +#pragma once +#include #include #include #include +template +std::string string_format(const std::string &format, Args... args) { + int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' + auto size = static_cast(size_s); + auto buf = std::make_unique(size); + std::snprintf(buf.get(), size, format.c_str(), args...); + return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside +} + + class StringTools { public: - static BOOL EndsWith(const std::string &a, const std::string &b); - - static const char *byte_to_binary(int32_t x); - - static std::string removeCharFromString(std::string &input, char toBeRemoved); - - static const char *fmt(const char *format, ...); - - static const wchar_t *wfmt(const char *format, ...); - - static int32_t strprintf(std::string &str, const char *format, ...); - - static std::string strfmt(const char *format, ...); - - static BOOL char2wchar_t(const char *src, wchar_t *dest); - static int32_t strtokcmp(const char *string, const char *compare, const char *separator); - static int32_t strextcmp(const char *string, const char *extension, char seperator); - static char *str_replace(char *orig, char *rep, char *with); + static const char *FullpathToFilename(const char *path) { + if (!path) + return path; - static const char *FullpathToFilename(const char *path); + const char *ptr = path; + const char *Filename = ptr; - static void RemoveDoubleSlashs(std::string &str); + while (*ptr != '\0') { + if (ptr[0] == '/' && ptr[1] != '\0') + Filename = ptr + 1; - static std::vector stringSplit(const std::string &value, const std::string &splitter); -}; + ++ptr; + } -#endif /* __STRING_TOOLS_H */ + return Filename; + } + + static void RemoveDoubleSlashs(std::string &str) { + uint32_t length = str.size(); + + //! clear path of double slashes + for (uint32_t i = 1; i < length; ++i) { + if (str[i - 1] == '/' && str[i] == '/') { + str.erase(i, 1); + i--; + length--; + } + } + } +}; \ No newline at end of file diff --git a/relocator/src/utils/dynamic.c b/wumsloader/src/utils/dynamic.c similarity index 62% rename from relocator/src/utils/dynamic.c rename to wumsloader/src/utils/dynamic.c index 16e85b5..b0822be 100644 --- a/relocator/src/utils/dynamic.c +++ b/wumsloader/src/utils/dynamic.c @@ -21,6 +21,11 @@ } while (0) #define IMPORT_END() +#define EXPORT_VAR(type, var) type var __attribute__((section(".data"))); + +EXPORT_VAR(uint32_t *, MEMAllocFromDefaultHeap); +EXPORT_VAR(uint32_t *, MEMAllocFromDefaultHeapEx); +EXPORT_VAR(uint32_t *, MEMFreeToDefaultHeap); void InitFunctionPointers(void) { OSDynLoad_Module handle; @@ -28,5 +33,16 @@ void InitFunctionPointers(void) { addr_OSDynLoad_FindExport = (void *) 0x0102B828; // 0200f428 - 0xFE3C00 addr_OSDynLoad_IsModuleLoaded = (void *) 0x0102A59C; // 0200e19c - 0xFE3C00 + OSDynLoad_Acquire("coreinit.rpl", &handle); + + uint32_t **value = 0; + OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeap", (void **) &value); + MEMAllocFromDefaultHeap = *value; + OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeapEx", (void **) &value); + MEMAllocFromDefaultHeapEx = *value; + OSDynLoad_FindExport(handle, 1, "MEMFreeToDefaultHeap", (void **) &value); + MEMFreeToDefaultHeap = *value; #include "imports.h" + // override failed __rplwrap_exit find export + OSDynLoad_FindExport(handle, 0, "exit", (void **) &addr___rplwrap_exit); } diff --git a/relocator/src/utils/dynamic.h b/wumsloader/src/utils/dynamic.h similarity index 100% rename from relocator/src/utils/dynamic.h rename to wumsloader/src/utils/dynamic.h diff --git a/relocator/src/hooks.cpp b/wumsloader/src/utils/hooks.cpp similarity index 61% rename from relocator/src/hooks.cpp rename to wumsloader/src/utils/hooks.cpp index e690af6..d535736 100644 --- a/relocator/src/hooks.cpp +++ b/wumsloader/src/utils/hooks.cpp @@ -1,7 +1,11 @@ #include "hooks.h" #include "globals.h" +#include "module/ModuleData.h" +#include "utils/logger.h" +#include #include +#ifdef DEBUG static const char **hook_names = (const char *[]){ "WUMS_HOOK_INIT_WUT_MALLOC", "WUMS_HOOK_FINI_WUT_MALLOC", @@ -22,36 +26,32 @@ static const char **hook_names = (const char *[]){ "WUMS_HOOK_APPLICATION_ENDS", "WUMS_HOOK_RELOCATIONS_DONE", "WUMS_HOOK_APPLICATION_REQUESTS_EXIT"}; +#endif -void CallHook(const std::vector> &modules, wums_hook_type_t type, bool condition) { +void CallHook(const std::vector> &modules, wums_hook_type_t type, bool condition) { if (condition) { CallHook(modules, type); } } -void CallHook(const std::vector> &modules, wums_hook_type_t type) { - DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] for all modules\n", hook_names[type], type); +void CallHook(const std::vector> &modules, wums_hook_type_t type) { + DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] for all modules", hook_names[type], type); for (auto &curModule : modules) { CallHook(curModule, type); } } -void CallHook(const std::shared_ptr &module, wums_hook_type_t type, bool condition) { +void CallHook(const std::shared_ptr &module, wums_hook_type_t type, bool condition) { if (condition) { CallHook(module, type); } } -void CallHook(const std::shared_ptr &module, wums_hook_type_t type) { - if (!module->relocationsDone) { - DEBUG_FUNCTION_LINE("Hook not called because the relocations failed\n"); - return; - } - +void CallHook(const std::shared_ptr &module, wums_hook_type_t type) { for (auto &curHook : module->getHookDataList()) { auto func_ptr = (uint32_t) curHook->getTarget(); if (func_ptr == 0) { - DEBUG_FUNCTION_LINE("Hook ptr was NULL\n"); + DEBUG_FUNCTION_LINE_ERR("Module %s: hook ptr was NULL", module->getExportName().c_str()); break; } @@ -70,19 +70,19 @@ void CallHook(const std::shared_ptr &module, wums_hook_type_t type == WUMS_HOOK_FINI_WUT_SOCKETS || type == WUMS_HOOK_INIT_WRAPPER || type == WUMS_HOOK_FINI_WRAPPER)) { - DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] %d for %s: %08X\n", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget()); + DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] %d for %s: %08X", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget()); ((void (*)())((uint32_t *) func_ptr))(); break; } else if (type == WUMS_HOOK_INIT || type == WUMS_HOOK_RELOCATIONS_DONE) { - DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] %d for %s: %08X\n", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget()); + DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] %d for %s: %08X", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget()); wums_app_init_args_t args; - args.module_information = gModuleData; + args.module_information = &gModuleInformation; ((void (*)(wums_app_init_args_t *))((uint32_t *) func_ptr))(&args); } else { - DEBUG_FUNCTION_LINE("#########################################\n"); - DEBUG_FUNCTION_LINE("#########HOOK NOT IMPLEMENTED %d#########\n", type); - DEBUG_FUNCTION_LINE("#########################################\n"); + DEBUG_FUNCTION_LINE_ERR("#########################################"); + DEBUG_FUNCTION_LINE_ERR("#########HOOK NOT IMPLEMENTED %d#########", type); + DEBUG_FUNCTION_LINE_ERR("#########################################"); } break; } diff --git a/wumsloader/src/utils/hooks.h b/wumsloader/src/utils/hooks.h new file mode 100644 index 0000000..f527516 --- /dev/null +++ b/wumsloader/src/utils/hooks.h @@ -0,0 +1,14 @@ +#pragma once + +#include "module/ModuleData.h" +#include +#include +#include + +void CallHook(const std::vector> &modules, wums_hook_type_t type, bool condition); + +void CallHook(const std::vector> &modules, wums_hook_type_t type); + +void CallHook(const std::shared_ptr &module, wums_hook_type_t type, bool condition); + +void CallHook(const std::shared_ptr &module, wums_hook_type_t type); diff --git a/relocator/src/utils/import_stub.S b/wumsloader/src/utils/import_stub.S similarity index 100% rename from relocator/src/utils/import_stub.S rename to wumsloader/src/utils/import_stub.S diff --git a/relocator/src/utils/imports.h b/wumsloader/src/utils/imports.h similarity index 51% rename from relocator/src/utils/imports.h rename to wumsloader/src/utils/imports.h index 5a298cb..f398862 100644 --- a/relocator/src/utils/imports.h +++ b/wumsloader/src/utils/imports.h @@ -18,6 +18,53 @@ IMPORT(MEMCreateExpHeapEx); IMPORT(OSUninterruptibleSpinLock_Acquire); IMPORT(OSUninterruptibleSpinLock_Release); IMPORT(OSReport); +IMPORT(MEMGetTotalFreeSizeForExpHeap); +IMPORT(OSMemoryBarrier); +IMPORT(OSInitMutex); +IMPORT(OSLockMutex); +IMPORT(OSUnlockMutex); +IMPORT(OSCompareAndSwapAtomicEx); +IMPORT(OSCompareAndSwapAtomic); +IMPORT(OSGetThreadSpecific); +IMPORT(OSSetThreadSpecific); +IMPORT(OSInitCond); +IMPORT(OSWaitCond); +IMPORT(OSSignalCond); +IMPORT(MEMAllocFromDefaultHeapEx); +IMPORT(MEMFreeToDefaultHeap); + +IMPORT(FSTimeToCalendarTime); +IMPORT(FSInit); +IMPORT(FSShutdown); +IMPORT(FSAddClient); +IMPORT(FSAddClientEx); +IMPORT(FSDelClient); +IMPORT(FSInitCmdBlock); +IMPORT(FSChangeDir); +IMPORT(FSGetFreeSpaceSize); +IMPORT(FSGetStat); +IMPORT(FSRemove); +IMPORT(FSOpenFile); +IMPORT(FSCloseFile); +IMPORT(FSOpenDir); +IMPORT(FSMakeDir); +IMPORT(FSReadDir); +IMPORT(FSRewindDir); +IMPORT(FSCloseDir); +IMPORT(FSGetStatFile); +IMPORT(FSReadFile); +IMPORT(FSWriteFile); +IMPORT(FSSetPosFile); +IMPORT(FSFlushFile); +IMPORT(FSTruncateFile); +IMPORT(FSRename); +IMPORT(FSGetMountSource); +IMPORT(FSMount); +IMPORT(FSUnmount); +IMPORT(FSChangeMode); +IMPORT(FSGetPosFile); +IMPORT(OSTicksToCalendarTime); +IMPORT(__rplwrap_exit); IMPORT_END(); diff --git a/wumsloader/src/utils/logger.c b/wumsloader/src/utils/logger.c new file mode 100644 index 0000000..36a73ae --- /dev/null +++ b/wumsloader/src/utils/logger.c @@ -0,0 +1,38 @@ +#ifdef DEBUG +#include +#include +#include +#include +#include + +uint32_t moduleLogInit = false; +uint32_t cafeLogInit = false; +uint32_t udpLogInit = false; +#endif // DEBUG + +void initLogging() { +#ifdef DEBUG + if (!(moduleLogInit = WHBLogModuleInit())) { + socket_lib_init(); + cafeLogInit = WHBLogCafeInit(); + udpLogInit = WHBLogUdpInit(); + } +#endif // DEBUG +} + +void deinitLogging() { +#ifdef DEBUG + if (moduleLogInit) { + WHBLogModuleDeinit(); + moduleLogInit = false; + } + if (cafeLogInit) { + WHBLogCafeDeinit(); + cafeLogInit = false; + } + if (udpLogInit) { + WHBLogUdpDeinit(); + udpLogInit = false; + } +#endif // DEBUG +} \ No newline at end of file diff --git a/wumsloader/src/utils/logger.h b/wumsloader/src/utils/logger.h new file mode 100644 index 0000000..2bb7a3e --- /dev/null +++ b/wumsloader/src/utils/logger.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_APP_TYPE "M" +#define LOG_APP_NAME "WUMSLoader" + +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) + +#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS) + +#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \ + do { \ + LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ + } while (0) + + +#ifdef DEBUG + +#ifdef VERBOSE_DEBUG +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS) +#else +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0) +#endif + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS) + +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS) + +#else + +#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0) + +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS) + +#endif + +void initLogging(); + +void deinitLogging(); + +#ifdef __cplusplus +} +#endif diff --git a/relocator/src/utils/memory.cpp b/wumsloader/src/utils/memory.cpp similarity index 94% rename from relocator/src/utils/memory.cpp rename to wumsloader/src/utils/memory.cpp index 2df306f..2c935fc 100644 --- a/relocator/src/utils/memory.cpp +++ b/wumsloader/src/utils/memory.cpp @@ -15,13 +15,13 @@ * along with this program. If not, see . ****************************************************************************/ #include "logger.h" +#include #include #include #include #include -#include +#include #include -#include extern MEMHeapHandle gHeapHandle; @@ -32,11 +32,10 @@ void *MEMAllocSafe(uint32_t size, uint32_t align) { return res; } - void *MemoryAlloc(uint32_t size) { void *res = MEMAllocSafe(size, 4); if (res == nullptr) { - OSFatal_printf("Failed to MemoryAlloc %d", size); + OSFatal("Failed to MemoryAlloc"); } return res; } @@ -44,7 +43,7 @@ void *MemoryAlloc(uint32_t size) { void *MemoryAllocEx(uint32_t size, uint32_t align) { void *res = MEMAllocSafe(size, align); if (res == nullptr) { - OSFatal_printf("Failed to MemoryAllocEX %d %d", size, align); + OSFatal("Failed to MemoryAllocEX"); } return res; } @@ -53,7 +52,7 @@ void MemoryFree(void *ptr) { if (ptr) { MEMFreeToExpHeap(gHeapHandle, ptr); } else { - OSFatal_printf("Failed to free"); + OSFatal("Failed to free"); } } diff --git a/relocator/src/utils/memory.h b/wumsloader/src/utils/memory.h similarity index 100% rename from relocator/src/utils/memory.h rename to wumsloader/src/utils/memory.h