啥都不会 发表于 2022-4-21 21:55

8086汇编-标志寄存器

# 前言

这篇笔记主要解释标志寄存器和JCC指令相关知识。

# 编程语言

汇编语言

# 以下为主题内容

CPU 内部的寄存器中,有一种特殊的寄存器(根据不同的处理器,个数和结构都可能不同)具有以下 3 种作用。

1. 用来存储相关指令的某些执行结果
2. 用来为 CPU 执行相关指令提供行为依据
3. 用来控制 CPU 相关的工作方式

这种特殊的寄存器在 8086CPU 中,被称为标志寄存器。8086CPU 的标志寄存器有 16 位,其中存储的信息通常被称为程序状态字(PSW)。

8086CPU 的 flag 寄存器的结构如下图所示:

!(https://i.loli.net/2020/08/30/VQ7RMIBLcCe6A23.png)

flag 寄存器的 1、3、5、12、13、14、15 位在 8086CPU 中没有使用,不具有任何含义。而 0、2、4、6、7、8、9、10、11 位都具有特殊的含义。

在 debug 调试器中各标志位的状态如下:

![图片](https://user-images.githubusercontent.com/25861639/163695297-5c610a94-1af1-49ac-9c67-80f7738cfe9a.png)

# 状态标志位

## CF 标志位

flag 的第 0 位是 CF 位,进位标志位,用来记录无符号运算的结果。当逻辑运算,出现超出寄存器大小的范围进位时 CF 位置 1,或者向超出寄存器大小范围进行借位时 CF 位置 1。

例1(进位):

```
al=FF=0(进位值) 1(最高有效位)111 1111
al+1=1(进位值) 1111 1111

这里 al+1 的结果多了超出 al 寄存器范围的1,此时CF位置1
```

![图片](https://user-images.githubusercontent.com/25861639/163695548-f9137e5a-8c55-41fe-b6b8-25f01f78e5b8.png)

例2(借位):

```
al=5=0(借位值) 0101
al-6=1(借位值) 0101-6=FF
```

![图片](https://user-images.githubusercontent.com/25861639/163695997-86b67789-233d-415b-b37c-d3cd58e393fb.png)

这里的进位或者借位,就可以当成 CF 位,当两个数相加或相减的操作数超过寄存器的大小,CF 位就会置 1。

## PF 标志位

flag 的第 2 位是 PF,奇偶标志位。它记录了相关指令执行后,其结果的所有 bit 位中 1 的个数是否为偶数。如果 1 的个数偶数,pf=1,如果为奇数,那么 pf=0。

例1:

```
mov al,1
add al,10
```

执行后,结果为 00010001B,其中有 2(偶数)个 1,则 pf=1;

![图片](https://user-images.githubusercontent.com/25861639/163696380-c116e2bc-a63c-4169-a7fe-16e0556efa1d.png)

例2:

```
sub al,10
```

执行后,结果为 00000001B,其中有 1(奇数)个 1,则 pf=0。

![图片](https://user-images.githubusercontent.com/25861639/163696449-2daec5ba-0bb0-4d81-a360-5d063b098bd7.png)

> PF位通常用来做校验的,校验数据传输的结果是否正确,或者校验数据拷贝的结果是否正确。例如:传输的时候有 4 个 1,但是接收的时候是3 个 1,这个时候就说明你传输的结果错了。

## ZF 标志

flag 的第 6 位是 ZF,零标志位。它记录相关指令执行后,其结果是否为 0。结果为 0,那么 zf=1;如果结果不为 0,那么 zf=0。

例1:

```
mov ax,1
sub ax,1
```

执行后,结果为 0,则 zf=1,表示 "结果是 0"

!(https://user-images.githubusercontent.com/25861639/163696706-7760a9d0-3cd9-4ec3-be6f-effe5efd6197.png)

例2:

```
mov ax,2
sub ax,1
```

执行后,结果不为0,则 zf=0,表示 “结果非 0”

!(https://user-images.githubusercontent.com/25861639/163696741-cfc6d8a0-e811-4802-9582-97452e4acd74.png)

> 在 8086CPU 的指令集中,大多数逻辑运算指令的执行是影响标志寄存器的,大多数数据转移指令的执行对标志寄存器没有影响。

## SF 标志

flag 的第 7 位是 SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。

在计算机中我们可以人为把一个数据看作是有符号数,也可以看成是无符号数。当把一个数看作有符号数,其最高位就是符号位(不包括在数值运算中)

例如:

```
0000 0001B,有符号数+1;
1000 0001B,有符号数-127。
```

例1(3+4):

```
mov al,3
add al,4
```

计算结果:3+4=7

两个正数相加,最高位是 0,SF 置 0

!(https://user-images.githubusercontent.com/25861639/163699195-bdd32788-7206-4a4e-8cbf-98bcf09d4440.png)

例2(-1-1):

```
mov al,ff
add al,ff
```

计算结果:-1+(-1)=-2(FE)

当 2 个负数相加最高位是1,所以 SF 置 1 。同时又因为这两个值相加导致出现溢出,所以 CF 位也置 1 。我们可以得出有符号数的运算,是会影响到无符号数运算的 CF 标志位。那这个会对无符号数运算结果有影响吗?

!(https://user-images.githubusercontent.com/25861639/163697882-55cb5591-b439-4971-ab3b-1c2d414c8431.png)

> SF位和CF位同时改变对计算结果没有影响,SF 位是符号位只表示这个值是正数还是负数,不会影响结果。如果我们做的是无符号计算,对于我们来说 SF 位如何改动都是没有意义的。

## OF 标志

flag 的第 11 位是 OF,溢出标志位(针对有符号数的进位运算)。如果有符号数运算结果超出机器所能表达的范围,将产生溢出,这里的溢出只是对有符号数运算而言。对于 8 位的有符号数据,机器所能表示的范围是 -128~127,对于 16 位有符号数据,机器所能表示的范围是 -32768~23767。

例1(100+100):

```
mov al,64
add al,64
```

计算结果:100+100=00C8

al 最大有符号数 127(7F),当 2 个正数相加得到的结果是负数,那就说明计算结果超过该寄存器有符号数的存储范围 OF 置 1 ,否则 OF 为 0

!(https://user-images.githubusercontent.com/25861639/163699296-bf4f6be1-67d4-4a4a-8b8f-3b4fb05a23c3.png)

> OF位和CF位同样互不影响,你要计算有符号数的进位,就看OF位;要计算无符号数的进位就看 CF 位。计算的时候别把这两个位搞混了,你想计算有符号数的进位,但是用的是CF位来计算,那就出问题了。

# 控制标志位

## TF 位

TF 位用于单步执行,调试器中的 T 命令就是单步执行。默认情况下 TF 位是为 0 的,也就是说 IP指针寄存器自动加1,程序会自动往下一条一条地执行指令。当 TF 置 1 时,就是单步执行,调试器里面的单步调试,就是 CPU 里面已经设置好了 TF 位,允许单步执行,所以调试器才可以单步执行。

## IF 位

IF 位默认状态是置 1 的,这个是中断标志位。中断可以理解为高级语言中的函数,其功能是控制计算机的外设数据的输入/输出。IF 置 1 表示开中断,IF 置 0 表示关中断。如果 IF 位置 0 了,那么外设就无法使用了,你无法通过外设向计算机中输入任何的数据。

## DF 位

DF 位默认状态是 0 ,是方向标志位。表示数据读取/拷贝是从左向右拷贝数据,还是从右向左拷贝数据。DF 置 0 是从左往右,即从低地址向高地址读取/拷贝数据。DF 置 1 是则相反。

# JCC 指令

JCC 指令是根据状态标志位,进行跳转的指令,它主要分为 3 组

一组是直接判断状态标志位

!(https://user-images.githubusercontent.com/25861639/163709127-15b2211c-a5bc-48e4-b044-b4503b0be0c9.png)

!(https://user-images.githubusercontent.com/25861639/163709100-4e12abf3-0cdb-421b-99fa-11c8878b5d01.png)

一组是无符号数的JCC指令

!(https://user-images.githubusercontent.com/25861639/163709197-0a2beea1-e509-4156-be04-9ebd0eab6dbd.png)

一组是有符号数的JCC指令

!(https://user-images.githubusercontent.com/25861639/163709267-89d6dbea-9625-4bc2-8f10-6d460c8680ba.png)

## 代码练习

1. JB.asm

```
;程序名:jb.asm
;功能:显示一个字符串
;===========================
assume cs:code,ds:data

data segment
;8086汇编中的变量定义
;在数据段偏移地址0处,定义一个以字节为单位的string变量
;为其分配 22 个字节大小的内存空间,并将数值初始化为相应字符
string db "hello ,welcome to JB!","$"

;在数据段偏移地址 number 处,定义一个以字节为单位的 number 变量,
;为其分配 6 个字节大小的内存空间,并将数值初始化为 "1,2,3,4,5,6"

number db 1,2,3,4,5,6   
data ends

code segment
start:
    mov ax,data
    mov ds,ax
    ;jb(jmp below)无符号数跳转, < CF=0
    mov si,offset number
    mov al,byte ptr ds:
    cmp al,         ;使用减法运算,功能与 sub 指令一样,区别在于该指令不会改变寄存器中的值
    jb str
    ;
    mov ax,4c00h
    int 21h
    ;
str:
    mov dx,offset string
    mov ah,9
    int 21h
    mov ax,4c00h
    int 21h
code ends
    end start
```

2. JL.asm

```
;程序名:JL.asm
;功能:显示一个字符串
;===========================
assume cs:code,ds:data

data segment
string db "hello ,welcome to JL!","$"
number db 1,2,3,4,5,6
data ends

code segment
start:
    mov ax,data
    mov ds,ax
    ;jL(jmp less)有符号数跳转, < SF xor OF=1 跳转
    mov si,offset number
    mov al,-1      
    cmp al,1         ;有符号数 -1<1
    ;jb str            ;用无符号数跳转,程序出现错误
    jlstr
    ;
    mov ax,4c00h
    int 21h
    ;
str:
    mov dx,offset string
    mov ah,9
    int 21h
    mov ax,4c00h
    int 21h
code ends
    end start
```

3. je.asm

```
;程序名:je.asm
;功能:显示一个字符串
;===========================
assume cs:code,ds:data

data segment
string db "hello ,welcome to jE!",0dh,0ah,24h
number db 1,2,3,4,5,6
data ends

code segment
start:
    mov ax,data
    mov ds,ax
    ;je(jmp equal)相等就跳转, == ZF=1
    mov si,offset number
    mov al,byte ptr ds:
    cmp al,
    je str
    ;
    mov ax,4c00h
    int 21h
str:
    mov dx,offset string
    mov ah,9
    int 21h
    mov ax,4c00h
    int 21h
code ends
    end start
```

> 注意:你要进行有符号数运算,就用有符号数跳转;无符号数运算,用无符号数跳转。无符号数跳转中含有B(Below)和A(Above),有符号数跳转中含有L(Less)和G(greater)。如有其他问题,自己修改代码进行验证。

跳转指令太多,有映像就行,不需要死记,如果忘了就去查,这些指令用多了就记住了。

BurnlOvKFAPD 发表于 2022-4-21 22:06

感谢楼主

uYE05 发表于 2022-4-21 22:06

前来向大佬学习

啥都不会 发表于 2022-4-21 22:14

uYE05 发表于 2022-4-21 22:06
前来向大佬学习

我也不是大佬,我只是会点汇编代码,逆向现在懂得并不是很多。写这些帖子还是想让大家能尽快入门学习汇编,少走些弯路。

uYtUSF 发表于 2022-4-21 22:14

谢谢分享

IKfTXCG95807 发表于 2022-4-21 22:14

感谢楼主

MUt309 发表于 2022-4-21 22:14

谢谢分享

oIUCxRZ85960 发表于 2022-4-21 22:15

谢谢分享

bTckhDOlMA 发表于 2022-4-21 22:17

感谢楼主

IKfTXCG95807 发表于 2022-4-21 22:18

谢谢分享
页: [1] 2 3 4 5 6 7 8
查看完整版本: 8086汇编-标志寄存器