我正在尝试编写以下形式的函数:
void swap(int *a, int *b);
在 x86-64 汇编中。
[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;
Run Code Online (Sandbox Code Playgroud)
我使用以下命令在 Linux 上编译它:
Run Code Online (Sandbox Code Playgroud)nasm -f elf64 swap.asm
它编译没有任何错误。主要文件如下:
#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;
}
Run Code Online (Sandbox Code Playgroud)
主文件也编译。但是,运行此程序时出现分段错误。我犯错的任何想法?
简短回答:您期待错误的调用约定。您还使用了 32 位指针而不是 64 位指针。
Linux x86-64 应用程序使用 System V AMD64 ABI,它具有在寄存器RDI, RSI, RDX, RCX, R8, 中传递的前 6 个“常规”参数R9。进入时,a在RDI,并且b在RSI。
对于您的swap,这简化了您的代码,因为您不需要从堆栈指针的偏移量加载。
swap:
mov eax, [rdi] ; *a to EAX
xchg eax, [rsi] ; Exchange *a with *b
mov [rdi], eax ; EAX to *a
ret
Run Code Online (Sandbox Code Playgroud)
请注意,这不一定是交换的最有效方法,在低级别。尽管指令较少,但这并不一定更好,而且在性能方面更差。适用于 x86-64 的 GCC 10生成加载到寄存器,然后存储两个翻转。