Search code examples
cassemblysegmentation-faultx86-64calling-convention

Assembler program to swap contents of registers


I'm trying to do a real simple assembler program to swap the contents of registers. This is what i've tried:

movq (%rcx), %rax
movq (%rbx), %rdx
movq %rdx, (%rcx)
movq %rax, (%rbx)
ret

It gives me segmentation fault.

Here is an example of a working program in c:

void swap(int64_t *a, int64_t *b) {
    int64_t c = *a;
    *a = *b;
    *b = c;
}

Solution

  • See: https://en.wikipedia.org/wiki/X86_calling_conventions

    You neglected to mention whether you're compiling for Microsoft/Win x64 or for the System V AMD64 ABI [or for something else entirely].

    You are using AT&T asm syntax, so I'm assuming you want the SysV calling convention. (Since tools like GCC and GAS are more common on Linux / MacOS. But if you're using MinGW w64 on Windows then you'll want the Windows convention.)


    You're assuming the args are in: %rcx and %rbx. This does not correspond with either convention [although it is somewhat closer to the MS ABI]

    For System V AMD64 ABI (e.g. Linux, BSD, MacOS), the first two args are passed in %rdi and %rsi respectively. And, not in %rdx and %rcx (which are for the 3rd and 4th args).

    You can always use %rax and %rdx as temp regs because %rax holds the function return value and %rdx is an arg reg so caller won't expect them to be preserved.

    So, you want:

    # Non-Windows
    movq (%rdi),%rax
    movq (%rsi),%rdx
    movq %rdx,(%rdi)
    movq %rax,(%rsi)
    ret
    

    For MS 64 bit, the arg registers are: %rcx, %rdx, %r8, %r9

    So, you'd want:

    # Windows
    movq (%rcx),%rax
    movq (%rdx),%r8
    movq %r8,(%rcx)
    movq %rax,(%rdx)
    ret