Search code examples
assemblyx86-64nasmcalling-conventionwin64

Different asm on Windows x64 from a CS:APP x86-64 Linux example function for swapping a long


i am reading CS:APP 3rd edition (Ch3. pic 3.7 GAS assembly code)

long exchange(long* xp, long y)
{
  long x = *xp;
  *xp = y;
  return x;
}

exchange:
    movq  (%rdi), %rax
    movq  %rsi, (%rdi)
    ret

i wonder why below assembly code(1. asm : which is converted to nasm) does not work?

i had diassembled working c function to nasm assembly source code using c2nasm. it is quite different to original assembly.

main.cpp :

int main()
{
  long a = 4;
  // long b = exchange(&a, 3);
  long b = exchange2(&a, 3);

  printf("[a: %ld] [b: %ld]\n", a, b);

  return 0;
}

1.asm :

BITS 64

; default rel
default abs 

global    exchange2 
section   .text

exchange2:
    ;;; this code does not works
    ;;; program output    ->        [a: 4] [b: 0]
    mov rax, [rdi]
    mov [rdi], rsi 
    ret

    ;;; this code works, generated by c2nasm.
    ;;; program output    ->        [a: 3] [b: 4]
    ; push    rbp
    ; mov     rbp, rsp
    ; sub     rsp, 16
    ; mov     qword [rbp+10H], rcx
    ; mov     dword [rbp+18H], edx
    ; mov     rax, qword [rbp+10H]
    ; mov     eax, dword [rax]
    ; mov     dword [rbp-4H], eax
    ; mov     rax, qword [rbp+10H]
    ; mov     edx, dword [rbp+18H]
    ; mov     dword [rax], edx
    ; mov     eax, dword [rbp-4H]
    ; leave
    ; ret

EDIT: thanks!
working version for Windows x64 long long exchange(long long*, long long):

BITS 64

default rel

global    _exchange2     ; Windows name-mangling prepends _ to C names
section   .text

_exchange2:
    mov rax, [rcx]
    mov [rcx], rdx 
    ret

Solution

  • Your example is for the x86-64 System V ABI, used on Linux, OS X, and other non-Windows platforms (64-bit long, args in RDI, RSI, ...)

    You compiled for Windows x64, which uses a different calling convention (args in RCX, RDX), and long is a 32-bit type.


    Also you compiled with optimization disabled so the asm is full of store/reload noise. With optimization it would be basically the same but with different registers.

    BTW, you can use gcc -O3 -masm=intel to get Intel-syntax assembly which is a lot closer to NASM syntax. (It's not NASM syntax though; it's MASM-like for addressing modes, and still uses GAS directives.)