Can anyone please, give me a very simple example of how to use the x86 CMPXCHG8B instruction with the NASM assembler?
Everything should be explained by comments, labels and code structure. Just a note on the lock
prefix: While it makes it atomic, it also makes it very slow, as all cores have to synchronize at that point and make sure there's no collision in memory access.
Then again, there's usually no sane reason to use cmpxchg
-like instructions without lock
, as atomic synchronization of parallel processes is the only usage where it outperforms many other solutions.
For true simple non-atomic "exchange" of memory content a classic set of mov
instructions will very likely outperform any xchg
, especially if you plan the swapping ahead and read/write all values with appropriate delays to not choke on memory bandwidth access.
If you expected some tutorial on parallel programming syncing here, then just google for some book/etc, that's not a "one answer" topic, but more like a "one book" topic.
section .text
global _start ;must be declared for using gcc
_start: ;tell linker entry point
; fail example (memory contains different than expected value)
; edx:eax = old value (to compare with memory)
mov eax,'BAD '
mov edx,'val.'
; ecx:ebx = new value to set
mov ebx,'NEW '
mov ecx,`val\n`
; CMPXCHG8B should fail, old value is different
lock cmpxchg8b [value] ; "lock" makes it atomic for multi-core
; here edx:eax == `OLD val\n` (the unexpected content of [value])
call displayValue
; pass example (memory value as expected)
; edx:eax = old value (to compare with memory)
mov eax,'OLD '
mov edx,`val\n`
; ecx:ebx = new value to set
mov ebx,'NEW '
mov ecx,`val\n`
; CMPXCHG8B should pass, setting up new value
lock cmpxchg8b [value] ; "lock" makes it atomic for multi-core
call displayValue
;system call number (sys_exit)
mov eax, 1
int 0x80
displayValue:
mov edx, 8 ;message length
mov ecx, value ;message to write
mov ebx, 1 ;file descriptor (stdout)
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
ret
section .data
value db `OLD val\n` ; 8 bytes long memory
To build and run, save it as some "cmpxchg8b.asm":
nasm -f elf32 cmpxchg8b.asm
ld -m elf_i386 -s -o cmpxchg8b cmpxchg8b.o
./cmpxchg8b
Expected output (on linux box, of course):
$ ./cmpxchg8bdemo
OLD val
NEW val