aboutsummaryrefslogtreecommitdiff
path: root/src/core/arm/nce/patcher.cpp
diff options
context:
space:
mode:
authorxbzk <xbzk@eden-emu.dev>2026-10-15 12:13:17 +0200
committercrueter <crueter@eden-emu.dev>2026-10-15 12:13:17 +0200
commitaaa0bcb9bf5694d62538c361b210147294a5ce3d (patch)
tree9d98ee51c095542d4ffba808443e814109e6e11e /src/core/arm/nce/patcher.cpp
parente255c20db4111485d228c10478bda63aabcfdde5 (diff)
[patcher, ro, settings] runtime tls patch (#4492) optimization and nuke toggle (#4502) (#4523)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- This is a follow up for the biomutant fix. By the time i knew it was shallow, coz i was running patchtext routine even for svc and modules, causing a routine which were needed to run 14 times to run 4000+ instead. Since some perf loss was reported in 30 sep nightly, and it caused ac3r to not boot, we had added a temp toggle, which is now being removed as optimizations + fix are in. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4523 Reviewed-by: lizzie <lizzie@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Diffstat (limited to 'src/core/arm/nce/patcher.cpp')
-rw-r--r--src/core/arm/nce/patcher.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp
index 7d2041d4d2..f21d7cacdc 100644
--- a/src/core/arm/nce/patcher.cpp
+++ b/src/core/arm/nce/patcher.cpp
@@ -45,6 +45,23 @@ Patcher::Patcher() : c(m_patch_instructions), c_pre(m_patch_instructions_pre) {
WriteLoadContext(c_pre);
}
+Patcher::Patcher(std::span<const u8> text) : c(m_patch_instructions), c_pre(m_patch_instructions_pre) {
+ modules.emplace_back();
+ curr_patch = &modules.back();
+ const auto words = std::span<const u32>{reinterpret_cast<const u32*>(text.data()), text.size() / sizeof(u32)};
+ for (u32 i = ModuleCodeIndex; i < static_cast<u32>(words.size()); ++i) {
+ const uintptr_t offset = i * sizeof(u32);
+ if (auto mrs = MRS{words[i]}; mrs.Verify() && mrs.GetRt() != 31 && (mrs.GetSystemReg() == TpidrEl0 || mrs.GetSystemReg() == TpidrroEl0)) {
+ BranchToPatch(offset);
+ const auto src_reg = mrs.GetSystemReg() == TpidrroEl0 ? oaknut::SystemReg::TPIDRRO_EL0 : oaknut::SystemReg::TPIDR_EL0;
+ WriteMrsHandler(offset + sizeof(u32), oaknut::XReg{static_cast<int>(mrs.GetRt())}, src_reg);
+ } else if (auto msr = MSR{words[i]}; msr.Verify() && msr.GetSystemReg() == TpidrEl0) {
+ BranchToPatch(offset);
+ WriteMsrHandler(offset + sizeof(u32), oaknut::XReg{static_cast<int>(msr.GetRt())});
+ }
+ }
+}
+
Patcher::~Patcher() = default;
bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet::Segment& code) {
@@ -182,6 +199,31 @@ bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet
return true;
}
+std::span<const u32> Patcher::RelocateRuntimeTls(
+ s64 patch_offset, std::vector<InstructionPatch>& out_patches) {
+ const auto& patch = modules.front();
+ const auto can_branch = [](s64 offset) {
+ return offset % 4 == 0 && offset >= -static_cast<s64>(MaxRelativeBranch) && offset < static_cast<s64>(MaxRelativeBranch);
+ };
+ out_patches.clear();
+ out_patches.reserve(patch.m_branch_to_patch_relocations.size());
+ for (const auto& rel : patch.m_branch_to_patch_relocations) {
+ const s64 offset = patch_offset + rel.patch_offset - static_cast<s64>(rel.module_offset);
+ if (!can_branch(offset)) {return {};}
+ u32 replacement;
+ oaknut::CodeGenerator rc{&replacement};
+ rc.B(offset);
+ out_patches.push_back({rel.module_offset, replacement});
+ }
+ for (const auto& rel : patch.m_branch_to_module_relocations) {
+ const s64 offset = static_cast<s64>(rel.module_offset) - patch_offset - rel.patch_offset;
+ if (!can_branch(offset)) {return {};}
+ oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)};
+ rc.B(offset);
+ }
+ return m_patch_instructions;
+}
+
bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, std::vector<u8>& program_image, EntryTrampolines* out_trampolines) {
const size_t patch_size = GetSectionSize();
const size_t pre_patch_size = GetPreSectionSize();