Reputation: 400
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
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