汇编语言call和ret的配合使用

问题
下面程序返回前,bx中的值是多少?

assume cx:code
code segment
       
start:  mov ax, 1
        mov cx,3
        call s
        mov bx, ax            ;(bx)=?    
        mov ax,4c00h
    int 21h    

s:  add ax,ax
    loop s
    ret
code ends
end start

分析
我们来看一下cPu执行这个程序的主要过程
(1) CPU将call s指令的机器码读入,IP指向了call s后的指令mov bx,ax,
然后CPU执行calls指令,将当前的IP值(指令movbx,ax的偏移地址)压栈
并将IP的值改变为标号s处的偏移地址;

(2) CPU 从标号s处开始执行指令,loop 循环完毕后,(ax)=8;

(3) CPU 将ret指令的机器码读入,IP 指向了ret指令后的内存单元
然后CPU执行ret指令,从栈中弹出一个值(即call s先前压入的mov bx,ax 指令的偏移地址)送入IP中
则CS:IP指向指令mov bx,ax
(4) CPU从mov bx,ax开始执行指令,直至完成

程序返回前,(bx)=8
可以看出,从标号s到ret的程序段的作用是计算2的N次方,计算前,N的值由cx提供
我们再来看下面的程序:

源程序                      内存中的情况(假设程序从内存1000:。处装入)
assume cs:code
stack segment
    db 8 dup (0)            1000:0000  00 00 00 00 00 00 00 00
    db 8 dup (0)            1000:0008  00 00 00 00 00 00 00 00
stack ends

code segment
    start:
    mov ax,stack            1001:0000  B8 00 10
    mov ss,ax               1001:0003  8E D0
    mov sp,16               1001:0005  BC 10 00
    mov ax,1000             1001:0008  B8 E8 03
    call s                  1001:000B  E8 05 00
  
    mov ax, 4c00h           1001:000E  B8 00 4C
    int 21h                 1001:0011  CD 21
    
    s:
    add ax,ax                1001:0013  03 C0
    ret                      1001:0015  C3
code ends
end start

看一下程序的主要执行过程。
(1)前3条指令执行后,栈的情况如下:

1000:0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                                                        |
                                                       SS:Sp

(2) call指令读入后,(IP)=OOOEH } CPU指令缓冲器中的代码为:E8 OS 00
CPU执行E8 OS 00,首先,栈中的情况变为:

1000:0000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 OE 00
                                                     |
                                                   SS:Sp

然后,(IP)={IP)+0005=0013H
(3) CPU从cs:0013H处(即标号s处)开始执行
(4) ret指令读入后:
(IP)=0016H,CPU指令缓冲器中的代码为: C3
CPU执行C3,相当于进行pop IP,执行后,栈中的情况为:

1000:0000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 OE 00
                                                           |
                                                         SS:Sp
(IP)=000EH

(5)CPU回到cs:000EH处(即call指令后面的指令处)继续执行

从上面的讨论中我们发现,可以写一个具有一定功能的程序段,我们称其为子程序,在需要的时候,用call 指令转去执行。可是执行完子程序后,如何让CPU接着call 指令向下执行?call 指令转去执行子程序之前,call 指令后面的指令的地址将存储在栈中 所以可在子程序的后面使用ret 指令,用栈中的数据设置IP的值从而转到call指令后面的代码处继续执行
这样,我们可以利用call 和ret来实现子程序的机制。
子程序的框架如下

 标号:
     指令
     ret

具有子程序的源程序的框架如下:

assume cs:code
code segment
    main: 
    :
    call sub1      ;调用子程序sub1
    :
    :
    mov ax,4c00h
    int 21h
    
    
    sub1:          ;子程序sub1开始
    :
    :
    
    call sub2      ;调用子程序sub2
        :
        :
        ret            ;子程序返回
    
    sub2:
        :
        :
        :
         ret            ;子程序返回
code ends
end main

现在,可以从子程序的角度,回过头来再看一下本节中的两个程序。


发布日期:

所属分类: 易语言 标签: