mirror of
https://github.com/wiiu-env/WUMSLoader.git
synced 2024-12-24 15:11:50 +01:00
Rewrite of the WUMSLoader to simplify the code and have more memory for modules
This commit is contained in:
parent
b247427427
commit
b1b99343d6
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src
|
||||
build-binary:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: clang-format
|
||||
|
13
.github/workflows/pr.yml
vendored
13
.github/workflows/pr.yml
vendored
@ -9,7 +9,18 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: clang-format
|
||||
run: |
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src
|
||||
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src
|
||||
check-build-with-logging:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: clang-format
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: build binary with logging
|
||||
run: |
|
||||
docker build . -t builder
|
||||
docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE
|
||||
docker run --rm -v ${PWD}:/project builder make clean
|
||||
docker run --rm -v ${PWD}:/project builder make DEBUG=1
|
||||
build-binary:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: clang-format
|
||||
|
@ -1,5 +1,5 @@
|
||||
FROM wiiuenv/devkitppc:20211229
|
||||
FROM wiiuenv/devkitppc:20220507
|
||||
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20220127 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20220507 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
25
Makefile
25
Makefile
@ -31,7 +31,7 @@ INCLUDES := source
|
||||
#-------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#-------------------------------------------------------------------------------
|
||||
CFLAGS := -Wall -O2 -ffunction-sections \
|
||||
CFLAGS := -Wall -Os -ffunction-sections \
|
||||
$(MACHDEP)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
@ -42,10 +42,17 @@ ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
export DEBUG=1
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),VERBOSE)
|
||||
export DEBUG=VERBOSE
|
||||
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
endif
|
||||
|
||||
LIBS := -lwut -lz
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -91,7 +98,7 @@ endif
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC) relocator.elf.o
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC) wumsloader.elf.o
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
@ -107,13 +114,13 @@ all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C relocator
|
||||
@$(MAKE) --no-print-directory -C wumsloader
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
make clean -C relocator
|
||||
make clean -C wumsloader
|
||||
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -126,16 +133,16 @@ DEPENDS := $(OFILES:.o=.d)
|
||||
# main targets
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
relocator_elf := ../relocator/relocator.elf
|
||||
wumsloader_elf := ../wumsloader/wumsloader.elf
|
||||
|
||||
all : $(OUTPUT).rpx
|
||||
|
||||
$(relocator_elf):
|
||||
make -C ../relocator
|
||||
$(wumsloader_elf):
|
||||
make -C ../wumsloader
|
||||
|
||||
$(OUTPUT).rpx : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
$(OFILES) : relocator_elf.h
|
||||
$(OFILES) : wumsloader_elf.h
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
@ -152,7 +159,7 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
||||
@echo $(notdir $<)
|
||||
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
|
||||
|
||||
relocator_elf.h: $(relocator_elf)
|
||||
wumsloader_elf.h: $(wumsloader_elf)
|
||||
bin2s -a 32 -H `(echo $(<F) | tr . _)`.h $< | $(AS) -o $(<F).o
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
@ -8,7 +8,7 @@ Put the `10_wums_loader.rpx` in the `fs:/vol/external01/wiiu/environments/[ENVIR
|
||||
|
||||
Put modules (in form of `.wms` files) that should be used a main()-hook into `fs:/vol/external01/wiiu/environments/[ENVIRONMENT]/modules/`.
|
||||
|
||||
The area between `0x00800000` and whereever this loader is loaded, will be used.
|
||||
The area between `0x00809000` and `0x00FFF000` will be used.
|
||||
|
||||
## Building
|
||||
Make you to have [wut](https://github.com/devkitPro/wut/) and [WiiUModuleSystem](https://github.com/wiiu-env/WiiUModuleSystem) installed and use the following command for build:
|
||||
@ -33,10 +33,10 @@ docker run -it --rm -v ${PWD}:/project wumsloader-builder make clean
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./relocator/src -i`
|
||||
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source ./wumsloader/src -i`
|
||||
|
||||
## Credits
|
||||
- maschell
|
||||
- Maschell
|
||||
- Copy paste stuff from dimok
|
||||
- Copy pasted the solution for using wut header in .elf files from [RetroArch](https://github.com/libretro/RetroArch)
|
||||
- Copy pasted resolving the ElfRelocations from [decaf](https://github.com/decaf-emu/decaf-emu)
|
@ -1,108 +0,0 @@
|
||||
#include "DynamicLinkingHelper.h"
|
||||
#include <cstring>
|
||||
|
||||
dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) {
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (functionName == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
dyn_linking_function_t *result = nullptr;
|
||||
for (auto &function : data->functions) {
|
||||
dyn_linking_function_t *curEntry = &function;
|
||||
if (strlen(curEntry->functionName) == 0) {
|
||||
if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n");
|
||||
return nullptr;
|
||||
}
|
||||
strncpy(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH);
|
||||
result = curEntry;
|
||||
break;
|
||||
}
|
||||
if (strncmp(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH) == 0) {
|
||||
result = curEntry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
||||
return getOrAddImport(data, importName, false);
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
||||
return getOrAddImport(data, importName, true);
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData) {
|
||||
if (importName == nullptr || data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
dyn_linking_import_t *result = nullptr;
|
||||
for (auto &import : data->imports) {
|
||||
dyn_linking_import_t *curEntry = &import;
|
||||
if (strlen(curEntry->importName) == 0) {
|
||||
if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n");
|
||||
return nullptr;
|
||||
}
|
||||
strncpy(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH);
|
||||
curEntry->isData = isData;
|
||||
result = curEntry;
|
||||
break;
|
||||
}
|
||||
if (strncmp(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry->isData == isData)) {
|
||||
return curEntry;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
||||
const std::shared_ptr<RelocationData> &relocationData) {
|
||||
return addRelocationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(),
|
||||
relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(),
|
||||
relocationData->getName(),
|
||||
relocationData->getImportRPLInformation());
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset,
|
||||
int32_t addend, void *destination,
|
||||
const std::string &name, const std::shared_ptr<ImportRPLInformation> &rplInfo) {
|
||||
dyn_linking_import_t *importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(), rplInfo->isData());
|
||||
if (importInfoGbl == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d rpl files to import reached.\n", DYN_LINK_IMPORT_LIST_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
dyn_linking_function_t *functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str());
|
||||
if (functionInfo == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d function to be relocated reached.\n", DYN_LINK_FUNCTION_LIST_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
return addRelocationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo,
|
||||
importInfoGbl);
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination,
|
||||
dyn_linking_function_t *functionName,
|
||||
dyn_linking_import_t *importInfo) {
|
||||
for (uint32_t i = 0; i < linking_entry_length; i++) {
|
||||
dyn_linking_relocation_entry_t *curEntry = &(linking_entries[i]);
|
||||
if (curEntry->functionEntry != nullptr) {
|
||||
continue;
|
||||
}
|
||||
curEntry->type = type;
|
||||
curEntry->offset = offset;
|
||||
curEntry->addend = addend;
|
||||
curEntry->destination = destination;
|
||||
curEntry->functionEntry = functionName;
|
||||
curEntry->importEntry = importInfo;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../source/module/RelocationData.h"
|
||||
#include "utils/logger.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wums.h>
|
||||
|
||||
class DynamicLinkingHelper {
|
||||
public:
|
||||
/**
|
||||
Gets the function entry for a given function name. If the function name is not present in the list, it will be added.
|
||||
|
||||
\param functionName Name of the function
|
||||
\return Returns a pointer to the entry which contains the functionName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_function_t *getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName);
|
||||
|
||||
/**
|
||||
Gets the function import entry for a given function name. If the import is not present in the list, it will be added.
|
||||
This will return entries for _function_ imports.
|
||||
|
||||
\param importName Name of the function
|
||||
\return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
||||
|
||||
|
||||
/**
|
||||
Gets the data import entry for a given data name. If the import is not present in the list, it will be added.
|
||||
This will return entries for _data_ imports.
|
||||
|
||||
\param importName Name of the data
|
||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
||||
|
||||
|
||||
/**
|
||||
Gets the import entry for a given data name and type. If the import is not present in the list, it will be added.
|
||||
This will return entries for _data_ and _function_ imports, depending on the isData parameter.
|
||||
|
||||
\param importName Name of the data
|
||||
\param isData Set this to true to return a data import
|
||||
|
||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData);
|
||||
|
||||
static bool addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
||||
const std::shared_ptr<RelocationData> &relocationData);
|
||||
|
||||
static bool
|
||||
addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend,
|
||||
void *destination, const std::string &name,
|
||||
const std::shared_ptr<ImportRPLInformation> &rplInfo);
|
||||
|
||||
static bool
|
||||
addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination,
|
||||
dyn_linking_function_t *functionName, dyn_linking_import_t *importInfo);
|
||||
|
||||
private:
|
||||
DynamicLinkingHelper() = default;
|
||||
|
||||
~DynamicLinkingHelper() = default;
|
||||
};
|
@ -1,87 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018-2021 Maschell
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#include "../../source/module/HookData.h"
|
||||
#include "../../source/module/RelocationData.h"
|
||||
#include <vector>
|
||||
|
||||
#pragma once
|
||||
|
||||
class ModuleDataMinimal {
|
||||
public:
|
||||
ModuleDataMinimal() = default;
|
||||
|
||||
~ModuleDataMinimal() = default;
|
||||
|
||||
void setExportName(const std::string &name) {
|
||||
this->export_name = name;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getExportName() const {
|
||||
return this->export_name;
|
||||
}
|
||||
|
||||
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
|
||||
relocation_data_list.push_back(relocation_data);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<RelocationData>> &getRelocationDataList() const {
|
||||
return relocation_data_list;
|
||||
}
|
||||
|
||||
void addHookData(const std::shared_ptr<HookData> &data) {
|
||||
hook_data_list.push_back(data);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<HookData>> &getHookDataList() const {
|
||||
return hook_data_list;
|
||||
}
|
||||
|
||||
void setEntrypoint(uint32_t addr) {
|
||||
this->entrypoint = addr;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getEntrypoint() const {
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isInitBeforeRelocationDoneHook() const {
|
||||
return this->initBeforeRelocationDoneHook;
|
||||
}
|
||||
|
||||
void setInitBeforeRelocationDoneHook(bool value) {
|
||||
this->initBeforeRelocationDoneHook = value;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isSkipInitFini() const {
|
||||
return this->skipInitFini;
|
||||
}
|
||||
|
||||
void setSkipInitFini(bool value) {
|
||||
this->skipInitFini = value;
|
||||
}
|
||||
|
||||
bool relocationsDone = false;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
|
||||
std::vector<std::shared_ptr<HookData>> hook_data_list;
|
||||
std::string export_name;
|
||||
uint32_t entrypoint = 0;
|
||||
bool initBeforeRelocationDoneHook = false;
|
||||
bool skipInitFini = false;
|
||||
};
|
@ -1,71 +0,0 @@
|
||||
#include "ModuleDataPersistence.h"
|
||||
#include "DynamicLinkingHelper.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <wums.h>
|
||||
|
||||
std::vector<std::shared_ptr<ModuleDataMinimal>> ModuleDataPersistence::loadModuleData(module_information_t *moduleInformation) {
|
||||
std::vector<std::shared_ptr<ModuleDataMinimal>> result;
|
||||
if (moduleInformation == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("moduleInformation == NULL\n");
|
||||
return result;
|
||||
}
|
||||
DCFlushRange((void *) moduleInformation, sizeof(module_information_t));
|
||||
ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t));
|
||||
|
||||
int32_t module_count = moduleInformation->number_used_modules;
|
||||
|
||||
if (module_count > MAXIMUM_MODULES) {
|
||||
DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n", module_count, MAXIMUM_MODULES, MAXIMUM_MODULES);
|
||||
module_count = MAXIMUM_MODULES;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < module_count; i++) {
|
||||
// Copy data from struct.
|
||||
module_information_single_t *module_data = &(moduleInformation->module_data[i]);
|
||||
auto moduleData = std::make_shared<ModuleDataMinimal>();
|
||||
|
||||
moduleData->setEntrypoint(module_data->entrypoint);
|
||||
moduleData->setInitBeforeRelocationDoneHook(module_data->initBeforeRelocationDoneHook);
|
||||
moduleData->setSkipInitFini(module_data->skipInitFini);
|
||||
moduleData->setExportName(module_data->module_export_name);
|
||||
|
||||
for (auto &hook_entry : module_data->hook_entries) {
|
||||
if (hook_entry.target == 0) {
|
||||
continue;
|
||||
}
|
||||
moduleData->addHookData(std::make_shared<HookData>(static_cast<wums_hook_type_t>(hook_entry.type), reinterpret_cast<const void *>(hook_entry.target)));
|
||||
}
|
||||
|
||||
for (auto &linking_entry : module_data->linking_entries) {
|
||||
if (linking_entry.destination == nullptr) {
|
||||
break;
|
||||
}
|
||||
dyn_linking_import_t *importEntry = linking_entry.importEntry;
|
||||
if (importEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n");
|
||||
continue;
|
||||
}
|
||||
if (importEntry->importName == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("importEntry->importName was NULL, skipping relocation entry\n");
|
||||
continue;
|
||||
}
|
||||
dyn_linking_function_t *functionEntry = linking_entry.functionEntry;
|
||||
|
||||
if (functionEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n");
|
||||
continue;
|
||||
}
|
||||
if (functionEntry->functionName == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("functionEntry->functionName was NULL, skipping relocation entry\n");
|
||||
continue;
|
||||
}
|
||||
auto rplInfo = std::make_shared<ImportRPLInformation>(importEntry->importName, importEntry->isData);
|
||||
auto reloc = std::make_shared<RelocationData>(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionEntry->functionName, rplInfo);
|
||||
|
||||
moduleData->addRelocationData(reloc);
|
||||
}
|
||||
|
||||
result.push_back(moduleData);
|
||||
}
|
||||
return result;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModuleDataMinimal.h"
|
||||
#include <vector>
|
||||
#include <wums.h>
|
||||
|
||||
class ModuleDataPersistence {
|
||||
public:
|
||||
static std::vector<std::shared_ptr<ModuleDataMinimal>> loadModuleData(module_information_t *moduleInformation);
|
||||
};
|
@ -1,264 +0,0 @@
|
||||
#include "../../source/module/RelocationData.h"
|
||||
#include "ElfUtils.h"
|
||||
#include "ModuleDataPersistence.h"
|
||||
#include "globals.h"
|
||||
#include "hooks.h"
|
||||
#include "utils/dynamic.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/memory.h"
|
||||
#include <algorithm>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/dynload.h>
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
MEMHeapHandle gHeapHandle __attribute__((section(".data"))) = nullptr;
|
||||
uint8_t gFunctionsPatched __attribute__((section(".data"))) = 0;
|
||||
uint8_t gInitCalled __attribute__((section(".data"))) = 0;
|
||||
|
||||
extern "C" void socket_lib_init();
|
||||
|
||||
std::vector<std::shared_ptr<ModuleDataMinimal>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleDataMinimal>> &loadedModules);
|
||||
|
||||
void CallInitHooksForModule(const std::shared_ptr<ModuleDataMinimal> &curModule);
|
||||
|
||||
extern "C" void doStart(int argc, char **argv);
|
||||
// We need to wrap it to make sure the main function is called AFTER our code.
|
||||
// The compiler tries to optimize this otherwise and calling the main function earlier
|
||||
extern "C" int _start(int argc, char **argv) {
|
||||
InitFunctionPointers();
|
||||
|
||||
static uint8_t ucSetupRequired = 1;
|
||||
if (ucSetupRequired) {
|
||||
gHeapHandle = MEMCreateExpHeapEx((void *) (MEMORY_REGION_USABLE_HEAP_START), MEMORY_REGION_USABLE_HEAP_END - MEMORY_REGION_USABLE_HEAP_START, 1);
|
||||
ucSetupRequired = 0;
|
||||
}
|
||||
|
||||
socket_lib_init();
|
||||
log_init();
|
||||
|
||||
doStart(argc, argv);
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Call real one\n");
|
||||
log_deinit();
|
||||
|
||||
return ((int (*)(int, char **))(*(unsigned int *) 0x1005E040))(argc, argv);
|
||||
}
|
||||
|
||||
bool doRelocation(std::vector<std::shared_ptr<RelocationData>> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length, bool skipAllocReplacement) {
|
||||
std::map<std::string, OSDynLoad_Module> moduleCache;
|
||||
for (auto const &curReloc : relocData) {
|
||||
std::string functionName = curReloc->getName();
|
||||
std::string rplName = curReloc->getImportRPLInformation()->getName();
|
||||
uint32_t functionAddress = 0;
|
||||
|
||||
for (uint32_t i = 0; i < MAXIMUM_MODULES; i++) {
|
||||
if (rplName == gModuleData->module_data[i].module_export_name) {
|
||||
export_data_t *exportEntries = gModuleData->module_data[i].export_entries;
|
||||
for (uint32_t j = 0; j < EXPORT_ENTRY_LIST_LENGTH; j++) {
|
||||
if (functionName == exportEntries[j].name) {
|
||||
functionAddress = (uint32_t) exportEntries[j].address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipAllocReplacement) {
|
||||
if (functionName == "MEMAllocFromDefaultHeap") {
|
||||
functionAddress = reinterpret_cast<uint32_t>(&MEMAlloc);
|
||||
} else if (functionName == "MEMAllocFromDefaultHeapEx") {
|
||||
functionAddress = reinterpret_cast<uint32_t>(&MEMAllocEx);
|
||||
} else if (functionName == "MEMFreeToDefaultHeap") {
|
||||
functionAddress = reinterpret_cast<uint32_t>(&MEMFree);
|
||||
}
|
||||
}
|
||||
|
||||
if (functionAddress == 0) {
|
||||
int32_t isData = curReloc->getImportRPLInformation()->isData();
|
||||
OSDynLoad_Module rplHandle = nullptr;
|
||||
if (moduleCache.count(rplName) == 0) {
|
||||
OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
|
||||
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded\n", rplName.c_str());
|
||||
// only acquire if not already loaded.
|
||||
err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
|
||||
if (err != OS_DYNLOAD_OK) {
|
||||
DEBUG_FUNCTION_LINE("Failed to acquire %s\n", rplName.c_str());
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
moduleCache[rplName] = rplHandle;
|
||||
}
|
||||
rplHandle = moduleCache.at(rplName);
|
||||
|
||||
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
|
||||
if (functionAddress == 0) {
|
||||
OSFatal_printf("Failed to find export %s of %s", functionName.c_str(), rplName.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!ElfUtils::elfLinkOne(curReloc->getType(), curReloc->getOffset(), curReloc->getAddend(), (uint32_t) curReloc->getDestination(), functionAddress, tramp_data, tramp_length,
|
||||
RELOC_TYPE_IMPORT)) {
|
||||
DEBUG_FUNCTION_LINE("Relocation failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleDataMinimal>> &loadedModules, bool skipMemoryMappingModule) {
|
||||
bool wasSuccessful = true;
|
||||
|
||||
for (auto &curModule : loadedModules) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Let's do the relocations for %s\n", curModule->getExportName().c_str());
|
||||
if (wasSuccessful) {
|
||||
auto relocData = curModule->getRelocationDataList();
|
||||
|
||||
// On first usage we can't redirect the alloc functions to our custom heap
|
||||
// because threads can't run it on it. In order to patch the kernel
|
||||
// to fully support our memory region, we have to run the FunctionPatcher and MemoryMapping
|
||||
// once with the default heap. Afterwards we can just rely on the custom heap.
|
||||
bool skipAllocFunction = skipMemoryMappingModule && (curModule->getExportName() == "homebrew_memorymapping" || curModule->getExportName() == "homebrew_functionpatcher");
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d\n", skipAllocFunction);
|
||||
if (!doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLINE_LIST_LENGTH, skipAllocFunction)) {
|
||||
DEBUG_FUNCTION_LINE("FAIL\n");
|
||||
wasSuccessful = false;
|
||||
curModule->relocationsDone = false;
|
||||
}
|
||||
curModule->relocationsDone = true;
|
||||
}
|
||||
}
|
||||
DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
|
||||
ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
|
||||
return wasSuccessful;
|
||||
}
|
||||
|
||||
extern "C" void doStart(int argc, char **argv) {
|
||||
if (!gFunctionsPatched) {
|
||||
gFunctionsPatched = 1;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Loading module data\n");
|
||||
auto loadedModulesUnordered = ModuleDataPersistence::loadModuleData(gModuleData);
|
||||
auto loadedModules = OrderModulesByDependencies(loadedModulesUnordered);
|
||||
|
||||
bool applicationEndHookLoaded = false;
|
||||
for (auto &curModule : loadedModules) {
|
||||
if (curModule->getExportName() == "homebrew_applicationendshook") {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("We have ApplicationEndsHook Module!\n");
|
||||
applicationEndHookLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure WUMS_HOOK_APPLICATION_ENDS and WUMS_HOOK_FINI_WUT are called
|
||||
for (auto &curModule : loadedModules) {
|
||||
for (auto &curHook : curModule->getHookDataList()) {
|
||||
if (curHook->getType() == WUMS_HOOK_APPLICATION_ENDS || curHook->getType() == WUMS_HOOK_FINI_WUT_DEVOPTAB) {
|
||||
if (!applicationEndHookLoaded) {
|
||||
OSFatal_printf("%s requires module homebrew_applicationendshook", curModule->getExportName().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Number of modules %d\n", gModuleData->number_used_modules);
|
||||
if (!gInitCalled) {
|
||||
gInitCalled = 1;
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions\n");
|
||||
ResolveRelocations(loadedModules, true);
|
||||
|
||||
for (auto &curModule : loadedModules) {
|
||||
if (curModule->isInitBeforeRelocationDoneHook()) {
|
||||
CallInitHooksForModule(curModule);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook\n");
|
||||
CallHook(loadedModules, WUMS_HOOK_RELOCATIONS_DONE);
|
||||
|
||||
for (auto &curModule : loadedModules) {
|
||||
if (!curModule->isInitBeforeRelocationDoneHook()) {
|
||||
CallInitHooksForModule(curModule);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations and replace alloc functions\n");
|
||||
ResolveRelocations(loadedModules, false);
|
||||
CallHook(loadedModules, WUMS_HOOK_RELOCATIONS_DONE);
|
||||
}
|
||||
|
||||
CallHook(loadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB);
|
||||
CallHook(loadedModules, WUMS_HOOK_INIT_WUT_SOCKETS);
|
||||
CallHook(loadedModules, WUMS_HOOK_APPLICATION_STARTS);
|
||||
}
|
||||
|
||||
void CallInitHooksForModule(const std::shared_ptr<ModuleDataMinimal> &curModule) {
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_STDCPP);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_DEVOPTAB);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_SOCKETS);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WRAPPER, !curModule->isSkipInitFini());
|
||||
CallHook(curModule, WUMS_HOOK_INIT);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ModuleDataMinimal>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleDataMinimal>> &loadedModules) {
|
||||
std::vector<std::shared_ptr<ModuleDataMinimal>> finalOrder;
|
||||
std::vector<std::string> loadedModulesExportNames;
|
||||
std::vector<uint32_t> loadedModulesEntrypoints;
|
||||
|
||||
while (true) {
|
||||
bool canBreak = true;
|
||||
bool weDidSomething = false;
|
||||
for (auto const &curModule : loadedModules) {
|
||||
if (std::find(loadedModulesEntrypoints.begin(), loadedModulesEntrypoints.end(), curModule->getEntrypoint()) != loadedModulesEntrypoints.end()) {
|
||||
// DEBUG_FUNCTION_LINE("%s [%08X] is already loaded\n", curModule->getExportName().c_str(), curModule->getEntrypoint());
|
||||
continue;
|
||||
}
|
||||
canBreak = false;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Check if we can load %s\n", curModule->getExportName().c_str());
|
||||
std::vector<std::string> importsFromOtherModules;
|
||||
for (const auto &curReloc : curModule->getRelocationDataList()) {
|
||||
std::string curRPL = curReloc->getImportRPLInformation()->getName();
|
||||
if (curRPL.rfind("homebrew", 0) == 0) {
|
||||
if (std::find(importsFromOtherModules.begin(), importsFromOtherModules.end(), curRPL) != importsFromOtherModules.end()) {
|
||||
// is already in vector
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s is importing from %s\n", curModule->getExportName().c_str(), curRPL.c_str());
|
||||
importsFromOtherModules.push_back(curRPL);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool canLoad = true;
|
||||
for (auto &curImportRPL : importsFromOtherModules) {
|
||||
if (std::find(loadedModulesExportNames.begin(), loadedModulesExportNames.end(), curImportRPL) != loadedModulesExportNames.end()) {
|
||||
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("We can't load the module, because %s is not loaded yet\n", curImportRPL.c_str());
|
||||
canLoad = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canLoad) {
|
||||
weDidSomething = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("We can load: %s\n", curModule->getExportName().c_str());
|
||||
finalOrder.push_back(curModule);
|
||||
loadedModulesExportNames.push_back(curModule->getExportName());
|
||||
loadedModulesEntrypoints.push_back(curModule->getEntrypoint());
|
||||
}
|
||||
}
|
||||
if (canBreak) {
|
||||
break;
|
||||
} else if (!weDidSomething) {
|
||||
OSFatal_printf("Failed to resolve dependencies.");
|
||||
}
|
||||
}
|
||||
return finalOrder;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#include "globals.h"
|
||||
|
||||
uint32_t MemoryMappingEffectiveToPhysicalPTR = 0;
|
||||
uint32_t MemoryMappingPhysicalToEffectivePTR = 0;
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../source/globals.h"
|
||||
#include <cstdint>
|
||||
|
||||
extern uint32_t MemoryMappingEffectiveToPhysicalPTR;
|
||||
extern uint32_t MemoryMappingPhysicalToEffectivePTR;
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModuleDataMinimal.h"
|
||||
#include <vector>
|
||||
#include <wums.h>
|
||||
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type, bool condition);
|
||||
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type);
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type, bool condition);
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type);
|
@ -1,33 +0,0 @@
|
||||
OUTPUT(loader.elf);
|
||||
|
||||
ENTRY(_start);
|
||||
|
||||
SECTIONS {
|
||||
. = 0x00809000;
|
||||
.text : {
|
||||
*(.kernel_code*);
|
||||
*(.text*);
|
||||
/* Tell linker to not garbage collect this section as it is not referenced anywhere */
|
||||
KEEP(*(.kernel_code*));
|
||||
}
|
||||
.sdata : {
|
||||
*(.sdata*)
|
||||
}
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
.sbss : {
|
||||
*(.sbss*)
|
||||
}
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
}
|
||||
/DISCARD/ : {
|
||||
*(*);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT((SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.sdata) + SIZEOF(.rodata) + SIZEOF(.sbss) + SIZEOF(.bss)) < 0x77000, "Memory overlapping with modules.");
|
@ -1,141 +0,0 @@
|
||||
#include "logger.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/systeminfo.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int log_socket __attribute__((section(".data"))) = -1;
|
||||
static struct sockaddr_in connect_addr __attribute__((section(".data")));
|
||||
static volatile int log_lock __attribute__((section(".data"))) = 0;
|
||||
|
||||
#define SOL_SOCKET -1
|
||||
|
||||
|
||||
#define SOCK_DGRAM 2
|
||||
|
||||
|
||||
#define INADDR_ANY 0
|
||||
#define INADDR_BROADCAST 0xFFFFFFFF
|
||||
|
||||
#define PF_UNSPEC 0
|
||||
#define PF_INET 2
|
||||
#define PF_INET6 23
|
||||
|
||||
#define AF_UNSPEC PF_UNSPEC
|
||||
#define AF_INET PF_INET
|
||||
#define AF_INET6 PF_INET6
|
||||
|
||||
#define IPPROTO_UDP 17
|
||||
|
||||
#define SO_BROADCAST 0x0020 // broadcast
|
||||
|
||||
typedef uint16_t sa_family_t;
|
||||
|
||||
struct in_addr {
|
||||
unsigned int s_addr;
|
||||
};
|
||||
|
||||
struct sockaddr {
|
||||
sa_family_t sa_family;
|
||||
char sa_data[];
|
||||
};
|
||||
|
||||
struct sockaddr_in {
|
||||
unsigned short sin_family;
|
||||
unsigned short sin_port;
|
||||
struct in_addr sin_addr;
|
||||
char sin_zero[8];
|
||||
};
|
||||
|
||||
typedef uint32_t socklen_t;
|
||||
|
||||
extern int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
|
||||
extern int socket(int domain, int type, int protocol);
|
||||
|
||||
extern int socketclose(int sockfd);
|
||||
|
||||
extern int sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
|
||||
extern uint32_t htonl(uint32_t val);
|
||||
|
||||
void log_init() {
|
||||
int broadcastEnable = 1;
|
||||
log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (log_socket < 0)
|
||||
return;
|
||||
|
||||
setsockopt(log_socket, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
|
||||
|
||||
memset(&connect_addr, 0, sizeof(struct sockaddr_in));
|
||||
connect_addr.sin_family = AF_INET;
|
||||
connect_addr.sin_port = 4405;
|
||||
connect_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
||||
}
|
||||
|
||||
void log_deinit() {
|
||||
if (log_socket < 0) {
|
||||
return;
|
||||
}
|
||||
if (socketclose(log_socket) != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void log_print(const char *str) {
|
||||
OSReport(str);
|
||||
// socket is always 0 initially as it is in the BSS
|
||||
if (log_socket < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (log_lock) {
|
||||
OSSleepTicks(OSMicrosecondsToTicks(1000));
|
||||
}
|
||||
log_lock = 1;
|
||||
|
||||
int len = strlen(str);
|
||||
int ret;
|
||||
while (len > 0) {
|
||||
int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet
|
||||
ret = sendto(log_socket, str, block, 0, (struct sockaddr *) &connect_addr, sizeof(struct sockaddr_in));
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
len -= ret;
|
||||
str += ret;
|
||||
}
|
||||
|
||||
log_lock = 0;
|
||||
}
|
||||
|
||||
void OSFatal_printf(const char *format, ...) {
|
||||
char tmp[512];
|
||||
tmp[0] = 0;
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
OSFatal(tmp);
|
||||
}
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void log_printf(const char *format, ...) {
|
||||
if (log_socket < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char tmp[512];
|
||||
tmp[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
log_print(tmp);
|
||||
}
|
||||
va_end(va);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
#ifndef __LOGGER_H_
|
||||
#define __LOGGER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void log_init();
|
||||
|
||||
void log_deinit(void);
|
||||
|
||||
void log_print(const char *str);
|
||||
|
||||
void log_printf(const char *format, ...);
|
||||
|
||||
void OSFatal_printf(const char *format, ...);
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
OSFatal_printf("[%s]%s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
log_printf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) \
|
||||
do { \
|
||||
log_printf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,53 +1,6 @@
|
||||
#include "../wumsloader/src/elfio/elf_types.hpp"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/memdefaultheap.h>
|
||||
#include <whb/file.h>
|
||||
#include <whb/log.h>
|
||||
#include <whb/sdcard.h>
|
||||
|
||||
#include "ElfUtils.h"
|
||||
#include "elfio/elfio.hpp"
|
||||
|
||||
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut) {
|
||||
char path[256];
|
||||
int result = 0;
|
||||
char *sdRootPath = nullptr;
|
||||
if (!WHBMountSdCard()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to mount SD Card...");
|
||||
result = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sdRootPath = WHBGetSdCardMountPath();
|
||||
sprintf(path, "%s/%s", sdRootPath, relativefilepath);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Loading file %s.", path);
|
||||
|
||||
*fileOut = WHBReadWholeFile(path, sizeOut);
|
||||
if (!(*fileOut)) {
|
||||
result = -2;
|
||||
DEBUG_FUNCTION_LINE("WHBReadWholeFile(%s) returned NULL", path);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
WHBUnmountSdCard();
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath) {
|
||||
char *elf_data = nullptr;
|
||||
uint32_t fileSize = 0;
|
||||
if (LoadFileToMem(relativePath, &elf_data, &fileSize) != 0) {
|
||||
OSFatal("Failed to load hook_payload.elf from the SD Card.");
|
||||
}
|
||||
uint32_t result = load_loader_elf(baseAddress, elf_data, fileSize);
|
||||
|
||||
MEMFreeToDefaultHeap((void *) elf_data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize) {
|
||||
ELFIO::Elf32_Ehdr *ehdr;
|
||||
@ -105,149 +58,4 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi
|
||||
}
|
||||
|
||||
return ehdr->e_entry;
|
||||
}
|
||||
|
||||
// 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 *trampoline_data, uint32_t trampoline_data_length,
|
||||
RelocationType reloc_type) {
|
||||
if (type == R_PPC_NONE) {
|
||||
return true;
|
||||
}
|
||||
auto target = destination + offset;
|
||||
auto value = symbol_addr + addend;
|
||||
|
||||
|
||||
auto relValue = value - static_cast<uint32_t>(target);
|
||||
|
||||
switch (type) {
|
||||
case R_PPC_NONE:
|
||||
break;
|
||||
case R_PPC_ADDR32:
|
||||
*((uint32_t *) (target)) = value;
|
||||
break;
|
||||
case R_PPC_ADDR16_LO:
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>(value & 0xFFFF);
|
||||
break;
|
||||
case R_PPC_ADDR16_HI:
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>(value >> 16);
|
||||
break;
|
||||
case R_PPC_ADDR16_HA:
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
|
||||
break;
|
||||
case R_PPC_DTPMOD32:
|
||||
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
|
||||
//*((int32_t *)(target)) = tlsModuleIndex;
|
||||
break;
|
||||
case R_PPC_DTPREL32:
|
||||
*((uint32_t *) (target)) = value;
|
||||
break;
|
||||
case R_PPC_GHS_REL16_HA:
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>((relValue + 0x8000) >> 16);
|
||||
break;
|
||||
case R_PPC_GHS_REL16_HI:
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>(relValue >> 16);
|
||||
break;
|
||||
case R_PPC_GHS_REL16_LO:
|
||||
*((uint16_t *) (target)) = static_cast<uint16_t>(relValue & 0xFFFF);
|
||||
break;
|
||||
case R_PPC_REL14: {
|
||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
if (distance > 0x7FFC || distance < -0x7FFC) {
|
||||
DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance & 3) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
|
||||
(distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
*(int32_t *) target = (*(int32_t *) target & 0xFFBF0003) | (distance & 0x0000fffc);
|
||||
break;
|
||||
}
|
||||
case R_PPC_REL24: {
|
||||
// if (isWeakSymbol && !symbolValue) {
|
||||
// symbolValue = static_cast<uint32_t>(target);
|
||||
// value = symbolValue + addend;
|
||||
// }
|
||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
||||
if (trampoline_data == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
||||
return false;
|
||||
} else {
|
||||
relocation_trampoline_entry_t *freeSlot = nullptr;
|
||||
for (uint32_t i = 0; i < trampoline_data_length; i++) {
|
||||
// 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.
|
||||
if (trampoline_data[i].status == RELOC_TRAMP_FREE ||
|
||||
trampoline_data[i].status == RELOC_TRAMP_IMPORT_DONE) {
|
||||
freeSlot = &(trampoline_data[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (freeSlot == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
||||
return false;
|
||||
}
|
||||
if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) {
|
||||
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
||||
return false;
|
||||
}
|
||||
|
||||
freeSlot->trampoline[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h
|
||||
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) {
|
||||
freeSlot->status = RELOC_TRAMP_FIXED;
|
||||
} else {
|
||||
// Relocations for the imports may be overridden
|
||||
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
||||
}
|
||||
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
||||
value = symbolValue + addend;
|
||||
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
}
|
||||
}
|
||||
|
||||
if (distance & 3) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance >= 0 && (distance & 0xFE000000)) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
*(int32_t *) target = (*(int32_t *) target & 0xfc000003) | (distance & 0x03fffffc);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,52 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <wums.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int32_t LoadFileToMem(const char *relativefilepath, char **fileOut, uint32_t *sizeOut);
|
||||
uint32_t load_loader_elf_from_sd(unsigned char *baseAddress, const char *relativePath);
|
||||
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize);
|
||||
|
||||
#define R_PPC_NONE 0
|
||||
#define R_PPC_ADDR32 1
|
||||
#define R_PPC_ADDR16_LO 4
|
||||
#define R_PPC_ADDR16_HI 5
|
||||
#define R_PPC_ADDR16_HA 6
|
||||
#define R_PPC_REL24 10
|
||||
#define R_PPC_REL14 11
|
||||
#define R_PPC_DTPMOD32 68
|
||||
#define R_PPC_DTPREL32 78
|
||||
#define R_PPC_EMB_SDA21 109
|
||||
#define R_PPC_EMB_RELSDA 116
|
||||
#define R_PPC_DIAB_SDA21_LO 180
|
||||
#define R_PPC_DIAB_SDA21_HI 181
|
||||
#define R_PPC_DIAB_SDA21_HA 182
|
||||
#define R_PPC_DIAB_RELSDA_LO 183
|
||||
#define R_PPC_DIAB_RELSDA_HI 184
|
||||
#define R_PPC_DIAB_RELSDA_HA 185
|
||||
#define R_PPC_GHS_REL16_HA 251
|
||||
#define R_PPC_GHS_REL16_HI 252
|
||||
#define R_PPC_GHS_REL16_LO 253
|
||||
|
||||
// Masks for manipulating Power PC relocation targets
|
||||
#define PPC_WORD32 0xFFFFFFFF
|
||||
#define PPC_WORD30 0xFFFFFFFC
|
||||
#define PPC_LOW24 0x03FFFFFC
|
||||
#define PPC_LOW14 0x0020FFFC
|
||||
#define PPC_HALF16 0xFFFF
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class ElfUtils {
|
||||
|
||||
public:
|
||||
static bool 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);
|
||||
};
|
||||
|
@ -1,173 +0,0 @@
|
||||
|
||||
#include <fs/CFile.hpp>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
CFile::CFile() {
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
|
||||
iFd = -1;
|
||||
this->open(filepath, mode);
|
||||
}
|
||||
|
||||
CFile::CFile(const uint8_t *mem, int32_t size) {
|
||||
iFd = -1;
|
||||
this->open(mem, size);
|
||||
}
|
||||
|
||||
CFile::~CFile() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
|
||||
this->close();
|
||||
int32_t openMode = 0;
|
||||
|
||||
// This depend on the devoptab implementation.
|
||||
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
case ReadOnly: // file must exist
|
||||
openMode = O_RDONLY;
|
||||
break;
|
||||
case WriteOnly: // file will be created / zerod
|
||||
openMode = O_TRUNC | O_CREAT | O_WRONLY;
|
||||
break;
|
||||
case ReadWrite: // file must exist
|
||||
openMode = O_RDWR;
|
||||
break;
|
||||
case Append: // append to file, file will be created if missing. write only
|
||||
openMode = O_CREAT | O_APPEND | O_WRONLY;
|
||||
break;
|
||||
}
|
||||
|
||||
//! Using fopen works only on the first launch as expected
|
||||
//! on the second launch it causes issues because we don't overwrite
|
||||
//! the .data sections which is needed for a normal application to re-init
|
||||
//! this will be added with launching as RPX
|
||||
iFd = ::open(filepath.c_str(), openMode);
|
||||
if (iFd < 0)
|
||||
return iFd;
|
||||
|
||||
|
||||
filesize = ::lseek(iFd, 0, SEEK_END);
|
||||
::lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t CFile::open(const uint8_t *mem, int32_t size) {
|
||||
this->close();
|
||||
|
||||
mem_file = mem;
|
||||
filesize = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CFile::close() {
|
||||
if (iFd >= 0)
|
||||
::close(iFd);
|
||||
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
int32_t CFile::read(uint8_t *ptr, size_t size) {
|
||||
if (iFd >= 0) {
|
||||
int32_t ret = ::read(iFd, ptr, size);
|
||||
if (ret > 0)
|
||||
pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t readsize = size;
|
||||
|
||||
if (readsize > (int64_t) (filesize - pos))
|
||||
readsize = filesize - pos;
|
||||
|
||||
if (readsize <= 0)
|
||||
return readsize;
|
||||
|
||||
if (mem_file != NULL) {
|
||||
memcpy(ptr, mem_file + pos, readsize);
|
||||
pos += readsize;
|
||||
return readsize;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t CFile::write(const uint8_t *ptr, size_t size) {
|
||||
if (iFd >= 0) {
|
||||
size_t done = 0;
|
||||
while (done < size) {
|
||||
int32_t ret = ::write(iFd, ptr, size - done);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ptr += ret;
|
||||
done += ret;
|
||||
pos += ret;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t CFile::seek(long int offset, int32_t origin) {
|
||||
int32_t ret = 0;
|
||||
int64_t newPos = pos;
|
||||
|
||||
if (origin == SEEK_SET) {
|
||||
newPos = offset;
|
||||
} else if (origin == SEEK_CUR) {
|
||||
newPos += offset;
|
||||
} else if (origin == SEEK_END) {
|
||||
newPos = filesize + offset;
|
||||
}
|
||||
|
||||
if (newPos < 0) {
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = newPos;
|
||||
}
|
||||
|
||||
if (iFd >= 0)
|
||||
ret = ::lseek(iFd, pos, SEEK_SET);
|
||||
|
||||
if (mem_file != NULL) {
|
||||
if (pos > filesize) {
|
||||
pos = filesize;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t CFile::fwrite(const char *format, ...) {
|
||||
char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = -1;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
result = this->write((uint8_t *) tmp, strlen(tmp));
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#ifndef CFILE_HPP_
|
||||
#define CFILE_HPP_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
class CFile {
|
||||
public:
|
||||
enum eOpenTypes {
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
ReadWrite,
|
||||
Append
|
||||
};
|
||||
|
||||
CFile();
|
||||
|
||||
CFile(const std::string &filepath, eOpenTypes mode);
|
||||
|
||||
CFile(const uint8_t *memory, int32_t memsize);
|
||||
|
||||
virtual ~CFile();
|
||||
|
||||
int32_t open(const std::string &filepath, eOpenTypes mode);
|
||||
|
||||
int32_t open(const uint8_t *memory, int32_t memsize);
|
||||
|
||||
BOOL isOpen() const {
|
||||
if (iFd >= 0)
|
||||
return true;
|
||||
|
||||
if (mem_file)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
int32_t read(uint8_t *ptr, size_t size);
|
||||
|
||||
int32_t write(const uint8_t *ptr, size_t size);
|
||||
|
||||
int32_t fwrite(const char *format, ...);
|
||||
|
||||
int32_t seek(long int offset, int32_t origin);
|
||||
|
||||
uint64_t tell() {
|
||||
return pos;
|
||||
};
|
||||
|
||||
uint64_t size() {
|
||||
return filesize;
|
||||
};
|
||||
|
||||
void rewind() {
|
||||
this->seek(0, SEEK_SET);
|
||||
};
|
||||
|
||||
protected:
|
||||
int32_t iFd;
|
||||
const uint8_t *mem_file;
|
||||
uint64_t filesize;
|
||||
uint64_t pos;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <wums/defines/module_defines.h>
|
||||
|
||||
#define MEMORY_REGION_START 0x00800000
|
||||
#define MEMORY_REGION_SIZE 0x00800000
|
||||
|
||||
#define MEMORY_REGION_USABLE_HEAP_START (MEMORY_REGION_START + 0x00080000) // We don't want to override the relocator
|
||||
#define MEMORY_REGION_USABLE_HEAP_END (MEMORY_REGION_USABLE_HEAP_START + 0x00080000) // heap size is 512 KiB for now
|
||||
|
||||
#define MEMORY_REGION_USABLE_START MEMORY_REGION_USABLE_HEAP_END
|
||||
#define MEMORY_REGION_USABLE_END 0x00FFF000 // The last 0x1000 bytes are reserved kernel hook
|
||||
|
||||
#define gModuleData ((module_information_t *) (MEMORY_REGION_USABLE_START))
|
@ -1,20 +1,20 @@
|
||||
#include "kernel.h"
|
||||
#include "ElfUtils.h"
|
||||
#include "relocator_elf.h"
|
||||
#include "wumsloader_elf.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
|
||||
extern "C" void SCKernelCopyData(uint32_t addr, uint32_t src, uint32_t len);
|
||||
extern "C" void SC_KernelCopyData(uint32_t addr, uint32_t src, uint32_t len);
|
||||
|
||||
void SetupRelocator() {
|
||||
void SetupWUMSLoader() {
|
||||
kern_write((void *) (KERN_SYSCALL_TBL_1 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||
kern_write((void *) (KERN_SYSCALL_TBL_2 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||
kern_write((void *) (KERN_SYSCALL_TBL_3 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||
kern_write((void *) (KERN_SYSCALL_TBL_4 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||
kern_write((void *) (KERN_SYSCALL_TBL_5 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||
|
||||
uint32_t entryPoint = load_loader_elf(0, (char *) relocator_elf, relocator_elf_size);
|
||||
uint32_t entryPoint = load_loader_elf(0, (char *) wumsloader_elf, wumsloader_elf_size);
|
||||
|
||||
unsigned int repl_addr = ADDRESS_main_entry_hook;
|
||||
KernelWriteU32(repl_addr, 0x48000003 | entryPoint);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define ADDRESS_main_entry_hook 0x0101C56C
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu
|
||||
#define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL)
|
||||
|
||||
void SetupRelocator();
|
||||
void SetupWUMSLoader();
|
||||
|
||||
void KernelWriteU32(uint32_t addr, uint32_t value);
|
||||
|
||||
|
@ -1,51 +1,26 @@
|
||||
#include <cstring>
|
||||
|
||||
#include <elfio/elfio.hpp>
|
||||
#include "../wumsloader/src/globals.h"
|
||||
#include "kernel.h"
|
||||
#include "utils/logger.h"
|
||||
#include <nn/act/client_cpp.h>
|
||||
#include <sysapp/launch.h>
|
||||
|
||||
#include "ElfUtils.h"
|
||||
#include "fs/DirList.h"
|
||||
#include "globals.h"
|
||||
#include "kernel.h"
|
||||
#include "module/ModuleDataFactory.h"
|
||||
#include "module/ModuleDataPersistence.h"
|
||||
|
||||
extern "C" uint32_t textStart();
|
||||
extern "C" void __fini();
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
initLogging();
|
||||
|
||||
// We subtract 0x100 to be safe.
|
||||
uint32_t textSectionStart = textStart() - 0x100;
|
||||
|
||||
memset((void *) gModuleData, 0, sizeof(module_information_t));
|
||||
gModuleData->version = MODULE_INFORMATION_VERSION;
|
||||
|
||||
std::string basePath = "fs:/vol/external01/wiiu";
|
||||
if (argc >= 1) {
|
||||
basePath = argv[0];
|
||||
}
|
||||
|
||||
DirList modules(basePath + "/modules", ".wms", DirList::Files, 1);
|
||||
modules.SortList();
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overflow="
|
||||
strncpy(ENVRIONMENT_STRING, basePath.c_str(), ENVIRONMENT_PATH_LENGTH - 1);
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
uint32_t destination_address = ((uint32_t) gModuleData + (sizeof(module_information_t) + 0x0000FFFF)) & 0xFFFF0000;
|
||||
for (int i = 0; i < modules.GetFilecount(); i++) {
|
||||
DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i));
|
||||
auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i), &destination_address, textSectionStart - destination_address, gModuleData->trampolines,
|
||||
DYN_LINK_TRAMPOLINE_LIST_LENGTH);
|
||||
if (moduleData) {
|
||||
DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i));
|
||||
ModuleDataPersistence::saveModuleData(gModuleData, moduleData.value());
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to load %s", modules.GetFilepath(i));
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Setup relocator");
|
||||
SetupRelocator();
|
||||
DEBUG_FUNCTION_LINE("Setup wumsloader");
|
||||
SetupWUMSLoader();
|
||||
|
||||
nn::act::Initialize();
|
||||
nn::act::SlotNo slot = nn::act::GetSlotNo();
|
||||
|
@ -1,111 +0,0 @@
|
||||
#include "DynamicLinkingHelper.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/dynload.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
dyn_linking_function_t *DynamicLinkingHelper::getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName) {
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (functionName == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
dyn_linking_function_t *result = nullptr;
|
||||
for (auto &function : data->functions) {
|
||||
dyn_linking_function_t *curEntry = &function;
|
||||
if (strlen(curEntry->functionName) == 0) {
|
||||
if (strlen(functionName) > DYN_LINK_FUNCTION_NAME_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add function name, it's too long.\n");
|
||||
return nullptr;
|
||||
}
|
||||
strncpy(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH);
|
||||
result = curEntry;
|
||||
break;
|
||||
}
|
||||
if (strncmp(curEntry->functionName, functionName, DYN_LINK_FUNCTION_NAME_LENGTH) == 0) {
|
||||
result = curEntry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
||||
return getOrAddImport(data, importName, false);
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName) {
|
||||
return getOrAddImport(data, importName, true);
|
||||
}
|
||||
|
||||
dyn_linking_import_t *DynamicLinkingHelper::getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData) {
|
||||
if (importName == nullptr || data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
dyn_linking_import_t *result = nullptr;
|
||||
for (auto &import : data->imports) {
|
||||
dyn_linking_import_t *curEntry = &import;
|
||||
if (strlen(curEntry->importName) == 0) {
|
||||
if (strlen(importName) > DYN_LINK_IMPORT_NAME_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add Import, it's too long.\n");
|
||||
return nullptr;
|
||||
}
|
||||
strncpy(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH);
|
||||
curEntry->isData = isData;
|
||||
result = curEntry;
|
||||
break;
|
||||
}
|
||||
if (strncmp(curEntry->importName, importName, DYN_LINK_IMPORT_NAME_LENGTH) == 0 && (curEntry->isData == isData)) {
|
||||
return curEntry;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
||||
const std::shared_ptr<RelocationData> &relocationData) {
|
||||
return addReloationEntry(linking_data, linking_entries, linking_entry_length, relocationData->getType(), relocationData->getOffset(), relocationData->getAddend(), relocationData->getDestination(),
|
||||
relocationData->getName(),
|
||||
relocationData->getImportRPLInformation());
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset,
|
||||
int32_t addend, void *destination,
|
||||
const std::string &name, const std::shared_ptr<ImportRPLInformation> &rplInfo) {
|
||||
dyn_linking_import_t *importInfoGbl = DynamicLinkingHelper::getOrAddImport(linking_data, rplInfo->getName().c_str(), rplInfo->isData());
|
||||
if (importInfoGbl == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d rpl files to import reached.\n", DYN_LINK_IMPORT_LIST_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
dyn_linking_function_t *functionInfo = DynamicLinkingHelper::getOrAddFunctionEntryByName(linking_data, name.c_str());
|
||||
if (functionInfo == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Getting import info failed. Probably maximum of %d function to be relocated reached.\n", DYN_LINK_FUNCTION_LIST_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
return addRelocationEntry(linking_entries, linking_entry_length, type, offset, addend, destination, functionInfo,
|
||||
importInfoGbl);
|
||||
}
|
||||
|
||||
bool DynamicLinkingHelper::addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination,
|
||||
dyn_linking_function_t *functionName,
|
||||
dyn_linking_import_t *importInfo) {
|
||||
for (uint32_t i = 0; i < linking_entry_length; i++) {
|
||||
dyn_linking_relocation_entry_t *curEntry = &(linking_entries[i]);
|
||||
if (curEntry->functionEntry != nullptr) {
|
||||
continue;
|
||||
}
|
||||
curEntry->type = type;
|
||||
curEntry->offset = offset;
|
||||
curEntry->addend = addend;
|
||||
curEntry->destination = destination;
|
||||
curEntry->functionEntry = functionName;
|
||||
curEntry->importEntry = importInfo;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RelocationData.h"
|
||||
#include "utils/logger.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wums.h>
|
||||
|
||||
class DynamicLinkingHelper {
|
||||
public:
|
||||
/**
|
||||
Gets the function entry for a given function name. If the function name is not present in the list, it will be added.
|
||||
|
||||
\param functionName Name of the function
|
||||
\return Returns a pointer to the entry which contains the functionName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_function_t *getOrAddFunctionEntryByName(dyn_linking_relocation_data_t *data, const char *functionName);
|
||||
|
||||
/**
|
||||
Gets the function import entry for a given function name. If the import is not present in the list, it will be added.
|
||||
This will return entries for _function_ imports.
|
||||
|
||||
\param importName Name of the function
|
||||
\return Returns a pointer to the function import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddFunctionImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
||||
|
||||
|
||||
/**
|
||||
Gets the data import entry for a given data name. If the import is not present in the list, it will be added.
|
||||
This will return entries for _data_ imports.
|
||||
|
||||
\param importName Name of the data
|
||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddDataImportByName(dyn_linking_relocation_data_t *data, const char *importName);
|
||||
|
||||
|
||||
/**
|
||||
Gets the import entry for a given data name and type. If the import is not present in the list, it will be added.
|
||||
This will return entries for _data_ and _function_ imports, depending on the isData parameter.
|
||||
|
||||
\param importName Name of the data
|
||||
\param isData Set this to true to return a data import
|
||||
|
||||
\return Returns a pointer to the data import entry which contains the importName. Null on error or if the list full.
|
||||
**/
|
||||
static dyn_linking_import_t *getOrAddImport(dyn_linking_relocation_data_t *data, const char *importName, bool isData);
|
||||
|
||||
static bool addRelocationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length,
|
||||
const std::shared_ptr<RelocationData> &relocationData);
|
||||
|
||||
static bool addReloationEntry(dyn_linking_relocation_data_t *linking_data, dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend,
|
||||
void *destination, const std::string &name,
|
||||
const std::shared_ptr<ImportRPLInformation> &rplInfo);
|
||||
|
||||
static bool
|
||||
addRelocationEntry(dyn_linking_relocation_entry_t *linking_entries, uint32_t linking_entry_length, char type, size_t offset, int32_t addend, void *destination,
|
||||
dyn_linking_function_t *functionName, dyn_linking_import_t *importInfo);
|
||||
|
||||
private:
|
||||
DynamicLinkingHelper() = default;
|
||||
|
||||
~DynamicLinkingHelper() = default;
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
#include "ModuleData.h"
|
||||
#include "utils/StringTools.h"
|
||||
|
||||
std::string ModuleData::toString() const {
|
||||
std::string res = StringTools::strfmt("Entrypoint %08X, bss: %08X (%d), bss: %08X (%d)\n", getEntrypoint(), getBSSAddr(), getBSSSize(), getSBSSAddr(), getSBSSSize());
|
||||
for (auto const &reloc : relocation_data_list) {
|
||||
res += reloc->toString();
|
||||
}
|
||||
return res;
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
#include "ModuleDataPersistence.h"
|
||||
#include "DynamicLinkingHelper.h"
|
||||
#include <coreinit/cache.h>
|
||||
|
||||
bool ModuleDataPersistence::saveModuleData(module_information_t *moduleInformation, const std::shared_ptr<ModuleData> &module) {
|
||||
int32_t module_count = moduleInformation->number_used_modules;
|
||||
|
||||
if (module_count >= MAXIMUM_MODULES) {
|
||||
DEBUG_FUNCTION_LINE("Reached maximum module count of %d", MAXIMUM_MODULES);
|
||||
return false;
|
||||
}
|
||||
// Copy data to global struct.
|
||||
module_information_single_t *module_data = &(moduleInformation->module_data[module_count]);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Saving relocation data for module at %08X", module->getEntrypoint());
|
||||
// Relocation
|
||||
auto relocationData = module->getRelocationDataList();
|
||||
for (auto const &reloc : relocationData) {
|
||||
if (!DynamicLinkingHelper::addRelocationEntry(&(moduleInformation->linking_data), module_data->linking_entries,
|
||||
DYN_LINK_RELOCATION_LIST_LENGTH, reloc)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add relocation entry\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto exportData = module->getExportDataList();
|
||||
for (auto const &curExport : exportData) {
|
||||
bool found = false;
|
||||
for (auto &export_entry : module_data->export_entries) {
|
||||
if (export_entry.address == 0) {
|
||||
export_entry.type = curExport->getType();
|
||||
export_entry.name[0] = '\0';
|
||||
strncat(export_entry.name, curExport->getName().c_str(), sizeof(export_entry.name) - 1);
|
||||
export_entry.address = (uint32_t) curExport->getAddress();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
DEBUG_FUNCTION_LINE("Failed to found enough exports slots");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto hookData = module->getHookDataList();
|
||||
for (auto const &curHook : hookData) {
|
||||
bool found = false;
|
||||
for (auto &hook_entry : module_data->hook_entries) {
|
||||
if (hook_entry.target == 0) {
|
||||
hook_entry.type = curHook->getType();
|
||||
hook_entry.target = (uint32_t) curHook->getTarget();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
DEBUG_FUNCTION_LINE("Failed to found enough hook slots");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(module_data->module_export_name, module->getExportName().c_str(), MAXIMUM_EXPORT_MODULE_NAME_LENGTH);
|
||||
|
||||
uint32_t entryCount = module->getFunctionSymbolDataList().size();
|
||||
if (entryCount > 0) {
|
||||
auto ptr = &moduleInformation->function_symbols[moduleInformation->number_used_function_symbols];
|
||||
module_data->function_symbol_entries = ptr;
|
||||
|
||||
uint32_t sym_offset = 0;
|
||||
for (auto &curFuncSym : module->getFunctionSymbolDataList()) {
|
||||
if (moduleInformation->number_used_function_symbols >= FUNCTION_SYMBOL_LIST_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Function symbol list is full");
|
||||
break;
|
||||
}
|
||||
module_data->function_symbol_entries[sym_offset].address = curFuncSym->getAddress();
|
||||
module_data->function_symbol_entries[sym_offset].name = (char *) curFuncSym->getName();
|
||||
module_data->function_symbol_entries[sym_offset].size = curFuncSym->getSize();
|
||||
|
||||
sym_offset++;
|
||||
moduleInformation->number_used_function_symbols++;
|
||||
}
|
||||
module_data->number_used_function_symbols = sym_offset;
|
||||
} else {
|
||||
module_data->function_symbol_entries = nullptr;
|
||||
module_data->number_used_function_symbols = 0;
|
||||
}
|
||||
|
||||
module_data->bssAddr = module->getBSSAddr();
|
||||
module_data->bssSize = module->getBSSSize();
|
||||
module_data->sbssAddr = module->getSBSSAddr();
|
||||
module_data->sbssSize = module->getSBSSSize();
|
||||
module_data->startAddress = module->getStartAddress();
|
||||
module_data->endAddress = module->getEndAddress();
|
||||
module_data->entrypoint = module->getEntrypoint();
|
||||
module_data->skipInitFini = module->isSkipInitFini();
|
||||
module_data->initBeforeRelocationDoneHook = module->isInitBeforeRelocationDoneHook();
|
||||
|
||||
moduleInformation->number_used_modules++;
|
||||
|
||||
DCFlushRange((void *) moduleInformation, sizeof(module_information_t));
|
||||
ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ModuleData>> ModuleDataPersistence::loadModuleData(module_information_t *moduleInformation) {
|
||||
std::vector<std::shared_ptr<ModuleData>> result;
|
||||
if (moduleInformation == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("moduleInformation == NULL\n");
|
||||
return result;
|
||||
}
|
||||
DCFlushRange((void *) moduleInformation, sizeof(module_information_t));
|
||||
ICInvalidateRange((void *) moduleInformation, sizeof(module_information_t));
|
||||
|
||||
int32_t module_count = moduleInformation->number_used_modules;
|
||||
if (module_count > MAXIMUM_MODULES) {
|
||||
DEBUG_FUNCTION_LINE("moduleInformation->module_count was bigger then allowed. %d > %d. Limiting to %d\n", module_count, MAXIMUM_MODULES, MAXIMUM_MODULES);
|
||||
module_count = MAXIMUM_MODULES;
|
||||
}
|
||||
for (int32_t i = 0; i < module_count; i++) {
|
||||
// Copy data from struct.
|
||||
module_information_single_t *module_data = &(moduleInformation->module_data[i]);
|
||||
auto moduleData = std::make_shared<ModuleData>();
|
||||
moduleData->setBSSLocation(module_data->bssAddr, module_data->bssSize);
|
||||
moduleData->setSBSSLocation(module_data->sbssAddr, module_data->sbssSize);
|
||||
moduleData->setEntrypoint(module_data->entrypoint);
|
||||
moduleData->setStartAddress(module_data->startAddress);
|
||||
moduleData->setEndAddress(module_data->endAddress);
|
||||
moduleData->setExportName(module_data->module_export_name);
|
||||
moduleData->setSkipInitFini(module_data->skipInitFini);
|
||||
moduleData->setInitBeforeRelocationDoneHook(module_data->initBeforeRelocationDoneHook);
|
||||
|
||||
for (auto &export_entrie : module_data->export_entries) {
|
||||
export_data_t *export_entry = &export_entrie;
|
||||
if (export_entry->address == 0) {
|
||||
continue;
|
||||
}
|
||||
auto exportData = std::make_shared<ExportData>(static_cast<wums_entry_type_t>(export_entry->type), export_entry->name, reinterpret_cast<const void *>(export_entry->address));
|
||||
moduleData->addExportData(exportData);
|
||||
}
|
||||
|
||||
for (auto &hook_entry : module_data->hook_entries) {
|
||||
if (hook_entry.target == 0) {
|
||||
continue;
|
||||
}
|
||||
auto hookData = std::make_shared<HookData>(static_cast<wums_hook_type_t>(hook_entry.type), reinterpret_cast<const void *>(hook_entry.target));
|
||||
moduleData->addHookData(hookData);
|
||||
}
|
||||
|
||||
for (auto &linking_entry : module_data->linking_entries) {
|
||||
if (linking_entry.destination == nullptr) {
|
||||
break;
|
||||
}
|
||||
dyn_linking_import_t *importEntry = linking_entry.importEntry;
|
||||
if (importEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("importEntry was NULL, skipping relocation entry\n");
|
||||
continue;
|
||||
}
|
||||
dyn_linking_function_t *functionEntry = linking_entry.functionEntry;
|
||||
|
||||
if (functionEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("functionEntry was NULL, skipping relocation entry\n");
|
||||
continue;
|
||||
}
|
||||
auto rplInfo = std::make_shared<ImportRPLInformation>(importEntry->importName, importEntry->isData);
|
||||
auto reloc = std::make_shared<RelocationData>(linking_entry.type, linking_entry.offset, linking_entry.addend, linking_entry.destination, functionEntry->functionName, rplInfo);
|
||||
|
||||
moduleData->addRelocationData(reloc);
|
||||
}
|
||||
|
||||
if (module_data->function_symbol_entries != nullptr && module_data->number_used_function_symbols > 0) {
|
||||
for (uint32_t j = 0; j < module_data->number_used_function_symbols; j++) {
|
||||
auto symbol = &module_data->function_symbol_entries[j];
|
||||
auto functionSymbolData = std::make_shared<FunctionSymbolData>(symbol->name, symbol->address, symbol->size);
|
||||
moduleData->addFunctionSymbolData(functionSymbolData);
|
||||
}
|
||||
}
|
||||
result.push_back(moduleData);
|
||||
}
|
||||
return result;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModuleData.h"
|
||||
#include <wums.h>
|
||||
|
||||
class ModuleDataPersistence {
|
||||
public:
|
||||
static bool saveModuleData(module_information_t *moduleInformation, const std::shared_ptr<ModuleData> &module);
|
||||
|
||||
static std::vector<std::shared_ptr<ModuleData>> loadModuleData(module_information_t *moduleInformation);
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
#include "RelocationData.h"
|
||||
#include "utils/StringTools.h"
|
||||
|
||||
std::string RelocationData::toString() const {
|
||||
return StringTools::strfmt("%s destination: %08X offset: %08X type: %02X addend: %d rplName: %s isData: %d \n", name.c_str(), destination, offset, type, addend, rplInfo->getName().c_str(),
|
||||
rplInfo->isData());
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
.section ".crt0"
|
||||
.global textStart
|
||||
textStart:
|
||||
mflr 4;
|
||||
bl a
|
||||
mflr 3;
|
||||
mtlr 4;
|
||||
subi 3,3,0x8
|
||||
a: blr
|
@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
@ -1,289 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <utils/StringTools.h>
|
||||
#include <vector>
|
||||
#include <wchar.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
|
||||
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
||||
if (b.size() > a.size())
|
||||
return false;
|
||||
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
||||
}
|
||||
|
||||
const char *StringTools::byte_to_binary(int32_t x) {
|
||||
static char b[9];
|
||||
b[0] = '\0';
|
||||
|
||||
int32_t z;
|
||||
for (z = 128; z > 0; z >>= 1) {
|
||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
||||
std::string output = input;
|
||||
size_t position;
|
||||
while (1) {
|
||||
position = output.find(toBeRemoved);
|
||||
if (position == std::string::npos)
|
||||
break;
|
||||
output.erase(position, 1);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const char *StringTools::fmt(const char *format, ...) {
|
||||
static char strChar[512];
|
||||
strChar[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(strChar, format, va) >= 0)) {
|
||||
va_end(va);
|
||||
return (const char *) strChar;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
||||
static char tmp[512];
|
||||
static wchar_t strWChar[512];
|
||||
strWChar[0] = 0;
|
||||
tmp[0] = 0;
|
||||
|
||||
if (!format)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
if (strcmp(format, "") == 0)
|
||||
return (const wchar_t *) strWChar;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
int bt;
|
||||
int32_t strlength = strlen(tmp);
|
||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
||||
|
||||
if (bt > 0) {
|
||||
strWChar[bt] = 0;
|
||||
return (const wchar_t *) strWChar;
|
||||
}
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
result = str.size();
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string StringTools::strfmt(const char *format, ...) {
|
||||
std::string str;
|
||||
static char tmp[512];
|
||||
tmp[0] = 0;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
str = tmp;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
||||
if (!strChar || !dest)
|
||||
return false;
|
||||
|
||||
int bt;
|
||||
bt = mbstowcs(dest, strChar, strlen(strChar));
|
||||
if (bt > 0) {
|
||||
dest[bt] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||
if (!string || !compare)
|
||||
return -1;
|
||||
|
||||
char TokCopy[512];
|
||||
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||
TokCopy[511] = '\0';
|
||||
|
||||
char *strTok = strtok(TokCopy, separator);
|
||||
|
||||
while (strTok != NULL) {
|
||||
if (strcasecmp(string, strTok) == 0) {
|
||||
return 0;
|
||||
}
|
||||
strTok = strtok(NULL, separator);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
||||
if (!string || !extension)
|
||||
return -1;
|
||||
|
||||
char *ptr = strrchr(string, seperator);
|
||||
if (!ptr)
|
||||
return -1;
|
||||
|
||||
return strcasecmp(ptr + 1, extension);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
||||
std::string value = inValue;
|
||||
std::vector<std::string> result;
|
||||
while (true) {
|
||||
uint32_t index = value.find(splitter);
|
||||
if (index == std::string::npos) {
|
||||
result.push_back(value);
|
||||
break;
|
||||
}
|
||||
std::string first = value.substr(0, index);
|
||||
result.push_back(first);
|
||||
if (index + splitter.size() == value.length()) {
|
||||
result.push_back("");
|
||||
break;
|
||||
}
|
||||
if (index + splitter.size() > value.length()) {
|
||||
break;
|
||||
}
|
||||
value = value.substr(index + splitter.size(), value.length());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const char *StringTools::FullpathToFilename(const char *path) {
|
||||
if (!path)
|
||||
return path;
|
||||
|
||||
const char *ptr = path;
|
||||
const char *Filename = ptr;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||
Filename = ptr + 1;
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return Filename;
|
||||
}
|
||||
|
||||
void StringTools::RemoveDoubleSlashs(std::string &str) {
|
||||
uint32_t length = str.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
for (uint32_t i = 1; i < length; ++i) {
|
||||
if (str[i - 1] == '/' && str[i] == '/') {
|
||||
str.erase(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// You must free the result if result is non-NULL.
|
||||
char *StringTools::str_replace(char *orig, char *rep, char *with) {
|
||||
char *result; // the return string
|
||||
char *ins; // the next insert point
|
||||
char *tmp; // varies
|
||||
int len_rep; // length of rep (the string to remove)
|
||||
int len_with; // length of with (the string to replace rep with)
|
||||
int len_front; // distance between rep and end of last rep
|
||||
int count; // number of replacements
|
||||
|
||||
// sanity checks and initialization
|
||||
if (!orig || !rep)
|
||||
return NULL;
|
||||
len_rep = strlen(rep);
|
||||
if (len_rep == 0)
|
||||
return NULL; // empty rep causes infinite loop during count
|
||||
if (!with)
|
||||
with = (char *) "";
|
||||
len_with = strlen(with);
|
||||
|
||||
// count the number of replacements needed
|
||||
ins = orig;
|
||||
for (count = 0; (tmp = strstr(ins, rep)); ++count) {
|
||||
ins = tmp + len_rep;
|
||||
}
|
||||
|
||||
tmp = result = (char *) malloc(strlen(orig) + (len_with - len_rep) * count + 1);
|
||||
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
// first time through the loop, all the variable are set correctly
|
||||
// from here on,
|
||||
// tmp points to the end of the result string
|
||||
// ins points to the next occurrence of rep in orig
|
||||
// orig points to the remainder of orig after "end of rep"
|
||||
while (count--) {
|
||||
ins = strstr(orig, rep);
|
||||
len_front = ins - orig;
|
||||
tmp = strncpy(tmp, orig, len_front) + len_front;
|
||||
tmp = strcpy(tmp, with) + len_with;
|
||||
orig += len_front + len_rep; // move to next "end of rep"
|
||||
}
|
||||
strcpy(tmp, orig);
|
||||
return result;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
@ -7,22 +8,33 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_APP_TYPE "M"
|
||||
#define LOG_APP_NAME "WUMSInstaller"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
|
||||
|
||||
#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
|
||||
do { \
|
||||
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
#else
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
#endif
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||
|
||||
#else
|
||||
|
||||
@ -32,6 +44,8 @@ extern "C" {
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||
|
||||
#endif
|
||||
|
||||
void initLogging();
|
||||
|
@ -1,38 +0,0 @@
|
||||
#include "utils/logger.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
// https://gist.github.com/ccbrown/9722406
|
||||
void dumpHex(const void *data, size_t size) {
|
||||
char ascii[17];
|
||||
size_t i, j;
|
||||
ascii[16] = '\0';
|
||||
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x0000): ", data);
|
||||
for (i = 0; i < size; ++i) {
|
||||
WHBLogWritef("%02X ", ((unsigned char *) data)[i]);
|
||||
if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') {
|
||||
ascii[i % 16] = ((unsigned char *) data)[i];
|
||||
} else {
|
||||
ascii[i % 16] = '.';
|
||||
}
|
||||
if ((i + 1) % 8 == 0 || i + 1 == size) {
|
||||
WHBLogWritef(" ");
|
||||
if ((i + 1) % 16 == 0) {
|
||||
WHBLogPrintf("| %s ", ascii);
|
||||
if (i + 1 < size) {
|
||||
DEBUG_FUNCTION_LINE_WRITE("0x%08X (0x%04X); ", data + i + 1, i + 1);
|
||||
}
|
||||
} else if (i + 1 == size) {
|
||||
ascii[(i + 1) % 16] = '\0';
|
||||
if ((i + 1) % 16 <= 8) {
|
||||
WHBLogWritef(" ");
|
||||
}
|
||||
for (j = (i + 1) % 16; j < 16; ++j) {
|
||||
WHBLogWritef(" ");
|
||||
}
|
||||
WHBLogPrintf("| %s ", ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#ifndef __UTILS_H_
|
||||
#define __UTILS_H_
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LIMIT(x, min, max) \
|
||||
({ \
|
||||
typeof(x) _x = x; \
|
||||
typeof(min) _min = min; \
|
||||
typeof(max) _max = max; \
|
||||
(((_x) < (_min)) ? (_min) : ((_x) > (_max)) ? (_max) \
|
||||
: (_x)); \
|
||||
})
|
||||
|
||||
#define DegToRad(a) ((a) *0.01745329252f)
|
||||
#define RadToDeg(a) ((a) *57.29577951f)
|
||||
|
||||
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||
#define ALIGN32(x) (((x) + 31) & ~31)
|
||||
|
||||
// those work only in powers of 2
|
||||
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
||||
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
|
||||
|
||||
|
||||
#define le16(i) ((((uint16_t) ((i) &0xFF)) << 8) | ((uint16_t) (((i) &0xFF00) >> 8)))
|
||||
#define le32(i) ((((uint32_t) le16((i) &0xFFFF)) << 16) | ((uint32_t) le16(((i) &0xFFFF0000) >> 16)))
|
||||
#define le64(i) ((((uint64_t) le32((i) &0xFFFFFFFFLL)) << 32) | ((uint64_t) le32(((i) &0xFFFFFFFF00000000LL) >> 32)))
|
||||
|
||||
//Needs to have log_init() called beforehand.
|
||||
void dumpHex(const void *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __UTILS_H_
|
@ -23,6 +23,7 @@ export AR := $(PREFIX)ar
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
|
||||
WUMS_ROOT := $(DEVKITPRO)/wums
|
||||
WUT_ROOT := $(DEVKITPRO)/wut
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
@ -30,10 +31,14 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := relocator
|
||||
TARGET := wumsloader
|
||||
BUILD := build
|
||||
BUILD_DBG := $(TARGET)_dbg
|
||||
SOURCES := src src/utils src/kernel
|
||||
SOURCES := src \
|
||||
src/utils \
|
||||
src/kernel \
|
||||
src/fs \
|
||||
src/module
|
||||
|
||||
DATA := data
|
||||
|
||||
@ -42,10 +47,22 @@ INCLUDES := src
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
CFLAGS := -g -Wall -O3 -ffunction-sections $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
CFLAGS := -g -Wall -O0 -ffunction-sections $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
|
||||
ASFLAGS := -mregnames
|
||||
LDFLAGS := -nostartfiles -Wl,--gc-sections
|
||||
LDFLAGS := -Wl,--gc-sections,--allow-multiple-definition
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
export DEBUG=1
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),VERBOSE)
|
||||
export DEBUG=VERBOSE
|
||||
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
Q := @
|
||||
@ -53,18 +70,13 @@ MAKEFLAGS += --no-print-directory
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lwums
|
||||
LIBS := -lwums -lwut -lz
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(CURDIR) \
|
||||
$(DEVKITPPC)/lib \
|
||||
$(DEVKITPRO)/wut \
|
||||
$(WUMS_ROOT) \
|
||||
$(DEVKITPPC)/lib/gcc/powerpc-eabi/$(GCC_VER)
|
||||
|
||||
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
@ -104,15 +116,10 @@ export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
|
||||
# build a list of include paths
|
||||
#---------------------------------------------------------------------------------
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \
|
||||
-I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# build a list of library paths
|
||||
#---------------------------------------------------------------------------------
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
|
||||
-L$(LIBOGC_LIB) -L$(PORTLIBS)/lib
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
.PHONY: $(BUILD) clean install
|
@ -1,5 +1,4 @@
|
||||
# Setup payload - relocator
|
||||
This is a payload that is bundled with the SetupPayload that handled the relocations for the imports.
|
||||
# WUMSLoader
|
||||
|
||||
## Credits
|
||||
- maschell
|
@ -270,7 +270,7 @@ class section_impl : public section
|
||||
|
||||
ret = inflate(&s, Z_FINISH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END){
|
||||
DEBUG_FUNCTION_LINE("NOOOO");
|
||||
DEBUG_FUNCTION_LINE_ERR("inflate section failed.");
|
||||
}
|
||||
|
||||
inflateEnd(&s);
|
||||
@ -288,7 +288,7 @@ class section_impl : public section
|
||||
}
|
||||
}else{
|
||||
set_size(0);
|
||||
DEBUG_FUNCTION_LINE("Failed to allocate memory.");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory.");
|
||||
}
|
||||
}
|
||||
}
|
189
wumsloader/src/entry.cpp
Normal file
189
wumsloader/src/entry.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
#include "entry.h"
|
||||
#include "fs/DirList.h"
|
||||
#include "globals.h"
|
||||
#include "module/ModuleDataFactory.h"
|
||||
#include "module/ModuleDataPersistence.h"
|
||||
#include "utils/ElfUtils.h"
|
||||
#include "utils/RelocationUtils.h"
|
||||
#include "utils/dynamic.h"
|
||||
#include "utils/hooks.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <cstdint>
|
||||
|
||||
void CallInitHooksForModule(const std::shared_ptr<ModuleData> &curModule);
|
||||
|
||||
std::vector<std::shared_ptr<ModuleData>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleData>> &loadedModules);
|
||||
|
||||
// We need to wrap it to make sure the main function is called AFTER our code.
|
||||
// The compiler tries to optimize this otherwise and calling the main function earlier
|
||||
extern "C" int _start(int argc, char **argv) {
|
||||
InitFunctionPointers();
|
||||
static uint8_t ucSetupRequired = 1;
|
||||
if (ucSetupRequired) {
|
||||
gHeapHandle = MEMCreateExpHeapEx((void *) (MEMORY_REGION_USABLE_HEAP_START), MEMORY_REGION_USABLE_HEAP_END - MEMORY_REGION_USABLE_HEAP_START, 1);
|
||||
if (!gHeapHandle) {
|
||||
OSFatal("Failed to alloc heap");
|
||||
}
|
||||
|
||||
__init();
|
||||
ucSetupRequired = 0;
|
||||
}
|
||||
|
||||
doStart(argc, argv);
|
||||
|
||||
return ((int (*)(int, char **))(*(unsigned int *) 0x1005E040))(argc, argv);
|
||||
}
|
||||
|
||||
void doStart(int argc, char **argv) {
|
||||
__init_wut();
|
||||
initLogging();
|
||||
|
||||
if (!gInitCalled) {
|
||||
gInitCalled = 1;
|
||||
|
||||
std::string basePath = ENVRIONMENT_STRING;
|
||||
DEBUG_FUNCTION_LINE("We need to load the modules. basePath %s", basePath.c_str());
|
||||
DirList modules(basePath + "/modules", ".wms", DirList::Files, 1);
|
||||
modules.SortList();
|
||||
for (int i = 0; i < modules.GetFilecount(); i++) {
|
||||
DEBUG_FUNCTION_LINE("Loading module %s", modules.GetFilepath(i));
|
||||
auto moduleData = ModuleDataFactory::load(modules.GetFilepath(i));
|
||||
if (moduleData) {
|
||||
DEBUG_FUNCTION_LINE("Successfully loaded %s", modules.GetFilepath(i));
|
||||
gLoadedModules.push_back(std::move(moduleData.value()));
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s", modules.GetFilepath(i));
|
||||
}
|
||||
}
|
||||
|
||||
gModuleInformation = {.version = MODULE_INFORMATION_VERSION};
|
||||
ModuleDataPersistence::saveModuleData(&gModuleInformation, gLoadedModules);
|
||||
|
||||
auto orderedModules = OrderModulesByDependencies(gLoadedModules);
|
||||
|
||||
// make sure the plugin backend module is at the end.
|
||||
auto it = std::find_if(gLoadedModules.begin(),
|
||||
gLoadedModules.end(),
|
||||
[](auto &cur) { return std::string_view(cur->getExportName()) == "homebrew_wupsbackend"; });
|
||||
if (it != gLoadedModules.end()) {
|
||||
auto module = *it;
|
||||
gLoadedModules.erase(it);
|
||||
gLoadedModules.push_back(module);
|
||||
}
|
||||
|
||||
bool applicationEndHookLoaded = false;
|
||||
for (auto &curModule : gLoadedModules) {
|
||||
if (std::string_view(curModule->getExportName()) == "homebrew_applicationendshook") {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("We have ApplicationEndsHook Module!");
|
||||
applicationEndHookLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure WUMS_HOOK_APPLICATION_ENDS and WUMS_HOOK_FINI_WUT are called
|
||||
for (auto &curModule : gLoadedModules) {
|
||||
for (auto &curHook : curModule->getHookDataList()) {
|
||||
if (curHook->getType() == WUMS_HOOK_APPLICATION_ENDS || curHook->getType() == WUMS_HOOK_FINI_WUT_DEVOPTAB) {
|
||||
if (!applicationEndHookLoaded) {
|
||||
DEBUG_FUNCTION_LINE_ERR("%s requires module homebrew_applicationendshook", curModule->getExportName().c_str());
|
||||
OSFatal("module requires module homebrew_applicationendshook");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Resolve relocations without replacing alloc functions");
|
||||
ResolveRelocations(gLoadedModules, true);
|
||||
|
||||
for (auto &curModule : gLoadedModules) {
|
||||
if (curModule->isInitBeforeRelocationDoneHook()) {
|
||||
CallInitHooksForModule(curModule);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Call Relocations done hook");
|
||||
CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE);
|
||||
|
||||
for (auto &curModule : gLoadedModules) {
|
||||
if (!curModule->isInitBeforeRelocationDoneHook()) {
|
||||
CallInitHooksForModule(curModule);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Resolve relocations and replace alloc functions");
|
||||
ResolveRelocations(gLoadedModules, false);
|
||||
CallHook(gLoadedModules, WUMS_HOOK_RELOCATIONS_DONE);
|
||||
}
|
||||
|
||||
CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_DEVOPTAB);
|
||||
CallHook(gLoadedModules, WUMS_HOOK_INIT_WUT_SOCKETS);
|
||||
CallHook(gLoadedModules, WUMS_HOOK_APPLICATION_STARTS);
|
||||
|
||||
deinitLogging();
|
||||
__fini_wut();
|
||||
}
|
||||
|
||||
void CallInitHooksForModule(const std::shared_ptr<ModuleData> &curModule) {
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_MALLOC);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_NEWLIB);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_STDCPP);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_DEVOPTAB);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WUT_SOCKETS);
|
||||
CallHook(curModule, WUMS_HOOK_INIT_WRAPPER, !curModule->isSkipInitFini());
|
||||
CallHook(curModule, WUMS_HOOK_INIT);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ModuleData>> OrderModulesByDependencies(const std::vector<std::shared_ptr<ModuleData>> &loadedModules) {
|
||||
std::vector<std::shared_ptr<ModuleData>> finalOrder;
|
||||
std::vector<std::string_view> loadedModulesExportNames;
|
||||
std::vector<uint32_t> loadedModulesEntrypoints;
|
||||
|
||||
while (true) {
|
||||
bool canBreak = true;
|
||||
bool weDidSomething = false;
|
||||
for (auto const &curModule : loadedModules) {
|
||||
if (std::find(loadedModulesEntrypoints.begin(), loadedModulesEntrypoints.end(), curModule->getEntrypoint()) != loadedModulesEntrypoints.end()) {
|
||||
// DEBUG_FUNCTION_LINE("%s [%08X] is already loaded" curModule->getExportName().c_str(), curModule->getEntrypoint());
|
||||
continue;
|
||||
}
|
||||
canBreak = false;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Check if we can load %s", curModule->getExportName());
|
||||
std::vector<std::string_view> importsFromOtherModules;
|
||||
for (const auto &curReloc : curModule->getRelocationDataList()) {
|
||||
std::string_view curRPL = curReloc->getImportRPLInformation()->getRPLName();
|
||||
if (curRPL == "homebrew_wupsbackend") {
|
||||
OSFatal("Error: module depends on homebrew_wupsbackend, this is not supported");
|
||||
}
|
||||
if (curRPL.starts_with("homebrew")) {
|
||||
if (std::find(importsFromOtherModules.begin(), importsFromOtherModules.end(), curRPL) == importsFromOtherModules.end()) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s is importing from %s", curModule->getExportName(), curRPL.begin());
|
||||
importsFromOtherModules.push_back(curRPL);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool canLoad = true;
|
||||
for (auto &curImportRPL : importsFromOtherModules) {
|
||||
if (std::find(loadedModulesExportNames.begin(), loadedModulesExportNames.end(), curImportRPL) == loadedModulesExportNames.end()) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("We can't load the module, because %s is not loaded yet", curImportRPL.begin());
|
||||
canLoad = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canLoad) {
|
||||
weDidSomething = true;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("We can load: %s", curModule->getExportName());
|
||||
finalOrder.push_back(curModule);
|
||||
loadedModulesExportNames.emplace_back(curModule->getExportName());
|
||||
loadedModulesEntrypoints.push_back(curModule->getEntrypoint());
|
||||
}
|
||||
}
|
||||
if (canBreak) {
|
||||
break;
|
||||
} else if (!weDidSomething) {
|
||||
OSFatal("Failed to resolve dependencies.");
|
||||
}
|
||||
}
|
||||
return finalOrder;
|
||||
}
|
7
wumsloader/src/entry.h
Normal file
7
wumsloader/src/entry.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
extern "C" void __init();
|
||||
extern "C" void __init_wut();
|
||||
extern "C" void __fini_wut();
|
||||
|
||||
void doStart(int argc, char **argv);
|
@ -1,21 +1,22 @@
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/memdefaultheap.h>
|
||||
#include <cstdint>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
||||
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
|
||||
|
||||
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = NULL;
|
||||
*inbuffer = nullptr;
|
||||
if (size) {
|
||||
*size = 0;
|
||||
}
|
||||
|
||||
int32_t iFd = open(filepath, O_RDONLY);
|
||||
int32_t iFd = open(filepath.c_str(), O_RDONLY);
|
||||
if (iFd < 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -23,7 +24,7 @@ int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size)
|
||||
uint32_t filesize = lseek(iFd, 0, SEEK_END);
|
||||
lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
|
||||
auto *buffer = (uint8_t *) MEMAllocFromDefaultHeapEx(ROUNDUP(filesize, 0x40), 0x40);
|
||||
if (buffer == nullptr) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
@ -59,4 +60,4 @@ int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size)
|
||||
}
|
||||
|
||||
return filesize;
|
||||
}
|
||||
}
|
4
wumsloader/src/fs/FileUtils.h
Normal file
4
wumsloader/src/fs/FileUtils.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size);
|
7
wumsloader/src/globals.cpp
Normal file
7
wumsloader/src/globals.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "globals.h"
|
||||
|
||||
MEMHeapHandle gHeapHandle __attribute__((section(".data"))) = nullptr;
|
||||
uint8_t gInitCalled __attribute__((section(".data"))) = 0;
|
||||
module_information_t gModuleInformation __attribute__((section(".data")));
|
||||
std::vector<std::shared_ptr<ModuleData>> gLoadedModules __attribute__((section(".data")));
|
||||
std::unique_ptr<module_information_single_t[]> gModuleDataInfo __attribute__((section(".data")));
|
25
wumsloader/src/globals.h
Normal file
25
wumsloader/src/globals.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "module/ModuleData.h"
|
||||
#include <coreinit/memheap.h>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
extern uint8_t gInitCalled;
|
||||
extern MEMHeapHandle gHeapHandle;
|
||||
extern module_information_t gModuleInformation;
|
||||
extern std::vector<std::shared_ptr<ModuleData>> gLoadedModules;
|
||||
extern std::unique_ptr<module_information_single_t[]> gModuleDataInfo;
|
||||
|
||||
#define MEMORY_REGION_START 0x00800000
|
||||
#define MEMORY_REGION_SIZE 0x00800000
|
||||
|
||||
#define CUSTOM_RPX_LOADER_RETURN_CODE 0x00009000 // We have to skip the first 0x00009000 bytes because it's still used
|
||||
#define RELOCATOR_SIZE 0x130000 // Maximum size of the wumsloader, needs to match the one defined in link.ld
|
||||
#define ENVIRONMENT_PATH_LENGTH 0x100 // Length of the EnvironmentPath.
|
||||
|
||||
#define MEMORY_REGION_ENVIRONMENT_STRING_ADRR (MEMORY_REGION_START + CUSTOM_RPX_LOADER_RETURN_CODE + RELOCATOR_SIZE)
|
||||
#define MEMORY_REGION_USABLE_HEAP_START (MEMORY_REGION_ENVIRONMENT_STRING_ADRR + ENVIRONMENT_PATH_LENGTH)
|
||||
#define MEMORY_REGION_USABLE_HEAP_END (0x00FFF000) // We need to leave space for the BAT hook
|
||||
|
||||
#define ENVRIONMENT_STRING ((char *) MEMORY_REGION_ENVIRONMENT_STRING_ADRR)
|
95
wumsloader/src/link.ld
Normal file
95
wumsloader/src/link.ld
Normal file
@ -0,0 +1,95 @@
|
||||
OUTPUT(loader.elf);
|
||||
|
||||
ENTRY(_start);
|
||||
|
||||
SECTIONS {
|
||||
. = 0x00809000;
|
||||
.text ALIGN(32) : {
|
||||
KEEP (*(.crt0))
|
||||
KEEP (*(SORT_NONE(.init)))
|
||||
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(SORT(.text.sorted.*))
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
*(.gnu.warning)
|
||||
*(.glink)
|
||||
|
||||
KEEP (*(SORT_NONE(.fini)))
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
|
||||
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
|
||||
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
|
||||
*(.gcc_except_table .gcc_except_table.*)
|
||||
*(.gnu_extab*)
|
||||
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP (*(.jcr))
|
||||
*(.fixup)
|
||||
*(.got1)
|
||||
*(.got2)
|
||||
*(.branch_lt)
|
||||
*(.got)
|
||||
*(.plt)
|
||||
*(.tm_clone_table)
|
||||
}
|
||||
|
||||
.eh_frame : {
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame_entry .eh_frame_entry.*)
|
||||
|
||||
KEEP (*(.eh_frame))
|
||||
*(.eh_frame.*)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
*(.data1)
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
}
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
*(.dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
}
|
||||
/DISCARD/ : {
|
||||
*(*);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT((SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata) + SIZEOF(.eh_frame) + SIZEOF(.bss)) < 0x130000, "Memory overlapping with modules.");
|
@ -6,9 +6,9 @@
|
||||
class ExportData {
|
||||
|
||||
public:
|
||||
ExportData(wums_entry_type_t type, const std::string &name, const void *address) {
|
||||
ExportData(wums_entry_type_t type, std::string name, const void *address) {
|
||||
this->type = type;
|
||||
this->name = name;
|
||||
this->name = std::move(name);
|
||||
this->address = address;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ public:
|
||||
return address;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string getName() const {
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class FunctionSymbolData {
|
||||
public:
|
||||
FunctionSymbolData(const FunctionSymbolData &o2) = default;
|
||||
|
||||
FunctionSymbolData(const char *name, void *address, uint32_t size) : name(name),
|
||||
FunctionSymbolData(std::string name, void *address, uint32_t size) : name(std::move(name)),
|
||||
address(address),
|
||||
size(size) {
|
||||
}
|
||||
@ -32,10 +32,10 @@ public:
|
||||
virtual ~FunctionSymbolData() = default;
|
||||
|
||||
bool operator<(const FunctionSymbolData &rhs) const {
|
||||
return (uint32_t) address < (uint32_t) rhs.address; //assume that you compare the record based on a
|
||||
return (uint32_t) address < (uint32_t) rhs.address;
|
||||
}
|
||||
|
||||
[[nodiscard]] const char *getName() const {
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -47,9 +47,8 @@ public:
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
const char *name;
|
||||
std::string name;
|
||||
void *address;
|
||||
uint32_t size;
|
||||
};
|
@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/debug.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
@ -26,44 +27,27 @@
|
||||
class ImportRPLInformation {
|
||||
|
||||
public:
|
||||
explicit ImportRPLInformation(std::string name, bool isData = false) {
|
||||
this->name = std::move(name);
|
||||
this->_isData = isData;
|
||||
explicit ImportRPLInformation(std::string rawSectionName) {
|
||||
this->name = std::move(rawSectionName);
|
||||
}
|
||||
|
||||
~ImportRPLInformation() = default;
|
||||
|
||||
static std::optional<std::shared_ptr<ImportRPLInformation>> createImportRPLInformation(std::string rawSectionName) {
|
||||
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 {
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
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 {
|
||||
return _isData;
|
||||
return name.starts_with(".dimport_");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
bool _isData = false;
|
||||
};
|
@ -54,51 +54,43 @@ public:
|
||||
this->entrypoint = addr;
|
||||
}
|
||||
|
||||
void setStartAddress(uint32_t addr) {
|
||||
this->startAddress = addr;
|
||||
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
|
||||
relocation_data_list.push_back(std::move(relocation_data));
|
||||
}
|
||||
|
||||
void setEndAddress(uint32_t _endAddress) {
|
||||
this->endAddress = _endAddress;
|
||||
}
|
||||
|
||||
void addRelocationData(const std::shared_ptr<RelocationData> &relocation_data) {
|
||||
relocation_data_list.push_back(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;
|
||||
}
|
||||
|
||||
void addExportData(const std::shared_ptr<ExportData> &data) {
|
||||
export_data_list.push_back(data);
|
||||
void addExportData(std::unique_ptr<ExportData> data) {
|
||||
export_data_list.push_back(std::move(data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<ExportData>> &getExportDataList() const {
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<ExportData>> &getExportDataList() const {
|
||||
return export_data_list;
|
||||
}
|
||||
|
||||
void addHookData(const std::shared_ptr<HookData> &data) {
|
||||
hook_data_list.push_back(data);
|
||||
void addHookData(std::unique_ptr<HookData> data) {
|
||||
hook_data_list.push_back(std::move(data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<HookData>> &getHookDataList() const {
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<HookData>> &getHookDataList() const {
|
||||
return hook_data_list;
|
||||
}
|
||||
|
||||
void addSectionInfo(const std::shared_ptr<SectionInfo> §ionInfo) {
|
||||
section_info_list[sectionInfo->getName()] = sectionInfo;
|
||||
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) {
|
||||
section_info_list[sectionInfo->getName()] = std::move(sectionInfo);
|
||||
}
|
||||
|
||||
void addFunctionSymbolData(const std::shared_ptr<FunctionSymbolData> &symbol_data) {
|
||||
symbol_data_list.insert(symbol_data);
|
||||
void addFunctionSymbolData(std::shared_ptr<FunctionSymbolData> symbol_data) {
|
||||
symbol_data_list.insert(std::move(symbol_data));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
||||
return symbol_data_list;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
|
||||
[[nodiscard]] const std::map<std::string_view, std::shared_ptr<SectionInfo>> &getSectionInfoList() const {
|
||||
return section_info_list;
|
||||
}
|
||||
|
||||
@ -106,10 +98,10 @@ public:
|
||||
if (getSectionInfoList().count(sectionName) > 0) {
|
||||
return section_info_list.at(sectionName);
|
||||
}
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getBSSAddr() const {
|
||||
[[nodiscard]] uint32_t getBSSAddress() const {
|
||||
return bssAddr;
|
||||
}
|
||||
|
||||
@ -117,7 +109,7 @@ public:
|
||||
return bssSize;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getSBSSAddr() const {
|
||||
[[nodiscard]] uint32_t getSBSSAddress() const {
|
||||
return sbssAddr;
|
||||
}
|
||||
|
||||
@ -125,25 +117,23 @@ public:
|
||||
return sbssSize;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getStartAddress() const {
|
||||
return reinterpret_cast<uint32_t>(dataPtr.get());
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getEndAddress() const {
|
||||
return reinterpret_cast<uint32_t>(dataPtr.get()) + this->totalSize;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getEntrypoint() const {
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getStartAddress() const {
|
||||
return startAddress;
|
||||
void setExportName(std::string name) {
|
||||
this->export_name = std::move(name);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t getEndAddress() const {
|
||||
return endAddress;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string toString() const;
|
||||
|
||||
void setExportName(const std::string &name) {
|
||||
this->export_name = name;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getExportName() const {
|
||||
[[nodiscard]] const std::string &getExportName() const {
|
||||
return this->export_name;
|
||||
}
|
||||
|
||||
@ -163,24 +153,33 @@ public:
|
||||
this->skipInitFini = value;
|
||||
}
|
||||
|
||||
bool relocationsDone = false;
|
||||
void setDataPtr(std::unique_ptr<uint8_t[]> ptr, uint32_t size) {
|
||||
this->dataPtr = std::move(ptr);
|
||||
this->totalSize = size;
|
||||
}
|
||||
|
||||
std::unique_ptr<hook_data_t[]> hookDataStruct;
|
||||
std::unique_ptr<export_data_t[]> exportDataStruct;
|
||||
std::unique_ptr<module_function_symbol_data_t[]> functionSymbolDataStruct;
|
||||
std::unique_ptr<dyn_linking_import_t[]> rplDataStruct;
|
||||
std::unique_ptr<dyn_linking_relocation_entry_t[]> relocationDataStruct;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
|
||||
std::vector<std::shared_ptr<ExportData>> export_data_list;
|
||||
std::vector<std::shared_ptr<HookData>> hook_data_list;
|
||||
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
|
||||
std::vector<std::unique_ptr<ExportData>> export_data_list;
|
||||
std::vector<std::unique_ptr<HookData>> hook_data_list;
|
||||
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_data_list;
|
||||
std::map<std::string, std::shared_ptr<SectionInfo>> section_info_list;
|
||||
std::map<std::string_view, std::shared_ptr<SectionInfo>> section_info_list;
|
||||
|
||||
std::unique_ptr<uint8_t[]> dataPtr;
|
||||
std::string export_name;
|
||||
|
||||
uint32_t bssAddr = 0;
|
||||
uint32_t bssSize = 0;
|
||||
uint32_t sbssAddr = 0;
|
||||
uint32_t sbssSize = 0;
|
||||
uint32_t startAddress = 0;
|
||||
uint32_t endAddress = 0;
|
||||
uint32_t entrypoint = 0;
|
||||
uint32_t totalSize = 0;
|
||||
bool initBeforeRelocationDoneHook = false;
|
||||
bool skipInitFini = false;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018 Maschell
|
||||
* Copyright (C) 2022 Maschell
|
||||
*
|
||||
* 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
|
||||
@ -16,54 +16,86 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "ModuleDataFactory.h"
|
||||
#include "ElfUtils.h"
|
||||
#include "utils/FileUtils.h"
|
||||
#include "utils/utils.h"
|
||||
#include "fs/FileUtils.h"
|
||||
#include "utils/ElfUtils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memdefaultheap.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wums.h>
|
||||
|
||||
using namespace ELFIO;
|
||||
|
||||
std::optional<std::shared_ptr<ModuleData>>
|
||||
ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_ptr, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) {
|
||||
std::optional<std::shared_ptr<ModuleData>> ModuleDataFactory::load(const std::string &path) {
|
||||
elfio reader;
|
||||
std::shared_ptr<ModuleData> moduleData = std::make_shared<ModuleData>();
|
||||
auto moduleData = std::make_shared<ModuleData>();
|
||||
if (!moduleData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc module data");
|
||||
return {};
|
||||
}
|
||||
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t fsize = 0;
|
||||
if (LoadFileToMem(path.c_str(), &buffer, &fsize) < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to load file");
|
||||
if (LoadFileToMem(path, &buffer, &fsize) < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load file");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Load ELF data
|
||||
if (!reader.load(reinterpret_cast<char *>(buffer), fsize)) {
|
||||
DEBUG_FUNCTION_LINE("Can't find or process %s", path.c_str());
|
||||
free(buffer);
|
||||
DEBUG_FUNCTION_LINE_ERR("Can't find or process %s", path.c_str());
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
return {};
|
||||
}
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
auto destinations = std::make_unique<uint8_t *[]>(sec_num);
|
||||
if (!destinations) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array");
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
uint32_t totalSize = 0;
|
||||
|
||||
auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num);
|
||||
uint32_t text_size = 0;
|
||||
uint32_t data_size = 0;
|
||||
|
||||
if (!destinations) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc memory for destinations");
|
||||
free(buffer);
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
auto *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||
uint32_t sectionSize = psec->get_size();
|
||||
auto address = (uint32_t) psec->get_address();
|
||||
if ((address >= 0x02000000) && address < 0x10000000) {
|
||||
text_size += sectionSize;
|
||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||
data_size += sectionSize;
|
||||
}
|
||||
if (psec->get_name().rfind(".wums.", 0) == 0) {
|
||||
data_size += sectionSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t baseOffset = *destination_address_ptr;
|
||||
auto data = std::make_unique<uint8_t[]>(text_size + data_size);
|
||||
if (!data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t offset_text = baseOffset;
|
||||
uint32_t offset_data = offset_text;
|
||||
DEBUG_FUNCTION_LINE("Allocated %d kb", (text_size + data_size) / 1024);
|
||||
|
||||
uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000;
|
||||
void *text_data = data.get();
|
||||
void *data_data = (void *) ((uint32_t) data.get() + text_size);
|
||||
auto baseOffset = (uint32_t) data.get();
|
||||
|
||||
uint32_t totalSize = 0;
|
||||
uint32_t endAddress = 0;
|
||||
uint32_t entrypoint = (uint32_t) text_data + (uint32_t) reader.get_entry() - 0x02000000;
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
@ -75,12 +107,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
uint32_t sectionSize = psec->get_size();
|
||||
|
||||
totalSize += sectionSize;
|
||||
if (totalSize > maximum_size) {
|
||||
DEBUG_FUNCTION_LINE("Couldn't load setup module because it's too big.");
|
||||
free(destinations);
|
||||
free(buffer);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto address = (uint32_t) psec->get_address();
|
||||
|
||||
@ -91,7 +117,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
destination -= 0x02000000;
|
||||
destinations[psec->get_index()] -= 0x02000000;
|
||||
baseOffset += sectionSize;
|
||||
offset_data += sectionSize;
|
||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||
destination -= 0x10000000;
|
||||
destinations[psec->get_index()] -= 0x10000000;
|
||||
@ -99,9 +124,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
destination -= 0xC0000000;
|
||||
destinations[psec->get_index()] -= 0xC0000000;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Unhandled case");
|
||||
free(destinations);
|
||||
free(buffer);
|
||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@ -115,10 +139,10 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
memcpy((void *) destination, p, sectionSize);
|
||||
}
|
||||
|
||||
//nextAddress = ROUNDUP(destination + sectionSize, 0x100);
|
||||
if (psec->get_name() == ".bss") {
|
||||
moduleData->setBSSLocation(destination, sectionSize);
|
||||
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
|
||||
|
||||
} else if (psec->get_name() == ".sbss") {
|
||||
moduleData->setSBSSLocation(destination, sectionSize);
|
||||
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
|
||||
@ -127,10 +151,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
moduleData->addSectionInfo(sectionInfo);
|
||||
DEBUG_FUNCTION_LINE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
|
||||
|
||||
if (endAddress < destination + sectionSize) {
|
||||
endAddress = destination + sectionSize;
|
||||
}
|
||||
|
||||
DCFlushRange((void *) destination, sectionSize);
|
||||
ICInvalidateRange((void *) destination, sectionSize);
|
||||
}
|
||||
@ -140,19 +160,14 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
section *psec = reader.sections[i];
|
||||
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());
|
||||
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) {
|
||||
DEBUG_FUNCTION_LINE("elfLink failed");
|
||||
free(destinations);
|
||||
free(buffer);
|
||||
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data, (uint32_t) data_data, nullptr, 0)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto relocationData = getImportRelocationData(reader, destinations);
|
||||
|
||||
for (auto const &reloc : relocationData) {
|
||||
moduleData->addRelocationData(reloc);
|
||||
}
|
||||
getImportRelocationData(moduleData, reader, destinations.get());
|
||||
|
||||
auto secInfo = moduleData->getSectionInfo(".wums.exports");
|
||||
if (secInfo && secInfo.value()->getSize() > 0) {
|
||||
@ -161,9 +176,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
if (entries != nullptr) {
|
||||
for (size_t j = 0; j < entries_count; j++) {
|
||||
wums_entry_t *exp = &entries[j];
|
||||
DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X" /*,pluginData.getPluginInformation()->getName().c_str()*/, exp->type, exp->name, (void *) exp->address);
|
||||
auto exportData = std::make_shared<ExportData>(exp->type, exp->name, exp->address);
|
||||
moduleData->addExportData(exportData);
|
||||
DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X", exp->type, exp->name, exp->address);
|
||||
auto exportData = std::make_unique<ExportData>(exp->type, exp->name, exp->address);
|
||||
if (!exportData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc ExportData");
|
||||
}
|
||||
moduleData->addExportData(std::move(exportData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -175,9 +193,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
if (hooks != nullptr) {
|
||||
for (size_t j = 0; j < entries_count; j++) {
|
||||
wums_hook_t *hook = &hooks[j];
|
||||
DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X" /*,pluginData.getPluginInformation()->getName().c_str()*/, hook->type, hook->target);
|
||||
auto hookData = std::make_shared<HookData>(hook->type, hook->target);
|
||||
moduleData->addHookData(hookData);
|
||||
DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X", hook->type, hook->target);
|
||||
auto hookData = std::make_unique<HookData>(hook->type, hook->target);
|
||||
if (!hookData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc HookData");
|
||||
}
|
||||
moduleData->addHookData(std::move(hookData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,7 +222,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
std::string value(curEntry + firstFound + 1);
|
||||
|
||||
if (key == "export_name") {
|
||||
DEBUG_FUNCTION_LINE("export_name = %s", value.c_str());
|
||||
moduleData->setExportName(value);
|
||||
} else if (key == "skipInitFini") {
|
||||
if (value == "true") {
|
||||
@ -219,9 +239,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
}
|
||||
} else if (key == "wums") {
|
||||
if (value != "0.3") {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring module - Unsupported WUMS version: %s.\n", value.c_str());
|
||||
free(destinations);
|
||||
free(buffer);
|
||||
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring module - Unsupported WUMS version: %s.", value.c_str());
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
@ -231,9 +250,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
}
|
||||
}
|
||||
|
||||
char *strTable = (char *) endAddress;
|
||||
uint32_t strOffset = 0;
|
||||
|
||||
// Get the symbol for functions.
|
||||
Elf_Half n = reader.sections.size();
|
||||
for (Elf_Half i = 0; i < n; ++i) {
|
||||
@ -258,14 +274,13 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
if (!sectionOpt.has_value()) {
|
||||
continue;
|
||||
}
|
||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||
|
||||
uint32_t stringSize = name.size() + 1;
|
||||
memcpy(strTable + strOffset, name.c_str(), stringSize);
|
||||
moduleData->addFunctionSymbolData(std::make_shared<FunctionSymbolData>(strTable + strOffset, (void *) finalAddress, (uint32_t) size));
|
||||
strOffset += stringSize;
|
||||
totalSize += stringSize;
|
||||
endAddress += stringSize;
|
||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||
auto functionSymbolData = std::make_shared<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
|
||||
if (!functionSymbolData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc FunctionSymbolData");
|
||||
} else {
|
||||
moduleData->addFunctionSymbolData(std::move(functionSymbolData));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -274,41 +289,44 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||
}
|
||||
}
|
||||
|
||||
DCFlushRange((void *) *destination_address_ptr, totalSize);
|
||||
ICInvalidateRange((void *) *destination_address_ptr, totalSize);
|
||||
DCFlushRange((void *) text_data, text_size);
|
||||
ICInvalidateRange((void *) text_data, text_size);
|
||||
DCFlushRange((void *) data_data, data_size);
|
||||
ICInvalidateRange((void *) data_data, data_size);
|
||||
|
||||
free(destinations);
|
||||
free(buffer);
|
||||
if (totalSize > text_size + data_size) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We didn't allocate enough memory!!");
|
||||
OSFatal("We didn't allocate enough memory!!");
|
||||
}
|
||||
|
||||
moduleData->setDataPtr(std::move(data), totalSize);
|
||||
moduleData->setEntrypoint(entrypoint);
|
||||
moduleData->setStartAddress(*destination_address_ptr);
|
||||
moduleData->setEndAddress(endAddress);
|
||||
DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint);
|
||||
DEBUG_FUNCTION_LINE("Saved startAddress as %08X", *destination_address_ptr);
|
||||
DEBUG_FUNCTION_LINE("Saved endAddress as %08X", endAddress);
|
||||
DEBUG_FUNCTION_LINE("Saved startAddress as %08X", (uint32_t) data.get());
|
||||
DEBUG_FUNCTION_LINE("Saved endAddress as %08X", (uint32_t) data.get() + totalSize);
|
||||
|
||||
*destination_address_ptr = (*destination_address_ptr + totalSize + 0x100) & 0xFFFFFF00;
|
||||
DEBUG_FUNCTION_LINE("Loaded %s size: %d kilobytes", path.c_str(), totalSize / 1024);
|
||||
|
||||
MEMFreeToDefaultHeap(buffer);
|
||||
|
||||
return moduleData;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) {
|
||||
std::vector<std::shared_ptr<RelocationData>> result;
|
||||
std::map<uint32_t, std::string> infoMap;
|
||||
void ModuleDataFactory::getImportRelocationData(std::shared_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations) {
|
||||
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
|
||||
|
||||
uint32_t sec_num = reader.sections.size();
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
auto *psec = reader.sections[i];
|
||||
if (psec->get_type() == 0x80000002) {
|
||||
infoMap[i] = psec->get_name();
|
||||
infoMap[i] = std::make_shared<ImportRPLInformation>(psec->get_name());
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
|
||||
DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str());
|
||||
relocation_section_accessor rel(reader, psec);
|
||||
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
||||
Elf64_Addr offset;
|
||||
@ -319,30 +337,39 @@ std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocat
|
||||
Elf_Half sym_section_index;
|
||||
|
||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get relocation");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||
OSFatal("Failed to get relocation");
|
||||
break;
|
||||
}
|
||||
|
||||
// uint32_t adjusted_sym_value = (uint32_t) sym_value;
|
||||
if (infoMap.count(sym_section_index) == 0) {
|
||||
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||
if (adjusted_sym_value < 0xC0000000) {
|
||||
continue;
|
||||
}
|
||||
auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]);
|
||||
if (!rplInfo) {
|
||||
DEBUG_FUNCTION_LINE("Failed to create import information");
|
||||
break;
|
||||
}
|
||||
|
||||
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 = std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value());
|
||||
//relocationData->printInformation();
|
||||
result.push_back(relocationData);
|
||||
auto relocationData = std::make_unique<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");
|
||||
OSFatal("Failed to alloc relocation data");
|
||||
continue;
|
||||
}
|
||||
|
||||
moduleData->addRelocationData(std::move(relocationData));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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,
|
||||
@ -352,7 +379,7 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||
section *psec = reader.sections[i];
|
||||
if (psec->get_info() == section_index) {
|
||||
DEBUG_FUNCTION_LINE("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);
|
||||
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
||||
Elf64_Addr offset;
|
||||
@ -363,7 +390,8 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
||||
Elf_Half sym_section_index;
|
||||
|
||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to get relocation");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||
OSFatal("Failed to get relocation");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -380,23 +408,21 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
||||
} else if (adjusted_sym_value == 0x0) {
|
||||
//
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Unhandled case %08X", adjusted_sym_value);
|
||||
DEBUG_FUNCTION_LINE_ERR("Unhandled case %08X", adjusted_sym_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sym_section_index == SHN_ABS) {
|
||||
//
|
||||
} else if (sym_section_index > SHN_LORESERVE) {
|
||||
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED: %04X", sym_section_index);
|
||||
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)) {
|
||||
DEBUG_FUNCTION_LINE("Link failed");
|
||||
DEBUG_FUNCTION_LINE_ERR("Link failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("done");
|
||||
}
|
||||
}
|
||||
return true;
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2019 Maschell
|
||||
* Copyright (C) 2022 Maschell
|
||||
*
|
||||
* 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
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
#include "ModuleData.h"
|
||||
#include "elfio/elfio.hpp"
|
||||
#include <coreinit/memheap.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -26,11 +27,15 @@
|
||||
|
||||
class ModuleDataFactory {
|
||||
public:
|
||||
static std::optional<std::shared_ptr<ModuleData>>
|
||||
load(const std::string &path, uint32_t *destination_address_ptr, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length);
|
||||
static std::optional<std::shared_ptr<ModuleData>> load(const std::string &path);
|
||||
|
||||
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);
|
||||
|
||||
static std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations);
|
||||
static void getImportRelocationData(std::shared_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations);
|
||||
};
|
211
wumsloader/src/module/ModuleDataPersistence.cpp
Normal file
211
wumsloader/src/module/ModuleDataPersistence.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
#include "ModuleDataPersistence.h"
|
||||
#include "globals.h"
|
||||
#include <coreinit/cache.h>
|
||||
|
||||
bool ModuleDataPersistence::saveModuleData(module_information_t *moduleInformation, const std::vector<std::shared_ptr<ModuleData>> &moduleList) {
|
||||
auto module_data_list = std::make_unique<module_information_single_t[]>(moduleList.size());
|
||||
if (!module_data_list) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory to persist module data");
|
||||
return false;
|
||||
}
|
||||
|
||||
moduleInformation->modules = module_data_list.get();
|
||||
|
||||
uint32_t i = 0;
|
||||
for (auto &module : moduleList) {
|
||||
auto &module_data = module_data_list[i];
|
||||
module_data = {};
|
||||
if (!saveModuleData(module_data, module)) {
|
||||
module->relocationDataStruct.reset();
|
||||
module->hookDataStruct.reset();
|
||||
module->exportDataStruct.reset();
|
||||
module->functionSymbolDataStruct.reset();
|
||||
module->rplDataStruct.reset();
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to persist data for module. No memory?");
|
||||
OSFatal("Failed to persist data for module. No memory?");
|
||||
continue;
|
||||
} else {
|
||||
moduleInformation->number_modules++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
gModuleDataInfo = std::move(module_data_list);
|
||||
OSMemoryBarrier();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleDataPersistence::saveModuleData(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
|
||||
if (!saveRelocationDataForModule(module_data, module)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store relocation data of module");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!saveHookDataForModule(module_data, module)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store hook data of module");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!saveExportDataForModule(module_data, module)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store export data of module");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!saveFunctionSymbolDataForModule(module_data, module)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to store function symbol data of module");
|
||||
return false;
|
||||
}
|
||||
|
||||
module_data.module_export_name = (char *) module->getExportName().c_str();
|
||||
|
||||
module_data.bssAddr = module->getBSSAddress();
|
||||
module_data.bssSize = module->getBSSSize();
|
||||
module_data.sbssAddr = module->getSBSSAddress();
|
||||
module_data.sbssSize = module->getSBSSSize();
|
||||
module_data.startAddress = module->getStartAddress();
|
||||
module_data.endAddress = module->getEndAddress();
|
||||
module_data.entrypoint = module->getEntrypoint();
|
||||
module_data.skipInitFini = module->isSkipInitFini();
|
||||
module_data.initBeforeRelocationDoneHook = module->isInitBeforeRelocationDoneHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleDataPersistence::saveFunctionSymbolDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
|
||||
uint32_t entryCount = module->getFunctionSymbolDataList().size();
|
||||
auto function_symbol_data = std::make_unique<module_function_symbol_data_t[]>(entryCount);
|
||||
if (!function_symbol_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the function symbol data.");
|
||||
return false;
|
||||
}
|
||||
uint32_t i = 0;
|
||||
for (auto &curFuncSym : module->getFunctionSymbolDataList()) {
|
||||
if (i >= entryCount) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
|
||||
OSFatal("We tried to write more entries than we have space for.");
|
||||
}
|
||||
function_symbol_data[i].address = curFuncSym->getAddress();
|
||||
function_symbol_data[i].name = (char *) curFuncSym->getName().c_str();
|
||||
function_symbol_data[i].size = curFuncSym->getSize();
|
||||
i++;
|
||||
}
|
||||
module_data.function_symbol_entries = function_symbol_data.get();
|
||||
module_data.number_function_symbols = i;
|
||||
|
||||
module->functionSymbolDataStruct = std::move(function_symbol_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleDataPersistence::saveExportDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
|
||||
auto export_data = std::make_unique<export_data_t[]>(module->getExportDataList().size());
|
||||
if (!export_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the export data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t exportCount = 0;
|
||||
for (auto const &export_ : module->getExportDataList()) {
|
||||
if (exportCount >= module->getExportDataList().size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
|
||||
OSFatal("We tried to write more entries than we have space for.");
|
||||
}
|
||||
auto *curExport = &export_data[exportCount++];
|
||||
curExport->type = export_->getType();
|
||||
curExport->name = export_->getName().c_str();
|
||||
curExport->address = (uint32_t) export_->getAddress();
|
||||
}
|
||||
module_data.export_entries = export_data.get();
|
||||
module_data.number_export_entries = exportCount;
|
||||
|
||||
module->exportDataStruct = std::move(export_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleDataPersistence::saveHookDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
|
||||
auto hook_data = std::make_unique<hook_data_t[]>(module->getHookDataList().size());
|
||||
if (!hook_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the hook data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t hookCount = 0;
|
||||
for (auto const &hook : module->getHookDataList()) {
|
||||
if (hookCount >= module->getHookDataList().size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
|
||||
OSFatal("We tried to write more entries than we have space for.");
|
||||
}
|
||||
auto *curHook = &hook_data[hookCount++];
|
||||
curHook->type = hook->getType();
|
||||
curHook->target = (uint32_t) hook->getTarget();
|
||||
}
|
||||
module_data.hook_entries = hook_data.get();
|
||||
module_data.number_hook_entries = hookCount;
|
||||
|
||||
module->hookDataStruct = std::move(hook_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleDataPersistence::saveRelocationDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module) {
|
||||
auto relocation_data = std::make_unique<dyn_linking_relocation_entry_t[]>(module->getRelocationDataList().size());
|
||||
if (!relocation_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the relocation data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine how many dyn_linking_import_t entries we need.
|
||||
std::set<std::string_view> rplInfoCountSet;
|
||||
for (auto const &reloc : module->getRelocationDataList()) {
|
||||
rplInfoCountSet.insert(reloc->getImportRPLInformation()->getName());
|
||||
}
|
||||
|
||||
uint32_t rplInfoTotalCount = rplInfoCountSet.size();
|
||||
rplInfoCountSet.clear();
|
||||
|
||||
auto rpl_data = std::make_unique<dyn_linking_import_t[]>(rplInfoTotalCount);
|
||||
if (!rpl_data) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the RPLInfos.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t relocationCount = 0;
|
||||
uint32_t rplInfoCount = 0;
|
||||
std::map<std::string_view, dyn_linking_import_t *> rplInfoMap;
|
||||
for (auto const &reloc : module->getRelocationDataList()) {
|
||||
if (relocationCount >= module->getRelocationDataList().size()) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
|
||||
OSFatal("We tried to write more entries than we have space for.");
|
||||
}
|
||||
auto *curReloc = &relocation_data[relocationCount++];
|
||||
curReloc->destination = reloc->getDestination();
|
||||
curReloc->offset = reloc->getOffset();
|
||||
curReloc->addend = reloc->getAddend();
|
||||
curReloc->type = reloc->getType();
|
||||
curReloc->functionName = reloc->getName().c_str();
|
||||
auto &rplInfo = reloc->getImportRPLInformation();
|
||||
|
||||
auto rplIt = rplInfoMap.find(rplInfo->getName());
|
||||
if (rplIt != rplInfoMap.end()) {
|
||||
curReloc->importEntry = rplIt->second;
|
||||
} else {
|
||||
if (rplInfoCount >= rplInfoTotalCount) {
|
||||
DEBUG_FUNCTION_LINE_ERR("We tried to write more entries than we have space for.");
|
||||
OSFatal("We tried to write more entries than we have space for.");
|
||||
}
|
||||
auto *rplInfoPtr = &rpl_data[rplInfoCount++];
|
||||
rplInfoPtr->isData = rplInfo->isData();
|
||||
rplInfoPtr->importName = rplInfo->getName().c_str();
|
||||
rplInfoMap[rplInfo->getName()] = rplInfoPtr;
|
||||
curReloc->importEntry = rplInfoPtr;
|
||||
}
|
||||
}
|
||||
module_data.linking_entries = relocation_data.get();
|
||||
module_data.number_linking_entries = relocationCount;
|
||||
|
||||
module->relocationDataStruct = std::move(relocation_data);
|
||||
module->rplDataStruct = std::move(rpl_data);
|
||||
|
||||
return true;
|
||||
}
|
15
wumsloader/src/module/ModuleDataPersistence.h
Normal file
15
wumsloader/src/module/ModuleDataPersistence.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModuleData.h"
|
||||
#include <coreinit/memheap.h>
|
||||
#include <wums.h>
|
||||
|
||||
class ModuleDataPersistence {
|
||||
public:
|
||||
static bool saveModuleData(module_information_t *moduleInformation, const std::vector<std::shared_ptr<ModuleData>> &moduleList);
|
||||
static bool saveModuleData(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
|
||||
static bool saveRelocationDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
|
||||
static bool saveExportDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
|
||||
static bool saveHookDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
|
||||
static bool saveFunctionSymbolDataForModule(module_information_single_t &module_data, const std::shared_ptr<ModuleData> &module);
|
||||
};
|
@ -51,16 +51,14 @@ public:
|
||||
return destination;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getName() const {
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ImportRPLInformation> getImportRPLInformation() const {
|
||||
[[nodiscard]] const std::shared_ptr<ImportRPLInformation> &getImportRPLInformation() const {
|
||||
return rplInfo;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string toString() const;
|
||||
|
||||
private:
|
||||
char type;
|
||||
size_t offset;
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2019 Maschell
|
||||
* Copyright (C) 2022 Maschell
|
||||
*
|
||||
* 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
|
||||
@ -30,14 +30,10 @@ public:
|
||||
|
||||
SectionInfo() = default;
|
||||
|
||||
SectionInfo(const SectionInfo &o2) : name(o2.name),
|
||||
address(o2.address),
|
||||
sectionSize(o2.sectionSize) {
|
||||
}
|
||||
SectionInfo(const SectionInfo &o2) = default;
|
||||
|
||||
SectionInfo &operator=(const SectionInfo &other) = default;
|
||||
|
||||
|
||||
virtual ~SectionInfo() = default;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
@ -1,4 +1,5 @@
|
||||
#include <coreinit/cache.h>
|
||||
#include <valarray>
|
||||
|
||||
#include "ElfUtils.h"
|
||||
#include "utils/logger.h"
|
||||
@ -9,6 +10,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
if (type == R_PPC_NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto target = destination + offset;
|
||||
auto value = symbol_addr + addend;
|
||||
|
||||
@ -30,7 +32,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);
|
||||
break;
|
||||
case R_PPC_DTPMOD32:
|
||||
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
|
||||
DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME");
|
||||
//*((int32_t *)(target)) = tlsModuleIndex;
|
||||
break;
|
||||
case R_PPC_DTPREL32:
|
||||
@ -48,18 +50,18 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
case R_PPC_REL14: {
|
||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
if (distance > 0x7FFC || distance < -0x7FFC) {
|
||||
DEBUG_FUNCTION_LINE("***14-bit relative branch cannot hit target.");
|
||||
DEBUG_FUNCTION_LINE_ERR("***14-bit relative branch cannot hit target.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance & 3) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
|
||||
(distance < 0 && ((distance & 0xFFFF8000) != 0xFFFF8000))) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 17 bits before shift must all be the same.", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -74,8 +76,8 @@ 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);
|
||||
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
||||
if (trampoline_data == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
||||
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", value, target, distance);
|
||||
return false;
|
||||
} else {
|
||||
relocation_trampoline_entry_t *freeSlot = nullptr;
|
||||
@ -93,14 +95,20 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
}
|
||||
}
|
||||
if (freeSlot == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
||||
|
||||
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", value, target, target - (uint32_t) & (freeSlot->trampoline[0]));
|
||||
return false;
|
||||
}
|
||||
if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) {
|
||||
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
|
||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
||||
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).");
|
||||
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;
|
||||
}
|
||||
|
||||
@ -117,24 +125,22 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
// Relocations for the imports may be overridden
|
||||
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
||||
}
|
||||
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
||||
value = symbolValue + addend;
|
||||
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||
distance = newDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (distance & 3) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: lower 2 bits must be zero before shifting.", -470022);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (1).", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (distance >= 0 && (distance & 0xFE000000)) {
|
||||
DEBUG_FUNCTION_LINE("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
|
||||
DEBUG_FUNCTION_LINE_ERR("***RELOC ERROR %d: upper 7 bits before shift must all be the same (0).", -470040);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -142,8 +148,10 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||
DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||
return false;
|
||||
}
|
||||
ICInvalidateRange(reinterpret_cast<void *>(target), 4);
|
||||
DCFlushRange(reinterpret_cast<void *>(target), 4);
|
||||
return true;
|
||||
}
|
102
wumsloader/src/utils/RelocationUtils.cpp
Normal file
102
wumsloader/src/utils/RelocationUtils.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include "RelocationUtils.h"
|
||||
#include "globals.h"
|
||||
#include "utils/ElfUtils.h"
|
||||
#include "utils/memory.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/dynload.h>
|
||||
|
||||
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules, bool skipMemoryMappingModule) {
|
||||
bool wasSuccessful = true;
|
||||
|
||||
for (auto &curModule : loadedModules) {
|
||||
DEBUG_FUNCTION_LINE("Let's do the relocations for %s", curModule->getExportName().c_str());
|
||||
|
||||
auto &relocData = curModule->getRelocationDataList();
|
||||
|
||||
// On first usage we can't redirect the alloc functions to our custom heap
|
||||
// because threads can't run it on it. In order to patch the kernel
|
||||
// to fully support our memory region, we have to run the MemoryMapping once with the default heap.
|
||||
// Afterwards we can just rely on the custom heap.
|
||||
bool skipAllocFunction = skipMemoryMappingModule && (std::string_view(curModule->getExportName()) == "homebrew_memorymapping");
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Skip alloc replace? %d", skipAllocFunction);
|
||||
if (!doRelocation(gLoadedModules, relocData, nullptr, 0, skipAllocFunction)) {
|
||||
wasSuccessful = false;
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to do Relocations for %s", curModule->getExportName().c_str());
|
||||
OSFatal("Failed to do Reloations");
|
||||
}
|
||||
}
|
||||
DCFlushRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
|
||||
ICInvalidateRange((void *) MEMORY_REGION_START, MEMORY_REGION_SIZE);
|
||||
return wasSuccessful;
|
||||
}
|
||||
|
||||
|
||||
bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
|
||||
const std::vector<std::unique_ptr<RelocationData>> &relocData,
|
||||
relocation_trampoline_entry_t *tramp_data,
|
||||
uint32_t tramp_length,
|
||||
bool skipAllocReplacement) {
|
||||
std::map<std::string, OSDynLoad_Module> moduleCache;
|
||||
for (auto const &curReloc : relocData) {
|
||||
auto &functionName = curReloc->getName();
|
||||
std::string rplName = curReloc->getImportRPLInformation()->getRPLName();
|
||||
uint32_t functionAddress = 0;
|
||||
|
||||
for (auto &module : moduleList) {
|
||||
if (rplName == module->getExportName()) {
|
||||
for (auto &exportData : module->getExportDataList()) {
|
||||
if (functionName == exportData->getName()) {
|
||||
functionAddress = (uint32_t) exportData->getAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipAllocReplacement) {
|
||||
if (functionName == "MEMAllocFromDefaultHeap") {
|
||||
functionAddress = reinterpret_cast<uint32_t>(&MEMAlloc);
|
||||
} else if (functionName == "MEMAllocFromDefaultHeapEx") {
|
||||
functionAddress = reinterpret_cast<uint32_t>(&MEMAllocEx);
|
||||
} else if (functionName == "MEMFreeToDefaultHeap") {
|
||||
functionAddress = reinterpret_cast<uint32_t>(&MEMFree);
|
||||
}
|
||||
}
|
||||
|
||||
if (functionAddress == 0) {
|
||||
int32_t isData = curReloc->getImportRPLInformation()->isData();
|
||||
OSDynLoad_Module rplHandle = nullptr;
|
||||
if (moduleCache.count(rplName) == 0) {
|
||||
OSDynLoad_Error err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle);
|
||||
if (err != OS_DYNLOAD_OK || rplHandle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s is not yet loaded", rplName.c_str());
|
||||
// only acquire if not already loaded.
|
||||
err = OSDynLoad_Acquire(rplName.c_str(), &rplHandle);
|
||||
if (err != OS_DYNLOAD_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to acquire %s", rplName.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
moduleCache[rplName] = rplHandle;
|
||||
}
|
||||
rplHandle = moduleCache.at(rplName);
|
||||
|
||||
OSDynLoad_FindExport(rplHandle, isData, functionName.c_str(), (void **) &functionAddress);
|
||||
if (functionAddress == 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to find export %s of %s", functionName.begin(), rplName.c_str());
|
||||
OSFatal("Failed to find export");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (tramp_data != nullptr) {
|
||||
DCFlushRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
ICInvalidateRange(tramp_data, tramp_length * sizeof(relocation_trampoline_entry_t));
|
||||
}
|
||||
return true;
|
||||
}
|
12
wumsloader/src/utils/RelocationUtils.h
Normal file
12
wumsloader/src/utils/RelocationUtils.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "module/ModuleData.h"
|
||||
#include <vector>
|
||||
|
||||
bool ResolveRelocations(std::vector<std::shared_ptr<ModuleData>> &loadedModules,
|
||||
bool skipMemoryMappingModule);
|
||||
|
||||
bool doRelocation(const std::vector<std::shared_ptr<ModuleData>> &moduleList,
|
||||
const std::vector<std::unique_ptr<RelocationData>> &relocData,
|
||||
relocation_trampoline_entry_t *tramp_data,
|
||||
uint32_t tramp_length,
|
||||
bool skipAllocReplacement);
|
51
wumsloader/src/utils/StringTools.cpp
Normal file
51
wumsloader/src/utils/StringTools.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <utils/StringTools.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||
if (!string || !compare)
|
||||
return -1;
|
||||
|
||||
char TokCopy[512];
|
||||
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||
TokCopy[511] = '\0';
|
||||
|
||||
char *strTok = strtok(TokCopy, separator);
|
||||
|
||||
while (strTok != nullptr) {
|
||||
if (strcasecmp(string, strTok) == 0) {
|
||||
return 0;
|
||||
}
|
||||
strTok = strtok(nullptr, separator);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
@ -23,42 +23,55 @@
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#ifndef __STRING_TOOLS_H
|
||||
#define __STRING_TOOLS_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wut_types.h>
|
||||
|
||||
template<typename... Args>
|
||||
std::string string_format(const std::string &format, Args... args) {
|
||||
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
||||
auto size = static_cast<size_t>(size_s);
|
||||
auto buf = std::make_unique<char[]>(size);
|
||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
|
||||
|
||||
class StringTools {
|
||||
public:
|
||||
static BOOL EndsWith(const std::string &a, const std::string &b);
|
||||
|
||||
static const char *byte_to_binary(int32_t x);
|
||||
|
||||
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
||||
|
||||
static const char *fmt(const char *format, ...);
|
||||
|
||||
static const wchar_t *wfmt(const char *format, ...);
|
||||
|
||||
static int32_t strprintf(std::string &str, const char *format, ...);
|
||||
|
||||
static std::string strfmt(const char *format, ...);
|
||||
|
||||
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
||||
|
||||
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||
|
||||
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
||||
|
||||
static char *str_replace(char *orig, char *rep, char *with);
|
||||
static const char *FullpathToFilename(const char *path) {
|
||||
if (!path)
|
||||
return path;
|
||||
|
||||
static const char *FullpathToFilename(const char *path);
|
||||
const char *ptr = path;
|
||||
const char *Filename = ptr;
|
||||
|
||||
static void RemoveDoubleSlashs(std::string &str);
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||
Filename = ptr + 1;
|
||||
|
||||
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
||||
};
|
||||
++ptr;
|
||||
}
|
||||
|
||||
#endif /* __STRING_TOOLS_H */
|
||||
return Filename;
|
||||
}
|
||||
|
||||
static void RemoveDoubleSlashs(std::string &str) {
|
||||
uint32_t length = str.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
for (uint32_t i = 1; i < length; ++i) {
|
||||
if (str[i - 1] == '/' && str[i] == '/') {
|
||||
str.erase(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -21,6 +21,11 @@
|
||||
} while (0)
|
||||
#define IMPORT_END()
|
||||
|
||||
#define EXPORT_VAR(type, var) type var __attribute__((section(".data")));
|
||||
|
||||
EXPORT_VAR(uint32_t *, MEMAllocFromDefaultHeap);
|
||||
EXPORT_VAR(uint32_t *, MEMAllocFromDefaultHeapEx);
|
||||
EXPORT_VAR(uint32_t *, MEMFreeToDefaultHeap);
|
||||
|
||||
void InitFunctionPointers(void) {
|
||||
OSDynLoad_Module handle;
|
||||
@ -28,5 +33,16 @@ void InitFunctionPointers(void) {
|
||||
addr_OSDynLoad_FindExport = (void *) 0x0102B828; // 0200f428 - 0xFE3C00
|
||||
addr_OSDynLoad_IsModuleLoaded = (void *) 0x0102A59C; // 0200e19c - 0xFE3C00
|
||||
|
||||
OSDynLoad_Acquire("coreinit.rpl", &handle);
|
||||
|
||||
uint32_t **value = 0;
|
||||
OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeap", (void **) &value);
|
||||
MEMAllocFromDefaultHeap = *value;
|
||||
OSDynLoad_FindExport(handle, 1, "MEMAllocFromDefaultHeapEx", (void **) &value);
|
||||
MEMAllocFromDefaultHeapEx = *value;
|
||||
OSDynLoad_FindExport(handle, 1, "MEMFreeToDefaultHeap", (void **) &value);
|
||||
MEMFreeToDefaultHeap = *value;
|
||||
#include "imports.h"
|
||||
// override failed __rplwrap_exit find export
|
||||
OSDynLoad_FindExport(handle, 0, "exit", (void **) &addr___rplwrap_exit);
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
#include "hooks.h"
|
||||
#include "globals.h"
|
||||
#include "module/ModuleData.h"
|
||||
#include "utils/logger.h"
|
||||
#include <memory>
|
||||
#include <wums.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
static const char **hook_names = (const char *[]){
|
||||
"WUMS_HOOK_INIT_WUT_MALLOC",
|
||||
"WUMS_HOOK_FINI_WUT_MALLOC",
|
||||
@ -22,36 +26,32 @@ static const char **hook_names = (const char *[]){
|
||||
"WUMS_HOOK_APPLICATION_ENDS",
|
||||
"WUMS_HOOK_RELOCATIONS_DONE",
|
||||
"WUMS_HOOK_APPLICATION_REQUESTS_EXIT"};
|
||||
#endif
|
||||
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type, bool condition) {
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type, bool condition) {
|
||||
if (condition) {
|
||||
CallHook(modules, type);
|
||||
}
|
||||
}
|
||||
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] for all modules\n", hook_names[type], type);
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type) {
|
||||
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] for all modules", hook_names[type], type);
|
||||
for (auto &curModule : modules) {
|
||||
CallHook(curModule, type);
|
||||
}
|
||||
}
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type, bool condition) {
|
||||
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type, bool condition) {
|
||||
if (condition) {
|
||||
CallHook(module, type);
|
||||
}
|
||||
}
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type) {
|
||||
if (!module->relocationsDone) {
|
||||
DEBUG_FUNCTION_LINE("Hook not called because the relocations failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type) {
|
||||
for (auto &curHook : module->getHookDataList()) {
|
||||
auto func_ptr = (uint32_t) curHook->getTarget();
|
||||
if (func_ptr == 0) {
|
||||
DEBUG_FUNCTION_LINE("Hook ptr was NULL\n");
|
||||
DEBUG_FUNCTION_LINE_ERR("Module %s: hook ptr was NULL", module->getExportName().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -70,19 +70,19 @@ void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t
|
||||
type == WUMS_HOOK_FINI_WUT_SOCKETS ||
|
||||
type == WUMS_HOOK_INIT_WRAPPER ||
|
||||
type == WUMS_HOOK_FINI_WRAPPER)) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] %d for %s: %08X\n", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
|
||||
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] %d for %s: %08X", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
|
||||
((void (*)())((uint32_t *) func_ptr))();
|
||||
break;
|
||||
} else if (type == WUMS_HOOK_INIT ||
|
||||
type == WUMS_HOOK_RELOCATIONS_DONE) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] %d for %s: %08X\n", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
|
||||
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] %d for %s: %08X", hook_names[type], type, curHook->getType(), module->getExportName().c_str(), curHook->getTarget());
|
||||
wums_app_init_args_t args;
|
||||
args.module_information = gModuleData;
|
||||
args.module_information = &gModuleInformation;
|
||||
((void (*)(wums_app_init_args_t *))((uint32_t *) func_ptr))(&args);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("#########################################\n");
|
||||
DEBUG_FUNCTION_LINE("#########HOOK NOT IMPLEMENTED %d#########\n", type);
|
||||
DEBUG_FUNCTION_LINE("#########################################\n");
|
||||
DEBUG_FUNCTION_LINE_ERR("#########################################");
|
||||
DEBUG_FUNCTION_LINE_ERR("#########HOOK NOT IMPLEMENTED %d#########", type);
|
||||
DEBUG_FUNCTION_LINE_ERR("#########################################");
|
||||
}
|
||||
break;
|
||||
}
|
14
wumsloader/src/utils/hooks.h
Normal file
14
wumsloader/src/utils/hooks.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "module/ModuleData.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <wums.h>
|
||||
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type, bool condition);
|
||||
|
||||
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type);
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type, bool condition);
|
||||
|
||||
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type);
|
@ -18,6 +18,53 @@ IMPORT(MEMCreateExpHeapEx);
|
||||
IMPORT(OSUninterruptibleSpinLock_Acquire);
|
||||
IMPORT(OSUninterruptibleSpinLock_Release);
|
||||
IMPORT(OSReport);
|
||||
IMPORT(MEMGetTotalFreeSizeForExpHeap);
|
||||
IMPORT(OSMemoryBarrier);
|
||||
IMPORT(OSInitMutex);
|
||||
IMPORT(OSLockMutex);
|
||||
IMPORT(OSUnlockMutex);
|
||||
IMPORT(OSCompareAndSwapAtomicEx);
|
||||
IMPORT(OSCompareAndSwapAtomic);
|
||||
IMPORT(OSGetThreadSpecific);
|
||||
IMPORT(OSSetThreadSpecific);
|
||||
IMPORT(OSInitCond);
|
||||
IMPORT(OSWaitCond);
|
||||
IMPORT(OSSignalCond);
|
||||
IMPORT(MEMAllocFromDefaultHeapEx);
|
||||
IMPORT(MEMFreeToDefaultHeap);
|
||||
|
||||
IMPORT(FSTimeToCalendarTime);
|
||||
IMPORT(FSInit);
|
||||
IMPORT(FSShutdown);
|
||||
IMPORT(FSAddClient);
|
||||
IMPORT(FSAddClientEx);
|
||||
IMPORT(FSDelClient);
|
||||
IMPORT(FSInitCmdBlock);
|
||||
IMPORT(FSChangeDir);
|
||||
IMPORT(FSGetFreeSpaceSize);
|
||||
IMPORT(FSGetStat);
|
||||
IMPORT(FSRemove);
|
||||
IMPORT(FSOpenFile);
|
||||
IMPORT(FSCloseFile);
|
||||
IMPORT(FSOpenDir);
|
||||
IMPORT(FSMakeDir);
|
||||
IMPORT(FSReadDir);
|
||||
IMPORT(FSRewindDir);
|
||||
IMPORT(FSCloseDir);
|
||||
IMPORT(FSGetStatFile);
|
||||
IMPORT(FSReadFile);
|
||||
IMPORT(FSWriteFile);
|
||||
IMPORT(FSSetPosFile);
|
||||
IMPORT(FSFlushFile);
|
||||
IMPORT(FSTruncateFile);
|
||||
IMPORT(FSRename);
|
||||
IMPORT(FSGetMountSource);
|
||||
IMPORT(FSMount);
|
||||
IMPORT(FSUnmount);
|
||||
IMPORT(FSChangeMode);
|
||||
IMPORT(FSGetPosFile);
|
||||
IMPORT(OSTicksToCalendarTime);
|
||||
IMPORT(__rplwrap_exit);
|
||||
|
||||
IMPORT_END();
|
||||
|
38
wumsloader/src/utils/logger.c
Normal file
38
wumsloader/src/utils/logger.c
Normal file
@ -0,0 +1,38 @@
|
||||
#ifdef DEBUG
|
||||
#include <nsysnet/_socket.h>
|
||||
#include <stdint.h>
|
||||
#include <whb/log_cafe.h>
|
||||
#include <whb/log_module.h>
|
||||
#include <whb/log_udp.h>
|
||||
|
||||
uint32_t moduleLogInit = false;
|
||||
uint32_t cafeLogInit = false;
|
||||
uint32_t udpLogInit = false;
|
||||
#endif // DEBUG
|
||||
|
||||
void initLogging() {
|
||||
#ifdef DEBUG
|
||||
if (!(moduleLogInit = WHBLogModuleInit())) {
|
||||
socket_lib_init();
|
||||
cafeLogInit = WHBLogCafeInit();
|
||||
udpLogInit = WHBLogUdpInit();
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
void deinitLogging() {
|
||||
#ifdef DEBUG
|
||||
if (moduleLogInit) {
|
||||
WHBLogModuleDeinit();
|
||||
moduleLogInit = false;
|
||||
}
|
||||
if (cafeLogInit) {
|
||||
WHBLogCafeDeinit();
|
||||
cafeLogInit = false;
|
||||
}
|
||||
if (udpLogInit) {
|
||||
WHBLogUdpDeinit();
|
||||
udpLogInit = false;
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
57
wumsloader/src/utils/logger.h
Normal file
57
wumsloader/src/utils/logger.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_APP_TYPE "M"
|
||||
#define LOG_APP_NAME "WUMSLoader"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX(LOG_FUNC, "", "", FMT, ##ARGS)
|
||||
|
||||
#define LOG_EX(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
|
||||
do { \
|
||||
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
#else
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
#endif
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||
|
||||
#endif
|
||||
|
||||
void initLogging();
|
||||
|
||||
void deinitLogging();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -15,13 +15,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
#include "logger.h"
|
||||
#include <cerrno>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memdefaultheap.h>
|
||||
#include <coreinit/memexpheap.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
#include <errno.h>
|
||||
#include <cstring>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
extern MEMHeapHandle gHeapHandle;
|
||||
|
||||
@ -32,11 +32,10 @@ void *MEMAllocSafe(uint32_t size, uint32_t align) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void *MemoryAlloc(uint32_t size) {
|
||||
void *res = MEMAllocSafe(size, 4);
|
||||
if (res == nullptr) {
|
||||
OSFatal_printf("Failed to MemoryAlloc %d", size);
|
||||
OSFatal("Failed to MemoryAlloc");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -44,7 +43,7 @@ void *MemoryAlloc(uint32_t size) {
|
||||
void *MemoryAllocEx(uint32_t size, uint32_t align) {
|
||||
void *res = MEMAllocSafe(size, align);
|
||||
if (res == nullptr) {
|
||||
OSFatal_printf("Failed to MemoryAllocEX %d %d", size, align);
|
||||
OSFatal("Failed to MemoryAllocEX");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -53,7 +52,7 @@ void MemoryFree(void *ptr) {
|
||||
if (ptr) {
|
||||
MEMFreeToExpHeap(gHeapHandle, ptr);
|
||||
} else {
|
||||
OSFatal_printf("Failed to free");
|
||||
OSFatal("Failed to free");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user