Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Forstall <brucefo@microsoft.com>2021-06-19 02:51:50 +0300
committerGitHub <noreply@github.com>2021-06-19 02:51:50 +0300
commitf5da499194580958cbaca9abdaf209572ec3b748 (patch)
tree45e88eaec87b2b9546f058d60899c75b94893b46 /src/coreclr/jit
parent27fece253494ac80f9f13843cbaa0e99a5d502ae (diff)
Fix AMD64 epilog ABI (#54357)
* Fix AMD64 epilog ABI The Windows AMD64 epilog ABI states that an `lea rsp,[rbp+constant]` instruction may only be used if a frame pointer has been reported to the OS in the prolog unwind info, otherwise an `add rsp, constant` instruction must be used. There were a number of cases where the JIT used the `lea` form simply because a frame pointer had been established and was available, even though it had not been reported to the OS (and, thus, the frame was effectively an `rsp` frame). Fix this by using the same condition in the epilog for determining which form to use, `lea` or `add`, that was used in the prolog to determine whether or not to report the frame pointer in the unwind info. Fixes #54320 * Formatting * Fix OSR
Diffstat (limited to 'src/coreclr/jit')
-rw-r--r--src/coreclr/jit/codegencommon.cpp37
1 files changed, 35 insertions, 2 deletions
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index f977ddfe6f3..e99f047c061 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -7454,7 +7454,7 @@ void CodeGen::genFnProlog()
// Establish the AMD64 frame pointer after the OS-reported prolog.
if (doubleAlignOrFramePointerUsed())
{
- bool reportUnwindData = compiler->compLocallocUsed || compiler->opts.compDbgEnC;
+ const bool reportUnwindData = compiler->compLocallocUsed || compiler->opts.compDbgEnC;
genEstablishFramePointer(compiler->codeGen->genSPtoFPdelta(), reportUnwindData);
}
#endif // TARGET_AMD64
@@ -8147,7 +8147,31 @@ void CodeGen::genFnEpilog(BasicBlock* block)
/* Compute the size in bytes we've pushed/popped */
- if (!doubleAlignOrFramePointerUsed())
+ bool removeEbpFrame = doubleAlignOrFramePointerUsed();
+
+#ifdef TARGET_AMD64
+ // We only remove the EBP frame using the frame pointer (using `lea rsp, [rbp + const]`)
+ // if we reported the frame pointer in the prolog. The Windows x64 unwinding ABI specifically
+ // disallows this `lea` form:
+ //
+ // See https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160#epilog-code
+ //
+ // "When a frame pointer is not used, the epilog must use add RSP,constant to deallocate the fixed part of the
+ // stack. It may not use lea RSP,constant[RSP] instead. This restriction exists so the unwind code has fewer
+ // patterns to recognize when searching for epilogs."
+ //
+ // Otherwise, we must use `add RSP, constant`, as stated. So, we need to use the same condition
+ // as genFnProlog() used in determining whether to report the frame pointer in the unwind data.
+ // This is a subset of the `doubleAlignOrFramePointerUsed()` cases.
+ //
+ if (removeEbpFrame)
+ {
+ const bool reportUnwindData = compiler->compLocallocUsed || compiler->opts.compDbgEnC;
+ removeEbpFrame = removeEbpFrame && reportUnwindData;
+ }
+#endif // TARGET_AMD64
+
+ if (!removeEbpFrame)
{
// We have an ESP frame */
@@ -8177,6 +8201,15 @@ void CodeGen::genFnEpilog(BasicBlock* block)
genPopCalleeSavedRegisters();
+#ifdef TARGET_AMD64
+ // In the case where we have an RSP frame, and no frame pointer reported in the OS unwind info,
+ // but we do have a pushed frame pointer and established frame chain, we do need to pop RBP.
+ if (doubleAlignOrFramePointerUsed())
+ {
+ inst_RV(INS_pop, REG_EBP, TYP_I_IMPL);
+ }
+#endif // TARGET_AMD64
+
// Extra OSR adjust to get to where RBP was saved by the original frame, and
// restore RBP.
//