x86-64汇编:为什么偏移25个字节?

Nib*_*bor 4 c++ assembly

我今天通过分析对应于这个c ++示例的汇编代码开始学习x86汇编(我知道存在类似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();
}
Run Code Online (Sandbox Code Playgroud)

如果编译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>
Run Code Online (Sandbox Code Playgroud)

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

int*_*jay 10

看看这个片段:

leaq    -25(%rbp), %rax
movq    %rax, %rdi
call    _ZNSaIiEC1Ev
Run Code Online (Sandbox Code Playgroud)

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

-24(%rbp)这之后,你看到的是一个不同对象的地址,编译器不跨越8字节边界读书.

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