我正在自学编译器是如何工作的。我正在通过阅读反汇编来学习GCC从小型 64 位 Linux 程序生成代码。
我写了这个C程序:
#include <stdio.h>
int main()
{
for(int i=0;i<10;i++){
int k=0;
}
}
使用 objdump 后我得到:
00000000004004d6 <main>:
4004d6: 55 push rbp
4004d7: 48 89 e5 mov rbp,rsp
4004da: c7 45 f8 00 00 00 00 mov DWORD PTR [rbp-0x8],0x0
4004e1: eb 0b jmp 4004ee <main+0x18>
4004e3: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
4004ea: 83 45 f8 01 add DWORD PTR [rbp-0x8],0x1
4004ee: 83 7d f8 09 cmp DWORD PTR [rbp-0x8],0x9
4004f2: 7e ef jle 4004e3 <main+0xd>
4004f4: b8 00 00 00 00 mov eax,0x0
4004f9: 5d pop rbp
4004fa: c3 ret
4004fb: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
现在我有一些疑问。
那是什么NOP在最后,为什么它在那里? (结盟?)
我正在编译gcc -Wall <program.c>
。为什么我没有收到警告control reaches end of non-void function
?
-
为什么编译器不在堆栈上分配空间sub rsp,0x10
?为什么不使用rbp
寄存器用于引用本地堆栈数据?
PS:如果我调用一个函数(比如printf
) 在里面for
循环,为什么编译器突然生成sub rsp,0x10
?为什么它仍然引用本地数据rsp
登记。我希望生成的代码能够引用本地堆栈数据rbp
!
关于第二个问题,既然C99标准允许没有明确的return 0
in the main
函数,编译器会隐式添加它。请注意,这仅适用于main
功能,没有其他功能。
至于第三个问题,rbp
寄存器充当帧指针 https://en.wikipedia.org/wiki/Call_stack#FRAME-POINTER.
最后是PS。被调用的函数很可能正在使用16
bytes (0x10
) 作为传递给函数的参数。减法就是从堆栈中“删除”这些变量。它可能是作为参数传递的两个指针吗?
如果您正在认真学习编译器的一般工作原理,并且可能想创建自己的编译器(这很有趣!:)),那么我建议您投资一些有关其理论和实践的书籍。龙之书 https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools是任何程序员书架上的绝佳补充。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)