整数算数运算指令也就是进行加、减、乘、除,相应的指令就是ADD、SUB、MUL、DIV,操作数可以是8位、16位、32位的。
标志寄存器
标志寄存器又称程序状态字,主要用于反映处理器的状态和ALU运算结果的某些特征及控制指令的执行,有些指令的执行会改变标志位,就比如逻辑运算指令等,不同的指令会影响不同的标志位。
每个标志位具体什么意思,本章就不说了。
如上面的PF,反应了运算结果中1的个数的奇偶性,如果个数为偶数,那么PF位位1,否则为0,还有如ZF反应了运算结果是否为0,如果为0,那么ZF位位1,否则为0,后面的例子会举例说明。
ADD
ADD是加法指令,用于源操作数加上目的操作数,最终结果存到源操作数中,ADD对于高级语言的语法就是a+=x
,格式如下:
ADD Reg/Mem,Reg/Mem/Imm
Reg表示寄存器,英文Register的缩写,Mem表示内存,Imm表示立即数。
.386
.Model Flat, StdCall
Option Casemap :None
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\msvcrt.lib
printf PROTO C : dword,:vararg
system PROTO C : dword,:vararg
.data
szMessage db 'a',10,13,0
bTest1 dword -1
szPause db 'pause',10,13,0
szOutFmt byte '%d+%d=%d',10,13,0
.code
START:
mov eax,10
add eax,10
invoke printf,addr szOutFmt,10,10,eax
invoke system ,addr szPause
END START
值为20的话,那么二进制就是0001 0100,标志位PF的值就是就是1,因为有两个1,是偶数,而ZF位由于结果不为0,就等于0。
我们可以通过OLLYDBG查看。
在换一下,计算3+4、0+0的值。
mov eax,3
add eax,4
invoke printf,addr szOutFmt,3,4,eax
由于结果为7,有3个1,是奇数,则PF位0,ZF位由于结果不为0,就等于0.
0+0=0,0也是偶数,所以则PF位1,ZF由于结果等于0,所以为1。
好了,真TM的绕。
加法还有一个INC指令,相当于高级语言的a++
,就是实现操作数+1,还有两个有关的指令是ADC、XADD。
减法
减法指令是SUB,将源操作数值减去目的操作数,结果存放到源操作数。
SUB Reg/Mem,Reg/Mem/Imm
受影响的标志位有AF、CF、OF、PF、SF、ZF
加法有单独加1的指令,当然减法也有,也就是DEC,还有两个有关的指令是SBB、NEG。
.386
.Model Flat, StdCall
Option Casemap :None
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\msvcrt.lib
printf PROTO C : dword,:vararg
system PROTO C : dword,:vararg
.data
szMessage db 'a',10,13,0
bTest1 dword -1
szPause db 'pause',10,13,0
szOutFmt byte '%d-%d=%d',10,13,0
.code
START:
mov eax,123H
SUB eax,122H
invoke printf,addr szOutFmt,123H,122H,eax
invoke system ,addr szPause
END START
乘法
32 位模式下,MUL(无符号数乘法)指令有三种类型:
1、 第一种执行 8 位操作数与 AL 寄存器的乘法;
2、第二种执行 16 位操作数与 AX 寄存器的乘法;
3、第三种执行 32 位操作数与 EAX 寄存器的乘法。
乘法指令一般仅乘数在指令中显示的写出来,而被乘数固定用EAX,结果存放在EDX|EAX中。
乘法影响的标志位有CF、OF。
.386
.Model Flat, StdCall
Option Casemap :None
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\msvcrt.lib
printf PROTO C : dword,:vararg
system PROTO C : dword,:vararg
.data
szMessage db 'a',10,13,0
bTest1 dword -1
szPause db 'pause',10,13,0
szOutFmt byte '%d*%d =%d',10,13,0
.code
x dword 5
START:
mov eax,8
mul x
invoke printf,addr szOutFmt,8,x,eax
invoke system ,addr szPause
END START
MUI是无符号乘法,有符号乘法指令是IMUL。无符号乘法指令数据的最高位是作为“数值”参与运算,有符号指令数据高位是作为“符号位”运算。
除法
除法也分无符号DIV和有符号IDIV,除法指令仅除数在指令中显示的写出来,被除数固定EDX|EAX,商存在EAX中,余数在EDX中。
受影响的标志位AF、CF、OF、PF、SF、ZF
.386
.Model Flat, StdCall
Option Casemap :None
include C:\masm32\include\kernel32.inc
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\msvcrt.lib
printf PROTO C : dword,:vararg
system PROTO C : dword,:vararg
.data
szMessage db 'a',10,13,0
bTest1 dword -1
szPause db 'pause',10,13,0
szOutFmt byte '%d/%d =%d...%d',10,13,0
.code
x dword 5
START:
mov eax,18
cdq
idiv x
invoke printf,addr szOutFmt,18,x,eax,edx
invoke system ,addr szPause
END START
为什么在使用DIV指令之前EDX应该为0?
从上面发现一条指令cdq,如果没有这条指令,程序会出错,这条指令的意思是将EAX符号位填充到EDX,也就是说,如果EAX小于十六进制80000000H,那么EDX就会成为0,如果大于十六进制80000000H,那么EDX就全是F。
也就是运算DIV指令之前EDX应该为0,关于这个问题,我找到一篇很好的文章。
https://www.codenong.com/38416593/