第九章 转移指令

简介

转移指令可以理解为转移程序执行位置的指令。转移指令通常会修改IP或(IPCS)。

转移指令分类

无条件转移指令(jmp)

其使用方式根据跳转的距离(修改IP的范围)分为三种

  1. 段内短转移——跳转的IP范围为 -128~127
    • jmp [short] 标号
    • jmp (16位reg)
    • jmp word ptr 内存单元地址
  2. 段内近转移——跳转的IP范围为 -32768~32767
    • jmp [near] 标号
    • jmp (16位reg)
    • jmp word ptr 内存单元地址
  3. 段间转移——没有限制
    • jmp far ptr 标号
    • jmp dword ptr 内存单元地址

段内短转移指令分析

其中带有[]内的内容其实可以忽略,因为这个大多数是用于编译器检查的;如果不加支持两种范围的段内转移
大家可以试试这段代码验证一下猜想

assume cs:codesg

codesg segment
    mov ax, 32767
    ; 使用下面这行代码就会报错
    ; jmp short temp 
    ; 使用下面这行代码就不会报错,但是会有个警告,说接近64K(即65536)
    jmp temp
    db 65535 dup (0)

temp:

    mov ax,4c00H
    int 21H

codesg ends

end

段内近转移指令分析

第二种指令仅支持 16位reg ,大家也不用考虑 8位reg~~~;第二种指令其实和第一种的原理是一样的,后续讲解原理的时候会讲到。

段间转移指令分析

第三种指令对于段内转移来说就是换一种方式取数据;而对于段间转移的话,高位地址保存CS数值;低位地址保存IP的数值

段内转移原理

段内转移的debug图
注意jmp指令,在汇编代码里是jmp 0004,而在二进制里是EB02,为什么这里是02,而不是04呢?
对于段内转移来说,jmp指令是根据偏移量来定位的,比如上述的例子:jmp指令后的第一条指令与标号之间的偏移量,也就是——(076A:0004 - 076A:0002 = 02

段间转移原理

段间转移的debug图
注意此处加入了一行db 128 dup (0)指令,主要是让标号temp超出段内短转移的范围(否则即使使用jmp far ptr 标号,编译器也会进行优化。)
这里的表示方法就比较简单粗暴,易于看懂,这里就不多加解释了。

有条件转移指令(jcxz、jne、je等等)

有条件转移指令包含了以下几个:

  1. jcxz:当 cx==0时,跳转到指定标号处
  2. jne:当 zf==0时(两个数不相等时),跳转到指定标号处
  3. je:当zf==1时(两个数相等时),跳转到指定标号处
  4. jb:当cf==1时(第一个数小于第二个数),跳转到指定标号处
  5. jnb:当cf==0时(第一个数不小于第二个数),跳转到指定标号处
  6. ja:当cf0&&zf0(第一个数大于第二个数),跳转到标号处
  7. jna:当cf0||zf1(第一个数不大于第二个数),跳转到标号处

这里着重分析第一条jcxz指令,该指令是当cx==0时,跳转到标号处的指令,该指令的操作数范围为 -128~127,可以理解为带有条件的jmp short 标号,操作数范围为 -128~127

循环指令(loop)

loop指令主要执行以下操作:

  1. --cx
  2. if(cx != 0) 跳转到标号处执行
  3. if(cx == 0) 继续向下执行
    该指令是短转移(所有的循环指令都是短转移),在对应的机器码中包含转移的位移而不是目的地址,操作数范围为 -128~127

注意点

如果对 偏移在-128~127之间的标号使用 偏移距离大于127的转移指令(段内近转移或者段间转移),就会生成nop(可以理解为对齐吧),看下面的示意图

对齐策略

这里纯属个人猜测:由于jmp near ptr 标号的范围是 -32768~32767(FFFF) ,所以编译器对于范围在 -128~127内的偏移量会自动进行转换,比如 段内近转移一般要3个字节,段内短转移只需要2个字节,所以使用段内近转移表示段内短转移的偏移量,会多生成一个字节凑够3个字节

课后检测点

第九章检测点

posted @ 2019-06-02 16:38  CoDeleven  阅读(1008)  评论(0编辑  收藏  举报