【发布时间】:2018-03-10 16:32:53
【问题描述】:
我今天开始通过分析与此 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();
}
如果使用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 字节边界的原因是什么?
【问题讨论】:
-
godbolt.org 是探索编译器生成的代码的绝佳资源
-
虽然这里实际上并没有发生,但未对齐的访问是在 x86 中通常是合法的