【问题标题】:Swap function in x86-64 assemblyx86-64 程序集中的交换函数
【发布时间】:2020-08-25 17:03:48
【问题描述】:

我正在尝试编写表单的函数:

无效交换(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;

我在 Linux 上使用以下命令编译它:

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;
 }

主文件也会编译。但是,当我运行这个程序时,我遇到了分段错误。有什么想法我犯了错误吗?

【问题讨论】:

  • 您应该指定您正在使用的操作系统/调用约定。有一些常见的 x86-64 调用约定。
  • 请写一份 MRE。
  • 不要将 XCHG 与内存操作数一起使用,除非您需要它是原子操作。 XCHG 具有隐含的 LOCK 语义,它比通过临时寄存器进行交换要慢得多。
  • 您说您正在编写 64 位代码,但您使用的是 32 位指针。
  • @prl:至少它是独立的,而不是内联的,如果你想学习 asm,这是一个不错的选择。鉴于初学者的错误,我认为是这种情况。

标签: assembly x86-64


【解决方案1】:

简短回答:您期待错误的调用约定。您还使用 32 位指针而不是 64 位指针。


Linux x86-64 应用程序使用 System V AMD64 ABI,它在寄存器 RDIRSIRDXRCXR8、@987654327 中传递了前 6 个“常规”参数@。输入时,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

请注意,在低级别上,这不一定是最有效的交换方法。尽管指令较少,但这不一定更好,而且在性能方面要差得多。 GCC 10 for x86-64 生成寄存器的负载,然后将两者翻转存储。

【讨论】:

  • 值得指出为什么它非常慢:xchg with memory 有一个隐含的lock 前缀,所以它是一个带有完整内存屏障的原子交换。
猜你喜欢
  • 2014-08-07
  • 1970-01-01
  • 2012-03-11
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
相关资源
最近更新 更多