I'm self-studying how compilers works. I'm learning by reading the disassembly of GCC generated code from small 64-bit Linux programs.
I wrote this C program:
#include <stdio.h> int main() { for(int i=0;i<10;i++){ int k=0; } } After using objdump I get:
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] Now I have some doubts.
What is that NOP at the end for, and why is it there? (alignment?)
I'm compiling with
gcc -Wall <program.c>. Why am I not getting the warningcontrol reaches end of non-void function?Why doesn't the compiler allocate space on the stack with
sub rsp,0x10? Why doesn't it use therbpregister for referencing local stack data?PS: If I call a function (like
printf) in theforloop, why does the compiler suddenly generatesub rsp,0x10? Why does it still references local data with therspregister. I expect the generated code to reference local stack data withrbp!
testfunction the compiler subtract 16 bytes although less is needed is related to 64-bit Linux ABI requirement that at the point of any function call (like callingtest) the stack needs to be 16 (and possibly 32-byte aligned). Since the stack is aligned at the point of the call, the CALL itself pushes 8 byte return address. That misaligns the stack by 8. Thepush rbpsubtracts another 8 which makes it 16 byte aligned again. Now you need local variable data. Compilers usually allocate enough bytes to maintain the 16-byte alignmenttestthe stack remains 16-byte aligned and all is good..