汇编语言实验 7:标志寄存器

516 阅读6分钟

1. 预备知识

  1. 在 CPU 内部,标志寄存器是一种特殊的寄存器,它的主要功能包括:存储相关指令的某些执行结果;为 CPU 执行某些指令提供行为依据;控制 CPU 的相关工作方式。

  2. 和其他寄存器不同,标志寄存器按位起作用,每位都有特殊含义。如:

15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
            OF DF IF TF SF ZF    AF    PF    CF
  1. 常用标志位的功能:

    • OF 记录有符号数的运算中,其结果是否溢出。如果溢出则 OF=1,否则 OF=0。

    • SF 记录指令执行后,其结果是否为负。如果为负则 SF=1,否则 SF=0。

    • ZF 记录指令执行后,其结果是否为零。如果为零则 ZF=1,否则 ZF=0。

    • PF 记录指令执行后,其结果二进制位中 1 的个数是否为偶数。如果为偶数则 PF=1,否则 PF=0。

    • CF 记录无符号数的运算中,向更高位的进位值或从更高位的借位值。

  2. cmp 是汇编语言中的比较指令。该指令相当于完成减法功能,但是不保存结果,仅影响相关标志位的值。可以借由 cmp 指令实现高级语言中条件语句的功能。指令格式为 cmp 对象1,对象2,如 cmp ax,bx 及其对应的转移指令如下:

    • 如果 (ax)=(bx),则 ZF=1,转移指令 je 表示等于时转移

    • 如果 (ax)≠(bx),则 ZF=0,转移指令 jne 表示不等于时转移

    • 如果 (ax)<(bx),则 CF=1,转移指令 jb 表示小于时转移

    • 如果 (ax)≥(bx),则 CF=0,转移指令 jnb 表示不小于时转移

    • 如果 (ax)>(bx),则 CF=0 且 ZF=0,转移指令 ja 表示大于时转移

    • 如果 (ax)≤(bx),则 CF=1 且 ZF=1,转移指令 jna 表示不大于时转移

  3. pushf 指令的功能是将标志寄存器的值入栈;popf 指令的功能是从栈中弹出数据,并将其送入标志寄存器中。

  4. 在 debug 模式下,界面显示了 OF、SF、ZF、PF、CF 等标志位的值。

    • OF=1 时为 OV,OF=0 时为 NV

    • SF=1 时为 NG,SF=0 时为 PL

    • ZF=1 时为 ZR,ZF=0 时为 NZ

    • PF=1 时为 PE,PF=0 时为 PO

    • CF=1 时为 CY,CF=0 时为 NC

如图,框内第一位表示 OF 的信息,第四位表示 SF、第五位表示 ZF、第七位表示 PF、第八位表示 CF。

2. 实验任务 1:标志寄存器按位起作用

写出下面每条指令执行后,各标志位 OF、SF、ZF、PF、CF 的值。

sub al,al
mov al,10h
add al,90h
mov al,80h
add al,80h
mov al,0FCh
add al,5h
mov al,7Dh
add al,0Bh

第二、四、六、八条指令 mov 为数据传送指令,不影响标志位的值。

第一条为减法指令,其结果为零。OF=0(NV)、SF=0(PL)、ZF=1(ZR)、PF=1(PE)、CF=0(NC)。

第三条为加法指令,执行 10h + 90h。结果 0A0h 的二进制形式为 1010 0000,最高位为 1 表示负数。OF=0(NV)、SF=1(NG)、ZF=0(NZ)、PF=1(PE)、CF=0(NC)。

第五条为加法指令,执行 80h + 80h。对于有符号数的计算而言,(-128) + (-128) = (-256),超出了 8 位有符号数的范围,产生溢出;对于无符号数的计算而言,80h + 80h = 100h,有向更高位的进位,且 AL 只能存储 00h 部分。OF=1(OV)、SF=0(PL)、ZF=1(ZR)、PF=1(PE)、CF=1(CY)。

