第9章 转移指令的原理
**可以修改CS和IP的指令叫做转移指令。**我们在前面已经学习过转移指令比如loop指令,这章主要介绍jmp指令,也叫做无条件转移指令
9.1 操作符 offset
offset操作符可以取得所在处离标号的偏移地址,如:
start:mov ax,offset start
mov ax,offset s
s: mov ax,[bx]
第一条指令取标号start的偏移地址,为0
第二条指令取标号s的偏移地址,因为mov ax,offset s 这条指令占3个字节,所以offset s 是3,偏移3个字节转移到目标标号处
在问题9.1中出现了nop指令,nop指令占一个字节但是什么都不会做
9.2 jmp指令
9.3根据位移转移的jmp指令
9.4 转移的目的地址在指令中的jmp指令
格式 范围 实现的功能
段内转移:
1.jmp short 标号 -128~127 短转移
2.jmp near ptr 标号 -32768~32767 近转移
段间转移:
3.jmp far ptr 标号 不同段之间 远转移(段间转移)
会有一个误区便是以为使用转移指令会需要转移的目标地址,实际上和offset操作符一样,jmp段内转移指令也是提供到标号的偏移位移即可
这体现在转移指令对应的机器码上,比如jmp short s指令对应的机器码是EB 03,其中的03就是指偏移3个字节。
而远转移指令对应的机器码则是包含目标地址, 否则无法确定目标地址是何处,毕竟我们的内存数据不是完全按顺序存放的。如0BBD:010B,表示的是转移到段地址是BD0B,偏移地址是010B处。
如果在使用过程中用转移指令去转移超出范围的距离则会出错, 比如用jmp short 指令去转移超出[-128,127]的距离就会报错
9.5 转移指令在寄存器中的jmp指令
jmp指令生效之后跳转到目标地址后,如果是向后转移,在jmp指令和目标地址之间的指令将不会生效!
9.6 转移地址在内存中的jmp指令
在这里书上介绍了两类jmp在内存中的使用情况:
1.段内转移-->jmp word ptr 内存单元地址
2.段间转移-->jmp dword ptr 内存单元地址
jmp word ptr 内存单元 作为段内转移只需要取一个字作为偏移地址
jmp dword ptr 内存单元 作为段间转移需要取两个字,高位的作为段地址,地位字内容作为偏移地址
在这里介绍一下其中涉及到的word和dword知识点:
sdword -->32位整数
dword -->32位无符号整数
sword -->16位整数
word -->16无符号整数
检测点9.1
(1)db 2 dup(0)
(2)0或bx
cs
9.7 jcxz指令
之前介绍的jmp指令也叫无条件转移指令,完善的计算机当然也会有与之对应的有条件转移指令,jcxz指令就是一种短转移条件指令,当cx=0时 jcxz指令生效, 值得注意的是,所有条件转移指令都是短转移指令, 比如我们之前已经遇见的loop指令。
可能会出现的一个误区,认为jmp指令中的段内转移是段转移,这个是错误的,jmp short 标号是短转移,而jmp near ptr 标号是近转移,短转移的范围都是-128~127之间
检测点9.2
s:mov cl,[bx]
mov ch,0
jcxz ok
inc bx
9.8 loop指令
loop指令是条件转移指令,也是循环指令,所有的循环指令都是短转移指令
loop指令在书的前面我们已经接触过了,loop指令需要转移的条件是cx!=0,当cx!=0时,先cx=cx-1再执行loop指令到目标地址。
检测点9.3
inc cx
9.9 根据位移进行转移的意义
jmp指令短内转移,jcxz指令以及loop指令都是得到偏移地址进行转移操作,如果loop s指令的机器码使用目标地址,结果标号s不在目标地址处就会引发错误,而使用偏移地址的话无论是否出现上面的现象指令都可以按偏移地址执行
9.10编译器对转移位移超界的检测
一如上面所讲,如果用jmp短转移指令执行偏移距离超过其范围时就会引发报错
实验8
实验9
关于80×25彩色字符模式显示及其他相关知识我就不在这里赘述了(书上介绍了),直接附上我写的答案,不太清楚的可以留言哦!
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 'welcome to masm!'
db 2,36,113 ;这是三种颜色对应的数据
datasg ends
stacksg segment
dw 0,0,0,0,0,0,0,0 ;我们创建一个栈来保存最外层的cx值
stacksg ends
codesg segment
start:mov ax,datasg
mov ds,ax
mov ax,stacksg
mov ss,ax
mov sp,16
mov ax,0B800H ;缓冲区地址
mov es,ax
mov bx,0 ;bx来指向我们需要输入的字符
mov di,16 ;di指向颜色对应的数据
mov si,160*12+128 ;高位放属性低位放字符,那么一行80字符160字节,我们的字符一共16个占32
;字节,160-24=128,所以结果会显示在最右边,题目说的是中间大家可以自己改一下
mov cx,3 ;最外层循环次数,我们一共显示三次三种颜色
s:push cx ;外层cx压入栈
mov cx,16 ;内层cx=16,我们一共16个字符
mov dh,ds:[di] ;将颜色放到高位dh,待会将字符放到低位dl,再一共放到缓冲区内存里
s1:mov dl,ds:[bx]
mov es:[si],dx
add si,2 ;放到缓冲区内存之后开始准备下一个字符的存放位置
inc bx
loop s1
add si,128 ;我们设置好了绿色的字符串,把si加上128到下一行去
sub bx,bx ;bx置0,指向第一个字符
inc di ;di加1,取第二种颜色
pop cx ;取出外层循环cx值,然后loop指令回去
loop s
mov ax,4c00h
int 21h
codesg ends
end start
放一张结果图: