mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2025-02-02 05:52:36 +01:00
Remove the global trampoline table and add a small trampoline table next to each .text section instead
This commit is contained in:
parent
389b9fc9f1
commit
d2015ec59d
@ -24,10 +24,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
static uint32_t sTrampolineID = 0;
|
||||
|
||||
std::vector<PluginContainer>
|
||||
PluginManagement::loadPlugins(const std::vector<PluginLoadWrapper> &pluginDataList, std::vector<relocation_trampoline_entry_t> &trampolineData) {
|
||||
PluginManagement::loadPlugins(const std::vector<PluginLoadWrapper> &pluginDataList) {
|
||||
std::vector<PluginContainer> plugins;
|
||||
|
||||
for (const auto &pluginDataWrapper : pluginDataList) {
|
||||
@ -37,7 +35,7 @@ PluginManagement::loadPlugins(const std::vector<PluginLoadWrapper> &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<PluginLoadWrapper> &pluginDataLi
|
||||
}
|
||||
|
||||
bool PluginManagement::doRelocation(const std::vector<RelocationData> &relocData,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
const uint32_t trampolineID,
|
||||
std::span<relocation_trampoline_entry_t> trampData,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls) {
|
||||
for (auto const &cur : relocData) {
|
||||
uint32_t functionAddress = 0;
|
||||
@ -118,7 +115,7 @@ bool PluginManagement::doRelocation(const std::vector<RelocationData> &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<uint32_t>(cur.getDestination()), functionAddress, trampData, RELOC_TYPE_IMPORT, trampolineID)) {
|
||||
if (!ElfUtils::elfLinkOne(cur.getType(), cur.getOffset(), cur.getAddend(), reinterpret_cast<uint32_t>(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<RelocationData> &relocData
|
||||
}
|
||||
|
||||
bool PluginManagement::doRelocations(const std::vector<PluginContainer> &plugins,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
std::map<std::string, OSDynLoad_Module> &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<PluginContainer> &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;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
class RelocationData;
|
||||
@ -15,18 +16,15 @@ class PluginContainer;
|
||||
class PluginManagement {
|
||||
public:
|
||||
static std::vector<PluginContainer> loadPlugins(
|
||||
const std::vector<PluginLoadWrapper> &pluginDataList,
|
||||
std::vector<relocation_trampoline_entry_t> &trampolineData);
|
||||
const std::vector<PluginLoadWrapper> &pluginDataList);
|
||||
|
||||
static void callInitHooks(const std::vector<PluginContainer> &plugins, const std::function<bool(const PluginContainer &)> &pred);
|
||||
|
||||
static bool doRelocations(const std::vector<PluginContainer> &plugins,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls);
|
||||
|
||||
static bool doRelocation(const std::vector<RelocationData> &relocData,
|
||||
std::vector<relocation_trampoline_entry_t> &trampData,
|
||||
uint32_t trampolineID,
|
||||
std::span<relocation_trampoline_entry_t> trampData,
|
||||
std::map<std::string, OSDynLoad_Module> &usedRPls);
|
||||
|
||||
static bool DoFunctionPatches(std::vector<PluginContainer> &plugins);
|
||||
|
@ -10,12 +10,10 @@
|
||||
#include "plugin/RelocationData.h"
|
||||
#include "plugin/SectionInfo.h"
|
||||
|
||||
|
||||
StoredBuffer gStoredTVBuffer = {};
|
||||
StoredBuffer gStoredDRCBuffer = {};
|
||||
|
||||
std::vector<PluginContainer> gLoadedPlugins;
|
||||
std::vector<relocation_trampoline_entry_t> gTrampData;
|
||||
|
||||
std::set<std::shared_ptr<PluginData>, PluginDataSharedPtrComparator> gLoadedData;
|
||||
std::vector<PluginLoadWrapper> gLoadOnNextLaunch;
|
||||
|
@ -24,8 +24,6 @@ class PluginLoadWrapper;
|
||||
extern StoredBuffer gStoredTVBuffer;
|
||||
extern StoredBuffer gStoredDRCBuffer;
|
||||
|
||||
#define TRAMP_DATA_SIZE 1024
|
||||
extern std::vector<relocation_trampoline_entry_t> gTrampData;
|
||||
extern std::vector<PluginContainer> gLoadedPlugins;
|
||||
|
||||
extern std::set<std::shared_ptr<PluginData>, PluginDataSharedPtrComparator> gLoadedData;
|
||||
|
@ -180,13 +180,6 @@ WUMS_APPLICATION_STARTS() {
|
||||
|
||||
std::lock_guard lock(gLoadedDataMutex);
|
||||
|
||||
if (gTrampData.empty()) {
|
||||
gTrampData = std::vector<relocation_trampoline_entry_t>(TRAMP_DATA_SIZE);
|
||||
for (auto &cur : gTrampData) {
|
||||
cur.status = RELOC_TRAMP_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PluginContainer> 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<PluginContainer> &&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<PluginContainer> &plugins) {
|
||||
auto *curThread = OSGetCurrentThread();
|
||||
|
@ -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<SectionInfo> 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<relocation_trampoline_entry_t> 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<relocation_trampoline_entry_t *>(entry.data()), entry.size() / sizeof(relocation_trampoline_entry_t));
|
||||
}
|
||||
|
@ -20,12 +20,14 @@
|
||||
#include "FunctionSymbolData.h"
|
||||
#include "utils/HeapMemoryFixedSize.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <wums/defines/relocation_defines.h>
|
||||
|
||||
class HeapMemoryFixedSize;
|
||||
class HeapMemoryFixedSizePool;
|
||||
class SectionInfo;
|
||||
class RelocationData;
|
||||
class FunctionData;
|
||||
@ -60,16 +62,18 @@ public:
|
||||
|
||||
[[nodiscard]] std::optional<SectionInfo> 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<relocation_trampoline_entry_t> getTrampData() const;
|
||||
|
||||
private:
|
||||
PluginLinkInformation() = default;
|
||||
|
||||
@ -83,18 +87,14 @@ private:
|
||||
|
||||
void addSectionInfo(const SectionInfo §ionInfo);
|
||||
|
||||
void setTrampolineId(uint8_t trampolineId);
|
||||
|
||||
std::vector<HookData> mHookDataList;
|
||||
std::vector<FunctionData> mFunctionDataList;
|
||||
std::vector<RelocationData> mRelocationDataList;
|
||||
std::set<FunctionSymbolData, FunctionSymbolDataComparator> mSymbolDataList;
|
||||
std::map<std::string, SectionInfo> mSectionInfoList;
|
||||
|
||||
uint8_t mTrampolineId = 0;
|
||||
|
||||
HeapMemoryFixedSize mAllocatedTextMemoryAddress;
|
||||
HeapMemoryFixedSize mAllocatedDataMemoryAddress;
|
||||
HeapMemoryFixedSizePool mAllocatedTextAndTrampMemoryAddress;
|
||||
HeapMemoryFixedSizePool mAllocatedDataMemoryAddress;
|
||||
|
||||
friend class PluginLinkInformationFactory;
|
||||
};
|
||||
|
@ -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<uint32_t>(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<Elf_Half>(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<int32_t>(offset);
|
||||
const auto value = static_cast<int32_t>(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<PluginLinkInformation>
|
||||
PluginLinkInformationFactory::load(const PluginData &pluginData, std::vector<relocation_trampoline_entry_t> &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<rel
|
||||
}
|
||||
}
|
||||
|
||||
HeapMemoryFixedSize text_data(text_size);
|
||||
if (!text_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
||||
return std::nullopt;
|
||||
uint32_t expectedTramps = 0;
|
||||
if (!predictRequiredTrampolineCount(reader, expectedTramps)) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to predict required trampoline count");
|
||||
}
|
||||
|
||||
HeapMemoryFixedSize data_data(data_size);
|
||||
if (!data_data) {
|
||||
// Add 20 tramp slots by default to any plugin to be safe.
|
||||
// This alone should already be more than enough from my current observations
|
||||
expectedTramps += 20;
|
||||
|
||||
size_t trampDataSize = (expectedTramps) * sizeof(relocation_trampoline_entry_t);
|
||||
|
||||
// We have to have the .text section and trampolines as close as possible in memory
|
||||
// Lets create a shared memory pool for both of them
|
||||
HeapMemoryFixedSizePool textAndTrampDataPool({text_size, trampDataSize});
|
||||
if (!textAndTrampDataPool) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes) and tramp data", text_size, trampDataSize);
|
||||
return std::nullopt;
|
||||
}
|
||||
// Segment 0 is the .text data
|
||||
const auto &text_data = textAndTrampDataPool[0];
|
||||
// Segment 1 the tramp data
|
||||
const auto &tramp_data = textAndTrampDataPool[1];
|
||||
memset(tramp_data.data(), 0, trampDataSize);
|
||||
|
||||
std::span trampolineList(static_cast<relocation_trampoline_entry_t *>(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::vector<rel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
if ((psec->get_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::vector<rel
|
||||
DCFlushRange((void *) data_data.data(), data_data.size());
|
||||
ICInvalidateRange((void *) data_data.data(), data_data.size());
|
||||
|
||||
pluginInfo.setTrampolineId(trampolineId);
|
||||
|
||||
auto secInfo = pluginInfo.getSectionInfo(".wups.hooks");
|
||||
if (secInfo && secInfo->getSize() > 0) {
|
||||
size_t entries_count = secInfo->getSize() / sizeof(wups_loader_hook_t);
|
||||
@ -225,11 +307,9 @@ PluginLinkInformationFactory::load(const PluginData &pluginData, std::vector<rel
|
||||
}
|
||||
|
||||
// Get the symbol for functions.
|
||||
Elf_Half n = reader.sections.size();
|
||||
for (Elf_Half i = 0; i < n; ++i) {
|
||||
section *sec = reader.sections[i];
|
||||
for (const auto &sec : reader.sections) {
|
||||
if (SHT_SYMTAB == sec->get_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::vector<rel
|
||||
|
||||
|
||||
// Save the addresses for the allocated memory. This way we can free it again :)
|
||||
pluginInfo.mAllocatedDataMemoryAddress = std::move(data_data);
|
||||
pluginInfo.mAllocatedTextMemoryAddress = std::move(text_data);
|
||||
pluginInfo.mAllocatedDataMemoryAddress = std::move(dataHeapPool);
|
||||
pluginInfo.mAllocatedTextAndTrampMemoryAddress = std::move(textAndTrampDataPool);
|
||||
|
||||
return pluginInfo;
|
||||
}
|
||||
@ -289,11 +369,10 @@ bool PluginLinkInformationFactory::addImportRelocationData(PluginLinkInformation
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
for (const auto &psec : reader.sections) {
|
||||
if (psec->get_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<relocation_trampoline_entry_t> &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<relocation_trampoline_entry_t> 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;
|
||||
}
|
||||
|
@ -30,12 +30,12 @@ class PluginLinkInformation;
|
||||
class PluginLinkInformationFactory {
|
||||
public:
|
||||
static std::optional<PluginLinkInformation>
|
||||
load(const PluginData &pluginData, std::vector<relocation_trampoline_entry_t> &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<relocation_trampoline_entry_t> &trampolineData, uint8_t trampolineId);
|
||||
std::span<relocation_trampoline_entry_t> trampolineData);
|
||||
|
||||
static bool
|
||||
addImportRelocationData(PluginLinkInformation &pluginInfo, const ELFIO::elfio &reader, std::span<uint8_t *> destinations);
|
||||
|
@ -1,14 +1,16 @@
|
||||
#include <coreinit/cache.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "ElfUtils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <coreinit/cache.h>
|
||||
|
||||
#include <span>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
// 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<relocation_trampoline_entry_t> &trampolineData, RelocationType reloc_type, uint8_t trampolineId) {
|
||||
std::span<relocation_trampoline_entry_t> 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 {
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <wums/defines/relocation_defines.h>
|
||||
|
||||
#include <span>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#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<relocation_trampoline_entry_t> &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<relocation_trampoline_entry_t> trampolineData,
|
||||
RelocationType reloc_type);
|
||||
};
|
||||
|
@ -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<uint8_t[]>(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<size_t> segmentSizes) : HeapMemoryFixedSizePool(std::span(segmentSizes.begin(), segmentSizes.size())) {}
|
||||
|
||||
HeapMemoryFixedSizePool::HeapMemoryFixedSizePool(std::span<const std::size_t> 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<uint8_t[]>(totalSize);
|
||||
mTotalSize = (mData ? totalSize : 0);
|
||||
if (mData) {
|
||||
auto address = reinterpret_cast<uint32_t>(mData.get());
|
||||
for (const auto size : segmentSizes) {
|
||||
address = ROUNDUP(address, 0x40);
|
||||
assert(address >= reinterpret_cast<uint32_t>(mData.get()) && address < reinterpret_cast<uint32_t>(mData.get()) + totalSize);
|
||||
mSegmentInfos.emplace_back(reinterpret_cast<void *>(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<int>(mSegmentInfos.size())) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Out of bounce access (tried to access index %d; size is", idx, mSegmentInfos.size());
|
||||
}
|
||||
return mSegmentInfos[idx];
|
||||
}
|
@ -1,30 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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<size_t> segmentSizes);
|
||||
HeapMemoryFixedSizePool(std::span<const std::size_t> 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<uint8_t[]> mData{};
|
||||
std::size_t mSize{};
|
||||
};
|
||||
std::size_t mTotalSize{};
|
||||
std::vector<MemorySegmentInfo> mSegmentInfos;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user