您的位置:首页 > 汽车 > 时评 > 汇编语言:call、call far ptr、call word ptr、call dword ptr、call 寄存器

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

2025/1/8 7:56:37 来源:https://blog.csdn.net/d704791892/article/details/141264623  浏览:    关键词:汇编语言: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 segmentdb 16 dup (0)
stack ends
code segment
start:mov ax, 0call s      ;执行该指令的内部逻辑步骤:(1) pop IP(即指向inc ax指令的首地址); ;                       (2)IP = IP + (s标号处指令的首地址 - call s指令的下一条指令(即 inc ax指令)的首地址)inc ax
s: pop axmov ax, 4c00hint 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 segmentdb 16 dup (0)
stack ends
code segment
start:;初始化栈mov ax, stack       ;ax = 204Dmov ss, ax          ;初始化栈:设置栈段地址ss = 204Dmov sp, 16          ;设置栈顶地址sp = 16mov ax, 0call far ptr s      ;(1)push CS (2)push IP (3)CPU转移到标号S处执行指令inc ax
s:pop ax              ;IP的值出栈add ax, axpop bx              ;CS的值出栈add ax, bx          mov ax, 4c00hint 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 segmentdb 16 dup (0)
stack ends
code segment
start:;初始化栈mov ax, stackmov ss, axmov sp, 16mov ax, 14call ax         ;(1)push IP (2)CPU转到 (ax寄存器) 处执行指令inc axmov bp, spadd ax, [bp]mov ax, 4c00hint 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版)》王爽

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com