tags:

views:

193

answers:

2

So, here's a piece of code that recently started causing grief when we upgraded to gcc4.3.3 from gcc4.2.4.

void testAndSet(  volatile int*  s, int* val )
{
   __asm__ __volatile__ ( "btsl   $0, %0\n   "
           "jc   bitSet\n   "
           "movl   $0, %1\n   "
           "jmp   returnVector\n"
           "bitSet:\n   "
           "movl   $1, %1\n"
           "returnVector: " : "=m"(*s), "=m"(*val) );
}

It now fails with the errors:

lock.cxx: Assembler messages:
lock.cxx:59: Error: symbol `bitSet' is already defined
lock.cxx:61: Error: symbol `returnVector' is already defined
lock.cxx:59: Error: symbol `bitSet' is already defined
lock.cxx:61: Error: symbol `returnVector' is already defined

I'm sure those symbols aren't found anywhere else. (Renaming them causes the same error with the new name).

What up with this? And why do I get the errors twice?

+5  A: 

Probably the optimizer has changed and is now inlining your testAndSet() function into 2 places. Because you are using global names for your labels, this does not work. You should use local names instead. E.g:

   __asm__ __volatile__ ( "btsl   $0, %0\n   "
           "jc   0f\n   "
           "movl   $0, %1\n   "
           "jmp   1f\n"
           "0:\n   "
           "movl   $1, %1\n"
           "1: " : "=m"(*s), "=m"(*val) );

Local labels are just numbers; to disambiguate cases where there are many labels called "0" you need to use "jmp 0f" for forward jumps and "jmp 0b" for backward jumps.

user9876
Great. That was it. Interestingly, fails with the gcc option -02 but not with -O
The higher the value to the -O parameter, the more likely it is to inline things; essentially, -O2 and -O3 are going to use optimizations based around increasingly aggressive inlining and loop-unrolling, etc. It might be worth trying '-Os' (optimize without increasing code size) which often provides a good middle-ground optimization.
Jim Dovey
+3  A: 

This is unrelated to your error, but you could improve your code and avoid branches simply using the setCC instruction:

   __asm__ __volatile__ ( "btsl   $0, %0\n   "
       "mov $0, %1\n"
       "setc %1\n" : "=m"(*s), "=m"(*val) );

The setCC instruction (where CC is one of the condition code flags, analogous to the jCC instruction) sets a byte to 0 or 1 depending on whether or not the given condition was satisfied. Since the destination is a 4-byte value, you need to either preload it with 0 or use the MOVZX instruction to make the upper 3 bytes 0.

Adam Rosenfield