第9章 转移指令的原理

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

根据转移行为分为两类

  • 段内转移,只修改IP。如:jmp ax
  • 段间转移,同时修改CS和IP。如:jmp 1000:0

同时,根据转移指令对IP的修改范围不同,段内转移有分为短转移和近转移

  • 短转移IP的修改范围是-128~127
  • 近转移IP的修改范围是-32768~32767

0x01 操作符 offset

  操作符的作用是:取得标号的偏移地址。

  如下述程序:

1 assume cs:codesg
2 
3 codesg  segment
4   start:  mov ax,offset start
5       s:    mov ax,offset s
6 codesg ends
7 
8 end start

 

  其中,offset操作符的意思是取得标号start和s的偏移地址。所以,mov ax,offset start 与mov ax,0的效果相同。

0x02 jmp指令

  无条件转移指令,可以只修改IP,也可以同时修改CS和IP。

1. 依据位移进行转移的jmp指令

  格式:

  jmp short 标号(转到标号处执行指令)

  解释:上述指令实现的是段内短转移,它对IP的修改范围为-128~127。向前转移时可以最多越过128字节,向后转移可以最多越过127个字节。

  指令执行完之后,CS:IP应该指向标号处的指令。

  程序1.1

  

1 assume    cs:codesg
2 codesg    segment
3     start:    mov ax,0
4                 jmp short s
5                 add ax,1
6          s:    inc ax
7 codesg ends
8 end start

  当指令执行到jmp short s,将会跳过吓一跳指令即add ax,1 转到执行inc ax。所以最终ax只是加了一个1。

  程序1.2

1 assume    cs:codesg
2 codesg    segment
3     start:  mov ax,0
4             mov bx,0
5             jmp short s
6             add ax,1
7         s:  inc ax
8 codesg ends
9 end start

  在debug中分别运行1.1和1.2 程序之后

  程序1.1

  

  程序1.2

  

  观察到不同的程序中,JMP对应的机器码都是EB03。第一个偏移地址是0008,第二个偏移地址是000B。

  所以,在执行JMP指令时,其机器码中并不包含转移的目的地址,而包含的是转移的位移。

  该位移是编译器根据汇编指令中的“标号”计算出来的。

  CPU执行指令的过程如下:

  (1) 从CS:IP指向内存单元读取指令,读取的指令进入指令缓存器;

  (2) (IP) = (IP) + 所读取指令的长度,从而指向下一条指令;

  (3) 执行指令。转到(1),重复这个过程。

  按照这个步骤,看一下程序1.2中jmp short s指令的读取和执行过程

  (1) (CS)=0772H,(IP)=0006H.CS:IP执行EB 03(jmp对应的机器码)

  (2) 读取指令码EB 03进入指令缓存器

  (3) (IP)=(IP)+所读取指令的长度=(IP) + 2 = 0008H,CS:IP指向add ax,1

  (4) CPU执行指令缓存器中的指令EB 03

  (5) 指令EB 03 执行后,(IP)=000BH,CS:IP 指向inc ax

  如果按照其他机器码的话,CPU执行该指令后,IP指向下一条指令,即此时(IP)=0008H。但是jmp指令后,IP变为000BH,比原来的多了3。这说明,该指令会修改(IP)的大小。

  具体怎么修改,可以看一下下图:

  

  也就是说,"jpm short 标号"指令的功能为:(IP) = (IP) + 8位位移。(等号右边的地址为该条指令执行完之后,下一条指令的偏移地址,1.2中(IP)=0008H)

  注释:这里的8位位移值得是8个二进制位,所以其对应的范围是-128~127。

  具体的计算方法为:标号处的地址-jmp指令后下一条指令所对应的地址

  如程序1.2中,标号处的地址是0772:000B,jmp指令后下一条指令所对应的地址是0772:0008

