This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Nonlocal gotos: wrong frame pointer handling
- From: Andreas Krebbel <krebbel1 at de dot ibm dot com>
- To: gcc at gcc dot gnu dot org
- Date: Wed, 5 Nov 2003 10:25:35 +0200
- Subject: Nonlocal gotos: wrong frame pointer handling
- Organization: IBM Entwicklung GmbH
Hello,
I've a problem using nonlocal gotos on S/390. The problem is identified but I need a
hint how to fix it.
The following program causes a segfault compiled on a S/390 (64 and 31 bit) with
gcc test.c -o test -O2
gcc -v:
Reading specs from /build/cvs/mygcc/lib/gcc/s390x-ibm-linux/3.4/specs
Configured with: ../gcc/configure --prefix=/build/cvs/mygcc --mandir=/usr/share/man
--infodir=/usr/share/info --enable-threads=posix --enable-shared --with-system-zlib
--enable-__cxa_atexit --disable-multilib --enable-serial-configure
Thread model: posix
gcc version 3.4 20031020 (experimental)
/* Target S/390 64 and 31 bit.
Checks whether the literal pool base pointer is saved and restored
correctly during nonlocal gotos.
Failures can also be caused through wrong handling of the hard frame
pointer in stmt.c: expand_goto.
Created by Andreas Krebbel <krebbel1@de.ibm.com> */
/* { dg-do run } */
/* { dg-options "-O2" } */
static void foo (int * a, int * b)
{
__label__ foo;
static void baz (int * c)
{
__label__ baz;
static void bazz ()
{
/* Force the compiler to create a literal pool for bazz. */
*c += 0xbbbbbbbb;
goto baz;
}
bazz();
*c += 0xcccccccc;
baz:
goto foo;
}
int d;
*a += 0xaaaaaaaa;
baz (&d);
foo:
*b += 0xaaaaaaaa;
}
int main ()
{
int a = 0, b = 0;
foo (&a, &b);
if (a != b)
exit (-1);
else
exit (0);
}
program execution:
# ./test
Segmentation fault
problem description:
The problem are two stack references in function baz. These are generated through:
save_area = replace_rtx (copy_rtx (save_area),
virtual_stack_vars_rtx, static_chain);
emit_move_insn (hard_frame_pointer_rtx, static_chain);
in function expand_goto file stmt.c .
The generated insns taken from test.c.01.rtl are:
(insn 30 29 31 (set (reg:DI 49)
(mem:DI (reg:DI 48) [0 S8 A8])) -1 (nil)
(nil))
(insn 31 30 32 (set (reg/f:DI %r11)
(reg:DI 48)) -1 (nil)
(nil))
The scheduler step likes to exchange both which at first glance seems to be valid. Unfortunately
register 48 turns out to be a reference to the stack using the frame pointer (register 11 on S/390)
which results in the following rtl expressions taken from test.c.39.mach:
(insn 31 34 86 (set (reg/f:DI %r11)
(mem:DI (plus:DI (reg/f:DI %r11)
(const_int 216 [0xd8])) [6 S8 A8])) 53 {*movdi_64} (nil)
(nil))
(insn 86 31 30 (set (reg:DI %r2)
(mem:DI (plus:DI (reg/f:DI %r11)
(const_int 216 [0xd8])) [6 S8 A8])) 53 {*movdi_64} (insn_list 31 (nil))
(nil))
On S/390 inserting a blockage between both instructions avoids the problem.
Index: stmt.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.333
diff -p -c -r1.333 stmt.c
*** stmt.c 28 Sep 2003 19:09:49 -0000 1.333
--- stmt.c 7 Oct 2003 15:15:53 -0000
*************** expand_goto (tree label)
*** 648,653 ****
--- 648,655 ----
else
#endif
{
+ emit_insn (gen_blockage ());
+
/* Restore frame pointer for containing function.
This sets the actual hard register used for the frame pointer
to the location of the function's incoming static chain info.
A blockage is defined in the s390 backend as an UNSPEC_VOLATILE. Therefore the scheduler can't
exchange the insns. But this solution is apparently platform dependent and therefore is not the right way.
My question is how to generate a blockage which is platform independent or whether there is a better way
to solve this.
Please consider including test.c in the testsuite in order to get notified in the regression test if the frame
pointer gets used in the wrong way during nonlocal gotos.
Bye,
-Andreas-