The 3.3.2 version is the one distributed with Debian. Also shows up on gcc-3.2 on hppa2.0n-hp-hpux11.00, but not on gcc-2.95.2 on hppa2.0n-hp-hpux11.00, nor on a number of non-hppa platforms. Command line: gcc -o conftest -g -O2 conftest.c -L/lib/pa1.1/ conftest.c is: int foo(int); main() { exit(foo(0)!=16); } int foo(int x) { if (x) { label1: asm(".skip 16"); /* or ".space 16" or somesuch */ label2: } return (&&label2)-(&&label1); } (The purpose of this program is a test for autoconf: test if .skip works as we expect). This program crashes, because the code in the asm statement is executed even though x is 0. A small variation is to insert some code before label1: int foo(int); main() { exit(foo(0)!=16); } int y; int foo(int x) { if (x) { y++; label1: asm(".skip 16"); /* or ".space 16" or somesuch */ label2: } return (&&label2)-(&&label1); } This time the program finishes, but produces the wrong result, because (interpreting the disassembled code) "&&label1" is computed as if it was placed before the "y++": (gdb) disass foo Dump of assembler code for function foo: ;;; File: conftest.c ;;; if (x) { 0x2648 <foo>: cmpib,= 0,%r26,0x266c <foo+36> 0x264c <foo+4>: addil L'0,%dp,%r1 ;;; y++; 0x2650 <foo+8>: ldw 0x20(%r1),%r19 0x2654 <foo+12>: ldo 1(%r19),%r19 0x2658 <foo+16>: stw %r19,0x20(%r1) ;;; asm(".skip 16"); /* or ".space 16" or somesuch */ 0x265c <foo+20>: break 0,0 0x2660 <foo+24>: break 0,0 0x2664 <foo+28>: break 0,0 0x2668 <foo+32>: break 0,0 ;;; return (&&label2)-(&&label1); 0x266c <foo+36>: ldil L'0x2000,%ret0 0x2670 <foo+40>: ldil L'0x2000,%r19 0x2674 <foo+44>: ldo 0x650(%r19),%r19 0x2678 <foo+48>: ldo 0x66c(%ret0),%ret0 ;;; } 0x267c <foo+52>: bv %r0(%rp) 0x2680 <foo+56>: sub %ret0,%r19,%ret0 0x2684 <foo+60>: break 0,0 I.e., &&label1 (%r19 at the end) is computed as 0x2650, but it should be 0x265c.
I think the code is wrong because the asm is not marked as volatile so the schedular is free to move it around. Can you try this: int foo(int); main() { if(foo(0)!=16) abort(); } int y; int foo(int x) { if (x) { label1: asm volatile (".skip 16"); /* or ".space 16" or somesuch */ label2: ; } return (&&label2)-(&&label1); }
Subject: Re: wrong code generated in the presence of asm("...") pinskia at gcc dot gnu dot org wrote: > I think the code is wrong because the asm is not marked as volatile so the schedular is free to > move it around. No: from the gcc manual (node Extended asm): | An `asm' instruction without any operands or clobbers (an "old |style" `asm') will be treated identically to a volatile `asm' |instruction. > Can you try this: > int foo(int); > main() > { > if(foo(0)!=16) > abort(); > } > int y; > int foo(int x) > { > if (x) { > label1: > asm volatile (".skip 16"); /* or ".space 16" or somesuch */ > label2: > ; > } > return (&&label2)-(&&label1); > } Same result. - anton
Marking as invalid to mark it as ...
unconfirmed. I think this might have been fixed on the mainline though. I also think this is the wrong way to test for an as feature.
I don't think gcc does, or should guarantee anything about the value of labels except that jumping to them works. Can you provide a test case where a goto hits the wrong place? Otherwise I don't think this is a bug.
Subject: Re: wrong code generated in the presence of asm("...") falk at debian dot org wrote: > I don't think gcc does, or should guarantee anything about the value of labels > except that jumping to them works. Can you provide a test case where a goto hits > the wrong place? Otherwise I don't think this is a bug. This bug exists independent of the labels stuff. Even if I remove the labels and all references to them, the faulting code is still the same. I.e., a conftest.c like this: int foo(int); main() { exit(foo(0)!=16); } int foo(int x) { if (x) { asm(".skip 16"); /* or ".space 16" or somesuch */ } return 0; } still produces a SIGILL and the assembly code for foo looks like this: foo .PROC .CALLINFO FRAME=0,NO_CALLS .ENTRY comiclr,= 0,%r26,%r0 .skip 16 L$0003 bv %r0(%r2) ldi 0,%r28 .EXIT .PROCEND Concerning a test case where the goto hits the wrong place: I have played around with the second example (with "y++") a little, and it seems that as soon as I insert a goto, the label corresponding to label1 is produced in the right place. This might be so by design, but also by accident, so I feel a little nervous about relying on it. In any case, a version that works (around the bug on hppa) is: int foo(int,int,int); main() { exit(foo(0,0,0)!=16); } int y; int foo(int x, int y, int z) { static void *labels[]={&&label1,&&label2}; if (x) { y++; label1: asm(".skip 16"); /* or ".space 16" or somesuch */ label2: ; } { if (y) goto *labels[z]; return labels[1]-labels[0]; } } Whether gcc should guarantee something about the values of labels beyond being able to goto there: There are a number of systems that work by copying code between two labels (as-values) at run-time; e.g., Gforth, qemu and Tempo. These systems require more than just being able to goto labels. gcc-2.95 provides for this on all platforms I have tested. I think future gccs should provide for it, too (maybe requiring special flags like -fno-reorder-blocks, but certainly in one way or the other). - anton
I can reproduce this with the same compiler version on hppa. This seems to be target specific; gcc thinks it can skip an asm with comiclr, but it can't, because an asm might be more than one instruction. I have no current 3.4 or 3.3, so I'll leave it unconfirmed for now.
This is documented as correct behavior now, see <http://gcc.gnu.org/onlinedocs/gcc/ Extended-Asm.html#Extended%20Asm>, Size of an asm, there is a new patch to say that it might create silent bad code that has not been commited yet.