C++/ASM : Passing by value uses xmm0, 但通过引用它使用 rdi

标签 c++ assembly x86-64

我正在熟悉如何让 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 被传递给 xmm0xmm1 中的函数,而按引用 double 的地址在 rdi 中传递,按值 doublexmm0 中传递。

不同的调用约定可能会有所不同,但基于寄存器的调用约定通常在 XMM 寄存器而不是通用寄存器中传递浮点值。

* 我无法保证 GCC 使用此 ABI,但它看起来是其默认 ABI。

关于C++/ASM : Passing by value uses xmm0, 但通过引用它使用 rdi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57748335/

相关文章:

assembly - RAX、RBX、RCX、RDX、RSI、RDI、RBP、RSP 中的 R 代表什么?

assembly - x86-64 汇编程序链接因 gcc 失败

linux - 为什么这里的 Solaris 汇编器生成的机器码与 GNU 汇编器不同?

c++ - 并行 gnu 在 shell 脚本中传递参数

c++ - 从后台线程切换到主线程

c++ - 这个简单的 C++ 模板类有什么问题?

c - 在 Assembly x86 中获取三个数字的最大值时出现段错误

assembly - 为什么函数参数在 x86 上占用至少 4 个字节的堆栈?

linux - vmalloc_to_pfn 在 Linux 32 系统上返回 32 位地址。为什么它会砍掉 PAE 物理地址的高位?

c++ - 具有不同参数的函数指针