Search code examples
assemblyx86nasmintel

CMPXCHG8B example using Nasm Assembler


Can anyone please, give me a very simple example of how to use the x86 CMPXCHG8B instruction with the NASM assembler?


Solution

  • 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