From 199e959dccfe1699e1ac7ea5e846036e56f94e3c Mon Sep 17 00:00:00 2001 From: Maschell Date: Tue, 18 Feb 2025 08:18:50 +0100 Subject: [PATCH] Add support for 0.3.4 to allow an custom rpl allocator --- Dockerfile | 2 +- wumsloader/src/entry.cpp | 14 +++++--- wumsloader/src/globals.cpp | 5 ++- wumsloader/src/globals.h | 3 ++ wumsloader/src/module/ModuleDataFactory.cpp | 2 +- wumsloader/src/utils/RelocationUtils.cpp | 36 +++++++++++++++------ wumsloader/src/utils/RelocationUtils.h | 7 ++-- wumsloader/src/utils/hooks.cpp | 13 ++++++++ wumsloader/src/utils/logger.h | 1 + 9 files changed, 63 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5d60105..2be4791 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM ghcr.io/wiiu-env/devkitppc:20241128 -COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20250208 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:0.3.4-dev-20250218-b62548a /artifacts $DEVKITPRO WORKDIR project diff --git a/wumsloader/src/entry.cpp b/wumsloader/src/entry.cpp index ac1f6ad..4543a59 100644 --- a/wumsloader/src/entry.cpp +++ b/wumsloader/src/entry.cpp @@ -16,7 +16,7 @@ #include #include -#define VERSION "v0.2.7" +#define VERSION "v0.2.8" void CallInitHooksForModule(const std::shared_ptr &curModule); @@ -209,7 +209,7 @@ void doStart(int argc, char **argv) { } #endif - DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions"); + DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without loading additonal rpls"); ResolveRelocations(gLoadedModules, true, gUsedRPLs); for (auto &curModule : gLoadedModules) { @@ -218,9 +218,14 @@ void doStart(int argc, char **argv) { } } + // Hacky workaround for modules to allow register a custom rpl allocator function + CallHook(gLoadedModules, WUMS_HOOK_GET_CUSTOM_RPL_ALLOCATOR); + + // Now we can load unloaded rpls. + ResolveRelocations(gLoadedModules, false, gUsedRPLs); + DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook"); CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE); - CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE); for (auto &curModule : gLoadedModules) { if (!curModule->isInitBeforeRelocationDoneHook()) { @@ -228,7 +233,8 @@ void doStart(int argc, char **argv) { } } } else { - DEBUG_FUNCTION_LINE("Resolve relocations and replace alloc functions"); + DEBUG_FUNCTION_LINE("Resolve relocations and load unloaded rpls functions"); + CallHook(gLoadedModules, WUMS_HOOK_CLEAR_ALLOCATED_RPL_MEMORY); ResolveRelocations(gLoadedModules, false, gUsedRPLs); CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE); } diff --git a/wumsloader/src/globals.cpp b/wumsloader/src/globals.cpp index d007573..399ab08 100644 --- a/wumsloader/src/globals.cpp +++ b/wumsloader/src/globals.cpp @@ -7,4 +7,7 @@ std::vector> gLoadedModules __attribute__((section(" std::unique_ptr gModuleDataInfo __attribute__((section(".data"))); std::map gUsedRPLs __attribute__((section(".data"))); -std::vector gAllocatedAddresses __attribute__((section(".data"))); \ No newline at end of file +std::vector gAllocatedAddresses __attribute__((section(".data"))); + +WUMSRPLAllocatorAllocFn gCustomRPLAllocatorAllocFn __attribute__((section(".data"))) = nullptr; +WUMSRPLAllocatorFreeFn gCustomRPLAllocatorFreeFn __attribute__((section(".data"))) = nullptr; \ No newline at end of file diff --git a/wumsloader/src/globals.h b/wumsloader/src/globals.h index c71eaa9..1621d18 100644 --- a/wumsloader/src/globals.h +++ b/wumsloader/src/globals.h @@ -14,6 +14,9 @@ extern std::unique_ptr gModuleDataInfo; extern std::map gUsedRPLs; extern std::vector gAllocatedAddresses; +extern WUMSRPLAllocatorAllocFn gCustomRPLAllocatorAllocFn; +extern WUMSRPLAllocatorFreeFn gCustomRPLAllocatorFreeFn; + #define MEMORY_REGION_START 0x00800000 #define MEMORY_REGION_SIZE 0x00800000 diff --git a/wumsloader/src/module/ModuleDataFactory.cpp b/wumsloader/src/module/ModuleDataFactory.cpp index ccb72d4..fe0569e 100644 --- a/wumsloader/src/module/ModuleDataFactory.cpp +++ b/wumsloader/src/module/ModuleDataFactory.cpp @@ -95,7 +95,7 @@ std::optional> ModuleDataFactory::load(const std::st } } else if (key == "wums" || key == "wum") { checkedVersion = true; - if (value != "0.3.1" && value != "0.3.2" && value != "0.3.3") { + if (value != "0.3.1" && value != "0.3.2" && value != "0.3.3" && value != "0.3.4") { DEBUG_FUNCTION_LINE_WARN("Ignoring module - Unsupported WUMS version: %s.", value.c_str()); return std::nullopt; } diff --git a/wumsloader/src/utils/RelocationUtils.cpp b/wumsloader/src/utils/RelocationUtils.cpp index fa43a3f..da65e0c 100644 --- a/wumsloader/src/utils/RelocationUtils.cpp +++ b/wumsloader/src/utils/RelocationUtils.cpp @@ -33,33 +33,41 @@ static void CustomDynLoadFree(void *addr) { free(addr); // Remove from list - auto it = std::find(gAllocatedAddresses.begin(), gAllocatedAddresses.end(), addr); - if (it != gAllocatedAddresses.end()) { + if (const auto it = std::ranges::find(gAllocatedAddresses, addr); it != gAllocatedAddresses.end()) { gAllocatedAddresses.erase(it); } } -bool ResolveRelocations(std::vector> &loadedModules, bool skipMemoryMappingModule, std::map &usedRPls) { +bool ResolveRelocations(const std::vector> &loadedModules, const bool skipUnloadedRpl, std::map &usedRPls) { bool wasSuccessful = true; + OSDynLoadAllocFn prevDynLoadAlloc = nullptr; OSDynLoadFreeFn prevDynLoadFree = nullptr; - OSDynLoad_GetAllocator(&prevDynLoadAlloc, &prevDynLoadFree); - OSDynLoad_SetAllocator(CustomDynLoadAlloc, CustomDynLoadFree); + if (!skipUnloadedRpl) { + OSDynLoad_GetAllocator(&prevDynLoadAlloc, &prevDynLoadFree); + if (gCustomRPLAllocatorAllocFn != nullptr && gCustomRPLAllocatorFreeFn != nullptr) { + OSDynLoad_SetAllocator(reinterpret_cast(gCustomRPLAllocatorAllocFn), gCustomRPLAllocatorFreeFn); + } else { + OSDynLoad_SetAllocator(CustomDynLoadAlloc, CustomDynLoadFree); + } + } for (auto &curModule : loadedModules) { DEBUG_FUNCTION_LINE("Let's do the relocations for %s", curModule->getExportName().c_str()); auto &relocData = curModule->getRelocationDataList(); - if (!doRelocation(gLoadedModules, relocData, nullptr, 0, usedRPls)) { + if (!doRelocation(gLoadedModules, relocData, nullptr, 0, usedRPls, skipUnloadedRpl)) { wasSuccessful = false; DEBUG_FUNCTION_LINE_ERR("Failed to do Relocations for %s", curModule->getExportName().c_str()); OSFatal("Failed to do Relocations"); } } - OSDynLoad_SetAllocator(prevDynLoadAlloc, prevDynLoadFree); + if (!skipUnloadedRpl) { + OSDynLoad_SetAllocator(prevDynLoadAlloc, prevDynLoadFree); + } DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE); ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE); @@ -70,8 +78,9 @@ bool ResolveRelocations(std::vector> &loadedModules, bool doRelocation(const std::vector> &moduleList, const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, - uint32_t tramp_length, - std::map &usedRPls) { + const uint32_t tramp_length, + std::map &usedRPls, + const bool skipUnloadedRpl) { for (auto const &curReloc : relocData) { auto &functionName = curReloc->getName(); std::string rplName = curReloc->getImportRPLInformation()->getRPLName(); @@ -106,7 +115,14 @@ bool doRelocation(const std::vector> &moduleList, OSDynLoad_Module rplHandle = nullptr; if (!usedRPls.contains(rplName)) { - DEBUG_FUNCTION_LINE_VERBOSE("Acquire %s", rplName.c_str()); + OSDynLoad_Module tmp = nullptr; + if (OSDynLoad_IsModuleLoaded(rplName.c_str(), &tmp) != OS_DYNLOAD_OK || tmp == nullptr) { + if (skipUnloadedRpl) { + DEBUG_FUNCTION_LINE_VERBOSE("Skip acquire of %s", rplName.c_str()); + continue; + } + } + // Always acquire to increase refcount and make sure it won't get unloaded while we're using it. OSDynLoad_Error err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle); if (err != OS_DYNLOAD_OK) { diff --git a/wumsloader/src/utils/RelocationUtils.h b/wumsloader/src/utils/RelocationUtils.h index 880dfe9..1237f33 100644 --- a/wumsloader/src/utils/RelocationUtils.h +++ b/wumsloader/src/utils/RelocationUtils.h @@ -4,12 +4,13 @@ #include #include -bool ResolveRelocations(std::vector> &loadedModules, - bool skipMemoryMappingModule, +bool ResolveRelocations(const std::vector> &loadedModules, + bool skipUnloadedRpl, std::map &usedRPls); bool doRelocation(const std::vector> &moduleList, const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, - std::map &usedRPls); \ No newline at end of file + std::map &usedRPls, + bool skipUnloadedRpl); \ No newline at end of file diff --git a/wumsloader/src/utils/hooks.cpp b/wumsloader/src/utils/hooks.cpp index 16384e9..d553d10 100644 --- a/wumsloader/src/utils/hooks.cpp +++ b/wumsloader/src/utils/hooks.cpp @@ -27,10 +27,15 @@ static const char **hook_names = (const char *[]){ "WUMS_HOOK_APPLICATION_ENDS", "WUMS_HOOK_RELOCATIONS_DONE", "WUMS_HOOK_APPLICATION_REQUESTS_EXIT", + "WUMS_HOOK_DEINIT", + "WUMS_HOOK_ALL_APPLICATION_STARTS_DONE", "WUMS_HOOK_ALL_APPLICATION_ENDS_DONE", "WUMS_HOOK_ALL_APPLICATION_REQUESTS_EXIT_DONE", + + "WUMS_HOOK_GET_CUSTOM_RPL_ALLOCATOR", + "WUMS_HOOK_CLEAR_ALLOCATED_RPL_MEMORY", }; #endif @@ -82,6 +87,7 @@ void CallHook(const std::shared_ptr &module, wums_hook_type_t type) type == WUMS_HOOK_DEINIT || type == WUMS_HOOK_ALL_APPLICATION_STARTS_DONE || type == WUMS_HOOK_ALL_APPLICATION_ENDS_DONE || + type == WUMS_HOOK_CLEAR_ALLOCATED_RPL_MEMORY || type == WUMS_HOOK_ALL_APPLICATION_REQUESTS_EXIT_DONE)) { 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))(); @@ -92,6 +98,13 @@ void CallHook(const std::shared_ptr &module, wums_hook_type_t type) wums_app_init_args_t args; args.module_information = &gModuleInformation; ((void (*)(wums_app_init_args_t *))((uint32_t *) func_ptr))(&args); + } else if (type == WUMS_HOOK_GET_CUSTOM_RPL_ALLOCATOR) { + 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()); + + const auto [allocFn, freeFn] = reinterpret_cast(reinterpret_cast(func_ptr))(); + gCustomRPLAllocatorAllocFn = allocFn; + gCustomRPLAllocatorFreeFn = freeFn; + } else { DEBUG_FUNCTION_LINE_ERR("#########################################"); DEBUG_FUNCTION_LINE_ERR("#########HOOK NOT IMPLEMENTED %d#########", type); diff --git a/wumsloader/src/utils/logger.h b/wumsloader/src/utils/logger.h index cdea2d8..8880106 100644 --- a/wumsloader/src/utils/logger.h +++ b/wumsloader/src/utils/logger.h @@ -49,6 +49,7 @@ extern "C" { #define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS) #define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX(OSReport, "##WARN ## ", "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX(OSReport, "##INFO ## ", "\n", FMT, ##ARGS) #endif