Rewrite of the WUMSLoader to simplify the code and have more memory for modules
This commit is contained in:
parent
b247427427
commit
b1b99343d6
|
@ -12,7 +12,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: clang-format
|
- name: clang-format
|
||||||
run: |
|
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:
|
build-binary:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
needs: clang-format
|
needs: clang-format
|
||||||
|
|
|
@ -9,7 +9,18 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: clang-format
|
- name: clang-format
|
||||||
run: |
|
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:
|
build-binary:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
needs: clang-format
|
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
|
WORKDIR project
|
25
Makefile
25
Makefile
|
@ -31,7 +31,7 @@ INCLUDES := source
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
CFLAGS := -Wall -O2 -ffunction-sections \
|
CFLAGS := -Wall -Os -ffunction-sections \
|
||||||
$(MACHDEP)
|
$(MACHDEP)
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||||
|
@ -42,10 +42,17 @@ ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map)
|
LDFLAGS = -g $(ARCH) $(RPXSPECS) --entry=_start -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
ifeq ($(DEBUG),1)
|
ifeq ($(DEBUG),1)
|
||||||
|
export DEBUG=1
|
||||||
CXXFLAGS += -DDEBUG -g
|
CXXFLAGS += -DDEBUG -g
|
||||||
CFLAGS += -DDEBUG -g
|
CFLAGS += -DDEBUG -g
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DEBUG),VERBOSE)
|
||||||
|
export DEBUG=VERBOSE
|
||||||
|
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
|
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
|
endif
|
||||||
|
|
||||||
LIBS := -lwut -lz
|
LIBS := -lwut -lz
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
@ -91,7 +98,7 @@ endif
|
||||||
|
|
||||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
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 HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
@ -107,13 +114,13 @@ all: $(BUILD)
|
||||||
|
|
||||||
$(BUILD):
|
$(BUILD):
|
||||||
@[ -d $@ ] || mkdir -p $@
|
@[ -d $@ ] || mkdir -p $@
|
||||||
@$(MAKE) --no-print-directory -C relocator
|
@$(MAKE) --no-print-directory -C wumsloader
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
clean:
|
clean:
|
||||||
@echo clean ...
|
@echo clean ...
|
||||||
make clean -C relocator
|
make clean -C wumsloader
|
||||||
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
|
@rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
@ -126,16 +133,16 @@ DEPENDS := $(OFILES:.o=.d)
|
||||||
# main targets
|
# main targets
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
relocator_elf := ../relocator/relocator.elf
|
wumsloader_elf := ../wumsloader/wumsloader.elf
|
||||||
|
|
||||||
all : $(OUTPUT).rpx
|
all : $(OUTPUT).rpx
|
||||||
|
|
||||||
$(relocator_elf):
|
$(wumsloader_elf):
|
||||||
make -C ../relocator
|
make -C ../wumsloader
|
||||||
|
|
||||||
$(OUTPUT).rpx : $(OUTPUT).elf
|
$(OUTPUT).rpx : $(OUTPUT).elf
|
||||||
$(OUTPUT).elf : $(OFILES)
|
$(OUTPUT).elf : $(OFILES)
|
||||||
$(OFILES) : relocator_elf.h
|
$(OFILES) : wumsloader_elf.h
|
||||||
|
|
||||||
$(OFILES_SRC) : $(HFILES_BIN)
|
$(OFILES_SRC) : $(HFILES_BIN)
|
||||||
|
|
||||||
|
@ -152,7 +159,7 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER)
|
@$(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
|
bin2s -a 32 -H `(echo $(<F) | tr . _)`.h $< | $(AS) -o $(<F).o
|
||||||
|
|
||||||
-include $(DEPENDS)
|
-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/`.
|
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
|
## 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:
|
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
|
## 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
|
## Credits
|
||||||
- maschell
|
- Maschell
|
||||||
- Copy paste stuff from dimok
|
- 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 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)
|
- 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 "utils/logger.h"
|
||||||
#include <coreinit/cache.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) {
|
uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fileSize) {
|
||||||
ELFIO::Elf32_Ehdr *ehdr;
|
ELFIO::Elf32_Ehdr *ehdr;
|
||||||
|
@ -106,148 +59,3 @@ uint32_t load_loader_elf(unsigned char *baseAddress, char *elf_data, uint32_t fi
|
||||||
|
|
||||||
return ehdr->e_entry;
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <wums.h>
|
|
||||||
|
|
||||||
#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);
|
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 "kernel.h"
|
||||||
#include "ElfUtils.h"
|
#include "ElfUtils.h"
|
||||||
#include "relocator_elf.h"
|
#include "wumsloader_elf.h"
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/memorymap.h>
|
#include <coreinit/memorymap.h>
|
||||||
|
|
||||||
extern "C" void SCKernelCopyData(uint32_t addr, uint32_t src, uint32_t len);
|
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);
|
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_1 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||||
kern_write((void *) (KERN_SYSCALL_TBL_2 + (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_3 + (0x25 * 4)), (unsigned int) SCKernelCopyData);
|
||||||
kern_write((void *) (KERN_SYSCALL_TBL_4 + (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);
|
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;
|
unsigned int repl_addr = ADDRESS_main_entry_hook;
|
||||||
KernelWriteU32(repl_addr, 0x48000003 | entryPoint);
|
KernelWriteU32(repl_addr, 0x48000003 | entryPoint);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
#define ADDRESS_main_entry_hook 0x0101C56C
|
#define ADDRESS_main_entry_hook 0x0101C56C
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu
|
#define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu
|
||||||
#define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL)
|
#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);
|
void KernelWriteU32(uint32_t addr, uint32_t value);
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,26 @@
|
||||||
#include <cstring>
|
#include "../wumsloader/src/globals.h"
|
||||||
|
#include "kernel.h"
|
||||||
#include <elfio/elfio.hpp>
|
#include "utils/logger.h"
|
||||||
#include <nn/act/client_cpp.h>
|
#include <nn/act/client_cpp.h>
|
||||||
#include <sysapp/launch.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();
|
extern "C" void __fini();
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
initLogging();
|
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";
|
std::string basePath = "fs:/vol/external01/wiiu";
|
||||||
if (argc >= 1) {
|
if (argc >= 1) {
|
||||||
basePath = argv[0];
|
basePath = argv[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
DirList modules(basePath + "/modules", ".wms", DirList::Files, 1);
|
#pragma GCC diagnostic push
|
||||||
modules.SortList();
|
#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;
|
DEBUG_FUNCTION_LINE("Setup wumsloader");
|
||||||
for (int i = 0; i < modules.GetFilecount(); i++) {
|
SetupWUMSLoader();
|
||||||
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();
|
|
||||||
|
|
||||||
nn::act::Initialize();
|
nn::act::Initialize();
|
||||||
nn::act::SlotNo slot = nn::act::GetSlotNo();
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include <coreinit/debug.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <whb/log.h>
|
#include <whb/log.h>
|
||||||
|
|
||||||
|
@ -7,22 +8,33 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#define LOG_APP_TYPE "M"
|
||||||
|
#define LOG_APP_NAME "WUMSInstaller"
|
||||||
|
|
||||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
#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)
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||||
do { \
|
|
||||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
|
||||||
do { \
|
|
||||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -32,6 +44,8 @@ extern "C" {
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_WRITE(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
|
#endif
|
||||||
|
|
||||||
void initLogging();
|
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
|
export OBJCOPY := $(PREFIX)objcopy
|
||||||
|
|
||||||
WUMS_ROOT := $(DEVKITPRO)/wums
|
WUMS_ROOT := $(DEVKITPRO)/wums
|
||||||
|
WUT_ROOT := $(DEVKITPRO)/wut
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# TARGET is the name of the output
|
# TARGET is the name of the output
|
||||||
|
@ -30,10 +31,14 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
||||||
# SOURCES is a list of directories containing source code
|
# SOURCES is a list of directories containing source code
|
||||||
# INCLUDES is a list of directories containing extra header files
|
# INCLUDES is a list of directories containing extra header files
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := relocator
|
TARGET := wumsloader
|
||||||
BUILD := build
|
BUILD := build
|
||||||
BUILD_DBG := $(TARGET)_dbg
|
BUILD_DBG := $(TARGET)_dbg
|
||||||
SOURCES := src src/utils src/kernel
|
SOURCES := src \
|
||||||
|
src/utils \
|
||||||
|
src/kernel \
|
||||||
|
src/fs \
|
||||||
|
src/module
|
||||||
|
|
||||||
DATA := data
|
DATA := data
|
||||||
|
|
||||||
|
@ -42,10 +47,22 @@ INCLUDES := src
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# 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
|
CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
|
||||||
ASFLAGS := -mregnames
|
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 := @
|
Q := @
|
||||||
|
@ -53,18 +70,13 @@ MAKEFLAGS += --no-print-directory
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# any extra libraries we wish to link with the project
|
# 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
|
# list of directories containing libraries, this must be the top level containing
|
||||||
# include and lib
|
# include and lib
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
LIBDIRS := $(CURDIR) \
|
LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUMS_ROOT)
|
||||||
$(DEVKITPPC)/lib \
|
|
||||||
$(DEVKITPRO)/wut \
|
|
||||||
$(WUMS_ROOT) \
|
|
||||||
$(DEVKITPPC)/lib/gcc/powerpc-eabi/$(GCC_VER)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# no real need to edit anything past this point unless you need to add additional
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
@ -105,14 +117,9 @@ export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
-I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \
|
-I$(CURDIR)/$(BUILD)
|
||||||
-I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
# build a list of library paths
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
|
|
||||||
-L$(LIBOGC_LIB) -L$(PORTLIBS)/lib
|
|
||||||
|
|
||||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
.PHONY: $(BUILD) clean install
|
.PHONY: $(BUILD) clean install
|
|
@ -1,5 +1,4 @@
|
||||||
# Setup payload - relocator
|
# WUMSLoader
|
||||||
This is a payload that is bundled with the SetupPayload that handled the relocations for the imports.
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
- maschell
|
- maschell
|
|
@ -270,7 +270,7 @@ class section_impl : public section
|
||||||
|
|
||||||
ret = inflate(&s, Z_FINISH);
|
ret = inflate(&s, Z_FINISH);
|
||||||
if (ret != Z_OK && ret != Z_STREAM_END){
|
if (ret != Z_OK && ret != Z_STREAM_END){
|
||||||
DEBUG_FUNCTION_LINE("NOOOO");
|
DEBUG_FUNCTION_LINE_ERR("inflate section failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
inflateEnd(&s);
|
inflateEnd(&s);
|
||||||
|
@ -288,7 +288,7 @@ class section_impl : public section
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
set_size(0);
|
set_size(0);
|
||||||
DEBUG_FUNCTION_LINE("Failed to allocate memory.");
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 <fcntl.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <stdint.h>
|
#include <string>
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
#define ROUNDDOWN(val, align) ((val) & ~(align - 1))
|
||||||
#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align)
|
#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
|
//! always initialze input
|
||||||
*inbuffer = NULL;
|
*inbuffer = nullptr;
|
||||||
if (size) {
|
if (size) {
|
||||||
*size = 0;
|
*size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t iFd = open(filepath, O_RDONLY);
|
int32_t iFd = open(filepath.c_str(), O_RDONLY);
|
||||||
if (iFd < 0) {
|
if (iFd < 0) {
|
||||||
return -1;
|
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);
|
uint32_t filesize = lseek(iFd, 0, SEEK_END);
|
||||||
lseek(iFd, 0, SEEK_SET);
|
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) {
|
if (buffer == nullptr) {
|
||||||
close(iFd);
|
close(iFd);
|
||||||
return -2;
|
return -2;
|
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int32_t LoadFileToMem(const std::string &filepath, uint8_t **inbuffer, uint32_t *size);
|
|
@ -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")));
|
|
@ -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)
|
|
@ -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 {
|
class ExportData {
|
||||||
|
|
||||||
public:
|
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->type = type;
|
||||||
this->name = name;
|
this->name = std::move(name);
|
||||||
this->address = address;
|
this->address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ public:
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::string getName() const {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ class FunctionSymbolData {
|
||||||
public:
|
public:
|
||||||
FunctionSymbolData(const FunctionSymbolData &o2) = default;
|
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),
|
address(address),
|
||||||
size(size) {
|
size(size) {
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@ public:
|
||||||
virtual ~FunctionSymbolData() = default;
|
virtual ~FunctionSymbolData() = default;
|
||||||
|
|
||||||
bool operator<(const FunctionSymbolData &rhs) const {
|
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;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +47,8 @@ public:
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *name;
|
std::string name;
|
||||||
void *address;
|
void *address;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
};
|
};
|
|
@ -18,6 +18,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include <coreinit/debug.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -26,44 +27,27 @@
|
||||||
class ImportRPLInformation {
|
class ImportRPLInformation {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ImportRPLInformation(std::string name, bool isData = false) {
|
explicit ImportRPLInformation(std::string rawSectionName) {
|
||||||
this->name = std::move(name);
|
this->name = std::move(rawSectionName);
|
||||||
this->_isData = isData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ImportRPLInformation() = default;
|
~ImportRPLInformation() = default;
|
||||||
|
|
||||||
static std::optional<std::shared_ptr<ImportRPLInformation>> createImportRPLInformation(std::string rawSectionName) {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
std::string fimport = ".fimport_";
|
|
||||||
std::string dimport = ".dimport_";
|
|
||||||
|
|
||||||
bool data = false;
|
|
||||||
|
|
||||||
std::string rplName;
|
|
||||||
|
|
||||||
if (rawSectionName.size() < fimport.size()) {
|
|
||||||
return std::nullopt;
|
|
||||||
} else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) {
|
|
||||||
rplName = rawSectionName.substr(fimport.size());
|
|
||||||
} else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) {
|
|
||||||
rplName = rawSectionName.substr(dimport.size());
|
|
||||||
data = true;
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE("invalid section name\n");
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
return std::make_shared<ImportRPLInformation>(rplName, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string getName() const {
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const char *getRPLName() const {
|
||||||
|
if (name.max_size() < strlen("._import_") + 1) {
|
||||||
|
OSFatal("Invalid RPLName, is too short to be valid");
|
||||||
|
}
|
||||||
|
return name.c_str() + strlen("._import_");
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool isData() const {
|
[[nodiscard]] bool isData() const {
|
||||||
return _isData;
|
return name.starts_with(".dimport_");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool _isData = false;
|
|
||||||
};
|
};
|
|
@ -54,51 +54,43 @@ public:
|
||||||
this->entrypoint = addr;
|
this->entrypoint = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStartAddress(uint32_t addr) {
|
void addRelocationData(std::unique_ptr<RelocationData> relocation_data) {
|
||||||
this->startAddress = addr;
|
relocation_data_list.push_back(std::move(relocation_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setEndAddress(uint32_t _endAddress) {
|
[[nodiscard]] const std::vector<std::unique_ptr<RelocationData>> &getRelocationDataList() const {
|
||||||
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 {
|
|
||||||
return relocation_data_list;
|
return relocation_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addExportData(const std::shared_ptr<ExportData> &data) {
|
void addExportData(std::unique_ptr<ExportData> data) {
|
||||||
export_data_list.push_back(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;
|
return export_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addHookData(const std::shared_ptr<HookData> &data) {
|
void addHookData(std::unique_ptr<HookData> data) {
|
||||||
hook_data_list.push_back(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;
|
return hook_data_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSectionInfo(const std::shared_ptr<SectionInfo> §ionInfo) {
|
void addSectionInfo(std::shared_ptr<SectionInfo> sectionInfo) {
|
||||||
section_info_list[sectionInfo->getName()] = sectionInfo;
|
section_info_list[sectionInfo->getName()] = std::move(sectionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFunctionSymbolData(const std::shared_ptr<FunctionSymbolData> &symbol_data) {
|
void addFunctionSymbolData(std::shared_ptr<FunctionSymbolData> symbol_data) {
|
||||||
symbol_data_list.insert(symbol_data);
|
symbol_data_list.insert(std::move(symbol_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
[[nodiscard]] const std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> &getFunctionSymbolDataList() const {
|
||||||
return symbol_data_list;
|
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;
|
return section_info_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +98,10 @@ public:
|
||||||
if (getSectionInfoList().count(sectionName) > 0) {
|
if (getSectionInfoList().count(sectionName) > 0) {
|
||||||
return section_info_list.at(sectionName);
|
return section_info_list.at(sectionName);
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint32_t getBSSAddr() const {
|
[[nodiscard]] uint32_t getBSSAddress() const {
|
||||||
return bssAddr;
|
return bssAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +109,7 @@ public:
|
||||||
return bssSize;
|
return bssSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint32_t getSBSSAddr() const {
|
[[nodiscard]] uint32_t getSBSSAddress() const {
|
||||||
return sbssAddr;
|
return sbssAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,25 +117,23 @@ public:
|
||||||
return sbssSize;
|
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 {
|
[[nodiscard]] uint32_t getEntrypoint() const {
|
||||||
return entrypoint;
|
return entrypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint32_t getStartAddress() const {
|
void setExportName(std::string name) {
|
||||||
return startAddress;
|
this->export_name = std::move(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint32_t getEndAddress() const {
|
[[nodiscard]] const std::string &getExportName() const {
|
||||||
return endAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string toString() const;
|
|
||||||
|
|
||||||
void setExportName(const std::string &name) {
|
|
||||||
this->export_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string getExportName() const {
|
|
||||||
return this->export_name;
|
return this->export_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,24 +153,33 @@ public:
|
||||||
this->skipInitFini = value;
|
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:
|
private:
|
||||||
std::vector<std::shared_ptr<RelocationData>> relocation_data_list;
|
std::vector<std::unique_ptr<RelocationData>> relocation_data_list;
|
||||||
std::vector<std::shared_ptr<ExportData>> export_data_list;
|
std::vector<std::unique_ptr<ExportData>> export_data_list;
|
||||||
std::vector<std::shared_ptr<HookData>> hook_data_list;
|
std::vector<std::unique_ptr<HookData>> hook_data_list;
|
||||||
std::set<std::shared_ptr<FunctionSymbolData>, FunctionSymbolDataComparator> symbol_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;
|
std::string export_name;
|
||||||
|
|
||||||
uint32_t bssAddr = 0;
|
uint32_t bssAddr = 0;
|
||||||
uint32_t bssSize = 0;
|
uint32_t bssSize = 0;
|
||||||
uint32_t sbssAddr = 0;
|
uint32_t sbssAddr = 0;
|
||||||
uint32_t sbssSize = 0;
|
uint32_t sbssSize = 0;
|
||||||
uint32_t startAddress = 0;
|
|
||||||
uint32_t endAddress = 0;
|
|
||||||
uint32_t entrypoint = 0;
|
uint32_t entrypoint = 0;
|
||||||
|
uint32_t totalSize = 0;
|
||||||
bool initBeforeRelocationDoneHook = false;
|
bool initBeforeRelocationDoneHook = false;
|
||||||
bool skipInitFini = 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
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,54 +16,86 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "ModuleDataFactory.h"
|
#include "ModuleDataFactory.h"
|
||||||
#include "ElfUtils.h"
|
#include "fs/FileUtils.h"
|
||||||
#include "utils/FileUtils.h"
|
#include "utils/ElfUtils.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/logger.h"
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
|
#include <coreinit/memdefaultheap.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <wums.h>
|
#include <wums.h>
|
||||||
|
|
||||||
using namespace ELFIO;
|
using namespace ELFIO;
|
||||||
|
|
||||||
std::optional<std::shared_ptr<ModuleData>>
|
std::optional<std::shared_ptr<ModuleData>> ModuleDataFactory::load(const std::string &path) {
|
||||||
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) {
|
|
||||||
elfio reader;
|
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;
|
uint8_t *buffer = nullptr;
|
||||||
uint32_t fsize = 0;
|
uint32_t fsize = 0;
|
||||||
if (LoadFileToMem(path.c_str(), &buffer, &fsize) < 0) {
|
if (LoadFileToMem(path, &buffer, &fsize) < 0) {
|
||||||
DEBUG_FUNCTION_LINE("Failed to load file");
|
DEBUG_FUNCTION_LINE_ERR("Failed to load file");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load ELF data
|
// Load ELF data
|
||||||
if (!reader.load(reinterpret_cast<char *>(buffer), fsize)) {
|
if (!reader.load(reinterpret_cast<char *>(buffer), fsize)) {
|
||||||
DEBUG_FUNCTION_LINE("Can't find or process %s", path.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Can't find or process %s", path.c_str());
|
||||||
free(buffer);
|
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 {};
|
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) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
DEBUG_FUNCTION_LINE("Failed to alloc memory for destinations");
|
auto *psec = reader.sections[i];
|
||||||
free(buffer);
|
if (psec->get_type() == 0x80000002) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t baseOffset = *destination_address_ptr;
|
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 offset_text = baseOffset;
|
auto data = std::make_unique<uint8_t[]>(text_size + data_size);
|
||||||
uint32_t offset_data = offset_text;
|
if (!data) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to alloc memory for the .text section (%d bytes)", text_size);
|
||||||
|
MEMFreeToDefaultHeap(buffer);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t entrypoint = offset_text + (uint32_t) reader.get_entry() - 0x02000000;
|
DEBUG_FUNCTION_LINE("Allocated %d kb", (text_size + data_size) / 1024);
|
||||||
|
|
||||||
uint32_t totalSize = 0;
|
void *text_data = data.get();
|
||||||
uint32_t endAddress = 0;
|
void *data_data = (void *) ((uint32_t) data.get() + text_size);
|
||||||
|
auto baseOffset = (uint32_t) data.get();
|
||||||
|
|
||||||
|
uint32_t entrypoint = (uint32_t) text_data + (uint32_t) reader.get_entry() - 0x02000000;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[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();
|
uint32_t sectionSize = psec->get_size();
|
||||||
|
|
||||||
totalSize += sectionSize;
|
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();
|
auto address = (uint32_t) psec->get_address();
|
||||||
|
|
||||||
|
@ -91,7 +117,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
destination -= 0x02000000;
|
destination -= 0x02000000;
|
||||||
destinations[psec->get_index()] -= 0x02000000;
|
destinations[psec->get_index()] -= 0x02000000;
|
||||||
baseOffset += sectionSize;
|
baseOffset += sectionSize;
|
||||||
offset_data += sectionSize;
|
|
||||||
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
} else if ((address >= 0x10000000) && address < 0xC0000000) {
|
||||||
destination -= 0x10000000;
|
destination -= 0x10000000;
|
||||||
destinations[psec->get_index()] -= 0x10000000;
|
destinations[psec->get_index()] -= 0x10000000;
|
||||||
|
@ -99,9 +124,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
destination -= 0xC0000000;
|
destination -= 0xC0000000;
|
||||||
destinations[psec->get_index()] -= 0xC0000000;
|
destinations[psec->get_index()] -= 0xC0000000;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Unhandled case");
|
DEBUG_FUNCTION_LINE_ERR("Unhandled case");
|
||||||
free(destinations);
|
MEMFreeToDefaultHeap(buffer);
|
||||||
free(buffer);
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,10 +139,10 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
memcpy((void *) destination, p, sectionSize);
|
memcpy((void *) destination, p, sectionSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
//nextAddress = ROUNDUP(destination + sectionSize, 0x100);
|
|
||||||
if (psec->get_name() == ".bss") {
|
if (psec->get_name() == ".bss") {
|
||||||
moduleData->setBSSLocation(destination, sectionSize);
|
moduleData->setBSSLocation(destination, sectionSize);
|
||||||
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
|
memset(reinterpret_cast<void *>(destination), 0, sectionSize);
|
||||||
|
|
||||||
} else if (psec->get_name() == ".sbss") {
|
} else if (psec->get_name() == ".sbss") {
|
||||||
moduleData->setSBSSLocation(destination, sectionSize);
|
moduleData->setSBSSLocation(destination, sectionSize);
|
||||||
memset(reinterpret_cast<void *>(destination), 0, 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);
|
moduleData->addSectionInfo(sectionInfo);
|
||||||
DEBUG_FUNCTION_LINE("Saved %s section info. Location: %08X size: %08X", psec->get_name().c_str(), destination, sectionSize);
|
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);
|
DCFlushRange((void *) destination, sectionSize);
|
||||||
ICInvalidateRange((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];
|
section *psec = reader.sections[i];
|
||||||
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) {
|
||||||
DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str());
|
DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str());
|
||||||
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) {
|
if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], (uint32_t) text_data, (uint32_t) data_data, nullptr, 0)) {
|
||||||
DEBUG_FUNCTION_LINE("elfLink failed");
|
DEBUG_FUNCTION_LINE_ERR("elfLink failed");
|
||||||
free(destinations);
|
MEMFreeToDefaultHeap(buffer);
|
||||||
free(buffer);
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto relocationData = getImportRelocationData(reader, destinations);
|
getImportRelocationData(moduleData, reader, destinations.get());
|
||||||
|
|
||||||
for (auto const &reloc : relocationData) {
|
|
||||||
moduleData->addRelocationData(reloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto secInfo = moduleData->getSectionInfo(".wums.exports");
|
auto secInfo = moduleData->getSectionInfo(".wums.exports");
|
||||||
if (secInfo && secInfo.value()->getSize() > 0) {
|
if (secInfo && secInfo.value()->getSize() > 0) {
|
||||||
|
@ -161,9 +176,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
if (entries != nullptr) {
|
if (entries != nullptr) {
|
||||||
for (size_t j = 0; j < entries_count; j++) {
|
for (size_t j = 0; j < entries_count; j++) {
|
||||||
wums_entry_t *exp = &entries[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);
|
DEBUG_FUNCTION_LINE("Saving export of type %08X, name %s, target: %08X", exp->type, exp->name, exp->address);
|
||||||
auto exportData = std::make_shared<ExportData>(exp->type, exp->name, exp->address);
|
auto exportData = std::make_unique<ExportData>(exp->type, exp->name, exp->address);
|
||||||
moduleData->addExportData(exportData);
|
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) {
|
if (hooks != nullptr) {
|
||||||
for (size_t j = 0; j < entries_count; j++) {
|
for (size_t j = 0; j < entries_count; j++) {
|
||||||
wums_hook_t *hook = &hooks[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);
|
DEBUG_FUNCTION_LINE("Saving hook of type %08X, target: %08X", hook->type, hook->target);
|
||||||
auto hookData = std::make_shared<HookData>(hook->type, hook->target);
|
auto hookData = std::make_unique<HookData>(hook->type, hook->target);
|
||||||
moduleData->addHookData(hookData);
|
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);
|
std::string value(curEntry + firstFound + 1);
|
||||||
|
|
||||||
if (key == "export_name") {
|
if (key == "export_name") {
|
||||||
DEBUG_FUNCTION_LINE("export_name = %s", value.c_str());
|
|
||||||
moduleData->setExportName(value);
|
moduleData->setExportName(value);
|
||||||
} else if (key == "skipInitFini") {
|
} else if (key == "skipInitFini") {
|
||||||
if (value == "true") {
|
if (value == "true") {
|
||||||
|
@ -219,9 +239,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
}
|
}
|
||||||
} else if (key == "wums") {
|
} else if (key == "wums") {
|
||||||
if (value != "0.3") {
|
if (value != "0.3") {
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring module - Unsupported WUMS version: %s.\n", value.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring module - Unsupported WUMS version: %s.", value.c_str());
|
||||||
free(destinations);
|
MEMFreeToDefaultHeap(buffer);
|
||||||
free(buffer);
|
|
||||||
return std::nullopt;
|
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.
|
// Get the symbol for functions.
|
||||||
Elf_Half n = reader.sections.size();
|
Elf_Half n = reader.sections.size();
|
||||||
for (Elf_Half i = 0; i < n; ++i) {
|
for (Elf_Half i = 0; i < n; ++i) {
|
||||||
|
@ -259,13 +275,12 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
auto finalAddress = offsetVal + sectionOpt.value()->getAddress();
|
||||||
|
auto functionSymbolData = std::make_shared<FunctionSymbolData>(name, (void *) finalAddress, (uint32_t) size);
|
||||||
uint32_t stringSize = name.size() + 1;
|
if (!functionSymbolData) {
|
||||||
memcpy(strTable + strOffset, name.c_str(), stringSize);
|
DEBUG_FUNCTION_LINE_ERR("Failed to alloc FunctionSymbolData");
|
||||||
moduleData->addFunctionSymbolData(std::make_shared<FunctionSymbolData>(strTable + strOffset, (void *) finalAddress, (uint32_t) size));
|
} else {
|
||||||
strOffset += stringSize;
|
moduleData->addFunctionSymbolData(std::move(functionSymbolData));
|
||||||
totalSize += stringSize;
|
}
|
||||||
endAddress += stringSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,41 +289,44 @@ ModuleDataFactory::load(const std::string &path, uint32_t *destination_address_p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DCFlushRange((void *) *destination_address_ptr, totalSize);
|
DCFlushRange((void *) text_data, text_size);
|
||||||
ICInvalidateRange((void *) *destination_address_ptr, totalSize);
|
ICInvalidateRange((void *) text_data, text_size);
|
||||||
|
DCFlushRange((void *) data_data, data_size);
|
||||||
|
ICInvalidateRange((void *) data_data, data_size);
|
||||||
|
|
||||||
free(destinations);
|
if (totalSize > text_size + data_size) {
|
||||||
free(buffer);
|
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->setEntrypoint(entrypoint);
|
||||||
moduleData->setStartAddress(*destination_address_ptr);
|
|
||||||
moduleData->setEndAddress(endAddress);
|
|
||||||
DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint);
|
DEBUG_FUNCTION_LINE("Saved entrypoint as %08X", entrypoint);
|
||||||
DEBUG_FUNCTION_LINE("Saved startAddress as %08X", *destination_address_ptr);
|
DEBUG_FUNCTION_LINE("Saved startAddress as %08X", (uint32_t) data.get());
|
||||||
DEBUG_FUNCTION_LINE("Saved endAddress as %08X", endAddress);
|
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;
|
return moduleData;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) {
|
void ModuleDataFactory::getImportRelocationData(std::shared_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations) {
|
||||||
std::vector<std::shared_ptr<RelocationData>> result;
|
std::map<uint32_t, std::shared_ptr<ImportRPLInformation>> infoMap;
|
||||||
std::map<uint32_t, std::string> infoMap;
|
|
||||||
|
|
||||||
uint32_t sec_num = reader.sections.size();
|
uint32_t sec_num = reader.sections.size();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
auto *psec = reader.sections[i];
|
||||||
if (psec->get_type() == 0x80000002) {
|
if (psec->get_type() == 0x80000002) {
|
||||||
infoMap[i] = psec->get_name();
|
infoMap[i] = std::make_shared<ImportRPLInformation>(psec->get_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sec_num; ++i) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
section *psec = reader.sections[i];
|
||||||
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
|
if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) {
|
||||||
DEBUG_FUNCTION_LINE("Found relocation section %s", psec->get_name().c_str());
|
|
||||||
relocation_section_accessor rel(reader, psec);
|
relocation_section_accessor rel(reader, psec);
|
||||||
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
||||||
Elf64_Addr offset;
|
Elf64_Addr offset;
|
||||||
|
@ -319,30 +337,39 @@ std::vector<std::shared_ptr<RelocationData>> ModuleDataFactory::getImportRelocat
|
||||||
Elf_Half sym_section_index;
|
Elf_Half sym_section_index;
|
||||||
|
|
||||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||||
DEBUG_FUNCTION_LINE("Failed to get relocation");
|
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||||
|
OSFatal("Failed to get relocation");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// uint32_t adjusted_sym_value = (uint32_t) sym_value;
|
auto adjusted_sym_value = (uint32_t) sym_value;
|
||||||
if (infoMap.count(sym_section_index) == 0) {
|
if (adjusted_sym_value < 0xC0000000) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]);
|
|
||||||
if (!rplInfo) {
|
|
||||||
DEBUG_FUNCTION_LINE("Failed to create import information");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t section_index = psec->get_info();
|
uint32_t section_index = psec->get_info();
|
||||||
|
if (!infoMap.contains(sym_section_index)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str());
|
||||||
|
OSFatal("Relocation is referencing a unknown section.");
|
||||||
|
}
|
||||||
|
|
||||||
// When these relocations are performed, we don't need the 0xC0000000 offset anymore.
|
auto relocationData = std::make_unique<RelocationData>(type,
|
||||||
auto relocationData = std::make_shared<RelocationData>(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value());
|
offset - 0x02000000,
|
||||||
//relocationData->printInformation();
|
addend,
|
||||||
result.push_back(relocationData);
|
(void *) (destinations[section_index] + 0x02000000),
|
||||||
|
sym_name,
|
||||||
|
infoMap[sym_section_index]);
|
||||||
|
|
||||||
|
if (!relocationData) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to alloc relocation data");
|
||||||
|
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,
|
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) {
|
for (uint32_t i = 0; i < sec_num; ++i) {
|
||||||
section *psec = reader.sections[i];
|
section *psec = reader.sections[i];
|
||||||
if (psec->get_info() == section_index) {
|
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);
|
relocation_section_accessor rel(reader, psec);
|
||||||
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) {
|
||||||
Elf64_Addr offset;
|
Elf64_Addr offset;
|
||||||
|
@ -363,7 +390,8 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
||||||
Elf_Half sym_section_index;
|
Elf_Half sym_section_index;
|
||||||
|
|
||||||
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) {
|
||||||
DEBUG_FUNCTION_LINE("Failed to get relocation");
|
DEBUG_FUNCTION_LINE_ERR("Failed to get relocation");
|
||||||
|
OSFatal("Failed to get relocation");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,23 +408,21 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3
|
||||||
} else if (adjusted_sym_value == 0x0) {
|
} else if (adjusted_sym_value == 0x0) {
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Unhandled case %08X", adjusted_sym_value);
|
DEBUG_FUNCTION_LINE_ERR("Unhandled case %08X", adjusted_sym_value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sym_section_index == SHN_ABS) {
|
if (sym_section_index == SHN_ABS) {
|
||||||
//
|
//
|
||||||
} else if (sym_section_index > SHN_LORESERVE) {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
|
if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) {
|
||||||
DEBUG_FUNCTION_LINE("Link failed");
|
DEBUG_FUNCTION_LINE_ERR("Link failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE("done");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
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
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "ModuleData.h"
|
#include "ModuleData.h"
|
||||||
#include "elfio/elfio.hpp"
|
#include "elfio/elfio.hpp"
|
||||||
|
#include <coreinit/memheap.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -26,11 +27,15 @@
|
||||||
|
|
||||||
class ModuleDataFactory {
|
class ModuleDataFactory {
|
||||||
public:
|
public:
|
||||||
static std::optional<std::shared_ptr<ModuleData>>
|
static std::optional<std::shared_ptr<ModuleData>> load(const std::string &path);
|
||||||
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 bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data,
|
static bool linkSection(ELFIO::elfio &reader,
|
||||||
|
uint32_t section_index,
|
||||||
|
uint32_t destination,
|
||||||
|
uint32_t base_text,
|
||||||
|
uint32_t base_data,
|
||||||
|
relocation_trampoline_entry_t *trampoline_data,
|
||||||
uint32_t trampoline_data_length);
|
uint32_t trampoline_data_length);
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<RelocationData>> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations);
|
static void getImportRelocationData(std::shared_ptr<ModuleData> &moduleData, ELFIO::elfio &reader, uint8_t **destinations);
|
||||||
};
|
};
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::string getName() const {
|
[[nodiscard]] const std::string &getName() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<ImportRPLInformation> getImportRPLInformation() const {
|
[[nodiscard]] const std::shared_ptr<ImportRPLInformation> &getImportRPLInformation() const {
|
||||||
return rplInfo;
|
return rplInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::string toString() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char type;
|
char type;
|
||||||
size_t offset;
|
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
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,14 +30,10 @@ public:
|
||||||
|
|
||||||
SectionInfo() = default;
|
SectionInfo() = default;
|
||||||
|
|
||||||
SectionInfo(const SectionInfo &o2) : name(o2.name),
|
SectionInfo(const SectionInfo &o2) = default;
|
||||||
address(o2.address),
|
|
||||||
sectionSize(o2.sectionSize) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SectionInfo &operator=(const SectionInfo &other) = default;
|
SectionInfo &operator=(const SectionInfo &other) = default;
|
||||||
|
|
||||||
|
|
||||||
virtual ~SectionInfo() = default;
|
virtual ~SectionInfo() = default;
|
||||||
|
|
||||||
[[nodiscard]] const std::string &getName() const {
|
[[nodiscard]] const std::string &getName() const {
|
|
@ -1,4 +1,5 @@
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
|
#include <valarray>
|
||||||
|
|
||||||
#include "ElfUtils.h"
|
#include "ElfUtils.h"
|
||||||
#include "utils/logger.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) {
|
if (type == R_PPC_NONE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto target = destination + offset;
|
auto target = destination + offset;
|
||||||
auto value = symbol_addr + addend;
|
auto value = symbol_addr + addend;
|
||||||
|
|
||||||
|
@ -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);
|
*((uint16_t *) (target)) = static_cast<uint16_t>((value + 0x8000) >> 16);
|
||||||
break;
|
break;
|
||||||
case R_PPC_DTPMOD32:
|
case R_PPC_DTPMOD32:
|
||||||
DEBUG_FUNCTION_LINE("################IMPLEMENT ME\n");
|
DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME");
|
||||||
//*((int32_t *)(target)) = tlsModuleIndex;
|
//*((int32_t *)(target)) = tlsModuleIndex;
|
||||||
break;
|
break;
|
||||||
case R_PPC_DTPREL32:
|
case R_PPC_DTPREL32:
|
||||||
|
@ -48,18 +50,18 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||||
case R_PPC_REL14: {
|
case R_PPC_REL14: {
|
||||||
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||||
if (distance > 0x7FFC || distance < -0x7FFC) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance & 3) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
|
if ((distance >= 0 && (distance & 0xFFFF8000)) ||
|
||||||
(distance < 0 && ((distance & 0xFFFF8000) != 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;
|
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);
|
auto distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
||||||
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) {
|
||||||
if (trampoline_data == nullptr) {
|
if (trampoline_data == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline isn't provided\n");
|
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided");
|
||||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, distance);
|
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
relocation_trampoline_entry_t *freeSlot = nullptr;
|
relocation_trampoline_entry_t *freeSlot = nullptr;
|
||||||
|
@ -93,14 +95,20 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (freeSlot == nullptr) {
|
if (freeSlot == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampoline data list is full\n");
|
DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full");
|
||||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) & (freeSlot->trampoline[0]));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) {
|
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
||||||
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer).");
|
auto newValue = symbolValue + addend;
|
||||||
DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0])));
|
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;
|
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
|
// Relocations for the imports may be overridden
|
||||||
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
freeSlot->status = RELOC_TRAMP_IMPORT_DONE;
|
||||||
}
|
}
|
||||||
auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]);
|
distance = newDistance;
|
||||||
value = symbolValue + addend;
|
|
||||||
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance & 3) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance < 0 && (distance & 0xFE000000) != 0xFE000000) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance >= 0 && (distance & 0xFE000000)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,8 +148,10 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
DEBUG_FUNCTION_LINE("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ICInvalidateRange(reinterpret_cast<void *>(target), 4);
|
||||||
|
DCFlushRange(reinterpret_cast<void *>(target), 4);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
|
@ -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
|
* for WiiXplorer 2010
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#ifndef __STRING_TOOLS_H
|
#pragma once
|
||||||
#define __STRING_TOOLS_H
|
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wut_types.h>
|
#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 {
|
class StringTools {
|
||||||
public:
|
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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __STRING_TOOLS_H */
|
|
|
@ -21,6 +21,11 @@
|
||||||
} while (0)
|
} while (0)
|
||||||
#define IMPORT_END()
|
#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) {
|
void InitFunctionPointers(void) {
|
||||||
OSDynLoad_Module handle;
|
OSDynLoad_Module handle;
|
||||||
|
@ -28,5 +33,16 @@ void InitFunctionPointers(void) {
|
||||||
addr_OSDynLoad_FindExport = (void *) 0x0102B828; // 0200f428 - 0xFE3C00
|
addr_OSDynLoad_FindExport = (void *) 0x0102B828; // 0200f428 - 0xFE3C00
|
||||||
addr_OSDynLoad_IsModuleLoaded = (void *) 0x0102A59C; // 0200e19c - 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"
|
#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 "hooks.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
#include "module/ModuleData.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <memory>
|
||||||
#include <wums.h>
|
#include <wums.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
static const char **hook_names = (const char *[]){
|
static const char **hook_names = (const char *[]){
|
||||||
"WUMS_HOOK_INIT_WUT_MALLOC",
|
"WUMS_HOOK_INIT_WUT_MALLOC",
|
||||||
"WUMS_HOOK_FINI_WUT_MALLOC",
|
"WUMS_HOOK_FINI_WUT_MALLOC",
|
||||||
|
@ -22,36 +26,32 @@ static const char **hook_names = (const char *[]){
|
||||||
"WUMS_HOOK_APPLICATION_ENDS",
|
"WUMS_HOOK_APPLICATION_ENDS",
|
||||||
"WUMS_HOOK_RELOCATIONS_DONE",
|
"WUMS_HOOK_RELOCATIONS_DONE",
|
||||||
"WUMS_HOOK_APPLICATION_REQUESTS_EXIT"};
|
"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) {
|
if (condition) {
|
||||||
CallHook(modules, type);
|
CallHook(modules, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallHook(const std::vector<std::shared_ptr<ModuleDataMinimal>> &modules, wums_hook_type_t type) {
|
void CallHook(const std::vector<std::shared_ptr<ModuleData>> &modules, wums_hook_type_t type) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d] for all modules\n", hook_names[type], type);
|
DEBUG_FUNCTION_LINE("Calling hook of type %s [%d] for all modules", hook_names[type], type);
|
||||||
for (auto &curModule : modules) {
|
for (auto &curModule : modules) {
|
||||||
CallHook(curModule, type);
|
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) {
|
if (condition) {
|
||||||
CallHook(module, type);
|
CallHook(module, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallHook(const std::shared_ptr<ModuleDataMinimal> &module, wums_hook_type_t type) {
|
void CallHook(const std::shared_ptr<ModuleData> &module, wums_hook_type_t type) {
|
||||||
if (!module->relocationsDone) {
|
|
||||||
DEBUG_FUNCTION_LINE("Hook not called because the relocations failed\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &curHook : module->getHookDataList()) {
|
for (auto &curHook : module->getHookDataList()) {
|
||||||
auto func_ptr = (uint32_t) curHook->getTarget();
|
auto func_ptr = (uint32_t) curHook->getTarget();
|
||||||
if (func_ptr == 0) {
|
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;
|
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_FINI_WUT_SOCKETS ||
|
||||||
type == WUMS_HOOK_INIT_WRAPPER ||
|
type == WUMS_HOOK_INIT_WRAPPER ||
|
||||||
type == WUMS_HOOK_FINI_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))();
|
((void (*)())((uint32_t *) func_ptr))();
|
||||||
break;
|
break;
|
||||||
} else if (type == WUMS_HOOK_INIT ||
|
} else if (type == WUMS_HOOK_INIT ||
|
||||||
type == WUMS_HOOK_RELOCATIONS_DONE) {
|
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;
|
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);
|
((void (*)(wums_app_init_args_t *))((uint32_t *) func_ptr))(&args);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("#########################################\n");
|
DEBUG_FUNCTION_LINE_ERR("#########################################");
|
||||||
DEBUG_FUNCTION_LINE("#########HOOK NOT IMPLEMENTED %d#########\n", type);
|
DEBUG_FUNCTION_LINE_ERR("#########HOOK NOT IMPLEMENTED %d#########", type);
|
||||||
DEBUG_FUNCTION_LINE("#########################################\n");
|
DEBUG_FUNCTION_LINE_ERR("#########################################");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
|
@ -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_Acquire);
|
||||||
IMPORT(OSUninterruptibleSpinLock_Release);
|
IMPORT(OSUninterruptibleSpinLock_Release);
|
||||||
IMPORT(OSReport);
|
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();
|
IMPORT_END();
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include <cerrno>
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/memdefaultheap.h>
|
#include <coreinit/memdefaultheap.h>
|
||||||
#include <coreinit/memexpheap.h>
|
#include <coreinit/memexpheap.h>
|
||||||
#include <coreinit/memorymap.h>
|
#include <coreinit/memorymap.h>
|
||||||
#include <errno.h>
|
#include <cstring>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern MEMHeapHandle gHeapHandle;
|
extern MEMHeapHandle gHeapHandle;
|
||||||
|
|
||||||
|
@ -32,11 +32,10 @@ void *MEMAllocSafe(uint32_t size, uint32_t align) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *MemoryAlloc(uint32_t size) {
|
void *MemoryAlloc(uint32_t size) {
|
||||||
void *res = MEMAllocSafe(size, 4);
|
void *res = MEMAllocSafe(size, 4);
|
||||||
if (res == nullptr) {
|
if (res == nullptr) {
|
||||||
OSFatal_printf("Failed to MemoryAlloc %d", size);
|
OSFatal("Failed to MemoryAlloc");
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +43,7 @@ void *MemoryAlloc(uint32_t size) {
|
||||||
void *MemoryAllocEx(uint32_t size, uint32_t align) {
|
void *MemoryAllocEx(uint32_t size, uint32_t align) {
|
||||||
void *res = MEMAllocSafe(size, align);
|
void *res = MEMAllocSafe(size, align);
|
||||||
if (res == nullptr) {
|
if (res == nullptr) {
|
||||||
OSFatal_printf("Failed to MemoryAllocEX %d %d", size, align);
|
OSFatal("Failed to MemoryAllocEX");
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +52,7 @@ void MemoryFree(void *ptr) {
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
MEMFreeToExpHeap(gHeapHandle, ptr);
|
MEMFreeToExpHeap(gHeapHandle, ptr);
|
||||||
} else {
|
} else {
|
||||||
OSFatal_printf("Failed to free");
|
OSFatal("Failed to free");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue