Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do programs know how much space to allocate for local variables on the stack?

In this simple function, space is allocated for local variables. Then, variables are initialized and printf is called to output them.

000000000040056a <func>:
  40056a:       55                      push   rbp ; function prologue
  40056b:       48 89 e5                mov    rbp,rsp  ; function prologue
  40056e:       48 83 ec 10             sub    rsp,0x10 ; deallocating space for local variables
  400572:       8b 4d fc                mov    ecx,DWORD PTR [rbp-0x4] ; variable initialization
  400575:       8b 55 f8                mov    edx,DWORD PTR [rbp-0x8] ; variable initialization
  400578:       8b 45 f4                mov    eax,DWORD PTR [rbp-0xc] ; variable initialization
  40057b:       89 c6                   mov    esi,eax ; string stuff
  40057d:       bf 34 06 40 00          mov    edi,0x400634 ; string stuff
  400582:       b8 00 00 00 00          mov    eax,0x0 ; return value 
  400587:       e8 84 fe ff ff          call   400410 <printf@plt> ; printf()
  40058c:       c9                      leave  ; clean up local variables, pops ebp
  40058d:       c3                      ret  ; return to the address that was pushed onto the stack (by popping it into eip)

What confuses me is this line sub rsp,0x10. How does the program know to allocate 0x10 bytes? Is it a guess? Is the program parsed before hand?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The compiler knows because it looked at the source code (or actually its internal representation of the logic after parsing it) and added up the total size needed for all the things that it had to allocate stack space for. And also it has to get RSP 16-byte aligned before the call, given that RSP % 16 == 8 on function entry.

So alignment is one reason compilers may reserve more than the function actually uses, but also compiler missed-optimization bugs can make it waste space: common for GCC to waste an extra 16 bytes, although that’s not happening here.

Yes, modern compilers parse the entire function (actually whole source file) before emitting any code for it. That’s kind of the point of an ahead-of-time optimizing compiler, so it’s designed around doing that, even if you make a debug build. By comparison, TCC, the Tiny C Compiler, is one-pass, and leaves a spot in its function prologue to go back later and fill in whatever total size after getting to the bottom of the function in the source code. See Tiny C Compiler's generated code emits extra (unnecessary?) NOPs and JMPs – when that number happens to be zero, there’s still a sub esp, 0 there. (TCC only targets 32-bit mode.)

Related: Function Prologue and Epilogue in C


Note that in 64-bit code, leave pops RBP, not EBP, and that ret pops into RIP, not EIP.

Also, mov ecx,DWORD PTR [rbp-0x4] is not variable initialization. That’s a load, from uninitialized memory into a register. Probably you did something like int a,b,c; without initializers, then passed them as args to printf.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading