转移指令:
可以修改IP,或者同时修改CS和IP的指令 称为转移指令。
只修改IP时,称为段内转移,段内转移根据IP的修改范围又分为短转移(short)和近转移(near);短转移IP的修改范围为8位补码表示的范围:-128~127.近转移IP的修改范围为16位补码表示的范围:-32768~32767(向前为负,向后为正)
同时修改IP和CS时,称为段间转移,又称远转移(far)。
转移指令分类:
- 无条件转移指令,jmp,其他转移指令大多可以基于jmp写出
- 有条件转移指令,jcxz
- 循环转移指令,loop
- 过程
- 中断
操作符offset:
offset的功能是获取标号的偏移地址EA,标号指的是s、start、data一类的名称。
无条件转移指令jmp:
jmp给出的两种信息:
- 转移的目的地址,由标号给出
- 转移的距离(段间转移,段内短转移short,段内近转移near)
- 短转移、近转移jmp指令
jmp short 标号 (该指令本身占两个字节)翻译成机器码为 EBXX,XX为转移位移量的补码表示,向前为负向后为正。没有表达出绝对的目的地址,只给出了相对的位移。
位移量XX = 标号处的地址 - jmp指令后一个字节的地址,short指明位移量为8位。(IP)=(IP)+ XX()8位位移
类似的还有 jmp near ptr 标号 (也可写成jmp s 省略near ptr)(该指令本身占三个字节)翻译成机器码为 E9XXXX 其位移量用两个字节表示,ptr可以看作是长度声明。(IP)=(IP) + XXXX 16位位移
2.远转移jmp指令
jmp far ptr 标号 (该指令本身占五个字节)翻译成机器码为 EAXXXX YYYY,XXXX为偏移地址,前两个X为低位,后两个X为高位;YYYY为段地址,前两个Y为低位,后两个Y为高位。
向前转移:
编译器中有一个地址计数器AC,编译器读到标号s时记下AC的值as,读到jmp时记下AC的值aj,再用aj - ac算出位移量disp
- -128 < disp < 127 时,近转移、远转移统统转化成短转移,机器码为EB disp(占两个字节)
- disp超出上述范围,得用16位补码表示时,短转移将产生编译错误,近转移和远转移正常执行
向后转移:
向后转移时,编译器先读到jmp指令,记下aj,但没有as,一时无法计算位移量disp,这时会对jmp指令进行一个预处理,预处理不管转移类型,统一当作短转移,但预留的空间不同
- 对于短转移,编译器生成EB和1个nop指令,相当于预留一字节,用于存放8位disp
- 对于近转移,编译器生成EB和2个nop指令,相当于预留两字节,用于存放16位disp
- 对于远转移,编译器生成EB和4个nop指令,相当于预留四字节,用于存放段地址和偏移地址
当编译器往后读到as时,计算disp = as - aj
- -128 < disp < 127 时,近转移、远转移统统转化成短转移,机器码为EB disp,多余的预留空间闲置
- disp超出上述范围,得用16位补码表示时,短转移将产生编译错误,近转移和远转移正常执行,在预留的位置添上相应代码即可
3.转移信息在寄存器或者内存中的jmp指令
jmp 16位寄存器(只能是16位寄存器,因为相当于mov ip ,res,寄存器位数要对应)。在Debug中还可以使用 jmp XXXX:YYYY格式直接修改CS和IP,但编译器无法识别。
jmp word ptr 内存单元地址 执行后,(IP) = (内存单元地址),指的是内存单元地址中的内容赋给IP,(两个字节)例如对应内容为0123H,那么IP = 0123H。只改变IP,是段内转移。
jmp dword ptr 内存单元地址 执行后,(IP)= (内存单元地址)(CS)= (内存单元地址+2),都是赋给其中的内容,(四个字节)低地址赋给IP,高地址赋给CS。改变IP和CS,是段间转移。
jcxz条件转移指令:
jcxz 标号 (如果(cx)=0,执行跳转指令,(cx)不为0时,跳过该指令)所有的条件转移指令都是短转移类型,机器码中包含的是8位位移。用C语言等价描述为 if ((cx) == 0) jmp short 标号
loop循环指令:
loop 标号 (先执行(cx)= (cx) - 1 ,再判断如果(cx) ≠0,修改IP转移到标号处执行,(CX)= 0时跳过指令往下执行)所有的循环指令都是短转移类型。用C语言等价描述为 (cx)--; if ((cx) != 0) jmp short 标号