读书笔记《x86 从实模式到保护模式》
16位相对近调用
特点
被调用的目标过程位于当前代码段内,而非另一个不同的代码段,所以只需要提供偏移地址
模式
call near proc_1
near指代这个调用是近调用,这个关键字是可缺省的,不指定则默认为near的近调用
proc_1来自程序中的某个标号,编译阶段proc_1被替换为其所在的汇编地址
解释
这个指令是三字节的指令:
操作码占一个字节,0XE8
操作数占两个字节,为什么?因为一个段的大小为2^16(还记得段要放在16字节对齐的地方),近调用的目标过程只会在这个段内,所以其操作数最大只有两个字节
编译阶段计算这个操作数的过程:proc_1所在的汇编地址减去这条call指令所在的汇编地址再减去3 计算出的值会替换掉proc_1 从而机器码变为:0xE8 计算出的值
当程序执行过程中CS:IP指向了这条指令,发现操作码为0xE8,处理器就知道这是个过程调用的命令,随即将后面的值拿过来加上当前IP的内容,再加上3就得到了一个新的偏移地址
这个地址当然要放入IP让CS:IP能够跳转过去的,但这个动作之前会把IP当前值保存到栈中,最后采用计算出的值替换IP中的内容。
由于计算过程中是两个汇编地址的相减,如果proc_1在这条call指令之前,那么计算出的操作数就是正的,反之则是负数。所以这个操作数是有符号数,其值当然也就是不是0~2^16-1
而是-(2^16)/2 ~ (2^16)/2
16位间接绝对近调用
特点
这种调用过程和16位相对近调用相似,区别在于相对和绝对。相对是计算偏移值,而绝对则是给出了过程所在的绝对汇编地址。过程同样是限制在本段中,不跨段调用。
模式
call cx
call [0x3000]
call [bx]
call [bx+si+0x02]
解释
由于绝对调用需要给出绝对地址,CS段寄存器不变,都是在一个段,IP是要替换的,现将IP寄存器压栈,用操作数替换IP,随后跳转到操作数所在的汇编地址上运行。
间接体现在操作数的获取必须要先访问地址如上面的0x3000取出地址上的值,也就是偏移地址,才能进行跳转
16位直接远调用
特点
和16位间接绝对近调用相似,直接一词说明可以直接给出跳转地址了,远调用说明不仅IP需要提供,CS也需要。
模式
call 0x2000:0x1000
16位间接绝对远调用
特点
间接:跳转地址是间接给出的
绝对:不需要计算偏移
远:可以跨段调用
模式
call far [0x2000]
call far [proc_1]
call far [bx]
call far [bx+si]
....
proc_1 dw 0x0102,0x2000
解释
间接远调用必须加上far关键字
指令中仅仅需要给出保存过程所在绝对汇编地址的标识所在的偏移地址
proc_1所在的汇编地址上保存了两个字:0x0102和0x2000 这就是要跳转的proc_1过程所在的汇编地址
过程返回
过程返回只有两种:
ret和retf
ret负责过程结束将之前压入栈的IP值恢复到IP寄存器
retf要稍微复杂一点,得恢复CS和IP