Module: Keep HI16/LO16 in a temp state object.

This doesn't need to live any longer than the link or unlink, so let's
just make that abundantly clear.
This commit is contained in:
Unknown W. Brackets
2021-01-16 11:57:37 -08:00
parent 17f3de66c5
commit 6efd1ae7f4
+33 -33
View File
@@ -561,18 +561,18 @@ struct HI16RelocInfo {
u32 addr;
u32 data;
};
static void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type, bool reverse = false) {
// We have to post-process the HI16 part, since it might be +1 or not depending on the LO16 value.
static u32 lastHI16ExportAddress = 0;
// This is just a list of recent HI16s for the same export address.
static std::vector<HI16RelocInfo> lastHI16Relocs;
static bool lastHI16Processed = true;
static bool lastHI16Reverse = false;
// We have to post-process the HI16 part, since it might be +1 or not depending on the LO16 value.
// For that purpose, we use this state to track HI16s to adjust.
struct WriteVarSymbolState {
u32 lastHI16ExportAddress = 0;
std::vector<HI16RelocInfo> lastHI16Relocs;
bool lastHI16Processed = true;
};
static void WriteVarSymbol(WriteVarSymbolState &state, u32 exportAddress, u32 relocAddress, u8 type, bool reverse = false) {
u32 relocData = Memory::Read_Instruction(relocAddress, true).encoding;
switch (type)
{
switch (type) {
case R_MIPS_NONE:
WARN_LOG_REPORT(LOADER, "Var relocation type NONE - %08x => %08x", exportAddress, relocAddress);
break;
@@ -601,14 +601,13 @@ static void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type, bool re
*/
case R_MIPS_HI16:
if (lastHI16ExportAddress != exportAddress || lastHI16Reverse != reverse) {
if (!lastHI16Processed && !lastHI16Relocs.empty()) {
WARN_LOG_REPORT(LOADER, "Unsafe unpaired HI16 variable relocation @ %08x / %08x", lastHI16Relocs[lastHI16Relocs.size() - 1].addr, relocAddress);
if (state.lastHI16ExportAddress != exportAddress) {
if (!state.lastHI16Processed && !state.lastHI16Relocs.empty()) {
WARN_LOG_REPORT(LOADER, "Unsafe unpaired HI16 variable relocation @ %08x / %08x", state.lastHI16Relocs[state.lastHI16Relocs.size() - 1].addr, relocAddress);
}
lastHI16ExportAddress = exportAddress;
lastHI16Reverse = reverse;
lastHI16Relocs.clear();
state.lastHI16ExportAddress = exportAddress;
state.lastHI16Relocs.clear();
}
// After this will be an R_MIPS_LO16. If that addition overflows, we need to account for it in HI16.
@@ -616,8 +615,8 @@ static void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type, bool re
HI16RelocInfo reloc;
reloc.addr = relocAddress;
reloc.data = Memory::Read_Instruction(relocAddress, true).encoding;
lastHI16Relocs.push_back(reloc);
lastHI16Processed = false;
state.lastHI16Relocs.push_back(reloc);
state.lastHI16Processed = false;
break;
case R_MIPS_LO16:
@@ -633,16 +632,14 @@ static void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type, bool re
}
// The ABI requires that these come in pairs, at least.
if (lastHI16Relocs.empty()) {
if (state.lastHI16Relocs.empty()) {
ERROR_LOG_REPORT(LOADER, "LO16 without any HI16 variable import at %08x for %08x", relocAddress, exportAddress);
// Try to process at least the low relocation...
} else if (lastHI16ExportAddress != exportAddress) {
ERROR_LOG_REPORT(LOADER, "HI16 and LO16 imports do not match at %08x for %08x (should be %08x)", relocAddress, lastHI16ExportAddress, exportAddress);
} else if (lastHI16Reverse != reverse) {
ERROR_LOG_REPORT(LOADER, "HI16 and LO16 imports reversing mismatch");
} else if (state.lastHI16ExportAddress != exportAddress) {
ERROR_LOG_REPORT(LOADER, "HI16 and LO16 imports do not match at %08x for %08x (should be %08x)", relocAddress, state.lastHI16ExportAddress, exportAddress);
} else {
// Process each of the HI16. Usually there's only one.
for (auto &reloc : lastHI16Relocs) {
for (auto &reloc : state.lastHI16Relocs) {
if (!reverse) {
full = (reloc.data << 16) + offsetLo + exportAddress;
} else {
@@ -654,7 +651,7 @@ static void WriteVarSymbol(u32 exportAddress, u32 relocAddress, u8 type, bool re
Memory::Write_U32((reloc.data & ~0xFFFF) | high, reloc.addr);
currentMIPS->InvalidateICache(reloc.addr, 4);
}
lastHI16Processed = true;
state.lastHI16Processed = true;
}
// With full set above (hopefully), now we just need to correct the low instruction.
@@ -690,9 +687,10 @@ void ImportVarSymbol(const VarSymbolImport &var) {
}
// Look for exports currently loaded modules already have. Maybe it's available?
for (auto it = module->exportedVars.begin(), end = module->exportedVars.end(); it != end; ++it) {
if (it->Matches(var)) {
WriteVarSymbol(it->symAddr, var.stubAddr, var.type);
WriteVarSymbolState state;
for (const auto &exported : module->exportedVars) {
if (exported.Matches(var)) {
WriteVarSymbol(state, exported.symAddr, var.stubAddr, var.type);
return;
}
}
@@ -711,10 +709,11 @@ void ExportVarSymbol(const VarSymbolExport &var) {
}
// Look for imports currently loaded modules already have, hook it up right away.
for (auto it = module->importedVars.begin(), end = module->importedVars.end(); it != end; ++it) {
if (var.Matches(*it)) {
WriteVarSymbolState state;
for (auto &imported : module->importedVars) {
if (var.Matches(imported)) {
INFO_LOG(LOADER, "Resolving var %s/%08x", var.moduleName, var.nid);
WriteVarSymbol(var.symAddr, it->stubAddr, it->type);
WriteVarSymbol(state, var.symAddr, imported.stubAddr, imported.type);
}
}
}
@@ -729,10 +728,11 @@ void UnexportVarSymbol(const VarSymbolExport &var) {
}
// Look for imports modules that are *still* loaded have, and reverse them.
for (auto it = module->importedVars.begin(), end = module->importedVars.end(); it != end; ++it) {
if (var.Matches(*it)) {
WriteVarSymbolState state;
for (auto &imported : module->importedVars) {
if (var.Matches(imported)) {
INFO_LOG(LOADER, "Unresolving var %s/%08x", var.moduleName, var.nid);
WriteVarSymbol(var.symAddr, it->stubAddr, it->type, true);
WriteVarSymbol(state, var.symAddr, imported.stubAddr, imported.type, true);
}
}
}