Arithmetic & Logic Instructions¶
约 1768 个字 33 行代码 预计阅读时间 9 分钟
在原先 8086 汇编语言笔记的基础上新增部分指令
算术指令¶
加法指令¶
ADD
- 指令格式: add dest, src
- 指令效果: dest += src
ADC
- 指令格式: adc dest, src
- 指令效果: dest += src + CF
- 注意: 即带进位加法,add with carry
INC
- 指令格式: inc op
- 指令效果: op++
- 注意: inc 指令不影响 CF
习题
求 12345678h+4243BCBCh 的和,要求结果存放在寄存器DX:AX中:
XADD
- 指令格式: xadd dest, src
- 指令效果: src = dest; dest += src
- 例如 xadd ah(1000h), bh(2000h),执行完后 ah = 3000h, bh = 1000h
- 注意: exchange and add
减法指令¶
SUB
- 指令格式: sub dest, src
- 指令效果: dest -= src
SBB
- 指令格式: sbb dest, src
- 指令效果: dest = dest - src - CF
- 注意: 即带借位减法,subtract with borrow
DEC
- 指令格式: dec op
- 指令效果: op--
- 注意: dec 指令不影响 CF
NEG
- 指令格式: neg op
- 指令效果: op = -op
- 注意: 相当于取反加一(求补码, op = not op + 1),非零数求补后 CF = 1,0 求补后 CF = 0
CMP
- 指令格式: cmp op1, op2
- 指令效果: compare op1 - op2
- 注意: cmp 指令并不计算差值,但会像 sub op1, op2 影响状态标志,后面通常接跳转指令
CMPXCHG
- 指令格式: cmpxhg dest, src
- 指令效果:
- 如果 dest == accu,那么 dest = src,ZF = 1
- 如果 dest <> accu,那么 accu = dest,ZF = 0
- 注意: cmpxhg 指令隐式使用了 A 系列寄存器作为操作数,并且会影响状态标志 ZF
试写出对存放在DX:AX中的32位数进行求补(neg)的汇编指令序列
乘法指令¶
MUL
- 指令格式: mul src
- 指令效果: 非符号数乘法
- src 为 8 位时,ax = al * src
- src 为 16 位时,dx:ax = ax * src
- src 为 32 位时,edx:eax = eax * src
- Example: DX:AX=
123400h➡ DX=0012h, AX=3400h
IMUL
- 指令格式: imul src
- 指令效果: 符号数乘法
- src 为 8 位时,ax = al * src
- src 为 16 位时,dx:ax = ax * src
- src 为 32 位时,edx:eax = eax * src
IMUL 的第二类用法
Intel 第二代CPU为IMUL新增了用法,支持两个或三个操作数。以下四组指令都实现对eax乘10,不同的是,lea和imul指令并不能处理乘法的溢出:
除法指令¶
DIV
- 指令格式: div src
- 指令效果: 非符号数除法
- src 为 8 位时,al = ax / src, ah = ax % src
- src 为 16 位时,ax = dx:ax / src, dx = dx:ax % src
- src 为 32 位时,eax = edx:eax / src, edx = edx:eax % src
- 注意: 若除数为 0 或者保存商的寄存器无法容纳商时会发生除法溢出,此时 CPU 会在除法指令上方插入并执行一条 int 00h 指令(除法的异常处理)
IDIV
- 指令格式: idiv src
- 指令效果: 符号数除法
- src 为 8 位时,al = ax / src, ah = ax % src
- src 为 16 位时,ax = dx:ax / src, dx = dx:ax % src
- src 为 32 位时,eax = edx:eax / src, edx = edx:eax % src
- 注意: 若除数为 0 或者保存商的寄存器无法容纳商时会发生除法溢出,此时 CPU 会在除法指令上方插入并执行一条 int 00h 指令
逻辑运算和移位指令¶
逻辑运算指令¶
AND
- 指令格式: and dest, src
- 指令效果: dest = dest & src
OR
- 指令格式: or dest, src
- 指令效果: dest = dest | src
XOR
- 指令格式: xor dest, src
- 指令效果: dest = dest ^ src
NOT
- 指令格式: not op
- 指令效果: op = ^op
- 注意: 所有逻辑运算中,只有 NOT 不影响任何状态标志
TEST
- 指令格式: test dest, op
- 指令效果: test dest & src
- 注意: test 指令并不保存结果值,但会像 and dest, src 一样影响状态标志
80386 - Pentium 4 有四种测试单个比特的 test 指令
BT AX, 4测试 AX 的第四位,CF = AX[4]BTS CX, 9设置 CX[9] = 1BTR CX, 9设置 CX[9] = 0BTC CX, 9设置 CX[9] = ~CX[9]
移位指令¶
SHL
- 指令格式: shl dest, count
- 指令效果: dest <<= count & 1Fh
- 注意: 右侧补0,左侧溢出位落入 CF;count 只能是 idata 或 cl
- 若为 .386,则 idata 可为任意大小的 8 位常数
- 若为 8086,则 idata 只能为 1
- 其它移位指令和 shl 指令规定相同,不再做阐述
SHR
- 指令格式: shr dest, count
- 指令效果: dest >>= count & 1Fh
- 注意: 左侧补0,右侧溢出位落入 CF;count 只能是 idata 或 cl
SAL
- 指令格式: sal dest, count
- 指令效果: dest <<= count & 1Fh
- 注意: 算术左移指令,与 SHL 完全相同
SAR
- 指令格式: sar dest, count
- 指令效果: dest >>= count & 1Fh
- 注意: 左侧不变,右侧溢出位落入 CF;count 只能是 idata 或 cl
- 使用算术右移做除法,得到的结果与 IDIV 并不一致,IDIV 将结果向 0 取整,SAR 将结果向 -inf 取整
通过对被除数进行补偿,达到 SAR 和 IDIV 等价的效果,具体是如果被除数为负则加上 \(2^k-1\)
ROL
- 指令格式: rol dest, count
- 指令效果: 对 dest 循环左移 count & 1Fh 位,最高位回到最低位同时移到 CF 中
- 注意: rotate left;count 只能是 idata 或 cl
ROR
- 指令格式: ror dest, count
- 指令效果: 对 dest 循环右移 count & 1Fh 位,最低位回到最高位同时移到 CF 中
- 注意: rotate right;count 只能是 idata 或 cl
RCL
- 指令格式: rcl dest, count
- 指令效果: 带进位循环左移,即 CF 加在 dest 左侧一起循环左移
- 注意: count 只能是 idata 或 cl
RCR
- 指令格式: rcr dest, count
- 指令效果: 带进位循环右移,即 CF 加在 dest 右侧一起循环右移
- 注意: count 只能是 idata 或 cl
试写出把32位数 3F7E59ACh 逻辑左移2位的汇编指令序列,要求结果存放在DX:AX中
十进制调整指令¶
Binary Coded Decimal 是指用二进制编码的十进制数。
- 压缩BCD码 以4位二进制表示1位十进制
- \(37_{Decimal}\Rightarrow 37h\)
- 非压缩BCD码 以8位二进制表示1位十进制
- \(37_{Decimal}\Rightarrow 0307h\)
- 高位没有意义,可以为任意值,如
06h,36h都表示十进制数 6
# 压缩BCD码调整指令
DAA
- 指令格式: daa
- 指令效果: 压缩BCD码加法的十进制调整,将AL调整回BCD码
- if (af == 1 || (al&0Fh) > 9) al += 6, af = 1; else af = 0
- if (cf == 1 || al > 9Fh) al += 60h, cf = 1; else cf = 0
DAS
- 指令格式: das
- 指令效果: 压缩BCD码减法的十进制调整,将AL调整回BCD码
- if (af == 1 || (al&0Fh) > 9) al -= 6, af = 1; else af = 0
- if (cf == 1 || al > 9Fh) al -= 60h, cf = 1; else cf = 0
# 非压缩BCD码调整指令
AAA
- 指令格式: aaa
- 指令效果: 加法的 ASCII 调整,在 al 被做加法后调整 ax 为非压缩BCD码(ah也被修改)
- if (af == 1 || (al&0Fh) > 9) al = (al+6)&0Fh, ah += 1, af = 1, cf = 1
- else af = 0, cf = 0
AAS
- 指令格式: aas
- 指令效果: 减法的 ASCII 调整,在 al 被做减法后调整 ax 为非压缩BCD码(ah也被修改)
- if (af == 1 || (af&0Fh) > 9) al = (al-6)&0Fh, ah -= 1, af = 1, cf = 1
- else af = 0, cf = 0
AAM
- 指令格式: aam
- 指令效果: 乘法的 ASCII 调整,在 al 被做乘法后调整 ax 为非压缩BCD码(ah也被修改)
- ah = al / 10, al = al % 10
AAD
- 指令格式: aam
- 指令效果: 除法的 ASCII 调整,在 al 被做除法后调整 ax 为非压缩BCD码(ah也被修改)
- al = ah * 10 + al, ah = 0
