无符号数加法
add
add指令可以改变Flag Register中的ZF,SF,AF,CF,PF,OF位。
下面是一个计算1-100和的程序
global main
extern printf
segment .text
main:
push ebp
mov ebp,esp
mov eax,0
mov edx,0
loop:
inc dl
add al,dl
adc ah,0
cmp dl,101
jnz loop
push eax
push msg
call printf
leave
ret
segment .data
msg: db "The sum of 0-100 is %u",0x0A,0
adc
上面的一段程序用到了adc指令,原因是al是不足以放下sum(1,100)的,adc指令会查看CF标志,并将其加到结果上。即adc,A,B 相当于 A=A+B+CF。这给计算寄存器不能存的下的数据提供了便利。如下面的程序,两个0xFFFFFFFF相加,并显示结果。将进位保存到ebx,然后采用GCC中的long long输出。
global main
extern printf
segment .text
main:
push ebp
mov ebp,esp
mov ebx,0
clc
start:
mov eax,[op1]
add eax,[op2]
adc ebx,0
push ebx
push eax
push msg
call printf
leave
ret
segment .data
op1: dd 0xFFFFFFFF
op2: dd 0xFFFFFFFF
msg: db 'Result is %llu',0xa,0x0
无符号数减法
sub
无符号减法的执行过程可以描述为
- 获取减数的二进制补码
- 与被减数相加
- 倒转进位
这样以来,执行sub后,若CF=0,结果为正;若CF=1,则结果为负。
下面这段程序计算了 2 sub 3。
global main
extern printf
segment .text
main:
push ebp
mov ebp,esp
mov eax,2
mov ebx,3
sub eax,ebx
not eax
add eax,1 ;求正数原码
push eax
push msg
call printf
leave
ret
segment .data
msg: db 'Result is -%u',0xa,0x0
sbb
与adc差不多,sbb A,B 相当于 A=A-B-CF。即若有借位则减一。
无符号数乘法
mul
无符号乘法,其中一个隐含操作数在寄存器eax中。结论见下表
类型 | 操作数1 | 操作数二 | 结果 |
8*8 | al | 寄存器/内存 | ax |
16*16 | ax | 寄存器/内存 | dx(高位),ax(低位) |
32*32 | eax | 寄存器/内存 | edx(高位),eax(低位) |
下面是一个例子:
global main
extern printf
segment .text
main:
push ebp
mov ebp,esp
mov eax,0
mov al,3
mov bl,4
mul bl
push eax
push msg1
call printf
mov ax,4500
mov bx,1000
mul bx
mov bx,dx
shl ebx,16
mov bx,ax
push ebx
push msg2
call printf
mov eax,0xFFFFFFFF
mov ebx,0xFFFFFFFF
mul ebx
push edx
push eax
push msg3
call printf
leave
ret
segment .data
msg1: db '3*4=%u',0x0a,0x0
msg2: db '4500*1000=%u',0x0a,0x0
msg3: db '0xFFFFFFFF*0xFFFFFFFF=%llu',0x0a,0x0
无符号除法
div
在进行出发时,若分母为0或商对寄存器来说太大,会产生异常。除法类型见下表
类型 | 分子 | 分母 | 商 | 余数 |
8/8 | al=x,ah=0 | 寄存器/内存 | al | ah |
16/16 | ax=x,dx=0 | 寄存器/内存 | ax | dx |
32/32 | eax=x,edx=0 | 寄存器/内存 | eax | edx |