diff --git a/source/PluginManagement.cpp b/source/PluginManagement.cpp index 65b3fbd..95d39d3 100644 --- a/source/PluginManagement.cpp +++ b/source/PluginManagement.cpp @@ -24,10 +24,8 @@ #include -static uint32_t sTrampolineID = 0; - std::vector -PluginManagement::loadPlugins(const std::vector &pluginDataList, std::vector &trampolineData) { +PluginManagement::loadPlugins(const std::vector &pluginDataList) { std::vector plugins; for (const auto &pluginDataWrapper : pluginDataList) { @@ -37,7 +35,7 @@ PluginManagement::loadPlugins(const std::vector &pluginDataLi if (pluginDataWrapper.isLoadAndLink()) { DEBUG_FUNCTION_LINE_INFO("LOAD (ACTIVE) %s", metaInfo->getName().c_str()); - auto linkInfo = PluginLinkInformationFactory::load(*pluginDataWrapper.getPluginData(), trampolineData, sTrampolineID++); + auto linkInfo = PluginLinkInformationFactory::load(*pluginDataWrapper.getPluginData()); if (!linkInfo) { auto errMsg = string_format("Failed to load plugin: %s", pluginDataWrapper.getPluginData()->getSource().c_str()); DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str()); @@ -68,8 +66,7 @@ PluginManagement::loadPlugins(const std::vector &pluginDataLi } bool PluginManagement::doRelocation(const std::vector &relocData, - std::vector &trampData, - const uint32_t trampolineID, + std::span trampData, std::map &usedRPls) { for (auto const &cur : relocData) { uint32_t functionAddress = 0; @@ -118,7 +115,7 @@ bool PluginManagement::doRelocation(const std::vector &relocData //DEBUG_FUNCTION_LINE("Found export for %s %s", rplName.c_str(), functionName.c_str()); } - if (!ElfUtils::elfLinkOne(cur.getType(), cur.getOffset(), cur.getAddend(), reinterpret_cast(cur.getDestination()), functionAddress, trampData, RELOC_TYPE_IMPORT, trampolineID)) { + if (!ElfUtils::elfLinkOne(cur.getType(), cur.getOffset(), cur.getAddend(), reinterpret_cast(cur.getDestination()), functionAddress, trampData, RELOC_TYPE_IMPORT)) { DEBUG_FUNCTION_LINE_ERR("elfLinkOne failed"); return false; } @@ -140,13 +137,8 @@ bool PluginManagement::doRelocation(const std::vector &relocData } bool PluginManagement::doRelocations(const std::vector &plugins, - std::vector &trampData, std::map &usedRPls) { - for (auto &cur : trampData) { - if (cur.status == RELOC_TRAMP_IMPORT_DONE) { - cur.status = RELOC_TRAMP_FREE; - } - } + OSDynLoadAllocFn prevDynLoadAlloc = nullptr; OSDynLoadFreeFn prevDynLoadFree = nullptr; @@ -158,10 +150,16 @@ bool PluginManagement::doRelocations(const std::vector &plugins if (!pluginContainer.isLinkedAndLoaded()) { continue; } + const auto &trampData = pluginContainer.getPluginLinkInformation().getTrampData(); + for (auto &cur : trampData) { + if (cur.status == RELOC_TRAMP_IMPORT_DONE) { + cur.status = RELOC_TRAMP_FREE; + } + } + DEBUG_FUNCTION_LINE_VERBOSE("Doing relocations for plugin: %s", pluginContainer.getMetaInformation().getName().c_str()); if (!PluginManagement::doRelocation(pluginContainer.getPluginLinkInformation().getRelocationDataList(), trampData, - pluginContainer.getPluginLinkInformation().getTrampolineId(), usedRPls)) { return false; } diff --git a/source/PluginManagement.h b/source/PluginManagement.h index 2060897..0b19e44 100644 --- a/source/PluginManagement.h +++ b/source/PluginManagement.h @@ -6,6 +6,7 @@ #include #include +#include #include class RelocationData; @@ -15,18 +16,15 @@ class PluginContainer; class PluginManagement { public: static std::vector loadPlugins( - const std::vector &pluginDataList, - std::vector &trampolineData); + const std::vector &pluginDataList); static void callInitHooks(const std::vector &plugins, const std::function &pred); static bool doRelocations(const std::vector &plugins, - std::vector &trampData, std::map &usedRPls); static bool doRelocation(const std::vector &relocData, - std::vector &trampData, - uint32_t trampolineID, + std::span trampData, std::map &usedRPls); static bool DoFunctionPatches(std::vector &plugins); diff --git a/source/globals.cpp b/source/globals.cpp index d602a96..7ab020d 100644 --- a/source/globals.cpp +++ b/source/globals.cpp @@ -10,12 +10,10 @@ #include "plugin/RelocationData.h" #include "plugin/SectionInfo.h" - StoredBuffer gStoredTVBuffer = {}; StoredBuffer gStoredDRCBuffer = {}; std::vector gLoadedPlugins; -std::vector gTrampData; std::set, PluginDataSharedPtrComparator> gLoadedData; std::vector gLoadOnNextLaunch; diff --git a/source/globals.h b/source/globals.h index 19e36b1..64575cb 100644 --- a/source/globals.h +++ b/source/globals.h @@ -24,8 +24,6 @@ class PluginLoadWrapper; extern StoredBuffer gStoredTVBuffer; extern StoredBuffer gStoredDRCBuffer; -#define TRAMP_DATA_SIZE 1024 -extern std::vector gTrampData; extern std::vector gLoadedPlugins; extern std::set, PluginDataSharedPtrComparator> gLoadedData; diff --git a/source/main.cpp b/source/main.cpp index f82fd76..75eff9c 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -180,13 +180,6 @@ WUMS_APPLICATION_STARTS() { std::lock_guard lock(gLoadedDataMutex); - if (gTrampData.empty()) { - gTrampData = std::vector(TRAMP_DATA_SIZE); - for (auto &cur : gTrampData) { - cur.status = RELOC_TRAMP_FREE; - } - } - std::vector newLoadedPlugins; if (gLoadedPlugins.empty()) { @@ -197,7 +190,7 @@ WUMS_APPLICATION_STARTS() { WUPSBackendSettings::LoadSettings(); auto &inactiveList = WUPSBackendSettings::GetInactivePluginFilenames(); const auto pluginData = PluginDataFactory::loadDir(pluginPath, inactiveList); - newLoadedPlugins = PluginManagement::loadPlugins(pluginData, gTrampData); + newLoadedPlugins = PluginManagement::loadPlugins(pluginData); } if (!gLoadOnNextLaunch.empty()) { @@ -230,7 +223,7 @@ WUMS_APPLICATION_STARTS() { CleanupPlugins(std::move(pluginsToDeinit)); DEBUG_FUNCTION_LINE("Load new plugins"); - newLoadedPlugins = PluginManagement::loadPlugins(toBeLoaded, gTrampData); + newLoadedPlugins = PluginManagement::loadPlugins(toBeLoaded); } DEBUG_FUNCTION_LINE("Clear plugin data lists."); @@ -245,7 +238,7 @@ WUMS_APPLICATION_STARTS() { // Move all new plugin containers into gLoadedPlugins append_move_all_values(gLoadedPlugins, newLoadedPlugins); - if (!PluginManagement::doRelocations(gLoadedPlugins, gTrampData, gUsedRPLs)) { + if (!PluginManagement::doRelocations(gLoadedPlugins, gUsedRPLs)) { DEBUG_FUNCTION_LINE_ERR("Relocations failed"); OSFatal("WiiUPluginLoaderBackend: Relocations failed.\n See crash logs for more information."); } @@ -305,18 +298,6 @@ void CleanupPlugins(std::vector &&pluginsToDeinit) { } plugin.DeinitButtonComboData(); } - - for (const auto &pluginContainer : pluginsToDeinit) { - for (auto &cur : gTrampData) { - if (!pluginContainer.isLinkedAndLoaded() || cur.id != pluginContainer.getPluginLinkInformation().getTrampolineId()) { - continue; - } - cur = {}; - } - } - DCFlushRange((void *) gTrampData.data(), gTrampData.size() * sizeof(relocation_trampoline_entry_t)); - ICInvalidateRange((void *) gTrampData.data(), gTrampData.size() * sizeof(relocation_trampoline_entry_t)); - OSMemoryBarrier(); } void CheckCleanupCallbackUsage(const std::vector &plugins) { auto *curThread = OSGetCurrentThread(); diff --git a/source/plugin/PluginLinkInformation.cpp b/source/plugin/PluginLinkInformation.cpp index 0ff18ba..244c9fa 100644 --- a/source/plugin/PluginLinkInformation.cpp +++ b/source/plugin/PluginLinkInformation.cpp @@ -4,31 +4,28 @@ #include "HookData.h" #include "RelocationData.h" #include "SectionInfo.h" +#include "utils/logger.h" PluginLinkInformation::PluginLinkInformation(PluginLinkInformation &&src) : mHookDataList(std::move(src.mHookDataList)), mFunctionDataList(std::move(src.mFunctionDataList)), mRelocationDataList(std::move(src.mRelocationDataList)), mSymbolDataList(std::move(src.mSymbolDataList)), mSectionInfoList(std::move(src.mSectionInfoList)), - mTrampolineId(src.mTrampolineId), - mAllocatedTextMemoryAddress(std::move(src.mAllocatedTextMemoryAddress)), + mAllocatedTextAndTrampMemoryAddress(std::move(src.mAllocatedTextAndTrampMemoryAddress)), mAllocatedDataMemoryAddress(std::move(src.mAllocatedDataMemoryAddress)) { - src.mTrampolineId = {}; } PluginLinkInformation &PluginLinkInformation::operator=(PluginLinkInformation &&src) noexcept { if (this != &src) { - this->mHookDataList = std::move(src.mHookDataList); - this->mFunctionDataList = std::move(src.mFunctionDataList); - this->mRelocationDataList = std::move(src.mRelocationDataList); - this->mSymbolDataList = std::move(src.mSymbolDataList); - this->mSectionInfoList = std::move(src.mSectionInfoList); - this->mTrampolineId = src.mTrampolineId; - this->mAllocatedTextMemoryAddress = std::move(src.mAllocatedTextMemoryAddress); - this->mAllocatedDataMemoryAddress = std::move(src.mAllocatedDataMemoryAddress); - src.mTrampolineId = {}; + this->mHookDataList = std::move(src.mHookDataList); + this->mFunctionDataList = std::move(src.mFunctionDataList); + this->mRelocationDataList = std::move(src.mRelocationDataList); + this->mSymbolDataList = std::move(src.mSymbolDataList); + this->mSectionInfoList = std::move(src.mSectionInfoList); + this->mAllocatedTextAndTrampMemoryAddress = std::move(src.mAllocatedTextAndTrampMemoryAddress); + this->mAllocatedDataMemoryAddress = std::move(src.mAllocatedDataMemoryAddress); } return *this; } @@ -80,15 +77,6 @@ std::optional PluginLinkInformation::getSectionInfo(const std::stri return std::nullopt; } - -void PluginLinkInformation::setTrampolineId(const uint8_t trampolineId) { - this->mTrampolineId = trampolineId; -} - -uint8_t PluginLinkInformation::getTrampolineId() const { - return mTrampolineId; -} - const FunctionSymbolData *PluginLinkInformation::getNearestFunctionSymbolData(uint32_t address) const { const FunctionSymbolData *result = nullptr; @@ -109,12 +97,12 @@ const FunctionSymbolData *PluginLinkInformation::getNearestFunctionSymbolData(ui return result; } -const HeapMemoryFixedSize &PluginLinkInformation::getTextMemory() const { - return mAllocatedTextMemoryAddress; +HeapMemoryFixedSizePool::MemorySegmentInfo PluginLinkInformation::getTextMemory() const { + return mAllocatedTextAndTrampMemoryAddress[0]; // 0 is .text data } -const HeapMemoryFixedSize &PluginLinkInformation::getDataMemory() const { - return mAllocatedDataMemoryAddress; +HeapMemoryFixedSizePool::MemorySegmentInfo PluginLinkInformation::getDataMemory() const { + return mAllocatedDataMemoryAddress[0]; // 0 is .data data } PluginLinkInformation PluginLinkInformation::CreateStub() { @@ -122,5 +110,13 @@ PluginLinkInformation PluginLinkInformation::CreateStub() { } bool PluginLinkInformation::hasValidData() const { - return mAllocatedDataMemoryAddress.size() > 0 && mAllocatedTextMemoryAddress.size() > 0; + return mAllocatedDataMemoryAddress && mAllocatedTextAndTrampMemoryAddress && mAllocatedTextAndTrampMemoryAddress.numberOfSegments() == 2; +} +std::span PluginLinkInformation::getTrampData() const { + if (mAllocatedTextAndTrampMemoryAddress && mAllocatedTextAndTrampMemoryAddress.numberOfSegments() < 2) { + DEBUG_FUNCTION_LINE_ERR("Failed to return trampoline data. Memory is either not valid or has not enough segments"); + return {}; + } + const auto &entry = mAllocatedTextAndTrampMemoryAddress[1]; // 1 is tramp data + return std::span(static_cast(entry.data()), entry.size() / sizeof(relocation_trampoline_entry_t)); } diff --git a/source/plugin/PluginLinkInformation.h b/source/plugin/PluginLinkInformation.h index 0d948c3..451163c 100644 --- a/source/plugin/PluginLinkInformation.h +++ b/source/plugin/PluginLinkInformation.h @@ -20,12 +20,14 @@ #include "FunctionSymbolData.h" #include "utils/HeapMemoryFixedSize.h" +#include #include #include #include #include +#include -class HeapMemoryFixedSize; +class HeapMemoryFixedSizePool; class SectionInfo; class RelocationData; class FunctionData; @@ -60,16 +62,18 @@ public: [[nodiscard]] std::optional getSectionInfo(const std::string §ionName) const; - [[nodiscard]] uint8_t getTrampolineId() const; - [[nodiscard]] const FunctionSymbolData *getNearestFunctionSymbolData(uint32_t address) const; - [[nodiscard]] const HeapMemoryFixedSize &getTextMemory() const; + [[nodiscard]] HeapMemoryFixedSizePool::MemorySegmentInfo getTextMemory() const; - [[nodiscard]] const HeapMemoryFixedSize &getDataMemory() const; + [[nodiscard]] HeapMemoryFixedSizePool::MemorySegmentInfo getDataMemory() const; [[nodiscard]] bool hasValidData() const; + [[nodiscard]] int numberOfSegments() const; + + [[nodiscard]] std::span getTrampData() const; + private: PluginLinkInformation() = default; @@ -83,18 +87,14 @@ private: void addSectionInfo(const SectionInfo §ionInfo); - void setTrampolineId(uint8_t trampolineId); - std::vector mHookDataList; std::vector mFunctionDataList; std::vector mRelocationDataList; std::set mSymbolDataList; std::map mSectionInfoList; - uint8_t mTrampolineId = 0; - - HeapMemoryFixedSize mAllocatedTextMemoryAddress; - HeapMemoryFixedSize mAllocatedDataMemoryAddress; + HeapMemoryFixedSizePool mAllocatedTextAndTrampMemoryAddress; + HeapMemoryFixedSizePool mAllocatedDataMemoryAddress; friend class PluginLinkInformationFactory; }; diff --git a/source/plugin/PluginLinkInformationFactory.cpp b/source/plugin/PluginLinkInformationFactory.cpp index f4ebc5e..8245c48 100644 --- a/source/plugin/PluginLinkInformationFactory.cpp +++ b/source/plugin/PluginLinkInformationFactory.cpp @@ -35,8 +35,70 @@ using namespace ELFIO; +namespace { + bool predictRequiredTrampolineCount(const elfio &reader, uint32_t &outTrampCount) { + Elf_Word symbol = 0; + Elf64_Addr offset; + Elf_Word type; + Elf_Sxword addend; + std::string sym_name; + Elf64_Addr sym_value; + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half sym_section_index; + unsigned char other; + + for (const auto &parentSec : reader.sections) { + if ((parentSec->get_type() == SHT_PROGBITS || parentSec->get_type() == SHT_NOBITS) && (parentSec->get_flags() & SHF_ALLOC)) { + for (const auto &psec : reader.sections) { + if (psec->get_info() == parentSec->get_info()) { + const relocation_section_accessor rel(reader, psec.get()); + for (uint32_t j = 0; j < static_cast(rel.get_entries_num()); ++j) { + if (!rel.get_entry(j, offset, symbol, type, addend)) { + DEBUG_FUNCTION_LINE_ERR("Failed to get relocation"); + return false; + } + const symbol_section_accessor symbols(reader, reader.sections[static_cast(psec->get_link())]); + + if (!symbols.get_symbol(symbol, sym_name, sym_value, size, + bind, symbolType, sym_section_index, other)) { + DEBUG_FUNCTION_LINE_ERR("Failed to get symbol"); + return false; + } + + if (sym_section_index == SHN_ABS) { + // + } else if (sym_section_index > SHN_LORESERVE) { + DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index); + return false; + } + if (type == R_PPC_REL24) { + const auto target = static_cast(offset); + const auto value = static_cast(sym_value + addend); + + const auto newDistance = value - target; + // The tramps are placed right after the .text section. We can cover 0x1FFFFFC + constexpr auto maxJumpDistance = 0x1FFFFFC; + // Subtract 0x10000 because it could be at the end of our tramp section. + constexpr auto maxUsedJumpDistance = maxJumpDistance - 0x10000; + if (newDistance > maxUsedJumpDistance || newDistance < -maxUsedJumpDistance) { + outTrampCount++; + } + } + } + return true; + } + } + } + } + + return false; + } +} // namespace + std::optional -PluginLinkInformationFactory::load(const PluginData &pluginData, std::vector &trampolineData, uint8_t trampolineId) { +PluginLinkInformationFactory::load(const PluginData &pluginData) { auto buffer = pluginData.getBuffer(); if (buffer.empty()) { DEBUG_FUNCTION_LINE_ERR("Buffer was empty"); @@ -85,20 +147,41 @@ PluginLinkInformationFactory::load(const PluginData &pluginData, std::vector(tramp_data.data()), expectedTramps); + + // For .data create a separate memory pool with just one try. + HeapMemoryFixedSizePool dataHeapPool({data_size}); + if (!dataHeapPool) { DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size); return std::nullopt; } + const auto &data_data = dataHeapPool[0]; - for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + for (const auto &psec : reader.sections) { if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") { continue; } @@ -165,12 +248,13 @@ PluginLinkInformationFactory::load(const PluginData &pluginData, std::vectorget_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { + if (psec && (psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { DEBUG_FUNCTION_LINE_VERBOSE("Linking (%d)... %s at %08X", i, psec->get_name().c_str(), destinations[psec->get_index()]); - if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data.data(), (uint32_t) data_data.data(), trampolineData, - trampolineId)) { + + if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data.data(), (uint32_t) data_data.data(), trampolineList)) { DEBUG_FUNCTION_LINE_ERR("linkSection failed"); return std::nullopt; } @@ -187,8 +271,6 @@ PluginLinkInformationFactory::load(const PluginData &pluginData, std::vectorgetSize() > 0) { size_t entries_count = secInfo->getSize() / sizeof(wups_loader_hook_t); @@ -225,11 +307,9 @@ PluginLinkInformationFactory::load(const PluginData &pluginData, std::vectorget_type()) { - symbol_section_accessor symbols(reader, sec); + symbol_section_accessor symbols(reader, sec.get()); auto sym_no = (uint32_t) symbols.get_symbols_num(); if (sym_no > 0) { for (Elf_Half j = 0; j < sym_no; ++j) { @@ -267,8 +347,8 @@ PluginLinkInformationFactory::load(const PluginData &pluginData, std::vectorget_type() == SHT_RELA || psec->get_type() == SHT_REL) { DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str()); - relocation_section_accessor rel(reader, psec); + relocation_section_accessor rel(reader, psec.get()); for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) { Elf_Word symbol = 0; Elf64_Addr offset; @@ -345,14 +424,11 @@ bool PluginLinkInformationFactory::addImportRelocationData(PluginLinkInformation } bool PluginLinkInformationFactory::linkSection(const elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, - std::vector &trampolineData, uint8_t trampolineId) { - uint32_t sec_num = reader.sections.size(); - - for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + std::span trampolineData) { + for (const auto &psec : reader.sections) { if (psec->get_info() == section_index) { DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str()); - relocation_section_accessor rel(reader, psec); + relocation_section_accessor rel(reader, psec.get()); for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) { Elf_Word symbol = 0; Elf64_Addr offset; @@ -415,11 +491,12 @@ bool PluginLinkInformationFactory::linkSection(const elfio &reader, uint32_t sec } // DEBUG_FUNCTION_LINE_VERBOSE("sym_value %08X adjusted_sym_value %08X offset %08X adjusted_offset %08X", (uint32_t) sym_value, adjusted_sym_value, (uint32_t) offset, adjusted_offset); - if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampolineData, RELOC_TYPE_FIXED, trampolineId)) { + if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampolineData, RELOC_TYPE_FIXED)) { DEBUG_FUNCTION_LINE_ERR("Link failed"); return false; } } + DEBUG_FUNCTION_LINE_VERBOSE("done"); return true; } diff --git a/source/plugin/PluginLinkInformationFactory.h b/source/plugin/PluginLinkInformationFactory.h index 7f9cbe3..f271d50 100644 --- a/source/plugin/PluginLinkInformationFactory.h +++ b/source/plugin/PluginLinkInformationFactory.h @@ -30,12 +30,12 @@ class PluginLinkInformation; class PluginLinkInformationFactory { public: static std::optional - load(const PluginData &pluginData, std::vector &trampolineData, uint8_t trampolineId); + load(const PluginData &pluginData); private: static bool linkSection(const ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, - std::vector &trampolineData, uint8_t trampolineId); + std::span trampolineData); static bool addImportRelocationData(PluginLinkInformation &pluginInfo, const ELFIO::elfio &reader, std::span destinations); diff --git a/source/utils/ElfUtils.cpp b/source/utils/ElfUtils.cpp index de50b62..afea52e 100644 --- a/source/utils/ElfUtils.cpp +++ b/source/utils/ElfUtils.cpp @@ -1,14 +1,16 @@ -#include -#include -#include -#include - #include "ElfUtils.h" #include "utils/logger.h" +#include + +#include + +#include +#include + // 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, - std::vector &trampolineData, RelocationType reloc_type, uint8_t trampolineId) { + std::span trampolineData, RelocationType reloc_type) { if (type == R_PPC_NONE) { return true; } @@ -85,11 +87,10 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des relocation_trampoline_entry_t *freeSlot = nullptr; for (auto &cur : trampolineData) { // 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. + // Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the plugin is unloaded. if (cur.status == RELOC_TRAMP_FREE) { freeSlot = &cur; break; @@ -119,9 +120,6 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des freeSlot->trampoline[3] = 0x4E800420; // bctr ICInvalidateRange((unsigned char *) freeSlot->trampoline, sizeof(freeSlot->trampoline)); - freeSlot->id = trampolineId; - ICInvalidateRange((unsigned char *) &freeSlot->id, sizeof(freeSlot->id)); - if (reloc_type == RELOC_TYPE_FIXED) { freeSlot->status = RELOC_TRAMP_FIXED; } else { diff --git a/source/utils/ElfUtils.h b/source/utils/ElfUtils.h index 9f20286..a682107 100644 --- a/source/utils/ElfUtils.h +++ b/source/utils/ElfUtils.h @@ -2,6 +2,8 @@ #include +#include + #include #ifdef __cplusplus @@ -47,6 +49,6 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi class ElfUtils { public: - static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, std::vector &trampolineData, - RelocationType reloc_type, uint8_t trampolineId); + static bool elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, std::span trampolineData, + RelocationType reloc_type); }; diff --git a/source/utils/HeapMemoryFixedSize.cpp b/source/utils/HeapMemoryFixedSize.cpp index b730e11..ef900a4 100644 --- a/source/utils/HeapMemoryFixedSize.cpp +++ b/source/utils/HeapMemoryFixedSize.cpp @@ -1,33 +1,69 @@ #include "HeapMemoryFixedSize.h" +#include "logger.h" #include "utils.h" -HeapMemoryFixedSize::HeapMemoryFixedSize() = default; +HeapMemoryFixedSizePool::MemorySegmentInfo::MemorySegmentInfo(void *data, const size_t size) : mData(data), + mSize(size) {} -HeapMemoryFixedSize::HeapMemoryFixedSize(const std::size_t size) : mData(make_unique_nothrow(size)), mSize(mData ? size : 0) {} - -HeapMemoryFixedSize::HeapMemoryFixedSize(HeapMemoryFixedSize &&other) noexcept - : mData(std::move(other.mData)), mSize(other.mSize) { - other.mSize = 0; +void *HeapMemoryFixedSizePool::MemorySegmentInfo::data() const { + return mData; } -HeapMemoryFixedSize &HeapMemoryFixedSize::operator=(HeapMemoryFixedSize &&other) noexcept { +size_t HeapMemoryFixedSizePool::MemorySegmentInfo::size() const { + return mSize; +} + +HeapMemoryFixedSizePool::HeapMemoryFixedSizePool() = default; + +HeapMemoryFixedSizePool::HeapMemoryFixedSizePool(const std::initializer_list segmentSizes) : HeapMemoryFixedSizePool(std::span(segmentSizes.begin(), segmentSizes.size())) {} + +HeapMemoryFixedSizePool::HeapMemoryFixedSizePool(std::span segmentSizes) { + assert(!segmentSizes.empty()); + size_t totalSize = 0; + for (const auto size : segmentSizes) { + totalSize += size + 0x40; // add 0x40 bytes overhead for each entry to ensure padding to 0x40 + } + + mData = make_unique_nothrow(totalSize); + mTotalSize = (mData ? totalSize : 0); + if (mData) { + auto address = reinterpret_cast(mData.get()); + for (const auto size : segmentSizes) { + address = ROUNDUP(address, 0x40); + assert(address >= reinterpret_cast(mData.get()) && address < reinterpret_cast(mData.get()) + totalSize); + mSegmentInfos.emplace_back(reinterpret_cast(address), size); + address += size; + } + } +} + +HeapMemoryFixedSizePool::HeapMemoryFixedSizePool(HeapMemoryFixedSizePool &&other) noexcept + : mData(std::move(other.mData)), mTotalSize(other.mTotalSize), mSegmentInfos(std::move(other.mSegmentInfos)) { + other.mTotalSize = 0; +} + +HeapMemoryFixedSizePool &HeapMemoryFixedSizePool::operator=(HeapMemoryFixedSizePool &&other) noexcept { if (this != &other) { - mData = std::move(other.mData); - mSize = other.mSize; - other.mSize = 0; + mData = std::move(other.mData); + mTotalSize = other.mTotalSize; + mSegmentInfos = std::move(other.mSegmentInfos); + other.mTotalSize = 0; } return *this; } -HeapMemoryFixedSize::operator bool() const { - return mData != nullptr; +uint32_t HeapMemoryFixedSizePool::numberOfSegments() const { + return mSegmentInfos.size(); } -[[nodiscard]] const void *HeapMemoryFixedSize::data() const { - return mData.get(); +HeapMemoryFixedSizePool::operator bool() const { + return mData != nullptr && mTotalSize > 0; } -[[nodiscard]] std::size_t HeapMemoryFixedSize::size() const { - return mSize; +HeapMemoryFixedSizePool::MemorySegmentInfo HeapMemoryFixedSizePool::operator[](const int idx) const { + if (idx < 0 || idx >= static_cast(mSegmentInfos.size())) { + DEBUG_FUNCTION_LINE_ERR("Out of bounce access (tried to access index %d; size is", idx, mSegmentInfos.size()); + } + return mSegmentInfos[idx]; } \ No newline at end of file diff --git a/source/utils/HeapMemoryFixedSize.h b/source/utils/HeapMemoryFixedSize.h index 715fca8..b576624 100644 --- a/source/utils/HeapMemoryFixedSize.h +++ b/source/utils/HeapMemoryFixedSize.h @@ -1,30 +1,45 @@ #pragma once #include +#include +#include #include -class HeapMemoryFixedSize { +class HeapMemoryFixedSizePool { public: - HeapMemoryFixedSize(); + class MemorySegmentInfo { + public: + MemorySegmentInfo(void *data, size_t size); - explicit HeapMemoryFixedSize(std::size_t size); + [[nodiscard]] void *data() const; + [[nodiscard]] size_t size() const; + + private: + void *mData; + size_t mSize; + }; + HeapMemoryFixedSizePool(); + + HeapMemoryFixedSizePool(std::initializer_list segmentSizes); + HeapMemoryFixedSizePool(std::span segmentSizes); // Delete the copy constructor and copy assignment operator - HeapMemoryFixedSize(const HeapMemoryFixedSize &) = delete; - HeapMemoryFixedSize &operator=(const HeapMemoryFixedSize &) = delete; + HeapMemoryFixedSizePool(const HeapMemoryFixedSizePool &) = delete; + HeapMemoryFixedSizePool &operator=(const HeapMemoryFixedSizePool &) = delete; - HeapMemoryFixedSize(HeapMemoryFixedSize &&other) noexcept; + HeapMemoryFixedSizePool(HeapMemoryFixedSizePool &&other) noexcept; - HeapMemoryFixedSize &operator=(HeapMemoryFixedSize &&other) noexcept; + HeapMemoryFixedSizePool &operator=(HeapMemoryFixedSizePool &&other) noexcept; + + [[nodiscard]] uint32_t numberOfSegments() const; explicit operator bool() const; - [[nodiscard]] const void *data() const; - - [[nodiscard]] std::size_t size() const; + MemorySegmentInfo operator[](int idx) const; private: std::unique_ptr mData{}; - std::size_t mSize{}; -}; \ No newline at end of file + std::size_t mTotalSize{}; + std::vector mSegmentInfos; +};