summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/ldr_ro
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/ldr_ro')
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.cpp1495
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.h714
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.cpp718
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.h22
-rw-r--r--src/core/hle/service/ldr_ro/memory_synchronizer.cpp42
-rw-r--r--src/core/hle/service/ldr_ro/memory_synchronizer.h42
6 files changed, 0 insertions, 3033 deletions
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp
deleted file mode 100644
index 6128f8a6c..000000000
--- a/src/core/hle/service/ldr_ro/cro_helper.cpp
+++ /dev/null
@@ -1,1495 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/alignment.h"
-#include "common/logging/log.h"
-#include "common/scope_exit.h"
-#include "core/hle/service/ldr_ro/cro_helper.h"
-
-namespace Service {
-namespace LDR {
-
-static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F
- ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument,
- ErrorLevel::Usage);
-
-static ResultCode CROFormatError(u32 description) {
- return ResultCode(static_cast<ErrorDescription>(description), ErrorModule::RO,
- ErrorSummary::WrongArgument, ErrorLevel::Permanent);
-}
-
-const std::array<int, 17> CROHelper::ENTRY_SIZE{{
- 1, // code
- 1, // data
- 1, // module name
- sizeof(SegmentEntry), sizeof(ExportNamedSymbolEntry), sizeof(ExportIndexedSymbolEntry),
- 1, // export strings
- sizeof(ExportTreeEntry), sizeof(ImportModuleEntry), sizeof(ExternalRelocationEntry),
- sizeof(ImportNamedSymbolEntry), sizeof(ImportIndexedSymbolEntry),
- sizeof(ImportAnonymousSymbolEntry),
- 1, // import strings
- sizeof(StaticAnonymousSymbolEntry), sizeof(InternalRelocationEntry),
- sizeof(StaticRelocationEntry),
-}};
-
-const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS{{
- Fix0Barrier, Fix1Barrier, Fix2Barrier, Fix3Barrier,
-}};
-
-VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const {
- u32 segment_num = GetField(SegmentNum);
-
- if (segment_tag.segment_index >= segment_num)
- return 0;
-
- SegmentEntry entry;
- GetEntry(segment_tag.segment_index, entry);
-
- if (segment_tag.offset_into_segment >= entry.size)
- return 0;
-
- return entry.offset + segment_tag.offset_into_segment;
-}
-
-ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType relocation_type,
- u32 addend, u32 symbol_address, u32 target_future_address) {
-
- switch (relocation_type) {
- case RelocationType::Nothing:
- break;
- case RelocationType::AbsoluteAddress:
- case RelocationType::AbsoluteAddress2:
- Memory::Write32(target_address, symbol_address + addend);
- break;
- case RelocationType::RelativeAddress:
- Memory::Write32(target_address, symbol_address + addend - target_future_address);
- break;
- case RelocationType::ThumbBranch:
- case RelocationType::ArmBranch:
- case RelocationType::ModifyArmBranch:
- case RelocationType::AlignedRelativeAddress:
- // TODO(wwylele): implement other types
- UNIMPLEMENTED();
- break;
- default:
- return CROFormatError(0x22);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType relocation_type) {
- switch (relocation_type) {
- case RelocationType::Nothing:
- break;
- case RelocationType::AbsoluteAddress:
- case RelocationType::AbsoluteAddress2:
- case RelocationType::RelativeAddress:
- Memory::Write32(target_address, 0);
- break;
- case RelocationType::ThumbBranch:
- case RelocationType::ArmBranch:
- case RelocationType::ModifyArmBranch:
- case RelocationType::AlignedRelativeAddress:
- // TODO(wwylele): implement other types
- UNIMPLEMENTED();
- break;
- default:
- return CROFormatError(0x22);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset) {
- if (symbol_address == 0 && !reset)
- return CROFormatError(0x10);
-
- VAddr relocation_address = batch;
- while (true) {
- RelocationEntry relocation;
- Memory::ReadBlock(relocation_address, &relocation, sizeof(RelocationEntry));
-
- VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
- if (relocation_target == 0) {
- return CROFormatError(0x12);
- }
-
- ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend,
- symbol_address, relocation_target);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
- return result;
- }
-
- if (relocation.is_batch_end)
- break;
-
- relocation_address += sizeof(RelocationEntry);
- }
-
- RelocationEntry relocation;
- Memory::ReadBlock(batch, &relocation, sizeof(RelocationEntry));
- relocation.is_batch_resolved = reset ? 0 : 1;
- Memory::WriteBlock(batch, &relocation, sizeof(RelocationEntry));
- return RESULT_SUCCESS;
-}
-
-VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
- if (!GetField(ExportTreeNum))
- return 0;
-
- std::size_t len = name.size();
- ExportTreeEntry entry;
- GetEntry(0, entry);
- ExportTreeEntry::Child next;
- next.raw = entry.left.raw;
- u32 found_id;
-
- while (true) {
- GetEntry(next.next_index, entry);
-
- if (next.is_end) {
- found_id = entry.export_table_index;
- break;
- }
-
- u16 test_byte = entry.test_bit >> 3;
- u16 test_bit_in_byte = entry.test_bit & 7;
-
- if (test_byte >= len) {
- next.raw = entry.left.raw;
- } else if ((name[test_byte] >> test_bit_in_byte) & 1) {
- next.raw = entry.right.raw;
- } else {
- next.raw = entry.left.raw;
- }
- }
-
- u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
-
- if (found_id >= export_named_symbol_num)
- return 0;
-
- u32 export_strings_size = GetField(ExportStringsSize);
- ExportNamedSymbolEntry symbol_entry;
- GetEntry(found_id, symbol_entry);
-
- if (Memory::ReadCString(symbol_entry.name_offset, export_strings_size) != name)
- return 0;
-
- return SegmentTagToAddress(symbol_entry.symbol_position);
-}
-
-ResultCode CROHelper::RebaseHeader(u32 cro_size) {
- ResultCode error = CROFormatError(0x11);
-
- // verifies magic
- if (GetField(Magic) != MAGIC_CRO0)
- return error;
-
- // verifies not registered
- if (GetField(NextCRO) != 0 || GetField(PreviousCRO) != 0)
- return error;
-
- // This seems to be a hard limit set by the RO module
- if (GetField(FileSize) > 0x10000000 || GetField(BssSize) > 0x10000000)
- return error;
-
- // verifies not fixed
- if (GetField(FixedSize) != 0)
- return error;
-
- if (GetField(CodeOffset) < CRO_HEADER_SIZE)
- return error;
-
- // verifies that all offsets are in the correct order
- constexpr std::array<HeaderField, 18> OFFSET_ORDER = {{
- CodeOffset, ModuleNameOffset, SegmentTableOffset, ExportNamedSymbolTableOffset,
- ExportTreeTableOffset, ExportIndexedSymbolTableOffset, ExportStringsOffset,
- ImportModuleTableOffset, ExternalRelocationTableOffset, ImportNamedSymbolTableOffset,
- ImportIndexedSymbolTableOffset, ImportAnonymousSymbolTableOffset, ImportStringsOffset,
- StaticAnonymousSymbolTableOffset, InternalRelocationTableOffset,
- StaticRelocationTableOffset, DataOffset, FileSize,
- }};
-
- u32 prev_offset = GetField(OFFSET_ORDER[0]);
- u32 cur_offset;
- for (std::size_t i = 1; i < OFFSET_ORDER.size(); ++i) {
- cur_offset = GetField(OFFSET_ORDER[i]);
- if (cur_offset < prev_offset)
- return error;
- prev_offset = cur_offset;
- }
-
- // rebases offsets
- u32 offset = GetField(NameOffset);
- if (offset != 0)
- SetField(NameOffset, offset + module_address);
-
- for (int field = CodeOffset; field < Fix0Barrier; field += 2) {
- HeaderField header_field = static_cast<HeaderField>(field);
- offset = GetField(header_field);
- if (offset != 0)
- SetField(header_field, offset + module_address);
- }
-
- // verifies everything is not beyond the buffer
- u32 file_end = module_address + cro_size;
- for (int field = CodeOffset, i = 0; field < Fix0Barrier; field += 2, ++i) {
- HeaderField offset_field = static_cast<HeaderField>(field);
- HeaderField size_field = static_cast<HeaderField>(field + 1);
- if (GetField(offset_field) + GetField(size_field) * ENTRY_SIZE[i] > file_end)
- return error;
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_address,
- u32 data_segment_size, VAddr bss_segment_address,
- u32 bss_segment_size) {
-
- u32 prev_data_segment = 0;
- u32 segment_num = GetField(SegmentNum);
- for (u32 i = 0; i < segment_num; ++i) {
- SegmentEntry segment;
- GetEntry(i, segment);
- if (segment.type == SegmentType::Data) {
- if (segment.size != 0) {
- if (segment.size > data_segment_size)
- return ERROR_BUFFER_TOO_SMALL;
- prev_data_segment = segment.offset;
- segment.offset = data_segment_address;
- }
- } else if (segment.type == SegmentType::BSS) {
- if (segment.size != 0) {
- if (segment.size > bss_segment_size)
- return ERROR_BUFFER_TOO_SMALL;
- segment.offset = bss_segment_address;
- }
- } else if (segment.offset != 0) {
- segment.offset += module_address;
- if (segment.offset > module_address + cro_size)
- return CROFormatError(0x19);
- }
- SetEntry(i, segment);
- }
- return MakeResult<VAddr>(prev_data_segment + module_address);
-}
-
-ResultCode CROHelper::RebaseExportNamedSymbolTable() {
- VAddr export_strings_offset = GetField(ExportStringsOffset);
- VAddr export_strings_end = export_strings_offset + GetField(ExportStringsSize);
-
- u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
- for (u32 i = 0; i < export_named_symbol_num; ++i) {
- ExportNamedSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.name_offset != 0) {
- entry.name_offset += module_address;
- if (entry.name_offset < export_strings_offset ||
- entry.name_offset >= export_strings_end) {
- return CROFormatError(0x11);
- }
- }
-
- SetEntry(i, entry);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::VerifyExportTreeTable() const {
- u32 tree_num = GetField(ExportTreeNum);
- for (u32 i = 0; i < tree_num; ++i) {
- ExportTreeEntry entry;
- GetEntry(i, entry);
-
- if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) {
- return CROFormatError(0x11);
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::RebaseImportModuleTable() {
- VAddr import_strings_offset = GetField(ImportStringsOffset);
- VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize);
- VAddr import_indexed_symbol_table_offset = GetField(ImportIndexedSymbolTableOffset);
- VAddr index_import_table_end =
- import_indexed_symbol_table_offset +
- GetField(ImportIndexedSymbolNum) * sizeof(ImportIndexedSymbolEntry);
- VAddr import_anonymous_symbol_table_offset = GetField(ImportAnonymousSymbolTableOffset);
- VAddr offset_import_table_end =
- import_anonymous_symbol_table_offset +
- GetField(ImportAnonymousSymbolNum) * sizeof(ImportAnonymousSymbolEntry);
-
- u32 module_num = GetField(ImportModuleNum);
- for (u32 i = 0; i < module_num; ++i) {
- ImportModuleEntry entry;
- GetEntry(i, entry);
-
- if (entry.name_offset != 0) {
- entry.name_offset += module_address;
- if (entry.name_offset < import_strings_offset ||
- entry.name_offset >= import_strings_end) {
- return CROFormatError(0x18);
- }
- }
-
- if (entry.import_indexed_symbol_table_offset != 0) {
- entry.import_indexed_symbol_table_offset += module_address;
- if (entry.import_indexed_symbol_table_offset < import_indexed_symbol_table_offset ||
- entry.import_indexed_symbol_table_offset > index_import_table_end) {
- return CROFormatError(0x18);
- }
- }
-
- if (entry.import_anonymous_symbol_table_offset != 0) {
- entry.import_anonymous_symbol_table_offset += module_address;
- if (entry.import_anonymous_symbol_table_offset < import_anonymous_symbol_table_offset ||
- entry.import_anonymous_symbol_table_offset > offset_import_table_end) {
- return CROFormatError(0x18);
- }
- }
-
- SetEntry(i, entry);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::RebaseImportNamedSymbolTable() {
- VAddr import_strings_offset = GetField(ImportStringsOffset);
- VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize);
- VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
- VAddr external_relocation_table_end =
- external_relocation_table_offset +
- GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
-
- u32 num = GetField(ImportNamedSymbolNum);
- for (u32 i = 0; i < num; ++i) {
- ImportNamedSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.name_offset != 0) {
- entry.name_offset += module_address;
- if (entry.name_offset < import_strings_offset ||
- entry.name_offset >= import_strings_end) {
- return CROFormatError(0x1B);
- }
- }
-
- if (entry.relocation_batch_offset != 0) {
- entry.relocation_batch_offset += module_address;
- if (entry.relocation_batch_offset < external_relocation_table_offset ||
- entry.relocation_batch_offset > external_relocation_table_end) {
- return CROFormatError(0x1B);
- }
- }
-
- SetEntry(i, entry);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
- VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
- VAddr external_relocation_table_end =
- external_relocation_table_offset +
- GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
-
- u32 num = GetField(ImportIndexedSymbolNum);
- for (u32 i = 0; i < num; ++i) {
- ImportIndexedSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.relocation_batch_offset != 0) {
- entry.relocation_batch_offset += module_address;
- if (entry.relocation_batch_offset < external_relocation_table_offset ||
- entry.relocation_batch_offset > external_relocation_table_end) {
- return CROFormatError(0x14);
- }
- }
-
- SetEntry(i, entry);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
- VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
- VAddr external_relocation_table_end =
- external_relocation_table_offset +
- GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
-
- u32 num = GetField(ImportAnonymousSymbolNum);
- for (u32 i = 0; i < num; ++i) {
- ImportAnonymousSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.relocation_batch_offset != 0) {
- entry.relocation_batch_offset += module_address;
- if (entry.relocation_batch_offset < external_relocation_table_offset ||
- entry.relocation_batch_offset > external_relocation_table_end) {
- return CROFormatError(0x17);
- }
- }
-
- SetEntry(i, entry);
- }
- return RESULT_SUCCESS;
-}
-
-VAddr CROHelper::GetOnUnresolvedAddress() {
- return SegmentTagToAddress(SegmentTag(GetField(OnUnresolvedSegmentTag)));
-}
-
-ResultCode CROHelper::ResetExternalRelocations() {
- u32 unresolved_symbol = GetOnUnresolvedAddress();
- u32 external_relocation_num = GetField(ExternalRelocationNum);
- ExternalRelocationEntry relocation;
-
- // Verifies that the last relocation is the end of a batch
- GetEntry(external_relocation_num - 1, relocation);
- if (!relocation.is_batch_end) {
- return CROFormatError(0x12);
- }
-
- bool batch_begin = true;
- for (u32 i = 0; i < external_relocation_num; ++i) {
- GetEntry(i, relocation);
- VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
-
- if (relocation_target == 0) {
- return CROFormatError(0x12);
- }
-
- ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend,
- unresolved_symbol, relocation_target);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
- return result;
- }
-
- if (batch_begin) {
- // resets to unresolved state
- relocation.is_batch_resolved = 0;
- SetEntry(i, relocation);
- }
-
- // if current is an end, then the next is a beginning
- batch_begin = relocation.is_batch_end != 0;
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ClearExternalRelocations() {
- u32 external_relocation_num = GetField(ExternalRelocationNum);
- ExternalRelocationEntry relocation;
-
- bool batch_begin = true;
- for (u32 i = 0; i < external_relocation_num; ++i) {
- GetEntry(i, relocation);
- VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
-
- if (relocation_target == 0) {
- return CROFormatError(0x12);
- }
-
- ResultCode result = ClearRelocation(relocation_target, relocation.type);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw);
- return result;
- }
-
- if (batch_begin) {
- // resets to unresolved state
- relocation.is_batch_resolved = 0;
- SetEntry(i, relocation);
- }
-
- // if current is an end, then the next is a beginning
- batch_begin = relocation.is_batch_end != 0;
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
- VAddr static_relocation_table_offset = GetField(StaticRelocationTableOffset);
- VAddr static_relocation_table_end =
- static_relocation_table_offset +
- GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
-
- CROHelper crs(crs_address);
- u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
- LOG_INFO(Service_LDR, "CRO \"%s\" exports %d static anonymous symbols", ModuleName().data(),
- offset_export_num);
- for (u32 i = 0; i < offset_export_num; ++i) {
- StaticAnonymousSymbolEntry entry;
- GetEntry(i, entry);
- u32 batch_address = entry.relocation_batch_offset + module_address;
-
- if (batch_address < static_relocation_table_offset ||
- batch_address > static_relocation_table_end) {
- return CROFormatError(0x16);
- }
-
- u32 symbol_address = SegmentTagToAddress(entry.symbol_position);
- LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module",
- ModuleName().data(), symbol_address);
- ResultCode result = crs.ApplyRelocationBatch(batch_address, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
- u32 segment_num = GetField(SegmentNum);
- u32 internal_relocation_num = GetField(InternalRelocationNum);
- for (u32 i = 0; i < internal_relocation_num; ++i) {
- InternalRelocationEntry relocation;
- GetEntry(i, relocation);
- VAddr target_addressB = SegmentTagToAddress(relocation.target_position);
- if (target_addressB == 0) {
- return CROFormatError(0x15);
- }
-
- VAddr target_address;
- SegmentEntry target_segment;
- GetEntry(relocation.target_position.segment_index, target_segment);
-
- if (target_segment.type == SegmentType::Data) {
- // If the relocation is to the .data segment, we need to relocate it in the old buffer
- target_address =
- old_data_segment_address + relocation.target_position.offset_into_segment;
- } else {
- target_address = target_addressB;
- }
-
- if (relocation.symbol_segment >= segment_num) {
- return CROFormatError(0x15);
- }
-
- SegmentEntry symbol_segment;
- GetEntry(relocation.symbol_segment, symbol_segment);
- LOG_TRACE(Service_LDR, "Internally relocates 0x%08X with 0x%08X", target_address,
- symbol_segment.offset);
- ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend,
- symbol_segment.offset, target_addressB);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ClearInternalRelocations() {
- u32 internal_relocation_num = GetField(InternalRelocationNum);
- for (u32 i = 0; i < internal_relocation_num; ++i) {
- InternalRelocationEntry relocation;
- GetEntry(i, relocation);
- VAddr target_address = SegmentTagToAddress(relocation.target_position);
-
- if (target_address == 0) {
- return CROFormatError(0x15);
- }
-
- ResultCode result = ClearRelocation(target_address, relocation.type);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw);
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-void CROHelper::UnrebaseImportAnonymousSymbolTable() {
- u32 num = GetField(ImportAnonymousSymbolNum);
- for (u32 i = 0; i < num; ++i) {
- ImportAnonymousSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.relocation_batch_offset != 0) {
- entry.relocation_batch_offset -= module_address;
- }
-
- SetEntry(i, entry);
- }
-}
-
-void CROHelper::UnrebaseImportIndexedSymbolTable() {
- u32 num = GetField(ImportIndexedSymbolNum);
- for (u32 i = 0; i < num; ++i) {
- ImportIndexedSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.relocation_batch_offset != 0) {
- entry.relocation_batch_offset -= module_address;
- }
-
- SetEntry(i, entry);
- }
-}
-
-void CROHelper::UnrebaseImportNamedSymbolTable() {
- u32 num = GetField(ImportNamedSymbolNum);
- for (u32 i = 0; i < num; ++i) {
- ImportNamedSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.name_offset != 0) {
- entry.name_offset -= module_address;
- }
-
- if (entry.relocation_batch_offset) {
- entry.relocation_batch_offset -= module_address;
- }
-
- SetEntry(i, entry);
- }
-}
-
-void CROHelper::UnrebaseImportModuleTable() {
- u32 module_num = GetField(ImportModuleNum);
- for (u32 i = 0; i < module_num; ++i) {
- ImportModuleEntry entry;
- GetEntry(i, entry);
-
- if (entry.name_offset != 0) {
- entry.name_offset -= module_address;
- }
-
- if (entry.import_indexed_symbol_table_offset) {
- entry.import_indexed_symbol_table_offset -= module_address;
- }
-
- if (entry.import_anonymous_symbol_table_offset) {
- entry.import_anonymous_symbol_table_offset -= module_address;
- }
-
- SetEntry(i, entry);
- }
-}
-
-void CROHelper::UnrebaseExportNamedSymbolTable() {
- u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
- for (u32 i = 0; i < export_named_symbol_num; ++i) {
- ExportNamedSymbolEntry entry;
- GetEntry(i, entry);
-
- if (entry.name_offset != 0) {
- entry.name_offset -= module_address;
- }
-
- SetEntry(i, entry);
- }
-}
-
-void CROHelper::UnrebaseSegmentTable() {
- u32 segment_num = GetField(SegmentNum);
- for (u32 i = 0; i < segment_num; ++i) {
- SegmentEntry segment;
- GetEntry(i, segment);
-
- if (segment.type == SegmentType::BSS) {
- segment.offset = 0;
- } else if (segment.offset != 0) {
- segment.offset -= module_address;
- }
-
- SetEntry(i, segment);
- }
-}
-
-void CROHelper::UnrebaseHeader() {
- u32 offset = GetField(NameOffset);
- if (offset != 0)
- SetField(NameOffset, offset - module_address);
-
- for (int field = CodeOffset; field < Fix0Barrier; field += 2) {
- HeaderField header_field = static_cast<HeaderField>(field);
- offset = GetField(header_field);
- if (offset != 0)
- SetField(header_field, offset - module_address);
- }
-}
-
-ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
- u32 import_strings_size = GetField(ImportStringsSize);
- u32 symbol_import_num = GetField(ImportNamedSymbolNum);
- for (u32 i = 0; i < symbol_import_num; ++i) {
- ImportNamedSymbolEntry entry;
- GetEntry(i, entry);
- VAddr relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- if (!relocation_entry.is_batch_resolved) {
- ResultCode result =
- ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
- std::string symbol_name =
- Memory::ReadCString(entry.name_offset, import_strings_size);
- u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
-
- if (symbol_address != 0) {
- LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"",
- ModuleName().data(), symbol_name.data(),
- source.ModuleName().data());
-
- ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
- result.raw);
- return result;
- }
-
- return MakeResult<bool>(false);
- }
-
- return MakeResult<bool>(true);
- });
- if (result.IsError()) {
- return result;
- }
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ResetImportNamedSymbol() {
- u32 unresolved_symbol = GetOnUnresolvedAddress();
-
- u32 symbol_import_num = GetField(ImportNamedSymbolNum);
- for (u32 i = 0; i < symbol_import_num; ++i) {
- ImportNamedSymbolEntry entry;
- GetEntry(i, entry);
- VAddr relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ResetImportIndexedSymbol() {
- u32 unresolved_symbol = GetOnUnresolvedAddress();
-
- u32 import_num = GetField(ImportIndexedSymbolNum);
- for (u32 i = 0; i < import_num; ++i) {
- ImportIndexedSymbolEntry entry;
- GetEntry(i, entry);
- VAddr relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ResetImportAnonymousSymbol() {
- u32 unresolved_symbol = GetOnUnresolvedAddress();
-
- u32 import_num = GetField(ImportAnonymousSymbolNum);
- for (u32 i = 0; i < import_num; ++i) {
- ImportAnonymousSymbolEntry entry;
- GetEntry(i, entry);
- VAddr relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
- u32 import_strings_size = GetField(ImportStringsSize);
-
- u32 import_module_num = GetField(ImportModuleNum);
- for (u32 i = 0; i < import_module_num; ++i) {
- ImportModuleEntry entry;
- GetEntry(i, entry);
- std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size);
-
- ResultCode result =
- ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
- if (want_cro_name == source.ModuleName()) {
- LOG_INFO(Service_LDR, "CRO \"%s\" imports %d indexed symbols from \"%s\"",
- ModuleName().data(), entry.import_indexed_symbol_num,
- source.ModuleName().data());
- for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
- ImportIndexedSymbolEntry im;
- entry.GetImportIndexedSymbolEntry(j, im);
- ExportIndexedSymbolEntry ex;
- source.GetEntry(im.index, ex);
- u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
- LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
- ResultCode result =
- ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
- result.raw);
- return result;
- }
- }
- LOG_INFO(Service_LDR, "CRO \"%s\" imports %d anonymous symbols from \"%s\"",
- ModuleName().data(), entry.import_anonymous_symbol_num,
- source.ModuleName().data());
- for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
- ImportAnonymousSymbolEntry im;
- entry.GetImportAnonymousSymbolEntry(j, im);
- u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
- LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
- ResultCode result =
- ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
- result.raw);
- return result;
- }
- }
- return MakeResult<bool>(false);
- }
- return MakeResult<bool>(true);
- });
- if (result.IsError()) {
- return result;
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
- LOG_DEBUG(Service_LDR, "CRO \"%s\" exports named symbols to \"%s\"", ModuleName().data(),
- target.ModuleName().data());
- 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 relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- if (!relocation_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 != 0) {
- LOG_TRACE(Service_LDR, " exports symbol \"%s\"", symbol_name.data());
- ResultCode result = target.ApplyRelocationBatch(relocation_addr, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
- return result;
- }
- }
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
- LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"", ModuleName().data(),
- target.ModuleName().data());
- u32 unresolved_symbol = target.GetOnUnresolvedAddress();
- 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 relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- if (relocation_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 != 0) {
- LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data());
- ResultCode result =
- target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
- return result;
- }
- }
- }
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
- 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_INFO(Service_LDR, "CRO \"%s\" exports %d indexed symbols to \"%s\"", module_name.data(),
- entry.import_indexed_symbol_num, target.ModuleName().data());
- for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
- ImportIndexedSymbolEntry im;
- entry.GetImportIndexedSymbolEntry(j, im);
- ExportIndexedSymbolEntry ex;
- GetEntry(im.index, ex);
- u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
- LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
- ResultCode result =
- target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
- return result;
- }
- }
-
- LOG_INFO(Service_LDR, "CRO \"%s\" exports %d anonymous symbols to \"%s\"",
- module_name.data(), entry.import_anonymous_symbol_num, target.ModuleName().data());
- for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
- ImportAnonymousSymbolEntry im;
- entry.GetImportAnonymousSymbolEntry(j, im);
- u32 symbol_address = SegmentTagToAddress(im.symbol_position);
- LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
- ResultCode result =
- target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
- return result;
- }
- }
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ResetModuleExport(CROHelper target) {
- u32 unresolved_symbol = target.GetOnUnresolvedAddress();
-
- 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.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation 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.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
- return result;
- }
- }
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
- u32 import_strings_size = GetField(ImportStringsSize);
- u32 symbol_import_num = GetField(ImportNamedSymbolNum);
- for (u32 i = 0; i < symbol_import_num; ++i) {
- ImportNamedSymbolEntry entry;
- GetEntry(i, entry);
- VAddr relocation_addr = entry.relocation_batch_offset;
- ExternalRelocationEntry relocation_entry;
- Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
-
- if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
- ResultCode result =
- ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
- u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
-
- if (symbol_address != 0) {
- LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"",
- ModuleName().data(), source.ModuleName().data());
-
- ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
- result.raw);
- return result;
- }
-
- return MakeResult<bool>(false);
- }
-
- return MakeResult<bool>(true);
- });
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying exit relocation %08X", result.raw);
- return result;
- }
- }
- }
- return RESULT_SUCCESS;
-}
-
-/**
- * Verifies a string or a string table matching a predicted size (i.e. terminated by 0)
- * if it is not empty. There can be many other nulls in the string table because
- * they are composed by many sub strings. This function is to check whether the
- * whole string (table) is terminated properly, despite that it is not actually one string.
- * @param address the virtual address of the string (table)
- * @param size the size of the string (table), including the terminating 0
- * @returns ResultCode RESULT_SUCCESS if the size matches, otherwise error code.
- */
-static ResultCode VerifyStringTableLength(VAddr address, u32 size) {
- if (size != 0) {
- if (Memory::Read8(address + size - 1) != 0)
- return CROFormatError(0x0B);
- }
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_addresss,
- u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size,
- bool is_crs) {
-
- ResultCode result = RebaseHeader(cro_size);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing header %08X", result.raw);
- return result;
- }
-
- result = VerifyStringTableLength(GetField(ModuleNameOffset), GetField(ModuleNameSize));
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error verifying module name %08X", result.raw);
- return result;
- }
-
- u32 prev_data_segment_address = 0;
- if (!is_crs) {
- auto result_val = RebaseSegmentTable(cro_size, data_segment_addresss, data_segment_size,
- bss_segment_address, bss_segment_size);
- if (result_val.Failed()) {
- LOG_ERROR(Service_LDR, "Error rebasing segment table %08X", result_val.Code().raw);
- return result_val.Code();
- }
- prev_data_segment_address = *result_val;
- }
-
- result = RebaseExportNamedSymbolTable();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing symbol export table %08X", result.raw);
- return result;
- }
-
- result = VerifyExportTreeTable();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error verifying export tree %08X", result.raw);
- return result;
- }
-
- result = VerifyStringTableLength(GetField(ExportStringsOffset), GetField(ExportStringsSize));
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error verifying export strings %08X", result.raw);
- return result;
- }
-
- result = RebaseImportModuleTable();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing object table %08X", result.raw);
- return result;
- }
-
- result = ResetExternalRelocations();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error resetting all external relocations %08X", result.raw);
- return result;
- }
-
- result = RebaseImportNamedSymbolTable();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing symbol import table %08X", result.raw);
- return result;
- }
-
- result = RebaseImportIndexedSymbolTable();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing index import table %08X", result.raw);
- return result;
- }
-
- result = RebaseImportAnonymousSymbolTable();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing offset import table %08X", result.raw);
- return result;
- }
-
- result = VerifyStringTableLength(GetField(ImportStringsOffset), GetField(ImportStringsSize));
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error verifying import strings %08X", result.raw);
- return result;
- }
-
- if (!is_crs) {
- result = ApplyStaticAnonymousSymbolToCRS(crs_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying offset export to CRS %08X", result.raw);
- return result;
- }
- }
-
- result = ApplyInternalRelocations(prev_data_segment_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying internal relocations %08X", result.raw);
- return result;
- }
-
- if (!is_crs) {
- result = ApplyExitRelocations(crs_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying exit relocations %08X", result.raw);
- return result;
- }
- }
-
- return RESULT_SUCCESS;
-}
-
-void CROHelper::Unrebase(bool is_crs) {
- UnrebaseImportAnonymousSymbolTable();
- UnrebaseImportIndexedSymbolTable();
- UnrebaseImportNamedSymbolTable();
- UnrebaseImportModuleTable();
- UnrebaseExportNamedSymbolTable();
-
- if (!is_crs)
- UnrebaseSegmentTable();
-
- SetNextModule(0);
- SetPreviousModule(0);
-
- SetField(FixedSize, 0);
-
- UnrebaseHeader();
-}
-
-ResultCode CROHelper::VerifyHash(u32 cro_size, VAddr crr) const {
- // TODO(wwylele): actually verify the hash
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
- ResultCode result = RESULT_SUCCESS;
-
- {
- VAddr data_segment_address;
- if (link_on_load_bug_fix) {
- // this is a bug fix introduced by 7.2.0-17's LoadCRO_New
- // The bug itself is:
- // If a relocation target is in .data segment, it will relocate to the
- // user-specified buffer. But if this is linking during loading,
- // the .data segment hasn't been transfer from CRO to the buffer,
- // thus the relocation will be overwritten by data transfer.
- // To fix this bug, we need temporarily restore the old .data segment
- // offset and apply imported symbols.
-
- // RO service seems assuming segment_index == segment_type,
- // so we do the same
- if (GetField(SegmentNum) >= 2) { // means we have .data segment
- SegmentEntry entry;
- GetEntry(2, entry);
- ASSERT(entry.type == SegmentType::Data);
- data_segment_address = entry.offset;
- entry.offset = GetField(DataOffset);
- SetEntry(2, entry);
- }
- }
- SCOPE_EXIT({
- // Restore the new .data segment address after importing
- if (link_on_load_bug_fix) {
- if (GetField(SegmentNum) >= 2) {
- SegmentEntry entry;
- GetEntry(2, entry);
- entry.offset = data_segment_address;
- SetEntry(2, entry);
- }
- }
- });
-
- // Imports named symbols from other modules
- result = ApplyImportNamedSymbol(crs_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying symbol import %08X", result.raw);
- return result;
- }
-
- // Imports indexed and anonymous symbols from other modules
- result = ApplyModuleImport(crs_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying module import %08X", result.raw);
- return result;
- }
- }
-
- // Exports symbols to other modules
- result = ForEachAutoLinkCRO(crs_address, [this](CROHelper target) -> ResultVal<bool> {
- ResultCode result = ApplyExportNamedSymbol(target);
- if (result.IsError())
- return result;
-
- result = ApplyModuleExport(target);
- if (result.IsError())
- return result;
-
- return MakeResult<bool>(true);
- });
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error applying export %08X", result.raw);
- return result;
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultCode CROHelper::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;
-}
-
-ResultCode CROHelper::ClearRelocations() {
- ResultCode result = ClearExternalRelocations();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error clearing external relocations %08X", result.raw);
- return result;
- }
-
- result = ClearInternalRelocations();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error clearing internal relocations %08X", result.raw);
- return result;
- }
- return RESULT_SUCCESS;
-}
-
-void CROHelper::InitCRS() {
- SetNextModule(0);
- SetPreviousModule(0);
-}
-
-void CROHelper::Register(VAddr crs_address, bool auto_link) {
- CROHelper crs(crs_address);
- CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule());
-
- if (head.module_address) {
- // there are already CROs registered
- // register as the new tail
- CROHelper tail(head.PreviousModule());
-
- // link with the old tail
- ASSERT(tail.NextModule() == 0);
- SetPreviousModule(tail.module_address);
- tail.SetNextModule(module_address);
-
- // set previous of the head pointing to the new tail
- head.SetPreviousModule(module_address);
- } else {
- // register as the first CRO
- // set previous to self as tail
- SetPreviousModule(module_address);
-
- // set self as head
- if (auto_link)
- crs.SetNextModule(module_address);
- else
- crs.SetPreviousModule(module_address);
- }
-
- // the new one is the tail
- SetNextModule(0);
-}
-
-void CROHelper::Unregister(VAddr crs_address) {
- CROHelper crs(crs_address);
- CROHelper next_head(crs.NextModule()), previous_head(crs.PreviousModule());
- CROHelper next(NextModule()), previous(PreviousModule());
-
- if (module_address == next_head.module_address ||
- module_address == previous_head.module_address) {
- // removing head
- if (next.module_address) {
- // the next is new head
- // let its previous point to the tail
- next.SetPreviousModule(previous.module_address);
- }
-
- // set new head
- if (module_address == previous_head.module_address) {
- crs.SetPreviousModule(next.module_address);
- } else {
- crs.SetNextModule(next.module_address);
- }
- } else if (next.module_address) {
- // link previous and next
- previous.SetNextModule(next.module_address);
- next.SetPreviousModule(previous.module_address);
- } else {
- // removing tail
- // set previous as new tail
- previous.SetNextModule(0);
-
- // let head's previous point to the new tail
- if (next_head.module_address && next_head.PreviousModule() == module_address) {
- next_head.SetPreviousModule(previous.module_address);
- } else if (previous_head.module_address &&
- previous_head.PreviousModule() == module_address) {
- previous_head.SetPreviousModule(previous.module_address);
- } else {
- UNREACHABLE();
- }
- }
-
- // unlink self
- SetNextModule(0);
- SetPreviousModule(0);
-}
-
-u32 CROHelper::GetFixEnd(u32 fix_level) const {
- u32 end = CRO_HEADER_SIZE;
- end = std::max<u32>(end, GetField(CodeOffset) + GetField(CodeSize));
-
- u32 entry_size_i = 2;
- int field = ModuleNameOffset;
- while (true) {
- end = std::max<u32>(end, GetField(static_cast<HeaderField>(field)) +
- GetField(static_cast<HeaderField>(field + 1)) *
- ENTRY_SIZE[entry_size_i]);
-
- ++entry_size_i;
- field += 2;
-
- if (field == FIX_BARRIERS[fix_level])
- return end;
- }
-}
-
-u32 CROHelper::Fix(u32 fix_level) {
- u32 fix_end = GetFixEnd(fix_level);
-
- if (fix_level != 0) {
- SetField(Magic, MAGIC_FIXD);
-
- for (int field = FIX_BARRIERS[fix_level]; field < Fix0Barrier; field += 2) {
- SetField(static_cast<HeaderField>(field), fix_end);
- SetField(static_cast<HeaderField>(field + 1), 0);
- }
- }
-
- fix_end = Common::AlignUp(fix_end, Memory::PAGE_SIZE);
-
- u32 fixed_size = fix_end - module_address;
- SetField(FixedSize, fixed_size);
- return fixed_size;
-}
-
-bool CROHelper::IsLoaded() const {
- u32 magic = GetField(Magic);
- if (magic != MAGIC_CRO0 && magic != MAGIC_FIXD)
- return false;
-
- // TODO(wwylele): verify memory state here after memory aliasing is implemented
-
- return true;
-}
-
-std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
- u32 segment_num = GetField(SegmentNum);
- for (u32 i = 0; i < segment_num; ++i) {
- SegmentEntry entry;
- GetEntry(i, entry);
- if (entry.type == SegmentType::Code && entry.size != 0) {
- VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
- VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);
- return std::make_tuple(begin, end - begin);
- }
- }
- return std::make_tuple(0, 0);
-}
-
-} // namespace LDR
-} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h
deleted file mode 100644
index 57b4fb6df..000000000
--- a/src/core/hle/service/ldr_ro/cro_helper.h
+++ /dev/null
@@ -1,714 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <array>
-#include <tuple>
-#include "common/common_types.h"
-#include "common/swap.h"
-#include "core/hle/result.h"
-#include "core/memory.h"
-
-namespace Service {
-namespace LDR {
-
-// GCC versions < 5.0 do not implement std::is_trivially_copyable.
-// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
-#if (__GNUC__ >= 5) || defined(__clang__)
-#define ASSERT_CRO_STRUCT(name, size) \
- static_assert(std::is_standard_layout<name>::value, \
- "CRO structure " #name " doesn't use standard layout"); \
- static_assert(std::is_trivially_copyable<name>::value, \
- "CRO structure " #name " isn't trivially copyable"); \
- static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name)
-#else
-#define ASSERT_CRO_STRUCT(name, size) \
- static_assert(std::is_standard_layout<name>::value, \
- "CRO structure " #name " doesn't use standard layout"); \
- static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name)
-#endif
-
-static constexpr u32 CRO_HEADER_SIZE = 0x138;
-static constexpr u32 CRO_HASH_SIZE = 0x80;
-
-/// Represents a loaded module (CRO) with interfaces manipulating it.
-class CROHelper final {
-public:
- explicit CROHelper(VAddr cro_address) : module_address(cro_address) {}
-
- std::string ModuleName() const {
- return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
- }
-
- u32 GetFileSize() const {
- return GetField(FileSize);
- }
-
- /**
- * Rebases the module according to its address.
- * @param crs_address the virtual address of the static module
- * @param cro_size the size of the CRO file
- * @param data_segment_address buffer address for .data segment
- * @param data_segment_size the buffer size for .data segment
- * @param bss_segment_address the buffer address for .bss segment
- * @param bss_segment_size the buffer size for .bss segment
- * @param is_crs true if the module itself is the static module
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_address,
- u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size,
- bool is_crs);
-
- /**
- * Unrebases the module.
- * @param is_crs true if the module itself is the static module
- */
- void Unrebase(bool is_crs);
-
- /**
- * Verifies module hash by CRR.
- * @param cro_size the size of the CRO
- * @param crr the virtual address of the CRR
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode VerifyHash(u32 cro_size, VAddr crr) const;
-
- /**
- * Links this module with all registered auto-link module.
- * @param crs_address the virtual address of the static module
- * @param link_on_load_bug_fix true if links when loading and fixes the bug
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode Link(VAddr crs_address, bool link_on_load_bug_fix);
-
- /**
- * 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);
-
- /**
- * Clears all relocations to zero.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ClearRelocations();
-
- /// Initialize this module as the static module (CRS)
- void InitCRS();
-
- /**
- * Registers this module and adds it to the module list.
- * @param crs_address the virtual address of the static module
- * @param auto_link whether to register as an auto link module
- */
- void Register(VAddr crs_address, bool auto_link);
-
- /**
- * Unregisters this module and removes from the module list.
- * @param crs_address the virtual address of the static module
- */
- void Unregister(VAddr crs_address);
-
- /**
- * Gets the end of reserved data according to the fix level.
- * @param fix_level fix level from 0 to 3
- * @returns the end of reserved data.
- */
- u32 GetFixEnd(u32 fix_level) const;
-
- /**
- * Zeros offsets to cropped data according to the fix level and marks as fixed.
- * @param fix_level fix level from 0 to 3
- * @returns page-aligned size of the module after fixing.
- */
- u32 Fix(u32 fix_level);
-
- bool IsFixed() const {
- return GetField(Magic) == MAGIC_FIXD;
- }
-
- u32 GetFixedSize() const {
- return GetField(FixedSize);
- }
-
- bool IsLoaded() const;
-
- /**
- * Gets the page address and size of the code segment.
- * @returns a tuple of (address, size); (0, 0) if the code segment doesn't exist.
- */
- std::tuple<VAddr, u32> GetExecutablePages() const;
-
-private:
- const VAddr module_address; ///< the virtual address of this module
-
- /**
- * Each item in this enum represents a u32 field in the header begin from address+0x80,
- * successively. We don't directly use a struct here, to avoid GetPointer, reinterpret_cast, or
- * Read/WriteBlock repeatedly.
- */
- enum HeaderField {
- Magic = 0,
- NameOffset,
- NextCRO,
- PreviousCRO,
- FileSize,
- BssSize,
- FixedSize,
- UnknownZero,
- UnkSegmentTag,
- OnLoadSegmentTag,
- OnExitSegmentTag,
- OnUnresolvedSegmentTag,
-
- CodeOffset,
- CodeSize,
- DataOffset,
- DataSize,
- ModuleNameOffset,
- ModuleNameSize,
- SegmentTableOffset,
- SegmentNum,
-
- ExportNamedSymbolTableOffset,
- ExportNamedSymbolNum,
- ExportIndexedSymbolTableOffset,
- ExportIndexedSymbolNum,
- ExportStringsOffset,
- ExportStringsSize,
- ExportTreeTableOffset,
- ExportTreeNum,
-
- ImportModuleTableOffset,
- ImportModuleNum,
- ExternalRelocationTableOffset,
- ExternalRelocationNum,
- ImportNamedSymbolTableOffset,
- ImportNamedSymbolNum,
- ImportIndexedSymbolTableOffset,
- ImportIndexedSymbolNum,
- ImportAnonymousSymbolTableOffset,
- ImportAnonymousSymbolNum,
- ImportStringsOffset,
- ImportStringsSize,
-
- StaticAnonymousSymbolTableOffset,
- StaticAnonymousSymbolNum,
- InternalRelocationTableOffset,
- InternalRelocationNum,
- StaticRelocationTableOffset,
- StaticRelocationNum,
- Fix0Barrier,
-
- Fix3Barrier = ExportNamedSymbolTableOffset,
- Fix2Barrier = ImportModuleTableOffset,
- Fix1Barrier = StaticAnonymousSymbolTableOffset,
- };
- static_assert(Fix0Barrier == (CRO_HEADER_SIZE - CRO_HASH_SIZE) / 4,
- "CRO Header fields are wrong!");
-
- enum class SegmentType : u32 {
- Code = 0,
- ROData = 1,
- Data = 2,
- BSS = 3,
- };
-
- /**
- * Identifies a program location inside of a segment.
- * Required to refer to program locations because individual segments may be relocated
- * independently of each other.
- */
- union SegmentTag {
- u32_le raw;
- BitField<0, 4, u32_le> segment_index;
- BitField<4, 28, u32_le> offset_into_segment;
-
- SegmentTag() = default;
- explicit SegmentTag(u32 raw_) : raw(raw_) {}
- };
-
- /// Information of a segment in this module.
- struct SegmentEntry {
- u32_le offset;
- u32_le size;
- SegmentType type;
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = SegmentTableOffset;
- };
- ASSERT_CRO_STRUCT(SegmentEntry, 12);
-
- /// Identifies a named symbol exported from this module.
- struct ExportNamedSymbolEntry {
- u32_le name_offset; // pointing to a substring in ExportStrings
- SegmentTag symbol_position; // to self's segment
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ExportNamedSymbolTableOffset;
- };
- ASSERT_CRO_STRUCT(ExportNamedSymbolEntry, 8);
-
- /// Identifies an indexed symbol exported from this module.
- struct ExportIndexedSymbolEntry {
- SegmentTag symbol_position; // to self's segment
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ExportIndexedSymbolTableOffset;
- };
- ASSERT_CRO_STRUCT(ExportIndexedSymbolEntry, 4);
-
- /// A tree node in the symbol lookup tree.
- struct ExportTreeEntry {
- u16_le test_bit; // bit address into the name to test
- union Child {
- u16_le raw;
- BitField<0, 15, u16_le> next_index;
- BitField<15, 1, u16_le> is_end;
- } left, right;
- u16_le export_table_index; // index of an ExportNamedSymbolEntry
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ExportTreeTableOffset;
- };
- ASSERT_CRO_STRUCT(ExportTreeEntry, 8);
-
- /// Identifies a named symbol imported from another module.
- struct ImportNamedSymbolEntry {
- u32_le name_offset; // pointing to a substring in ImportStrings
- u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset;
- };
- ASSERT_CRO_STRUCT(ImportNamedSymbolEntry, 8);
-
- /// Identifies an indexed symbol imported from another module.
- struct ImportIndexedSymbolEntry {
- u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module
- u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset;
- };
- ASSERT_CRO_STRUCT(ImportIndexedSymbolEntry, 8);
-
- /// Identifies an anonymous symbol imported from another module.
- struct ImportAnonymousSymbolEntry {
- SegmentTag symbol_position; // in the exporting segment
- u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset;
- };
- ASSERT_CRO_STRUCT(ImportAnonymousSymbolEntry, 8);
-
- /// Information of a imported module and symbols imported from it.
- struct ImportModuleEntry {
- u32_le name_offset; // pointing to a substring in ImportStrings
- u32_le import_indexed_symbol_table_offset; // pointing to a subtable in
- // ImportIndexedSymbolTable
- u32_le import_indexed_symbol_num;
- u32_le import_anonymous_symbol_table_offset; // pointing to a subtable in
- // ImportAnonymousSymbolTable
- u32_le import_anonymous_symbol_num;
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset;
-
- void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) {
- Memory::ReadBlock(import_indexed_symbol_table_offset +
- index * sizeof(ImportIndexedSymbolEntry),
- &entry, sizeof(ImportIndexedSymbolEntry));
- }
-
- void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) {
- Memory::ReadBlock(import_anonymous_symbol_table_offset +
- index * sizeof(ImportAnonymousSymbolEntry),
- &entry, sizeof(ImportAnonymousSymbolEntry));
- }
- };
- ASSERT_CRO_STRUCT(ImportModuleEntry, 20);
-
- enum class RelocationType : u8 {
- Nothing = 0,
- AbsoluteAddress = 2,
- RelativeAddress = 3,
- ThumbBranch = 10,
- ArmBranch = 28,
- ModifyArmBranch = 29,
- AbsoluteAddress2 = 38,
- AlignedRelativeAddress = 42,
- };
-
- struct RelocationEntry {
- SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static
- // module segment as a StaticRelocationEntry
- RelocationType type;
- u8 is_batch_end;
- u8 is_batch_resolved; // set at a batch beginning if the batch is resolved
- INSERT_PADDING_BYTES(1);
- u32_le addend;
- };
-
- /// Identifies a normal cross-module relocation.
- struct ExternalRelocationEntry : RelocationEntry {
- static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset;
- };
- ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12);
-
- /// Identifies a special static relocation (no game is known using this).
- struct StaticRelocationEntry : RelocationEntry {
- static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset;
- };
- ASSERT_CRO_STRUCT(StaticRelocationEntry, 12);
-
- /// Identifies a in-module relocation.
- struct InternalRelocationEntry {
- SegmentTag target_position; // to self's segment
- RelocationType type;
- u8 symbol_segment;
- INSERT_PADDING_BYTES(2);
- u32_le addend;
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset;
- };
- ASSERT_CRO_STRUCT(InternalRelocationEntry, 12);
-
- /// Identifies a special static anonymous symbol (no game is known using this).
- struct StaticAnonymousSymbolEntry {
- SegmentTag symbol_position; // to self's segment
- u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable
-
- static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset;
- };
- ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8);
-
- /**
- * Entry size of each table, from Code to StaticRelocationTable.
- * Byte string contents (such as Code) are treated with entries of size 1.
- * This is used for verifying the size of each table and calculating the fix end.
- */
- static const std::array<int, 17> ENTRY_SIZE;
-
- /// The offset field of the table where to crop for each fix level
- static const std::array<HeaderField, 4> FIX_BARRIERS;
-
- static constexpr u32 MAGIC_CRO0 = 0x304F5243;
- static constexpr u32 MAGIC_FIXD = 0x44584946;
-
- VAddr Field(HeaderField field) const {
- return module_address + CRO_HASH_SIZE + field * 4;
- }
-
- u32 GetField(HeaderField field) const {
- return Memory::Read32(Field(field));
- }
-
- void SetField(HeaderField field, u32 value) {
- Memory::Write32(Field(field), value);
- }
-
- /**
- * Reads an entry in one of module tables.
- * @param index index of the entry
- * @param data where to put the read entry
- * @note the entry type must have the static member TABLE_OFFSET_FIELD
- * indicating which table the entry is in.
- */
- template <typename T>
- void GetEntry(std::size_t index, T& data) const {
- Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
- &data, sizeof(T));
- }
-
- /**
- * Writes an entry to one of module tables.
- * @param index index of the entry
- * @param data the entry data to write
- * @note the entry type must have the static member TABLE_OFFSET_FIELD
- * indicating which table the entry is in.
- */
- template <typename T>
- void SetEntry(std::size_t index, const T& data) {
- Memory::WriteBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
- &data, sizeof(T));
- }
-
- /**
- * Converts a segment tag to virtual address in this module.
- * @param segment_tag the segment tag to convert
- * @returns VAddr the virtual address the segment tag points to; 0 if invalid.
- */
- VAddr SegmentTagToAddress(SegmentTag segment_tag) const;
-
- VAddr NextModule() const {
- return GetField(NextCRO);
- }
-
- VAddr PreviousModule() const {
- return GetField(PreviousCRO);
- }
-
- void SetNextModule(VAddr next) {
- SetField(NextCRO, next);
- }
-
- void SetPreviousModule(VAddr previous) {
- SetField(PreviousCRO, previous);
- }
-
- /**
- * A helper function iterating over all registered auto-link modules, including the static
- * module.
- * @param crs_address the virtual address of the static module
- * @param func a function object to operate on a module. It accepts one parameter
- * CROHelper and returns ResultVal<bool>. It should return true to continue the
- * iteration,
- * false to stop the iteration, or an error code (which will also stop the iteration).
- * @returns ResultCode indicating the result of the operation, RESULT_SUCCESS if all iteration
- * success,
- * otherwise error code of the last iteration.
- */
- template <typename FunctionObject>
- static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) {
- VAddr current = crs_address;
- while (current != 0) {
- CROHelper cro(current);
- CASCADE_RESULT(bool next, func(cro));
- if (!next)
- break;
- current = cro.NextModule();
- }
- return RESULT_SUCCESS;
- }
-
- /**
- * Applies a relocation
- * @param target_address where to apply the relocation
- * @param relocation_type the type of the relocation
- * @param addend address addend applied to the relocated symbol
- * @param symbol_address the symbol address to be relocated with
- * @param target_future_address the future address of the target.
- * Usually equals to target_address, but will be different for a target in .data segment
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, u32 addend,
- u32 symbol_address, u32 target_future_address);
-
- /**
- * Clears a relocation to zero
- * @param target_address where to apply the relocation
- * @param relocation_type the type of the relocation
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type);
-
- /**
- * Applies or resets a batch of relocations
- * @param batch the virtual address of the first relocation in the batch
- * @param symbol_address the symbol address to be relocated with
- * @param reset false to set the batch to resolved state, true to reset the batch to unresolved
- * state
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false);
-
- /**
- * Finds an exported named symbol in this module.
- * @param name the name of the symbol to find
- * @return VAddr the virtual address of the symbol; 0 if not found.
- */
- VAddr FindExportNamedSymbol(const std::string& name) const;
-
- /**
- * Rebases offsets in module header according to module address.
- * @param cro_size the size of the CRO file
- * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
- * code.
- */
- ResultCode RebaseHeader(u32 cro_size);
-
- /**
- * Rebases offsets in segment table according to module address.
- * @param cro_size the size of the CRO file
- * @param data_segment_address the buffer address for .data segment
- * @param data_segment_size the buffer size for .data segment
- * @param bss_segment_address the buffer address for .bss segment
- * @param bss_segment_size the buffer size for .bss segment
- * @returns ResultVal<VAddr> with the virtual address of .data segment in CRO.
- */
- ResultVal<VAddr> RebaseSegmentTable(u32 cro_size, VAddr data_segment_address,
- u32 data_segment_size, VAddr bss_segment_address,
- u32 bss_segment_size);
-
- /**
- * Rebases offsets in exported named symbol table according to module address.
- * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
- * code.
- */
- ResultCode RebaseExportNamedSymbolTable();
-
- /**
- * Verifies indices in export tree table.
- * @returns ResultCode RESULT_SUCCESS if all indices are verified as valid, otherwise error
- * code.
- */
- ResultCode VerifyExportTreeTable() const;
-
- /**
- * Rebases offsets in exported module table according to module address.
- * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
- * code.
- */
- ResultCode RebaseImportModuleTable();
-
- /**
- * Rebases offsets in imported named symbol table according to module address.
- * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
- * code.
- */
- ResultCode RebaseImportNamedSymbolTable();
-
- /**
- * Rebases offsets in imported indexed symbol table according to module address.
- * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
- * code.
- */
- ResultCode RebaseImportIndexedSymbolTable();
-
- /**
- * Rebases offsets in imported anonymous symbol table according to module address.
- * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error
- * code.
- */
- ResultCode RebaseImportAnonymousSymbolTable();
-
- /**
- * Gets the address of OnUnresolved function in this module.
- * Used as the applied symbol for reset relocation.
- * @returns the virtual address of OnUnresolved. 0 if not provided.
- */
- VAddr GetOnUnresolvedAddress();
-
- /**
- * Resets all external relocations to unresolved state.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ResetExternalRelocations();
-
- /**
- * Clears all external relocations to zero.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ClearExternalRelocations();
-
- /**
- * Applies all static anonymous symbol to the static module.
- * @param crs_address the virtual address of the static module
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address);
-
- /**
- * Applies all internal relocations to the module itself.
- * @param old_data_segment_address the virtual address of data segment in CRO buffer
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyInternalRelocations(u32 old_data_segment_address);
-
- /**
- * Clears all internal relocations to zero.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ClearInternalRelocations();
-
- /// Unrebases offsets in imported anonymous symbol table
- void UnrebaseImportAnonymousSymbolTable();
-
- /// Unrebases offsets in imported indexed symbol table
- void UnrebaseImportIndexedSymbolTable();
-
- /// Unrebases offsets in imported named symbol table
- void UnrebaseImportNamedSymbolTable();
-
- /// Unrebases offsets in imported module table
- void UnrebaseImportModuleTable();
-
- /// Unrebases offsets in exported named symbol table
- void UnrebaseExportNamedSymbolTable();
-
- /// Unrebases offsets in segment table
- void UnrebaseSegmentTable();
-
- /// Unrebases offsets in module header
- void UnrebaseHeader();
-
- /**
- * Looks up all imported named symbols of this module in all registered auto-link modules, and
- * resolves them if found.
- * @param crs_address the virtual address of the static module
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyImportNamedSymbol(VAddr crs_address);
-
- /**
- * Resets all imported named symbols of this module to unresolved state.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ResetImportNamedSymbol();
-
- /**
- * Resets all imported indexed symbols of this module to unresolved state.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ResetImportIndexedSymbol();
-
- /**
- * Resets all imported anonymous symbols of this module to unresolved state.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ResetImportAnonymousSymbol();
-
- /**
- * 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
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyModuleImport(VAddr crs_address);
-
- /**
- * Resolves target module's imported named symbols that exported by this module.
- * @param target the module to resolve.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyExportNamedSymbol(CROHelper target);
-
- /**
- * 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);
-
- /**
- * Resolves imported indexed and anonymous symbols in the target module which imports this
- * module.
- * @param target the module to resolve.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyModuleExport(CROHelper target);
-
- /**
- * 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);
-
- /**
- * Resolves the exit function in this module
- * @param crs_address the virtual address of the static module.
- * @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
- */
- ResultCode ApplyExitRelocations(VAddr crs_address);
-};
-
-} // namespace LDR
-} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp
deleted file mode 100644
index 7255ea026..000000000
--- a/src/core/hle/service/ldr_ro/ldr_ro.cpp
+++ /dev/null
@@ -1,718 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/alignment.h"
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "core/arm/arm_interface.h"
-#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/vm_manager.h"
-#include "core/hle/service/ldr_ro/cro_helper.h"
-#include "core/hle/service/ldr_ro/ldr_ro.h"
-#include "core/hle/service/ldr_ro/memory_synchronizer.h"
-
-namespace Service {
-namespace LDR {
-
-static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9
- ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal,
- ErrorLevel::Permanent);
-static const ResultCode ERROR_NOT_INITIALIZED = // 0xD9612FF8
- ResultCode(ErrorDescription::NotInitialized, ErrorModule::RO, ErrorSummary::Internal,
- ErrorLevel::Permanent);
-static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F
- ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument,
- ErrorLevel::Usage);
-static const ResultCode ERROR_MISALIGNED_ADDRESS = // 0xD9012FF1
- ResultCode(ErrorDescription::MisalignedAddress, ErrorModule::RO, ErrorSummary::WrongArgument,
- ErrorLevel::Permanent);
-static const ResultCode ERROR_MISALIGNED_SIZE = // 0xD9012FF2
- ResultCode(ErrorDescription::MisalignedSize, ErrorModule::RO, ErrorSummary::WrongArgument,
- ErrorLevel::Permanent);
-static const ResultCode ERROR_ILLEGAL_ADDRESS = // 0xE1612C0F
- ResultCode(static_cast<ErrorDescription>(15), ErrorModule::RO, ErrorSummary::Internal,
- ErrorLevel::Usage);
-static const ResultCode ERROR_INVALID_MEMORY_STATE = // 0xD8A12C08
- ResultCode(static_cast<ErrorDescription>(8), ErrorModule::RO, ErrorSummary::InvalidState,
- ErrorLevel::Permanent);
-static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D
- ResultCode(static_cast<ErrorDescription>(13), ErrorModule::RO, ErrorSummary::InvalidState,
- ErrorLevel::Permanent);
-
-static MemorySynchronizer memory_synchronizer;
-
-// TODO(wwylele): this should be in the per-client storage when we implement multi-process
-static VAddr loaded_crs; ///< the virtual address of the static module
-
-static bool VerifyBufferState(VAddr buffer_ptr, u32 size) {
- auto vma = Kernel::g_current_process->vm_manager.FindVMA(buffer_ptr);
- return vma != Kernel::g_current_process->vm_manager.vma_map.end() &&
- vma->second.base + vma->second.size >= buffer_ptr + size &&
- vma->second.permissions == Kernel::VMAPermission::ReadWrite &&
- vma->second.meminfo_state == Kernel::MemoryState::Private;
-}
-
-/**
- * LDR_RO::Initialize service function
- * Inputs:
- * 0 : 0x000100C2
- * 1 : CRS buffer pointer
- * 2 : CRS Size
- * 3 : Process memory address where the CRS will be mapped
- * 4 : handle translation descriptor (zero)
- * 5 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void Initialize(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 3, 2);
- VAddr crs_buffer_ptr = rp.Pop<u32>();
- u32 crs_size = rp.Pop<u32>();
- VAddr crs_address = rp.Pop<u32>();
- // TODO (wwylele): RO service checks the descriptor here and return error 0xD9001830 for
- // incorrect descriptor. This error return should be probably built in IPC::RequestParser.
- // All other service functions below have the same issue.
- Kernel::Handle process = rp.PopHandle();
-
- LOG_DEBUG(Service_LDR,
- "called, crs_buffer_ptr=0x%08X, crs_address=0x%08X, crs_size=0x%X, process=0x%08X",
- crs_buffer_ptr, crs_address, crs_size, process);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-
- if (loaded_crs != 0) {
- LOG_ERROR(Service_LDR, "Already initialized");
- rb.Push(ERROR_ALREADY_INITIALIZED);
- return;
- }
-
- if (crs_size < CRO_HEADER_SIZE) {
- LOG_ERROR(Service_LDR, "CRS is too small");
- rb.Push(ERROR_BUFFER_TOO_SMALL);
- return;
- }
-
- if (crs_buffer_ptr & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRS original address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- return;
- }
-
- if (crs_address & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRS mapping address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- return;
- }
-
- if (crs_size & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRS size is not aligned");
- rb.Push(ERROR_MISALIGNED_SIZE);
- return;
- }
-
- if (!VerifyBufferState(crs_buffer_ptr, crs_size)) {
- LOG_ERROR(Service_LDR, "CRS original buffer is in invalid state");
- rb.Push(ERROR_INVALID_MEMORY_STATE);
- return;
- }
-
- if (crs_address < Memory::PROCESS_IMAGE_VADDR ||
- crs_address + crs_size > Memory::PROCESS_IMAGE_VADDR_END) {
- LOG_ERROR(Service_LDR, "CRS mapping address is not in the process image region");
- rb.Push(ERROR_ILLEGAL_ADDRESS);
- return;
- }
-
- ResultCode result = RESULT_SUCCESS;
-
- if (crs_buffer_ptr != crs_address) {
- // TODO(wwylele): should be memory aliasing
- std::shared_ptr<std::vector<u8>> crs_mem = std::make_shared<std::vector<u8>>(crs_size);
- Memory::ReadBlock(crs_buffer_ptr, crs_mem->data(), crs_size);
- result = Kernel::g_current_process->vm_manager
- .MapMemoryBlock(crs_address, crs_mem, 0, crs_size, Kernel::MemoryState::Code)
- .Code();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw);
- rb.Push(result);
- return;
- }
-
- result = Kernel::g_current_process->vm_manager.ReprotectRange(crs_address, crs_size,
- Kernel::VMAPermission::Read);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw);
- rb.Push(result);
- return;
- }
-
- memory_synchronizer.AddMemoryBlock(crs_address, crs_buffer_ptr, crs_size);
- } else {
- // Do nothing if buffer_ptr == address
- // TODO(wwylele): verify this behaviour. This is only seen in the web browser app,
- // and the actual behaviour is unclear. "Do nothing" is probably an incorrect implement.
- // There is also a chance that another issue causes the app passing wrong arguments.
- LOG_WARNING(Service_LDR, "crs_buffer_ptr == crs_address (0x%08X)", crs_address);
- }
-
- CROHelper crs(crs_address);
- crs.InitCRS();
-
- result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing CRS 0x%08X", result.raw);
- rb.Push(result);
- return;
- }
-
- memory_synchronizer.SynchronizeOriginalMemory();
-
- loaded_crs = crs_address;
-
- rb.Push(RESULT_SUCCESS);
-}
-
-/**
- * LDR_RO::LoadCRR service function
- * Inputs:
- * 0 : 0x00020082
- * 1 : CRR buffer pointer
- * 2 : CRR Size
- * 3 : handle translation descriptor (zero)
- * 4 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void LoadCRR(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 2);
- VAddr crr_buffer_ptr = rp.Pop<u32>();
- u32 crr_size = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
- rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_LDR,
- "(STUBBED) called, crr_buffer_ptr=0x%08X, crr_size=0x%08X, process=0x%08X",
- crr_buffer_ptr, crr_size, process);
-}
-
-/**
- * LDR_RO::UnloadCRR service function
- * Inputs:
- * 0 : 0x00030042
- * 1 : CRR buffer pointer
- * 2 : handle translation descriptor (zero)
- * 3 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void UnloadCRR(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 2);
- u32 crr_buffer_ptr = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
- rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_LDR, "(STUBBED) called, crr_buffer_ptr=0x%08X, process=0x%08X",
- crr_buffer_ptr, process);
-}
-
-/**
- * LDR_RO::LoadCRO service function
- * Inputs:
- * 0 : 0x000402C2 (old) / 0x000902C2 (new)
- * 1 : CRO buffer pointer
- * 2 : memory address where the CRO will be mapped
- * 3 : CRO Size
- * 4 : .data segment buffer pointer
- * 5 : must be zero
- * 6 : .data segment buffer size
- * 7 : .bss segment buffer pointer
- * 8 : .bss segment buffer size
- * 9 : (bool) register CRO as auto-link module
- * 10 : fix level
- * 11 : CRR address (zero if use loaded CRR)
- * 12 : handle translation descriptor (zero)
- * 13 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : CRO fixed size
- * Note:
- * This service function has two versions. The function defined here is a
- * unified one of two, with an additional parameter link_on_load_bug_fix.
- * There is a dispatcher template below.
- */
-static void LoadCRO(Interface* self, bool link_on_load_bug_fix) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), link_on_load_bug_fix ? 0x09 : 0x04, 11, 2);
- VAddr cro_buffer_ptr = rp.Pop<u32>();
- VAddr cro_address = rp.Pop<u32>();
- u32 cro_size = rp.Pop<u32>();
- VAddr data_segment_address = rp.Pop<u32>();
- u32 zero = rp.Pop<u32>();
- u32 data_segment_size = rp.Pop<u32>();
- u32 bss_segment_address = rp.Pop<u32>();
- u32 bss_segment_size = rp.Pop<u32>();
- bool auto_link = rp.Pop<bool>();
- u32 fix_level = rp.Pop<u32>();
- VAddr crr_address = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- LOG_DEBUG(Service_LDR, "called (%s), cro_buffer_ptr=0x%08X, cro_address=0x%08X, cro_size=0x%X, "
- "data_segment_address=0x%08X, zero=%d, data_segment_size=0x%X, "
- "bss_segment_address=0x%08X, bss_segment_size=0x%X, auto_link=%s, "
- "fix_level=%d, crr_address=0x%08X, process=0x%08X",
- link_on_load_bug_fix ? "new" : "old", cro_buffer_ptr, cro_address, cro_size,
- data_segment_address, zero, data_segment_size, bss_segment_address, bss_segment_size,
- auto_link ? "true" : "false", fix_level, crr_address, process);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
-
- if (loaded_crs == 0) {
- LOG_ERROR(Service_LDR, "Not initialized");
- rb.Push(ERROR_NOT_INITIALIZED);
- rb.Push<u32>(0);
- return;
- }
-
- if (cro_size < CRO_HEADER_SIZE) {
- LOG_ERROR(Service_LDR, "CRO too small");
- rb.Push(ERROR_BUFFER_TOO_SMALL);
- rb.Push<u32>(0);
- return;
- }
-
- if (cro_buffer_ptr & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRO original address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- rb.Push<u32>(0);
- return;
- }
-
- if (cro_address & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRO mapping address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- rb.Push<u32>(0);
- return;
- }
-
- if (cro_size & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRO size is not aligned");
- rb.Push(ERROR_MISALIGNED_SIZE);
- rb.Push<u32>(0);
- return;
- }
-
- if (!VerifyBufferState(cro_buffer_ptr, cro_size)) {
- LOG_ERROR(Service_LDR, "CRO original buffer is in invalid state");
- rb.Push(ERROR_INVALID_MEMORY_STATE);
- rb.Push<u32>(0);
- return;
- }
-
- if (cro_address < Memory::PROCESS_IMAGE_VADDR ||
- cro_address + cro_size > Memory::PROCESS_IMAGE_VADDR_END) {
- LOG_ERROR(Service_LDR, "CRO mapping address is not in the process image region");
- rb.Push(ERROR_ILLEGAL_ADDRESS);
- rb.Push<u32>(0);
- return;
- }
-
- if (zero) {
- LOG_ERROR(Service_LDR, "Zero is not zero %d", zero);
- rb.Push(ResultCode(static_cast<ErrorDescription>(29), ErrorModule::RO,
- ErrorSummary::Internal, ErrorLevel::Usage));
- rb.Push<u32>(0);
- return;
- }
-
- ResultCode result = RESULT_SUCCESS;
-
- if (cro_buffer_ptr != cro_address) {
- // TODO(wwylele): should be memory aliasing
- std::shared_ptr<std::vector<u8>> cro_mem = std::make_shared<std::vector<u8>>(cro_size);
- Memory::ReadBlock(cro_buffer_ptr, cro_mem->data(), cro_size);
- result = Kernel::g_current_process->vm_manager
- .MapMemoryBlock(cro_address, cro_mem, 0, cro_size, Kernel::MemoryState::Code)
- .Code();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error mapping memory block %08X", result.raw);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
-
- result = Kernel::g_current_process->vm_manager.ReprotectRange(cro_address, cro_size,
- Kernel::VMAPermission::Read);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw);
- Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
-
- memory_synchronizer.AddMemoryBlock(cro_address, cro_buffer_ptr, cro_size);
- } else {
- // Do nothing if buffer_ptr == address
- // TODO(wwylele): verify this behaviour.
- // This is derived from the case of LoadCRS with buffer_ptr==address,
- // and is never seen in any game. "Do nothing" is probably an incorrect implement.
- // There is also a chance that this case is just prohibited.
- LOG_WARNING(Service_LDR, "cro_buffer_ptr == cro_address (0x%08X)", cro_address);
- }
-
- CROHelper cro(cro_address);
-
- result = cro.VerifyHash(cro_size, crr_address);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error verifying CRO in CRR %08X", result.raw);
- Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
-
- result = cro.Rebase(loaded_crs, cro_size, data_segment_address, data_segment_size,
- bss_segment_address, bss_segment_size, false);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error rebasing CRO %08X", result.raw);
- Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
-
- result = cro.Link(loaded_crs, link_on_load_bug_fix);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw);
- Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
-
- cro.Register(loaded_crs, auto_link);
-
- u32 fix_size = cro.Fix(fix_level);
-
- memory_synchronizer.SynchronizeOriginalMemory();
-
- // TODO(wwylele): verify the behaviour when buffer_ptr == address
- if (cro_buffer_ptr != cro_address) {
- if (fix_size != cro_size) {
- result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address + fix_size,
- cro_size - fix_size);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error unmapping memory block %08X", result.raw);
- Kernel::g_current_process->vm_manager.UnmapRange(cro_address, cro_size);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
- }
-
- // Changes the block size
- memory_synchronizer.ResizeMemoryBlock(cro_address, cro_buffer_ptr, fix_size);
- }
-
- VAddr exe_begin;
- u32 exe_size;
- std::tie(exe_begin, exe_size) = cro.GetExecutablePages();
- if (exe_begin) {
- result = Kernel::g_current_process->vm_manager.ReprotectRange(
- exe_begin, exe_size, Kernel::VMAPermission::ReadExecute);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error reprotecting memory block %08X", result.raw);
- Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fix_size);
- rb.Push(result);
- rb.Push<u32>(0);
- return;
- }
- }
-
- Core::CPU().ClearInstructionCache();
-
- LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", cro.ModuleName().data(),
- cro_address, cro_address + fix_size);
-
- rb.Push(RESULT_SUCCESS, fix_size);
-}
-
-template <bool link_on_load_bug_fix>
-static void LoadCRO(Interface* self) {
- LoadCRO(self, link_on_load_bug_fix);
-}
-
-/**
- * LDR_RO::UnloadCRO service function
- * Inputs:
- * 0 : 0x000500C2
- * 1 : mapped CRO pointer
- * 2 : zero? (RO service doesn't care)
- * 3 : original CRO pointer
- * 4 : handle translation descriptor (zero)
- * 5 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void UnloadCRO(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 3, 2);
- VAddr cro_address = rp.Pop<u32>();
- u32 zero = rp.Pop<u32>();
- VAddr cro_buffer_ptr = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- LOG_DEBUG(Service_LDR,
- "called, cro_address=0x%08X, zero=%d, cro_buffer_ptr=0x%08X, process=0x%08X",
- cro_address, zero, cro_buffer_ptr, process);
-
- CROHelper cro(cro_address);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-
- if (loaded_crs == 0) {
- LOG_ERROR(Service_LDR, "Not initialized");
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- if (cro_address & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRO address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- return;
- }
-
- if (!cro.IsLoaded()) {
- LOG_ERROR(Service_LDR, "Invalid or not loaded CRO");
- rb.Push(ERROR_NOT_LOADED);
- return;
- }
-
- LOG_INFO(Service_LDR, "Unloading CRO \"%s\"", cro.ModuleName().data());
-
- u32 fixed_size = cro.GetFixedSize();
-
- cro.Unregister(loaded_crs);
-
- ResultCode result = cro.Unlink(loaded_crs);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw);
- rb.Push(result);
- return;
- }
-
- // If the module is not fixed, clears all external/internal relocations
- // to restore the state before loading, so that it can be loaded again(?)
- if (!cro.IsFixed()) {
- result = cro.ClearRelocations();
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error clearing relocations %08X", result.raw);
- rb.Push(result);
- return;
- }
- }
-
- cro.Unrebase(false);
-
- memory_synchronizer.SynchronizeOriginalMemory();
-
- // TODO(wwylele): verify the behaviour when buffer_ptr == address
- if (cro_address != cro_buffer_ptr) {
- result = Kernel::g_current_process->vm_manager.UnmapRange(cro_address, fixed_size);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error unmapping CRO %08X", result.raw);
- }
- memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr);
- }
-
- Core::CPU().ClearInstructionCache();
-
- rb.Push(result);
-}
-
-/**
- * LDR_RO::LinkCRO service function
- * Inputs:
- * 0 : 0x00060042
- * 1 : mapped CRO pointer
- * 2 : handle translation descriptor (zero)
- * 3 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void LinkCRO(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 2);
- VAddr cro_address = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, process=0x%08X", cro_address, process);
-
- CROHelper cro(cro_address);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-
- if (loaded_crs == 0) {
- LOG_ERROR(Service_LDR, "Not initialized");
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- if (cro_address & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRO address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- return;
- }
-
- if (!cro.IsLoaded()) {
- LOG_ERROR(Service_LDR, "Invalid or not loaded CRO");
- rb.Push(ERROR_NOT_LOADED);
- return;
- }
-
- LOG_INFO(Service_LDR, "Linking CRO \"%s\"", cro.ModuleName().data());
-
- ResultCode result = cro.Link(loaded_crs, false);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error linking CRO %08X", result.raw);
- }
-
- memory_synchronizer.SynchronizeOriginalMemory();
- Core::CPU().ClearInstructionCache();
-
- rb.Push(result);
-}
-
-/**
- * LDR_RO::UnlinkCRO service function
- * Inputs:
- * 0 : 0x00070042
- * 1 : mapped CRO pointer
- * 2 : handle translation descriptor (zero)
- * 3 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void UnlinkCRO(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 1, 2);
- VAddr cro_address = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- LOG_DEBUG(Service_LDR, "called, cro_address=0x%08X, process=0x%08X", cro_address, process);
-
- CROHelper cro(cro_address);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-
- if (loaded_crs == 0) {
- LOG_ERROR(Service_LDR, "Not initialized");
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- if (cro_address & Memory::PAGE_MASK) {
- LOG_ERROR(Service_LDR, "CRO address is not aligned");
- rb.Push(ERROR_MISALIGNED_ADDRESS);
- return;
- }
-
- if (!cro.IsLoaded()) {
- LOG_ERROR(Service_LDR, "Invalid or not loaded CRO");
- rb.Push(ERROR_NOT_LOADED);
- return;
- }
-
- LOG_INFO(Service_LDR, "Unlinking CRO \"%s\"", cro.ModuleName().data());
-
- ResultCode result = cro.Unlink(loaded_crs);
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error unlinking CRO %08X", result.raw);
- }
-
- memory_synchronizer.SynchronizeOriginalMemory();
- Core::CPU().ClearInstructionCache();
-
- rb.Push(result);
-}
-
-/**
- * LDR_RO::Shutdown service function
- * Inputs:
- * 0 : 0x00080042
- * 1 : original CRS buffer pointer
- * 2 : handle translation descriptor (zero)
- * 3 : KProcess handle
- * Outputs:
- * 0 : Return header
- * 1 : Result of function, 0 on success, otherwise error code
- */
-static void Shutdown(Interface* self) {
- IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 2);
- VAddr crs_buffer_ptr = rp.Pop<u32>();
- Kernel::Handle process = rp.PopHandle();
-
- LOG_DEBUG(Service_LDR, "called, crs_buffer_ptr=0x%08X, process=0x%08X", crs_buffer_ptr,
- process);
-
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
-
- if (loaded_crs == 0) {
- LOG_ERROR(Service_LDR, "Not initialized");
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- CROHelper crs(loaded_crs);
- crs.Unrebase(true);
-
- memory_synchronizer.SynchronizeOriginalMemory();
-
- ResultCode result = RESULT_SUCCESS;
-
- // TODO(wwylele): verify the behaviour when buffer_ptr == address
- if (loaded_crs != crs_buffer_ptr) {
- result = Kernel::g_current_process->vm_manager.UnmapRange(loaded_crs, crs.GetFileSize());
- if (result.IsError()) {
- LOG_ERROR(Service_LDR, "Error unmapping CRS %08X", result.raw);
- }
- memory_synchronizer.RemoveMemoryBlock(loaded_crs, crs_buffer_ptr);
- }
-
- loaded_crs = 0;
- rb.Push(result);
-}
-
-const Interface::FunctionInfo FunctionTable[] = {
- // clang-format off
- {0x000100C2, Initialize, "Initialize"},
- {0x00020082, LoadCRR, "LoadCRR"},
- {0x00030042, UnloadCRR, "UnloadCRR"},
- {0x000402C2, LoadCRO<false>, "LoadCRO"},
- {0x000500C2, UnloadCRO, "UnloadCRO"},
- {0x00060042, LinkCRO, "LinkCRO"},
- {0x00070042, UnlinkCRO, "UnlinkCRO"},
- {0x00080042, Shutdown, "Shutdown"},
- {0x000902C2, LoadCRO<true>, "LoadCRO_New"},
- // clang-format on
-};
-
-LDR_RO::LDR_RO() {
- Register(FunctionTable);
-
- loaded_crs = 0;
- memory_synchronizer.Clear();
-}
-
-} // namespace LDR
-} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h
deleted file mode 100644
index 0f6fe7b60..000000000
--- a/src/core/hle/service/ldr_ro/ldr_ro.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Service {
-namespace LDR {
-
-class LDR_RO final : public Interface {
-public:
- LDR_RO();
-
- std::string GetPortName() const override {
- return "ldr:ro";
- }
-};
-
-} // namespace LDR
-} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
deleted file mode 100644
index 0d44bf6bd..000000000
--- a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <algorithm>
-#include "common/assert.h"
-#include "core/hle/service/ldr_ro/memory_synchronizer.h"
-
-namespace Service {
-namespace LDR {
-
-auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) {
- auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(),
- [=](MemoryBlock& b) { return b.original == original; });
- ASSERT(block->mapping == mapping);
- return block;
-}
-
-void MemorySynchronizer::Clear() {
- memory_blocks.clear();
-}
-
-void MemorySynchronizer::AddMemoryBlock(VAddr mapping, VAddr original, u32 size) {
- memory_blocks.push_back(MemoryBlock{mapping, original, size});
-}
-
-void MemorySynchronizer::ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size) {
- FindMemoryBlock(mapping, original)->size = size;
-}
-
-void MemorySynchronizer::RemoveMemoryBlock(VAddr mapping, VAddr original) {
- memory_blocks.erase(FindMemoryBlock(mapping, original));
-}
-
-void MemorySynchronizer::SynchronizeOriginalMemory() {
- for (auto& block : memory_blocks) {
- Memory::CopyBlock(block.original, block.mapping, block.size);
- }
-}
-
-} // namespace LDR
-} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h
deleted file mode 100644
index 438293a58..000000000
--- a/src/core/hle/service/ldr_ro/memory_synchronizer.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <vector>
-#include "core/memory.h"
-
-namespace Service {
-namespace LDR {
-
-/**
- * This is a work-around before we implement memory aliasing.
- * CRS and CRO are mapped (aliased) to another memory when loading. Games can read
- * from both the original buffer and the mapping memory. So we use this to synchronize
- * all original buffers with mapping memory after modifying the content.
- */
-class MemorySynchronizer {
-public:
- void Clear();
-
- void AddMemoryBlock(VAddr mapping, VAddr original, u32 size);
- void ResizeMemoryBlock(VAddr mapping, VAddr original, u32 size);
- void RemoveMemoryBlock(VAddr mapping, VAddr original);
-
- void SynchronizeOriginalMemory();
-
-private:
- struct MemoryBlock {
- VAddr mapping;
- VAddr original;
- u32 size;
- };
-
- std::vector<MemoryBlock> memory_blocks;
-
- auto FindMemoryBlock(VAddr mapping, VAddr original);
-};
-
-} // namespace LDR
-} // namespace Service