In an earlier article, we have seen & . Here we will see "How C program converts into the assembly?" and different aspect of its working at the machine level. C runtime: before starting main How C program stored in RAM memory /!\: Originally published @ . www.vishalchovatiya.com A bit about function stack frames During function code execution, a new stack frame is created in stack memory to allow access to function parameters and local variables. The direction of stack frame growth totally depends on compiler ABI which is out of our scope for this article. The complete information on stack frame size, memory allocation, returning from stack frame is decided at compile time. Before diving into assembly code you should be aware of two things : CPU registers of x86 machine. x86 assembly instructions: As this is a very vast topic & updating quite frequently, we will only see the instructions needed for our examples. x86 CPU Registers General Purpose Registers Pointer Register Segment Register Index Registers Apart from all these, there are many other registers as well which even I don't know about. But above-mentioned registers are sufficient to understand the subsequent topics. How C program converts into assembly? We will consider the following example with its disassembly inlined to understand its different aspect of its working at machine level : We will focus on a stack frame of the function . But before analysing stack frame of it, we will see how the calling of function happens func() Function calling Function calling is done by call instruction(see Line 15) which is subroutine instruction equivalent to: push rip + 1 ; return address is address of next instructions jmp func Here, store the (not that +1 is just for simplicity, technically this will be substituted by the size of instruction) in the stack which is return address once call to ends. call rip+1 func() Function stack frame A function stack frame is divided into three parts /Entry Prologue User code /Exit Epilogue As you can see instructions(line 2 to 4) generated against start bracket is prologue which is setting up the stack frame for , Line 2 is pushing the previous frame pointer into the stack & Line 3 is updating the current frame pointer with stack end which is going to be a new frame start. 1. Prologue/Entry: { func() is basically equivalent to : push sub esp, 4 ; decrements ESP by 4 which is kind of space allocation mov [esp], X ; put new stack item value X in Parameter passing Argument of is stored in register on Line 14 before calling instruction. If there is more argument then it will be stored in a subsequent register or stack & address will be used. func() edi call Line 4 in is reserving space by pulling frame pointer(pointed by register) down by 4 bytes for the parameter as it is of type . Then instruction will initialize it with value store in . This is how parameters are passed & stored in the current stack frame. func() rbp arg int mov edi ---|-------------------------|--- main() | | | | | | |-------------------------| | main frame pointer | rbp & rsp ---|-------------------------|--- func() in func() | arg | |-------------------------| | a | |-------------------------| stack | + | | | + | | | + | | ---|-------------------------|--- \|/ | | | | Allocating space for local variables Line 5 is reserving space for a local variable , again by pulling frame pointer further down by 4 bytes. instruction will initialize that memory with a value . 2. User code: a mov 5 Accessing global & local static variables As you can see above, is addressed directly with its absolute addressing because its address is fixed which lies in the data segment. g This is not the case all the time. Here we have compiled our code for x86 mode, that’s why it is accessing it with an absolute address. In the case of x64 mode, the address is resolved using register which meant that the assembler and linker should cooperate to compute the offset of from the ultimate location of the current instruction which is pointed by register. rip g rip The same statement stands true for the local static variables also. After the user code execution, the previous frame pointer is retrieved from the stack by instruction which we have stored in Line 2. is equivalent to: 3. Epilogue/Exit: pop pop mov X, [esp] ; put top stack item value into X add esp, 4 ; increments ESP by 4 which is kind of deallocation from function Return instruction jumps back to the next instruction from where called by retrieving the jump address from stack stored by instruction. is subroutine instruction which is equivalent to: ret func() call ret pop rip ; jmp rip ; If any return value specified then it will be stored in register which you can see in Line 16. eax So, this is it for “How C program converts into assembly?”. Although this kind of information is strictly coupled with compiler & ABI. But most of the compilers, ABI & instruction set architecture follows the same more or less. In case, you have not gone through , here are simple FAQs helps you to understand better: my previous articles Intuitive FAQs Q. How do you determine the stack growth direction ? Simple…! by comparing the address of two different function’s local variables. A. *main_ptr = ; *func_ptr = ; { a; func_ptr = &a; } { a; main_ptr = &a; func(); (main_ptr > func_ptr) ? ( ) : ( ); ; } int NULL int NULL void func () int int main () int printf "DOWN\n" printf "UP\n" return 0 Q. How do you corrupt stack deliberately ? Corrupt the SFR values stored in the stack frame. A. { a; (&a, , ); } { func(); ; } void func () int memset 0 100 // Corrupt SFR values stored in stack frame int main () return 0 Q. How you can increase stack frame size ? is the answer. Google about it or see . Although this is not recommended. A. alloca() this