mirror of
https://github.com/wiiu-env/EnvironmentLoader.git
synced 2024-11-27 08:14:14 +01:00
Fix and improve module loading
This commit is contained in:
parent
790394a72d
commit
fe17abe0c9
@ -8,16 +8,16 @@
|
|||||||
#include "ElfUtils.h"
|
#include "ElfUtils.h"
|
||||||
#include "elfio/elfio.hpp"
|
#include "elfio/elfio.hpp"
|
||||||
|
|
||||||
bool ElfUtils::doRelocation(std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length) {
|
bool ElfUtils::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length) {
|
||||||
for (auto const &curReloc : relocData) {
|
for (auto const &curReloc : relocData) {
|
||||||
std::string functionName = curReloc->getName();
|
std::string functionName = curReloc->getName();
|
||||||
std::string rplName = curReloc->getImportRPLInformation()->getName();
|
std::string rplName = curReloc->getImportRPLInformation()->getRPLName();
|
||||||
int32_t isData = curReloc->getImportRPLInformation()->isData();
|
int32_t isData = curReloc->getImportRPLInformation()->isData();
|
||||||
OSDynLoad_Module rplHandle = nullptr;
|
OSDynLoad_Module rplHandle = nullptr;
|
||||||
|
|
||||||
|
|
||||||
auto err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
|
auto err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
|
||||||
if (err != OS_DYNLOAD_OK || rplHandle == 0) {
|
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
|
||||||
// only acquire if not already loaded.
|
// only acquire if not already loaded.
|
||||||
OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
|
OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
|
||||||
}
|
}
|
||||||
@ -41,15 +41,15 @@ bool ElfUtils::doRelocation(std::vector<std::shared_ptr<RelocationData>> &relocD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144
|
// 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, relocation_trampoline_entry_t *trampolin_data, uint32_t trampolin_data_length,
|
bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length,
|
||||||
RelocationType reloc_type) {
|
RelocationType reloc_type) {
|
||||||
if (type == R_PPC_NONE) {
|
if (type == R_PPC_NONE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto target = destination + offset;
|
auto target = destination + offset;
|
||||||
auto value = symbol_addr + addend;
|
auto value = symbol_addr + addend;
|
||||||
|
|
||||||
|
|
||||||
auto relValue = value - static_cast<uint32_t>(target);
|
auto relValue = value - static_cast<uint32_t>(target);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -68,7 +68,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
|||||||
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
|
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
|
||||||
break;
|
break;
|
||||||
case R_PPC_DTPMOD32:
|
case R_PPC_DTPMOD32:
|
||||||
DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME\n");
|
DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME");
|
||||||
//*((int32_t *)(target)) = tlsModuleIndex;
|
//*((int32_t *)(target)) = tlsModuleIndex;
|
||||||
break;
|
break;
|
||||||
case R_PPC_DTPREL32:
|
case R_PPC_DTPREL32:
|
||||||
@ -111,33 +111,40 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
|||||||
// }
|
// }
|
||||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||||
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
||||||
if (trampolin_data == nullptr) {
|
if (trampoline_data == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided\n");
|
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided");
|
||||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
relocation_trampoline_entry_t *freeSlot = nullptr;
|
relocation_trampoline_entry_t *freeSlot = nullptr;
|
||||||
for (uint32_t i = 0; i < trampolin_data_length; i++) {
|
for (uint32_t i = 0; i < trampoline_data_length; i++) {
|
||||||
// We want to override "old" relocations of imports
|
// We want to override "old" relocations of imports
|
||||||
// Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS.
|
// 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
|
// 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.
|
// 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 module is unloaded.
|
||||||
if (trampolin_data[i].status == RELOC_TRAMP_FREE ||
|
if (trampoline_data[i].status == RELOC_TRAMP_FREE ||
|
||||||
trampolin_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
trampoline_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
||||||
freeSlot = &(trampolin_data[i]);
|
freeSlot = &(trampoline_data[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (freeSlot == nullptr) {
|
if (freeSlot == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full\n");
|
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full");
|
||||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) & (freeSlot->trampoline[0]));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) {
|
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
||||||
|
auto newValue = symbolValue + addend;
|
||||||
|
auto newDistance = static_cast<int32_t>(newValue) - static_cast<int32_t>(target);
|
||||||
|
if (newDistance > 0x1FFFFFC || newDistance < -0x1FFFFFC) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("**Cannot link 24-bit jump (too far to tramp buffer).");
|
DEBUG_FUNCTION_LINE_ERR("**Cannot link 24-bit jump (too far to tramp buffer).");
|
||||||
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
if (newDistance < 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance -%08X", newValue, target, abs(newDistance));
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", newValue, target, newDistance);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,9 +161,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
|||||||
// Relocations for the imports may be overridden
|
// Relocations for the imports may be overridden
|
||||||
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
||||||
}
|
}
|
||||||
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
distance = newDistance;
|
||||||
value = symbolValue + addend;
|
|
||||||
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,5 +187,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
|||||||
DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ICInvalidateRange(reinterpret_cast<void *>(target), 4);
|
||||||
|
DCFlushRange(reinterpret_cast<void *>(target), 4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -50,5 +50,5 @@ public:
|
|||||||
RelocationType reloc_type);
|
RelocationType reloc_type);
|
||||||
|
|
||||||
|
|
||||||
static bool doRelocation(std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length);
|
static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length);
|
||||||
};
|
};
|
||||||
|
@ -184,13 +184,13 @@ int main(int argc, char **argv) {
|
|||||||
DYN_LINK_TRAMPOLIN_LIST_LENGTH);
|
DYN_LINK_TRAMPOLIN_LIST_LENGTH);
|
||||||
if (!moduleData) {
|
if (!moduleData) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", setupModules.GetFilepath(i));
|
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", setupModules.GetFilepath(i));
|
||||||
|
OSFatal("EnvironmentLoader: Failed to load module");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE("Loaded module data");
|
DEBUG_FUNCTION_LINE("Loaded module data");
|
||||||
auto relocData = moduleData.value()->getRelocationDataList();
|
if (!ElfUtils::doRelocation(moduleData.value()->getRelocationDataList(), gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) {
|
||||||
if (!ElfUtils::doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Relocations failed");
|
DEBUG_FUNCTION_LINE_ERR("Relocations failed");
|
||||||
OSFatal("Relocations failed");
|
OSFatal("EnvironmentLoader: Relocations failed");
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Relocation done");
|
DEBUG_FUNCTION_LINE("Relocation done");
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Copyright (C) 2018 Maschell
|
* Copyright (C) 2018 Maschell
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include <coreinit/debug.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -26,44 +27,27 @@
|
|||||||
class ImportRPLInformation {
|
class ImportRPLInformation {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ImportRPLInformation(std::string name, bool isData = false) {
|
explicit ImportRPLInformation(std::string rawSectionName) {
|
||||||
this->name = std::move(name);
|
this->name = std::move(rawSectionName);
|
||||||
this->_isData = isData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ImportRPLInformation() = default;
|
~ImportRPLInformation() = default;
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<ImportRPLInformation>> createImportRPLInformation(std::string rawSectionName) {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
std::string fimport = ".fimport_";
|
|
||||||
std::string dimport = ".dimport_";
|
|
||||||
|
|
||||||
bool data = false;
|
|
||||||
|
|
||||||
std::string rplName;
|
|
||||||
|
|
||||||
if (rawSectionName.size() < fimport.size()) {
|
|
||||||
return std::nullopt;
|
|
||||||
} else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) {
|
|
||||||
rplName = rawSectionName.substr(fimport.size());
|
|
||||||
} else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) {
|
|
||||||
rplName = rawSectionName.substr(dimport.size());
|
|
||||||
data = true;
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE("invalid section name\n");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
return std::make_shared<ImportRPLInformation>(rplName, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string getName() const {
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const char *getRPLName() const {
|
||||||
|
if (name.max_size() < strlen("._import_") + 1) {
|
||||||
|
OSFatal("Invalid RPLName, is too short to be valid");
|
||||||
|
}
|
||||||
|
return name.c_str() + strlen("._import_");
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool isData() const {
|
[[nodiscard]] bool isData() const {
|
||||||
return _isData;
|
return name.starts_with(".dimport_");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool _isData = false;
|
|
||||||
};
|
};
|
||||||
|
@ -29,15 +29,15 @@ public:
|
|||||||
|
|
||||||
~ModuleData() = default;
|
~ModuleData() = default;
|
||||||
|
|
||||||
void setEntrypoint(uint32_t addr) {
|
void setEntrypoint(uint32_t address) {
|
||||||
this->entrypoint = addr;
|
this->entrypoint = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
|
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
|
||||||
relocation_data_list.push_back(relocation_data);
|
relocation_data_list.push_back(std::move(relocation_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::vector<std::shared_ptr<RelocationData>> &getRelocationDataList() const {
|
[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
|
||||||
return relocation_data_list;
|
return relocation_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,12 +45,12 @@ public:
|
|||||||
return entrypoint;
|
return entrypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStartAddress(uint32_t addr) {
|
void setStartAddress(uint32_t address) {
|
||||||
this->startAddress = addr;
|
this->startAddress = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setEndAddress(uint32_t _endAddress) {
|
void setEndAddress(uint32_t address) {
|
||||||
this->endAddress = _endAddress;
|
this->endAddress = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint32_t getStartAddress() const {
|
[[nodiscard]] uint32_t getStartAddress() const {
|
||||||
@ -62,7 +62,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
|
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
|
||||||
uint32_t entrypoint = 0;
|
uint32_t entrypoint = 0;
|
||||||
uint32_t startAddress = 0;
|
uint32_t startAddress = 0;
|
||||||
uint32_t endAddress = 0;
|
uint32_t endAddress = 0;
|
||||||
|
@ -18,17 +18,21 @@
|
|||||||
#include "ModuleDataFactory.h"
|
#include "ModuleDataFactory.h"
|
||||||
#include "../utils/FileUtils.h"
|
#include "../utils/FileUtils.h"
|
||||||
#include "ElfUtils.h"
|
#include "ElfUtils.h"
|
||||||
|
#include "utils/OnLeavingScope.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace ELFIO;
|
std::optional<std::unique_ptr<ModuleData>>
|
||||||
|
|
||||||
std::optional<std::shared_ptr<ModuleData>>
|
|
||||||
ModuleDataFactory::load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
|
ModuleDataFactory::load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
|
||||||
elfio reader;
|
ELFIO::elfio reader;
|
||||||
std::shared_ptr<ModuleData> moduleData = std::make_shared<ModuleData>();
|
auto moduleData = make_unique_nothrow<ModuleData>();
|
||||||
|
if (!moduleData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate ModuleData");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *buffer = nullptr;
|
uint8_t *buffer = nullptr;
|
||||||
uint32_t fsize = 0;
|
uint32_t fsize = 0;
|
||||||
@ -44,12 +48,19 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sec_num = reader.sections.size();
|
auto cleanupBuffer = onLeavingScope([buffer]() { free(buffer); });
|
||||||
auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num);
|
|
||||||
|
uint32_t sec_num = reader.sections.size();
|
||||||
|
|
||||||
|
auto destinations = make_unique_nothrow<uint8_t *[]>(sec_num);
|
||||||
|
if (!destinations) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t sizeOfModule = 0;
|
uint32_t sizeOfModule = 0;
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
ELFIO::section *psec = reader.sections[i];
|
||||||
if (psec->get_type() == 0x80000002) {
|
if (psec->get_type() == 0x80000002) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -61,8 +72,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
|
|
||||||
if (sizeOfModule > maximum_size) {
|
if (sizeOfModule > maximum_size) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Module is too big.");
|
DEBUG_FUNCTION_LINE_ERR("Module is too big.");
|
||||||
free(destinations);
|
|
||||||
free(buffer);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +87,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
uint32_t endAddress = 0;
|
uint32_t endAddress = 0;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
ELFIO::section *psec = reader.sections[i];
|
||||||
if (psec->get_type() == 0x80000002) {
|
if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,8 +98,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
totalSize += sectionSize;
|
totalSize += sectionSize;
|
||||||
if (totalSize > maximum_size) {
|
if (totalSize > maximum_size) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Couldn't load setup module because it's too big.");
|
DEBUG_FUNCTION_LINE_ERR("Couldn't load setup module because it's too big.");
|
||||||
free(destinations);
|
|
||||||
free(buffer);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,17 +115,20 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
destination -= 0x10000000;
|
destination -= 0x10000000;
|
||||||
destinations[psec->get_index()] -= 0x10000000;
|
destinations[psec->get_index()] -= 0x10000000;
|
||||||
} else if (address >= 0xC0000000) {
|
} else if (address >= 0xC0000000) {
|
||||||
destination -= 0xC0000000;
|
DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported");
|
||||||
destinations[psec->get_index()] -= 0xC0000000;
|
return std::nullopt;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||||
free(destinations);
|
|
||||||
free(buffer);
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *p = reader.sections[i]->get_data();
|
const char *p = reader.sections[i]->get_data();
|
||||||
|
|
||||||
|
if (destination + sectionSize > (uint32_t) destination_address_end) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Tried to overflow buffer. %08X > %08X", destination + sectionSize, destination_address_end);
|
||||||
|
OSFatal("EnvironmentLoader: Tried to overflow buffer");
|
||||||
|
}
|
||||||
|
|
||||||
if (psec->get_type() == SHT_NOBITS) {
|
if (psec->get_type() == SHT_NOBITS) {
|
||||||
DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
|
DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
|
||||||
memset((void *) destination, 0, sectionSize);
|
memset((void *) destination, 0, sectionSize);
|
||||||
@ -143,29 +153,20 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
ELFIO::section *psec = reader.sections[i];
|
||||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||||
DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str());
|
DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str());
|
||||||
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) {
|
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
|
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
|
||||||
free(destinations);
|
|
||||||
free(buffer);
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto relocationData = getImportRelocationData(reader, destinations);
|
getImportRelocationData(moduleData, reader, destinations.get());
|
||||||
|
|
||||||
for (auto const &reloc : relocationData) {
|
|
||||||
moduleData->addRelocationData(reloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCFlushRange((void *) baseOffset, totalSize);
|
DCFlushRange((void *) baseOffset, totalSize);
|
||||||
ICInvalidateRange((void *) baseOffset, totalSize);
|
ICInvalidateRange((void *) baseOffset, totalSize);
|
||||||
|
|
||||||
free(destinations);
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
moduleData->setStartAddress(startAddress);
|
moduleData->setStartAddress(startAddress);
|
||||||
moduleData->setEndAddress(endAddress);
|
moduleData->setEndAddress(endAddress);
|
||||||
moduleData->setEntrypoint(entrypoint);
|
moduleData->setEntrypoint(entrypoint);
|
||||||
@ -174,79 +175,91 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en
|
|||||||
return moduleData;
|
return moduleData;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) {
|
bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations) {
|
||||||
std::vector<std::shared_ptr<RelocationData>> result;
|
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
|
||||||
std::map<uint32_t, std::string> infoMap;
|
|
||||||
|
|
||||||
uint32_t sec_num = reader.sections.size();
|
uint32_t sec_num = reader.sections.size();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
auto *psec = reader.sections[i];
|
||||||
if (psec->get_type() == 0x80000002) {
|
if (psec->get_type() == 0x80000002) {
|
||||||
infoMap[i] = psec->get_name();
|
auto info = make_shared_nothrow<ImportRPLInformation>(psec->get_name());
|
||||||
|
if (!info) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed too allocate ImportRPLInformation");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
infoMap[i] = std::move(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
ELFIO::section *psec = reader.sections[i];
|
||||||
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
|
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
|
ELFIO::relocation_section_accessor rel(reader, psec);
|
||||||
relocation_section_accessor rel(reader, psec);
|
|
||||||
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
||||||
Elf64_Addr offset;
|
ELFIO::Elf64_Addr offset;
|
||||||
Elf_Word type;
|
ELFIO::Elf_Word type;
|
||||||
Elf_Sxword addend;
|
ELFIO::Elf_Sxword addend;
|
||||||
std::string sym_name;
|
std::string sym_name;
|
||||||
Elf64_Addr sym_value;
|
ELFIO::Elf64_Addr sym_value;
|
||||||
Elf_Half sym_section_index;
|
ELFIO::Elf_Half sym_section_index;
|
||||||
|
|
||||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||||
|
OSFatal("Failed to get relocation");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32_t adjusted_sym_value = (uint32_t) sym_value;
|
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||||
if (infoMap.count(sym_section_index) == 0) {
|
if (adjusted_sym_value < 0xC0000000) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]);
|
|
||||||
if (!rplInfo) {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to create import information");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t section_index = psec->get_info();
|
uint32_t section_index = psec->get_info();
|
||||||
|
if (!infoMap.contains(sym_section_index)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str());
|
||||||
|
OSFatal("Relocation is referencing a unknown section.");
|
||||||
|
}
|
||||||
|
|
||||||
// When these relocations are performed, we don't need the 0xC0000000 offset anymore.
|
auto relocationData = make_unique_nothrow<RelocationData>(type,
|
||||||
auto relocationData = std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value());
|
offset - 0x02000000,
|
||||||
//relocationData->printInformation();
|
addend,
|
||||||
result.push_back(relocationData);
|
(void *) (destinations[section_index] + 0x02000000),
|
||||||
|
sym_name,
|
||||||
|
infoMap[sym_section_index]);
|
||||||
|
|
||||||
|
if (!relocationData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to alloc relocation data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleData->addRelocationData(std::move(relocationData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
bool ModuleDataFactory::linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||||
uint32_t trampoline_data_length) {
|
uint32_t trampoline_data_length) {
|
||||||
uint32_t sec_num = reader.sections.size();
|
uint32_t sec_num = reader.sections.size();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
ELFIO::section *psec = reader.sections[i];
|
||||||
if (psec->get_info() == section_index) {
|
if (psec->get_info() == section_index) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
|
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
|
||||||
relocation_section_accessor rel(reader, psec);
|
ELFIO::relocation_section_accessor rel(reader, psec);
|
||||||
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
||||||
Elf64_Addr offset;
|
ELFIO::Elf64_Addr offset;
|
||||||
Elf_Word type;
|
ELFIO::Elf_Word type;
|
||||||
Elf_Sxword addend;
|
ELFIO::Elf_Sxword addend;
|
||||||
std::string sym_name;
|
std::string sym_name;
|
||||||
Elf64_Addr sym_value;
|
ELFIO::Elf64_Addr sym_value;
|
||||||
Elf_Half sym_section_index;
|
ELFIO::Elf_Half sym_section_index;
|
||||||
|
|
||||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto adjusted_sym_value = (uint32_t) sym_value;
|
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||||
@ -272,13 +285,11 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
|||||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index);
|
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
|
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Link failed");
|
DEBUG_FUNCTION_LINE_ERR("Link failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("done");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -26,11 +26,11 @@
|
|||||||
|
|
||||||
class ModuleDataFactory {
|
class ModuleDataFactory {
|
||||||
public:
|
public:
|
||||||
static std::optional<std::shared_ptr<ModuleData>>
|
static std::optional<std::unique_ptr<ModuleData>>
|
||||||
load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);
|
load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);
|
||||||
|
|
||||||
static bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
static bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
||||||
uint32_t trampoline_data_length);
|
uint32_t trampoline_data_length);
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations);
|
static bool getImportRelocationData(std::unique_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations);
|
||||||
};
|
};
|
||||||
|
113
source/utils/OnLeavingScope.h
Normal file
113
source/utils/OnLeavingScope.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are based on the article posted at the
|
||||||
|
* following location:
|
||||||
|
*
|
||||||
|
* http://crascit.com/2015/06/03/on-leaving-scope-part-2/
|
||||||
|
*
|
||||||
|
* The material in that article has some commonality with the code made
|
||||||
|
* available as part of Facebook's folly library at:
|
||||||
|
*
|
||||||
|
* https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h
|
||||||
|
*
|
||||||
|
* Furthermore, similar material is currently part of a draft proposal
|
||||||
|
* to the C++ standards committee, referencing the same work by Andrei
|
||||||
|
* Alexandresu that led to the folly implementation. The draft proposal
|
||||||
|
* can be found at:
|
||||||
|
*
|
||||||
|
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf
|
||||||
|
*
|
||||||
|
* With the above in mind, the content below is made available under
|
||||||
|
* the same license terms as folly to minimize any legal concerns.
|
||||||
|
* Should there be ambiguity over copyright ownership between Facebook
|
||||||
|
* and myself for any material included in this file, it should be
|
||||||
|
* interpreted that Facebook is the copyright owner for the ambiguous
|
||||||
|
* section of code concerned.
|
||||||
|
*
|
||||||
|
* Craig Scott
|
||||||
|
* 3rd June 2015
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Copyright 2015 Craig Scott
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRASCIT_ONLEAVINGSCOPE_H
|
||||||
|
#define CRASCIT_ONLEAVINGSCOPE_H
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is intended to be used only to create a local object on the
|
||||||
|
* stack. It accepts a function object in its constructor and will invoke
|
||||||
|
* that function object in its destructor. The class provides a move
|
||||||
|
* constructor so it can be used with the onLeavingScope factory function,
|
||||||
|
* but it cannot be copied.
|
||||||
|
*
|
||||||
|
* Do no use this function directly, use the onLeavingScope() factory
|
||||||
|
* function instead.
|
||||||
|
*/
|
||||||
|
template<typename Func>
|
||||||
|
class OnLeavingScope {
|
||||||
|
public:
|
||||||
|
// Prevent copying
|
||||||
|
OnLeavingScope(const OnLeavingScope &) = delete;
|
||||||
|
OnLeavingScope &operator=(const OnLeavingScope &) = delete;
|
||||||
|
|
||||||
|
// Allow moving
|
||||||
|
OnLeavingScope(OnLeavingScope &&other) : m_func(std::move(other.m_func)),
|
||||||
|
m_owner(other.m_owner) {
|
||||||
|
other.m_owner = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnLeavingScope(const Func &f) : m_func(f),
|
||||||
|
m_owner(true) {
|
||||||
|
}
|
||||||
|
OnLeavingScope(Func &&f) : m_func(std::move(f)),
|
||||||
|
m_owner(true) {
|
||||||
|
}
|
||||||
|
~OnLeavingScope() {
|
||||||
|
if (m_owner)
|
||||||
|
m_func();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Func m_func;
|
||||||
|
bool m_owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory function for creating an OnLeavingScope object. It is intended
|
||||||
|
* to be used like so:
|
||||||
|
*
|
||||||
|
* auto cleanup = onLeavingScope(...);
|
||||||
|
*
|
||||||
|
* where the ... could be a lambda function, function object or pointer to
|
||||||
|
* a free function to be invoked when the cleanup object goes out of scope.
|
||||||
|
* The function object must take no function arguments, but can return any
|
||||||
|
* type (the return value is ignored).
|
||||||
|
*
|
||||||
|
* The \a Func template parameter would rarely, if ever, be manually
|
||||||
|
* specified. Normally, it would be deduced automatically by the compiler
|
||||||
|
* from the object passed as the function argument.
|
||||||
|
*/
|
||||||
|
template<typename Func>
|
||||||
|
OnLeavingScope<typename std::decay<Func>::type> onLeavingScope(Func &&f) {
|
||||||
|
return OnLeavingScope<typename std::decay<Func>::type>(std::forward<Func>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CRASCIT_ONLEAVINGSCOPE_H
|
17
source/utils/utils.h
Normal file
17
source/utils/utils.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
template<class T, class... Args>
|
||||||
|
std::unique_ptr<T> make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||||
|
return std::unique_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline typename std::_MakeUniq<T>::__array make_unique_nothrow(size_t num) noexcept {
|
||||||
|
return std::unique_ptr<T>(new (std::nothrow) std::remove_extent_t<T>[num]());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class... Args>
|
||||||
|
std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
|
||||||
|
return std::shared_ptr<T>(new (std::nothrow) T(std::forward<Args>(args)...));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user