汇编语言第十章——CALL和RET指令

今天我们学习call和ret指令。
我们在第九章里学习了转移指令的原理。
今天标题里的两个指令,也都是转移指令。
那么,下面我们就分别来讲解这两个指令。

ret和retf

那么这个指令的用处是什么呢?
ret是利用栈中的数据来修改IP,从而实现近转移。
retf利用栈中的数据来修改CS和IP,从而实现远转移。
由这里的定义,我们可以看到,我们修改用的数据和数据来源,以及修改的目标都是非常明确的,所以我们并不需要更多的参数,所以这两个指令使用时,直接使用即可。如:

ret
retf

就是这样简单。
但是,我们应该怎么去理解这个操作呢?
我们可以用汇编语句来解释这两个指令。
首先时ret:

pop IP

也就是说执行ret,其实就是执行pop IP,也就是从SS:SP处取出数据放入IP。
那么retf呢:

pop IP
pop CS

这里有一点值得注意,那就是先后顺序,我们在执行retf时,是先修改IP,再修改CS的。

call指令

CPU在执行call时主要进行两个步骤:

  1. 将当前的IP或CS:IP压入栈中
  2. 转移

那么call怎么用呢?
call和jmp用法比较多,我们接下来一次介绍。

依据位移进行转移

格式比较简单:

call [flag]

这里的flag就不多解释了。
那么这里的call的意思,就是把IP压入栈中,然后转移到标号处进行下一步。
我们同样可以用汇编指令来解释:

push IP
jmp near ptr [flag]

给出转移的目的地址

先上格式:

call far ptr [flag]

和jmp有些类似,不是吗?
从这里的far,相信你也能知道,它是实现段之间的转移。
那么它在执行时,干了些什么事呢?

  1. 把CS和IP压入栈内
  2. 转移

我们同样可以用汇编指令来解释:

push CS
push IP
jmp far ptr [flag]

注意,这里的push的顺序和之前retf的pop顺序是相对应的。
也许在这里你会感觉call和ret就像一对互逆的操作。

转移地址在寄存器中

格式如下:

call reg(16bit)

我们直接用汇编语句解释:

push IP
jmp reg

转移地址在内存中

这里我们有两种格式:

call word ptr 内存单元
call dword ptr 内存单元

我们依然可以用汇编语句来解释这两条指令。
第一条解释如下:

push IP
jmp word ptr 内存单元

第二条如下:

push CS
push IP
jmp dword ptr 内存单元

call和ret的配合使用

我在之前也提示过了,这两条指令就像一对逆操作,所以这里我们来看看他们配合起来是怎么使用的。

assume cs:code
code segment
	start:	mov ax,1
			mov cx,3
			call s
			mov bx,ax
			mov ax,4c00h
			int 21h
	s:		add ax,ax
			loop s
			ret
code ends
end start

是不是觉得这个用法很像,很像函数?
这里,call使得跳转至s处,然后用ret返回到原来的地方。

mul指令

这里mul是multiplication的缩写,也就是乘法的意思。
关于这条指令,有两点提示:

  1. 两个乘数,要么都是八位,要么都是16位。如果是8位,则其中一个存放在AL,另一个存放在一个内存单元内或者一个reg内;如果是16位,则其中一个在AX里,另一个存放在内存单元或者reg内
  2. 关于结果存放的位置,如果两个乘数都是8位,则结果存放在ax中;如果两个都是16位,则结果,高位存放在DX,低位存放在AX

从这里的说明,我们可以看出,我们有一个乘数是默认在ax的,结果也是有默认的位置的,所以我们在使用这个指令时,只需要提供另一个乘数的位置即可,所以这条指令的结构如下;

mul reg
mul 内存单元

当然了,这里的内存单元可以用不同的寻址方式,比如:

mul byte ptr ds:[0]

call和ret的意义

我们在前面说过call和ret的配合使用可以实现类似函数一样的功能,其实这里也就为汇编的模块化设计提供了条件。所以下面我们来说说用汇编进行模块化设计需要注意的几个问题。

参数和结果传递问题

我们在写函数时,经常会需要参数和返回值,那么我们在汇编中的模块化设计如何实现参数和返回值呢?
其实这并不是非常难的事情,比如上面的例子:

assume cs:code
code segment
	start:	mov ax,1
			mov cx,3
			call s
			mov bx,ax
			mov ax,4c00h
			int 21h
	s:		add ax,ax
			loop s
			ret
code ends
end start

这里的s实现的功能就是求2的三次方。
我们这里时将1存储在ax中,作为参数传递过去,同时,我们最后函数的结果,也就是返回值,依然时存储在ax中返回的。
所以,在汇编中,内存和存储器这些存储单位都是公用的,所以我们在传递起来,反而更加方便了一些。

批量传递数据

我们前面说可以用寄存器去传递数据,但是我们也知道寄存器的数量终究是有限的,如果我们想大量的传递数据应该怎么办呢?
我们之前总结过,我们的数据来源一般有两个——reg和内存。
既然reg不够用了,那我们就用内存就好了。
然后我们将这一段数据的首地址放入寄存器,就可以实现大量数据的传递了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值