On Sat, Jul 29, 2017 at 4:22 PM, H.J. Lu <hjl.to...@gmail.com> wrote:
> Since there is an extra error code passed to the exception handler,
> INCOMING_FRAME_SP_OFFSET is return address plus error code for the
> exception handler.  This patch updates INCOMING_FRAME_SP_OFFSET to
> the correct value for the exception handler.
>
> This patch exposed a bug in DWARF stack frame CFI generation, which
> assumes that INCOMING_FRAME_SP_OFFSET is the same for all functions:
>
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81570
>
> It sets and caches the incoming stack frame offset with the same
> INCOMING_FRAME_SP_OFFSET for all functions.  When there are both
> exception handler and normal function in the same input, the wrong
> incoming stack frame offset is used for exception handler or normal
> function, which leads to
>
> FAIL: gcc.dg/guality/pr68037-1.c   -O2 -flto -fuse-linker-plugin 
> -fno-fat-lto-objects  line 33 error == 0x12345670
> FAIL: gcc.dg/guality/pr68037-1.c   -O2 -flto -fuse-linker-plugin 
> -fno-fat-lto-objects  line 33 frame->ip == 0x12345671
> FAIL: gcc.dg/guality/pr68037-1.c   -O2 -flto -fuse-linker-plugin 
> -fno-fat-lto-objects  line 33 frame->cs == 0x12345672
> FAIL: gcc.dg/guality/pr68037-1.c   -O2 -flto -fuse-linker-plugin 
> -fno-fat-lto-objects  line 33 frame->flags == 0x12345673
> FAIL: gcc.dg/guality/pr68037-1.c   -O2 -flto -fuse-linker-plugin 
> -fno-fat-lto-objects  line 33 frame->sp == 0x12345674
> FAIL: gcc.dg/guality/pr68037-1.c   -O2 -flto -fuse-linker-plugin 
> -fno-fat-lto-objects  line 33 frame->ss == 0x12345675
>
> With the patch for PR 81570:
>
> https://gcc.gnu.org/ml/gcc-patches/2017-07/msg01851.html
>
> applied, there are no regressions on i686 and x86-64.
>
> OK for trunk?

I have two nits below.

LGTM - you know this part better than I, so it is your call.

Uros.

