我试图找到从c程序生成的汇编代码的含义。这是C中的程序:
int* a = &argc;
int b = 8;
a = &b;
以下是使用说明生成的汇编代码。有一部分我不明白:
主要序言:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $36, %esp
在%eax中加载argc的地址:
movl %ecx, %eax
我没有得到的部分:
movl 4(%eax), %edx
movl %edx, -28(%ebp)
Stack-Smashing Protector代码(设置):
movl %gs:20, %ecx
movl %ecx, -12(%ebp)
xorl %ecx, %ecx
在a和b中加载值(参见main.c):
movl %eax, -16(%ebp)
movl $8, -20(%ebp)
修改a(a =& b)的值:
leal -20(%ebp), %eax
movl %eax, -16(%ebp)
Stack-Smashing Protector代码(验证堆栈是否正常):
movl $0, %eax
movl -12(%ebp), %edx
xorl %gs:20, %edx
je .L7
call __stack_chk_fail
如果堆栈是Ok:
.L7:
addl $36, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
所以我不理解的部分是修改-28(%ebp)中的值,这是一个从未使用过的地址。有人知道为什么会生成这个部分吗?
答案 0 :(得分:6)
查看编译器功能的好方法。我假设你有一个名为main.c的文件:
int main(int argc, char **argv)
{
int* a = &argc;
int b = 8;
a = &b;
}
使用调试信息编译到目标文件:
$ gcc -c -g main.c
查看程序集:
$ objdump -S main.o
main.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
int main(int argc, char **argv)
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d ec mov %edi,-0x14(%rbp)
7: 48 89 75 e0 mov %rsi,-0x20(%rbp)
int* a = &argc;
b: 48 8d 45 ec lea -0x14(%rbp),%rax
f: 48 89 45 f8 mov %rax,-0x8(%rbp)
int b = 8;
13: c7 45 f4 08 00 00 00 movl $0x8,-0xc(%rbp)
a = &b;
1a: 48 8d 45 f4 lea -0xc(%rbp),%rax
1e: 48 89 45 f8 mov %rax,-0x8(%rbp)
22: b8 00 00 00 00 mov $0x0,%eax
}
27: 5d pop %rbp
28: c3 retq
然后对完全优化做同样的事情:
$ gcc -c -g -O3 main.c
再次查看程序集:
$ objdump -S main.o
main.o: file format elf64-x86-64
Disassembly of section .text.startup:
0000000000000000 <main>:
int main(int argc, char **argv)
{
int* a = &argc;
int b = 8;
a = &b;
}
0: 31 c0 xor %eax,%eax
2: c3 retq
所以答案是肯定的。编译器可以生成不需要的指令。这就是你打开优化的原因。当它们被关闭时,编译器会以一种非常通用的方式完成它的工作而不用考虑。例如,它为未使用的变量保留空间。