mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 20:31:04 +00:00
HLE/LDR: Fixed a few mistakes
This commit is contained in:
parent
1e88337cf1
commit
943ce6f6f5
@ -82,8 +82,8 @@ struct ImportTableEntry {
|
|||||||
|
|
||||||
struct ExportTreeEntry {
|
struct ExportTreeEntry {
|
||||||
u16 segment_offset;
|
u16 segment_offset;
|
||||||
u16 unk;
|
u16 next;
|
||||||
u16 unk2;
|
u16 next_level;
|
||||||
u16 export_table_id;
|
u16 export_table_id;
|
||||||
|
|
||||||
u8 GetTargetSegment() { return segment_offset & 0x7; }
|
u8 GetTargetSegment() { return segment_offset & 0x7; }
|
||||||
@ -513,6 +513,9 @@ static void ApplyPatch(Patch* patch, u32 patch_base, u32 patch_address, u32* pat
|
|||||||
if (!patch_address1)
|
if (!patch_address1)
|
||||||
patch_address1 = &patch_address;
|
patch_address1 = &patch_address;
|
||||||
|
|
||||||
|
if (patch_address == 0x119C74)
|
||||||
|
__debugbreak();
|
||||||
|
|
||||||
switch (patch->type) {
|
switch (patch->type) {
|
||||||
case 2:
|
case 2:
|
||||||
Memory::Write32(patch_address, patch_base + patch->x);
|
Memory::Write32(patch_address, patch_base + patch->x);
|
||||||
@ -559,7 +562,7 @@ static void ApplyListPatches(CROHeader& header, Patch* first_patch, u32 patch_ba
|
|||||||
first_patch->unk2 = 1;
|
first_patch->unk2 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyUnk3Patches(CROHeader& header, u32 base) {
|
static void ApplyUnk3Patches(CROHeader& header, CROHeader* crs, u32 base) {
|
||||||
for (int i = 0; i < header.unk3_num; ++i) {
|
for (int i = 0; i < header.unk3_num; ++i) {
|
||||||
Unk3Patch* patch = header.GetUnk3PatchEntry(i);
|
Unk3Patch* patch = header.GetUnk3PatchEntry(i);
|
||||||
SegmentTableEntry segment = header.GetSegmentTableEntry(patch->GetTargetSegment());
|
SegmentTableEntry segment = header.GetSegmentTableEntry(patch->GetTargetSegment());
|
||||||
@ -567,7 +570,7 @@ static void ApplyUnk3Patches(CROHeader& header, u32 base) {
|
|||||||
u32 patches_table = base + patch->patches_offset;
|
u32 patches_table = base + patch->patches_offset;
|
||||||
|
|
||||||
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(patches_table));
|
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(patches_table));
|
||||||
ApplyListPatches(header, first_patch, patch_base);
|
ApplyListPatches(*crs, first_patch, patch_base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,45 +593,93 @@ static void ApplyRelocationPatches(CROHeader& header, u32 base, u32 section0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyExitPatches(CROHeader& header, u32 base) {
|
static const u32 EXPORT_TABLE_FINISHED = 0x8000;
|
||||||
|
|
||||||
|
static u32 FindExportByName(CROHeader& header, char* str) {
|
||||||
|
if (header.export_tree_num) {
|
||||||
|
ExportTreeEntry* first_entry = header.GetExportTreeEntry(0);
|
||||||
|
u32 len = strlen(str);
|
||||||
|
ExportTreeEntry* next_entry = header.GetExportTreeEntry(first_entry->next);
|
||||||
|
bool run = false;
|
||||||
|
while (!run) {
|
||||||
|
u16 next_offset = 0;
|
||||||
|
u32 next_len = next_entry->GetSegmentOffset();
|
||||||
|
u8 next_segment = str[next_len];
|
||||||
|
if (next_len >= len)
|
||||||
|
next_offset = next_entry->next;
|
||||||
|
else if (!((next_segment >> next_entry->GetTargetSegment()) & 1))
|
||||||
|
next_offset = next_entry->next;
|
||||||
|
else
|
||||||
|
next_offset = next_entry->next_level;
|
||||||
|
run = next_offset & EXPORT_TABLE_FINISHED;
|
||||||
|
next_entry = header.GetExportTreeEntry(next_offset & ~EXPORT_TABLE_FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 export_id = next_entry->export_table_id;
|
||||||
|
ExportTableEntry* export_entry = header.GetExportTableEntry(export_id);
|
||||||
|
char* export_name = (char*)Memory::GetPointer(export_entry->name_offset);
|
||||||
|
if (!strcmp(export_name, str)) {
|
||||||
|
SegmentTableEntry segment = header.GetSegmentTableEntry(export_entry->GetTargetSegment());
|
||||||
|
return segment.segment_offset + export_entry->GetSegmentOffset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ApplyExitPatches(CROHeader& header, CROHeader* crs, u32 base) {
|
||||||
// Find the "__aeabi_atexit" in the import table 1
|
// Find the "__aeabi_atexit" in the import table 1
|
||||||
for (int i = 0; i < header.import_table1_num; ++i) {
|
for (int i = 0; i < header.import_table1_num; ++i) {
|
||||||
ImportTableEntry* entry = header.GetImportTable1Entry(i);
|
ImportTableEntry* entry = header.GetImportTable1Entry(i);
|
||||||
// The name is already relocated
|
// The name is already relocated
|
||||||
char* entry_name = reinterpret_cast<char*>(Memory::GetPointer(entry->name_offset));
|
char* entry_name = reinterpret_cast<char*>(Memory::GetPointer(entry->name_offset));
|
||||||
if (!strcmp(entry_name, "__aeabi_atexit")) {
|
if (!strcmp(entry_name, "__aeabi_atexit")) {
|
||||||
// Only apply these patches if some previous CRO exports "nnroAeabiAtexit_"
|
// Only apply these patches if the CRS exports "nnroAeabiAtexit_"
|
||||||
auto export_ = loaded_exports.find("nnroAeabiAtexit_");
|
u32 offset = FindExportByName(*crs, "nnroAeabiAtexit_");
|
||||||
if (export_ == loaded_exports.end())
|
|
||||||
return;
|
ASSERT_MSG(offset, "Could not find nnroAeabiAtexit_ in the CRS");
|
||||||
|
|
||||||
// Patch it!
|
// Patch it!
|
||||||
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
||||||
ApplyListPatches(header, first_patch, export_->second.cro_offset);
|
ApplyListPatches(header, first_patch, offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_ERROR(Service_LDR, "Could not find __aeabi_atexit in the CRO imports!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ApplyImportTable1Patches(CROHeader& header, u32 base) {
|
static void BackApplyImportTable1Patches(CROHeader& old_header, CROHeader& new_header) {
|
||||||
|
for (int i = 0; i < old_header.import_table1_num; ++i) {
|
||||||
|
ImportTableEntry* entry = old_header.GetImportTable1Entry(i);
|
||||||
|
Patch* patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
||||||
|
if (!patch->unk2) {
|
||||||
|
u32 patch_base = FindExportByName(new_header, (char*)Memory::GetPointer(entry->name_offset));
|
||||||
|
|
||||||
|
if (patch_base) {
|
||||||
|
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
||||||
|
ApplyListPatches(old_header, first_patch, patch_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ApplyImportTable1Patches(CROHeader& header, CROHeader* head) {
|
||||||
for (int i = 0; i < header.import_table1_num; ++i) {
|
for (int i = 0; i < header.import_table1_num; ++i) {
|
||||||
ImportTableEntry* entry = header.GetImportTable1Entry(i);
|
ImportTableEntry* entry = header.GetImportTable1Entry(i);
|
||||||
Patch* patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
Patch* patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
||||||
if (!patch->unk2) {
|
if (!patch->unk2) {
|
||||||
// The name offset is already relocated
|
u32 patch_base = 0;
|
||||||
std::string entry_name = reinterpret_cast<char*>(Memory::GetPointer(entry->name_offset));
|
while (head) {
|
||||||
auto export_ = loaded_exports.find(entry_name);
|
patch_base = FindExportByName(*head, (char*)Memory::GetPointer(entry->name_offset));
|
||||||
if (export_ == loaded_exports.end())
|
if (patch_base)
|
||||||
continue;
|
break;
|
||||||
|
head = reinterpret_cast<CROHeader*>(Memory::GetPointer(head->next_cro));
|
||||||
u32 patch_base = export_->second.cro_offset;
|
}
|
||||||
|
if (patch_base) {
|
||||||
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
|
||||||
ApplyListPatches(header, first_patch, patch_base);
|
ApplyListPatches(header, first_patch, patch_base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static u32 GetCROBaseByName(char* name) {
|
static u32 GetCROBaseByName(char* name) {
|
||||||
for (u32 base : loaded_cros) {
|
for (u32 base : loaded_cros) {
|
||||||
@ -719,38 +770,9 @@ static void LoadExportsTable(CROHeader& header, u32 base) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 FindExportByName(CROHeader& header, char* str) {
|
|
||||||
if (header.export_tree_num) {
|
|
||||||
ExportTreeEntry* first_entry = header.GetExportTreeEntry(0);
|
|
||||||
u32 len = strlen(str);
|
|
||||||
ExportTreeEntry* next_entry = header.GetExportTreeEntry(first_entry->unk);
|
|
||||||
bool v16 = false;
|
|
||||||
do {
|
|
||||||
u16 v14 = 0;
|
|
||||||
bool v12 = next_entry->GetSegmentOffset() >= len;
|
|
||||||
if (v12 || !((*(str + next_entry->GetSegmentOffset()) >> next_entry->GetTargetSegment()) & 1))
|
|
||||||
v14 = next_entry->unk;
|
|
||||||
else
|
|
||||||
v14 = next_entry->unk2;
|
|
||||||
v16 = (v14 & 0x8000) == 0;
|
|
||||||
next_entry = header.GetExportTreeEntry(v14 & 0x7FFF);
|
|
||||||
} while (v16);
|
|
||||||
|
|
||||||
u32 export_id = next_entry->export_table_id;
|
|
||||||
ExportTableEntry* export_entry = header.GetExportTableEntry(export_id);
|
|
||||||
char* export_name = (char*)Memory::GetPointer(export_entry->name_offset);
|
|
||||||
if (!strcmp(export_name, str)) {
|
|
||||||
SegmentTableEntry segment = header.GetSegmentTableEntry(export_entry->GetTargetSegment());
|
|
||||||
return segment.segment_offset + export_entry->GetSegmentOffset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void LinkCROs(CROHeader* crs, CROHeader& new_cro, u32 base) {
|
static void LinkCROs(CROHeader* crs, CROHeader& new_cro, u32 base) {
|
||||||
|
if (crs->next_cro) {
|
||||||
auto v3 = reinterpret_cast<CROHeader*>(Memory::GetPointer(crs->next_cro));
|
auto v3 = reinterpret_cast<CROHeader*>(Memory::GetPointer(crs->next_cro));
|
||||||
|
|
||||||
if (v3) {
|
|
||||||
crs = reinterpret_cast<CROHeader*>(Memory::GetPointer(v3->previous_cro));
|
crs = reinterpret_cast<CROHeader*>(Memory::GetPointer(v3->previous_cro));
|
||||||
new_cro.previous_cro = v3->previous_cro;
|
new_cro.previous_cro = v3->previous_cro;
|
||||||
new_cro.next_cro = 0;
|
new_cro.next_cro = 0;
|
||||||
@ -763,7 +785,7 @@ static void LinkCROs(CROHeader* crs, CROHeader& new_cro, u32 base) {
|
|||||||
crs->next_cro = base;
|
crs->next_cro = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_section0, u32 data_section1, bool crs) {
|
static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_section0, u32 data_section1, bool is_crs) {
|
||||||
// Relocate all offsets
|
// Relocate all offsets
|
||||||
if (!header.VerifyAndRelocateOffsets(base, size))
|
if (!header.VerifyAndRelocateOffsets(base, size))
|
||||||
return ResultCode(0xD9012C11);
|
return ResultCode(0xD9012C11);
|
||||||
@ -777,7 +799,7 @@ static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_sectio
|
|||||||
u32 prev_section0 = 0;
|
u32 prev_section0 = 0;
|
||||||
ResultCode result = RESULT_SUCCESS;
|
ResultCode result = RESULT_SUCCESS;
|
||||||
|
|
||||||
if (!crs) {
|
if (!is_crs) {
|
||||||
// Relocate segments
|
// Relocate segments
|
||||||
result = header.RelocateSegmentsTable(base, size, data_section0, data_section1, prev_section0);
|
result = header.RelocateSegmentsTable(base, size, data_section0, data_section1, prev_section0);
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
@ -794,6 +816,12 @@ static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_sectio
|
|||||||
Memory::Read8(header.export_strings_offset + header.export_strings_num - 1) != 0)
|
Memory::Read8(header.export_strings_offset + header.export_strings_num - 1) != 0)
|
||||||
return ResultCode(0xD9012C0B);
|
return ResultCode(0xD9012C0B);
|
||||||
|
|
||||||
|
CROHeader* crs = nullptr;
|
||||||
|
if (is_crs)
|
||||||
|
crs = &header;
|
||||||
|
else
|
||||||
|
crs = reinterpret_cast<CROHeader*>(Memory::GetPointer(loaded_cros.front()));
|
||||||
|
|
||||||
// Rebase unk2
|
// Rebase unk2
|
||||||
header.RelocateUnk2Patches(base);
|
header.RelocateUnk2Patches(base);
|
||||||
|
|
||||||
@ -807,22 +835,24 @@ static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_sectio
|
|||||||
header.RelocateImportTable2(base);
|
header.RelocateImportTable2(base);
|
||||||
header.RelocateImportTable3(base);
|
header.RelocateImportTable3(base);
|
||||||
|
|
||||||
|
if (!is_crs) {
|
||||||
// Apply unk3 patches
|
// Apply unk3 patches
|
||||||
ApplyUnk3Patches(header, base);
|
ApplyUnk3Patches(header, crs, base);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply relocation patches
|
// Apply relocation patches
|
||||||
ApplyRelocationPatches(header, base, prev_section0 + base);
|
ApplyRelocationPatches(header, base, prev_section0 + base);
|
||||||
|
|
||||||
// Apply import table 1 patches
|
// Apply import table 1 patches
|
||||||
ApplyExitPatches(header, base);
|
ApplyExitPatches(header, crs, base);
|
||||||
|
|
||||||
// Import Table 1
|
// Import Table 1
|
||||||
ApplyImportTable1Patches(header, base);
|
ApplyImportTable1Patches(header, crs);
|
||||||
|
|
||||||
// Load exports
|
// Load exports
|
||||||
LoadExportsTable(header, base);
|
LoadExportsTable(header, base);
|
||||||
|
|
||||||
if (!crs) {
|
if (!is_crs) {
|
||||||
// Apply unk2 patches
|
// Apply unk2 patches
|
||||||
ApplyUnk2Patches(header, base);
|
ApplyUnk2Patches(header, base);
|
||||||
|
|
||||||
@ -831,12 +861,12 @@ static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_sectio
|
|||||||
for (auto itr = loaded_cros.rbegin(); itr != loaded_cros.rend(); ++itr) {
|
for (auto itr = loaded_cros.rbegin(); itr != loaded_cros.rend(); ++itr) {
|
||||||
u32 cro_base = *itr;
|
u32 cro_base = *itr;
|
||||||
CROHeader* cro_header = reinterpret_cast<CROHeader*>(Memory::GetPointer(cro_base));
|
CROHeader* cro_header = reinterpret_cast<CROHeader*>(Memory::GetPointer(cro_base));
|
||||||
ApplyImportTable1Patches(*cro_header, cro_base);
|
BackApplyImportTable1Patches(*cro_header, header);
|
||||||
BackApplyUnk2Patches(*cro_header, cro_base, header, base);
|
BackApplyUnk2Patches(*cro_header, cro_base, header, base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crs) {
|
if (!is_crs) {
|
||||||
// Link the CROs
|
// Link the CROs
|
||||||
LinkCROs(reinterpret_cast<CROHeader*>(Memory::GetPointer(loaded_cros.front())), header, base);
|
LinkCROs(reinterpret_cast<CROHeader*>(Memory::GetPointer(loaded_cros.front())), header, base);
|
||||||
}
|
}
|
||||||
@ -913,8 +943,8 @@ static void Initialize(Service::Interface* self) {
|
|||||||
/**
|
/**
|
||||||
* LDR_RO::LoadCRR service function
|
* LDR_RO::LoadCRR service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
* 1 : CRS buffer pointer
|
* 1 : CRR buffer pointer
|
||||||
* 2 : CRS Size
|
* 2 : CRR Size
|
||||||
* 3 : Value, must be zero
|
* 3 : Value, must be zero
|
||||||
* 4 : KProcess handle
|
* 4 : KProcess handle
|
||||||
* Outputs:
|
* Outputs:
|
||||||
@ -997,8 +1027,7 @@ static void LoadExeCRO(Service::Interface* self) {
|
|||||||
|
|
||||||
bool link = cmd_buff[9] & 0xFF;
|
bool link = cmd_buff[9] & 0xFF;
|
||||||
|
|
||||||
if (link)
|
ASSERT_MSG(link, "Link must be set");
|
||||||
LOG_CRITICAL(HW_GPU, "Something here");
|
|
||||||
|
|
||||||
std::shared_ptr<std::vector<u8>> cro = std::make_shared<std::vector<u8>>(size);
|
std::shared_ptr<std::vector<u8>> cro = std::make_shared<std::vector<u8>>(size);
|
||||||
memcpy(cro->data(), cro_buffer, size);
|
memcpy(cro->data(), cro_buffer, size);
|
||||||
@ -1090,10 +1119,10 @@ static void LoadExeCRO(Service::Interface* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void UnlinkCRO(CROHeader* crs, CROHeader* cro, u32 address) {
|
static void UnlinkCRO(CROHeader* crs, CROHeader* cro, u32 address) {
|
||||||
auto v5 = reinterpret_cast<CROHeader*>(Memory::GetPointer(crs->previous_cro));
|
|
||||||
auto v5_base = crs->previous_cro;
|
auto v5_base = crs->previous_cro;
|
||||||
|
|
||||||
if (v5_base == address) {
|
if (v5_base == address) {
|
||||||
|
auto v5 = reinterpret_cast<CROHeader*>(Memory::GetPointer(v5_base));
|
||||||
auto v7_base = v5->next_cro;
|
auto v7_base = v5->next_cro;
|
||||||
if (v7_base) {
|
if (v7_base) {
|
||||||
auto v7 = reinterpret_cast<CROHeader*>(Memory::GetPointer(v7_base));
|
auto v7 = reinterpret_cast<CROHeader*>(Memory::GetPointer(v7_base));
|
||||||
@ -1125,6 +1154,7 @@ static void UnlinkCRO(CROHeader* crs, CROHeader* cro, u32 address) {
|
|||||||
if (v8_base && v8->previous_cro == address) {
|
if (v8_base && v8->previous_cro == address) {
|
||||||
v8->previous_cro = v16_base;
|
v8->previous_cro = v16_base;
|
||||||
} else {
|
} else {
|
||||||
|
auto v5 = reinterpret_cast<CROHeader*>(Memory::GetPointer(v5_base));
|
||||||
v5->previous_cro = v16_base;
|
v5->previous_cro = v16_base;
|
||||||
}
|
}
|
||||||
v16->next_cro = 0;
|
v16->next_cro = 0;
|
||||||
@ -1157,7 +1187,7 @@ static u32 CalculateBaseOffset(CROHeader* cro) {
|
|||||||
if (cro->GetImportPatchesTargetSegment() < cro->segment_table_num) {
|
if (cro->GetImportPatchesTargetSegment() < cro->segment_table_num) {
|
||||||
SegmentTableEntry base_segment = cro->GetSegmentTableEntry(cro->GetImportPatchesTargetSegment());
|
SegmentTableEntry base_segment = cro->GetSegmentTableEntry(cro->GetImportPatchesTargetSegment());
|
||||||
if (cro->GetImportPatchesSegmentOffset() < base_segment.segment_size)
|
if (cro->GetImportPatchesSegmentOffset() < base_segment.segment_size)
|
||||||
base_offset = base_segment.segment_size + cro->GetImportPatchesSegmentOffset();
|
base_offset = base_segment.segment_offset + cro->GetImportPatchesSegmentOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
return base_offset;
|
return base_offset;
|
||||||
@ -1375,12 +1405,11 @@ static ResultCode UnloadCRO(u32 address) {
|
|||||||
UnloadImportTable2Patches(unload, base_offset);
|
UnloadImportTable2Patches(unload, base_offset);
|
||||||
UnloadImportTable3Patches(unload, base_offset);
|
UnloadImportTable3Patches(unload, base_offset);
|
||||||
|
|
||||||
ApplyCRSUnloadPatches(crs, *unload);
|
|
||||||
|
|
||||||
for (u32 base : loaded_cros) {
|
for (u32 base : loaded_cros) {
|
||||||
if (base == address)
|
if (base == address)
|
||||||
continue;
|
continue;
|
||||||
CROHeader* cro = reinterpret_cast<CROHeader*>(Memory::GetPointer(base));
|
CROHeader* cro = reinterpret_cast<CROHeader*>(Memory::GetPointer(base));
|
||||||
|
ApplyCRSUnloadPatches(cro, *unload);
|
||||||
base_offset = CalculateBaseOffset(cro);
|
base_offset = CalculateBaseOffset(cro);
|
||||||
UnloadUnk2Patches(cro, unload, base_offset);
|
UnloadUnk2Patches(cro, unload, base_offset);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user