(十)汇编语言——CALL和RET指令

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

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

文章目录

相信大家肯定在C语言里面接触过函数这个概念或者是一些高级语言里面的方法那么汇编语言有没有这样类似的概念呢答案是当然的接下来就让我们来介绍一下汇编的模块化程序设计。

CALL指令

这个CALL指令呢我们是第一次接触它主要的作用就是调用子程序实质上就是进行流程转移而且实现转移的方法和jmp指令的原理相似。使用的格式就是call 标号这个就类似于把当前位置保存起来去执行其他地方的代码执行完了之后再回到原处去执行。就类似于我们的中断。

功能

首先将当前的IP压入栈中然后转移到标号处执行指令。相当于下面的语句。实现的是段间转移如果我们要实现段内转移呢我们继续讲解。

  1. (sp)=(sp)–2
  2. ((ss)*16+(sp))=(IP)
  3. (IP)=(IP)+16位位移
push IP
jmp near ptr 标号

寄存器

而如果转移地址在寄存器里面的话就有一点不一样了但是和我们之前介绍的 jmp 指令类似的我们具体看看吧就相当于下面的语句。

push IP
jmp 16位寄存器

内存

转移地址在内存中的call指令其实也是类似的我们给出相应的语句相信大家可以很清楚的理解到。

;call word ptr 内存单元地址
push IP
jmp word ptr 内存单元地址

;calld word ptr 内存单元地址
push CS
push IP
jmp dword ptr 内存单元地址

段间转移

我们如果想要实现段间转移的话使用的指令就是call far ptr 标号这个时候我们就会把CS和IP同时入栈保存起来。具体步骤如下所示

  • (sp)=(sp)–2
  • ((ss)×16+(sp))=(CS)
  • (sp)=(sp)–2
  • ((ss)×16+(sp))=(IP)
  • (CS)=标号所在的段地址
  • (IP)=标号所在的偏移地址
push CS
push IP
jmp far ptr 标号

“call 标号”类似”jmp near ptr 标号”对应的机器指令中为相对于当前IP的转移位移而不是转移的目的地址实现段内转移。而指令“call far ptr 标号”实现的是段间转移

返回指令

我们这里主要介绍ret指令和retf指令。

ret

用栈中的数据修改IP的内容从而实现近转移相当于 pop IP。

retf

用栈中的数据修改CS和IP的内容从而实现远转移

实例

这个程序就是计算一下ax的平方但是值得注意的就是这里我们用到了栈段因为我们的call 指令和ret指令需要入栈和出栈操作。

assume cs:code, ss:stack
stack segment
	db 8 dup(0)
	db 8 dup(0)
stack ends
code segment

start :mov ax, stack
	mov ss,ax
	mov sp,16
	mov ax,1000
	call s
	mov ax, 4c00h
	int 21h

  s:add ax,ax
	ret

code ends
end start

MUL指令

mul指令就是我们的乘法指令我们之前介绍过除法div指令我们来简单回顾一下。

被除数AXDX和AX
除数8位内存或寄存器16位内存或寄存器
ALAX
余数AHDX

而接下来我们介绍的乘法指令与这个类似我们来看看吧

被乘数ALAX
除数8位内存或寄存器16位内存或寄存器
结果AXDX高位和AX低位

我们来看一个例子吧计算100乘10和100乘10000。

;100*10
mov al,100
mov bl,10
mul bl

;100*10000
mov ax,100
mov bx,10000
mul bx

模块化程序设计

我们知道在程序设计中模块化设计是十分重要的那么在汇编语言中有没有这要的设计呢聪明的小伙伴们应该想到了调用我们刚刚介绍的CALL 指令和RET指令即可。但是呢需要我们去解决两个问题那就是参数和返回值的问题我们来看一下这两个问题我们如何来解决。

在这之前我们来看一个问题就是根据提供的N计算N的3次方。我们可以考虑用循环去做但是我们现在选择使用模块化程序设计的方法去解决具体解决办法如下

寄存器

