第9章 转移指令的原理
一、8086转移指令的分类
1、无条件转移指令,如jmp;
2、条件转移指令,如jcxz;
3、循环指令,如loop;
4、过程;
5、中断
二、几种转移指令的详解
*基础知识:补码
在计算机系统中,数值一律用补码来表示(存储)。正数补码与原码相同,如十进制17;原码为0001 0001;其补码也为0001 0001;
负数的补码最高位取1,剩余7位为将负数取绝对值按位取反后+1,得其补码(对8位补码)。如-1;最高位取1,绝对值7位为0000001,按位取反后为1111110;+1后为1111111;则-1的补码为11111111.
也可知,对8位补码,其可表示的数值范围为-128~127;对16位补码其表示范围为-32768~32767.
*offset操作符:offset 标号 表示:获取标号位置处的偏移地址。
1、段内短转移:jmp short 标号
其仅对ip值进行修改;修改范围是-128~127(往前128个字节,往后127个字节);
在机器码中,jmp short 标号对应的是使用位移来寻址,该语句告诉CPU的并不是目的地址,而是基于当前ip的位移量。
如下指令及设其ip对应如下:
mov ax,0--------IP:a1
mov bx,0--------IP:a1+3
jmp short s--------IP:a1+6
add ax,1--------IP:b1
s:add ax,2--------IP:b2
当ip=a1+6时候,CPU读取jmp short s进入指令缓冲区;ip指向下一条指令,即ip=b1;然后执行jmp short s;执行完毕后指令指向标号s处,即ip=b2;其位移量为(b2-b1);通过上述分析可知,位移量应为(目标偏移地址减去jmp指令下一条指令的偏移地址)。
也因此,jmp short s的功能为:(IP)=(IP)+8位位移量(位移量的计算是在编译过程中计算出的)。以上例具体来说位移量为b2-b1.而执行完jmp指令后的ip=b1;即新的(ip)=b2-b1+b1=b2。
2、段内近转移:jmp near ptr 标号;
其功能与段内短转移类似,表达为:(IP)=(IP)+16位位移量
3、不使用位移量转移而直接指定转移目的地址的jmp指令
(1)转移目的地址在指令中的jmp指令
段间转移(远转移):jmp far ptr 标号
表达为:(CS)=标号所在段的段地址;(IP)=标号所在位置的偏移地址。
(2)转移地址在寄存器中的jmp指令:jmp 16位reg
表达为:(IP)=(16位reg)
(3)转移地址在内存中的jmp指令:jmp word/dword ptr 内存单元地址
如:jmp word ptr ds:[0]
功能为:CS不变,(IP)=(ds:[0])
如:jmp dword ptr ds:[0]
功能为:(CS)=(ds:[2]),(IP)=(ds:[0])
4、条件转移指令:jcxz 标号
表达为:if((cx)==0) jmp short 标号
注意:所有的条件转移均为短转移。即位移量为-128~127.
5、循环指令loop 标号
表达为:
cx=cx-1;
if ((cx)!=0) jmp short 标号
注意:所有的循环转移也均为短转移。即位移量为-128~127.
三、通过位移量确定转移地址的几个指令
总共有4类,jmp型的有两种:
(1)jmp short 标号
(2)jmp near ptr 标号
另外等价的还有两种:
(3)jcxz 标号:等价于 if(!(cx)) jmp short 标号
(4)loop 标号:等价于:先(cx)=(cx)-1;再if((cx)) jmp short标号
检测点9.1
(1)要使程序中jmp指令执行后,cs:ip指向程序第一条指令,data段该如何定义。
分析:jmp word ptr []使用的是直接给出偏移地址,即这里ds:[bx+1]的值要为0.
对于data段来说,就是第二个内存单元值为0,对其他无所谓。
assume cs:code data segment db 0,0 data ends code segment start:mov ax,data mov ds,ax mov bx,0 jmp word ptr [bx+1] code ends
(2)补全程序,使得jmp执行后,cs:ip指向程序第一条指令。
分析:jmp dword ptr ds:[0]设置的是(cs)=(ds:[2]);(ip)=(ds:[0])。
assume cs:code data segment dd 12345678H data ends code segment start: mov ax, data mov ds, ax mov bx, 0 mov [bx],bx mov [bx+2], cs jmp word ptr ds:[0] mov ax, 4c00h int 21h code ends end start
检测点9.2
补全程序,利用jcxz指令,在内存2000H段中查找第一个为0的单元,将其偏移地址存储在dx中。
assume cs:code code segment start:mov ax,2000h mov ds,ax mov bx,0 s: mov cl,ds:[bx]; mov ch,0; jcxz ok; inc bx; jmp short s ok: mov dx,bx mov ax ,4c00h int 21h code ends end start
检测点9.3
补全程序,利用loop指令,实现在内存2000H段中查找第一个为0的单元,将其偏移地址存储在dx中。
assume cs:code code segment start: mov ax,2000H mov ds,ax mov bx,0 s: mov cl,[bx] mov ch,0 inc cx ;自增1满足loop跳出条件 inc bx loop s ok: dec bx mov dx,bx mov ax,4c00h int 21h code ends end start
实验8 分析一个奇怪的程序
assume cs:codesg codesg segment mov ax,4c00h ;A int 21h ;B start mov ax,0 s: nop ;C nop ;D mov di,offset s ;E mov si,offset s2 mov ax,cs:[si] mov cs:[di],ax ;把s2处的jmp short s1代码复制到s处,而该jmp代码实质是偏移-(x+2)个字节单位。 s0: jmp short s s1: mov ax,0 int 21h mov ax,0 ;设s1开始的这三句占据x字节 s2: jmp short s1 ;这句jmp本身占据2字节,则此处实质偏移量为-(x+2) nop codesg ends end start ;先从start入口开始执行,到F处执行完成后就是使得s标号处的代码变成了jmp指令 ;继续往下执行到s0标号处,执行完跳转到标号s处 ;此时s处的代码已经更新为jmp指令,该指令实质为往前偏移(x+2)个单元。 ;可以看出A到E中间的代码长度和s1到s2处的nop的长度是一样的。所以执行s处的代码后,跳转到A处 ;执行A,B;退出程序返回