我正在分析X86_64上GDB中以下(非常简单的)C程序的反汇编。
int main()
{
int a = 5;
int b = a + 6;
return 0;
}
据我所知,在X86_64中,堆栈会逐渐减少。这是堆栈顶部的地址低于堆栈底部的地址。上述程序的汇编程序如下:
Dump of assembler code for function main:
0x0000000000400474 <+0>: push %rbp
0x0000000000400475 <+1>: mov %rsp,%rbp
0x0000000000400478 <+4>: movl $0x5,-0x8(%rbp)
0x000000000040047f <+11>: mov -0x8(%rbp),%eax
0x0000000000400482 <+14>: add $0x6,%eax
0x0000000000400485 <+17>: mov %eax,-0x4(%rbp)
0x0000000000400488 <+20>: mov $0x0,%eax
0x000000000040048d <+25>: leaveq
0x000000000040048e <+26>: retq
End of assembler dump.
我理解:
-0x8(%rbp)
中。因为int中有4个字节,所以不应该是堆栈中的下一个地址-0x4(%rbp)
而不是-0x8(%rbp)
?a
的值复制到%eax
,添加6,然后将值复制到-0x4(%rbp)
的地址。使用此图形作为参考:
http://eli.thegreenplace.net/images/2011/08/x64_frame_nonleaf.png
看起来堆栈具有以下内容:
|--------------|
| rbp | <-- %rbp
| 11 | <-- -0x4(%rbp)
| 5 | <-- -0x8(%rbp)
当我期待这个时:
|--------------|
| rbp | <-- %rbp
| 5 | <-- -0x4(%rbp)
| 11 | <-- -0x8(%rbp)
似乎是7-understanding-c-by-learning-assembly中显示汇编的情况:
(gdb) disassemble
Dump of assembler code for function main:
0x0000000100000f50 <main+0>: push %rbp
0x0000000100000f51 <main+1>: mov %rsp,%rbp
0x0000000100000f54 <main+4>: mov $0x0,%eax
0x0000000100000f59 <main+9>: movl $0x0,-0x4(%rbp)
0x0000000100000f60 <main+16>: movl $0x5,-0x8(%rbp)
0x0000000100000f67 <main+23>: mov -0x8(%rbp),%ecx
0x0000000100000f6a <main+26>: add $0x6,%ecx
0x0000000100000f70 <main+32>: mov %ecx,-0xc(%rbp)
0x0000000100000f73 <main+35>: pop %rbp
0x0000000100000f74 <main+36>: retq
End of assembler dump.
当b
明确声明并首先初始化时,为什么a
的值被放入堆栈中的高位内存地址而不是a
?
答案 0 :(得分:7)
b
的值放在堆栈中,无论编译器感觉如何。你没有影响力。你不应该这样做。订单可能会在编译器的次要版本之间发生变化,因为某些内部数据结构已更改或某些代码已重新排列。有些编译器甚至会故意在不同的编译中随机化堆栈的布局,因为它可能会使某些错误难以利用。
实际上,编译器可能根本不使用堆栈。没有必要。这是在启用了一些优化的情况下编译的同一程序的反汇编:
$ cat > foo.c
int main()
{
int a = 5;
int b = a + 6;
return 0;
}
$ cc -O -c foo.c
$ objdump -S foo.o
foo.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 31 c0 xor %eax,%eax
2: c3 retq
$
通过一些简单的优化,编译器发现你没有使用变量&#39; b&#39;因此不需要计算它。因此,你不能使用变量&#39; a&#39;或者,所以没有必要分配它。只有没有优化的编译(或非常糟糕的编译器)才会在此处放置任何内容。即使您使用这些值,基本优化也会将它们放入寄存器中,因为触摸堆栈非常昂贵。