Could somebody please tell me what is the purpose of the two push ecx
instructions below? I can't understand what they are supposed to be doing?
I realise the push epb
is saving the stack base pointer and then mov epb, esp
is assigning the stack pointer to the previous stack base pointer.
int main(){
01301190 push ebp
01301191 mov ebp,esp
01301193 push ecx ;here??
01301194 mov dword ptr [h],0CCCCCCCCh
int h = my_func(1,3);
int my_func(int a, int b){
01301160 push ebp
01301161 mov ebp,esp
01301163 push ecx ;here??
01301164 mov dword ptr [m],0CCCCCCCCh
int m = 0;
0130116B mov dword ptr [m],0
m = a*b;
01301172 mov eax,dword ptr [a]
01301175 imul eax,dword ptr [b]
01301179 mov dword ptr [m],eax
return m;
0130117C mov eax,dword ptr [m]
}
0130117F mov esp,ebp
}
01301181 pop ebp
01301182 ret
The
push ecx
allocates 4 bytes on the stack for the local variable (m
andh
). The actual content ofecx
does not matter - the allocated slot is immediately overwritten by0CCCCCCCCh
(this magic value is used by Visual C++ in debug builds to mark uninitialized variables).Visual C++ often uses
push ecx
andpop ecx
as alternatives tosub esp, 4
andadd esp, 4
. Why? There are several reasons:push ecx
andpop ecx
are single-byte instructions, whileadd
andsub
are three byte each. The difference may not be huge, but all the saved bytes in all functions may add up to something substantial.ecx
is considered to be spoiled by a function call, so it's safe to trash it withpop ecx
after function calls. So you often see code like:For
push
, there's no real reason to useecx
specifically - any of the basic registers would do. I guess it was just picked for symmetry, or to not be confused with real saving of a non-volatile register likeesi
oredi
.It would be extremely instructive to see the definitions of
a
,b
, andm
in the assembly code above. I'm guessing they areebp+8
,ebp+12
, andebp-4
. If that is true, the compiler is not generating any special code for the debugger, it is just generating the code in the most straight-forward method. The location created on the stack by pushingecx
is the memory location created for the local variablem
.I assume you have optimizations turned off.
The compiler pushes ECX before calling the function. It does this because ECX is a volatile register and it wants to ensure its contents are restored when the function call is returned.
Inside the function it pushes ECX so that the debugger can easily read the arguments passed in to the function.
Disassembly of optimized code is usually easier to understand.
In debug mode, there may be a loop to fill local memory for variables with some special pattern, like 0CCCCCCCCh, and this loop normally uses ecx. In these cases, the loop isn't there. Looking at the code, the model is passing all arguments on the stack (as opposed to using ecx, edx for two of the parameters), so there's no real reason to be saving ecx. So the push ecx is just left over junk from the compiler, since it never uses ecx or "restores" ecx with a pop.