citra-emu
/
citra
Archived
1
0
Fork 0

ldr_ro: pass process reference to memory operation

Note that not all memory operation is fixed. Specifically, u8/u16/u32 Read/Write is still using the current page tabel
This commit is contained in:
Weiyi Wang 2018-11-17 15:01:20 -05:00
parent d4ba87d90a
commit 524364d95a
3 changed files with 62 additions and 42 deletions

View File

@ -7,6 +7,7 @@
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/ldr_ro/cro_helper.h" #include "core/hle/service/ldr_ro/cro_helper.h"
namespace Service::LDR { namespace Service::LDR {
@ -120,7 +121,7 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
VAddr relocation_address = batch; VAddr relocation_address = batch;
while (true) { while (true) {
RelocationEntry relocation; RelocationEntry relocation;
Memory::ReadBlock(relocation_address, &relocation, sizeof(RelocationEntry)); Memory::ReadBlock(process, relocation_address, &relocation, sizeof(RelocationEntry));
VAddr relocation_target = SegmentTagToAddress(relocation.target_position); VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
if (relocation_target == 0) { if (relocation_target == 0) {
@ -141,9 +142,9 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
} }
RelocationEntry relocation; RelocationEntry relocation;
Memory::ReadBlock(batch, &relocation, sizeof(RelocationEntry)); Memory::ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
relocation.is_batch_resolved = reset ? 0 : 1; relocation.is_batch_resolved = reset ? 0 : 1;
Memory::WriteBlock(batch, &relocation, sizeof(RelocationEntry)); Memory::WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -547,7 +548,7 @@ ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
static_relocation_table_offset + static_relocation_table_offset +
GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry); GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
CROHelper crs(crs_address); CROHelper crs(crs_address, process);
u32 offset_export_num = GetField(StaticAnonymousSymbolNum); u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} static anonymous symbols", ModuleName(), LOG_INFO(Service_LDR, "CRO \"{}\" exports {} static anonymous symbols", ModuleName(),
offset_export_num); offset_export_num);
@ -753,11 +754,12 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
GetEntry(i, entry); GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (!relocation_entry.is_batch_resolved) { if (!relocation_entry.is_batch_resolved) {
ResultCode result = ResultCode result =
ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { ForEachAutoLinkCRO(process, crs_address, [&](CROHelper source) -> ResultVal<bool> {
std::string symbol_name = std::string symbol_name =
Memory::ReadCString(entry.name_offset, import_strings_size); Memory::ReadCString(entry.name_offset, import_strings_size);
u32 symbol_address = source.FindExportNamedSymbol(symbol_name); u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
@ -795,7 +797,8 @@ ResultCode CROHelper::ResetImportNamedSymbol() {
GetEntry(i, entry); GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
if (result.IsError()) { if (result.IsError()) {
@ -815,7 +818,8 @@ ResultCode CROHelper::ResetImportIndexedSymbol() {
GetEntry(i, entry); GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
if (result.IsError()) { if (result.IsError()) {
@ -835,7 +839,8 @@ ResultCode CROHelper::ResetImportAnonymousSymbol() {
GetEntry(i, entry); GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true); ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
if (result.IsError()) { if (result.IsError()) {
@ -856,13 +861,13 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size); std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size);
ResultCode result = ResultCode result =
ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { ForEachAutoLinkCRO(process, crs_address, [&](CROHelper source) -> ResultVal<bool> {
if (want_cro_name == source.ModuleName()) { if (want_cro_name == source.ModuleName()) {
LOG_INFO(Service_LDR, "CRO \"{}\" imports {} indexed symbols from \"{}\"", LOG_INFO(Service_LDR, "CRO \"{}\" imports {} indexed symbols from \"{}\"",
ModuleName(), entry.import_indexed_symbol_num, source.ModuleName()); ModuleName(), entry.import_indexed_symbol_num, source.ModuleName());
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
ImportIndexedSymbolEntry im; ImportIndexedSymbolEntry im;
entry.GetImportIndexedSymbolEntry(j, im); entry.GetImportIndexedSymbolEntry(process, j, im);
ExportIndexedSymbolEntry ex; ExportIndexedSymbolEntry ex;
source.GetEntry(im.index, ex); source.GetEntry(im.index, ex);
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position); u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
@ -879,7 +884,7 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
ModuleName(), entry.import_anonymous_symbol_num, source.ModuleName()); ModuleName(), entry.import_anonymous_symbol_num, source.ModuleName());
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
ImportAnonymousSymbolEntry im; ImportAnonymousSymbolEntry im;
entry.GetImportAnonymousSymbolEntry(j, im); entry.GetImportAnonymousSymbolEntry(process, j, im);
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position); u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address); LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
ResultCode result = ResultCode result =
@ -911,7 +916,8 @@ ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
target.GetEntry(i, entry); target.GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (!relocation_entry.is_batch_resolved) { if (!relocation_entry.is_batch_resolved) {
std::string symbol_name = std::string symbol_name =
@ -941,7 +947,8 @@ ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
target.GetEntry(i, entry); target.GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (relocation_entry.is_batch_resolved) { if (relocation_entry.is_batch_resolved) {
std::string symbol_name = std::string symbol_name =
@ -976,7 +983,7 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
entry.import_indexed_symbol_num, target.ModuleName()); entry.import_indexed_symbol_num, target.ModuleName());
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
ImportIndexedSymbolEntry im; ImportIndexedSymbolEntry im;
entry.GetImportIndexedSymbolEntry(j, im); entry.GetImportIndexedSymbolEntry(process, j, im);
ExportIndexedSymbolEntry ex; ExportIndexedSymbolEntry ex;
GetEntry(im.index, ex); GetEntry(im.index, ex);
u32 symbol_address = SegmentTagToAddress(ex.symbol_position); u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
@ -993,7 +1000,7 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
entry.import_anonymous_symbol_num, target.ModuleName()); entry.import_anonymous_symbol_num, target.ModuleName());
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
ImportAnonymousSymbolEntry im; ImportAnonymousSymbolEntry im;
entry.GetImportAnonymousSymbolEntry(j, im); entry.GetImportAnonymousSymbolEntry(process, j, im);
u32 symbol_address = SegmentTagToAddress(im.symbol_position); u32 symbol_address = SegmentTagToAddress(im.symbol_position);
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address); LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
ResultCode result = ResultCode result =
@ -1025,7 +1032,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
target.ModuleName()); target.ModuleName());
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) { for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
ImportIndexedSymbolEntry im; ImportIndexedSymbolEntry im;
entry.GetImportIndexedSymbolEntry(j, im); entry.GetImportIndexedSymbolEntry(process, j, im);
ResultCode result = ResultCode result =
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
if (result.IsError()) { if (result.IsError()) {
@ -1038,7 +1045,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
target.ModuleName()); target.ModuleName());
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) { for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
ImportAnonymousSymbolEntry im; ImportAnonymousSymbolEntry im;
entry.GetImportAnonymousSymbolEntry(j, im); entry.GetImportAnonymousSymbolEntry(process, j, im);
ResultCode result = ResultCode result =
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true); target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
if (result.IsError()) { if (result.IsError()) {
@ -1059,11 +1066,12 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
GetEntry(i, entry); GetEntry(i, entry);
VAddr relocation_addr = entry.relocation_batch_offset; VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry; ExternalRelocationEntry relocation_entry;
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry)); Memory::ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") { if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
ResultCode result = ResultCode result =
ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> { ForEachAutoLinkCRO(process, crs_address, [&](CROHelper source) -> ResultVal<bool> {
u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_"); u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
if (symbol_address != 0) { if (symbol_address != 0) {
@ -1291,7 +1299,7 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
} }
// Exports symbols to other modules // Exports symbols to other modules
result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> { result = ForEachAutoLinkCRO(process, crs_address, [this](CROHelper target) -> ResultVal<bool> {
ResultCode result = ApplyExportNamedSymbol(target); ResultCode result = ApplyExportNamedSymbol(target);
if (result.IsError()) if (result.IsError())
return result; return result;
@ -1335,7 +1343,7 @@ ResultCode CROHelper::Unlink(VAddr crs_address) {
// Resets all symbols in other modules imported from this module // Resets all symbols in other modules imported from this module
// Note: the RO service seems only searching in auto-link modules // Note: the RO service seems only searching in auto-link modules
result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> { result = ForEachAutoLinkCRO(process, crs_address, [this](CROHelper target) -> ResultVal<bool> {
ResultCode result = ResetExportNamedSymbol(target); ResultCode result = ResetExportNamedSymbol(target);
if (result.IsError()) if (result.IsError())
return result; return result;
@ -1375,13 +1383,13 @@ void CROHelper::InitCRS() {
} }
void CROHelper::Register(VAddr crs_address, bool auto_link) { void CROHelper::Register(VAddr crs_address, bool auto_link) {
CROHelper crs(crs_address); CROHelper crs(crs_address, process);
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule()); CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process);
if (head.module_address) { if (head.module_address) {
// there are already CROs registered // there are already CROs registered
// register as the new tail // register as the new tail
CROHelper tail(head.PreviousModule()); CROHelper tail(head.PreviousModule(), process);
// link with the old tail // link with the old tail
ASSERT(tail.NextModule() == 0); ASSERT(tail.NextModule() == 0);
@ -1407,9 +1415,9 @@ void CROHelper::Register(VAddr crs_address, bool auto_link) {
} }
void CROHelper::Unregister(VAddr crs_address) { void CROHelper::Unregister(VAddr crs_address) {
CROHelper crs(crs_address); CROHelper crs(crs_address, process);
CROHelper next_head(crs.NextModule()), previous_head(crs.PreviousModule()); CROHelper next_head(crs.NextModule(), process), previous_head(crs.PreviousModule(), process);
CROHelper next(NextModule()), previous(PreviousModule()); CROHelper next(NextModule(), process), previous(PreviousModule(), process);
if (module_address == next_head.module_address || if (module_address == next_head.module_address ||
module_address == previous_head.module_address) { module_address == previous_head.module_address) {

View File

@ -11,6 +11,10 @@
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/memory.h" #include "core/memory.h"
namespace Kernel {
class Process;
}
namespace Service::LDR { namespace Service::LDR {
// GCC versions < 5.0 do not implement std::is_trivially_copyable. // GCC versions < 5.0 do not implement std::is_trivially_copyable.
@ -36,7 +40,8 @@ static constexpr u32 CRO_HASH_SIZE = 0x80;
class CROHelper final { class CROHelper final {
public: public:
// TODO (wwylele): pass in the process handle for memory access // TODO (wwylele): pass in the process handle for memory access
explicit CROHelper(VAddr cro_address) : module_address(cro_address) {} explicit CROHelper(VAddr cro_address, Kernel::Process& process)
: module_address(cro_address), process(process) {}
std::string ModuleName() const { std::string ModuleName() const {
return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize)); return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
@ -144,6 +149,7 @@ public:
private: private:
const VAddr module_address; ///< the virtual address of this module const VAddr module_address; ///< the virtual address of this module
Kernel::Process& process; ///< the owner process of this module
/** /**
* Each item in this enum represents a u32 field in the header begin from address+0x80, * Each item in this enum represents a u32 field in the header begin from address+0x80,
@ -311,14 +317,18 @@ private:
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset; static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset;
void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) { void GetImportIndexedSymbolEntry(Kernel::Process& process, u32 index,
Memory::ReadBlock(import_indexed_symbol_table_offset + ImportIndexedSymbolEntry& entry) {
Memory::ReadBlock(process,
import_indexed_symbol_table_offset +
index * sizeof(ImportIndexedSymbolEntry), index * sizeof(ImportIndexedSymbolEntry),
&entry, sizeof(ImportIndexedSymbolEntry)); &entry, sizeof(ImportIndexedSymbolEntry));
} }
void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) { void GetImportAnonymousSymbolEntry(Kernel::Process& process, u32 index,
Memory::ReadBlock(import_anonymous_symbol_table_offset + ImportAnonymousSymbolEntry& entry) {
Memory::ReadBlock(process,
import_anonymous_symbol_table_offset +
index * sizeof(ImportAnonymousSymbolEntry), index * sizeof(ImportAnonymousSymbolEntry),
&entry, sizeof(ImportAnonymousSymbolEntry)); &entry, sizeof(ImportAnonymousSymbolEntry));
} }
@ -413,7 +423,8 @@ private:
*/ */
template <typename T> template <typename T>
void GetEntry(std::size_t index, T& data) const { void GetEntry(std::size_t index, T& data) const {
Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), Memory::ReadBlock(process,
GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
&data, sizeof(T)); &data, sizeof(T));
} }
@ -466,10 +477,11 @@ private:
* otherwise error code of the last iteration. * otherwise error code of the last iteration.
*/ */
template <typename FunctionObject> template <typename FunctionObject>
static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) { static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, VAddr crs_address,
FunctionObject func) {
VAddr current = crs_address; VAddr current = crs_address;
while (current != 0) { while (current != 0) {
CROHelper cro(current); CROHelper cro(current, process);
CASCADE_RESULT(bool next, func(cro)); CASCADE_RESULT(bool next, func(cro));
if (!next) if (!next)
break; break;

View File

@ -115,7 +115,7 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) {
return; return;
} }
CROHelper crs(crs_address); CROHelper crs(crs_address, *process);
crs.InitCRS(); crs.InitCRS();
result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true); result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true);
@ -249,7 +249,7 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
return; return;
} }
CROHelper cro(cro_address); CROHelper cro(cro_address, *process);
result = cro.VerifyHash(cro_size, crr_address); result = cro.VerifyHash(cro_size, crr_address);
if (result.IsError()) { if (result.IsError()) {
@ -331,7 +331,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}, zero={}, cro_buffer_ptr=0x{:08X}", LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}, zero={}, cro_buffer_ptr=0x{:08X}",
cro_address, zero, cro_buffer_ptr); cro_address, zero, cro_buffer_ptr);
CROHelper cro(cro_address); CROHelper cro(cro_address, *process);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -398,7 +398,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address); LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
CROHelper cro(cro_address); CROHelper cro(cro_address, *process);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -438,7 +438,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address); LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
CROHelper cro(cro_address); CROHelper cro(cro_address, *process);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -487,7 +487,7 @@ void RO::Shutdown(Kernel::HLERequestContext& ctx) {
return; return;
} }
CROHelper crs(slot->loaded_crs); CROHelper crs(slot->loaded_crs, *process);
crs.Unrebase(true); crs.Unrebase(true);
ResultCode result = RESULT_SUCCESS; ResultCode result = RESULT_SUCCESS;