> H.J.
> ---
> gcc/
>
>         PR target/79793
>         * config/i386/i386.c (ix86_function_arg): Update arguments for
>         exception handler.
>         (ix86_compute_frame_layout): Set the initial stack offset to
>         INCOMING_FRAME_SP_OFFSET.  Update red-zone offset with
>         INCOMING_FRAME_SP_OFFSET.
>         (ix86_expand_epilogue): Don't pop the 'ERROR_CODE' off the
>         stack before exception handler returns.
>         * config/i386/i386.h (INCOMING_FRAME_SP_OFFSET): Add the
>         the 'ERROR_CODE' for exception handler.
>
> gcc/testsuite/
>
>         PR target/79793
>         * gcc.dg/guality/pr68037-1.c: Update gdb breakpoints.
>         * gcc.target/i386/interrupt-5.c (interrupt_frame): New struct.
>         (foo): Check the builtin return address against the return address
>         in interrupt frame.
>         * gcc.target/i386/pr79793-1.c: New test.
>         * gcc.target/i386/pr79793-2.c: Likewise.
> ---
>  gcc/config/i386/i386.c                      | 36 
> +++++++++--------------------
>  gcc/config/i386/i386.h                      |  6 +++--
>  gcc/testsuite/gcc.dg/guality/pr68037-1.c    | 12 +++++-----
>  gcc/testsuite/gcc.target/i386/interrupt-5.c | 13 +++++++++--
>  gcc/testsuite/gcc.target/i386/pr79793-1.c   | 14 +++++++++++
>  gcc/testsuite/gcc.target/i386/pr79793-2.c   | 16 +++++++++++++
>  6 files changed, 62 insertions(+), 35 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr79793-1.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr79793-2.c
>
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index f1486ff3750..e1582f8c9a6 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -10422,25 +10422,21 @@ ix86_function_arg (cumulative_args_t cum_v, 
> machine_mode omode,
>         {
>           /* This is the pointer argument.  */
>           gcc_assert (TYPE_MODE (type) == Pmode);
> -         if (cfun->machine->func_type == TYPE_INTERRUPT)
> -           /* -WORD(AP) in the current frame in interrupt handler.  */
> -           arg = plus_constant (Pmode, arg_pointer_rtx,
> -                                -UNITS_PER_WORD);
> -         else
> -           /* (AP) in the current frame in exception handler.  */
> -           arg = arg_pointer_rtx;
> +         /* It is at -WORD(AP) in the current frame in interrupt and
> +            exception handlers.  */
> +         arg = plus_constant (Pmode, arg_pointer_rtx, -UNITS_PER_WORD);
>         }
>        else
>         {
>           gcc_assert (cfun->machine->func_type == TYPE_EXCEPTION
>                       && TREE_CODE (type) == INTEGER_TYPE
>                       && TYPE_MODE (type) == word_mode);
> -         /* The integer argument is the error code at -WORD(AP) in
> +         /* The integer argument is the error code at -2 * WORD(AP) in
>              the current frame in exception handler.  */

The comment should probably say:

  /* The error code is the word-mode integer argument at -2 * WORD(AP)
in the current frame of the exception handler.  */

>           arg = gen_rtx_MEM (word_mode,
>                              plus_constant (Pmode,
>                                             arg_pointer_rtx,
> -                                           -UNITS_PER_WORD));
> +                                           -2 * UNITS_PER_WORD));
>         }
>        return arg;
>      }
> @@ -12915,8 +12911,8 @@ ix86_compute_frame_layout (void)
>           the registers need to be saved before allocating the frame.  */
>         && flag_stack_check != STATIC_BUILTIN_STACK_CHECK);
>
> -  /* Skip return address.  */
> -  offset = UNITS_PER_WORD;
> +  /* Skip return address and error code in exception handler.  */
> +  offset = INCOMING_FRAME_SP_OFFSET;
>
>    /* Skip pushed static chain.  */
>    if (ix86_static_chain_on_stack)
> @@ -15221,8 +15217,9 @@ ix86_expand_epilogue (int style)
>    m->fs.red_zone_offset = 0;
>    if (ix86_using_red_zone () && crtl->args.pops_args < 65536)
>      {
> -      /* The red-zone begins below the return address.  */
> -      m->fs.red_zone_offset = RED_ZONE_SIZE + UNITS_PER_WORD;
> +      /* The red-zone begins below return address and error code in
> +        exception handler.  */
> +      m->fs.red_zone_offset = RED_ZONE_SIZE + INCOMING_FRAME_SP_OFFSET;
>
>        /* When the register save area is in the aligned portion of
>           the stack, determine the maximum runtime displacement that
> @@ -15517,18 +15514,7 @@ ix86_expand_epilogue (int style)
>      }
>
>    if (cfun->machine->func_type != TYPE_NORMAL)
> -    {
> -      /* Return with the "IRET" instruction from interrupt handler.
> -        Pop the 'ERROR_CODE' off the stack before the 'IRET'
> -        instruction in exception handler.  */
> -      if (cfun->machine->func_type == TYPE_EXCEPTION)
> -       {
> -         rtx r = plus_constant (Pmode, stack_pointer_rtx,
> -                                UNITS_PER_WORD);
> -         emit_insn (gen_rtx_SET (stack_pointer_rtx, r));
> -       }
> -      emit_jump_insn (gen_interrupt_return ());
> -    }
> +    emit_jump_insn (gen_interrupt_return ());
>    else if (crtl->args.pops_args && crtl->args.size)
>      {
>        rtx popc = GEN_INT (crtl->args.pops_args);
> diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
> index 682745ae06b..ddbd6759caf 100644
> --- a/gcc/config/i386/i386.h
> +++ b/gcc/config/i386/i386.h
> @@ -2177,8 +2177,10 @@ extern int const 
> svr4_dbx_register_map[FIRST_PSEUDO_REGISTER];
>  /* PC is dbx register 8; let's use that column for RA.  */
>  #define DWARF_FRAME_RETURN_COLUMN      (TARGET_64BIT ? 16 : 8)
>
> -/* Before the prologue, the top of the frame is at 4(%esp).  */
> -#define INCOMING_FRAME_SP_OFFSET UNITS_PER_WORD
> +/* Before the prologue, there are return address and error code for
> +   exception handler on the top of the frame.  */
> +#define INCOMING_FRAME_SP_OFFSET \
> +  (UNITS_PER_WORD * (1 + (cfun->machine->func_type == TYPE_EXCEPTION)))

The above is unnecessarily complicated way to write:

+#define INCOMING_FRAME_SP_OFFSET \
+  (cfun->machine->func_type == TYPE_EXCEPTION \
+   ? 2 * UNITS_PER_WORD : UNITS_PER_WORD)

>  /* Describe how we implement __builtin_eh_return.  */
>  #define EH_RETURN_DATA_REGNO(N)        ((N) <= DX_REG ? (N) : INVALID_REGNUM)
> diff --git a/gcc/testsuite/gcc.dg/guality/pr68037-1.c 
> b/gcc/testsuite/gcc.dg/guality/pr68037-1.c
> index 74f61ec5f96..44cab58659f 100644
> --- a/gcc/testsuite/gcc.dg/guality/pr68037-1.c
> +++ b/gcc/testsuite/gcc.dg/guality/pr68037-1.c
> @@ -59,9 +59,9 @@ main ()
>    return 0;
>  }
>
> -/* { dg-final { gdb-test 31 "error" "0x12345670" } } */
> -/* { dg-final { gdb-test 31 "frame->ip" "0x12345671" } } */
> -/* { dg-final { gdb-test 31 "frame->cs" "0x12345672" } } */
> -/* { dg-final { gdb-test 31 "frame->flags" "0x12345673" } } */
> -/* { dg-final { gdb-test 31 "frame->sp" "0x12345674" } } */
> -/* { dg-final { gdb-test 31 "frame->ss" "0x12345675" } } */
> +/* { dg-final { gdb-test 33 "error" "0x12345670" } } */
> +/* { dg-final { gdb-test 33 "frame->ip" "0x12345671" } } */
> +/* { dg-final { gdb-test 33 "frame->cs" "0x12345672" } } */
> +/* { dg-final { gdb-test 33 "frame->flags" "0x12345673" } } */
> +/* { dg-final { gdb-test 33 "frame->sp" "0x12345674" } } */
> +/* { dg-final { gdb-test 33 "frame->ss" "0x12345675" } } */
> diff --git a/gcc/testsuite/gcc.target/i386/interrupt-5.c 
> b/gcc/testsuite/gcc.target/i386/interrupt-5.c
> index 803c0636299..5742b6f4743 100644
> --- a/gcc/testsuite/gcc.target/i386/interrupt-5.c
> +++ b/gcc/testsuite/gcc.target/i386/interrupt-5.c
> @@ -7,12 +7,21 @@ extern void link_error (void);
>
>  typedef unsigned int uword_t __attribute__ ((mode (__word__)));
>
> +struct interrupt_frame
> +{
> +  uword_t ip;
> +  uword_t cs;
> +  uword_t flags;
> +  uword_t sp;
> +  uword_t ss;
> +};
> +
>  __attribute__ ((used, interrupt))
>  void
> -foo (void *frame, uword_t error)
> +foo (struct interrupt_frame *frame, uword_t error)
>  {
>    void *ra = __builtin_return_address (0);
> -  if ((uintptr_t) ra != (uintptr_t) error)
> +  if ((uintptr_t) ra != (uintptr_t) frame->ip)
>      link_error ();
>  }
>
> diff --git a/gcc/testsuite/gcc.target/i386/pr79793-1.c 
> b/gcc/testsuite/gcc.target/i386/pr79793-1.c
> new file mode 100644
> index 00000000000..a382fe9c5e2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr79793-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
> +/* { dg-options "-O2 -mgeneral-regs-only" } */
> +
> +void
> + __attribute__ ((interrupt))
> +fn1 (void *frame)
> +{
> +  char fxsave_region [512] __attribute__((aligned(16)));
> +  __builtin_ia32_fxsave64 (fxsave_region);
> +}
> +
> +/* { dg-final { scan-assembler-times "sub\[lq\]\[\t \]*\\\$400,\[\t 
> \]*%\[re\]sp" 1 } } */
> +/* { dg-final { scan-assembler-times "fxsave64\[\t \]*-120\\(%\[re\]sp\\)" 1 
> } } */
> +/* { dg-final { scan-assembler-times "add\[lq\]\[\t \]*\\\$400,\[\t 
> \]*%\[re\]sp" 1 } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr79793-2.c 
> b/gcc/testsuite/gcc.target/i386/pr79793-2.c
> new file mode 100644
> index 00000000000..f6ae5aed33a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr79793-2.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */
> +/* { dg-options "-O2 -mgeneral-regs-only" } */
> +
> +typedef unsigned int uword_t __attribute__ ((mode (__word__)));
> +
> +void
> + __attribute__ ((interrupt))
> +fn1 (void *frame, uword_t error)
> +{
> +  char fxsave_region [512] __attribute__((aligned(16)));
> +  __builtin_ia32_fxsave64 (fxsave_region);
> +}
> +
> +/* { dg-final { scan-assembler-times "sub\[lq\]\[\t \]*\\\$392,\[\t 
> \]*%\[re\]sp" 1 } } */
> +/* { dg-final { scan-assembler-times "fxsave64\[\t \]*-120\\(%\[re\]sp\\)" 1 
> } } */
> +/* { dg-final { scan-assembler-times "add\[lq\]\[\t \]*\\\$400,\[\t 
> \]*%\[re\]sp" 1 } } */
> --
> 2.13.3
>

Reply via email to