Log in

View Full Version : sub esp, 40h


true_ruf
December 12th, 2006, 14:22
Im courious, why does the Visual C++ compiler leave this space in the stack in the prolog of a function even when no local variables are declared?

btw, 40h comes from __LOCAL_SIZE. From the msdn:

"Its value is the total number of bytes of all user-defined locals as well as compiler-generated temporary variables."

Anyone knows what are the compiler-generated temporary variables and why are they used?

reverser
December 12th, 2006, 17:21
Would you give an example of the stack reservation "even when no local variables are declared"? I don't think I've ever seen that.
As for "compiler-generated variables", SEH stackframe comes to mind. However it's not allocated by reserving space but rather by directly pushing the values.

Maximus
December 12th, 2006, 18:27
C++ compilers generate alot of temporary variables, usually 'hidden' and not seen unless you know the evil of C++.
they are:
temporary objects created using = operator.
temporary objects created by implicit constructor.
temporary objects created by implicit conversions.

i.e. temporaries created when you pass to a function a variable in an unexpected format.

I can ensure you that many programmers do not 'see' them, and the C++ compilers usually perform alot of garbage operations 'behind' programmer's shoulders. One of the reasons for declaring a dummy = operator in each class is to avoid such automatic conversions (the default assignment perform a memory copy, and can be really dangerous sometime).
By the way, one of the reason I prefer Pascal to C++ (C is ok, as it is more "WYSWYG" than C++).

true_ruf
December 14th, 2006, 13:17
Im talking about this:

Code:

void main()
{
}


Is translated into:

Code:

00411960 55 push ebp
00411961 8B EC mov ebp,esp
00411963 83 EC 40 sub esp,40h
00411966 53 push ebx
00411967 56 push esi
00411968 57 push edi
00411969 33 C0 xor eax,eax
0041196B 5F pop edi
0041196C 5E pop esi
0041196D 5B pop ebx
0041196E 8B E5 mov esp,ebp
00411970 5D pop ebp
00411971 C3 ret


Exceptions and Run type checks are disabled.

Declaring an integer variable inside main, increases stack for locals to 44h, that is, in 4 the size of an integer.

Maximus
December 14th, 2006, 15:21
Oh, you're referring to _that.
It's normal issue.
Even GCC does this (or at least it did). I guess it is related to the default stub included by the compiler in main(). Check out your optimization flags, but I guess you can little about... same for the useless push sequence, I suppose.

However, about GCC we discussed upon the Stack-alignment instruction possibility (which is not this case, would be something like and ESP,xxx00), don't remember.

LLXX
December 14th, 2006, 18:33
Compilers are stupid. Also, GCC is more so than MSVCPP (which would've emitted a single ret for that empty function above).

Let's just leave it at that...

Code:
...
mov [esp+12], eax ; nothing jumps between this line
mov eax, [esp+12] ; and this line
...


Edit: What version of the compiler are you using? I just tested that empty main() with the "Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86" and indeed it did emit a single "ret" (followed by 15 NOPs which I haven't figured out how to eliminate...)
Code:
"empty.c"
main() { }

Code:
"compile options"
cl /c /Ox /MD empty.c

Code:
"link options"
link /entry:main /subsystem:windows /align:4096 /merge:.text=.rdata empty.obj ..\lib\msvcrt.lib

true_ruf
December 22nd, 2006, 10:24
Quote:
[Originally Posted by LLXX;63151]
Edit: What version of the compiler are you using? I just tested that empty main() with the "Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86" and indeed it did emit a single "ret" (followed by 15 NOPs which I haven't figured out how to eliminate...)


I was compiling in debug version, but anyway i dont know why the compiler leaves 40h space in the stack.

ZaiRoN
December 22nd, 2006, 14:25
Here is what I get compiling your empty main in debug mode:
Code:
00401010 PUSH EBP
00401011 MOV EBP,ESP
00401013 XOR EAX,EAX
00401015 POP EBP
00401016 RETN
To obtain the code above I setted the option "Debug information format" to something that is not "Program database for edit & continue". Seems like the 0x40 bytes problem is related with this flag.
Visual C++ compiler puzzles me everytime I have to deal with it, I don't know all the exact meaning of each parameters so it's better for you to look around msdn; you'll surely find out something

LLXX
December 22nd, 2006, 18:28
ZaiRoN, what version of VC++ is that?

I used VC'98 and it doesn't put a "xor eax, eax" in there.

If you want to know about the compiler options run "cl /?" at a command prompt in the bin directory.

ZaiRoN
December 23rd, 2006, 09:03
LLXX, VC++ .net

true_ruf
December 26th, 2006, 05:19
ZaiRoN you were right, these 40h bytes are used only if "Program Database for Edit & Continue (/ZI)" is enabled. Btw it is enabled by default when you compile from the IDE in Debug mode.

The mystery: The space is reserved so you can declare new local variables during debug without restarting. But you can only declare 64 bytes (40h) of new local variables.

From MSDN:

"In some cases, Edit and Continue cannot apply code changes to the executable immediately, but may be able to apply the code changes later if you continue debugging. This occurs if you edit a function that calls the current function or if you add more than 64 bytes of new variables to a function on the call stack."

Thx to everybody who tried to answer my question.

laola
December 31st, 2006, 15:18
Quote:
[Originally Posted by LLXX;63151]Edit: What version of the compiler are you using? I just tested that empty main() with the "Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86" and indeed it did emit a single "ret" (followed by 15 NOPs which I haven't figured out how to eliminate...)


The 15 NOPs are due to the 16 byte (1 paragraph) alignment that the compiler uses to enhance cache performance on newer CPUs. Each function gets aligned to the start of a paragraph, and the compiler fills in NOPs to align the start of the next function properly. Off top of my head I don't know how to change that, it's probably hardcoded