Arani
Arani

Reputation: 400

Swap function in x86-64 assembly

I am trying to write a function of the form:

void swap(int *a, int *b);

in x86-64 assembly.

[section .text]
global  swap ;
swap: mov ecx, [esp+8] ; copy parameter a to ecx
mov edx, [esp+16] ; copy parameter b to edx
mov eax, [ecx] ; copy a into eax
xchg eax, [edx] ; exchange eax with b
mov [ecx], eax;
ret;

I compile this on Linux using the following command:

nasm -f elf64 swap.asm

It compiles without any error. The main file is as follows:

 #include <stdio.h>
 extern void swap(int *a,int *b);
 int main(){
          int a = 10, int b = 20;
          swap(&a,&b);
          printf("a = %d b = %d\n",a,b );
          return 0;
 }

The main file also compiles. However, I get a segmentation fault when I run this program. Any ideas where I am making a mistake?

Upvotes: 2

Views: 3882

Answers (1)

Thomas Jager
Thomas Jager

Reputation: 5265

Short answer: You're expecting the wrong calling convention. You're also using 32-bit pointers instead of 64-bit ones.


Linux x86-64 applications use the System V AMD64 ABI, which has the first 6 "regular" arguments passed in the registers RDI, RSI, RDX, RCX, R8, R9. On entry, a is in RDI, and b is in RSI.

In the case of your swap, this simplifies your code because you don't need to load from offsets from the stack pointer.


swap:
    mov eax, [rdi]    ; *a to EAX
    xchg eax, [rsi]   ; Exchange *a with *b
    mov [rdi], eax    ; EAX to *a
    ret

Note that this isn't necessarily the most effective method for a swap, at a low level. Even though it's fewer instructions, this isn't necessarily better, and is much worse performance-wise. GCC 10 for x86-64 generates loads to registers, then stores with the two flipped.

Upvotes: 8

Related Questions