引言
call指令是转移指令,CPU执行call指令,进行两步操作:
(1)将当前IP或当前CS和IP压入栈中
(2)转移。call指令不能短转移,除此之外,call指令转移的方法跟jmp指令的原理相同。
1. call 标号
call 标号 是根据位移进行进转移的call指令,实现的是段内转移,指令功能:将当前IP压入栈中,然后转移到标号处执行指令。其对寄存器操作的原理如下:
(1)(sp) = (sp) - 2 ;栈顶开辟2个字节的空间
((ss)*16+(sp)) = (IP) ;栈顶的值 = (IP)
(2)(IP) = (IP) + 16位位移 ;修改IP值
tips:
16位位移 = 标号处的地址 - call指令后的下一条指令的首地址
16位位移用补码的形式表示,范围在 -32768 ~ 32767
16位位移由编译器编译时算出
所以,CPU执行call 标号指令时,相当于执行:
(1)push IP
(2)jmp near ptr 标号
assume cs:code, ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
start:
mov ax, 0
call s ;执行该指令的内部逻辑步骤:(1) pop IP(即指向inc ax指令的首地址);
; (2)IP = IP + (s标号处指令的首地址 - call s指令的下一条指令(即 inc ax指令)的首地址)
inc ax
s:
pop ax
mov ax, 4c00h
int 21h
code ends
end start
从以上运行结果分析
(1)16位位移 = s标号处指令的首地址 - call s指令的下一条指令的首地址 = 0007h - 0006h = 0001h
(2)call s,编译成 call 0007,对应的机器码:E80100(低字节序),其中最低位:E8是操作码,0001是16位位移
(3)执行 call s 指令,IP = 0006h压入栈,然后 IP = IP + (0007h - 0006h) = 0006h + 0001h = 0007h
(4)程序转移到s标号处,即pop ax 处执行,得到:ax = 0006h
2. call far ptr 标号
call far ptr 标号 是转移的目的地址在指令中的call指令,实现的是段间转移,指令功能:将当前CS压入栈中,然后再将当前IP压入栈中,最后转移到标号处执行指令。其对寄存器操作的原理如下:
(1)(sp) = (sp) - 2 ;栈顶开辟2个字节的空间
((ss)*16+(sp)) = (CS) ;当前栈顶的值 = (CS)
(sp) = (sp) - 2 ;栈顶再开辟2个字节的空间
((ss)*16+(sp)) = (IP) ;当前栈顶的值 = (IP)
(2)(CS) = 标号所在段的段地址
(IP) = 标号在段中的偏移地址
所以,CPU执行call far ptr 标号指令时,相当于执行:
(1)push CS
push IP
(2)jmp far ptr 标号
assume cs:code, ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
start:
;初始化栈
mov ax, stack ;ax = 204D
mov ss, ax ;初始化栈:设置栈段地址ss = 204D
mov sp, 16 ;设置栈顶地址sp = 16
mov ax, 0
call far ptr s ;(1)push CS (2)push IP (3)CPU转移到标号S处执行指令
inc ax
s:
pop ax ;IP的值出栈
add ax, ax
pop bx ;CS的值出栈
add ax, bx
mov ax, 4c00h
int 21h
code ends
end start
(1)程序分析
程序包括16个字节的栈段(stack segment ... stack end)和代码段 (code segment ... code ends) 。end start 指明程序开始执行时,从代码段的 start 标号处开始执行,start标号在代码段中的首地址处,所以 IP = 0000h
(2)代码执行过程分析:
a) 调试程序(父进程)把我们的程序(子进程)加载进内存,并设置CS:IP = 204E:0000,CPU开始执行我们的指令代码。
b) mov ax, stack ;ax = 204Dh
mov ss, ax ;初始化栈:设置栈段地址ss = 204Dh
mov sp, 16 ;设置栈顶地址sp = 16
c) mov ax, 0 ; ax = 0h
call far ptr s ; (1)push CS (2) push IP (3)CPU转移到标号S处执行指令
inc ax
d) s:
pop ax ;IP的值出栈,ax = 0010h
add ax, ax ; ax = 0020h
pop bx ;CS的值出栈,bx = 204Eh
add ax, bx ; ax = ax + bx = 0020h + 204Eh = 206Eh
3. call 16位寄存器
call 16位寄存器 是转移的目的地址在寄存器中的call指令,实现的是段内转移,指令功能:将当前IP压入栈中,然后转移到寄存器中指明的目的地址处执行指令。其对寄存器操作的原理如下:
(1)(sp) = (sp) - 2 ;栈顶开辟2个字节的空间
((ss)*16+(sp)) = (IP) ;栈顶的值 = (IP)
(2)(IP) = (16位寄存器) ;修改IP值
CPU执行call 16位寄存器指令时,相当于执行:
(1)push IP
(2)jmp 16位寄存器
assume cs:code, ss:stack
stack segment
db 16 dup (0)
stack ends
code segment
start:
;初始化栈
mov ax, stack
mov ss, ax
mov sp, 16
mov ax, 14
call ax ;(1)push IP (2)CPU转到 (ax寄存器) 处执行指令
inc ax
mov bp, sp
add ax, [bp]
mov ax, 4c00h
int 21h
code ends
end start
(1)程序分析
程序包括16个字节的栈段(stack segment ... stack end)和代码段 (code segment ... code ends) 。end start 指明程序开始执行时,从代码段的 start 标号处开始执行,start标号在代码段中的首地址处,所以 IP = 0000h
(2)代码执行过程分析:
a) 调试程序(父进程)把我们的程序(子进程)加载进内存,并设置CS:IP = 204E:0000,CPU开始执行我们的指令代码。
b) mov ax, stack ;ax = 204Dh
mov ss, ax ;初始化栈:设置栈段地址ss = 204Dh
mov sp, 16 ;设置栈顶地址sp = 16
c) mov ax, 14 ; ax = 000Eh
call ax ; (1)push IP (2)CPU转到 (ax寄存器) 处执行指令
inc ax
d) mov bp, sp ; bp = sp = 000Eh
add ax, [bp] ; ax = ax + ss:[bp] = 000Eh + 000Dh = 001Bh
4. call word ptr 内存单元地址
call word ptr 内存单元地址 是转移的目的地址在内存中的call指令,实现的是段内转移,指令功能:将当前IP压入栈中,然后转移到内存中指明的目的地址处执行指令。其对寄存器操作的原理如下:
(1)(sp) = (sp) - 2 ;栈顶开辟2个字节的空间
((ss)*16+(sp)) = (IP) ;栈顶的值 = (IP)
(2)(IP) = (内存单元地址) ;修改IP值
CPU执行 call word ptr 内存单元地址 指令时,相当于执行:
(1)push IP
(2)jmp word ptr 内存单元地址
例如,下面的指令
mov sp = 16
mov ax = 0008h
mov ds:[0], ax
call word ptr ds:[0]
执行后,(IP) = 0008h, (sp) = 000Eh
5. call dword ptr 内存单元地址
call dword ptr 内存单元地址 是转移的目的地址在内存中的call指令,实现的是段间转移,指令功能:将当前CS压入栈中,然后再将当前IP压入栈中,最后转移到内存中指明的目的地址处执行指令,在指明的内存单元地址中,高字(2字节)内存中存放的是目的段地址(CS),低字(2字节)内存中存放的是目的偏移地址(IP)。其对寄存器操作的原理如下:
(1)(sp) = (sp) - 2 ;栈顶开辟2个字节的空间
((ss)*16+(sp)) = (CS) ;当前栈顶的值 = (CS)
(sp) = (sp) - 2 ;栈顶再开辟2个字节的空间
((ss)*16+(sp)) = (IP) ;当前栈顶的值 = (IP)
(2)(CS) = 内存单元地址[2]
(IP) = 内存单元地址[0]
所以,CPU执行call dword ptr 内存单元地址指令时,相当于执行:
(1)push CS
push IP
(2)jmp dword ptr 内存单元地址
例如,下面的指令
mov sp, 16
mov word ptr ds:[0], 0
mov ax, 204Eh
mov ds:[2], ax
call dword ptr ds:[0]
执行后,(CS) = 204Eh, (IP) = 0000h, (sp) = 000Ch
参考文献
《汇编语言(第4版)》王爽