Hi!

The indirect branch thunks we emit look like:
__x86_indirect_thunk_rax:
        .cfi_startproc
        call    .LIND1
.LIND0:
        pause
        lfence
        jmp     .LIND0
.LIND1:
        mov     %rax, (%rsp)
        ret
        .cfi_endproc

The problem is that the CFI is incorrect.  On the first entry it is correct,
the default is CFA %rsp+8 and rip at cfa-8, before call .LIND1 is executed,
the return address (to whatever called the thunk) is at %rsp+8 like on entry
to any other function.  But the call insn pushes a word to the stack, which
we don't want to show up as another caller, and worse is in the mov insn
overwritten with something else.

The following patch adds .cfi_def_cfa_offset 16 right after the .LIND1
label, so that the CFI is correct until the end of the thunk.  It works
properly also with -fno-dwarf2-cfi-asm.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-09-25  Jakub Jelinek  <ja...@redhat.com>

        PR target/87414
        * config/i386/i386.c: Include debug.h and dwarf2out.h.
        (output_indirect_thunk): Emit DW_CFA_def_cfa_offset after the
        call.

--- gcc/config/i386/i386.c.jj   2018-09-24 10:36:54.559016673 +0200
+++ gcc/config/i386/i386.c      2018-09-24 22:09:48.218211652 +0200
@@ -89,6 +89,8 @@ along with GCC; see the file COPYING3.
 #include "ipa-fnsummary.h"
 #include "wide-int-bitmask.h"
 #include "tree-vector-builder.h"
+#include "debug.h"
+#include "dwarf2out.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -10464,6 +10466,23 @@ output_indirect_thunk (unsigned int regn
 
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, indirectlabel2);
 
+  /* The above call insn pushed a word to stack.  Adjust CFI info.  */
+  if (flag_asynchronous_unwind_tables && dwarf2out_do_frame ())
+    {
+      if (! dwarf2out_do_cfi_asm ())
+       {
+         dw_cfi_ref xcfi = ggc_cleared_alloc<dw_cfi_node> ();
+         xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
+         xcfi->dw_cfi_oprnd1.dw_cfi_addr = ggc_strdup (indirectlabel2);
+         vec_safe_push (cfun->fde->dw_fde_cfi, xcfi);
+       }
+      dw_cfi_ref xcfi = ggc_cleared_alloc<dw_cfi_node> ();
+      xcfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+      xcfi->dw_cfi_oprnd1.dw_cfi_offset = 2 * UNITS_PER_WORD;
+      vec_safe_push (cfun->fde->dw_fde_cfi, xcfi);
+      dwarf2out_emit_cfi (xcfi);
+    }
+
   if (regno != INVALID_REGNUM)
     {
       /* MOV.  */

        Jakub

Reply via email to