把数据存储到寄存器里面是一个解决办法我们来看看具体的操作。

  1. 首先把参数放到 bx 中即(bx)=N;
  2. 然后子程序中用多个mul指令计算N3;
  3. 最后将结果放到dx和ax中(dx:ax)=N3
assume cs:code
data segment
	dw 1,2,3,4,5,6,7,8
	dd 0,0,0,0,0,0,0,0
data ends

code segment
start:mov ax,data
	mov ds,ax
	mov si,0     ;指向第一组单词
	mov di,16    ;指向第二组单词
	
	mov cx,8
  s:mov bx,[si]
	call cube
	mov [di],ax
	mov [di].2,dx
	add si,2
	add di,4
	loop s        ;循环处理
	
	mov ax,4c00h
	int 21h

cube:mov ax,bx
	mul bx
	mul bx
	ret

code ends
end start

这样处理当然是没有问题的但是会面临一个问题就是我们的寄存器只有那么多如果需要传递的东西比较多寄存器不够用了怎么办确实这是我们会遇到的问题。既然寄存器比较少我们就换一个方法使用内存单元去传递信息。

内存单元

为了避免寄存器不够的尴尬于是我们现在使用内存单元去传递数据。我们的做法就是先将批量数据放到内存中然后将它们所在内存空间的首地址放在寄存器中传递给需要的子程序。对于具有批量数据的返回结果也可用同样的方法。

比如我们看这个例子将data段中的字符串转化为大写。

data segment
	db 'conversation'
data ends

我们来看一下具体的代码段怎么去写。

code segment
start:mov ax,data
	  mov ds,ax
	  mov si,0
  	  mov cx,12;循环次数
	  call capital
	  mov ax,4c00h
	  int 21h
capital: and byte ptr [si],11011111b;变大写
	  inc si
	  loop capital
	  ret
code ends

目前这样基本上是没有什么问题了。但是我们还要介绍另外一种方法那就是通过我们的栈来实现传递参数。

接下来我们就使用栈来进行参数传递主要的原理就是由调用者将需要传递给子程序的参数压入栈中子程序从栈中取得参数。同样的我们介绍一个例子那就是计算(a–b)3a、b为word型数据。我们来看一下代码段部分。

code segment
start:
	mov ax,1
	push ax
	mov ax,3
	push ax
	;首先将一些数据入栈
	call difcube
	;调用子程序
	mov ax,4c00h
	int 21h
	
difcube:
	push bp
	;先在栈中保存BP的值
	mov bp,sp
	mov ax,[bp+4]
	sub ax,[bp+6]
	mov bp,ax
	mul bp
	mul bp
	;获得参数并计算返回到AX中
	pop bp
	;恢复之前的BP值
	ret 4
	;放弃入栈的参数
code ends

好啦这就是关于用栈来传递参数的方法我们就介绍到这。

寄存器冲突问题

接下来我们将来解决有关寄存器冲突的问题具体来说就是避免在子程序里面使用的寄存器与主程序里面使用的寄存器冲突了导致程序无法运行。好啦接下来我们就会来介绍如何解决这个问题。给大家一个提示那就是使用我们经常使用的栈来保存数据。

方法

前面说了我们是使用栈去解决这个问题那么就让我们来卡看具体如何使用吧。

子程序开始

  1. 子程序中使用的寄存器入栈
  2. 子程序内容
  3. 子程序使用的寄存器出栈
  4. 返回ret、retf
capital:
	push cx
	push si
change:
	mov cl,[si]
	mov ch,0
	jcxz ok
	and byte ptr [si],11011111b
	inc si
	jmp short change
ok:
	pop si
	pop cx
	ret

大家看这个地方原理就是用栈先去保存数据然后在程序结束的时候再把原来的数据出栈。
子程序中使用的寄存器入栈
2. 子程序内容
3. 子程序使用的寄存器出栈
4. 返回ret、retf

capital:
	push cx
	push si
change:
	mov cl,[si]
	mov ch,0
	jcxz ok
	and byte ptr [si],11011111b
	inc si
	jmp short change
ok:
	pop si
	pop cx
	ret

大家看这个地方原理就是用栈先去保存数据然后在程序结束的时候再把原来的数据出栈。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6