diff --git a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp index 199360d21..4a96fc502 100644 --- a/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp @@ -1601,7 +1601,7 @@ DEF_OP(VBroadcastFromMem) { DEF_OP(Push) { const auto Op = IROp->C(); const auto ValueSize = Op->ValueSize; - const auto Src = GetReg(Op->Value.ID()); + auto Src = GetReg(Op->Value.ID()); const auto AddrSrc = GetReg(Op->Addr.ID()); const auto Dst = GetReg(Node); @@ -1617,6 +1617,22 @@ DEF_OP(Push) { } } + if (Src == AddrSrc) { + // If the data source is the address source then we need to do some additional work. + // This is because it is undefined behaviour to do a writeback on store operation where dest == src. + // In the case of writeback where the source is the address there are multiple behaviours. + // - SIGILL - Apple Silicon Behaviour + // - Stores original value - Cortex behaviour + // - Stores value after pre-index adjust adjust - Vixl simulator behaviour. + // - Undefined value stored + // - Undefined behaviour(!) + + // In this path Src can end up overlapping both AddrSrc and Dst. + // Move the data to a temporary and store from there instead. + mov(TMP1, Src.X()); + Src = TMP1; + } + if (NeedsMoveAfterwards) { switch (ValueSize) { case 1: { diff --git a/unittests/ASM/FEX_bugs/Push.asm b/unittests/ASM/FEX_bugs/Push.asm new file mode 100644 index 000000000..5cd7e374c --- /dev/null +++ b/unittests/ASM/FEX_bugs/Push.asm @@ -0,0 +1,22 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xe0000010", + "RSP": "0xe0000008" + } +} +%endif + +; FEX had a bug where a `push rsp` would generate an Arm64 instruction with undefined behaviour. +; `push rsp` -> `str x8, [x8, #-8]!` +; This instruction has constrained undefined behaviour. +; On Cortex it stores the original value. +; On Apple Silicon it raises a SIGILL. +; It can also store undefined data or have undefined behaviour. +; Test to ensure we don't generate undefined behaviour. +mov rsp, 0xe0000010 +push rsp + +mov rax, [rsp] + +hlt