Nasm,C++,传递 class 对象

Nasm, C++, passing class object

我的 cpp 文件中有一些 class。

class F{
private:
  int id;
  float o;
  float p;
  float s; 
  static int next; 
public:
  F(double o,  double s = 0.23, double p = 0.0):
  id(next++), o(o), 
  p(p), s(s){}
};

int F::next = 0;

extern "C" float pod(F f); 

int main(){
  F bur(1000,  0.23, 100);
  pod(bur);
  return 0;
}

并且我正在尝试将 class 对象 bur 传递给在我的 asm 文件中定义的函数 pod。但是,我从这个 class 对象获取值时遇到了很大的问题。

在 asm 程序中,我在 XMM1 中有 0.23,在 XMM2 中有 100,但我找不到 1000 的存储位置。

我不知道你为什么在 xmm2 中看到 100,我怀疑这完全是巧合。查看结构如何传递的最简单方法是编译 C++ 代码。

删除了 cruft 后,我​​的编译器会这样做:

main:
.LFB3:
        .cfi_startproc
        subq    , %rsp
        .cfi_def_cfa_offset 16
        movl    _ZN1F4nextE(%rip), %edi    # load F::next into edi/rdi
        movq    .LC3(%rip), %xmm0          # load { 0.23, 100 } into xmm0
        leal    1(%rdi), %eax              # store rdi + 1 into eax
        movl    %eax, _ZN1F4nextE(%rip)    # store eax back into F::next
        movabsq 34256341737799680, %rax # load { 1000.0, 0 } into rax
        orq     %rax, %rdi                 # or rax into pre-increment F::next in rdi
        call    pod
        xorl    %eax, %eax
        addq    , %rsp
        .cfi_def_cfa_offset 8
        ret
.LC3:
        .quad   4497835022170456064

常量 4497835022170456064 的十六进制形式为 3E6B851F42C80000,如果您查看最重要的四个字节 (3E6B851F),则在解释为单精度 float,最低有效四字节 (42C80000) 为 100.0.

同样,常量 4934256341737799680(十六进制 447A000000000000)的最重要的四个字节是 1000.0.

所以,bur.idbur.ordi中传递,bur.pbur.sxmm0中传递。

x86-64 abi reference 中记录了这样做的原因。极端总结一下,因为前两个字段足够小,是混合类型,其中一个是整数,所以它们被传递到一个通用寄存器(rdi是第一个通用参数寄存器),因为接下来的两个字段都是 float,它们在 SSE 寄存器中传递。

您想看看 Agner 的 here 中的调用约定编译。根据编译器、操作系统以及您是否使用 32 位或 64 位,可能会发生不同的事情。 (参见 Table 5 第 7 章)。

例如,对于 64 位 linux,由于您的对象包含不同的值(参见 table 6),R 情况似乎适用:

Entire object is transferred in integer registers and/or XMM registers if the size is no bigger than 128 bits, otherwise on the stack. Each 64-bit part of the object is transferred in an XMM register if it contains only float or double, or in an integer register if it contains integer types or mixed integer and float. Two consecutive floats can be packed into the lower half of one XMM register.

在您的例子中,class 适合 128 位。 @CharlesBailey 的实验说明了这种行为。按照惯例

... or in an integer register if it contains integer types or mixed integer and float. Two consecutive floats can be packed into the lower half of one XMM register. Examples: int and float: RDI.

第一个 int 寄存器 rdi 应该保存 ido 其中 xmm0 应该保存 ps.

在 xmm2 中看到 100 可能是初始化的副作用,因为它作为双精度传递给结构构造函数。