@@ -36,6 +36,15 @@ along with GCC; see the file COPYING3. If not see
#undef TARGET_SEH
#define TARGET_SEH TARGET_64BIT_MS_ABI
+/* Support hooks for SEH. */
+#undef TARGET_ASM_UNWIND_EMIT
+#define TARGET_ASM_UNWIND_EMIT i386_pe_seh_unwind_emit
+#undef TARGET_ASM_UNWIND_EMIT_BEFORE_INSN
+#define TARGET_ASM_UNWIND_EMIT_BEFORE_INSN false
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE i386_pe_seh_end_prologue
+#define SUBTARGET_ASM_UNWIND_INIT i386_pe_seh_init
+
#undef DEFAULT_ABI
#define DEFAULT_ABI (TARGET_64BIT ? MS_ABI : SYSV_ABI)
@@ -270,15 +279,12 @@ do { \
properly. If we are generating SDB debugging information, this
will happen automatically, so we only need to handle other cases. */
#undef ASM_DECLARE_FUNCTION_NAME
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
- do \
- { \
- i386_pe_maybe_record_exported_symbol (DECL, NAME, 0); \
- if (write_symbols != SDB_DEBUG) \
- i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \
- ASM_OUTPUT_FUNCTION_LABEL (FILE, NAME, DECL); \
- } \
- while (0)
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ i386_pe_start_function (FILE, NAME, DECL)
+
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \
+ i386_pe_end_function (FILE, NAME, DECL)
/* Add an external function to the list of functions to be declared at
the end of the file. */
@@ -31,6 +31,7 @@ extern void ix86_setup_frame_addresses (void);
extern HOST_WIDE_INT ix86_initial_elimination_offset (int, int);
extern void ix86_expand_prologue (void);
extern void ix86_expand_epilogue (int);
+extern void ix86_compute_frame_layout (struct ix86_frame *);
extern void ix86_output_addr_vec_elt (FILE *, int);
extern void ix86_output_addr_diff_elt (FILE *, int, int);
@@ -230,8 +231,14 @@ extern void i386_pe_asm_output_aligned_decl_common (FILE *, tree,
HOST_WIDE_INT,
HOST_WIDE_INT);
extern void i386_pe_file_end (void);
+extern void i386_pe_start_function (FILE *, const char *, tree);
+extern void i386_pe_end_function (FILE *, const char *, tree);
extern tree i386_pe_mangle_decl_assembler_name (tree, tree);
+extern void i386_pe_seh_init (FILE *);
+extern void i386_pe_seh_end_prologue (FILE *);
+extern void i386_pe_seh_unwind_emit (FILE *, rtx);
+
/* In winnt-cxx.c and winnt-stubs.c */
extern void i386_pe_adjust_class_at_definition (tree);
extern bool i386_pe_type_dllimport_p (tree);
@@ -1818,53 +1818,6 @@ struct GTY(()) stack_local_entry {
struct stack_local_entry *next;
};
-/* Structure describing stack frame layout.
- Stack grows downward:
-
- [arguments]
- <- ARG_POINTER
- saved pc
-
- saved static chain if ix86_static_chain_on_stack
-
- saved frame pointer if frame_pointer_needed
- <- HARD_FRAME_POINTER
- [saved regs]
- <- regs_save_offset
- [padding0]
-
- [saved SSE regs]
- <- sse_regs_save_offset
- [padding1] |
- | <- FRAME_POINTER
- [va_arg registers] |
- |
- [frame] |
- |
- [padding2] | = to_allocate
- <- STACK_POINTER
- */
-struct ix86_frame
-{
- int nsseregs;
- int nregs;
- int va_arg_size;
- int red_zone_size;
- int outgoing_arguments_size;
- HOST_WIDE_INT frame;
-
- /* The offsets relative to ARG_POINTER. */
- HOST_WIDE_INT frame_pointer_offset;
- HOST_WIDE_INT hard_frame_pointer_offset;
- HOST_WIDE_INT stack_pointer_offset;
- HOST_WIDE_INT reg_save_offset;
- HOST_WIDE_INT sse_reg_save_offset;
-
- /* When save_regs_using_mov is set, emit prologue using
- move instead of push instructions. */
- bool save_regs_using_mov;
-};
-
/* Code model option. */
enum cmodel ix86_cmodel;
/* Asm dialect. */
@@ -1976,7 +1929,6 @@ static rtx ix86_function_value (const_tree, const_tree, bool);
static bool ix86_function_value_regno_p (const unsigned int);
static rtx ix86_static_chain (const_tree, bool);
static int ix86_function_regparm (const_tree, const_tree);
-static void ix86_compute_frame_layout (struct ix86_frame *);
static bool ix86_expand_vector_init_one_nonzero (bool, enum machine_mode,
rtx, rtx, int);
static void ix86_add_new_builtins (int);
@@ -2005,7 +1957,6 @@ static void ix86_set_current_function (tree);
static unsigned int ix86_minimum_incoming_stack_boundary (bool);
static enum calling_abi ix86_function_abi (const_tree);
-
#ifndef SUBTARGET32_DEFAULT_CPU
#define SUBTARGET32_DEFAULT_CPU "i386"
@@ -5166,6 +5117,10 @@ ix86_asm_output_function_label (FILE *asm_out_file, const char *fname,
fprintf (asm_out_file, ASM_LONG " %#x\n", filler_cc);
}
+#ifdef SUBTARGET_ASM_UNWIND_INIT
+ SUBTARGET_ASM_UNWIND_INIT (asm_out_file);
+#endif
+
ASM_OUTPUT_LABEL (asm_out_file, fname);
/* Output magic byte marker, if hot-patch attribute is set. */
@@ -8318,7 +8273,7 @@ ix86_builtin_setjmp_frame_value (void)
/* Fill structure ix86_frame about frame of currently computed function. */
-static void
+void
ix86_compute_frame_layout (struct ix86_frame *frame)
{
unsigned int stack_alignment_needed;
@@ -31476,6 +31431,7 @@ ix86_enum_va_list (int idx, const char **pname, tree *ptree)
return 0;
}
+
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
@@ -2333,6 +2333,55 @@ struct GTY(()) machine_frame_state
BOOL_BITFIELD realigned : 1;
};
+/* Structure describing stack frame layout.
+ Stack grows downward:
+
+ [arguments]
+ <- ARG_POINTER
+ saved pc
+
+ saved static chain if ix86_static_chain_on_stack
+
+ saved frame pointer if frame_pointer_needed
+ <- HARD_FRAME_POINTER
+ [saved regs]
+ <- regs_save_offset
+ [padding0]
+
+ [saved SSE regs]
+ <- sse_regs_save_offset
+ [padding1] |
+ | <- FRAME_POINTER
+ [va_arg registers] |
+ |
+ [frame] |
+ |
+ [padding2] | = to_allocate
+ <- STACK_POINTER
+ */
+struct ix86_frame
+{
+ int nsseregs;
+ int nregs;
+ int va_arg_size;
+ int red_zone_size;
+ int outgoing_arguments_size;
+ HOST_WIDE_INT frame;
+
+ /* The offsets relative to ARG_POINTER. */
+ HOST_WIDE_INT frame_pointer_offset;
+ HOST_WIDE_INT hard_frame_pointer_offset;
+ HOST_WIDE_INT stack_pointer_offset;
+ HOST_WIDE_INT reg_save_offset;
+ HOST_WIDE_INT sse_reg_save_offset;
+
+ /* When save_regs_using_mov is set, emit prologue using
+ move instead of push instructions. */
+ bool save_regs_using_mov;
+};
+
+struct seh_frame_state;
+
struct GTY(()) machine_function {
struct stack_local_entry *stack_locals;
const char *some_ld_name;
@@ -2376,6 +2425,9 @@ struct GTY(()) machine_function {
/* During prologue/epilogue generation, the current frame state.
Otherwise, the frame state at the end of the prologue. */
struct machine_frame_state fs;
+
+ /* During SEH output, this is non-null. */
+ struct seh_frame_state * GTY((skip(""))) seh;
};
#endif
@@ -730,4 +730,565 @@ i386_pe_file_end (void)
}
}
+
+/* x64 Structured Exception Handling unwind info. */
+
+struct seh_frame_state
+{
+ /* The frame data for this function. */
+ struct ix86_frame frame;
+
+ /* SEH uses unsigned offsets for all register saves. When using a frame
+ pointer, these offsets are relative to FP_BASE = FP_REG - FP_OFFSET.
+ Not to be confusing with too many "offset" values, but this variable
+ contains the CFA offset of the FP_BASE we've chosen for this function.
+ This makes it easy fo compare with other CFA offsets we'll be
+ extracting from the RTX_FRAME_RELATED expressions. */
+ HOST_WIDE_INT fp_base_offset;
+
+ /* The CFA is located at CFA_REG + CFA_OFFSET. */
+ HOST_WIDE_INT cfa_offset;
+ unsigned int cfa_regno;
+
+ /* From the SEH docs: "If an FP reg is used, then any unwind code
+ taking an offset must only be used after the FP reg is established
+ in the prolog." This records if such an event has ocurred. */
+ bool reg_save_emitted;
+
+ /* This is all kinds of tricky:
+
+ In order to support functions with a DRAP, we actually emit two SEH
+ regions; the first covers from the function entry point until we've
+ re-aligned the stack. The second covers the balance of the function.
+ In the first region we set up DRAP as the FP. This keeps track of
+ the entry stack value while we perform the re-alignment. In the
+ second region we set up RBP as the FP as normal, and use the saved
+ CFA within the stack frame as the saved RSP value.
+
+ This is complicated by the fact that we can't begin this second SEH
+ frame until we've performed the DRAP store into the re-aligned frame,
+ because we have to immediately record the RSP store. Thus we must
+ queue other register stores that happen beforehand. */
+ bool saw_realign;
+ bool saw_realign_frame;
+
+ /* If we see a register store while SAW_REALIGN, then record the CFA
+ offset of the store here. */
+#define MAX_SEH_SAVE 32
+ int realign_save_count;
+ rtx realign_save_reg[MAX_SEH_SAVE];
+ int realign_save_off[MAX_SEH_SAVE];
+};
+
+static void seh_emit_realign_frame (FILE *, struct seh_frame_state *,
+ HOST_WIDE_INT);
+
+/* Set up data structures beginning output for SEH. */
+
+void
+i386_pe_seh_init (FILE *f)
+{
+ struct seh_frame_state *seh;
+
+ if (!TARGET_SEH)
+ return;
+
+ seh = XCNEW (struct seh_frame_state);
+ cfun->machine->seh = seh;
+
+ ix86_compute_frame_layout (&seh->frame);
+
+ if (frame_pointer_needed)
+ {
+ /* Careful: FP_OFFSET must be a multiple of 16. If we have no
+ SSE registers to save, then we won't have aligned the SSE
+ register save area, and so this offset might not be aligned. */
+ if (seh->frame.nsseregs == 0)
+ seh->frame.sse_reg_save_offset += seh->frame.sse_reg_save_offset & 8;
+ gcc_checking_assert ((seh->frame.sse_reg_save_offset & 15) == 0);
+ }
+
+ seh->cfa_offset = INCOMING_FRAME_SP_OFFSET;
+ seh->cfa_regno = STACK_POINTER_REGNUM;
+
+ fputs ("\t.seh_proc\t", f);
+ assemble_name (f, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)));
+ fputc ('\n', f);
+}
+
+void
+i386_pe_seh_end_prologue (FILE *f)
+{
+ if (!TARGET_SEH)
+ return;
+
+ XDELETE (cfun->machine->seh);
+ cfun->machine->seh = NULL;
+
+ fputs ("\t.seh_endprologue\n", f);
+}
+
+static void
+i386_pe_seh_fini (FILE *f)
+{
+ if (!TARGET_SEH)
+ return;
+
+ fputs ("\t.seh_endproc\n", f);
+}
+
+/* Emit an assembler directive to save REG via a PUSH. */
+
+static void
+seh_emit_push (FILE *f, struct seh_frame_state *seh, rtx reg)
+{
+ unsigned int regno = REGNO (reg);
+
+ gcc_checking_assert (GENERAL_REGNO_P (regno));
+
+ if (seh->cfa_regno == STACK_POINTER_REGNUM)
+ seh->cfa_offset += UNITS_PER_WORD;
+
+ if (seh->saw_realign && !seh->saw_realign_frame)
+ {
+ gcc_checking_assert (seh->cfa_regno == STACK_POINTER_REGNUM);
+ if (regno == REGNO (crtl->drap_reg))
+ seh_emit_realign_frame (f, seh, seh->cfa_offset);
+ else
+ {
+ int i = seh->realign_save_count++;
+ seh->realign_save_reg[i] = reg;
+ seh->realign_save_off[i] = seh->cfa_offset;
+ }
+ }
+ else
+ {
+ fputs ("\t.seh_pushreg\t", f);
+ print_reg (reg, 0, f);
+ fputc ('\n', f);
+ }
+}
+
+/* Emit an assembler directive to save REG at CFA - CFA_OFFSET. */
+
+static void
+seh_emit_save (FILE *f, struct seh_frame_state *seh,
+ rtx reg, HOST_WIDE_INT cfa_offset)
+{
+ unsigned int regno = REGNO (reg);
+
+ if (seh->saw_realign && !seh->saw_realign_frame)
+ {
+ if (regno == REGNO (crtl->drap_reg))
+ seh_emit_realign_frame (f, seh, cfa_offset);
+ else
+ {
+ int i = seh->realign_save_count++;
+ seh->realign_save_reg[i] = reg;
+ seh->realign_save_off[i] = cfa_offset;
+ }
+ }
+ else
+ {
+ HOST_WIDE_INT base_offset, offset;
+
+ if (seh->cfa_regno == STACK_POINTER_REGNUM)
+ base_offset = seh->cfa_offset;
+ else
+ base_offset = seh->fp_base_offset;
+
+ /* Negative save offsets are not supported. */
+ gcc_assert (base_offset >= cfa_offset);
+ offset = base_offset - cfa_offset;
+
+ fputs ((SSE_REGNO_P (regno) ? "\t.seh_savexmm\t"
+ : GENERAL_REGNO_P (regno) ? "\t.seh_savereg\t"
+ : (gcc_unreachable (), "")), f);
+ print_reg (reg, 0, f);
+ fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+
+ seh->reg_save_emitted = true;
+ }
+}
+
+/* Emit an assembler directive to adjust RSP by OFFSET. */
+
+static void
+seh_emit_stackalloc (FILE *f, struct seh_frame_state *seh,
+ HOST_WIDE_INT offset)
+{
+ /* We're only concerned with prologue stack allocations, which all
+ are subtractions from the stack pointer. */
+ gcc_assert (offset < 0);
+ offset = -offset;
+
+ if (seh->cfa_regno == STACK_POINTER_REGNUM)
+ seh->cfa_offset += offset;
+
+ if (!seh->saw_realign || seh->saw_realign_frame)
+ fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Emit an assembler directive to set up the frame pointer. */
+
+static void
+seh_emit_setframe (FILE *f, struct seh_frame_state *seh,
+ rtx reg, HOST_WIDE_INT cfa_offset,
+ HOST_WIDE_INT max_offset)
+{
+ HOST_WIDE_INT offset;
+
+ if (seh->saw_realign && !seh->saw_realign_frame)
+ return;
+
+ offset = max_offset - seh->cfa_offset;
+ gcc_assert (seh->cfa_regno == STACK_POINTER_REGNUM);
+ gcc_assert (offset >= 0);
+ gcc_assert ((offset & 15) == 0);
+
+ seh->cfa_regno = REGNO (reg);
+ seh->cfa_offset = cfa_offset;
+ seh->fp_base_offset = max_offset;
+
+ fputs ("\t.seh_setframe\t", f);
+ print_reg (reg, 0, f);
+ fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
+}
+
+/* Emit assembler directives to establish a realigned stack frame. */
+
+static void
+seh_emit_realign_frame (FILE *f, struct seh_frame_state *seh,
+ HOST_WIDE_INT drap_cfa_offset)
+{
+ int i;
+
+ gcc_assert (seh->saw_realign);
+ gcc_assert (!seh->saw_realign_frame);
+ seh->saw_realign_frame = true;
+
+ /* End the first SEH frame and begin another. For some reason the
+ syntax of .seh_proc requires a symbol; invent a new "r.foo" symbol
+ to describe the second SEH frame. */
+ fputs ("\t.seh_endproc\n", f);
+ fputs ("\t.seh_proc\tr.", f);
+ assemble_name (f, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)));
+ fputc ('\n', f);
+
+ /* We've been tracking the current stack offset via CFA_OFFSET,
+ but we havn't been able to record anything so far. Do so now. */
+ gcc_assert (seh->cfa_regno == STACK_POINTER_REGNUM);
+ fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n",
+ seh->cfa_offset);
+
+ /* Establish the frame pointer for the realigned frame. */
+ seh_emit_setframe (f, seh, hard_frame_pointer_rtx,
+ seh->frame.hard_frame_pointer_offset,
+ seh->frame.sse_reg_save_offset);
+
+ /* Record all of the register saves we've seen to this point. */
+ for (i = seh->realign_save_count - 1; i >= 0; --i)
+ seh_emit_save (f, seh, seh->realign_save_reg[i], seh->realign_save_off[i]);
+
+ /* Record the save of the DRAP as a save of RSP. */
+ seh_emit_save (f, seh, stack_pointer_rtx, drap_cfa_offset);
+}
+
+/* Process REG_CFA_DEF_CFA for SEH. */
+
+static void
+seh_cfa_def_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ HOST_WIDE_INT addend = 0;
+
+ /* Another bit of a hack; see ix86_emit_save_reg_using_mov for
+ the original. We've stored the DRAP register into the frame.
+ For dwarf2 we want to establish a new CFA. For SEH we want
+ to record this as a save of the original RSP.
+
+ The other instances of REG_CFA_DEF_CFA are in the epilogue,
+ which are not relevant here. */
+ gcc_assert (MEM_P (pat));
+ pat = XEXP (pat, 0);
+ if (GET_CODE (pat) == PLUS)
+ {
+ addend = INTVAL (XEXP (pat, 1));
+ pat = XEXP (pat, 0);
+ }
+ gcc_assert (pat == hard_frame_pointer_rtx);
+
+ seh_emit_realign_frame (f, seh,
+ seh->frame.hard_frame_pointer_offset - addend);
+}
+
+/* Process REG_CFA_ADJUST_CFA for SEH. */
+
+static void
+seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ rtx dest, src;
+ HOST_WIDE_INT reg_offset = 0;
+ unsigned int dest_regno;
+
+ dest = SET_DEST (pat);
+ src = SET_SRC (pat);
+
+ if (GET_CODE (src) == PLUS)
+ {
+ reg_offset = INTVAL (XEXP (src, 1));
+ src = XEXP (src, 0);
+ }
+ gcc_assert (src == stack_pointer_rtx);
+ gcc_assert (seh->cfa_regno == STACK_POINTER_REGNUM);
+ dest_regno = REGNO (dest);
+
+ if (dest_regno == STACK_POINTER_REGNUM)
+ seh_emit_stackalloc (f, seh, reg_offset);
+ else if (dest_regno == HARD_FRAME_POINTER_REGNUM)
+ seh_emit_setframe (f, seh, dest, seh->cfa_offset - reg_offset,
+ seh->frame.sse_reg_save_offset);
+ else if (crtl->drap_reg && dest_regno == REGNO (crtl->drap_reg))
+ seh_emit_setframe (f, seh, dest, seh->cfa_offset - reg_offset,
+ seh->cfa_offset);
+ else
+ gcc_unreachable ();
+}
+
+/* Process REG_CFA_OFFSET for SEH. */
+
+static void
+seh_cfa_offset (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ rtx dest, src;
+ HOST_WIDE_INT reg_offset;
+
+ dest = SET_DEST (pat);
+ src = SET_SRC (pat);
+
+ gcc_assert (MEM_P (dest));
+ dest = XEXP (dest, 0);
+ if (REG_P (dest))
+ reg_offset = 0;
+ else
+ {
+ gcc_assert (GET_CODE (dest) == PLUS);
+ reg_offset = INTVAL (XEXP (dest, 1));
+ dest = XEXP (dest, 0);
+ }
+ gcc_assert (REGNO (dest) == seh->cfa_regno);
+
+ seh_emit_save (f, seh, src, seh->cfa_offset - reg_offset);
+}
+
+/* Process REG_CFA_EXPRESSION for SEH. */
+
+static void
+seh_cfa_expression (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ /* ??? This is valid only under extremely limited circumstances.
+ This should be a re-aligned stack frame with DRAP. For dwarf2,
+ the CFA is still up with the DRAP and we need the CFA_expression
+ in order to save a register relative to RBP instead of relative
+ to the CFA. For SEH, we should be in the (second) aligned frame
+ with the frame pointer established. */
+ gcc_checking_assert (seh->saw_realign);
+ seh_cfa_offset (f, seh, pat);
+}
+
+/* Process a FRAME_RELATED_EXPR for SEH. */
+
+static void
+seh_frame_related_expr (FILE *f, struct seh_frame_state *seh, rtx pat)
+{
+ rtx dest, src;
+ HOST_WIDE_INT addend;
+
+ /* See the full loop in dwarf2out_frame_debug_expr. */
+ if (GET_CODE (pat) == PARALLEL || GET_CODE (pat) == SEQUENCE)
+ {
+ int i, n = XVECLEN (pat, 0), pass, npass;
+
+ npass = (GET_CODE (pat) == PARALLEL ? 2 : 1);
+ for (pass = 0; pass < npass; ++pass)
+ for (i = 0; i < n; ++i)
+ {
+ rtx ele = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (ele) != SET)
+ continue;
+ dest = SET_DEST (ele);
+
+ /* Process each member of the PARALLEL independently. The first
+ member is always processed; others only if they are marked. */
+ if (i == 0 || RTX_FRAME_RELATED_P (ele))
+ {
+ /* Evaluate all register saves in the first pass and all
+ register updates in the second pass. */
+ if (MEM_P (dest) ^ pass)
+ seh_frame_related_expr (f, seh, ele);
+ }
+ }
+ return;
+ }
+
+ dest = SET_DEST (pat);
+ src = SET_SRC (pat);
+
+ switch (GET_CODE (dest))
+ {
+ case REG:
+ switch (GET_CODE (src))
+ {
+ case REG:
+ /* REG = REG: This should be establishing a frame pointer. */
+ gcc_assert (src == stack_pointer_rtx);
+ gcc_assert (dest == hard_frame_pointer_rtx);
+ seh_emit_setframe (f, seh, dest, seh->cfa_offset,
+ seh->frame.sse_reg_save_offset);
+ break;
+
+ case PLUS:
+ addend = INTVAL (XEXP (src, 1));
+ src = XEXP (src, 0);
+ if (REGNO (src) == seh->cfa_regno)
+ seh_cfa_adjust_cfa (f, seh, pat);
+ else if (dest == stack_pointer_rtx)
+ {
+ gcc_assert (src == stack_pointer_rtx);
+ seh_emit_stackalloc (f, seh, addend);
+ }
+ else
+ gcc_unreachable ();
+ break;
+
+ case AND:
+ gcc_assert (dest == stack_pointer_rtx);
+ if (stack_realign_drap)
+ {
+ seh->saw_realign = true;
+ seh->cfa_regno = STACK_POINTER_REGNUM;
+ seh->cfa_offset = 0;
+
+ fputs ("\t.seh_endprologue\n", f);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case MEM:
+ /* A save of some kind. */
+ dest = XEXP (dest, 0);
+ if (GET_CODE (dest) == PRE_DEC)
+ {
+ gcc_checking_assert (GET_MODE (src) == Pmode);
+
+ /* During drap, we push a copy of the return address so that
+ it's in the aligned stack frame. We need do nothing except
+ account for the stack usage. */
+ if (MEM_P (src))
+ seh_emit_stackalloc (f, seh, -UNITS_PER_WORD);
+ else
+ seh_emit_push (f, seh, src);
+ }
+ else
+ seh_cfa_offset (f, seh, pat);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* This function looks at a single insn and emits any SEH directives
+ required for unwind of this insn. */
+
+void
+i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn)
+{
+ rtx note, pat;
+ bool handled_one = false;
+ struct seh_frame_state *seh;
+
+ if (!TARGET_SEH)
+ return;
+ if (NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn))
+ return;
+
+ /* We free the SEH data once done with the prologue. Ignore those
+ RTX_FRAME_RELATED_P insns that are associated with the epilogue. */
+ seh = cfun->machine->seh;
+ if (seh == NULL)
+ return;
+
+ for (note = REG_NOTES (insn); note ; note = XEXP (note, 1))
+ {
+ pat = XEXP (note, 0);
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_FRAME_RELATED_EXPR:
+ goto found;
+
+ case REG_CFA_DEF_CFA:
+ seh_cfa_def_cfa (asm_out_file, seh, pat);
+ handled_one = true;
+ break;
+
+ case REG_CFA_ADJUST_CFA:
+ if (pat == NULL)
+ {
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) == PARALLEL)
+ pat = XVECEXP (pat, 0, 0);
+ }
+ seh_cfa_adjust_cfa (asm_out_file, seh, pat);
+ handled_one = true;
+ break;
+
+ case REG_CFA_OFFSET:
+ if (pat == NULL)
+ pat = single_set (insn);
+ seh_cfa_offset (asm_out_file, seh, pat);
+ handled_one = true;
+ break;
+
+ case REG_CFA_REGISTER:
+ gcc_unreachable ();
+
+ case REG_CFA_EXPRESSION:
+ seh_cfa_expression (asm_out_file, seh, pat);
+ handled_one = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (handled_one)
+ return;
+ pat = PATTERN (insn);
+ found:
+ seh_frame_related_expr (asm_out_file, seh, pat);
+}
+
+
+void
+i386_pe_start_function (FILE *f, const char *name, tree decl)
+{
+ i386_pe_maybe_record_exported_symbol (decl, name, 0);
+ if (write_symbols != SDB_DEBUG)
+ i386_pe_declare_function_type (f, name, TREE_PUBLIC (decl));
+ ASM_OUTPUT_FUNCTION_LABEL (f, name, decl);
+}
+
+void
+i386_pe_end_function (FILE *f, const char *name ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
+{
+ i386_pe_seh_fini (f);
+}
+
+
#include "gt-winnt.h"
From: Richard Henderson <rth@twiddle.net> Horrid parsing code manages to build 2 SEH frames for DRAP functions. Which doesn't work during the epilogues, and it is unknown if it will even work for the body of the function. --- gcc/config/i386/cygming.h | 24 ++- gcc/config/i386/i386-protos.h | 7 + gcc/config/i386/i386.c | 56 +---- gcc/config/i386/i386.h | 52 ++++ gcc/config/i386/winnt.c | 561 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 641 insertions(+), 59 deletions(-)