Find the answer to your Linux question:
Results 1 to 2 of 2
I'm working on a program where I've implemented a wrapper around an assembly atomic compare-and-exchange function. It seems to "work" correctly in some cases... however... in one case (implementation of ...
  1. #1
    Just Joined!
    Join Date
    Jan 2005
    Posts
    3

    gcc asm (x86) issue

    I'm working on a program where I've implemented a wrapper around an assembly atomic compare-and-exchange function. It seems to "work" correctly in some cases... however... in one case (implementation of a type of spin-lock) it does not. Here is the assembly block:
    Code:
    //Compares expectedValue with the value at pInt, and if they are the same, sets pInt to newValue and returns true with outResultValue set to newValue.  If they are different then pInt is unaffected, and returns false with outResultValue set to the value that was found at pInt.
    inline bool AtomicCompareExchange(volatile unsigned int *pInt, unsigned int expectedValue, unsigned int newValue, volatile unsigned int &outResultValue)
    {
    	unsigned int changed=0;
    	unsigned int rval;
    	asm(
    		 "lock cmpxchgl %4, (%2);"
    		 "jnz AtomCmpExch_Diff%=;"
    		 "movl %%ecx, %%eax;"
    		 "incl %1;"
    		 "AtomCmpExch_Diff%=:;"
    		 "movl %%eax, %0;"
    		:"=g"(rval), "=g"(changed)
    		:"b"(pInt), "a"(expectedValue), "c"(newValue)
    		:"memory", "cc");
    
    	outResultValue=rval;
    	return changed!=0;
    }
    And here is how it is being called in this case:

    Code:
    //TODO: check for single processor system
    bool isSingleProc=false;
    	
    //
    unsigned int yawn;
    while (!AtomicCompareExchange(&locker.taken, 0, 1, yawn))
    {
    	locker.collision=true;
    	if (isSingleProc)
    		Sleep(0);
    }
    Interesting to note also, when compiled using g++ with -g, the problem does not occur. When compiled with -O2 it does show up. Similar assembly written in intel format and compiled on msvc (this is a cross-platform project) also does not have this problem (with or without optimizations).

    I'm still relatively new to g++'s asm syntax... am I just missing something in the clobbered list maybe? It doesn't let me add any registers I've used in the input/output list there.

  2. #2
    Just Joined!
    Join Date
    Jan 2005
    Posts
    3
    I've messed with it a very little... it's currently:
    Code:
    	inline bool AtomicCompareExchange(volatile unsigned int *pInt, unsigned int expectedValue, unsigned int newValue, volatile unsigned int &outResultValue)
    	{
    		unsigned int changed=0;
    		unsigned int rval;
    		asm(
    			 "lock cmpxchgl %4, (%2);"
    			 "jnz AtomCmpExch_Diff%=;"
    			 "movl %4, %%eax;"
    			 "incl %1;"
    			 "AtomCmpExch_Diff%=:;"
    			 "movl %%eax, %0;"
    			:"=g"(rval), "=g"(changed)
    			:"r"(pInt), "a"(expectedValue), "r"(newValue)
    			:"memory", "cc");
    
    		outResultValue=rval;
    		return changed!=0;
    	}
    I see the problem though from looking at the disassembly it generated in one case.

    Being called like:
    Code:
    uint someInt=1000;
    unsigned int newVal=0;
    bool changed=AtomicCompareExchange(&someInt,900,800,newVal);
    if (changed) ......
    Here's the relevant part generated:
    Code:
    mov    $0x320,%edx
    movl   $0x0,0xffffffdc(%ebp)
    movl   $0x3e8,0xffffffe0(%ebp)
    lock cmpxchg %edx,(%esi)
    jne    0x804bdd9 <AtomCmpExch_Diff1012>
    mov    %edx,%eax
    mov    $0x1,%edx
    mov    %eax,%eax
    test   %edx,%edx
    ...it then uses edx (the "return value") in a jnz.

    Looking at that.. there's no possible way for edx to be 0 there. Is this a bug in the compiler/assembler? I'm running out of ideas here. If this forum is meant for less technical questions, can anyone point me to one more specialized in lower level issues like this?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...