【问题标题】:Nasm, C++, passing class objectNasm,C++,传递类对象
【发布时间】:2016-09-03 02:27:09
【问题描述】:

我的 cpp 文件中有一些类。

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

我正在尝试将类对象 bur 传递给我的 asm 文件中定义的函数 pod。但是我从这个类对象中获取值有很大的问题。

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

【问题讨论】:

    标签: c++ assembly x86 nasm x86-64


    【解决方案1】:

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

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

    main:
    .LFB3:
            .cfi_startproc
            subq    $8, %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 $4934256341737799680, %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    $8, %rsp
            .cfi_def_cfa_offset 8
            ret
    .LC3:
            .quad   4497835022170456064
    

    常量4497835022170456064 是十六进制的3E6B851F42C80000,如果您查看最重要的四个字节(3E6B851F),当解释为单精度float 时,这是0.23,而最不重要的四个字节(42C80000)是100.0

    同样,常量4934256341737799680(十六进制447A000000000000)的最高有效四个字节是1000.0

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

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

    【讨论】:

    • 您的代码经过优化编译(没有多余的加载和存储)。我怀疑 OP 没有使用优化,并且在 call pod 之前临时使用了 XMM2 。他可能认为这是参数的一部分。
    【解决方案2】:

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

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

    如果大小不大于 128 位,则整个对象在整数寄存器和/或 XMM 寄存器中传输,否则在堆栈中。如果对象的每个 64 位部分仅包含浮点数或双精度,则在 XMM 寄存器中传输,如果它包含整数类型或混合整数和浮点数,则在整数寄存器中传输。两个连续的浮点数可以打包到一个 XMM 寄存器的下半部分。

    在您的情况下,该类适合 128 位。 @CharlesBailey 的实验说明了这种行为。按照惯例

    ... 如果它包含整数类型或混合整数和浮点数,则在整数寄存器中。两个连续的浮点数可以打包到一个 XMM 寄存器的下半部分。示例:int 和 float:RDI。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-03
      • 2015-02-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      相关资源
      最近更新 更多