We have found aproblem in the Linux/ia64 kernel related to sibling call optimization and the syscall_linkage attribute. On this platform, the attribute indicates that the function paramaters must be treated as read-only by the compiler. Any modification requires making a copy. The following code give an example of the problem we are describing: void bar(void) { printf("in syscall_trace\n"); } void foo(long value) __attribute__((syscall_linkage)); void foo (long value) { bar(); } Because foo() is so simple, and bar() is the last call, the compiler generates a direct branch to bar as opposed to a normal function call. The bar() function will return directly to the caller of foo(). The generated code at -O2 looks as follows: 0000000000000000 <bar>: 0: [MII] alloc r33=ar.pfs,4,3,0 6: mov r32=b0 c: addl r35=0,r1 10: [MMI] mov r34=r1;; 16: ld8 r35=[r35] 1c: nop.i 0x0 20: [MIB] nop.m 0x0 26: nop.i 0x0 2c: br.call.sptk.many b0=20 <bar+0x20>;; 30: [MII] mov r1=r34 36: mov.i ar.pfs=r33 3c: mov b0=r32 40: [MIB] nop.m 0x0 46: nop.i 0x0 4c: br.ret.sptk.many b0;; 0000000000000050 <foo>: 50: [MMI] alloc r16=ar.pfs,8,8,0;; 56: alloc r2=ar.pfs,8,0,0 5c: nop.i 0x0 60: [MIB] nop.m 0x0 66: nop.i 0x0 6c: br.many 60 <foo+0x10>;; 70: [MFB] nop.m 0x0 76: break.f 0x0 7c: nop.b 0x0;; foo() cannot modify r32 (the first argument) because of the syscall_linkage attibute. However bar() is allowed to. The sibling optimization makes a direct branch (br.many) to bar(). That branch does not actually "protect" r32 because no RSE movement occurs. The alloc in bar() simply resizes its current frame but the same r32 that was passed to foo() is also accessible and can be modified at will. In functions with the syscall_linkage attribute, sibling call optimization should not be done because it could break the guarantee offered by the attribute.
Created attachment 7124 [details] Disable sibcalls from syscall_linkage functions. This fixes the bug for me. I will do the usual testing, and then check it in. Since this is a kernel miscompilation problem, I will add the patch to mainline and gcc-3.4, and also try to get it into gcc-3.3. The testing will take a few days. I will try building a kernel to see what happens, but I won't try booting it.
Mine. IA-64. Problem confirmed.
Subject: Bug 17455 CVSROOT: /cvs/gcc Module name: gcc Changes by: wilson@gcc.gnu.org 2004-09-15 23:26:37 Modified files: gcc : ChangeLog gcc/config/ia64: ia64.c Log message: Fix linux kernel miscompilation. PR target/17455 * config/ia64/ia64.c (ia64_function_ok_for_sibcall): Return false if current_function_decl is a sibcall. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.5471&r2=2.5472 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/ia64/ia64.c.diff?cvsroot=gcc&r1=1.323&r2=1.324
Subject: Bug 17455 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-3_3-branch Changes by: wilson@gcc.gnu.org 2004-09-17 17:56:35 Modified files: gcc : ChangeLog gcc/config/ia64: ia64.c Log message: Fix linux kernel miscompile. PR target/17455 * config/ia64/ia64.c (ia64_function_ok_for_sibcall): Return false if current_function_decl is a sibcall. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.16114.2.1016&r2=1.16114.2.1017 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/ia64/ia64.c.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.198.2.21&r2=1.198.2.22
Postponed until GCC 3.4.4.
The patch is actually on the gcc-3.4 branch already, I added it Sept 15, 2004. I must have forgotten to include the PR line in the cvs log entry, ergo no CVS commit message in the PR. And I also forgot to close it. Fixed on gcc-3.3, gcc-3.4, and mainline (pre gcc-4 branch).