From 908b1e9a3701f142de51e133d910aa058d4b071c Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 20 Sep 2026 00:29:28 +0200 Subject: [PATCH] [dynarmic] fix bad arm codegen on relocations (#4458) In an earlier version I had these as constants which were referred to via `db`, I haphazardly left the LDR and didn't notice. Even still relocations apply to only 1 ins at a time. Fixes regressions on #4158 Signed-off-by: lizzie - [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. ------------------- Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4458 Reviewed-by: CamilleLaVey Reviewed-by: MaranBr --- .../backend/arm64/a32_address_space.cpp | 75 ++++++++++++++++--- .../backend/arm64/a64_address_space.cpp | 74 +++++++++++++++--- .../dynarmic/backend/arm64/address_space.cpp | 51 +++++-------- .../dynarmic/backend/arm64/address_space.h | 20 ++++- 4 files changed, 160 insertions(+), 60 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp index dc14d16978..0cf9bb9fae 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -24,29 +24,65 @@ namespace Dynarmic::Backend::Arm64 { template -static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { +static void* EmitCallReadTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { using namespace oaknut::util; - const auto info = Devirtualize(this_); - oaknut::Label l_addr, l_this; - void* target = code.xptr(); + // params = { this, vaddr, bitsize } code.LDR(X0, l_this); + // X1 = vaddr + code.MOV(X2, bitsize); code.LDR(Xscratch0, l_addr); code.BR(Xscratch0); - code.align(8); code.l(l_this); code.dx(info.this_ptr); code.l(l_addr); code.dx(info.fn_ptr); - return target; } template -static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_) { +static void* EmitCallWriteTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { + using namespace oaknut::util; + const auto info = Devirtualize(this_); + oaknut::Label l_addr, l_this; + void* target = code.xptr(); + // params = { this, vaddr, value, bitsize } + code.LDR(X0, l_this); + // X1 = vaddr + // X2 = value + code.MOV(X3, bitsize); + code.LDR(Xscratch0, l_addr); + code.BR(Xscratch0); + code.align(8); + code.l(l_this); + code.dx(info.this_ptr); + code.l(l_addr); + code.dx(info.fn_ptr); + return target; +} + +template +static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { + using namespace oaknut::util; + const auto info = Devirtualize(this_); + oaknut::Label l_addr, l_this; + void* target = code.xptr(); + code.LDR(X0, l_this); + code.LDR(Xscratch0, l_addr); + code.BR(Xscratch0); + code.align(8); + code.l(l_this); + code.dx(info.this_ptr); + code.l(l_addr); + code.dx(info.fn_ptr); + return target; +} + +template +static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { using namespace oaknut::util; const auto info = Devirtualize(this_); @@ -59,6 +95,7 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_ ABI_PushRegisters(code, save_regs, 0); code.LDR(X0, l_this); code.MOV(X1, Xscratch0); + code.MOV(X2, bitsize); code.LDR(Xscratch0, l_addr); code.BLR(Xscratch0); code.MOV(Xscratch0, X0); @@ -101,7 +138,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const } template -static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_) { +static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { using namespace oaknut::util; const auto info = Devirtualize(this_); @@ -115,6 +152,7 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this code.LDR(X0, l_this); code.MOV(X1, Xscratch0); code.MOV(X2, Xscratch1); + code.MOV(X3, bitsize); code.LDR(Xscratch0, l_addr); code.BLR(Xscratch0); ABI_PopRegisters(code, save_regs, 0); @@ -176,14 +214,27 @@ void A32AddressSpace::EmitPrelude() { UnprotectCodeMemory(); - prelude_info.read_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks); - prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks); + + prelude_info.read_memory_8 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); + prelude_info.read_memory_16 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16)); + prelude_info.read_memory_32 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32)); + prelude_info.read_memory_64 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64)); + prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); + prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16)); + prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32)); + prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64)); prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u8>(code, conf); prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u16>(code, conf); prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u32>(code, conf); prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf); - prelude_info.write_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks); - prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks); + prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); + prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16)); + prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32)); + prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64)); + prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); + prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16)); + prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32)); + prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64)); prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf); prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf); prelude_info.exclusive_write_memory_32 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive32, u32>(code, conf); diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp index efb9fc538c..492242fa73 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -23,29 +23,65 @@ namespace Dynarmic::Backend::Arm64 { template -static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { +static void* EmitCallReadTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { using namespace oaknut::util; - const auto info = Devirtualize(this_); - oaknut::Label l_addr, l_this; - void* target = code.xptr(); + // params = { this, vaddr, bitsize } code.LDR(X0, l_this); + // X1 = vaddr + code.MOV(X2, bitsize); code.LDR(Xscratch0, l_addr); code.BR(Xscratch0); - code.align(8); code.l(l_this); code.dx(info.this_ptr); code.l(l_addr); code.dx(info.fn_ptr); - return target; } template -static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_) { +static void* EmitCallWriteTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { + using namespace oaknut::util; + const auto info = Devirtualize(this_); + oaknut::Label l_addr, l_this; + void* target = code.xptr(); + // params = { this, vaddr, value, bitsize } + code.LDR(X0, l_this); + // X1 = vaddr + // X2 = value + code.MOV(X3, bitsize); + code.LDR(Xscratch0, l_addr); + code.BR(Xscratch0); + code.align(8); + code.l(l_this); + code.dx(info.this_ptr); + code.l(l_addr); + code.dx(info.fn_ptr); + return target; +} + +template +static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) { + using namespace oaknut::util; + const auto info = Devirtualize(this_); + oaknut::Label l_addr, l_this; + void* target = code.xptr(); + code.LDR(X0, l_this); + code.LDR(Xscratch0, l_addr); + code.BR(Xscratch0); + code.align(8); + code.l(l_this); + code.dx(info.this_ptr); + code.l(l_addr); + code.dx(info.fn_ptr); + return target; +} + +template +static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { using namespace oaknut::util; const auto info = Devirtualize(this_); @@ -58,6 +94,7 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_ ABI_PushRegisters(code, save_regs, 0); code.LDR(X0, l_this); code.MOV(X1, Xscratch0); + code.MOV(X2, bitsize); code.LDR(Xscratch0, l_addr); code.BLR(Xscratch0); code.MOV(Xscratch0, X0); @@ -100,7 +137,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const } template -static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_) { +static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) { using namespace oaknut::util; const auto info = Devirtualize(this_); @@ -114,6 +151,7 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this code.LDR(X0, l_this); code.MOV(X1, Xscratch0); code.MOV(X2, Xscratch1); + code.MOV(X3, bitsize); code.LDR(Xscratch0, l_addr); code.BLR(Xscratch0); ABI_PopRegisters(code, save_regs, 0); @@ -342,18 +380,30 @@ void A64AddressSpace::EmitPrelude() { UnprotectCodeMemory(); - prelude_info.read_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks); + prelude_info.read_memory_8 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); + prelude_info.read_memory_16 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16)); + prelude_info.read_memory_32 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32)); + prelude_info.read_memory_64 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64)); prelude_info.read_memory_128 = EmitRead128CallTrampoline(code, conf.callbacks); - prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks); + prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8)); + prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16)); + prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32)); + prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64)); prelude_info.wrapped_read_memory_128 = EmitWrappedRead128CallTrampoline(code, conf.callbacks); prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u8>(code, conf); prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u16>(code, conf); prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u32>(code, conf); prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u64>(code, conf); prelude_info.exclusive_read_memory_128 = EmitExclusiveRead128CallTrampoline(code, conf); - prelude_info.write_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks); + prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); + prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16)); + prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32)); + prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64)); prelude_info.write_memory_128 = EmitWrite128CallTrampoline(code, conf.callbacks); - prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks); + prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8)); + prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16)); + prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32)); + prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64)); prelude_info.wrapped_write_memory_128 = EmitWrappedWrite128CallTrampoline(code, conf.callbacks); prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf); prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf); diff --git a/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp b/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp index 7b83e372e6..4ef3296c4a 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp @@ -147,44 +147,37 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) { break; // { this, vaddr, size } case LinkTarget::ReadMemory8: - c.LDR(X2, 1); - c.BL(prelude_info.read_memory); + c.BL(prelude_info.read_memory_8); break; case LinkTarget::ReadMemory16: - c.LDR(X2, 2); - c.BL(prelude_info.read_memory); + c.BL(prelude_info.read_memory_16); break; case LinkTarget::ReadMemory32: - c.LDR(X2, 4); - c.BL(prelude_info.read_memory); + c.BL(prelude_info.read_memory_32); break; case LinkTarget::ReadMemory64: - c.LDR(X2, 8); - c.BL(prelude_info.read_memory); + c.BL(prelude_info.read_memory_64); break; case LinkTarget::ReadMemory128: c.BL(prelude_info.read_memory_128); break; // { this, vaddr, size } case LinkTarget::WrappedReadMemory8: - c.LDR(X2, 1); - c.BL(prelude_info.wrapped_read_memory); + c.BL(prelude_info.wrapped_read_memory_8); break; case LinkTarget::WrappedReadMemory16: - c.LDR(X2, 2); - c.BL(prelude_info.wrapped_read_memory); + c.BL(prelude_info.wrapped_read_memory_16); break; case LinkTarget::WrappedReadMemory32: - c.LDR(X2, 4); - c.BL(prelude_info.wrapped_read_memory); + c.BL(prelude_info.wrapped_read_memory_32); break; case LinkTarget::WrappedReadMemory64: - c.LDR(X2, 8); - c.BL(prelude_info.wrapped_read_memory); + c.BL(prelude_info.wrapped_read_memory_64); break; case LinkTarget::WrappedReadMemory128: c.BL(prelude_info.wrapped_read_memory_128); break; + // case LinkTarget::ExclusiveReadMemory8: c.BL(prelude_info.exclusive_read_memory_8); break; @@ -202,43 +195,37 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) { break; // { this, vaddr, value, size } case LinkTarget::WriteMemory8: - c.LDR(X3, 1); - c.BL(prelude_info.write_memory); + c.BL(prelude_info.write_memory_8); break; case LinkTarget::WriteMemory16: - c.LDR(X3, 2); - c.BL(prelude_info.write_memory); + c.BL(prelude_info.write_memory_16); break; case LinkTarget::WriteMemory32: - c.LDR(X3, 4); - c.BL(prelude_info.write_memory); + c.BL(prelude_info.write_memory_32); break; case LinkTarget::WriteMemory64: - c.LDR(X3, 8); - c.BL(prelude_info.write_memory); + c.BL(prelude_info.write_memory_64); break; case LinkTarget::WriteMemory128: c.BL(prelude_info.write_memory_128); break; + // case LinkTarget::WrappedWriteMemory8: - c.LDR(X3, 1); - c.BL(prelude_info.wrapped_write_memory); + c.BL(prelude_info.wrapped_write_memory_8); break; case LinkTarget::WrappedWriteMemory16: - c.LDR(X3, 2); - c.BL(prelude_info.wrapped_write_memory); + c.BL(prelude_info.wrapped_write_memory_16); break; case LinkTarget::WrappedWriteMemory32: - c.LDR(X3, 4); - c.BL(prelude_info.wrapped_write_memory); + c.BL(prelude_info.wrapped_write_memory_32); break; case LinkTarget::WrappedWriteMemory64: - c.LDR(X3, 8); - c.BL(prelude_info.wrapped_write_memory); + c.BL(prelude_info.wrapped_write_memory_64); break; case LinkTarget::WrappedWriteMemory128: c.BL(prelude_info.wrapped_write_memory_128); break; + // case LinkTarget::ExclusiveWriteMemory8: c.BL(prelude_info.exclusive_write_memory_8); break; diff --git a/src/dynarmic/src/dynarmic/backend/arm64/address_space.h b/src/dynarmic/src/dynarmic/backend/arm64/address_space.h index 73e2c94a19..755b05bd02 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/address_space.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/address_space.h @@ -93,18 +93,30 @@ protected: void* return_to_dispatcher; void* return_from_run_code; - void* read_memory; + void* read_memory_8; + void* read_memory_16; + void* read_memory_32; + void* read_memory_64; void* read_memory_128; - void* wrapped_read_memory; + void* wrapped_read_memory_8; + void* wrapped_read_memory_16; + void* wrapped_read_memory_32; + void* wrapped_read_memory_64; void* wrapped_read_memory_128; void* exclusive_read_memory_8; void* exclusive_read_memory_16; void* exclusive_read_memory_32; void* exclusive_read_memory_64; void* exclusive_read_memory_128; - void* write_memory; + void* write_memory_8; + void* write_memory_16; + void* write_memory_32; + void* write_memory_64; void* write_memory_128; - void* wrapped_write_memory; + void* wrapped_write_memory_8; + void* wrapped_write_memory_16; + void* wrapped_write_memory_32; + void* wrapped_write_memory_64; void* wrapped_write_memory_128; void* exclusive_write_memory_8; void* exclusive_write_memory_16;