第七条为加法指令,执行 0FCh + 5h。对于有符号数的计算而言,(-4) + 5 = 1,无溢出;对于无符号数的计算而言,0FCh + 5h = 101h,有向更高位的进位,且 AL 只能存储 01h 部分。OF=0(NV)、SF=0(PL)、ZF=0(NZ)、PF=0(PO)、CF=1(CY)。

第九条为加法指令,执行 7Dh + 0Bh。对于有符号数的计算而言,125 + 11 = 136,超出了 8 位有符号数的范围,产生溢出;对于无符号数的计算而言,7Dh + 0Bh = 88h,无向更高位的进位,结果的二进制形式为 1000 1000,最高位为 1 表示负数。OF=1(OV)、SF=1(NG)、ZF=0(NZ)、PF=1(PE)、CF=0(NC)。

3. 实验任务 2:范围计数

编程,统计 075A:0000 处 32 个字节中,大小在 [32, 128] 的数据的个数。

3.1 实验分析

使用计数器统计大小在 [32, 128] 的数据的个数,当数据小于 32 或大于 128 时不计数,判断 32 个字节的数据即从 075A:0000 开始循环 32 次访问字节单元。整体代码为:

assume cs:code
code segment
start:
    mov ax,075Ah
    mov ds,ax
    mov bx,0	;计数器
    mov dx,0	;取数据的索引
    mov cx,32	;循环次数
s:
    mov al,ds:[bx]
    cmp al,32
    jb help	;小于32时转移至help
    cmp al,128
    jb help	;大于128时转移至help
    inc dx	;计数器
help:
    inc bx 
    loop s 
code ends
end start

3.2 实验结果

查看 075A:0000 开始 32 个字节单元的内容。

在 [32, 128] 范围内的数据共 16 个,运行程序后,寄存器 DX 的内容为 10h:

4. 实验任务 3:修改句子中的字母

编写子程序,将包含任意字符、以 0 结尾的字符串中的小写字母转换为大写。如将

Beginner's All-purpose Symbolic Instruction Code.

转换为:

BEGINNER'S ALL-PURPOSE SYMBOLIC INSTRUCTION CODE.

4.1 实验分析

根据示例可知,实验要求仅操作句子中的小写字母,其他字母不变。和实验任务 3 类似,我们可以先通过比较指令找出小写字母(ASCII 码位于 [97, 122]),然后通过位运算执行转换。整体代码为:

assume cs:codesg
datasg segment
    db "Beginner's All-purpose Symbolic Instruction Code",0
datasg ends
codesg segment
begin:
    mov ax,datasg
    mov ds,ax 		;段寄存器DS指向datasg段
    mov si,0		;取字符
    mov cx,0		;防止CX不为零影响jcxz的判断
    call letterc	;子程序调用
    mov ax,4c00h
    int 21h
letterc: 
    mov cl,ds:[si]	;取字符串中的字符
    jcxz exit		;如果CX等于0则退出
    cmp cl,97
    jb help 		;如果ASCII值小于97则转移至help
    cmp cl,122
    ja help		;如果ASCII值大于122则转移至help
    and cl,11011111b	;通过逻辑与运算将小写字母转换为大写字母
    mov ds:[si],cl	;将转换后的字符重写回对应的内存单元
help:
    inc si 		;偏移1个字节取字符
    jmp short letterc 	;循环
exit:
    ret			;子程序返回
codesg ends 
end begin

4.2 实验结果

程序运行前,数据的存放情况:

程序运行后,数据的存放情况:

5. 总结

  1. 标志寄存器是 CPU 内部的特殊寄存器,主要用于存储相关指令的某些执行结果;为 CPU 执行某些指令提供行为依据;控制 CPU 的相关工作方式等

  2. 实验 1 直观地感受了在指令执行过程中,各标志位的变化情况;实验 2 和实验 3 通过与标志寄存器相关的条件转移指令筛选数据

  3. 参考:汇编语言/王爽著.——北京:清华大学出版社,2003