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