I have a spin lock with the xchg instruction. The C++ function takes in the resource to be locked.
Following is the code
void SpinLock::lock( u32& resource )
{
__asm__ __volatile__
(
"mov ebx, %0\n\t"
"InUseLoop:\n\t"
"mov eax, 0x01\n\t" /* 1=In Use*/
"xchg eax, [ebx]\n\t"
"cmp eax, 0x01\n\t"
"je InUseLoop\n\t"
:"=r"(resource)
:"r"(resource)
:"eax","ebx"
);
}
void SpinLock::unlock(u32& resource )
{
__asm__ __volatile__
(
/* "mov DWORD PTR ds:[%0],0x00\n\t" */
"mov ebx, %0\n\t"
"mov DWORD PTR [ebx], 0x00\n\t"
:"=r"(resource)
:"r"(resource)
: "ebx"
);
}
This code is compiled with gcc 4.5.2 -masm=intel on a 64 bit intel machine.
The objdump produces following assembly for the above functions .
0000000000490968 <_ZN8SpinLock4lockERj>:
490968: 55 push %rbp
490969: 48 89 e5 mov %rsp,%rbp
49096c: 53 push %rbx
49096d: 48 89 7d f0 mov %rdi,-0x10(%rbp)
490971: 48 8b 45 f0 mov -0x10(%rbp),%rax
490975: 8b 10 mov (%rax),%edx
490977: 89 d3 mov %edx,%ebx
0000000000490979 <InUseLoop>:
490979: b8 01 00 00 00 mov $0x1,%eax
49097e: 67 87 03 addr32 xchg %eax,(%ebx)
490981: 83 f8 01 cmp $0x1,%eax
490984: 74 f3 je 490979 <InUseLoop>
490986: 48 8b 45 f0 mov -0x10(%rbp),%rax
49098a: 89 10 mov %edx,(%rax)
49098c: 5b pop %rbx
49098d: c9 leaveq
49098e: c3 retq
49098f: 90 nop
0000000000490990 <_ZN8SpinLock6unlockERj>:
490990: 55 push %rbp
490991: 48 89 e5 mov %rsp,%rbp
490994: 53 push %rbx
490995: 48 89 7d f0 mov %rdi,-0x10(%rbp)
490999: 48 8b 45 f0 mov -0x10(%rbp),%rax
49099d: 8b 00 mov (%rax),%eax
49099f: 89 d3 mov %edx,%ebx
4909a1: 67 c7 03 00 00 00 00 addr32 movl $0x0,(%ebx)
4909a8: 48 8b 45 f0 mov -0x10(%rbp),%rax
4909ac: 89 10 mov %edx,(%rax)
4909ae: 5b pop %rbx
4909af: c9 leaveq
4909b0: c3 retq
4909b1: 90 nop
The code dumps core when executing the locking operation.
Is there something grossly wrong here ?
Regards,
-J
First, why are you using truncated 32-bit addresses in your assembly code whereas the rest of the program is compiled to execute in 64-bit mode and operate with 64-bit addresses/pointers? I’m referring to
ebx. Why is it notrbx?Second, why are you trying to return a value from the assembly code with
"=r"(resource)? Your functions change the in-memory value withxchg eax, [ebx]andmov DWORD PTR [ebx], 0x00and returnvoid. Remove"=r"(resource).Lastly, if you look closely at the disassembly of
SpinLock::lock(), can’t you see something odd aboutebx?:In this code, the
ebxvalue, which is an address/pointer, does not come directly from the function’s parameter (rdi), the parameter first gets dereferenced withmov (%rax),%edx, but why? If you throw away all the confusing C++ reference stuff, technically, the function receives a pointer tou32, not a pointer to a pointer tou32, and thus needs no extra dereference anywhere.The problem is here:
"r"(resource). It must be"r"(&resource).A small 32-bit test app demonstrates this problem:
Output: