Section I6.14.2 64-Bit Mode Stack Frame in Intel SDM Vol 3 has In IA-32e mode, the RSP is aligned to a 16-byte boundary before pushing the stack frame. The stack frame itself is aligned on a 16-byte boundary when the interrupt handler is called. static unsigned int ix86_minimum_incoming_stack_boundary (bool sibcall) { unsigned int incoming_stack_boundary; /* Stack of interrupt handler is always aligned to MIN_STACK_BOUNDARY. */ if (cfun->machine->func_type != TYPE_NORMAL) incoming_stack_boundary = MIN_STACK_BOUNDARY; is incorrect for 64-bit mode.
Well, not "incorrect" but too conservative.
Patch posted at https://gcc.gnu.org/ml/gcc-patches/2017-03/msg00178.html
Author: hjl Date: Mon Mar 6 16:08:59 2017 New Revision: 245926 URL: https://gcc.gnu.org/viewcvs?rev=245926&root=gcc&view=rev Log: Set incoming stack boundary to 128 for 64-bit targets For 64-bit targets, the incoming stack of interrupt handler is aligned to 16 bytes. Update ix86_minimum_incoming_stack_boundary to set the incoming stack boundary of interrupt handler to 128 for 64-bit targets. gcc/ 2017-03-06 Julia Koval <julia.koval@intel.com> PR target/79793 * config/i386/i386.c (ix86_minimum_incoming_stack_boundary): Set incoming stack boundary to 128 for 64-bit targets. gcc/testsuite/ 2017-03-06 Julia Koval <julia.koval@intel.com> PR target/79793 * gcc.target/i386/interrupt-12.c: Update scan-assembler-times directives. * gcc.target/i386/interrupt-13.c: Ditto. * gcc.target/i386/interrupt-14.c: Ditto. * gcc.target/i386/interrupt-15.c: Ditto. Modified: trunk/gcc/ChangeLog trunk/gcc/config/i386/i386.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/gcc.target/i386/interrupt-12.c trunk/gcc/testsuite/gcc.target/i386/interrupt-13.c trunk/gcc/testsuite/gcc.target/i386/interrupt-14.c trunk/gcc/testsuite/gcc.target/i386/interrupt-15.c
Fixed for GCC 7.
In 64-bit mode, stack is 16-byte aligned when entering handler. But if there is error code SS RSP FLAGS CS RIP Error Code the stack alignment is off by 8 bytes. That is %rsp + 8 isn't multiple of 16 at the start of handler.
GCC 7.1 has been released.
(In reply to H.J. Lu from comment #5) > In 64-bit mode, stack is 16-byte aligned when entering handler. But if > there is error code > > SS > RSP > FLAGS > CS > RIP > Error Code > > the stack alignment is off by 8 bytes. That is %rsp + 8 isn't multiple > of 16 at the start of handler. A testcase: [hjl@gnu-skl-1 pr79793]$ cat y.c #include <fxsrintrin.h> 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__((interrupt)) void fn (struct interrupt_frame *frame, uword_t error) { char fxsave_region [512] __attribute__((aligned(16))); _fxsave64 (fxsave_region); } [hjl@gnu-skl-1 pr79793]$ make y.s /export/build/gnu/gcc-x32-7/build-x86_64-linux/gcc/xgcc -B/export/build/gnu/gcc-x32-7/build-x86_64-linux/gcc/ -O2 -mgeneral-regs-only -S -o y.s y.c [hjl@gnu-skl-1 pr79793]$ cat y.s .file "y.c" .text .p2align 4,,15 .globl fn .type fn, @function fn: .LFB4: .cfi_startproc subq $400, %rsp .cfi_def_cfa_offset 408 fxsave64 -120(%rsp) addq $408, %rsp iretq .cfi_endproc .LFE4: .size fn, .-fn .ident "GCC: (GNU) 7.1.1 20170724" .section .note.GNU-stack,"",@progbits [hjl@gnu-skl-1 pr79793]$ -120(%rsp) isn't aligned at 16 bytes. For [hjl@gnu-skl-1 pr79793]$ cat x.c #include <fxsrintrin.h> 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__((interrupt)) void fn (struct interrupt_frame *frame) { char fxsave_region [512] __attribute__((aligned(16))); _fxsave64 (fxsave_region); } [hjl@gnu-skl-1 pr79793]$ make x.s /export/build/gnu/gcc-x32-7/build-x86_64-linux/gcc/xgcc -B/export/build/gnu/gcc-x32-7/build-x86_64-linux/gcc/ -O2 -mgeneral-regs-only -S -o x.s x.c [hjl@gnu-skl-1 pr79793]$ cat x.s .file "x.c" .text .p2align 4,,15 .globl fn .type fn, @function fn: .LFB4: .cfi_startproc subq $400, %rsp .cfi_def_cfa_offset 408 fxsave64 -120(%rsp) addq $400, %rsp .cfi_def_cfa_offset 8 iretq .cfi_endproc .LFE4: .size fn, .-fn .ident "GCC: (GNU) 7.1.1 20170724" .section .note.GNU-stack,"",@progbits [hjl@gnu-skl-1 pr79793]$ -120(%rsp) is aligned at 16 bytes.
clang 5.0 handles stack alignment correctly: [hjl@gnu-skl-1 pr79793]$ cat x.c typedef unsigned int uword_t __attribute__ ((mode (__word__))); __attribute__((interrupt)) void fn (void *frame) { char fxsave_region [512] __attribute__((aligned(16))); __builtin_ia32_fxsave (fxsave_region); } [hjl@gnu-skl-1 pr79793]$ cat y.c typedef unsigned int uword_t __attribute__ ((mode (__word__))); __attribute__((interrupt)) void fn (void *frame, uword_t error) { char fxsave_region [512] __attribute__((aligned(16))); __builtin_ia32_fxsave (fxsave_region); } [hjl@gnu-skl-1 pr79793]$ make /export/build/gnu/llvm-clang/build-x86_64-linux/bin/clang -O2 -mgeneral-regs-only -S -o y.s y.c clang-5.0: warning: argument unused during compilation: '-mgeneral-regs-only' [-Wunused-command-line-argument] [hjl@gnu-skl-1 pr79793]$ cat x.s .text .file "x.c" .globl fn # -- Begin function fn .p2align 4, 0x90 .type fn,@function fn: # @fn .cfi_startproc # BB#0: # %entry subq $392, %rsp # imm = 0x188 .Lcfi0: .cfi_def_cfa_offset 400 cld fxsave -128(%rsp) addq $392, %rsp # imm = 0x188 iretq .Lfunc_end0: .size fn, .Lfunc_end0-fn .cfi_endproc # -- End function .ident "clang version 5.0.0 (http://llvm.org/git/clang.git f53edbb006df3bc205bf38008d96de510b2adddd) (http://llvm.org/git/llvm.git 9889fe2290766430b99a2d4fadbc5ba92f8004b6)" .section ".note.GNU-stack","",@progbits [hjl@gnu-skl-1 pr79793]$ cat y.s .text .file "y.c" .globl fn # -- Begin function fn .p2align 4, 0x90 .type fn,@function fn: # @fn .cfi_startproc # BB#0: # %entry pushq %rax subq $400, %rsp # imm = 0x190 .Lcfi0: .cfi_def_cfa_offset 408 cld fxsave -120(%rsp) addq $400, %rsp # imm = 0x190 addq $16, %rsp iretq .Lfunc_end0: .size fn, .Lfunc_end0-fn .cfi_endproc # -- End function .ident "clang version 5.0.0 (http://llvm.org/git/clang.git f53edbb006df3bc205bf38008d96de510b2adddd) (http://llvm.org/git/llvm.git 9889fe2290766430b99a2d4fadbc5ba92f8004b6)" .section ".note.GNU-stack","",@progbits [hjl@gnu-skl-1 pr79793]$
Created attachment 41826 [details] Adjust INCOMING_FRAME_SP_OFFSET for TYPE_EXCEPTION functions How about something like attached patch? The patch adjusts INCOMING_FRAME_SP_OFFSET of an exception handler to 2 * UNITS_PER_WORD. The resulting code reads: .cfi_startproc subq $392, %rsp .cfi_def_cfa_offset 400 fxsave64 -120(%rsp) addq $400, %rsp .cfi_def_cfa_offset 0 iretq .cfi_endproc Patch is otherwise untested. Probably, function argument parsing code has to be adjusted as well. I'm also not sure if all .cfi directives are correct.
Created attachment 41827 [details] An untested patch
(In reply to Uroš Bizjak from comment #9) > Created attachment 41826 [details] > Adjust INCOMING_FRAME_SP_OFFSET for TYPE_EXCEPTION functions > > How about something like attached patch? The patch adjusts > INCOMING_FRAME_SP_OFFSET of an exception handler to 2 * UNITS_PER_WORD. > > The resulting code reads: > > .cfi_startproc > subq $392, %rsp > .cfi_def_cfa_offset 400 > fxsave64 -120(%rsp) > addq $400, %rsp > .cfi_def_cfa_offset 0 > iretq > .cfi_endproc > > Patch is otherwise untested. Probably, function argument parsing code has to > be adjusted as well. I'm also not sure if all .cfi directives are correct. Our patches are very similar. Mine passed most of interrupt tests.
Created attachment 41828 [details] An updated patch Update gcc.dg/guality/pr68037-1.c. I got 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 and Running target unix/-m32 Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target. Using /usr/share/dejagnu/config/unix.exp as generic interface file for target. Using /export/gnu/import/git/sources/gcc/gcc/testsuite/config/default.exp as tool-and-target-specific interface file. Running /export/gnu/import/git/sources/gcc/gcc/testsuite/gcc.target/i386/i386.exp ... FAIL: gcc.target/i386/interrupt-12.c scan-assembler-times movl[\\t ]*-4\\(%ebp\\),[\\t ]*%eax 1 FAIL: gcc.target/i386/interrupt-13.c scan-assembler-times movl[\\t ]*-4\\(%ebp\\),[\\t ]*%eax 1 FAIL: gcc.target/i386/interrupt-15.c scan-assembler-times movl[\\t ]*-4\\(%ebp\\),[\\t ]*%eax 2 === gcc Summary for unix/-m32 === # of expected passes 211 # of unexpected failures 3 # of unsupported tests 2
Created attachment 41830 [details] An untested patch The only interrupt failures are 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
Created attachment 41834 [details] An untested patch
Created attachment 41839 [details] A patch -g -O2 -flto generates: Dump of assembler code for function fn: 0x0000000000400550 <+0>: push %rdi 0x0000000000400551 <+1>: sub $0x8,%rsp 0x0000000000400555 <+5>: cmpq $0x12345670,0x10(%rsp) 0x000000000040055e <+14>: jne 0x400430 <fn> => 0x0000000000400564 <+20>: cmpq $0x12345671,0x18(%rsp) with debug info: 00000084 0000000000000018 00000058 FDE cie=00000030 pc=0000000000400550..00000000004005b7 DW_CFA_advance_loc: 1 to 0000000000400551 DW_CFA_def_cfa_offset: 16 DW_CFA_offset: r5 (rdi) at cfa-16 DW_CFA_advance_loc: 4 to 0000000000400555 DW_CFA_def_cfa_offset: 24 DW_CFA_nop DW_CFA_nop DW_CFA_nop -g -O2 generates: 0x0000000000400550 <+0>: push %rdi 0x0000000000400551 <+1>: sub $0x8,%rsp 0x0000000000400555 <+5>: cmpq $0x12345670,0x10(%rsp) 0x000000000040055e <+14>: jne 0x400430 <fn> 0x0000000000400564 <+20>: cmpq $0x12345671,0x18(%rsp) with debug info: 00000070 0000000000000018 00000044 FDE cie=00000030 pc=0000000000400550..00000000004005b7 DW_CFA_advance_loc: 1 to 0000000000400551 DW_CFA_def_cfa_offset: 24 DW_CFA_offset: r5 (rdi) at cfa-24 DW_CFA_advance_loc: 4 to 0000000000400555 DW_CFA_def_cfa_offset: 32 DW_CFA_nop DW_CFA_nop DW_CFA_nop Somehow -flto -O2 generates the incorrect debug info.
The problem is in create_cie_data: /* On entry, the Canonical Frame Address is at SP. */ memset (&loc, 0, sizeof (loc)); loc.reg = dw_stack_pointer_regnum; loc.offset = INCOMING_FRAME_SP_OFFSET; def_cfa_1 (&loc); We lost the function type info with LTO.
(In reply to H.J. Lu from comment #16) > The problem is in create_cie_data: > > /* On entry, the Canonical Frame Address is at SP. */ > memset (&loc, 0, sizeof (loc)); > loc.reg = dw_stack_pointer_regnum; > loc.offset = INCOMING_FRAME_SP_OFFSET; > def_cfa_1 (&loc); > > We lost the function type info with LTO. We didn't lose the info. The problem is that create_pseudo_cfg assumes INCOMING_FRAME_SP_OFFSET is a constant.
(In reply to H.J. Lu from comment #17) > > We didn't lose the info. The problem is that create_pseudo_cfg assumes > INCOMING_FRAME_SP_OFFSET is a constant. I opened PR 81570.
Author: hjl Date: Sun Jul 30 14:10:32 2017 New Revision: 250721 URL: https://gcc.gnu.org/viewcvs?rev=250721&root=gcc&view=rev Log: i386: Update INCOMING_FRAME_SP_OFFSET for exception handler 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. 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. Added: trunk/gcc/testsuite/gcc.target/i386/pr79793-1.c trunk/gcc/testsuite/gcc.target/i386/pr79793-2.c Modified: trunk/gcc/ChangeLog trunk/gcc/config/i386/i386.c trunk/gcc/config/i386/i386.h trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/gcc.dg/guality/pr68037-1.c trunk/gcc/testsuite/gcc.target/i386/interrupt-5.c
Fixed for GCC 8.
Author: aldyh Date: Wed Sep 13 16:05:20 2017 New Revision: 252181 URL: https://gcc.gnu.org/viewcvs?rev=252181&root=gcc&view=rev Log: i386: Update INCOMING_FRAME_SP_OFFSET for exception handler 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. 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. Added: branches/range-gen2/gcc/testsuite/gcc.target/i386/pr79793-1.c branches/range-gen2/gcc/testsuite/gcc.target/i386/pr79793-2.c Modified: branches/range-gen2/gcc/ChangeLog branches/range-gen2/gcc/config/i386/i386.c branches/range-gen2/gcc/config/i386/i386.h branches/range-gen2/gcc/testsuite/ChangeLog branches/range-gen2/gcc/testsuite/gcc.dg/guality/pr68037-1.c branches/range-gen2/gcc/testsuite/gcc.target/i386/interrupt-5.c