一段求数字%2模代码的反汇编
这是一段简单的代码,就一个数是否为奇偶的片段
1 int main() 2 { 3 int num ; 4 scanf("%d",&num); 5 num = num % 2; // 这里求%2的模 6 printf("%d",num); 7 return 0; 8 }
反汇编代码如下:
.text:00401000 _main proc near ; CODE XREF: start+AFp .text:00401000 .text:00401000 var_4 = dword ptr -4 .text:00401000 .text:00401000 push ecx .text:00401001 lea eax, [esp+4+var_4] .text:00401005 push eax .text:00401006 push offset Format ; "%d" .text:0040100B call _scanf .text:00401010 mov eax, [esp+0Ch+var_4] .text:00401014 and eax, 80000001h .text:00401019 jns short loc_401020 .text:0040101B dec eax .text:0040101C or eax, 0FFFFFFFEh .text:0040101F inc eax .text:00401020 .text:00401020 loc_401020: ; CODE XREF: _main+19j .text:00401020 push eax .text:00401021 push offset Format ; "%d" .text:00401026 mov [esp+14h+var_4], eax .text:0040102A call sub_401040 .text:0040102F xor eax, eax .text:00401031 add esp, 14h .text:00401034 retn .text:00401034 _main endp
其中主要代码为:
.text:00401010 mov eax, [esp+0Ch+var_4]
.text:00401014 and eax, 80000001h
.text:00401019 jns short loc_401020
.text:0040101B dec eax
.text:0040101C or eax, 0FFFFFFFEh
.text:0040101F inc eax
首先:
1、因为有符号的数对2求模,只能有三种结果 -1 、0 、1;
2、编译器进行优化,and eax,80000001h 后,无论数字为多少,只会保留最高位和最低位。如果数字为奇数,最低位必然为1,同理,富豪为也会被保留下来
3、在通过jns short loc_401020进行判断符号位,符号位1(为负数),不跳转;符号位0(为正数),跳转。
4、对负数进行特殊处理,因为负数在内存中以补码的形式存放,就要讲第2步得出的结果进行修正,修正为补码形式,就是
dec eax
or eax, 0FFFFFFFEh
inc eax
举例1:经过第2步的出的结果为-1,即 1000 0001 ,当然,这个不是补码形式,就要把它换为补码形式( 1111 1111)
进行减1,1000 0000 ;然后同 0FFFF FFFEh进行位或运算,结果为1111 1110 ,所以,再加上一个1 ,即 1111 1111
举例2:经过第2步的出的结果为-0,即 1000 0000 ,当然,这个不是补码形式,就要把它换为补码形式( 1111 1111)
进行减1,0111 1111 ;然后同 0FFFF FFFEh进行位或运算,结果为1111 1111 ,所以,再加上一个1 ,即 0000 0000
下面是求一个数 %3的模代码
int main() { int num ; scanf("%d",&num); num = num % 3; printf("%d",num); return 0; }
反汇编代码如下:
00401000 /$ 51 push ecx 00401001 |. 8D4424 00 lea eax,dword ptr ss:[esp] 00401005 |. 50 push eax 00401006 |. 68 30804000 push definevs.00408030 ; ASCII "%d" 0040100B |. E8 61000000 call definevs.00401071
00401010 |. 8B4424 08 mov eax,dword ptr ss:[esp+8] 00401014 |. B9 03000000 mov ecx,3 00401019 |. 99 cdq ;将寄存器扩展为 EDX:EAX 6位 0040101A |. F7F9 idiv ecx ;进行有符号数字的除法,商放EAX,余放EDX中
0040101C |. 52 push edx 0040101D |. 68 30804000 push definevs.00408030 ; ASCII "%d" 00401022 |. 895424 10 mov dword ptr ss:[esp+10],edx 00401026 |. E8 15000000 call definevs.00401040 0040102B |. 33C0 xor eax,eax 0040102D |. 83C4 14 add esp,14
可见,除了就跟2的模外,其他的都会使用预先已有的除法指令进行!