mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
feat: update memory hint handling and enhance entry point discovery logic
This commit is contained in:
@@ -69,14 +69,8 @@ namespace ps2recomp
|
||||
|
||||
MemoryAccessHint InstructionTranslator::effectiveMemoryHintFor(const Instruction &inst, const MemoryAccessHint &memoryHint) const
|
||||
{
|
||||
MemoryAccessHint effectiveMemoryHint = memoryHint;
|
||||
if (inst.isMmio)
|
||||
{
|
||||
effectiveMemoryHint.hasAddress = true;
|
||||
effectiveMemoryHint.address = inst.mmioAddress;
|
||||
}
|
||||
|
||||
return effectiveMemoryHint;
|
||||
// TODO disable for now since it causing issues with some games.
|
||||
return memoryHint;
|
||||
}
|
||||
|
||||
std::string InstructionTranslator::translateMemoryRead(const Instruction &inst,
|
||||
@@ -190,11 +184,11 @@ namespace ps2recomp
|
||||
case OPCODE_LW:
|
||||
return fmt::format("SET_GPR_S32(ctx, {}, (int32_t){});", inst.rt, genRead(32, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
case OPCODE_LBU:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, (uint8_t){});", inst.rt, genRead(8, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
return fmt::format("SET_GPR_ZE32(ctx, {}, (uint8_t){});", inst.rt, genRead(8, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
case OPCODE_LHU:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, (uint16_t){});", inst.rt, genRead(16, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
return fmt::format("SET_GPR_ZE32(ctx, {}, (uint16_t){});", inst.rt, genRead(16, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
case OPCODE_LWU:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, {});", inst.rt, genRead(32, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
return fmt::format("SET_GPR_ZE32(ctx, {}, {});", inst.rt, genRead(32, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate)));
|
||||
case OPCODE_SB:
|
||||
return genWrite(8, fmt::format("ADD32(GPR_U32(ctx, {}), {})", inst.rs, inst.simmediate), fmt::format("(uint8_t)GPR_U32(ctx, {})", inst.rt)) + ";";
|
||||
case OPCODE_SH:
|
||||
|
||||
@@ -288,7 +288,8 @@ namespace ps2recomp
|
||||
std::unordered_map<uint32_t, std::vector<Instruction>> &decodedFunctions,
|
||||
const std::vector<Section> §ions,
|
||||
CodeGenerator *codeGenerator,
|
||||
const std::function<bool(Function &)> &decodeExternalFunction)
|
||||
const std::function<bool(Function &)> &decodeExternalFunction,
|
||||
const std::unordered_set<uint32_t> &seedEntryAddresses = {})
|
||||
{
|
||||
std::unordered_set<uint32_t> existingStarts;
|
||||
for (const auto &function : functions)
|
||||
@@ -312,6 +313,19 @@ namespace ps2recomp
|
||||
return false;
|
||||
};
|
||||
|
||||
auto executableSectionEnd = [&](uint32_t address) -> std::optional<uint32_t>
|
||||
{
|
||||
for (const auto §ion : sections)
|
||||
{
|
||||
if (!section.isCode || address < section.address || address >= section.address + section.size)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return section.address + section.size;
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
auto isSimpleReturnThunkStart = [](const Instruction &inst) -> bool
|
||||
{
|
||||
return inst.opcode == OPCODE_SPECIAL &&
|
||||
@@ -397,6 +411,14 @@ namespace ps2recomp
|
||||
pendingStarts.insert(target);
|
||||
};
|
||||
|
||||
if (stats.passCount == 1u)
|
||||
{
|
||||
for (uint32_t target : seedEntryAddresses)
|
||||
{
|
||||
queuePendingEntry(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &function : functions)
|
||||
{
|
||||
if (!function.isRecompiled || function.isStub || function.isSkipped)
|
||||
@@ -534,13 +556,24 @@ namespace ps2recomp
|
||||
}
|
||||
else
|
||||
{
|
||||
auto nextStartOpt = findNextBoundaryStart(target);
|
||||
if (!nextStartOpt.has_value() || nextStartOpt.value() <= target)
|
||||
const auto sectionEndOpt = executableSectionEnd(target);
|
||||
if (!sectionEndOpt.has_value())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entryFunction.end = nextStartOpt.value();
|
||||
uint32_t entryEnd = sectionEndOpt.value();
|
||||
auto nextStartOpt = findNextBoundaryStart(target);
|
||||
if (nextStartOpt.has_value() && nextStartOpt.value() < entryEnd)
|
||||
{
|
||||
entryEnd = nextStartOpt.value();
|
||||
}
|
||||
if (entryEnd <= target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entryFunction.end = entryEnd;
|
||||
if (!decodeExternalFunction(entryFunction))
|
||||
{
|
||||
continue;
|
||||
@@ -1869,6 +1902,63 @@ namespace ps2recomp
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_set<uint32_t> guestFallbackEntryAddresses = m_entryPointHintStarts;
|
||||
for (uint32_t address : m_stubFunctionStarts)
|
||||
{
|
||||
const auto bindingIt = m_stubHandlerBindingsByStart.find(address);
|
||||
if (bindingIt == m_stubHandlerBindingsByStart.end() ||
|
||||
resolveStubTarget(bindingIt->second) == StubTarget::Unknown)
|
||||
{
|
||||
guestFallbackEntryAddresses.insert(address);
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer the existing wrapper when a configured entry lies inside a
|
||||
// decoded function. If Ghidra/analyzer omitted the whole routine,
|
||||
// synthesize a standalone guest function bounded by the next known
|
||||
// function instead of leaving a valid executable target unregistered.
|
||||
collectInternalEntryTargetsImpl(m_functions, m_decodedFunctions, guestFallbackEntryAddresses, m_resumeEntryTargetsByOwner);
|
||||
|
||||
std::unordered_set<uint32_t> coveredEntryAddresses;
|
||||
coveredEntryAddresses.reserve(m_functions.size() + guestFallbackEntryAddresses.size());
|
||||
for (const auto &function : m_functions)
|
||||
{
|
||||
coveredEntryAddresses.insert(function.start);
|
||||
}
|
||||
for (const auto &[owner, targets] : m_resumeEntryTargetsByOwner)
|
||||
{
|
||||
coveredEntryAddresses.insert(targets.begin(), targets.end());
|
||||
}
|
||||
|
||||
std::unordered_set<uint32_t> standaloneEntryAddresses;
|
||||
for (uint32_t address : guestFallbackEntryAddresses)
|
||||
{
|
||||
if (!coveredEntryAddresses.contains(address))
|
||||
{
|
||||
standaloneEntryAddresses.insert(address);
|
||||
}
|
||||
}
|
||||
|
||||
if (!standaloneEntryAddresses.empty())
|
||||
{
|
||||
const EntryDiscoveryStats configuredStats = discoverAdditionalEntryPointsImpl(
|
||||
m_functions,
|
||||
m_decodedFunctions,
|
||||
m_sections,
|
||||
nullptr,
|
||||
[this](Function &function)
|
||||
{ return decodeFunction(function); },
|
||||
standaloneEntryAddresses);
|
||||
if (configuredStats.discoveredCount > 0u)
|
||||
{
|
||||
m_reporter.recordAdditionalEntryPoints(configuredStats.discoveredCount);
|
||||
std::ostringstream msg;
|
||||
msg << "synthesized " << configuredStats.discoveredCount
|
||||
<< " standalone configured guest entry point(s)";
|
||||
m_reporter.progress(msg.str());
|
||||
}
|
||||
}
|
||||
|
||||
auto findContainingFunction = [&](uint32_t address) -> const Function *
|
||||
{
|
||||
const Function *best = nullptr;
|
||||
@@ -1959,22 +2049,6 @@ namespace ps2recomp
|
||||
targets.push_back(target);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<uint32_t> guestFallbackEntryAddresses = m_entryPointHintStarts;
|
||||
for (uint32_t address : m_stubFunctionStarts)
|
||||
{
|
||||
const auto bindingIt = m_stubHandlerBindingsByStart.find(address);
|
||||
if (bindingIt == m_stubHandlerBindingsByStart.end() ||
|
||||
resolveStubTarget(bindingIt->second) == StubTarget::Unknown)
|
||||
{
|
||||
guestFallbackEntryAddresses.insert(address);
|
||||
}
|
||||
}
|
||||
collectInternalEntryTargetsImpl(
|
||||
m_functions,
|
||||
m_decodedFunctions,
|
||||
guestFallbackEntryAddresses,
|
||||
m_resumeEntryTargetsByOwner);
|
||||
|
||||
size_t totalTargets = 0u;
|
||||
for (auto it = m_resumeEntryTargetsByOwner.begin(); it != m_resumeEntryTargetsByOwner.end();)
|
||||
|
||||
Reference in New Issue
Block a user