VC++代码是最接近汇编指令的高级语言,为了更加准确和深刻理解VC++编码中所涉及的很多技术概念和编译器参数的含义,从汇编指令层面进行剖析和解读,有助于开发者更加准确、直观、深刻理解高级语言中很多概念和技术的真正含义,对程序优化和编码都有非常实用的重要价值。由于内容很多,我会分解为很多篇章进行解读实例。
从main入口开始分析,使用古老的VC6.0编译器编译,先从最简单的例子开始逐步扩展,便于大家逐步入门。
VC++源代码:
int main(int argc, char* argv[])
{
printf("Hello World!\n");
return 0;
}
最简单不过的代码了,看看汇编代码是什么呢?关于32位X86寄存器的基础知识,大家可以自己先上网看啦。
debug状态下无优化的汇编代码:
int main(int argc, char* argv[])
20: {
00401030 55 push ebp ==保存EBP
00401031 8B EC mov ebp,esp ==保存ESP
00401033 83 EC 40 sub esp,40h ==没有定义任何临时变量的情况下,默认预留64字节的栈内存空间
00401036 53 push ebx ==保存EBX
00401037 56 push esi ==保存ESI
00401038 57 push edi ==保存edi
00401039 8D 7D C0 lea edi,[ebp-40h] ==将栈顶地址放入EDI中
0040103C B9 10 00 00 00 mov ecx,10h ==计数器16放入ECX
00401041 B8 CC CC CC CC mov eax,0CCCCCCCCh ===初始值为指向INT3地址
00401046 F3 AB rep stos dword ptr [edi] ===初始化16个DWORD的栈空间
26: printf("Hello World!\n");
00401048 68 1C 20 42 00 push offset string "Hello World!\n" (0042201c) ==将字符串参数地址入栈
0040104D E8 EE 00 00 00 call printf (00401140) ==调用函数
00401052 83 C4 04 add esp,4 ==恢复ESP
27: return 0;
00401055 33 C0 xor eax,eax ==EAX清零
28: }
00401057 5F pop edi ==恢复EDI
00401058 5E pop esi ==恢复ESI
00401059 5B pop ebx ==恢复EBX
0040105A 83 C4 40 add esp,40h ==恢复ESP
0040105D 3B EC cmp ebp,esp ==检查ESP和EBP
0040105F E8 5C 01 00 00 call __chkesp (004011c0) ==比较检查结果,若不相等会抛出异常
00401064 8B E5 mov esp,ebp ==恢复esp
00401066 5D pop ebp ==恢复ebp
00401067 C3 ret
总结:上面汇编指令序列的模式实际是典型的函数调用过程,简单来说就是保存堆栈指针,保存寄存器,根据临时变量的声明,开辟堆栈空间并初始化,压栈传参,调用函数,恢复寄存器,恢复堆栈指针,退出程序。
下一篇,我会在程序中增加更多内容,展示相应的汇编代码底层实现过程。