简单构造函数的复杂编译器输出

bar*_*ler 3 c++ assembly gcc clang compiler-optimization

我有一个带有两个64位整数成员的struct X和一个构造函数:

struct X
{
    X(uint64_t a, uint64_t b)
    {
        a_ = a; b_ = b;
    }

    uint64_t a_, b_;
};
Run Code Online (Sandbox Code Playgroud)

当我查看编译器输出(在64位Linux上为x86-64 gcc 8.3和x86-64 clang 8.0.0)时,未启用任何优化,我看到了以下针对构造函数的代码。

x86-64 gcc 8.3:

X::X(unsigned long, unsigned long):
    push    rbp
    mov     rbp, rsp
    mov     QWORD PTR [rbp-8], rdi
    mov     QWORD PTR [rbp-16], rsi
    mov     QWORD PTR [rbp-24], rdx
    mov     rax, QWORD PTR [rbp-8]
    mov     QWORD PTR [rax], 0
    mov     rax, QWORD PTR [rbp-8]
    mov     QWORD PTR [rax+8], 0
    mov     rax, QWORD PTR [rbp-8]
    mov     rdx, QWORD PTR [rbp-16]
    mov     QWORD PTR [rax+8], rdx
    mov     rax, QWORD PTR [rbp-8]
    mov     rdx, QWORD PTR [rbp-24]
    mov     QWORD PTR [rax], rdx
    nop
    pop     rbp
    ret
Run Code Online (Sandbox Code Playgroud)

x86-64铛8.0.0:

X::X(unsigned long, unsigned long):
    push    rbp
    mov     rbp, rsp
    mov     qword ptr [rbp - 8], rdi
    mov     qword ptr [rbp - 16], rsi
    mov     qword ptr [rbp - 24], rdx
    mov     rdx, qword ptr [rbp - 8]
    mov     qword ptr [rdx], 0
    mov     qword ptr [rdx + 8], 0
    mov     rsi, qword ptr [rbp - 16]
    mov     qword ptr [rdx + 8], rsi
    mov     rsi, qword ptr [rbp - 24]
    mov     qword ptr [rdx], rsi
    pop     rbp
    ret
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么输出如此复杂?我希望有两个简单的“ mov”语句,即使没有启用优化也是如此。

Zan*_*ynx 7

未经优化的代码总是将所有C ++变量(包括函数args)存储到语句之间的内存位置中,以便调试器可以读取甚至修改这些值。(并且因为它没有花时间进行寄存器分配。)这包括函数的第一个C ++语句之前将寄存器args存储到内存中。


这是类似于from的Intel语法程序集gcc -masm=intel,因此它使用的是目标,源顺序。(我们可以根据使用的PTR,方括号和缺少的%寄存器名称来判断。)

前三个存储是根据(this, a, b)x86-64 System V ABI的调用约定在寄存器RDI,RSI和RDX中传递的函数参数。

mov     QWORD PTR [rbp-8], rdi        # this
mov     QWORD PTR [rbp-16], rsi       # a
mov     QWORD PTR [rbp-24], rdx       # b
Run Code Online (Sandbox Code Playgroud)

现在,它是装载thisrax,写零到a_b_因为你没有使用正确的构造函数初始化。或者可能是使用未在此处显示的某些代码或奇数编译器选项将初始化添加为零。

mov     rax, QWORD PTR [rbp-8]
mov     QWORD PTR [rax], 0           # this->a_ = 0
mov     rax, QWORD PTR [rbp-8]
mov     QWORD PTR [rax+8], 0         # this->b_ = 0
Run Code Online (Sandbox Code Playgroud)

然后将thisrax再次a装入rdx,然后this->a_rdxaka 写入a。再次相同b

等等,实际上必须先写入b_然后再写入,a_因为需要结构来匹配声明和内存顺序。一定[rax+8]要这样b_,不是a_

mov     rax, QWORD PTR [rbp-8]
mov     rdx, QWORD PTR [rbp-16]        # reload a
mov     QWORD PTR [rax+8], rdx         # this->b_ = a
mov     rax, QWORD PTR [rbp-8]
mov     rdx, QWORD PTR [rbp-24]        # reload b
mov     QWORD PTR [rax], rdx           # this->a_ = b
Run Code Online (Sandbox Code Playgroud)

因此,您的asm与问题中的C ++源不匹配。