汇编入门笔记(十一)

0x31:adc指令和sbb指令

adc是带进位加法指令,它利用了CF位上记录的进位值。

指令格式:adc 操作对象1, 操作对象2

功能:操作对象1 = 操作对象1 + 操作对象2 + CF

1
2
3
4
mov ax, 2
mov bx, 1
sub bx, ax ;无符号运算借位CF=1,有符号运算OF = 0
adc ax, 1 ;执行后,(ax)= 4。adc执行时,相当于计算:(ax)+1+CF = 2+1+1 = 4。

image-20210928212150972

1
2
3
4
5
6
;计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中。
;将计算分两步进行,先将低16位相加,然后将高16位和进位值相加。
mov ax, 001EH
mov bx, 0F000H ;十六进制形式不能以字母开头,前面必须加上0
add bx, 1000H
adc ax, 0020H

sbb指令

sbb是带借位减法指令,它利用了CF位上记录的借位值。

指令格式:sbb 操作对象1, 操作对象2

功能:操作对象1 = 操作对象1 - 操作对象2 - CF

1
2
3
4
5
;计算 003E1000H - 00202000H,结果放在ax,bx中,程序如下:
mov bx, 1000H
mov ax, 003EH
sub bx, 2000H ;结果是F00H,1000H < 2000H,借一位,11000H - 2000H = F00H,其实也就是-1000H的补码,补码的原理就是这样,-1000H + 10000H转成正数
sbb ax, 0020H

0x32:cmp指令

cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。

其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。

cmp指令格式:cmp 操作对象1,操作对象2

例如:
指令cmp ax, ax,做(ax)-(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的相关各位
指令执行后:zf=1,pf=1,sf=0,cf=0,of=0。

CPU在执行cmp指令的时候,也包含两种含义:进行无符号数运算和进行有符号数运算。

0x33:检测比较结果的条件转移指令

可以根据某种条件,决定是否修改IP的指令。

jcxz它可以检测cx中的数值,如果(cx)=0,就修改IP,否则什么也不做。


所有条件转移指令的转移位移都是[-128,127]。(短转移)

多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。

这些指令可以分为对有符号数和无符号数的比较。

根据无符号数的比较结果进行转移的条件转移指令(它们检测zf、cf的值)

指令 含义 检测的相关标志位
je 等于则转移 zf = 1
jne 不等于则转移 zf = 0
jb 低于则转移 cf = 1
jnb 不低于则转移 cf = 0
ja 高于则转移 cf = 0 且 zf = 0
jna 不高于则转移 cf = 1 或 zf = 1

j:jump,e:equal,b:below,a:above,n:not

这些条件转移指令通常和cmp指令配合使用的,根据cmp指令导致的寄存器变化结果进行条件转移。

但它们也可以不和cmp指令一起使用,那就看当前标志寄存器的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
;编程,统计data段中数值为8的字节的个数,用ax保存统计结果。
data segment
db 8,11,8,1,8,5,63,38
data ends
mov ax, data
mov ds, ax
mov bx, 0 ;ds:bx指向第一个字节
mov ax, 0 ;初始化累加器
mov cx,8

s:
cmp byte ptr [bx], 8 ;和8进行比较
jne next ;如果不相等转到next,继续循环
inc ax ;如果相等就将计数值加1
next:
inc bx
loop s ;程序执行后:(ax)=3

0x34:DF标志和串传送指令

方向标志位。在串处理指令中,控制每次操作后si、di的增减。

  • df = 0每次操作后si、di递增;
  • df = 1每次操作后si、di递减。

串传送指令:

格式:movsb
功能:将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器df位的值,将si和di递增1或递减1

格式:movsw
功能:将ds:si指向的内存字单元中的送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或递减2

格式:rep movsb
movsb和movsw进行的是串传送操作中的一个步骤,一般来说,movsb和movsw都和rep配合使用
功能:rep的作用是根据cx的值,重复执行后面的串传送指令

1
2
3
4
rep movsb <==> s:movsb
loop s
rep movsw <==> s:movsw
loop s

8086CPU提供下面两条指令对df位进行设置。

  • cld指令:将标志寄存器的df位置0,正向复制
  • std指令:将标志寄存器的df位置1,反向复制

显然串传送指令很适合一段连续空间的复制操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;将data段中的第一个字符串复制到它后面的空间中。
data segment
db 'Welcome to masm!'
db 16 dup (0)
data ends

mov ax, data
mov ds, ax
mov si, 0 ;ds:si 指向data:0
mov es, ax
mov di, 16 ;es:di指向data:0010

mov cx, 16 ;(cx)=16,rep循环16次
cld ;设置df=0,正向传送
rep movsb

0x35:pushf和popf

pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中

pushf和popf,为直接访问标志寄存器提供了一种方法。

标志寄存器在debug中的表示:

image-20210929100118196

坚持原创技术分享,您的支持将鼓励我继续创作!