c++ - x86-64 程序集 : why offset 25 bytes?

标签 c++ assembly

我今天开始学习 x86 汇编,通过分析与这个 c++ 示例对应的汇编代码(我知道存在类似 atoi 的东西,但我想使示例保持最小):

#include <vector>

std::vector<int> range(int N) {
    std::vector<int> v(N);
    for (unsigned int i = 0; i < N; ++i)
        v[i] = i;
    return v;
}

int main() {
    return range(100).back();
}

如果使用 g++ -O0 -S -fno-stack-protector return_by_value.cpp 进行编译,则会产生以下摘录:

... <snip>
_Z5rangei:
.LFB509:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    .cfi_lsda 0x3,.LLSDA509
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $40, %rsp
    .cfi_offset 3, -24
    movq    %rdi, -40(%rbp)
    movl    %esi, -44(%rbp)
    leaq    -25(%rbp), %rax
    movq    %rax, %rdi
    call    _ZNSaIiEC1Ev
    movl    $0, -24(%rbp)
    movl    -44(%rbp), %eax
    movslq  %eax, %rsi
    leaq    -25(%rbp), %rcx
    leaq    -24(%rbp), %rdx
    ... <snip>

我很惊讶地看到一个奇怪的(即不是 8 的倍数)偏移量:leaq -25(%rbp), %rax,特别是因为它是一个 q指令和进一步我们还有 -24(%rbp)编译器读取 8 字节边界的原因是什么?

最佳答案

看这个片段:

leaq    -25(%rbp), %rax
movq    %rax, %rdi
call    _ZNSaIiEC1Ev

_ZNSaIiEC1Ev被分解为 std::allocator<int>::allocator() , 所以 -25(%rbp)allocator<int> 的地址传递给构造函数的对象。如果我们打印 sizeof在GCC中这个对象的大小我们会得到1。由于对象的大小是1,所以不需要将它对齐到8字节,它可以放在任何内存地址。

-24(%rbp)您稍后看到的是另一个对象的地址,编译器没有读取 8 字节边界。

请注意 lea指令实际上并不访问内存——它只计算一个地址。因此,它有一个 q 的事实后缀并不意味着它访问8个字节。

关于c++ - x86-64 程序集 : why offset 25 bytes?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49211435/

相关文章:

assembly - 使用 GNU Assembler Intel 语法进行内存寻址

c++ - 你怎么解释 *(y_ptr)&val;

c - 打开 Watcom 内联汇编 SEG 和 OFFSET 运算符

c++ - 将参数传递给比较器

c++ - 检查所选数组中是否存储了任何内容? C++

c++ - 了解 C/C++ 中 Windows/MSVC 的一些 Antidebug 内联汇编

assembly - Dlang - 理解汇编中的 std.cycle()

assembly - 位字节字和双字 - 何时在汇编中使用什么?

c++ - 将迭代器取消引用到自定义结构字段

c++ - 使用插件更改 C++ 应用程序中的默认行为