summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2017-07-25 04:43:05 -0700
committerH.J. Lu <hjl.tools@gmail.com>2017-07-27 09:43:30 -0700
commitebba3121c46092b238e9d337b160f03b6b106b6d (patch)
treed8b17b0cd4ea848cbe44e9c376f200e8f9d38916
parentd80a40e357bf8d4f52504933d90b17feaee27ff7 (diff)
downloadgcc-hjl/pr79793/master.tar.gz
Properly compute stack frame for exception handlerhjl/pr79793/master
-rw-r--r--gcc/config/i386/i386.c35
-rw-r--r--gcc/config/i386/i386.h6
-rw-r--r--gcc/testsuite/gcc.dg/guality/pr68037-1.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/interrupt-5.c13
4 files changed, 31 insertions, 35 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f1486ff3750..534a611a296 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10422,25 +10422,20 @@ 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;
+ /* -WORD(AP) in the current frame in interrupt handler. */
+ 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. */
arg = gen_rtx_MEM (word_mode,
plus_constant (Pmode,
arg_pointer_rtx,
- -UNITS_PER_WORD));
+ -2 * UNITS_PER_WORD));
}
return arg;
}
@@ -12915,8 +12910,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 +15216,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 +15513,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)))
/* 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 ();
}