可以修改 IP,或同时修改 CS 和 IP 的指令统称为转移指令。控制 CPU 执行内存某处代码的指令。
8086CPU 转移行为:
- 段内转移:只修改 IP,例:jmp ax。
- 段间转移:同时修改 CS 和 IP,例:jmp 1000:0。
段内转移分短转移和近转移。
- 短转移 IP 的修改范围:-128 ~ 127
- 近转移 IP 的修改范围为:-32768 ~ 32767
8086CPU 转移指令分类:
- 无条件转移指令,例:jmp
- 条件转移指令
- 循环指令,例:loop
- 过程
- 中断
操作符 offset
offset 是由编译器处理的符号,用于取得标号的偏移地址。
1 | cs:codesg |
offset 操作符取得标号 start、s 的偏移地址 0 和 3。
jmp 指令
jmp 为无条件转移指令,可以只修改 IP 也可以同时修改 CS 和 IP。
jmp 指令要给出两种信息:
- 转移的目的地址
- 转移的距离
根据位移进行转移的 jmp 指令
转到标号处执行指令:
1 | jmp short 标号 |
实现的是段内短转移,对 IP 的修改范围为 -128 ~ 127,向前转移可以最多越过 128 个字节,向后转移可以最多越过 127 个字节。
short 符号表示进行的是短转移,「标号」指的是代码段中的标号,转移指令结束后,CS:IP 应该指向标号处的指令。
1 | cs:codesg |
jmp short 标号
指令的机器码中不包含转移的目的地址,包含的是 CPU 要转移的位移。位移是编译器根据汇编指令中的标号计算出来的。
jmp short 标号
的功能为:(IP) = (IP) + 8 位位移。
- 8 位位移 = 标号处的地址 - jmp 指令后第一个字节的地址。(因为运行了 jmp 指令后 IP 会指向下一条指令的第一个字节)
- short 指明此处的位移为 8 位位移
- 8 位位移的范围是 -128 ~ 127,用补码表示
- 8 位位移由编译程序在编译时算出
段内近转移指令格式 jmp near ptr 标号
。
功能为:(IP) = (IP) + 16 位位移。
- 16 位位移 = 标号处的地址 - jmp 指令后第一个字节的地址。(因为运行了 jmp 指令后 IP 会指向下一条指令的第一个字节)
- near ptr 指明此处的位移为 16 位位移,进行的是段内近转移
- 16 位位移的范围是 -32768 ~ 32767,用补码表示
- 16 位位移由编译程序在编译时算出
转移的目的地址在指令中的 jmp 指令
jmp far ptr 标号
实现的是段间转移,又称为远转移。
功能为:(CS) = 标号所在段的段地址;(IP) = 标号所在段的偏移地址。
far ptr
指明了指令用标号的段地址和偏移地址修改 CS 和 IP。
示例程序:
1 | cs:codesg |
jmp far ptr s
对应的机器码包含转移的目的地址。
转移地址在寄存器中的 jmp 指令
指令格式:jmp 16 位 reg
功能:(IP) = (16 位 reg)
转移地址在内存中的 jmp 指令
jmp word ptr 内存单元地址(段内转移)
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
jmp dword ptr 内存单元地址(段间转移)
功能:内存单元地址开始存放着两个字,高地址处的字是转移的目的段地址(CS),低地址处是转移的目的偏移地址(IP)。
(CS) = (内存单元地址 + 2)
(IP) = (内存单元地址)
jcxz 指令
jcxz 指令是有条件转移指令,所有的有条件转移指令都是短转移,对应的机器码中包含转移的位移,而不是目的地址。对 IP 的修改范围都为:-128 ~ 127。
指令格式:jcxz 标号(如果 (cx) = 0 则跳转到标号处执行。)
操作:当 (cx) = 0 时,(IP) = (IP) + 8 位位移。
- 8 位位移 = 标号处的地址 - jcxz 指令后第一个字节的地址。(因为运行了 jmp 指令后 IP 会指向下一条指令的第一个字节)
- 8 位位移的范围是 -128 ~ 127,用补码表示
- 8 位位移由编译程序在编译时算出
当 (cx) ≠ 0 时,程序继续向下运行,什么也不做。
jcxz 标号
的功能相当于:if((cx) == 0) jmp short 标号
loop 指令
loop 指令为循环指令,所有的循环指令都是短转移,对应的机器码中包含转移的位移,而不是目的地址。对 IP 的修改范围都为:-128 ~ 127。
指令格式:loop 标号((cx) = (cx) - 1,如果 (cx) ≠ 0,转移到标号处执行。
操作:
- (cx) = (cx) - 1
- 如果 (cx) ≠ 0,(IP) = (IP) + 8 位位移。
如果 (cx) = 0,程序向下执行。
loop 标号
相当于:
1 | (cx)--; |
根据位移进行转移的意义
jmp short 标号
jmp near ptr 标号
jcxz 标号
loop 标号
几种汇编指令对 IP 的修改是根据转移目的地址和转移起始地址之间的位移来进行的。机器码中不包含转移的目的地址,包含的是到目的地址的位移。方便程序段在内存中的浮动装配。
编译器对转移位移超界的检测
根据位移进行转移的指令,如果在源程序中出现了转移范围超界的问题,编译的时候,编译器将报错。
形如 jmp 2000:0100
的转移指令只能在 debug 里面使用,汇编编译器并不认识,在源程序中使用的话编译器会报错。
分析一个奇怪的程序
1 | cs:codesg |
这个程序说明了短转移指令的机器码中包含的是位移,不包含目的地址,所有的转移根据位移来进行。s2 处的机器码为 BEF6,BE 代表转移,F6 是位移,补码,相当于 -10,表示向前转移 10 个字节。
当程序执行到 jmp short s
时,会跳转到 s 标号处执行,执行的机器指令是 BEF6,含义是向前转移 10 个字节,转移到了 codesg 段,执行终止退出命令,所以这个程序能正常退出。
在显示器上输出彩色字符
80 x 25 彩色字符模式显示缓冲区的结构:
向内存空间 B8000H ~ B8FFFFH 写入数据,写入的内容会立即出现在显示器上。
显示缓冲区分为 8 页,每页 4KB,显示器可以显示任意一页的内容,一般显示第 0 页的内容,B8000H ~ B8F9FH 中的 4000 个字节内容将出现在显示器上。
一个字符占两个字节存储空间,低位字节存储字符的 ASCII 码,高位字节存储字符的属性。
属性字节的格式:
位 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
含义 | 闪烁 | 背景色 R | 背景色 G | 背景色 B | 高亮 | 前景色 R | 前景色 G | 前景色 B |
1 | cs:codesg |