我今天通过分析对应于这个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个字节.
| 归档时间: |
|
| 查看次数: |
252 次 |
| 最近记录: |