今天闲来无事写了一段代码:
int Func1(int x,int y){
return (x&y)+((x^y)>>1);
}
void main(){
int Array[] = {1,2,3,4,5};
int *ptr = Array;
int c = Func1(*ptr,*(++ptr));
printf("%d\n",c);
}
原本预想输出结果应该为1,谁知竟然为2,百思不得姐之后,就调试了下进入反汇编查看其中奥妙:
55: int Array[] = {1,2,3,4,5};
00401088 mov dword ptr [ebp-14h],1
0040108F mov dword ptr [ebp-10h],2
00401096 mov dword ptr [ebp-0Ch],3
0040109D mov dword ptr [ebp-8],4
004010A4 mov dword ptr [ebp-4],5
这个过程就不用解释了,预先计算数组大小,数组按内存地址从低位到高位分配,接下来:
56: int *ptr = Array;
004010AB lea eax,[ebp-14h]
004010AE mov dword ptr [ebp-18h],eax
注意mov和lea的区别,如果你认为lea eax,[ebp-18h]是将内存地址为ebp-14h中的内容赋给eax那就错了,lea只是将内存地址赋给eax,也就是此时eax的内容是ebp-14h。对于指令mov eax,[ebp-14h]自然是将内存中的地址压入eax。说到这里就啰嗦一下,mov的右值必须为常量不能为表达式,如,
可以写MOV EAX, EBP,但不能写MOV EAX, EBP + 8
这是因为EBP + 8本身也需要一条指令来计算,所以不能跟MOV写在一条指令里。但是汇编指令中内存地址符可以做算术运算,所以对于指令MOV EAX, [EBP + 8]完全是合法的。接下来继续跟下一条指令:
57: int c = Func1(*ptr,*(++ptr));
004010B1 mov ecx,dword ptr [ebp-18h] //ecx赋值为ebp-14h
004010B4 add ecx,4 //ecx值为ebp-10h,指向Array[1]
004010B7 mov dword ptr [ebp-18h],ecx
004010BA mov edx,dword ptr [ebp-18h]
004010BD mov eax,dword ptr [edx] //Array[1]压入eax
004010BF push eax //2
004010C0 mov ecx,dword ptr [ebp-18h]
004010C3 mov edx,dword ptr [ecx] //ecx值为ebp-10h,指向Array[1]
004010C5 push edx //2
004010C6 call @ILT+0(Func1) (00401005)
004010CB add esp,8
004010CE mov dword ptr [ebp-1Ch],eax
根据以上指令我们可以判断该函数参数的入栈顺序为从右至左,所以先执行了++ptr指令,我们继续往下跟:
58: printf("%d\n",c);
004010D1 mov eax,dword ptr [ebp-1Ch]
004010D4 push eax
004010D5 push offset string "%d\n" (0043101c)
004010DA call printf (004081f0)
004010DF add esp,8
很明显,ebp-1Ch为局部变量c的地址,在printf中居然也是先将c压栈,然后才是那一串格式控制字符串,这个平时居然没有注意,那么对于以下代码该输出多少呢?int i=0;printf("%d,%d,%d",++i,i,--i);输出该是0,-1,-1,而不是想当然的1,1,0。这个问题可以继续深入的探讨下去,通过查阅资料,得到如下结论:
1. 参数入栈顺序是和具体 编译器实现相关的。比如,Pascal语言中参数就是从左到右入栈的,有些语言中还可以通过修饰符进行指定,如Visual C++。
2. Pascal语言不支持可变长参数,而C语言支持这种特色,正是这个原 因使得C语言函数参数入栈顺序为从右至左。具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。
3. 这里面还牵涉到一个新的问题:标准调用_stdcall和C调用_cdecl,这两种调用方式可等到以后用到时在仔细区别。
最后,对于Func1函数的功能做个说明,这是个面试据说会考到的问题,它的作用是求两输入参数的平均值。
完-----------------------------^o^