文章目录
第11章 标志寄存器
标志寄存器是一种特殊的寄存器,具有以下3种作用:
- 用来存储相关指令的某些执行结果:
- 用来为CPU执行相关指令提供行为依据;
- 用来控制CPU的相关工作方式。
以下简称为flag,flag是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息。
ZF标志
位于flag第6位,零标志位。
如果相关指令执行结果为0,那么zf=1,如果不为0,则zf=0
mov ax,1
sub ax,1
;zf=1
mov ax,2
sub ax,1
;zf=0
那么任何指令都会影响到zf吗?答案是否定的。
在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如,dd、 sub、mul、div、inc、or、and等,它们大都是运算指令(进行逻辑或算术运算);有的指令的执行对标志寄存器没有影响,比如,mov、push、pop等,它们大都是传送指令。在使用一条指令的时候,要注意这条指令的全部功能,其中包括,执行结果对标志寄存器的哪些标志位造成影响。
PF标志
位于flag第2位,奇偶标志位。
如果相关指令执行结果的所有bit位中1的个数是偶数,pf=1,如果是奇数,那么pf=0.
mov al,1
add al,10
;结果为1011b,奇数个1,pf=0
mov al,1
or al,2
;结果为11b,偶数个1,pf=1
SF标志
位于flag第7位, 符号标志位.
相关指令执行结果为负, sf=1, 如果非负, sf=0
只有我们把影响sf的相关指令视为有符号数运算时, sf的值才是有意义的.
我们可以说sf把每个数都视为有符号的, 只不过实际意义上并不一定.
CF标志
位于flag第0位, 进位标志位.
在进行无符号数运算时, 它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值.
OF标志
位于flag第11位, 一般情况下, OF记录了有符号数运算的结果是否发生了溢出.
如果发生溢出, OF=1, 如果没有, OF=0.
adc 指令
adc是带进位加法指令
功能: 操作对象1 = 操作对象1 + 操作对象2 + CF
简而言之, adc 比 add 指令 多加了一个 CF.
不能取代, 因为add si,2
和 add di, 2
肯定不会进位, 导致CF一直是0.
sbb指令
同上, sbb是带借位减法指令
功能: 操作对象1 = 操作对象1 - 操作对象2 - CF
通过sbb可以实现和adc类似的功能.
cmp指令
cmp指令相当于减法指令, 但是不保存结果, 也就是不会改变被减数大小, 它只会对标志寄存器产生影响.
对于cmp ax,bx
反过来说, 我们可以根据标志寄存器判断ax和bx的大小关系.
-对于有符号运算
检测比较结果的条件转移指令
“转移”指的是它能够修改IP,而“条件”指的是它可以根据某种条件,决定是否修改P。
[!NOTE]
重新理解一下
jcxz
的语义, “j"显然代表"jump(转移)”, 那么接下来就是条件了.
jcxz
的转移条件是cx=0
, 不难想到cxz
的意思就是**“cx = z(ero)”**.既然有了"cxz", 也就有其他类似的条件转移指令.
大多数条件转移指令都检测标志寄存器的相关标志位, 它们都与cmp
指令密切相关.
示例程序: 统计data段中数值为8的字节的个数, 用ax保存统计结果.
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
;这个程序也可以写成这样:
mov ax,data
mov ds,ax
mov bx,0 ;ds:bx指向第一个字节
mov ax,0 ;初始化累加器
mov cx,8
S:
cmp byte ptr [bx],8 ;和8进行比较
je ok ;如果相等转到ok
jmp short next ;如果不相等就转next,继续循环
ok:
inc ax ;如果相等就将计数值加1
next
inc bx
loop s
第二个示例虽然更符合题目的语义, 但是多使用了一个标志, 不如第一个示例简洁, 这种逆向思考的思维值得学习.
DF标志和串传送指令
位于flag第10位,方向标志位,在串处理指令中,控制每次操作后si、di的增减
- df=0 每次操作后si、di递增;
- di=1 每次操作后si、di递减。
-movsb指令
将ds:si指向的内存单元中的字节送入es:di中, 然后根据df的值将si和di递增或递减.
-movsw指令
movsb操作byte(字节), movsw操作word(字), 而且si和di递增2或递减2.
-rep指令
一般来说,movsb和movsw都和rep配合使用, 格式如下:
rep movsb
类似于
s: movsb
loop s
也就是执行cx次movsb, rep movsb可以循环实现(cx)个字符的传送.
-cld,std
既然df决定着movsb(w)执行的方向, 所以CPU提供了相应的指令来设置df位:
cld
指令: df = 0
std
指令: df = 1
用串传送指令,将F000H段中的最后16个字符复制到data段中.
data segment
db 16 dup (0)
data ends
code segment
start:
mov ax, 0f000h
mov ds, ax
mov si, 0ffffh
mov ax, data
mov es, ax
mov di, 15
std
mov cx, 16 ;mov cx,8
rep movsb ;rep movsw 同理
mov ax, 4c00h
int 21h
code ends
end start
pushf 和 popf
pushf 将标志寄存器的值压栈, popf从栈中弹出数据, 送入标志寄存器中.
实验11
assume cs:code, ds:data
data segment
db "Beginner's All-purpose Symbolic Instruction Code.",0
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0
call letterc
mov ax, 4c00h
int 21h
letterc:
push si
mov ch, 0
convert:
mov cl, [si]
jcxz done
cmp cl, 97
jb next ;小于a的ascii值
cmp cl, 122
ja next ;大于z的ascii值
;符合要求,转换为大写,-32
mov al, 32
sub cl, al
mov [si], cl
next:;进入下个循环
inc si
jmp short convert
done:;循环结束
pop si
ret
code ends
end start
-结果
在DEBUG中查看转换结果