在80x86中有两种指令可以改变程序执行流程,一种是jmp还有一种就是call
call指令由四种调用:两种近调用和两种远调用
(1)相对进调用
(2)直接绝对近调用
(3)间接绝对远调用
(4)直接绝对远调用##############################################################
相对近调用:
近的意思是目标函数的地址与当前指令在同一个段中,即不用改变段基址,只需给出段内偏移地址,相对的意思是指段内偏移地址是相对与call指令而言的相对地址
指令格式:
call near 立即数地址
call near near_proc
jmp $
addr dd 4
near_proc:
mov ax,0x1234
ret假如near_proc编译后被分配的地址是0x5678,那么call指令调用的操作数并不是0x5678,而是0x5678-call指令所在起始地址-3字节(call指令本身占3个字节)
既然是相对量,那就有正负之分,如果目标函数地址比call指令所在地址大,相对量即为正数,否则为负数,由于段是个16位大小的空间,所以相对量的取值范围是-32768~32768
没有加直接二字是因为CPU最后还是需要将这个相对地址算成绝对地址
#############################################################
间接绝对近调用
间接的意思是目标函数的地址不是以立即数的形式给出而是需要从内存或寄存器中取出,绝对的意思是目标函数的地址是绝对地址,不是前面的相对地址
指令格式:
call near 寄存器 或 call near 内存地址
section call_test vstart=0x900
mov word[addr],near_proc
call [addr]
mov ax,near_proc
call ax
jmp $
addr dd 4
near_proc:
mov ax,0x1234
ret由于是近调用,段地址相同,所以直接把IP寄存器的值入栈保存,把新的值赋给IP即可
##############################################################
直接绝对远调用
远调用指的是目标函数地址与当前指令不再同一个段内,需要跨段调用
指令格式:
call far 段基址(立即数):段内偏移地址(立即数)
section call_test vstart=0x900
call 0:far_proc
jmp $
far_proc:
mov ax,0x1234
retf由于目标函数地址与当前指令不再同一个段内,所以要先把CS寄存器值入栈保存,再把IP寄存器值入栈保存,把新的值赋给CS:IP
间接绝对远调用
指令格式:call far 内存寻址
section call_test vstart=0x900
call far [addr]
jmp $
addr dw far_proc,0
far_proc:
mov ax,0x1234
retfcall far [0x1234],将默认的段基址ds*16再与0x1234相加得到物理地址,再用该物理地址去新的段基址和段内偏移地址,以该物理地址为起始的2个字节是段内偏移地址,以该物理地址+2为起始的2个字节是段基址