我一直在拆解一些可执行文件来学习汇编语言。我用GCC和Visual Studio编译了一个非常简单的程序,并注意到传递参数的一个奇怪的区别。
(cdecl)int some_function(int, int)
VS
mov eax, [ebp+8]
push eax
mov ecx, [ebp+4]
push ecx
call some_function
GCC
mov eax, [ebp+8]
mov [esp+4], eax
mov eax, [ebp+4]
mov [esp], eax
call some_function
为什么GCC使用mov
代替push
?
编辑:这是原始程序供参考。
int some_function(int a, int b) {
return a + b;
}
int main(void) {
int a = 1, b = 2;
printf("string %d\n", some_function(a, b));
}
答案 0 :(得分:0)
因为 gcc
的这个版本在堆栈中为局部变量和在函数序言中传递给被调用者的参数分配内存。
Visual C
编译器仅对局部变量执行此操作,并将callee的参数推送到堆栈中。
这是一种依赖于语言实现的行为。 gcc的方法允许在评估被调用者的参数时进行更好的优化:编译器可以重新排序评估,而不记住特定被调用者参数的空间尚未分配。
答案 1 :(得分:0)
有些编译器使用esp
作为基指针
如果要使用push
esp
会改变。不断变化的基指针会使它的使用复杂化; ESP。在循环中。
通过使用mov [esp+x],reg
代替push
,编译器仍然可以推送'参数,同时保持esp
可用作基指针。
虽然付出了代价。现代CPU有一个堆栈引擎
通过不使用push
,编译器可以绕过堆栈引擎及其优点。