From 5da6afb310d9bb0b7a45d86ddd7d3eb6a15b1753 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 16 Jun 2023 17:17:19 +0200 Subject: [PATCH] Improve RPL loading when running the environment setup files --- source/ElfUtils.cpp | 25 ++++++++++++++++--------- source/ElfUtils.h | 4 +++- source/main.cpp | 10 +++++++++- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/source/ElfUtils.cpp b/source/ElfUtils.cpp index adaaf9e..48a8a9e 100644 --- a/source/ElfUtils.cpp +++ b/source/ElfUtils.cpp @@ -3,28 +3,35 @@ #include #include #include -#include #include "ElfUtils.h" #include "elfio/elfio.hpp" -bool ElfUtils::doRelocation(const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length) { +bool ElfUtils::doRelocation(const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map &usedRPls) { for (auto const &curReloc : relocData) { std::string functionName = curReloc->getName(); std::string rplName = curReloc->getImportRPLInformation()->getRPLName(); int32_t isData = curReloc->getImportRPLInformation()->isData(); OSDynLoad_Module rplHandle = nullptr; - - auto err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle); - if (err != OS_DYNLOAD_OK || rplHandle == nullptr) { - // only acquire if not already loaded. - OSDynLoad_Acquire(rplName.c_str(), &rplHandle); + if (!usedRPls.contains(rplName)) { + DEBUG_FUNCTION_LINE_VERBOSE("Acquire %s", rplName.c_str()); + // 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) { + DEBUG_FUNCTION_LINE_ERR("Failed to acquire %s", rplName.c_str()); + return false; + } + // Keep track RPLs we are using. + // They will be released on exit (See: AromaBaseModule) + usedRPls[rplName] = rplHandle; + } else { + DEBUG_FUNCTION_LINE_VERBOSE("Use from usedRPLs cache! %s", rplName.c_str()); } + rplHandle = usedRPls[rplName]; uint32_t functionAddress = 0; - OSDynLoad_FindExport(rplHandle, (OSDynLoad_ExportType) isData, functionName.c_str(), (void **) &functionAddress); - if (functionAddress == 0) { + if ((OSDynLoad_FindExport(rplHandle, (OSDynLoad_ExportType) isData, functionName.c_str(), (void **) &functionAddress) != OS_DYNLOAD_OK) || functionAddress == 0) { DEBUG_FUNCTION_LINE_ERR("Failed to find export for %s %s %d", functionName.c_str(), rplName.c_str(), isData); return false; } diff --git a/source/ElfUtils.h b/source/ElfUtils.h index c544f28..e077055 100644 --- a/source/ElfUtils.h +++ b/source/ElfUtils.h @@ -2,8 +2,10 @@ #include "common/relocation_defines.h" #include "module/RelocationData.h" +#include #include #include +#include #include #include @@ -50,5 +52,5 @@ public: RelocationType reloc_type); - static bool doRelocation(const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length); + static bool doRelocation(const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map &usedRPls); }; diff --git a/source/main.cpp b/source/main.cpp index dfa0aa7..7582249 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -180,6 +180,7 @@ int main(int argc, char **argv) { DirList setupModules(environment_path + "/modules/setup", ".rpx", DirList::Files, 1); setupModules.SortList(); + std::map usedRPls; for (int i = 0; i < setupModules.GetFilecount(); i++) { //! skip hidden linux and mac files if (setupModules.GetFilename(i)[0] == '.' || setupModules.GetFilename(i)[0] == '_') { @@ -206,7 +207,7 @@ int main(int argc, char **argv) { continue; } DEBUG_FUNCTION_LINE("Loaded module data"); - if (!ElfUtils::doRelocation(moduleData.value()->getRelocationDataList(), gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) { + if (!ElfUtils::doRelocation(moduleData.value()->getRelocationDataList(), gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH, usedRPls)) { DEBUG_FUNCTION_LINE_ERR("Relocations failed"); OSFatal("EnvironmentLoader: Relocations failed"); } else { @@ -223,7 +224,14 @@ int main(int argc, char **argv) { ((int(*)(int, char **)) moduleData.value()->getEntrypoint())(1, arr); // clang-format on DEBUG_FUNCTION_LINE("Back from module"); + + for (auto &rpl : usedRPls) { + DEBUG_FUNCTION_LINE_VERBOSE("Release %s", rpl.first.c_str()); + OSDynLoad_Release(rpl.second); + } + usedRPls.clear(); } + } else { DEBUG_FUNCTION_LINE("Return to Wii U Menu"); ProcUIInit(OSSavesDone_ReadyToRelease);