8086汇编学习笔记11

转移指令

系列文章

转移指令概念和offset操作符

可以修改 IP ,或同时修改 CSIP 的指令统称为转移指令。概括地说,转移指令就是可以控制CPU执行内存某处代码的指令。

8086CPU转移行为的分类:

段内转移对 IP 的修改范围不同时,又分为

8086CPU的转移指令的分类:

操作符 offset 在汇编语言中是由编译器处理的符号,功能是取得标号的偏移地址。例如:

start:  mov ax, offset start  ; same as "mov ax, 0"
next:   mov bx, offset next   ; same as "mov bx, 3"

关于JMP指令

之前介绍了 JMP 指令。该指令要给出两种信息:

  1. 转移的目的地址
  2. 转移的距离(段间转移、段内短转移、段内近转移)

该指令有以下用法:

该语句转到标号 label 处执行指令。关键字 short 说明指令进行的是短转移,它向前转移时最多可以越过128字节,向后转移时最多可以越过127字节

转移指令结束后,CS:IP 应该指向标号处的指令

JMP short label ”的功能为:(IP) +=8位位移。

8位位移以补码的形式给出。

在“ JMP short label ”指令所对应的机器码中,并不包含转移的目的地址,而是包含转移的位移。该位移由编译器计算出结果。

该转移语句,关键字 near ptr 说明实现的是段内近转移

JMP near ptr label ”的功能为:(IP) +=16位位移。

该指令实现的是段间转移,又称为远转移

JMP far ptr label ”的功能为:(CS) =标号所在段的段地址;(IP) =标号所在段中的偏移地址。

关键字 far ptr 指明了用标号的段地址和偏移地址修改 CSIP

使用16位寄存器 16bit-reg 中的值修改 IP

该指令是段内转移,将内存单元地址 memory 处的字型数据(16位)作为转移目的的偏移地址

内存单元地址可用寻址方式的任意格式给出。

该指令是段间转移,对应内存单元地址 memory 处存放的连续两个字,高地址处存放的字是转移目的的段地址,低地址处存放的字是转移目的的偏移地址

内存单元地址可用寻址方式的任意格式给出。

JCXZ、NOP指令

JCXZ 指令为有条件转移指令所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是转移的目的地址。

JXCZ指令(有条件转移指令)
格式:
JXCZ label
用途:
当寄存器 CX 的值为0时,短转移到标号 label 处执行;当寄存器 CX 的值不为零时,程序继续向下执行(什么也不做)。

对比一下 LOOP 指令:

LOOP 指令为循环指令,所有的循环指令也都是短转移
LOOP 指令会先使 CX 寄存器中的值减1,如果 CX 中的值不为零时,程序跳转到标号 label 处执行;当寄存器 CX 的值为0时,程序继续向下执行(什么也不做)。

NOP指令(空指令)
格式:
NOP
用途:
什么也不做。

NOP 指令除了占用三个周期,什么操作都没有。因此它一般用于控制时间周期

位移转移与转移越界

目前介绍的转移指令,包括 JMPJCXZLOOP ,它们对 IP 的修改是根据转移起始地址和转移目的地址的位移来进行的。

这种位移的实现由编译器完成。它的优点是无需得到目标代码的真实地址,方便程序在内存中浮动装配

根据位移进行转移的指令,它们的转移范围受到转移位移的限制,如果在源程序中出现了转移越界的问题,在编译时编译器会报错

DOS字符显示

DOS操作系统采用80×25彩色字符模式显示缓冲区,该缓冲区的结构为:

内存地址空间中,B8000H~BFFFFH32KB的空间,为80×25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上

在80×25彩色字符模式下,显示器可以显示25行,每行80个字符,每个字符可以有256种属性(背景色、前景色、闪烁、高亮组合信息)。

这样,一个字符在显示缓冲区中要占2个字节:低字节存放字符的ASCII码信息,高字节存放字符的属性信息

属性字节的格式见下图:

在属性对应的位中,0代表无效果或无色值,1代表有效果和有色值。色值可以叠加,背景色最多有8种。

可以按位设置属性字节,从而得到不同的属性。

80×25模式下,一个显示屏的内容在缓冲区中共占用4000个字节。
显示缓冲区分8页,每页4KB。显示器可以显示任意一页的内容,但一般情况下,显示第0页的内容。通常情况下,B8000H~B8F9FH中的4000个字节的内容将出现在显示器上。
在一页显示缓冲区中:

偏移000H~09FH对应显示器上的第1行(80个字符,占160字节);
偏移0A0H~13FH对应显示器上的第2行;
偏移140H~1DFH对应显示器上的第3行;
……
偏移F00H~1DFH对应显示器上的第25行。

在一行中:

00H~01H单元对应显示器上的第1列;
02H~03H单元对应显示器上的第2列;
04H~05H单元对应显示器上的第3列;
……
9EH~9FH单元对应显示器上的第80列。

以下是一个字符显示示例:

assume cs: codes, ds: datas, ss: stacks
datas segment
    db 'H', 61h, 'e', 03h, 'l', 65h, 'l', 25h, 'o', 07h, ',', 41h
    db ' ', 00h, 'w', 09h, 'o', 41h, 'r', 04h, 'l', 02h, 'd', 61h
datas ends
stacks segment
    db 128 dup (0)
stacks ends
codes segment
start:
    mov ax, stacks
    mov ss, ax
    mov sp, 128  ; set SS:SP to stack bottom
    mov ax, datas
    mov ds, ax
    mov bx, 0    ; set DS:[BX] to data segment
    mov cx, 12   ; view 12 chars
send:
    push [bx]
    add bx, 2
    loop send    ; push chars into stack
    mov ax, 0b800h
    mov ds, ax
    mov bx, 906h ; set DS:[BX] to monitor buffer
    mov cx, 12   ; view 12 chars
print:
    pop [bx]     ; pop 12 chars to monitor buffer
    sub bx, 2
    loop print  
    mov ax, 4c00h
    int 21h
codes ends
end start

它在显示器上第0EH(14)行、23H(35)列(都以0开始计数)处显示“ Hello, world ”,显示的效果为: