为什么我有PUSH ecx?

时间:2014-03-12 02:53:56

标签: assembly x86

有人可以告诉我下面两条push ecx说明的目的是什么?我无法理解他们应该做什么?

我意识到push epb正在保存堆栈基指针,然后mov epb, esp将堆栈指针分配给前一个堆栈基指针。

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  

4 个答案:

答案 0 :(得分:7)

push ecx在堆栈上为局部变量(mh)分配4个字节。 ecx的实际内容无关紧要 - 分配的插槽会被0CCCCCCCCh立即覆盖(Visual C ++在调试版本中使用此神奇值来标记未初始化的变量)。

Visual C ++经常使用push ecxpop ecx作为sub esp, 4add esp, 4的替代品。为什么?有几个原因:

push ecxpop ecx是单字节指令,而addsub各为3字节。差异可能不是很大,但所有功能中所有保存的字节可能会增加很多东西。

ecx被认为会被函数调用破坏,因此在函数调用后将其与pop ecx一起删除是安全的。所以你经常会看到如下代码:

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

对于push,没有真正的理由专门使用ecx - 任何基本寄存器都可以。我想它只是选择了对称性,或者不与实际保存非esiedi等非易失性寄存器混淆。

答案 1 :(得分:1)

在上面的汇编代码中查看abm的定义非常有用。我猜他们是ebp+8ebp+12ebp-4。如果这是真的,编译器不会为调试器生成任何特殊代码,它只是以最直接的方法生成代码。通过推送ecx在堆栈上创建的位置是为局部变量m创建的内存位置。

答案 2 :(得分:0)

我假设您已关闭优化功能。

编译器在调用函数之前推送ECX。这样做是因为ECX是一个易失性寄存器,它希望确保在返回函数调用时恢复其内容。

在函数内部推送ECX,以便调试器可以轻松读取传入函数的参数。

优化代码的反汇编通常更容易理解。

答案 3 :(得分:0)

在调试模式下,可能有一个循环用于填充本地内存以获取具有某些特殊模式的变量,如0CCCCCCCCh,并且此循环通常使用ecx。在这些情况下,循环不在那里。查看代码,模型传递堆栈上的所有参数(而不是使用ecx,edx作为两个参数),因此没有真正的理由保存ecx。所以push ecx只是遗留在编译器的垃圾上,因为它从不使用ecx或者#34;恢复" ecx有一个流行音乐。