汇编语言-子程序调用

来源:互联网 发布:js 判断ie9以下版本 编辑:程序博客网 时间:2024/06/06 12:37

汇编语言-子程序调用

ret与ref指令

ret

ret == pop IP

ret指令用栈中的数据,修改IP的内容,从而实现近转移;

功能介绍

retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移
CPU执行ret指令时,进行下面两步操作:

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

相当于进行:

pop IP

retf

retf == pop IP + POP CS

功能介绍

CPU执行retf指令时,进行下面两步操作:

(1)(IP) = ((ss) * 16 + (sp))(2)(sp) = (sp) + 2(3)(CS) = ((ss) * 16 + (sp))(4)(sp) = (sp) + 2

相当于进行:

pop IPpop CS

call指令

call 标号

功能介绍

(把当前IP压栈后, 转到标号处执行指令)

a. (SP) = (SP) - 2   ((SS) * 16 + SP) = (IP)b. (IP) = (IP) + 16位位移

相当于:

push IPjmp near ptr 标号
  • 16位位移 = “标号”处的地址 - call指令后的第一个字节的地址;
  • 16位位移的范围 -32768—-32767, 用补码表示;
  • 16位位移由编译程序在编译时算出;

call far ptr 标号

功能介绍

(把当前CS,IP压栈后, 转到标号处执行指令)

a. (SP) = (SP) - 2   ((SS) * 16 + SP) = (CS)b. (SP) = (SP) - 2   ((SS) * 16 + SP) = (IP)c. (CS) = 标号所在段的段地址   (IP) = 标号在段中的偏移地址

相当于:

push CSpush IPjmp par ptr 标号

call 16位寄存器

功能介绍

(sp) = (sp) – 2((ss) * 16 + (sp)) = (IP)(IP) = (16位寄存器) 

相当于:

push IP jmp 16位寄存器

call word ptr 内存单元地址

功能介绍

push IPjmp word ptr 内存单元地址

实例展示

mov sp, 10hmov ax, 0123hmov ds:[0], axcall word ptr ds:[0]执行后,(IP)=0123H,(sp)=0EH

call dword ptr 内存单元地址

功能介绍

push CSpush IPjmp dword ptr 内存单元地址

实例展示

mov sp, 10hmov ax, 0123hmov ds:[0], axmov word ptr ds:[2], 0call dword ptr ds:[0]执行后,(CS)=0,(IP)=0123H,(sp)=0CH((IP)= ds:[0], (CS) = ds:[2])

子程序调用

通过上面介绍的两个指令,我们可以完成子程序的调用。简单调用程序如下:

assume cs:codecode segmentstart:  mov ax,1    mov cx,3    call s    mov bx, ax    mov ax,4c00H    int 21H    s:  add ax,ax        loop s    retcode endsend start

子程序调用-传递参数问题

我们在写c语言或者其他高级语言的时候,要经常用到函数之间的参数传递这一个概念。那么在汇编语言中,我们怎么做到总程序和子程序之间的参数传递呢?

寄存器存放法

首先可以考虑在寄存器中,存放数据,比如a存放在ax中,b存放在bx中。

mov ax,amov bx,b

这种方式可以在参数比较少的时候使用,但是参数多了呢?那么那么多的寄存器给你存放。因此这种方式不是长久之计。

内存存放法

我们想到了一个比较好的思路,就是将参数保存到内存中,然后在寄存器中存放这些参数的首地址,通过首地址访问一系列的参数。这种方式,显然可以存放更多的数据,并且没有数量上的限制。

;参数存放段data segment    db 'aaaaa',0    db 'aaaaa',0    db 'aaaaa',0data endscode segment     ...    ...    mov ax,data    mov es,ax    mov si,0    call sub1    ...    ...    sub1:   mov ax,es[si]            ...            ...    retcode ends

这里还是存在一个问题,如果在主程序中用到了一个xx寄存器,然后在子程序中也用到了这个xx寄存器,那么当子程序返回到主程序的时,主程序中存放参数的内存地址已经没有记录了,程序出错。

内存存放法(改进)

为了解决这个问题,我们需要每次进入子程序时,将子程序中的需要用到的寄存器,push到栈中,每次退出子程序时,将相应寄存器pop出来。

子程序都应遵循下面的模式:

capital:        push cx        push sichange:        mov cl,[si]        mov ch,0        jcxz ok        and byte ptr[si],11011111B        inc si        jmp short changeok:         pop si        pop cx        ret
0 0
原创粉丝点击