diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index e5850e5aa00..e038c522d91 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -1393,8 +1393,10 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx, /* For ABIs not tracking RA, the return address is expected to be in a specific location. Explicit manourvering to a different offset (than the - default offset) is non-representable in SFrame. */ - if (!sframe_ra_tracking_p () && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG + default offset) is non-representable in SFrame, unless flex FDE generation + is supported for the ABI. */ + if (!sframe_support_flex_fde_p () && !sframe_ra_tracking_p () + && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG && cfi_insn->u.ri.offset != sframe_cfa_ra_offset ()) { as_warn (_("no SFrame FDE emitted; %s register %u in .cfi_offset"), @@ -1412,16 +1414,35 @@ sframe_xlate_do_offset (struct sframe_xlate_ctx *xlate_ctx, cur_fre->fp_deref_p = true; cur_fre->merge_candidate = false; } - else if (sframe_ra_tracking_p () - && cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG) + /* Either the ABI has enabled RA tracking, in which case we must process the + DW_CFA_offset opcode for REG_RA like usual. Or if the ABI has not enabled + RA tracking, but flex FDE generation is supported, distinguish between + whether its time to reset the RA tracking state or not. */ + else if (cfi_insn->u.ri.reg == SFRAME_CFA_RA_REG) { - sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset); - cur_fre->ra_reg = SFRAME_FRE_REG_INVALID; - cur_fre->ra_deref_p = true; - cur_fre->merge_candidate = false; + if (!sframe_ra_tracking_p () + && cfi_insn->u.ri.offset == sframe_cfa_ra_offset ()) + { + /* Reset RA tracking info, if fixed offset. */ + cur_fre->ra_reg = SFRAME_FRE_REG_INVALID; + cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_NONE; + cur_fre->ra_deref_p = false; + cur_fre->merge_candidate = false; + } + else + { + sframe_fre_set_ra_track (cur_fre, cfi_insn->u.ri.offset); + cur_fre->ra_reg = SFRAME_FRE_REG_INVALID; + cur_fre->ra_loc = SFRAME_FRE_ELEM_LOC_STACK; + cur_fre->ra_deref_p = true; + cur_fre->merge_candidate = false; + + if (!sframe_ra_tracking_p () && sframe_support_flex_fde_p ()) + xlate_ctx->flex_p = true; + } } - /* This is used to track changes to non-rsp registers, skip all others - except FP / RA for now. */ + + /* Skip all other registers. */ return SFRAME_XLATE_OK; } diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d new file mode 100644 index 00000000000..a8aa9a61a38 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.d @@ -0,0 +1,25 @@ +#as: --gsframe +#objdump: --sframe=.sframe +#name: Flex FDE with RA state transition +#... +Contents of the SFrame section .sframe: + + Header : + + Version: SFRAME_VERSION_3 + Flags: SFRAME_F_FDE_FUNC_START_PCREL + CFA fixed RA offset: \-8 + Num FDEs: 1 + Num FREs: 5 + + Function Index : + + func idx \[0\]: pc = 0x0, size = 16 bytes, attr = "F" + STARTPC +CFA +FP +RA + + 0+0000 +sp\+8 +u +f + + 0+0004 +sp\+40 +u +f + + 0+0008 +sp\+40 +u +r3\+0 + + 0+000b +sp\+40 +u +f + + 0+000f +sp\+8 +u +f + + +#pass diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s new file mode 100644 index 00000000000..a4600dce66f --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-6.s @@ -0,0 +1,16 @@ +# Testcase for transition of tracked entity (rip) from +# register to CFA+offset. + .type foo, @function +foo: + .cfi_startproc + sub $0x20,%rsp + .cfi_adjust_cfa_offset 0x20 + .long 0 + .cfi_register rip, 3 + mov %rax, %rdi + .cfi_offset rip, -8 + .long 0 + .cfi_def_cfa rsp, 8 + ret + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-7.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-7.d new file mode 100644 index 00000000000..2d910f3b8a7 --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-7.d @@ -0,0 +1,25 @@ +#as: --gsframe +#objdump: --sframe=.sframe +#name: Flex FDE with RA state transition 2 +#... +Contents of the SFrame section .sframe: + + Header : + + Version: SFRAME_VERSION_3 + Flags: SFRAME_F_FDE_FUNC_START_PCREL + CFA fixed RA offset: \-8 + Num FDEs: 1 + Num FREs: 5 + + Function Index : + + func idx \[0\]: pc = 0x0, size = 20 bytes, attr = "F" + STARTPC +CFA +FP +RA + + 0+0000 +sp\+8 +u +f + + 0+0004 +sp\+40 +u +f + + 0+000b +sp\+40 +u +c-16 + + 0+000f +sp\+8 +u +c-16 + + 0+0013 +sp\+8 +u +f + + +#pass diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-7.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-7.s new file mode 100644 index 00000000000..bad89ea6fdc --- /dev/null +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-x86_64-7.s @@ -0,0 +1,17 @@ +# Testcase for creation of flex FDE for offset divergence from fixed offset on +# AMD64 + .type foo, @function +foo: + .cfi_startproc + sub $0x20,%rsp + .cfi_adjust_cfa_offset 0x20 + .long 0 + mov %rax, %rdi + .cfi_offset rip, -16 + .long 0 + .cfi_def_cfa rsp, 8 + .long 0 + .cfi_offset rip, -8 + ret + .cfi_endproc + .size foo, .-foo diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp index 4fbb04f838f..18f89c7e189 100644 --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp @@ -63,6 +63,8 @@ if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then { run_dump_test "cfi-sframe-x86_64-3" run_dump_test "cfi-sframe-x86_64-4" run_dump_test "cfi-sframe-x86_64-5" + run_dump_test "cfi-sframe-x86_64-6" + run_dump_test "cfi-sframe-x86_64-7" run_dump_test "cfi-sframe-x86_64-esc-expr-1" run_dump_test "cfi-sframe-x86_64-esc-expr-2" run_dump_test "cfi-sframe-x86_64-esc-expr-3"