1. 过程调用:
1) 即call和ret指令的组合使用,这里我们先介绍call指令的使用方式;
2) 16位段内直接相对近调用:
i. 格式:call near(可省) 标号/立即数;
ii. near就表示近的意思,但是near可以省了,汇编器会默认为是16位段内直接相对近调用;
iii. 直接是指:调用的过程的地址直接由立即数(即一个显示的汇编地址)或者标号(符号化的汇编地址)给出;
iv. 段内:是指只给出了偏移地址而没有给出段地址,因此只能调用同一个段中的过程;
v. 相对:是指不直接用标号或立即数对IP进行赋值,而是给出(在指令的二进制码中给出)目的地和当前跳转指令的下一条指令的汇编地址之差,即一个位移量,这使得程序的浮动性(灵活性)增强;
vi. 16位是指位移量是一个16位的有符号数,因此跳转范围为[-32768, 32767],即最多向前跳32768个字节最多向后跳32767个字节;
3) 16位段内间接绝对近调用:
i. 格式:call r16/m16,其r16表示16位通用寄存器,m16表示16位内存单元;
ii. 间接是指:跳转的地址不是直接给出而是存放在后面指定寄存器或内存中;
iii. 绝对是指:直接将跳转地址值赋给IP而不是计算位移量;
iv. 16位段内是指:偏移地址由16位单元给出,由于只给出了偏移地址而没有段地址因此只能在段内跳转,挑战范围是整个64KB的段空间界限;
4) 16位段内直接相对近转移或间接绝对近转移的使用规范:建议不适用near关键字,这样方便记忆;
5) 16位直接绝对远调用:
i. 格式:call 立即数:立即数,即直接给出"段地址:偏移地址",立即数可以是标号、宏等;
ii. 16位主要是约束偏移地址,即偏移地址只能是16位的,这也是理所应当的;
iii. 直接绝对是指直接给出精确的物理地址(20位物理地址);
iv. 这里的远调用是指由于给出了段地址,就可以全局地在段之间来换跳转了;
6) 16位间接绝对远调用:
i. 格式:call far m32,由于必须给出段地址和偏移地址,同时由于是8086体系不能使用32位寄存器保存地址,因此只能使用32位内存来保存了;
ii. 16位同样是约束偏移地址的;
iii. 间接是指调转地址保存在后面指定的内存中;
iv. 绝对是指直接将内存中的段地址和偏移地址直接赋给cs:ip,同样是低位保存偏移地址高位保存段地址;
v. 最常使用的手法是将跳转地址保存到一个标号所代表的数据区中,调用时直接取标号所在内存中的地址即可:
func_addr dw 0x1020, 0x2000 call far [func_addr]7) ret和retf:这在MASM讲过了,ret对应只给出偏移地址的近调用,retf对应给出全地址的远调用,后者比前者多一个cs的push和pop;
2. 无条件转移指令(和call的格式基本相似):
1) 相对短转移:
i. 格式:jmp short 立即数/标号
ii. 只要是短转移必定都是直接的,即直接给出立即数/标号的偏移地址;
iii. 短转移比近转移的范围还要小,同样也是相对的,即跳转一个位移量,但是范围只有1字节长度,即[-128, 127];
2) 16位直接相对近转移:
i. 格式:jmp near 立即数/标号
ii. 同样也是段内的、位移量的跳转,范围是[-32768, 32767]的16位长度;
3) 16位间接绝对近转移:
i. 格式:jmp near r16/m16
ii. 同样也是段内的、直接对ip赋值的跳转;
!!!注意:以上的短转移和近转移的short和near都可以省略,如果是标号或者立即数,汇编器会自动根据位移量的大小决定使用短转移还是近转移,如果给出的寄存器或内存则只能是间接绝对近转移了;
!短转移和近转移的使用规范:统一不加关键字short和near,这样简便且方便记忆!
4) 16位直接绝对远转移:jmp far i16:i16,其中i16就是指16位立即数,也可以是标号或宏,和16位的远call相对应;
5) 16位简介绝对远转移:jmp far m32,和16位的远call相对应;
3. 对call和jmp越界的检查:
1) 对于间接近转移:由于给出地址的都是寄存器或内存,本身就已经限制在16位了,因此不可能会超出16位长度的跳转范围,因此没有产生超出范围报错的可能,但是CPU是笨的,并不会检查跳转是否超出了逻辑(人定义的)段的范围,比如虽然是在16位限制以内,但不会检查是否从.text段跳到了.data是不会检查的(也许这两个段相距很短);
2) 对于short类型的短转移只检查跳跃范围是否超出[-128, 127],其余逻辑层面上的越界不检查;
3) 对于直接近转移和前面short类型的检查方法一样,只检查跳跃范围处在[-32768, 32767]之内,逻辑层面的不检查;
4) 对于远跳转则什么都不检查,可以随意、任意、全局地跳,即使跳跃范围是在段内也无所谓;
4. $和$$标记:
1) 是在转移指令中常用的两个标记;
2) $表示$所在的当前行的汇编地址,比如jmp $就表示无限循环,即不停地跳转到自己的位置;
3) $$表示$$标记所在的段的起始位置的汇编地址(如果用户有定义的段的话),如果没有定义任何段则整个汇编程序自成一段;