I found that following program loops infinitely on SPARC if it is optimized.
% uname -a SunOS mule 5.8 Generic_108528-29 sun4u sparc SUNW,Ultra-80 % cat tst.i typedef unsigned int size_t; extern int printf(const char *, ...); typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned int uint_t; typedef char *caddr_t; typedef int greg_t; typedef greg_t gregset_t[19]; struct rwindow { greg_t rw_local[8]; greg_t rw_in[8]; }; typedef struct gwindows { int wbcnt; greg_t *spbuf[31]; struct rwindow wbuf[31]; } gwindows_t; struct fpu { union { uint32_t fpu_regs[32]; double fpu_dregs[16]; } fpu_fr; struct fq *fpu_q; uint32_t fpu_fsr; uint8_t fpu_qcnt; uint8_t fpu_q_entrysize; uint8_t fpu_en; }; typedef struct fpu fpregset_t; typedef struct { unsigned int xrs_id; caddr_t xrs_ptr; } xrs_t; typedef struct { gregset_t gregs; gwindows_t *gwins; fpregset_t fpregs; xrs_t xrs; long filler[19]; } mcontext_t; typedef struct { unsigned int __sigbits[4]; } sigset_t; typedef struct sigaltstack { void *ss_sp; size_t ss_size; int ss_flags; } stack_t; typedef struct ucontext ucontext_t; struct ucontext { uint_t uc_flags; ucontext_t *uc_link; sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; long uc_filler[23]; }; extern int getcontext(ucontext_t *); extern int setcontext(const ucontext_t *); int flag; ucontext_t cont; int pad[100]; typedef void (*fun_t)(int); fun_t p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12; void h(int v) { printf("%d\n", v); } void f(void) { flag = 1; setcontext(&cont); } static int g(void) { int ret; flag = 0; getcontext(&cont); ret = flag; if (ret == 0) { printf("first flag=%d\n", flag); p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = h; f(); p0(ret); p1(ret); p2(ret); p3(ret); p4(ret); p5(ret); p6(ret); p7(ret); p8(ret); } else { printf("second flag=%d\n", flag); } return ret; } int main(int argc, char **argv) { g(); return 0; } % gcc-4.0 -v -g -O1 tst.i Using built-in specs. Target: sparc-sun-solaris2.8 Configured with: ../gcc/configure --prefix=/home/akr/g/gcc-4.0 --enable-languages=c --disable-nls Thread model: posix gcc version 4.0.1 20050618 (prerelease) /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/cc1 -fpreprocessed tst.i -quiet -dumpbase tst.i -mcpu=v7 -auxbase tst -g -O1 -version -o /var/tmp//ccINkNlP.s GNU C version 4.0.1 20050618 (prerelease) (sparc-sun-solaris2.8) compiled by GNU C version 4.0.1 20050618 (prerelease). GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 /usr/ccs/bin/as -V -Qy -s -xarch=v8 -o /var/tmp//ccwL3YLE.o /var/tmp//ccINkNlP.s /usr/ccs/bin/as: Sun WorkShop 6 2003/12/18 Compiler Common 6.0 Patch 114802-02 /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/collect2 -V -Y P,/usr/ccs/lib:/usr/lib -Qy /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crt1.o /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crti.o /usr/ccs/lib/values-Xa.o /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtbegin.o -L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1 -L/usr/ccs/bin -L/usr/ccs/lib -L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/../../.. /var/tmp//ccwL3YLE.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh -lc /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtend.o /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtn.o ld: Software Generation Utilities - Solaris Link Editors: 5.8-1.285 % ./a.out first flag=0 first flag=0 first flag=0 first flag=0 first flag=0 first flag=0 first flag=0 first flag=0 first flag=0 first flag=0 ... But it terminates as follows if it is not optimized. % gcc-4.0 -v -g -o a.out.nonopt tst.i Using built-in specs. Target: sparc-sun-solaris2.8 Configured with: ../gcc/configure --prefix=/home/akr/g/gcc-4.0 --enable-languages=c --disable-nls Thread model: posix gcc version 4.0.1 20050618 (prerelease) /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/cc1 -fpreprocessed tst.i -quiet -dumpbase tst.i -mcpu=v7 -auxbase tst -g -version -o /var/tmp//ccbUpN08.s GNU C version 4.0.1 20050618 (prerelease) (sparc-sun-solaris2.8) compiled by GNU C version 4.0.1 20050618 (prerelease). GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 /usr/ccs/bin/as -V -Qy -s -xarch=v8 -o /var/tmp//ccMsWIyd.o /var/tmp//ccbUpN08.s /usr/ccs/bin/as: Sun WorkShop 6 2003/12/18 Compiler Common 6.0 Patch 114802-02 /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/collect2 -V -Y P,/usr/ccs/lib:/usr/lib -Qy -o a.out.nonopt /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crt1.o /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crti.o /usr/ccs/lib/values-Xa.o /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtbegin.o -L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1 -L/usr/ccs/bin -L/usr/ccs/lib -L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/../../.. /var/tmp//ccMsWIyd.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh -lc /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtend.o /home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtn.o ld: Software Generation Utilities - Solaris Link Editors: 5.8-1.285 % ./a.out.nonopt first flag=0 second flag=1 ------------------------------------------------------------------------------- I investigated the problem as follows. | % gdb a.out | GNU gdb 6.3 | Copyright 2004 Free Software Foundation, Inc. | GDB is free software, covered by the GNU General Public License, and you are | welcome to change it and/or distribute copies of it under certain conditions. | Type "show copying" to see the conditions. | There is absolutely no warranty for GDB. Type "show warranty" for details. | This GDB was configured as "sparc-sun-solaris2.8"... | (gdb) disassemble g | Dump of assembler code for function g: | 0x000108ec <g+0>: save %sp, -112, %sp | 0x000108f0 <g+4>: sethi %hi(0x20c00), %l0 | 0x000108f4 <g+8>: clr [ %l0 + 0x228 ] ! 0x20e28 <flag> | 0x000108f8 <g+12>: sethi %hi(0x20c00), %o0 | 0x000108fc <g+16>: call 0x20b84 <getcontext> | 0x00010900 <g+20>: or %o0, 0x240, %o0 ! 0x20e40 <cont> | 0x00010904 <g+24>: ld [ %l0 + 0x228 ], %i0 It seems that the code assumes %l0 is preserved across the call to getcontext. | 0x00010908 <g+28>: cmp %i0, 0 | 0x0001090c <g+32>: bne,a 0x109ec <g+256> | 0x00010910 <g+36>: sethi %hi(0x10800), %o0 | 0x00010914 <g+40>: sethi %hi(0x10800), %o0 | 0x00010918 <g+44>: or %o0, 0x2b8, %o0 ! 0x10ab8 <_lib_version+16> | 0x0001091c <g+48>: call 0x20b6c <printf> | 0x00010920 <g+52>: clr %o1 | 0x00010924 <g+56>: sethi %hi(0x21000), %i5 | 0x00010928 <g+60>: sethi %hi(0x10800), %g1 | 0x0001092c <g+64>: or %g1, 0xac, %g1 ! 0x108ac <h> | 0x00010930 <g+68>: st %g1, [ %i5 + 0x20 ] | 0x00010934 <g+72>: sethi %hi(0x21000), %l7 | 0x00010938 <g+76>: st %g1, [ %l7 + 0x1c ] ! 0x2101c <p7> | 0x0001093c <g+80>: sethi %hi(0x21000), %l6 | 0x00010940 <g+84>: st %g1, [ %l6 + 0x18 ] ! 0x21018 <p6> | 0x00010944 <g+88>: sethi %hi(0x21000), %l5 | 0x00010948 <g+92>: st %g1, [ %l5 + 0x14 ] ! 0x21014 <p5> | 0x0001094c <g+96>: sethi %hi(0x21000), %l4 | 0x00010950 <g+100>: st %g1, [ %l4 + 0x10 ] ! 0x21010 <p4> | 0x00010954 <g+104>: sethi %hi(0x21000), %l3 | 0x00010958 <g+108>: st %g1, [ %l3 + 0xc ] ! 0x2100c <p3> | 0x0001095c <g+112>: sethi %hi(0x21000), %l2 | 0x00010960 <g+116>: st %g1, [ %l2 + 8 ] ! 0x21008 <p2> | 0x00010964 <g+120>: sethi %hi(0x21000), %l1 | 0x00010968 <g+124>: st %g1, [ %l1 + 4 ] ! 0x21004 <p1> | 0x0001096c <g+128>: sethi %hi(0x21000), %l0 | 0x00010970 <g+132>: call 0x108c8 <f> | 0x00010974 <g+136>: st %g1, [ %l0 ] | 0x00010978 <g+140>: ld [ %l0 ], %g1 | 0x0001097c <g+144>: call %g1 | 0x00010980 <g+148>: clr %o0 | ---Type <return> to continue, or q <return> to quit--- | 0x00010984 <g+152>: ld [ %l1 + 4 ], %g1 | 0x00010988 <g+156>: call %g1 | 0x0001098c <g+160>: clr %o0 | 0x00010990 <g+164>: ld [ %l2 + 8 ], %g1 | 0x00010994 <g+168>: call %g1 | 0x00010998 <g+172>: clr %o0 | 0x0001099c <g+176>: ld [ %l3 + 0xc ], %g1 | 0x000109a0 <g+180>: call %g1 | 0x000109a4 <g+184>: clr %o0 | 0x000109a8 <g+188>: ld [ %l4 + 0x10 ], %g1 | 0x000109ac <g+192>: call %g1 | 0x000109b0 <g+196>: clr %o0 | 0x000109b4 <g+200>: ld [ %l5 + 0x14 ], %g1 | 0x000109b8 <g+204>: call %g1 | 0x000109bc <g+208>: clr %o0 | 0x000109c0 <g+212>: ld [ %l6 + 0x18 ], %g1 | 0x000109c4 <g+216>: call %g1 | 0x000109c8 <g+220>: clr %o0 | 0x000109cc <g+224>: ld [ %l7 + 0x1c ], %g1 | 0x000109d0 <g+228>: call %g1 | 0x000109d4 <g+232>: clr %o0 | 0x000109d8 <g+236>: ld [ %i5 + 0x20 ], %g1 | 0x000109dc <g+240>: call %g1 | 0x000109e0 <g+244>: clr %o0 | 0x000109e4 <g+248>: ret | 0x000109e8 <g+252>: restore | 0x000109ec <g+256>: or %o0, 0x2c8, %o0 | 0x000109f0 <g+260>: call 0x20b6c <printf> | 0x000109f4 <g+264>: mov %i0, %o1 | 0x000109f8 <g+268>: ret | 0x000109fc <g+272>: restore | End of assembler dump. | (gdb) break *0x000108f4 | Breakpoint 1 at 0x108f4: file tst.i, line 83. | (gdb) break *0x00010904 | Breakpoint 2 at 0x10904: file tst.i, line 85. Two breakpoints are set before and after getcontext call. | (gdb) display/i $pc | (gdb) run | Starting program: /home/akr/z/a.out | | Breakpoint 1, 0x000108f4 in g () at tst.i:83 | 83 flag = 0; | 1: x/i $pc 0x108f4 <g+8>: clr [ %l0 + 0x228 ] ! 0x20e28 <flag> | (gdb) p $l0 | $1 = 134144 | (gdb) x $l0 + 0x228 | 0x20e28 <flag>: 0x00000000 %l0 is 134144 before getcontext is called. It is hi bits of the address of flag. It is used to clear flag. | (gdb) c | Continuing. | | Breakpoint 2, g () at tst.i:85 | 85 ret = flag; | 1: x/i $pc 0x10904 <g+24>: ld [ %l0 + 0x228 ], %i0 | (gdb) p $l0 | $2 = 134144 | (gdb) x $l0 + 0x228 | 0x20e28 <flag>: 0x00000000 %l0 is still 134144 after first return from getcontext. It is used to reference flag. | (gdb) c | Continuing. | first flag=0 | | Breakpoint 2, g () at tst.i:85 | 85 ret = flag; | 1: x/i $pc 0x10904 <g+24>: ld [ %l0 + 0x228 ], %i0 | (gdb) p $l0 | $3 = 135168 | (gdb) x $l0 + 0x228 | 0x21228: 0x00000000 %l0 is changed to 135168 after second return from getcontext. It is intended to reference flag but actually reference other address. The address accessed is 135168 + 0x228 which value is zero. | (gdb) x 134144 + 0x228 | 0x20e28 <flag>: 0x00000001 The value of flag is one. | (gdb) p $i0 | $4 = 0 | (gdb) si | 86 if (ret == 0) { | 1: x/i $pc 0x10908 <g+28>: cmp %i0, 0 | (gdb) p $i0 | $5 = 0 | (gdb) The condition doesn't work as intended because the compared value is different from flag. I think this is similar to GCC Bug 21957. Note that the source program is follows. | % cat tst.c | #include <stdlib.h> | #include <stdio.h> | #include <ucontext.h> | | int flag; | ucontext_t cont; | int pad[100]; | typedef void (*fun_t)(int); | fun_t p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12; | | void h(int v) | { | printf("%d\n", v); | } | | void f(void) | { | flag = 1; | setcontext(&cont); | } | | static int | g(void) | { | int ret; | | flag = 0; | getcontext(&cont); | ret = flag; | if (ret == 0) { | printf("first flag=%d\n", flag); | p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = h; | f(); | p0(ret); p1(ret); p2(ret); p3(ret); p4(ret); p5(ret); p6(ret); p7(ret); p8(ret); | } | else { | printf("second flag=%d\n", flag); | } | return ret; | } | | int main(int argc, char **argv) | { | g(); | return 0; | } -- Summary: SPARC register window is not preserved after getcontext call Product: gcc Version: 4.0.1 Status: UNCONFIRMED Severity: normal Priority: P2 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: akr at m17n dot org CC: gcc-bugs at gcc dot gnu dot org GCC build triplet: sparc-sun-solaris2.8 GCC host triplet: sparc-sun-solaris2.8 GCC target triplet: sparc-sun-solaris2.8 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22127