[backport proposed gcc-4.8/trunk fix for SEH handling ] From: Eric Botcazou Subject: [i386] Fix unwind/debug info for nested functions on 64-bit Windows Date: Mon, 01 Oct 2012 10:11:26 +0200 List-Archive: Hi, in the section of ix86_expand_prologue establishing the frame for Windows targets, there is: /* Note that SEH directives need to continue tracking the stack pointer even after the frame pointer has been set up. */ if (m->fs.cfa_reg == stack_pointer_rtx || TARGET_SEH) { if (m->fs.cfa_reg == stack_pointer_rtx) m->fs.cfa_offset += allocate; RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, stack_pointer_rtx, plus_constant (Pmode, stack_pointer_rtx, -allocate))); } But there is also a few lines above: if (eax_live) { emit_insn (gen_push (eax)); allocate -= UNITS_PER_WORD; } if (r10_live) { r10 = gen_rtx_REG (Pmode, R10_REG); emit_insn (gen_push (r10)); allocate -= UNITS_PER_WORD; } and these 2 pushes aren't marked, which can result in wrong SEH unwind and DWARF debug info on 64-bit Windows (we have an example of each kind in Ada). Tested on x86_64-suse-linux and with a 4.7-based SEH-enabled compiler for 64- Bit Windows. OK for mainline and 4.7 branch? 2012-10-01 Eric Botcazou * config/i386/i386.c (ix86_expand_prologue): Emit frame info for the special register pushes before frame probing and allocation. --- gcc-4.7.2/gcc/config/i386/i386.c.~1~ 2012-09-13 19:32:23.000000000 +0200 +++ gcc-4.7.2/gcc/config/i386/i386.c 2012-10-06 13:26:45.000000000 +0200 @@ -10339,7 +10339,7 @@ ix86_expand_prologue (void) rtx eax = gen_rtx_REG (Pmode, AX_REG); rtx r10 = NULL; rtx (*adjust_stack_insn)(rtx, rtx, rtx); - + const bool sp_is_cfa_reg = (m->fs.cfa_reg == stack_pointer_rtx); bool eax_live = false; bool r10_live = false; @@ -10348,16 +10348,31 @@ ix86_expand_prologue (void) if (!TARGET_64BIT_MS_ABI) eax_live = ix86_eax_live_at_start_p (); + /* Note that SEH directives need to continue tracking the stack + pointer even after the frame pointer has been set up. */ if (eax_live) { - emit_insn (gen_push (eax)); + insn = emit_insn (gen_push (eax)); allocate -= UNITS_PER_WORD; + if (sp_is_cfa_reg || TARGET_SEH) + { + if (sp_is_cfa_reg) + m->fs.cfa_offset += UNITS_PER_WORD; + RTX_FRAME_RELATED_P (insn) = 1; + } } + if (r10_live) { r10 = gen_rtx_REG (Pmode, R10_REG); - emit_insn (gen_push (r10)); + insn = emit_insn (gen_push (r10)); allocate -= UNITS_PER_WORD; + if (sp_is_cfa_reg || TARGET_SEH) + { + if (sp_is_cfa_reg) + m->fs.cfa_offset += UNITS_PER_WORD; + RTX_FRAME_RELATED_P (insn) = 1; + } } emit_move_insn (eax, GEN_INT (allocate)); @@ -10371,13 +10386,10 @@ ix86_expand_prologue (void) insn = emit_insn (adjust_stack_insn (stack_pointer_rtx, stack_pointer_rtx, eax)); - /* Note that SEH directives need to continue tracking the stack - pointer even after the frame pointer has been set up. */ - if (m->fs.cfa_reg == stack_pointer_rtx || TARGET_SEH) + if (sp_is_cfa_reg || TARGET_SEH) { - if (m->fs.cfa_reg == stack_pointer_rtx) + if (sp_is_cfa_reg) m->fs.cfa_offset += allocate; - RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, stack_pointer_rtx,