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.id
和bur.o
在rdi
中传递,bur.p
和bur.s
在xmm0
中传递。
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
应该保存 id
和 o
其中 xmm0
应该保存 p
和 s
.
在 xmm2 中看到 100
可能是初始化的副作用,因为它作为双精度传递给结构构造函数。
我的 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.id
和bur.o
在rdi
中传递,bur.p
和bur.s
在xmm0
中传递。
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
应该保存 id
和 o
其中 xmm0
应该保存 p
和 s
.
在 xmm2 中看到 100
可能是初始化的副作用,因为它作为双精度传递给结构构造函数。