mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 17:30:16 +00:00
LDR fixup relocation
This commit is contained in:
parent
f1f940d8d7
commit
1ddbb7f6df
@ -99,8 +99,8 @@ class CROHelper final {
|
|||||||
|
|
||||||
ImportModuleTableOffset,
|
ImportModuleTableOffset,
|
||||||
ImportModuleNum,
|
ImportModuleNum,
|
||||||
ExternalPatchTableOffset,
|
ExternalRelocationTableOffset,
|
||||||
ExternalPatchNum,
|
ExternalRelocationNum,
|
||||||
ImportNamedSymbolTableOffset,
|
ImportNamedSymbolTableOffset,
|
||||||
ImportNamedSymbolNum,
|
ImportNamedSymbolNum,
|
||||||
ImportIndexedSymbolTableOffset,
|
ImportIndexedSymbolTableOffset,
|
||||||
@ -112,10 +112,10 @@ class CROHelper final {
|
|||||||
|
|
||||||
StaticAnonymousSymbolTableOffset,
|
StaticAnonymousSymbolTableOffset,
|
||||||
StaticAnonymousSymbolNum,
|
StaticAnonymousSymbolNum,
|
||||||
InternalPatchTableOffset,
|
InternalRelocationTableOffset,
|
||||||
InternalPatchNum,
|
InternalRelocationNum,
|
||||||
StaticPatchTableOffset,
|
StaticRelocationTableOffset,
|
||||||
StaticPatchNum,
|
StaticRelocationNum,
|
||||||
Fix0Barrier,
|
Fix0Barrier,
|
||||||
|
|
||||||
Fix3Barrier = ExportNamedSymbolTableOffset,
|
Fix3Barrier = ExportNamedSymbolTableOffset,
|
||||||
@ -187,8 +187,8 @@ class CROHelper final {
|
|||||||
|
|
||||||
/// Identifies a named symbol imported from another module.
|
/// Identifies a named symbol imported from another module.
|
||||||
struct ImportNamedSymbolEntry {
|
struct ImportNamedSymbolEntry {
|
||||||
u32_le name_offset; // pointing to a substring in ImportStrings
|
u32_le name_offset; // pointing to a substring in ImportStrings
|
||||||
u32_le patch_batch_offset; // pointing to a patch batch in ExternalPatchTable
|
u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable
|
||||||
|
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset;
|
||||||
};
|
};
|
||||||
@ -196,8 +196,8 @@ class CROHelper final {
|
|||||||
|
|
||||||
/// Identifies an indexed symbol imported from another module.
|
/// Identifies an indexed symbol imported from another module.
|
||||||
struct ImportIndexedSymbolEntry {
|
struct ImportIndexedSymbolEntry {
|
||||||
u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module
|
u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module
|
||||||
u32_le patch_batch_offset; // pointing to a patch batch in ExternalPatchTable
|
u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable
|
||||||
|
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset;
|
||||||
};
|
};
|
||||||
@ -205,8 +205,8 @@ class CROHelper final {
|
|||||||
|
|
||||||
/// Identifies an anonymous symbol imported from another module.
|
/// Identifies an anonymous symbol imported from another module.
|
||||||
struct ImportAnonymousSymbolEntry {
|
struct ImportAnonymousSymbolEntry {
|
||||||
SegmentTag symbol_position; // in the exporting segment
|
SegmentTag symbol_position; // in the exporting segment
|
||||||
u32_le patch_batch_offset; // pointing to a patch batch in ExternalPatchTable
|
u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable
|
||||||
|
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset;
|
||||||
};
|
};
|
||||||
@ -234,7 +234,7 @@ class CROHelper final {
|
|||||||
};
|
};
|
||||||
ASSERT_CRO_STRUCT(ImportModuleEntry, 20);
|
ASSERT_CRO_STRUCT(ImportModuleEntry, 20);
|
||||||
|
|
||||||
enum class PatchType : u8 {
|
enum class RelocationType : u8 {
|
||||||
Nothing = 0,
|
Nothing = 0,
|
||||||
AbsoluteAddress = 2,
|
AbsoluteAddress = 2,
|
||||||
RelativeAddress = 3,
|
RelativeAddress = 3,
|
||||||
@ -245,50 +245,50 @@ class CROHelper final {
|
|||||||
AlignedRelativeAddress = 42,
|
AlignedRelativeAddress = 42,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PatchEntry {
|
struct RelocationEntry {
|
||||||
SegmentTag target_position; // to self's segment as an ExternalPatchEntry; to static module segment as a StaticPatchEntry
|
SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static module segment as a StaticRelocationEntry
|
||||||
PatchType type;
|
RelocationType type;
|
||||||
u8 is_batch_end;
|
u8 is_batch_end;
|
||||||
u8 is_batch_resolved; // set at a batch beginning if the batch is resolved
|
u8 is_batch_resolved; // set at a batch beginning if the batch is resolved
|
||||||
INSERT_PADDING_BYTES(1);
|
INSERT_PADDING_BYTES(1);
|
||||||
u32_le shift;
|
u32_le addend;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Identifies a normal cross-module patch.
|
/// Identifies a normal cross-module relocation.
|
||||||
struct ExternalPatchEntry : PatchEntry {
|
struct ExternalRelocationEntry : RelocationEntry {
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalPatchTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset;
|
||||||
};
|
};
|
||||||
ASSERT_CRO_STRUCT(ExternalPatchEntry, 12);
|
ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12);
|
||||||
|
|
||||||
/// Identifies a special static patch (no game is known using this).
|
/// Identifies a special static relocation (no game is known using this).
|
||||||
struct StaticPatchEntry : PatchEntry {
|
struct StaticRelocationEntry : RelocationEntry {
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = StaticPatchTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset;
|
||||||
};
|
};
|
||||||
ASSERT_CRO_STRUCT(StaticPatchEntry, 12);
|
ASSERT_CRO_STRUCT(StaticRelocationEntry, 12);
|
||||||
|
|
||||||
/// Identifies a in-module patch.
|
/// Identifies a in-module relocation.
|
||||||
struct InternalPatchEntry {
|
struct InternalRelocationEntry {
|
||||||
SegmentTag target_position; // to self's segment
|
SegmentTag target_position; // to self's segment
|
||||||
PatchType type;
|
RelocationType type;
|
||||||
u8 symbol_segment;
|
u8 symbol_segment;
|
||||||
INSERT_PADDING_BYTES(2);
|
INSERT_PADDING_BYTES(2);
|
||||||
u32_le shift;
|
u32_le addend;
|
||||||
|
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = InternalPatchTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset;
|
||||||
};
|
};
|
||||||
ASSERT_CRO_STRUCT(InternalPatchEntry, 12);
|
ASSERT_CRO_STRUCT(InternalRelocationEntry, 12);
|
||||||
|
|
||||||
/// Identifies a special static anonymous symbol (no game is known using this).
|
/// Identifies a special static anonymous symbol (no game is known using this).
|
||||||
struct StaticAnonymousSymbolEntry {
|
struct StaticAnonymousSymbolEntry {
|
||||||
SegmentTag symbol_position; // to self's segment
|
SegmentTag symbol_position; // to self's segment
|
||||||
u32_le patch_batch_offset; // pointing to a patch batch in StaticPatchTable
|
u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable
|
||||||
|
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset;
|
||||||
};
|
};
|
||||||
ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8);
|
ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry size of each table, from Code to StaticPatchTable.
|
* Entry size of each table, from Code to StaticRelocationTable.
|
||||||
* Byte string contents (such as Code) are treated with entries of size 1.
|
* 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.
|
* This is used for verifying the size of each table and calculating the fix end.
|
||||||
*/
|
*/
|
||||||
@ -395,30 +395,30 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a patch
|
* Applies a relocation
|
||||||
* @param target_address where to apply the patch
|
* @param target_address where to apply the relocation
|
||||||
* @param patch_type the type of the patch
|
* @param relocation_type the type of the relocation
|
||||||
* @param shift address shift apply to the patched symbol
|
* @param addend address addend applied to the relocated symbol
|
||||||
* @param symbol_address the symbol address to be patched with
|
* @param symbol_address the symbol address to be relocated with
|
||||||
* @param target_future_address the future address of the target.
|
* @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
|
* Usually equals to target_address, but will be different for a target in .data segment
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ApplyPatch(VAddr target_address, PatchType patch_type, u32 shift, u32 symbol_address, u32 target_future_address) {
|
ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, u32 addend, u32 symbol_address, u32 target_future_address) {
|
||||||
switch (patch_type) {
|
switch (relocation_type) {
|
||||||
case PatchType::Nothing:
|
case RelocationType::Nothing:
|
||||||
break;
|
break;
|
||||||
case PatchType::AbsoluteAddress:
|
case RelocationType::AbsoluteAddress:
|
||||||
case PatchType::AbsoluteAddress2:
|
case RelocationType::AbsoluteAddress2:
|
||||||
Memory::Write32(target_address, symbol_address + shift);
|
Memory::Write32(target_address, symbol_address + addend);
|
||||||
break;
|
break;
|
||||||
case PatchType::RelativeAddress:
|
case RelocationType::RelativeAddress:
|
||||||
Memory::Write32(target_address, symbol_address + shift - target_future_address);
|
Memory::Write32(target_address, symbol_address + addend - target_future_address);
|
||||||
break;
|
break;
|
||||||
case PatchType::ThumbBranch:
|
case RelocationType::ThumbBranch:
|
||||||
case PatchType::ArmBranch:
|
case RelocationType::ArmBranch:
|
||||||
case PatchType::ModifyArmBranch:
|
case RelocationType::ModifyArmBranch:
|
||||||
case PatchType::AlignedRelativeAddress:
|
case RelocationType::AlignedRelativeAddress:
|
||||||
// TODO(wwylele): implement other types
|
// TODO(wwylele): implement other types
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
break;
|
break;
|
||||||
@ -429,24 +429,24 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears a patch to zero
|
* Clears a relocation to zero
|
||||||
* @param target_address where to apply the patch
|
* @param target_address where to apply the relocation
|
||||||
* @param patch_type the type of the patch
|
* @param relocation_type the type of the relocation
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ClearPatch(VAddr target_address, PatchType patch_type) {
|
ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type) {
|
||||||
switch (patch_type) {
|
switch (relocation_type) {
|
||||||
case PatchType::Nothing:
|
case RelocationType::Nothing:
|
||||||
break;
|
break;
|
||||||
case PatchType::AbsoluteAddress:
|
case RelocationType::AbsoluteAddress:
|
||||||
case PatchType::AbsoluteAddress2:
|
case RelocationType::AbsoluteAddress2:
|
||||||
case PatchType::RelativeAddress:
|
case RelocationType::RelativeAddress:
|
||||||
Memory::Write32(target_address, 0);
|
Memory::Write32(target_address, 0);
|
||||||
break;
|
break;
|
||||||
case PatchType::ThumbBranch:
|
case RelocationType::ThumbBranch:
|
||||||
case PatchType::ArmBranch:
|
case RelocationType::ArmBranch:
|
||||||
case PatchType::ModifyArmBranch:
|
case RelocationType::ModifyArmBranch:
|
||||||
case PatchType::AlignedRelativeAddress:
|
case RelocationType::AlignedRelativeAddress:
|
||||||
// TODO(wwylele): implement other types
|
// TODO(wwylele): implement other types
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
break;
|
break;
|
||||||
@ -457,42 +457,42 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies or resets a batch of patch
|
* Applies or resets a batch of relocations
|
||||||
* @param batch the virtual address of the first patch in the batch
|
* @param batch the virtual address of the first relocation in the batch
|
||||||
* @param symbol_address the symbol address to be patched with
|
* @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
|
* @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.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ApplyPatchBatch(VAddr batch, u32 symbol_address, bool reset = false) {
|
ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false) {
|
||||||
if (symbol_address == 0 && !reset)
|
if (symbol_address == 0 && !reset)
|
||||||
return CROFormatError(0x10);
|
return CROFormatError(0x10);
|
||||||
|
|
||||||
VAddr patch_address = batch;
|
VAddr relocation_address = batch;
|
||||||
while (true) {
|
while (true) {
|
||||||
PatchEntry patch;
|
RelocationEntry relocation;
|
||||||
Memory::ReadBlock(patch_address, &patch, sizeof(PatchEntry));
|
Memory::ReadBlock(relocation_address, &relocation, sizeof(RelocationEntry));
|
||||||
|
|
||||||
VAddr patch_target = SegmentTagToAddress(patch.target_position);
|
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
||||||
if (patch_target == 0) {
|
if (relocation_target == 0) {
|
||||||
return CROFormatError(0x12);
|
return CROFormatError(0x12);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = ApplyPatch(patch_target, patch.type, patch.shift, symbol_address, patch_target);
|
ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, symbol_address, relocation_target);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch.is_batch_end)
|
if (relocation.is_batch_end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
patch_address += sizeof(PatchEntry);
|
relocation_address += sizeof(RelocationEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchEntry patch;
|
RelocationEntry relocation;
|
||||||
Memory::ReadBlock(batch, &patch, sizeof(PatchEntry));
|
Memory::ReadBlock(batch, &relocation, sizeof(RelocationEntry));
|
||||||
patch.is_batch_resolved = reset ? 0 : 1;
|
relocation.is_batch_resolved = reset ? 0 : 1;
|
||||||
Memory::WriteBlock(batch, &patch, sizeof(PatchEntry));
|
Memory::WriteBlock(batch, &relocation, sizeof(RelocationEntry));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,14 +584,14 @@ class CROHelper final {
|
|||||||
ExportIndexedSymbolTableOffset,
|
ExportIndexedSymbolTableOffset,
|
||||||
ExportStringsOffset,
|
ExportStringsOffset,
|
||||||
ImportModuleTableOffset,
|
ImportModuleTableOffset,
|
||||||
ExternalPatchTableOffset,
|
ExternalRelocationTableOffset,
|
||||||
ImportNamedSymbolTableOffset,
|
ImportNamedSymbolTableOffset,
|
||||||
ImportIndexedSymbolTableOffset,
|
ImportIndexedSymbolTableOffset,
|
||||||
ImportAnonymousSymbolTableOffset,
|
ImportAnonymousSymbolTableOffset,
|
||||||
ImportStringsOffset,
|
ImportStringsOffset,
|
||||||
StaticAnonymousSymbolTableOffset,
|
StaticAnonymousSymbolTableOffset,
|
||||||
InternalPatchTableOffset,
|
InternalRelocationTableOffset,
|
||||||
StaticPatchTableOffset,
|
StaticRelocationTableOffset,
|
||||||
DataOffset,
|
DataOffset,
|
||||||
FileSize
|
FileSize
|
||||||
}};
|
}};
|
||||||
@ -780,8 +780,8 @@ class CROHelper final {
|
|||||||
ResultCode RebaseImportNamedSymbolTable() {
|
ResultCode RebaseImportNamedSymbolTable() {
|
||||||
VAddr import_strings_offset = GetField(ImportStringsOffset);
|
VAddr import_strings_offset = GetField(ImportStringsOffset);
|
||||||
VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize);
|
VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize);
|
||||||
VAddr external_patch_table_offset = GetField(ExternalPatchTableOffset);
|
VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
|
||||||
VAddr external_patch_table_end = external_patch_table_offset + GetField(ExternalPatchNum) * sizeof(ExternalPatchEntry);
|
VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||||
|
|
||||||
u32 num = GetField(ImportNamedSymbolNum);
|
u32 num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < num ; ++i) {
|
for (u32 i = 0; i < num ; ++i) {
|
||||||
@ -796,10 +796,10 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.patch_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.patch_batch_offset += module_address;
|
entry.relocation_batch_offset += module_address;
|
||||||
if (entry.patch_batch_offset < external_patch_table_offset
|
if (entry.relocation_batch_offset < external_relocation_table_offset
|
||||||
|| entry.patch_batch_offset > external_patch_table_end) {
|
|| entry.relocation_batch_offset > external_relocation_table_end) {
|
||||||
return CROFormatError(0x1B);
|
return CROFormatError(0x1B);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,18 +814,18 @@ class CROHelper final {
|
|||||||
* @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode RebaseImportIndexedSymbolTable() {
|
ResultCode RebaseImportIndexedSymbolTable() {
|
||||||
VAddr external_patch_table_offset = GetField(ExternalPatchTableOffset);
|
VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
|
||||||
VAddr external_patch_table_end = external_patch_table_offset + GetField(ExternalPatchNum) * sizeof(ExternalPatchEntry);
|
VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||||
|
|
||||||
u32 num = GetField(ImportIndexedSymbolNum);
|
u32 num = GetField(ImportIndexedSymbolNum);
|
||||||
for (u32 i = 0; i < num ; ++i) {
|
for (u32 i = 0; i < num ; ++i) {
|
||||||
ImportIndexedSymbolEntry entry;
|
ImportIndexedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
|
|
||||||
if (entry.patch_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.patch_batch_offset += module_address;
|
entry.relocation_batch_offset += module_address;
|
||||||
if (entry.patch_batch_offset < external_patch_table_offset
|
if (entry.relocation_batch_offset < external_relocation_table_offset
|
||||||
|| entry.patch_batch_offset > external_patch_table_end) {
|
|| entry.relocation_batch_offset > external_relocation_table_end) {
|
||||||
return CROFormatError(0x14);
|
return CROFormatError(0x14);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,18 +840,18 @@ class CROHelper final {
|
|||||||
* @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode RebaseImportAnonymousSymbolTable() {
|
ResultCode RebaseImportAnonymousSymbolTable() {
|
||||||
VAddr external_patch_table_offset = GetField(ExternalPatchTableOffset);
|
VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
|
||||||
VAddr external_patch_table_end = external_patch_table_offset + GetField(ExternalPatchNum) * sizeof(ExternalPatchEntry);
|
VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||||
|
|
||||||
u32 num = GetField(ImportAnonymousSymbolNum);
|
u32 num = GetField(ImportAnonymousSymbolNum);
|
||||||
for (u32 i = 0; i < num ; ++i) {
|
for (u32 i = 0; i < num ; ++i) {
|
||||||
ImportAnonymousSymbolEntry entry;
|
ImportAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
|
|
||||||
if (entry.patch_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.patch_batch_offset += module_address;
|
entry.relocation_batch_offset += module_address;
|
||||||
if (entry.patch_batch_offset < external_patch_table_offset
|
if (entry.relocation_batch_offset < external_relocation_table_offset
|
||||||
|| entry.patch_batch_offset > external_patch_table_end) {
|
|| entry.relocation_batch_offset > external_relocation_table_end) {
|
||||||
return CROFormatError(0x17);
|
return CROFormatError(0x17);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -863,7 +863,7 @@ class CROHelper final {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the address of OnUnresolved function in this module.
|
* Gets the address of OnUnresolved function in this module.
|
||||||
* Used as the applied symbol for reset patch.
|
* Used as the applied symbol for reset relocation.
|
||||||
* @returns the virtual address of OnUnresolved. 0 if not provided.
|
* @returns the virtual address of OnUnresolved. 0 if not provided.
|
||||||
*/
|
*/
|
||||||
VAddr GetOnUnresolvedAddress() {
|
VAddr GetOnUnresolvedAddress() {
|
||||||
@ -871,79 +871,79 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets all external patches to unresolved state.
|
* Resets all external relocations to unresolved state.
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ResetExternalPatches() {
|
ResultCode ResetExternalRelocations() {
|
||||||
u32 unresolved_symbol = GetOnUnresolvedAddress();
|
u32 unresolved_symbol = GetOnUnresolvedAddress();
|
||||||
u32 external_patch_num = GetField(ExternalPatchNum);
|
u32 external_relocation_num = GetField(ExternalRelocationNum);
|
||||||
ExternalPatchEntry patch;
|
ExternalRelocationEntry relocation;
|
||||||
|
|
||||||
// Verifies that the last patch is the end of a batch
|
// Verifies that the last relocation is the end of a batch
|
||||||
GetEntry(external_patch_num - 1, patch);
|
GetEntry(external_relocation_num - 1, relocation);
|
||||||
if (!patch.is_batch_end) {
|
if (!relocation.is_batch_end) {
|
||||||
return CROFormatError(0x12);
|
return CROFormatError(0x12);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool batch_begin = true;
|
bool batch_begin = true;
|
||||||
for (u32 i = 0; i < external_patch_num; ++i) {
|
for (u32 i = 0; i < external_relocation_num; ++i) {
|
||||||
GetEntry(i, patch);
|
GetEntry(i, relocation);
|
||||||
VAddr patch_target = SegmentTagToAddress(patch.target_position);
|
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
||||||
|
|
||||||
if (patch_target == 0) {
|
if (relocation_target == 0) {
|
||||||
return CROFormatError(0x12);
|
return CROFormatError(0x12);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = ApplyPatch(patch_target, patch.type, patch.shift, unresolved_symbol, patch_target);
|
ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, unresolved_symbol, relocation_target);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch_begin) {
|
if (batch_begin) {
|
||||||
// resets to unresolved state
|
// resets to unresolved state
|
||||||
patch.is_batch_resolved = 0;
|
relocation.is_batch_resolved = 0;
|
||||||
SetEntry(i, patch);
|
SetEntry(i, relocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if current is an end, then the next is a beginning
|
// if current is an end, then the next is a beginning
|
||||||
batch_begin = patch.is_batch_end != 0;
|
batch_begin = relocation.is_batch_end != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all external patches to zero.
|
* Clears all external relocations to zero.
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ClearExternalPatches() {
|
ResultCode ClearExternalRelocations() {
|
||||||
u32 external_patch_num = GetField(ExternalPatchNum);
|
u32 external_relocation_num = GetField(ExternalRelocationNum);
|
||||||
ExternalPatchEntry patch;
|
ExternalRelocationEntry relocation;
|
||||||
|
|
||||||
bool batch_begin = true;
|
bool batch_begin = true;
|
||||||
for (u32 i = 0; i < external_patch_num; ++i) {
|
for (u32 i = 0; i < external_relocation_num; ++i) {
|
||||||
GetEntry(i, patch);
|
GetEntry(i, relocation);
|
||||||
VAddr patch_target = SegmentTagToAddress(patch.target_position);
|
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
||||||
|
|
||||||
if (patch_target == 0) {
|
if (relocation_target == 0) {
|
||||||
return CROFormatError(0x12);
|
return CROFormatError(0x12);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = ClearPatch(patch_target, patch.type);
|
ResultCode result = ClearRelocation(relocation_target, relocation.type);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error clearing patch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch_begin) {
|
if (batch_begin) {
|
||||||
// resets to unresolved state
|
// resets to unresolved state
|
||||||
patch.is_batch_resolved = 0;
|
relocation.is_batch_resolved = 0;
|
||||||
SetEntry(i, patch);
|
SetEntry(i, relocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if current is an end, then the next is a beginning
|
// if current is an end, then the next is a beginning
|
||||||
batch_begin = patch.is_batch_end != 0;
|
batch_begin = relocation.is_batch_end != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
@ -955,8 +955,8 @@ class CROHelper final {
|
|||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
|
ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
|
||||||
VAddr static_patch_table_offset = GetField(StaticPatchTableOffset);
|
VAddr static_relocation_table_offset = GetField(StaticRelocationTableOffset);
|
||||||
VAddr static_patch_table_end = static_patch_table_offset + GetField(StaticPatchNum) * sizeof(StaticPatchEntry);
|
VAddr static_relocation_table_end = static_relocation_table_offset + GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
|
||||||
|
|
||||||
CROHelper crs(crs_address);
|
CROHelper crs(crs_address);
|
||||||
u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
|
u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
|
||||||
@ -964,18 +964,18 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < offset_export_num; ++i) {
|
for (u32 i = 0; i < offset_export_num; ++i) {
|
||||||
StaticAnonymousSymbolEntry entry;
|
StaticAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
u32 batch_address = entry.patch_batch_offset + module_address;
|
u32 batch_address = entry.relocation_batch_offset + module_address;
|
||||||
|
|
||||||
if (batch_address < static_patch_table_offset
|
if (batch_address < static_relocation_table_offset
|
||||||
|| batch_address > static_patch_table_end) {
|
|| batch_address > static_relocation_table_end) {
|
||||||
return CROFormatError(0x16);
|
return CROFormatError(0x16);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 symbol_address = SegmentTagToAddress(entry.symbol_position);
|
u32 symbol_address = SegmentTagToAddress(entry.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module", ModuleName().data(), symbol_address);
|
LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module", ModuleName().data(), symbol_address);
|
||||||
ResultCode result = crs.ApplyPatchBatch(batch_address, symbol_address);
|
ResultCode result = crs.ApplyRelocationBatch(batch_address, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -983,42 +983,42 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies all internal patches to the module itself.
|
* Applies all internal relocations to the module itself.
|
||||||
* @param old_data_segment_address the virtual address of data segment in CRO buffer
|
* @param old_data_segment_address the virtual address of data segment in CRO buffer
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ApplyInternalPatches(u32 old_data_segment_address) {
|
ResultCode ApplyInternalRelocations(u32 old_data_segment_address) {
|
||||||
u32 segment_num = GetField(SegmentNum);
|
u32 segment_num = GetField(SegmentNum);
|
||||||
u32 internal_patch_num = GetField(InternalPatchNum);
|
u32 internal_relocation_num = GetField(InternalRelocationNum);
|
||||||
for (u32 i = 0; i < internal_patch_num; ++i) {
|
for (u32 i = 0; i < internal_relocation_num; ++i) {
|
||||||
InternalPatchEntry patch;
|
InternalRelocationEntry relocation;
|
||||||
GetEntry(i, patch);
|
GetEntry(i, relocation);
|
||||||
VAddr target_addressB = SegmentTagToAddress(patch.target_position);
|
VAddr target_addressB = SegmentTagToAddress(relocation.target_position);
|
||||||
if (target_addressB == 0) {
|
if (target_addressB == 0) {
|
||||||
return CROFormatError(0x15);
|
return CROFormatError(0x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
VAddr target_address;
|
VAddr target_address;
|
||||||
SegmentEntry target_segment;
|
SegmentEntry target_segment;
|
||||||
GetEntry(patch.target_position.segment_index, target_segment);
|
GetEntry(relocation.target_position.segment_index, target_segment);
|
||||||
|
|
||||||
if (target_segment.type == SegmentType::Data) {
|
if (target_segment.type == SegmentType::Data) {
|
||||||
// If the patch is to the .data segment, we need to patch it in the old buffer
|
// If the relocation is to the .data segment, we need to relocate it in the old buffer
|
||||||
target_address = old_data_segment_address + patch.target_position.offset_into_segment;
|
target_address = old_data_segment_address + relocation.target_position.offset_into_segment;
|
||||||
} else {
|
} else {
|
||||||
target_address = target_addressB;
|
target_address = target_addressB;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patch.symbol_segment >= segment_num) {
|
if (relocation.symbol_segment >= segment_num) {
|
||||||
return CROFormatError(0x15);
|
return CROFormatError(0x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentEntry symbol_segment;
|
SegmentEntry symbol_segment;
|
||||||
GetEntry(patch.symbol_segment, symbol_segment);
|
GetEntry(relocation.symbol_segment, symbol_segment);
|
||||||
LOG_TRACE(Service_LDR, "Internally patches 0x%08X with 0x%08X", target_address, symbol_segment.offset);
|
LOG_TRACE(Service_LDR, "Internally relocates 0x%08X with 0x%08X", target_address, symbol_segment.offset);
|
||||||
ResultCode result = ApplyPatch(target_address, patch.type, patch.shift, symbol_segment.offset, target_addressB);
|
ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend, symbol_segment.offset, target_addressB);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1026,23 +1026,23 @@ class CROHelper final {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all internal patches to zero.
|
* Clears all internal relocations to zero.
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ClearInternalPatches() {
|
ResultCode ClearInternalRelocations() {
|
||||||
u32 internal_patch_num = GetField(InternalPatchNum);
|
u32 internal_relocation_num = GetField(InternalRelocationNum);
|
||||||
for (u32 i = 0; i < internal_patch_num; ++i) {
|
for (u32 i = 0; i < internal_relocation_num; ++i) {
|
||||||
InternalPatchEntry patch;
|
InternalRelocationEntry relocation;
|
||||||
GetEntry(i, patch);
|
GetEntry(i, relocation);
|
||||||
VAddr target_address = SegmentTagToAddress(patch.target_position);
|
VAddr target_address = SegmentTagToAddress(relocation.target_position);
|
||||||
|
|
||||||
if (target_address == 0) {
|
if (target_address == 0) {
|
||||||
return CROFormatError(0x15);
|
return CROFormatError(0x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = ClearPatch(target_address, patch.type);
|
ResultCode result = ClearRelocation(target_address, relocation.type);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error clearing patch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error clearing relocation %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1056,8 +1056,8 @@ class CROHelper final {
|
|||||||
ImportAnonymousSymbolEntry entry;
|
ImportAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
|
|
||||||
if (entry.patch_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.patch_batch_offset -= module_address;
|
entry.relocation_batch_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(i, entry);
|
||||||
@ -1071,8 +1071,8 @@ class CROHelper final {
|
|||||||
ImportIndexedSymbolEntry entry;
|
ImportIndexedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
|
|
||||||
if (entry.patch_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.patch_batch_offset -= module_address;
|
entry.relocation_batch_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(i, entry);
|
||||||
@ -1090,8 +1090,8 @@ class CROHelper final {
|
|||||||
entry.name_offset -= module_address;
|
entry.name_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.patch_batch_offset) {
|
if (entry.relocation_batch_offset) {
|
||||||
entry.patch_batch_offset -= module_address;
|
entry.relocation_batch_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(i, entry);
|
||||||
@ -1178,11 +1178,11 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < symbol_import_num; ++i) {
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (!patch_entry.is_batch_resolved) {
|
if (!relocation_entry.is_batch_resolved) {
|
||||||
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||||
std::string symbol_name = Memory::ReadCString(entry.name_offset, import_strings_size);
|
std::string symbol_name = Memory::ReadCString(entry.name_offset, import_strings_size);
|
||||||
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
|
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
|
||||||
@ -1191,9 +1191,9 @@ class CROHelper final {
|
|||||||
LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"",
|
LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"",
|
||||||
ModuleName().data(), symbol_name.data(), source.ModuleName().data());
|
ModuleName().data(), symbol_name.data(), source.ModuleName().data());
|
||||||
|
|
||||||
ResultCode result = ApplyPatchBatch(patch_addr, symbol_address);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1221,13 +1221,13 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < symbol_import_num; ++i) {
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
ResultCode result = ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error reseting patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1246,13 +1246,13 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < import_num; ++i) {
|
for (u32 i = 0; i < import_num; ++i) {
|
||||||
ImportIndexedSymbolEntry entry;
|
ImportIndexedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
ResultCode result = ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error reseting patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1270,13 +1270,13 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < import_num; ++i) {
|
for (u32 i = 0; i < import_num; ++i) {
|
||||||
ImportAnonymousSymbolEntry entry;
|
ImportAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
ResultCode result = ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error reseting patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1308,9 +1308,9 @@ class CROHelper final {
|
|||||||
source.GetEntry(im.index, ex);
|
source.GetEntry(im.index, ex);
|
||||||
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
|
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
||||||
ResultCode result = ApplyPatchBatch(im.patch_batch_offset, symbol_address);
|
ResultCode result = ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1321,9 +1321,9 @@ class CROHelper final {
|
|||||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||||
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
|
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
||||||
ResultCode result = ApplyPatchBatch(im.patch_batch_offset, symbol_address);
|
ResultCode result = ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1351,18 +1351,18 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
target.GetEntry(i, entry);
|
target.GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (!patch_entry.is_batch_resolved) {
|
if (!relocation_entry.is_batch_resolved) {
|
||||||
std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
||||||
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
||||||
if (symbol_address != 0) {
|
if (symbol_address != 0) {
|
||||||
LOG_TRACE(Service_LDR, " exports symbol \"%s\"", symbol_name.data());
|
LOG_TRACE(Service_LDR, " exports symbol \"%s\"", symbol_name.data());
|
||||||
ResultCode result = target.ApplyPatchBatch(patch_addr, symbol_address);
|
ResultCode result = target.ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1385,18 +1385,18 @@ class CROHelper final {
|
|||||||
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
target.GetEntry(i, entry);
|
target.GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (patch_entry.is_batch_resolved) {
|
if (relocation_entry.is_batch_resolved) {
|
||||||
std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
std::string symbol_name = Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
||||||
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
||||||
if (symbol_address != 0) {
|
if (symbol_address != 0) {
|
||||||
LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data());
|
LOG_TRACE(Service_LDR, " unexports symbol \"%s\"", symbol_name.data());
|
||||||
ResultCode result = target.ApplyPatchBatch(patch_addr, unresolved_symbol, true);
|
ResultCode result = target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1430,9 +1430,9 @@ class CROHelper final {
|
|||||||
GetEntry(im.index, ex);
|
GetEntry(im.index, ex);
|
||||||
u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
|
u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
|
LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
|
||||||
ResultCode result = target.ApplyPatchBatch(im.patch_batch_offset, symbol_address);
|
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1444,9 +1444,9 @@ class CROHelper final {
|
|||||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||||
u32 symbol_address = SegmentTagToAddress(im.symbol_position);
|
u32 symbol_address = SegmentTagToAddress(im.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
|
LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
|
||||||
ResultCode result = target.ApplyPatchBatch(im.patch_batch_offset, symbol_address);
|
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1478,9 +1478,9 @@ class CROHelper final {
|
|||||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||||
ImportIndexedSymbolEntry im;
|
ImportIndexedSymbolEntry im;
|
||||||
entry.GetImportIndexedSymbolEntry(j, im);
|
entry.GetImportIndexedSymbolEntry(j, im);
|
||||||
ResultCode result = target.ApplyPatchBatch(im.patch_batch_offset, unresolved_symbol, true);
|
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1490,9 +1490,9 @@ class CROHelper final {
|
|||||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||||
ImportAnonymousSymbolEntry im;
|
ImportAnonymousSymbolEntry im;
|
||||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||||
ResultCode result = target.ApplyPatchBatch(im.patch_batch_offset, unresolved_symbol, true);
|
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1506,15 +1506,15 @@ class CROHelper final {
|
|||||||
* @param crs_address the virtual address of the static module.
|
* @param crs_address the virtual address of the static module.
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ApplyExitPatches(VAddr crs_address) {
|
ResultCode ApplyExitRelocations(VAddr crs_address) {
|
||||||
u32 import_strings_size = GetField(ImportStringsSize);
|
u32 import_strings_size = GetField(ImportStringsSize);
|
||||||
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < symbol_import_num; ++i) {
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(i, entry);
|
||||||
VAddr patch_addr = entry.patch_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalPatchEntry patch_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(patch_addr, &patch_entry, sizeof(ExternalPatchEntry));
|
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit"){
|
if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit"){
|
||||||
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||||
@ -1524,9 +1524,9 @@ class CROHelper final {
|
|||||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"",
|
LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"",
|
||||||
ModuleName().data(), source.ModuleName().data());
|
ModuleName().data(), source.ModuleName().data());
|
||||||
|
|
||||||
ResultCode result = ApplyPatchBatch(patch_addr, symbol_address);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying patch batch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1536,7 +1536,7 @@ class CROHelper final {
|
|||||||
return MakeResult<bool>(true);
|
return MakeResult<bool>(true);
|
||||||
});
|
});
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying exit patch %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying exit relocation %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1618,9 +1618,9 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ResetExternalPatches();
|
result = ResetExternalRelocations();
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error resetting all external patches %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error resetting all external relocations %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1656,16 +1656,16 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ApplyInternalPatches(prev_data_segment_address);
|
result = ApplyInternalRelocations(prev_data_segment_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying internal patches %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying internal relocations %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_crs) {
|
if (!is_crs) {
|
||||||
result = ApplyExitPatches(crs_address);
|
result = ApplyExitRelocations(crs_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error applying exit patches %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error applying exit relocations %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1720,10 +1720,10 @@ public:
|
|||||||
if (link_on_load_bug_fix) {
|
if (link_on_load_bug_fix) {
|
||||||
// this is a bug fix introduced by 7.2.0-17's LoadCRO_New
|
// this is a bug fix introduced by 7.2.0-17's LoadCRO_New
|
||||||
// The bug itself is:
|
// The bug itself is:
|
||||||
// If a patch target is in .data segment, it will patch to the
|
// If a relocation target is in .data segment, it will relocate to the
|
||||||
// user-specified buffer. But if this is linking during loading,
|
// user-specified buffer. But if this is linking during loading,
|
||||||
// the .data segment hasn't been tranfer from CRO to the buffer,
|
// the .data segment hasn't been tranfer from CRO to the buffer,
|
||||||
// thus the patch will be overwritten by data transfer.
|
// thus the relocation will be overwritten by data transfer.
|
||||||
// To fix this bug, we need temporarily restore the old .data segment
|
// To fix this bug, we need temporarily restore the old .data segment
|
||||||
// offset and apply imported symbols.
|
// offset and apply imported symbols.
|
||||||
|
|
||||||
@ -1835,19 +1835,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all patches to zero.
|
* Clears all relocations to zero.
|
||||||
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS on success, otherwise error code.
|
||||||
*/
|
*/
|
||||||
ResultCode ClearPatches() {
|
ResultCode ClearRelocations() {
|
||||||
ResultCode result = ClearExternalPatches();
|
ResultCode result = ClearExternalRelocations();
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error clearing external patches %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error clearing external relocations %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ClearInternalPatches();
|
result = ClearInternalRelocations();
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error clearing internal patches %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error clearing internal relocations %08X", result.raw);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
@ -2037,14 +2037,14 @@ const std::array<int, 17> CROHelper::ENTRY_SIZE {{
|
|||||||
1, // export strings
|
1, // export strings
|
||||||
sizeof(ExportTreeEntry),
|
sizeof(ExportTreeEntry),
|
||||||
sizeof(ImportModuleEntry),
|
sizeof(ImportModuleEntry),
|
||||||
sizeof(ExternalPatchEntry),
|
sizeof(ExternalRelocationEntry),
|
||||||
sizeof(ImportNamedSymbolEntry),
|
sizeof(ImportNamedSymbolEntry),
|
||||||
sizeof(ImportIndexedSymbolEntry),
|
sizeof(ImportIndexedSymbolEntry),
|
||||||
sizeof(ImportAnonymousSymbolEntry),
|
sizeof(ImportAnonymousSymbolEntry),
|
||||||
1, // import strings
|
1, // import strings
|
||||||
sizeof(StaticAnonymousSymbolEntry),
|
sizeof(StaticAnonymousSymbolEntry),
|
||||||
sizeof(InternalPatchEntry),
|
sizeof(InternalRelocationEntry),
|
||||||
sizeof(StaticPatchEntry)
|
sizeof(StaticRelocationEntry)
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS {{
|
const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS {{
|
||||||
@ -2576,12 +2576,12 @@ static void UnloadCRO(Service::Interface* self) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the module is not fixed, clears all external/internal patches
|
// If the module is not fixed, clears all external/internal relocations
|
||||||
// to restore the state before loading, so that it can be loaded again(?)
|
// to restore the state before loading, so that it can be loaded again(?)
|
||||||
if (!cro.IsFixed()) {
|
if (!cro.IsFixed()) {
|
||||||
result = cro.ClearPatches();
|
result = cro.ClearRelocations();
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error clearing patches %08X", result.raw);
|
LOG_ERROR(Service_LDR, "Error clearing relocations %08X", result.raw);
|
||||||
cmd_buff[1] = result.raw;
|
cmd_buff[1] = result.raw;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user