mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2026-08-28 05:45:30 -05:00
Remove the global trampoline table and add a small trampoline table next to each .text section instead
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user