我正在熟悉如何让 C/C++ 与 ASM 函数对话。为此,我首先了解寄存器如何用于参数。
我有 2 个例程,它们只会乘以 2 个 64 位 float 。其中一个返回结果,另一个将结果保存在第一个参数中,该参数通过引用传递。 第一种情况很简单,而且没有问题,但第二种情况我无法让它工作,直到我让 g++ 生成汇编代码以查看它应该如何完成。程序集和 C++ 主机代码放在它们自己的文件中:
section .text
global Mul_Double_ASM
global Mul_Double_ASM_2
Mul_Double_ASM:
mulsd xmm0, xmm1
ret
Mul_Double_ASM_2:
mulsd xmm0, [rdi]
movsd [rdi], xmm0
C++ 代码很简单:
#include <iostream>
using namespace std;
extern "C" double Mul_Double_ASM(double val1, double val2);
extern "C" void Mul_Double_ASM_2(double &val1, double val2);
int main(void)
{
double val_1,
val_2;
cin >> val_1;
cin >> val_2;
cout << std::fixed << Mul_Double_ASM(val_1, val_2) << endl;
Mul_Double_ASM_2(val_1, val_2);
cout << std::fixed << val_1 << endl;
return 0;
}
它读取 2 个用户提供的数字并将它们与汇编函数相乘。两种代码现在都可以使用,但我尝试 Mul_Double_ASM_2 的方式是:
mulsd xmm0, xmm1
最后没有 ret,当我打印 val_1 的值时,它具有原始值。然后我了解到第一个参数存储在寄存器 rdi 中,因此对我的代码进行了调整。
所以我的问题是:我可以在第一个函数中直接将 xmm0 和 xmm1 相乘并且从不使用 rdi,但是当函数是按引用传递时我需要使用 rdi。您能解释一下为什么在第一种情况下使用 xmm0 和 xmm1 有效,而在第二种情况下无效吗?
最佳答案
GCC 使用的调用约定——System V AMD64 ABI *—将浮点值放在 XMM 寄存器中,但将非浮点值放在通用寄存器中。引用在程序集中作为指针(非 float )传递(参见 How are references implemented internally? )。
这意味着两个按值 double
被传递给 xmm0
和 xmm1
中的函数,而按引用 double
的地址在 rdi
中传递,按值 double
在 xmm0
中传递。
不同的调用约定可能会有所不同,但基于寄存器的调用约定通常在 XMM 寄存器而不是通用寄存器中传递浮点值。
* 我无法保证 GCC 使用此 ABI,但它看起来是其默认 ABI。
关于C++/ASM : Passing by value uses xmm0, 但通过引用它使用 rdi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57748335/