汇编语言:call、call far ptr、call word ptr、call dword ptr、call 寄存器

引言

        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版)》王爽

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值