HLE/LDR: Fixed a few mistakes

This commit is contained in:
Subv 2016-01-03 07:43:55 -05:00
parent 1e88337cf1
commit 943ce6f6f5

View file

@ -82,8 +82,8 @@ struct ImportTableEntry {
struct ExportTreeEntry {
u16 segment_offset;
u16 unk;
u16 unk2;
u16 next;
u16 next_level;
u16 export_table_id;
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)
patch_address1 = &patch_address;
if (patch_address == 0x119C74)
__debugbreak();
switch (patch->type) {
case 2:
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;
}
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) {
Unk3Patch* patch = header.GetUnk3PatchEntry(i);
SegmentTableEntry segment = header.GetSegmentTableEntry(patch->GetTargetSegment());
@ -567,7 +570,7 @@ static void ApplyUnk3Patches(CROHeader& header, u32 base) {
u32 patches_table = base + patch->patches_offset;
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
for (int i = 0; i < header.import_table1_num; ++i) {
ImportTableEntry* entry = header.GetImportTable1Entry(i);
// The name is already relocated
char* entry_name = reinterpret_cast<char*>(Memory::GetPointer(entry->name_offset));
if (!strcmp(entry_name, "__aeabi_atexit")) {
// Only apply these patches if some previous CRO exports "nnroAeabiAtexit_"
auto export_ = loaded_exports.find("nnroAeabiAtexit_");
if (export_ == loaded_exports.end())
return;
// Only apply these patches if the CRS exports "nnroAeabiAtexit_"
u32 offset = FindExportByName(*crs, "nnroAeabiAtexit_");
ASSERT_MSG(offset, "Could not find nnroAeabiAtexit_ in the CRS");
// Patch it!
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;
}
}
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) {
ImportTableEntry* entry = header.GetImportTable1Entry(i);
Patch* patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
if (!patch->unk2) {
// The name offset is already relocated
std::string entry_name = reinterpret_cast<char*>(Memory::GetPointer(entry->name_offset));
auto export_ = loaded_exports.find(entry_name);
if (export_ == loaded_exports.end())
continue;
u32 patch_base = export_->second.cro_offset;
u32 patch_base = 0;
while (head) {
patch_base = FindExportByName(*head, (char*)Memory::GetPointer(entry->name_offset));
if (patch_base)
break;
head = reinterpret_cast<CROHeader*>(Memory::GetPointer(head->next_cro));
}
if (patch_base) {
Patch* first_patch = reinterpret_cast<Patch*>(Memory::GetPointer(entry->symbol_offset));
ApplyListPatches(header, first_patch, patch_base);
}
}
}
}
static u32 GetCROBaseByName(char* name) {
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) {
if (crs->next_cro) {
auto v3 = reinterpret_cast<CROHeader*>(Memory::GetPointer(crs->next_cro));
if (v3) {
crs = reinterpret_cast<CROHeader*>(Memory::GetPointer(v3->previous_cro));
new_cro.previous_cro = v3->previous_cro;
new_cro.next_cro = 0;
@ -763,7 +785,7 @@ static void LinkCROs(CROHeader* crs, CROHeader& new_cro, u32 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
if (!header.VerifyAndRelocateOffsets(base, size))
return ResultCode(0xD9012C11);
@ -777,7 +799,7 @@ static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_sectio
u32 prev_section0 = 0;
ResultCode result = RESULT_SUCCESS;
if (!crs) {
if (!is_crs) {
// Relocate segments
result = header.RelocateSegmentsTable(base, size, data_section0, data_section1, prev_section0);
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)
return ResultCode(0xD9012C0B);
CROHeader* crs = nullptr;
if (is_crs)
crs = &header;
else
crs = reinterpret_cast<CROHeader*>(Memory::GetPointer(loaded_cros.front()));
// Rebase unk2
header.RelocateUnk2Patches(base);
@ -807,22 +835,24 @@ static ResultCode LoadCRO(u32 base, u32 size, CROHeader& header, u32 data_sectio
header.RelocateImportTable2(base);
header.RelocateImportTable3(base);
if (!is_crs) {
// Apply unk3 patches
ApplyUnk3Patches(header, base);
ApplyUnk3Patches(header, crs, base);
}
// Apply relocation patches
ApplyRelocationPatches(header, base, prev_section0 + base);
// Apply import table 1 patches
ApplyExitPatches(header, base);
ApplyExitPatches(header, crs, base);
// Import Table 1
ApplyImportTable1Patches(header, base);
ApplyImportTable1Patches(header, crs);
// Load exports
LoadExportsTable(header, base);
if (!crs) {
if (!is_crs) {
// Apply unk2 patches
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) {
u32 cro_base = *itr;
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);
}
}
if (!crs) {
if (!is_crs) {
// Link the CROs
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
* Inputs:
* 1 : CRS buffer pointer
* 2 : CRS Size
* 1 : CRR buffer pointer
* 2 : CRR Size
* 3 : Value, must be zero
* 4 : KProcess handle
* Outputs:
@ -997,8 +1027,7 @@ static void LoadExeCRO(Service::Interface* self) {
bool link = cmd_buff[9] & 0xFF;
if (link)
LOG_CRITICAL(HW_GPU, "Something here");
ASSERT_MSG(link, "Link must be set");
std::shared_ptr<std::vector<u8>> cro = std::make_shared<std::vector<u8>>(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) {
auto v5 = reinterpret_cast<CROHeader*>(Memory::GetPointer(crs->previous_cro));
auto v5_base = crs->previous_cro;
if (v5_base == address) {
auto v5 = reinterpret_cast<CROHeader*>(Memory::GetPointer(v5_base));
auto v7_base = v5->next_cro;
if (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) {
v8->previous_cro = v16_base;
} else {
auto v5 = reinterpret_cast<CROHeader*>(Memory::GetPointer(v5_base));
v5->previous_cro = v16_base;
}
v16->next_cro = 0;
@ -1157,7 +1187,7 @@ static u32 CalculateBaseOffset(CROHeader* cro) {
if (cro->GetImportPatchesTargetSegment() < cro->segment_table_num) {
SegmentTableEntry base_segment = cro->GetSegmentTableEntry(cro->GetImportPatchesTargetSegment());
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;
@ -1375,12 +1405,11 @@ static ResultCode UnloadCRO(u32 address) {
UnloadImportTable2Patches(unload, base_offset);
UnloadImportTable3Patches(unload, base_offset);
ApplyCRSUnloadPatches(crs, *unload);
for (u32 base : loaded_cros) {
if (base == address)
continue;
CROHeader* cro = reinterpret_cast<CROHeader*>(Memory::GetPointer(base));
ApplyCRSUnloadPatches(cro, *unload);
base_offset = CalculateBaseOffset(cro);
UnloadUnk2Patches(cro, unload, base_offset);
}