2.转移的目的地址在指令中的jmp指令

  格式:"jmp far ptr 标号"

  实现的是段间转移,又成为远转移。

  (CS)=标号所在段的段地址;(IP)=标号在段中的偏移地址

  程序2.1

 1 assume cs:code
 2 code segment
 3     start:  mov ax,0
 4             mov bx,0
 5             jmp far ptr s
 6             db 256 dup (0)
 7         s:  add ax,1
 8             inc ax 
 9 code ends
10 end start 

  编译连接后,deubg打开程序

  对应的机器码是:

 

  

  jmp far ptr s 所对应的机器码是: EA 0B 01 72 07

  其中,"0B 01 72 07" 是目的地址在指令中的存储顺序,高地址的"72 07"是转移的段地址:0772H,低地址的"0B 01"是偏移地址:010BH

  查看一下该目的地址对应的指令

  

3. 转移地址在寄存器中的jmp指令

  格式: jmp 16位 reg

  功能:(IP)=(16位 reg)

  通过代码理解下

  程序3.1

 1 assume cs:code
 2 code segment
 3     start:  mov ax,1
 4             mov bx,ds
 5             add ax,bx
 6             jmp ax           
 7             mov ax,4c00h
 8             int 21h
 9 code ends
10 end start 

  debug后,看一下指令对应的机器码

4.转移地址在内存中的jmp指令

(1) jmp word ptr 内存单元地址(段内转移)

  功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。

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

  情形一:

  mov ax,0001H

  mov ds:[0],ax

  jmp word ptr ds:[0]

  结果,(IP)=0001H

  情形二:

  mov ax,0123H

  mov [bx],ax

  jmp word ptr [bx]

  执行后,(IP)=0123H

(2) jmp dword ptr 内存单元地址(段间转移)

  功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址

  (CS)=(内存单元地址+2)

  (IP)=(内存单元地址)

  如:

  mov ax,0123H

  mov ds:[0],ax

  mov word ptr ds:[2],0

  jmp dword ptr ds:[0]

  执行后,(CS)=0,(IP)=0123H,CS:IP指向0000:0123

0x02 jcxz 指令

  jcxz 指令为有条件转移指令,属于段内转移中的短转移。

  格式: jcxz 标号(如果(cx)=0,转移到标号处执行。)

  操作:当(CX)=0时,(IP)=(IP)+8位位移

                 当(CX)≠0时,程序向下执行

  程序4.1

 1 assume cs:code
 2 code segment
 3     start:  
 4             mov bx,0
 5         s:  mov ch,0
 6             mov cl,[bx]
 7             jcxz ok
 8             inc bx
 9             jmp short s
10             ok: mov dx,bx
11                 mov ax,4c00h
12                 int 21h
13 code ends
14 end start

  该程序目的是,实现在ds对应的内存地址中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。  

  编译链接,在debug中打开

  先查看下,ds对应的内存中内容

  

 

 

  即内存中ds:0004中的内容为00

  截至运行知道,查找到第一个值为0的字节

  

 

  

  dx中的内容,即为对应的偏移地址

0x03 loop指令

  loop 指令为循环指令,所有的循环指令都是短转移。

  对应的机器码中包含转移的位移,而不是目的地址。

  对IP的修改范围:-128-127

  格式:loop 标号 ((cx)=(cx)-1,如果(cx)≠0,转移到标号处执行。)

  操作:

  (1) (cx)=(cx)-1;

  (2) 如果(cx)≠0,(IP)=(IP)+8位位移

  如果(cx)=0,什么也不做(程序向下执行)

  loop 标号 的功能相当于:

  (cx)--;

  if ((cx)≠0) jmp short 标号;

0x04 其他

1. 根据位移进行转移的意义

  更具位移进行转移的话,使用起来更加灵活。比如说下面的程序

  s:  add ax,ax

      loop s

  假如现在使用标识号的地址进行定位的。想要准确的跳转到s指令处,就需要对环境进行严格的限定,比如说,代码段的地址等

  而使用位移进行转移的话,不需要这些额外的要求。

2.编译器对转移位移超界的检测

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

 

posted @ 2018-12-31 16:08  justn0w  阅读(318)  评论(0)    收藏  举报