有人可以告诉我下面两条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
答案 0 :(得分:7)
push ecx
在堆栈上为局部变量(m
和h
)分配4个字节。 ecx
的实际内容无关紧要 - 分配的插槽会被0CCCCCCCCh
立即覆盖(Visual C ++在调试版本中使用此神奇值来标记未初始化的变量)。
Visual C ++经常使用push ecx
和pop ecx
作为sub esp, 4
和add esp, 4
的替代品。为什么?有几个原因:
push ecx
和pop ecx
是单字节指令,而add
和sub
各为3字节。差异可能不是很大,但所有功能中所有保存的字节可能会增加很多东西。
ecx
被认为会被函数调用破坏,因此在函数调用后将其与pop ecx
一起删除是安全的。所以你经常会看到如下代码:
push arg1 ; push an argument
call __func1 ; call the function
pop ecx ; restore the stack
对于push
,没有真正的理由专门使用ecx
- 任何基本寄存器都可以。我想它只是选择了对称性,或者不与实际保存非esi
或edi
等非易失性寄存器混淆。
答案 1 :(得分:1)
在上面的汇编代码中查看a
,b
和m
的定义非常有用。我猜他们是ebp+8
,ebp+12
和ebp-4
。如果这是真的,编译器不会为调试器生成任何特殊代码,它只是以最直接的方法生成代码。通过推送ecx
在堆栈上创建的位置是为局部变量m
创建的内存位置。
答案 2 :(得分:0)
我假设您已关闭优化功能。
编译器在调用函数之前推送ECX。这样做是因为ECX是一个易失性寄存器,它希望确保在返回函数调用时恢复其内容。
在函数内部推送ECX,以便调试器可以轻松读取传入函数的参数。
优化代码的反汇编通常更容易理解。
答案 3 :(得分:0)
在调试模式下,可能有一个循环用于填充本地内存以获取具有某些特殊模式的变量,如0CCCCCCCCh,并且此循环通常使用ecx。在这些情况下,循环不在那里。查看代码,模型传递堆栈上的所有参数(而不是使用ecx,edx作为两个参数),因此没有真正的理由保存ecx。所以push ecx只是遗留在编译器的垃圾上,因为它从不使用ecx或者#34;恢复" ecx有一个流行音乐。