Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make rpx loading more robust and respect section alignment #34

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions source/ElfUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
#include "ElfUtils.h"
#include "elfio/elfio.hpp"

bool ElfUtils::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map<std::string, OSDynLoad_Module> &usedRPls) {
bool ElfUtils::doRelocation(const std::vector<RelocationData> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map<std::string, OSDynLoad_Module> &usedRPls) {
for (auto const &curReloc : relocData) {
std::string functionName = curReloc->getName();
std::string rplName = curReloc->getImportRPLInformation()->getRPLName();
int32_t isData = curReloc->getImportRPLInformation()->isData();
std::string functionName = curReloc.getName();
std::string rplName = curReloc.getImportRPLInformation()->getRPLName();
int32_t isData = curReloc.getImportRPLInformation()->isData();
OSDynLoad_Module rplHandle = nullptr;

if (!usedRPls.contains(rplName)) {
Expand All @@ -35,7 +35,7 @@ bool ElfUtils::doRelocation(const std::vector<std::unique_ptr<RelocationData>> &
DEBUG_FUNCTION_LINE_ERR("Failed to find export for %s %s %d", functionName.c_str(), rplName.c_str(), isData);
return false;
}
if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length,
if (!ElfUtils::elfLinkOne(curReloc.getType(), curReloc.getOffset(), curReloc.getAddend(), (uint32_t) curReloc.getDestination(), functionAddress, tramp_data, tramp_length,
RELOC_TYPE_IMPORT)) {
DEBUG_FUNCTION_LINE_ERR("Relocation failed\n");
return false;
Expand Down Expand Up @@ -159,7 +159,6 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
freeSlot->trampoline[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
freeSlot->trampoline[2] = 0x7D6903A6; // mtctr r11
freeSlot->trampoline[3] = 0x4E800420; // bctr
DCFlushRange((void *) freeSlot->trampoline, sizeof(freeSlot->trampoline));
ICInvalidateRange((unsigned char *) freeSlot->trampoline, sizeof(freeSlot->trampoline));

if (reloc_type == RELOC_TYPE_FIXED) {
Expand Down
3 changes: 1 addition & 2 deletions source/ElfUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,5 @@ class ElfUtils {
static bool 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,
RelocationType reloc_type);


static bool doRelocation(const std::vector<std::unique_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map<std::string, OSDynLoad_Module> &usedRPls);
static bool doRelocation(const std::vector<RelocationData> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, std::map<std::string, OSDynLoad_Module> &usedRPls);
};
5 changes: 1 addition & 4 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#include "utils/wiiu_zlib.hpp"
#include "version.h"

#define ENVIRONMENT_LOADER_VERSION "v0.3.0"
#define ENVIRONMENT_LOADER_VERSION "v0.3.1"

#define MEMORY_REGION_START 0x00800000
#define AUTOBOOT_CONFIG_PATH "fs:/vol/external01/wiiu/environments/default.cfg"
Expand Down Expand Up @@ -385,9 +385,6 @@ void LoadAndRunModule(std::string_view filepath, std::string_view environment_pa
DEBUG_FUNCTION_LINE("Relocation done");
}

DCFlushRange((void *) moduleData.value()->getStartAddress(), moduleData.value()->getEndAddress() - moduleData.value()->getStartAddress());
ICInvalidateRange((void *) moduleData.value()->getStartAddress(), moduleData.value()->getEndAddress() - moduleData.value()->getStartAddress());

char *arr[4];
arr[0] = (char *) environment_path.data();
arr[1] = (char *) "EnvironmentLoader"; //
Expand Down
34 changes: 10 additions & 24 deletions source/module/ModuleData.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,42 +34,28 @@ class ModuleData {
this->entrypoint = address;
}

void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
void addRelocationData(RelocationData relocation_data) {
relocation_data_list.push_back(std::move(relocation_data));
}

[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
[[nodiscard]] const std::vector<RelocationData> &getRelocationDataList() const {
return relocation_data_list;
}

[[nodiscard]] uint32_t getEntrypoint() const {
return entrypoint;
}

void setStartAddress(uint32_t address) {
this->startAddress = address;
void setTextMemory(ExpHeapMemory &&memory) {
mTextMemory = std::move(memory);
}

void setEndAddress(uint32_t address) {
this->endAddress = address;
}

[[nodiscard]] uint32_t getStartAddress() const {
return startAddress;
}

[[nodiscard]] uint32_t getEndAddress() const {
return endAddress;
}

void setMemory(ExpHeapMemory &&memory) {
mMemory = std::move(memory);
void setDataMemory(ExpHeapMemory &&memory) {
mDataMemory = std::move(memory);
}

private:
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
uint32_t entrypoint = 0;
uint32_t startAddress = 0;
uint32_t endAddress = 0;
ExpHeapMemory mMemory;
std::vector<RelocationData> relocation_data_list;
uint32_t entrypoint = 0;
ExpHeapMemory mTextMemory;
ExpHeapMemory mDataMemory;
};
155 changes: 85 additions & 70 deletions source/module/ModuleDataFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ uint32_t ModuleDataFactory::GetSizeOfModule(const ELFIO::elfio &reader) {
uint32_t sizeOfModule = 0;
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if (psec->get_type() == 0x80000002) {
if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") {
continue;
}

if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
sizeOfModule += psec->get_size() + 1;
sizeOfModule += psec->get_size() + psec->get_addr_align();
}
}
return sizeOfModule;
Expand All @@ -58,26 +58,41 @@ ModuleDataFactory::load(const ELFIO::elfio &reader, const HeapWrapper &heapWrapp
return {};
}

uint32_t sizeOfModule = GetSizeOfModule(reader);
uint32_t text_size = 0;
uint32_t data_size = 0;

auto moduleDataOpt = heapWrapper.Alloc(sizeOfModule, 0x100);
if (!moduleData) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for module");
return {};
}
ExpHeapMemory moduleMemory = std::move(*moduleDataOpt);
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if (psec->get_type() == 0x80000002) {
continue;
}

uint32_t dataPtr = (uint32_t) ((void *) moduleMemory);
uint32_t baseOffset = dataPtr;
uint32_t startAddress = baseOffset;
if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
uint32_t sectionSize = psec->get_size();
auto address = (uint32_t) psec->get_address();
if ((address >= 0x02000000) && address < 0x10000000) {
text_size += sectionSize + psec->get_addr_align();
} else if ((address >= 0x10000000) && address < 0xC0000000) {
data_size += sectionSize + psec->get_addr_align();
}
}
}

uint32_t offset_text = baseOffset;
uint32_t offset_data = offset_text;
auto text_dataOpt = heapWrapper.Alloc(text_size, 0x100);
if (!text_dataOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
return std::nullopt;
}
ExpHeapMemory text_data = std::move(*text_dataOpt);

uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000;
auto data_dataOpt = heapWrapper.Alloc(data_size, 0x100);
if (!data_dataOpt) {
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .data section (%d bytes)", data_size);
return std::nullopt;
}
ExpHeapMemory data_data = std::move(*data_dataOpt);

uint32_t totalSize = 0;
uint32_t endAddress = 0;
uint32_t entrypoint = (uint32_t) text_data.data() + (uint32_t) reader.get_entry() - 0x02000000;

for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
Expand All @@ -87,26 +102,34 @@ ModuleDataFactory::load(const ELFIO::elfio &reader, const HeapWrapper &heapWrapp

if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
uint32_t sectionSize = psec->get_size();
auto address = (uint32_t) psec->get_address();

totalSize += sectionSize;
if (totalSize > sizeOfModule) {
DEBUG_FUNCTION_LINE_ERR("Couldn't load setup module because it's too big.");
return {};
}

auto address = (uint32_t) psec->get_address();
uint32_t destination = address;

destinations[psec->get_index()] = (uint8_t *) baseOffset;

uint32_t destination = baseOffset + address;
if ((address >= 0x02000000) && address < 0x10000000) {
destination += (uint32_t) text_data.data();
destination -= 0x02000000;
destinations[psec->get_index()] -= 0x02000000;
baseOffset += sectionSize;
offset_data += sectionSize;
destinations[psec->get_index()] = (uint8_t *) text_data.data();

if (destination + sectionSize > (uint32_t) text_data.data() + text_size) {
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .text buffer. %08X > %08X", destination + sectionSize, (uint32_t) text_data.data() + text_data.size());
OSFatal("EnvironmentLoader: Tried to overflow .text buffer");
} else if (destination < (uint32_t) text_data.data()) {
DEBUG_FUNCTION_LINE_ERR("Tried to underflow .text buffer. %08X < %08X", destination, (uint32_t) text_data.data());
OSFatal("EnvironmentLoader: Tried to underflow .text buffer");
}
} else if ((address >= 0x10000000) && address < 0xC0000000) {
destination += (uint32_t) data_data.data();
destination -= 0x10000000;
destinations[psec->get_index()] -= 0x10000000;
destinations[psec->get_index()] = (uint8_t *) data_data.data();

if (destination + sectionSize > (uint32_t) data_data.data() + data_data.size()) {
DEBUG_FUNCTION_LINE_ERR("Tried to overflow .data buffer. %08X > %08X", destination + sectionSize, (uint32_t) data_data.data() + data_data.size());
OSFatal("EnvironmentLoader: Tried to overflow .data buffer");
} else if (destination < (uint32_t) data_data.data()) {
DEBUG_FUNCTION_LINE_ERR("Tried to underflow .data buffer. %08X < %08X", destination, (uint32_t) data_data.data());
OSFatal("EnvironmentLoader: Tried to underflow .data buffer");
}
} else if (address >= 0xC0000000) {
DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported");
return std::nullopt;
Expand All @@ -115,34 +138,22 @@ ModuleDataFactory::load(const ELFIO::elfio &reader, const HeapWrapper &heapWrapp
return std::nullopt;
}

const char *p = reader.sections[i]->get_data();
const char *p = psec->get_data();

if (destination < dataPtr) {
DEBUG_FUNCTION_LINE_ERR("Tried to underflow buffer. %08X < %08X", destination, dataPtr);
OSFatal("EnvironmentLoader: Tried to underflow buffer");
}
if (destination + sectionSize > (uint32_t) dataPtr + sizeOfModule) {
DEBUG_FUNCTION_LINE_ERR("Tried to overflow buffer. %08X > %08X", destination + sectionSize, dataPtr + sizeOfModule);
OSFatal("EnvironmentLoader: Tried to overflow buffer");
uint32_t address_align = psec->get_addr_align();
if ((destination & (address_align - 1)) != 0) {
DEBUG_FUNCTION_LINE_WARN("Address not aligned: %08X %08X", destination, address_align);
OSFatal("EnvironmentLoader: Address not aligned");
}

if (psec->get_type() == ELFIO::SHT_NOBITS) {
DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
DEBUG_FUNCTION_LINE_VERBOSE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize);
memset((void *) destination, 0, sectionSize);
} else if (psec->get_type() == ELFIO::SHT_PROGBITS) {
DEBUG_FUNCTION_LINE("Copy section %s %08X -> %08X (%d bytes)", psec->get_name().c_str(), p, destination, sectionSize);
DEBUG_FUNCTION_LINE_VERBOSE("Copy section %s %08X -> %08X (%d bytes)", psec->get_name().c_str(), p, destination, sectionSize);
memcpy((void *) destination, p, sectionSize);
}

//nextAddress = ROUNDUP(destination + sectionSize, 0x100);
if (psec->get_name() == ".bss" || psec->get_name() == ".sbss") {
DEBUG_FUNCTION_LINE("memset %s section. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
}

if (endAddress < destination + sectionSize) {
endAddress = destination + sectionSize;
}
DEBUG_FUNCTION_LINE_VERBOSE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);

DCFlushRange((void *) destination, sectionSize);
ICInvalidateRange((void *) destination, sectionSize);
Expand All @@ -153,21 +164,20 @@ ModuleDataFactory::load(const ELFIO::elfio &reader, const HeapWrapper &heapWrapp
ELFIO::section *psec = reader.sections[i];
if ((psec->get_type() == ELFIO::SHT_PROGBITS || psec->get_type() == ELFIO::SHT_NOBITS) && (psec->get_flags() & ELFIO::SHF_ALLOC)) {
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()], (uint32_t) (text_data.data()), (uint32_t) (data_data.data()), trampoline_data, trampoline_data_length)) {
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
return std::nullopt;
}
}
}
getImportRelocationData(moduleData, reader, destinations.get());

DCFlushRange((void *) dataPtr, totalSize);
ICInvalidateRange((void *) dataPtr, totalSize);
DCFlushRange((void *) data_data.data(), data_data.size());
ICInvalidateRange((void *) text_data.data(), text_data.size());

moduleData->setStartAddress(startAddress);
moduleData->setEndAddress(endAddress);
moduleData->setEntrypoint(entrypoint);
moduleData->setMemory(std::move(moduleMemory));
moduleData->setTextMemory(std::move(text_data));
moduleData->setDataMemory(std::move(data_data));

DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint);

Expand All @@ -194,6 +204,7 @@ bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &mod
for (uint32_t i = 0; i < sec_num; ++i) {
ELFIO::section *psec = reader.sections[i];
if (psec->get_type() == ELFIO::SHT_RELA || psec->get_type() == ELFIO::SHT_REL) {
DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str());
ELFIO::relocation_section_accessor rel(reader, psec);
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
ELFIO::Elf_Word symbol = 0;
Expand Down Expand Up @@ -231,21 +242,15 @@ bool ModuleDataFactory::getImportRelocationData(std::unique_ptr<ModuleData> &mod
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("EnvironmentLoader: Relocation is referencing a unknown section.");
}

auto relocationData = make_unique_nothrow<RelocationData>(type,
offset - 0x02000000,
addend,
(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));
moduleData->addRelocationData(RelocationData(type,
offset - 0x02000000,
addend,
(void *) (destinations[section_index]),
sym_name,
infoMap[sym_section_index]));
}
}
}
Expand Down Expand Up @@ -305,17 +310,27 @@ bool ModuleDataFactory::linkSection(const ELFIO::elfio &reader, uint32_t section
return false;
}

auto adjusted_offset = (uint32_t) offset;
if ((offset >= 0x02000000) && offset < 0x10000000) {
adjusted_offset -= 0x02000000;
} else if ((adjusted_offset >= 0x10000000) && adjusted_offset < 0xC0000000) {
adjusted_offset -= 0x10000000;
} else if (adjusted_offset >= 0xC0000000) {
adjusted_offset -= 0xC0000000;
}

if (sym_section_index == ELFIO::SHN_ABS) {
//
} else if (sym_section_index > ELFIO::SHN_LORESERVE) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index);
return false;
}
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
if (!ElfUtils::elfLinkOne(type, adjusted_offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
DEBUG_FUNCTION_LINE_ERR("Link failed");
return false;
}
}
return true;
}
}
return true;
Expand Down
Loading