6

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  
user997112
  • 29,025
  • 43
  • 182
  • 361

4 Answers4

11

The push ecx allocates 4 bytes on the stack for the local variable (m and h). The actual content of ecx does not matter - the allocated slot is immediately overwritten by 0CCCCCCCCh (this magic value is used by Visual C++ in debug builds to mark uninitialized variables).

Visual C++ often uses push ecx and pop ecx as alternatives to sub esp, 4 and add esp, 4. Why? There are several reasons:

push ecx and pop ecx are single-byte instructions, while add and sub 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 with pop ecx after function calls. So you often see code like:

  push arg1    ; push an argument
  call __func1 ; call the function
  pop ecx      ; restore the stack

For push, there's no real reason to use ecx 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 like esi or edi.

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
1

It would be extremely instructive to see the definitions of a, b, and m in the assembly code above. I'm guessing they are ebp+8, ebp+12, and ebp-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 pushing ecx is the memory location created for the local variable m.

Dwayne Towell
  • 8,154
  • 4
  • 36
  • 49
  • they are the local variables of the c++ function,including two parameters? – user997112 Mar 12 '14 at 06:04
  • Right, but `mov eax,dword ptr [a]` is not a literal 80x86 instruction. The `a` has to be replaced by something like `ebp+8`. There should be somewhere in the code a line something like `a equ ebp+8` which defines `a`. – Dwayne Towell Mar 12 '14 at 15:06
0

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.

thisisdog
  • 908
  • 1
  • 5
  • 13
  • 1
    Unless you use `gcc`'s insane optimisation level `-O3`. Then your chance of understanding it is greatly reduced :-) – paxdiablo Mar 12 '14 at 03:03
  • ECX is different from the other registers? I only saw on wikipedia that its usually used for loop counting. – user997112 Mar 12 '14 at 03:20
  • There are other volatile registers, for example EAX and EDX. ECX is special in that it's used for the first integral argument to the function, which in your case is a, but is often the this pointer – thisisdog Mar 12 '14 at 03:22
  • 1
    There's no calls of any functions inside `my_func`. Also, `ECX` is used as an argument only for `__thiscall` or `__fastcall` functions, which is not the case here. All arguments are passed on the stack in the pasted code. – Igor Skochinsky Mar 12 '14 at 12:25
0

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.

rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • mayi ask what is this 0CCCCCCCCh? – user997112 Mar 12 '14 at 06:04
  • @user997112 http://stackoverflow.com/questions/370195/when-and-why-will-an-os-initialise-memory-to-0xcd-0xdd-etc-on-malloc-free-new – phuclv Mar 12 '14 at 07:44
  • The 0CCCCCCCCh is mostly used to check for unitialized pointers, if you use a pointer with that value, it should cause an exception. – rcgldr Mar 12 '14 at 09:36