C/C++反汇编-各种表达式(加减乘)
基于vs2019的反汇编
优化
对于vs来说一般的优化有两种方案:
O1:生成可执行文件空间小
O2:执行效率高
在vs2019中的release默认是采用的O2方案来处理也就是执行效率优先,而在debug版本中为了调试比较方便可能就会优化比较少。接下来的反汇编会在release和debug中两个分开呈现
常量传播
编译期间会将可计算结果的变量转化为常量来处理
比如int c = 1;
printf("%d\n",c);
这里会直接用1来替代c而不是在内存中进行读取
常量折叠
当几个常量进行计算的时候,编译器会直接将计算的结果来处理
int c=1+2-3;
会直接把c赋值为 0
加法
直接上代码
DEBUG下
//加法反汇编
//变量赋值
int Number1 = 0;
00C11DE8 mov dword ptr [Number1],0
int Number2 = 0;
00C11DEF mov dword ptr [Number2],0
//常量加常量
Number1 = 1 + 2;
00C11DF6 mov dword ptr [Number1],3
//常量加变量
Number1 = Number2 + 1;
00C11DFD mov eax,dword ptr [Number2]
00C11E00 add eax,1
00C11E03 mov dword ptr [Number1],eax
//变量加变量
Number1 = Number1 + Number2;
00C11E06 mov eax,dword ptr [Number1]
00C11E09 add eax,dword ptr [Number2]
00C11E0C mov dword ptr [Number1],eax
这里可以看到当两个常量相加的时候,编译器会直接计算值来处理而不是一个一个寄存器来读取,这样会直接减少运行量
Release下
//加法反汇编
//变量赋值
int Number1 = 0;
int Number2 = 0;
//常量加常量
Number1 = 1 + 2;
//常量加变量
Number1 = Number2 + 1;
//变量加变量
Number1 = Number1 + Number2;
这里直接没有了那么为什么呢?
因为这里采用了各种优化,在编译过程中,编译器通常会采用两种优化方式:常量传播和常量折叠来处理
这里可以采用对变量进行不是常量的赋值比如:
int Number = argc
argc是main函数中的第一个参数,需要输入才能识别,所以编译器不会将其折叠
减法
减法和加法类似,只是对于减法的处理是利用对补码的加法来处理。
乘法
由于乘法的周期比较长,所以编译器会优先考虑使用加法或者使用位移的方法来处理乘法
debug下:
//两常量相乘
printf("2 * 2 = %d\n", 2 * 2);
00BE43CC push offset string "2 * 2 = %d\n" (0BE7CD0h)
00BE43D1 call _main (0BE13C5h)
00BE43D6 add esp,8
//混和运算
printf("Number1*4+5=%d\n", Number1 * 4 + 5);
00BE43D9 mov eax,dword ptr [Number1]
00BE43DC lea ecx,[eax*4+5]
00BE43E3 push ecx
00BE43E4 push offset string "Number1*4+5=%d\n" (0BE7CDCh)
00BE43E9 call _main (0BE13C5h)
00BE43EE add esp,8
printf("Number1*9+5=%d\n", Number1 * 9 + 5);
00BE43F1 imul eax,dword ptr [Number1],9
00BE43F5 add eax,5
00BE43F8 push eax
00BE43F9 push offset string "Number1*9+5=%d\n" (0BE7CECh)
00BE43FE call _main (0BE13C5h)
00BE4403 add esp,8
//两个变量相乘
printf("Number1*Number2=%d\n",Number1*Number2);
00BE4406 mov eax,dword ptr [Number1]
00BE4409 imul eax,dword ptr [Number2]
00BE440D push eax
00BE440E push offset string "Number1*Number2=%d\n" (0BE7E20h)
00BE4413 call _main (0BE13C5h)
00BE4418 add esp,8
在release下的情况:
//处理不是2的倍数的乘数作为乘法时
printf("Number1*15=%d\n", Number1 * 15);
00A31044 mov esi,dword ptr [argc]
00A31047 mov eax,esi
00A31049 shl eax,4
00A3104C sub eax,esi
00A3104E push eax
00A3104F push offset string "Number1*15=%d\n" (0A32100h)
00A31054 call printf (0A31010h)
//处理以2为倍数的乘法作为乘法时
printf("Number1*16=%d\n", Number1 * 16);
00A31059 mov eax,esi
00A3105B shl eax,4
00A3105E push eax
00A3105F push offset string "Number1*16=%d\n" (0A32110h)
00A31064 call printf (0A31010h)
//两常量相乘
printf("2 * 2 = %d\n", 2 * 2);
00A31069 push 4
00A3106B push offset string "2 * 2 = %d\n" (0A32120h)
00A31070 call printf (0A31010h)
//混和运算
printf("Number1*4+5=%d\n", Number1 * 4 + 5);
00A31075 lea eax,[esi*4+5]
00A3107C push eax
00A3107D push offset string "Number1*4+5=%d\n" (0A3212Ch)
00A31082 call printf (0A31010h)
printf("Number1*9+5=%d\n", Number1 * 9 + 5);
00A31087 lea eax,[esi*8+5]
00A3108E add eax,esi
00A31090 push eax
00A31091 push offset string "Number1*9+5=%d\n" (0A3213Ch)
00A31096 call printf (0A31010h)
//两个变量相乘
printf("Number1*Number2=%d\n",Number1*Number2);
00A3109B imul esi,esi
00A3109E push esi
00A3109F push offset string "Number1*Number2=%d\n" (0A3214Ch)
00A310A4 call printf (0A31010h)
00A310A9 add esp,30h