汇编语言:call和ret配合使用设计模块化程序

一. call指令

1. call 标号

        call 标号 是根据位移进行进转移的call指令,实现的是段内转移,只修改IP的值,操作原理:

(1)(sp) = (sp) - 2                    ;栈顶开辟2字节空间
         ((ss)*16 + (sp)) = (IP)        ;栈顶的值 = (IP)
(2)(IP) = (IP) + 16位位移       ;修改IP的值
CPU执行 call 标号 指令,相当于执行:
(1)push IP
(2)jmp near ptr 标号

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 标号

3. call 寄存器

        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位寄存器

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 内存单元地址

5. call dword ptr 内存单元地址

        call dword 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) = 内存单元地址[2]
         (IP) = 内存单元地址[0]

CPU执行call dword ptr 内存单元地址指令,相当于执行:

(1)push CS
         push IP
(2)jmp dword ptr 内存单元地址

二. ret 和 retf指令

1. ret 指令

         ret指令用栈顶中的数据,修改IP的内容,从而实现近转移。执行ret指令的基本步骤原理如下:

(1)(IP) = ((ss)*16 + (sp))

         (sp) = (sp) + 2

CPU执行 ret 指令,相当于执行

        pop IP

tips:

        ret n 指令,相当于

        pop IP

        add sp, n

2. retf 指令

         retf指令用栈顶中的数据,同时修改IP和CS,从而实现远转移。执行retf指令的基本步骤原理如下:

(1)(IP) = ((ss)*16 + (sp))

         (sp) = (sp) + 2

 (2)(CS) = ((ss)*16 + (sp))

          (sp) = (sp) + 2

    CPU执行ret指令时,相当于执行:

(1)pop IP

(2)pop CS

三. 模块化程序设计

1. 用栈传递参数

        用栈传递参数的原理是由调用者通过push指令将需要传递给子程序的参数压入栈中,子程序从栈中取得参数。

2. 函数调用栈

        用栈传递参数这种技术和高级语言编译器的工作原理密切相关。bp(base pointer,基址指针)寄存器和 sp(stack pointer,栈顶指针)共同管理函数调用栈。bp 寄存器用于保存进入函数时的栈顶基址,用于作为正在运行的函数的栈帧的栈底,每一个函数都有自己的栈帧,函数栈帧的大小并不固定,一般与其对应函数的局部变量多少有关。函数运行过程中,其栈帧大小也是在不停变化的。而 sp 寄存器永远指向栈顶位置。

        IP (Instruction Pointer,指令指针寄存器),其内存放着一个指针,该指针指向下一条等待执行的指令地址。

        理论看起来是枯燥,似懂非懂的样子,我们来看下面的例子。

示例:写一个求一个数立方的函数,在主程序中,我们调用这个函数,求:2^{3}

assume cs:code, ss:stack
stack segment
    db 32 dup (0)
stack ends
code segment
start:
    ;初始化栈
    mov ax, stack
    mov ss, ax
    mov sp, 32
    mov bp, sp

    mov ax, 2
    push ax     ;调用者将传递给被调用者的参数压入栈
    call cube

    mov ax, 4c00h
    int 21h

    ;函数功能:计算a³,a为字型数据
    ;参数:进入子程序时,栈顶存放IP,后面存放参数a
    ;结果:ax存放结果的低16位,dx存放结果的高16位
cube:
    push bp         ;保存原栈顶基址
    mov bp, sp      ;设置现栈顶基址
    mov ax, [bp+4]  ;取到参数,因为call会push IP,又执行了push bp,所以函数调用栈中,传递给该函数参数在 [bp+4]处
    mul word ptr [bp+4] ;16位乘法,一个数默认在ax寄存器,结果的低16位存放ax寄存器中,高16位存在dx寄存器中
    mul word ptr [bp+4] ;
    pop bp          ;恢复原栈顶基址
    ret 2           ;执行ret 2,相当于 pop IP; add sp, 2
code ends
end start

(1)各寄存器和栈段原始状态如下:

(2)初始化栈

(3)主程序将执行子程序需要的参数压入栈

(4)主程序调用子程序

(5)进入子程序

a)push bp        ; 保存原栈顶基址

b)mov bp, sp      ;设置现栈顶基址,bp = 001Ah

     mov ax, [bp+4]  ;取到参数,因为call会push IP,又执行了push bp,所以函数调用栈中,传递给该函数参数在 [bp+4]处

     mul word ptr [bp+4] ;16位乘法,一个数默认在ax寄存器,结果的低16位存放ax寄存器中,高16位存在dx寄存器中

     mul word ptr [bp+4] ;执行该指令后,一个数的立方计算完成,结果的低16位存放ax寄存器中,高16位存在dx寄存器中

此时,所以,ax = 0008h,dx = 0000h

c)pop bp          ;恢复原栈顶基址,bp = 0020h

(6)子程序返回:ret 2           ;执行ret 2,相当于 pop IP; add sp, 2

至此,cube子程序执行完毕,栈又回到了未调用cube 子程序时的状态,CS:IP指向了代码段中:mov ax, 4c00h  这条指令。

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值