mirror of
https://github.com/wiiu-env/WUMSLoader.git
synced 2024-11-16 13:09:18 +01:00
102 lines
4.7 KiB
C++
102 lines
4.7 KiB
C++
|
#include "RelocationUtils.h"
|
||
|
#include "globals.h"
|
||
|
#include "utils/ElfUtils.h"
|
||
|
#include "utils/memory.h"
|
||
|
#include <coreinit/cache.h>
|
||
|
#include <coreinit/dynload.h>
|
||
|
|
||
|
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &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<std::shared_ptr<ModuleData>> &moduleList,
|
||
|
const std::vector<std::unique_ptr<RelocationData>> &relocData,
|
||
|
relocation_trampoline_entry_t *tramp_data,
|
||
|
uint32_t tramp_length,
|
||
|
bool skipAllocReplacement) {
|
||
|
std::map<std::string, OSDynLoad_Module> 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<uint32_t>(&MEMAlloc);
|
||
|
} else if (functionName == "MEMAllocFromDefaultHeapEx") {
|
||
|
functionAddress = reinterpret_cast<uint32_t>(&MEMAllocEx);
|
||
|
} else if (functionName == "MEMFreeToDefaultHeap") {
|
||
|
functionAddress = reinterpret_cast<uint32_t>(&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;
|
||
|
}
|