mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 18:20:14 +00:00
LDR: implement unlink
This commit is contained in:
parent
bed5915f4f
commit
1e2bcb21f2
@ -1193,6 +1193,79 @@ class CROHelper final {
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all imported named symbols of this module to unresolved state.
|
||||||
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
*/
|
||||||
|
ResultCode ResetImportNamedSymbol() {
|
||||||
|
u32 unresolved_symbol = SegmentTagToAddress(GetField(OnUnresolvedSegmentTag));
|
||||||
|
|
||||||
|
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
||||||
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
|
ImportNamedSymbolEntry entry;
|
||||||
|
GetEntry(i, entry);
|
||||||
|
VAddr patch_addr = entry.patch_batch_offset;
|
||||||
|
ExternalPatchEntry patch_entry;
|
||||||
|
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
||||||
|
|
||||||
|
ResultCode result = ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error reseting patch batch %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all imported indexed symbols of this module to unresolved state.
|
||||||
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
*/
|
||||||
|
ResultCode ResetImportIndexedSymbol() {
|
||||||
|
u32 unresolved_symbol = SegmentTagToAddress(GetField(OnUnresolvedSegmentTag));
|
||||||
|
|
||||||
|
u32 import_num = GetField(ImportIndexedSymbolNum);
|
||||||
|
for (u32 i = 0; i < import_num; ++i) {
|
||||||
|
ImportIndexedSymbolEntry entry;
|
||||||
|
GetEntry(i, entry);
|
||||||
|
VAddr patch_addr = entry.patch_batch_offset;
|
||||||
|
ExternalPatchEntry patch_entry;
|
||||||
|
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
||||||
|
|
||||||
|
ResultCode result = ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error reseting patch batch %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets all imported anonymous symbols of this module to unresolved state.
|
||||||
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
*/
|
||||||
|
ResultCode ResetImportAnonymousSymbol() {
|
||||||
|
u32 unresolved_symbol = SegmentTagToAddress(GetField(OnUnresolvedSegmentTag));
|
||||||
|
|
||||||
|
u32 import_num = GetField(ImportAnonymousSymbolNum);
|
||||||
|
for (u32 i = 0; i < import_num; ++i) {
|
||||||
|
ImportAnonymousSymbolEntry entry;
|
||||||
|
GetEntry(i, entry);
|
||||||
|
VAddr patch_addr = entry.patch_batch_offset;
|
||||||
|
ExternalPatchEntry patch_entry;
|
||||||
|
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
||||||
|
|
||||||
|
ResultCode result = ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error reseting patch batch %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds registered auto-link modules that this module imports, and resolves indexed and anonymous symbols exported by them.
|
* Finds registered auto-link modules that this module imports, and resolves indexed and anonymous symbols exported by them.
|
||||||
* @param crs_address the virtual address of the static module
|
* @param crs_address the virtual address of the static module
|
||||||
@ -1281,6 +1354,40 @@ class CROHelper final {
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets target's named symbols imported from this module to unresolved state.
|
||||||
|
* @param target the module to reset.
|
||||||
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
*/
|
||||||
|
ResultCode ResetExportNamedSymbol(CROHelper target) {
|
||||||
|
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"",
|
||||||
|
ModuleName().data(), target.ModuleName().data());
|
||||||
|
u32 unresolved_symbol = target.SegmentTagToAddress(target.GetField(OnUnresolvedSegmentTag));
|
||||||
|
u32 target_import_strings_size = target.GetField(ImportStringsSize);
|
||||||
|
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
||||||
|
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
||||||
|
ImportNamedSymbolEntry entry;
|
||||||
|
target.GetEntry(i, entry);
|
||||||
|
VAddr patch_addr = entry.patch_batch_offset;
|
||||||
|
ExternalPatchEntry patch_entry;
|
||||||
|
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
||||||
|
|
||||||
|
if (patch_entry.is_batch_resolved) {
|
||||||
|
std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
||||||
|
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
||||||
|
if (symbol_address) {
|
||||||
|
LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data());
|
||||||
|
ResultCode result = target.ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves imported indexed and anonymous symbols in the target module which imports this module.
|
* Resolves imported indexed and anonymous symbols in the target module which imports this module.
|
||||||
* @param target the module to resolve.
|
* @param target the module to resolve.
|
||||||
@ -1331,6 +1438,52 @@ class CROHelper final {
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets target's indexed and anonymous symbol imported from this module to unresolved state.
|
||||||
|
* @param target the module to reset.
|
||||||
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
*/
|
||||||
|
ResultCode ResetModuleExport(CROHelper target) {
|
||||||
|
u32 unresolved_symbol = target.SegmentTagToAddress(target.GetField(OnUnresolvedSegmentTag));
|
||||||
|
|
||||||
|
std::string module_name = ModuleName();
|
||||||
|
u32 target_import_string_size = target.GetField(ImportStringsSize);
|
||||||
|
u32 target_import_module_num = target.GetField(ImportModuleNum);
|
||||||
|
for (u32 i = 0; i < target_import_module_num; ++i) {
|
||||||
|
ImportModuleEntry entry;
|
||||||
|
target.GetEntry(i, entry);
|
||||||
|
|
||||||
|
if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports indexed symbols to \"%s\"",
|
||||||
|
module_name.data(), target.ModuleName().data());
|
||||||
|
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||||
|
ImportIndexedSymbolEntry im;
|
||||||
|
entry.GetImportIndexedSymbolEntry(j, im);
|
||||||
|
ResultCode result = target.ApplyPatchBatch(im.patch_batch_offset, unresolved_symbol, true);
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports anonymous symbols to \"%s\"",
|
||||||
|
module_name.data(), target.ModuleName().data());
|
||||||
|
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||||
|
ImportAnonymousSymbolEntry im;
|
||||||
|
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||||
|
ResultCode result = target.ApplyPatchBatch(im.patch_batch_offset, unresolved_symbol, true);
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the exit function in this module
|
* Resolves the exit function in this module
|
||||||
* @param crs_address the virtual address of the static module.
|
* @param crs_address the virtual address of the static module.
|
||||||
@ -1605,6 +1758,55 @@ public:
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlinks this module with other modules.
|
||||||
|
* @param crs_address the virtual address of the static module
|
||||||
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
*/
|
||||||
|
ResultCode Unlink(VAddr crs_address) {
|
||||||
|
|
||||||
|
// Resets all imported named symbols
|
||||||
|
ResultCode result = ResetImportNamedSymbol();
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error resetting symbol import %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets all imported indexed symbols
|
||||||
|
result = ResetImportIndexedSymbol();
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error resetting indexed import %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets all imported anonymous symbols
|
||||||
|
result = ResetImportAnonymousSymbol();
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error resetting anonymous import %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets all symbols in other modules imported from this module
|
||||||
|
// Note: the RO service seems only searching in auto-link modules
|
||||||
|
result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> {
|
||||||
|
ResultCode result = ResetExportNamedSymbol(target);
|
||||||
|
if (result.IsError())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = ResetModuleExport(target);
|
||||||
|
if (result.IsError())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return MakeResult<bool>(true);
|
||||||
|
});
|
||||||
|
if (result.IsError()) {
|
||||||
|
LOG_ERROR(Service_LDR, "Error resetting export %08X", result.raw);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all patches to zero.
|
* Clears all patches to zero.
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
|
Loading…
Reference in New Issue
Block a user