(十)汇编语言——CALL和RET指令
(十)汇编语言——CALL和RET指令
文章目录
- (十)汇编语言——CALL和RET指令
- CALL指令
- 功能
- 寄存器
- 内存
- 段间转移
- 返回指令
- ret
- retf
- 实例
- MUL指令
- 模块化程序设计
- 寄存器
- 内存单元
- 栈
- 寄存器冲突问题
- 方法
相信大家肯定在C语言里面接触过函数这个概念,或者是一些高级语言里面的方法,那么汇编语言有没有这样类似的概念呢,答案是当然的,接下来就让我们来介绍一下汇编的模块化程序设计。
CALL指令
这个CALL指令呢,我们是第一次接触,它主要的作用就是调用子程序,实质上就是进行流程转移,而且实现转移的方法和jmp指令的原理相似。使用的格式就是call 标号,这个就类似于,把当前位置保存起来,去执行其他地方的代码,执行完了之后再回到原处去执行。就类似于我们的中断。
功能
首先将当前的IP压入栈中,然后转移到标号处执行指令。相当于下面的语句。实现的是段间转移,如果我们要实现段内转移呢?我们继续讲解。
- (sp)=(sp)–2
- ((ss)*16+(sp))=(IP)
- (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 segmentdb 8 dup(0)db 8 dup(0)
stack ends
code segmentstart :mov ax, stackmov ss,axmov sp,16mov ax,1000call smov ax, 4c00hint 21hs:add ax,axretcode ends
end start
MUL指令
mul指令就是我们的乘法指令,我们之前介绍过除法div指令,我们来简单回顾一下。
被除数 | AX | DX和AX |
---|---|---|
除数 | 8位内存或寄存器 | 16位内存或寄存器 |
商 | AL | AX |
余数 | AH | DX |
而接下来我们介绍的乘法指令与这个类似,我们来看看吧!
被乘数 | AL | AX |
---|---|---|
除数 | 8位内存或寄存器 | 16位内存或寄存器 |
结果 | AX | DX(高位)和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次方。我们可以考虑用循环去做,但是我们现在选择使用模块化程序设计的方法去解决,具体解决办法如下:
寄存器
把数据存储到寄存器里面是一个解决办法,我们来看看具体的操作。
- 首先把参数放到 bx 中,即(bx)=N;
- 然后子程序中用多个mul指令计算N3;
- 最后将结果放到dx和ax中:(dx:ax)=N3;
assume cs:code
data segmentdw 1,2,3,4,5,6,7,8dd 0,0,0,0,0,0,0,0
data endscode segment
start:mov ax,datamov ds,axmov si,0 ;指向第一组单词mov di,16 ;指向第二组单词mov cx,8s:mov bx,[si]call cubemov [di],axmov [di].2,dxadd si,2add di,4loop s ;循环处理mov ax,4c00hint 21hcube:mov ax,bxmul bxmul bxretcode ends
end start
这样处理当然是没有问题的,但是会面临一个问题,就是我们的寄存器只有那么多,如果需要传递的东西比较多,寄存器不够用了怎么办,确实这是我们会遇到的问题。既然寄存器比较少,我们就换一个方法,使用内存单元去传递信息。
内存单元
为了避免寄存器不够的尴尬,于是我们现在使用内存单元去传递数据。我们的做法就是先将批量数据放到内存中,然后将它们所在内存空间的首地址放在寄存器中,传递给需要的子程序。对于具有批量数据的返回结果,也可用同样的方法。
比如我们看这个例子,将data段中的字符串转化为大写。
data segmentdb 'conversation'
data ends
我们来看一下具体的代码段怎么去写。
code segment
start:mov ax,datamov ds,axmov si,0mov cx,12;循环次数call capitalmov ax,4c00hint 21h
capital: and byte ptr [si],11011111b;变大写inc siloop capitalret
code ends
目前这样基本上是没有什么问题了。但是我们还要介绍另外一种方法,那就是通过我们的栈来实现传递参数。
栈
接下来我们就使用栈来进行参数传递,主要的原理就是由调用者将需要传递给子程序的参数压入栈中,子程序从栈中取得参数。同样的,我们介绍一个例子,那就是计算(a–b)3,a、b为word型数据。我们来看一下代码段部分。
code segment
start:mov ax,1push axmov ax,3push ax;首先将一些数据入栈call difcube;调用子程序mov ax,4c00hint 21hdifcube:push bp;先在栈中保存BP的值mov bp,spmov ax,[bp+4]sub ax,[bp+6]mov bp,axmul bpmul bp;获得参数并计算,返回到AX中pop bp;恢复之前的BP值ret 4;放弃入栈的参数
code ends
好啦,这就是关于用栈来传递参数的方法,我们就介绍到这。
寄存器冲突问题
接下来我们将来解决有关寄存器冲突的问题,具体来说就是避免在子程序里面使用的寄存器与主程序里面使用的寄存器冲突了,导致程序无法运行。好啦,接下来我们就会来介绍如何解决这个问题。给大家一个提示,那就是使用我们经常使用的栈来保存数据。
方法
前面说了,我们是使用栈去解决这个问题,那么就让我们来卡看具体如何使用吧。
子程序开始:
- 子程序中使用的寄存器入栈
- 子程序内容
- 子程序使用的寄存器出栈
- 返回(ret、retf)
capital:push cxpush si
change:mov cl,[si]mov ch,0jcxz okand byte ptr [si],11011111binc sijmp short change
ok:pop sipop cxret
大家看这个地方,原理就是用栈先去保存数据,然后在程序结束的时候再把原来的数据出栈。
子程序中使用的寄存器入栈
2. 子程序内容
3. 子程序使用的寄存器出栈
4. 返回(ret、retf)
capital:push cxpush si
change:mov cl,[si]mov ch,0jcxz okand byte ptr [si],11011111binc sijmp short change
ok:pop sipop cxret
大家看这个地方,原理就是用栈先去保存数据,然后在程序结束的时候再把原来的数据出栈。
(十)汇编语言——CALL和RET指令相关推荐
- 汇编语言 | CALL 和RET指令
call和ret指令都是转移指令,它们都修改IP,但同时修改CS和IP. 1.ret和retf ret指令用栈中的数据,修改IP的内容,从而实现近转移. retf指令用栈中的数据,修改CS和IP的内容 ...
- [汇编语言]CALL和RET指令
目录 一.ret和retf 二.call指令 2.1 依据位移进行转移的call指令 2.2 转移的目的地址在指令中的call指令 2.3 转移地址在寄存器中的call指令 2.4 转移地址在内存中的 ...
- 王爽 《汇编语言》 读书笔记 十 CALL和RET指令
第十章 CALL和RET指令 call和ret都是转移指令,它们都修改IP,或同时修改CS和IP,常用于子程序的设计. 10.1 ret 和 retf ret用栈中的数据,修改IP的内容,从而实现近转 ...
- 汇编语言笔记10-CALL和RET指令
☞模块化程序设计 模块化程序设计 汇编语言通过call和ret指令实现了模块化程序设计.可以实现多个相互联系.功能独立的子程序来解决一个复杂的问题. 子程序的框架 1 assume cs:code 2 ...
- 王爽 汇编语言第三版 第10章 call 和 ret 指令 以及 子程序设计
第10章 call 和 ret 指令 10.1 ret 和 reft 指令 call 和 ret 指令都是转移指令,他们都修改 IP,或同事修改 CS 和 IP .他们经常被共同来实现子程序的设计. ...
- 汇编语言(第三版)第十章 CALL 和 RET 指令 笔记
call 和 ret 都是可以改变 ip 或是 cs 和 ip .经常用来实现子程序设计. 10.1 ret 和 retf ret指令用栈中的数据,修改IP实现近转移 retf指令用栈中的程序,修改c ...
- 《汇编语言》第十章 call 和 ret 指令
call指令和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP,它们经常被共同用来实现子程序的设计 10.1 ret 和 retf ret指令用栈中的数据,修改IP的内容,从而实现近转移 ...
- 《汇编语言》第10章 call和ret指令
call和ret指令都是转移指令,经们都修改IP,或同时修改CS和IP.它们经常被共同用来实现子程序的设计.这一章,我们讲解call和ret指令的原理. 10.1 ret和retf ret指令用栈中的 ...
- 汇编语言——第10章 CALL和RET指令
目录 引言 10.1 ret和retf 检测点10.1 10.2 call指令 10.3 依据位移进行转移的call指令 检测点10.2 10.4 转移的目的地址在指令中的call指令 检测点10.3 ...
最新文章
- 【java】4.27上课及做作业时遇到的问题及第十六节课笔记整理
- SAP RETAIL 如何查看分配表是参考哪个PO来创建的?
- hdp分享码2020_和平精英2020黄金风衣龙cdk兑换码
- MATLAB R2022 最新中英文版 数据处理
- java 手机号码归属地_【原创】Java实现手机号码归属地查询
- dubbo-go v1.5.6来喽!
- 隐藏水滴屏的软件_突破屏下摄像头技术,vivo APEX 2020,开启全面屏手机黑科技!...
- 工作133:nexttick的使用
- Java NIO 读取文件、写入文件、读取写入混合
- HDU2026 首字母变大写【文本处理】
- css字体浏览(转)
- 服务器pe系统ghost系统安装教程,科技教程:U盘PE启动安装GHOST系统图文教程
- word中脚注和尾注的处理
- opencv在图片上添加文字
- gitbook安装使用看完这一篇就够了
- android 友盟统计动态设置渠道,Android 友盟多渠道打包
- 什么是EISA分区,如何删除
- 数据大牛都在啃的15本书
- 最具价值和投资前景的域名系列之-SoShow(搜秀)
- 计算机 屏幕卡住,电脑屏幕突然卡死应该怎么办?
热门文章
- HFSS学习笔记—20.自适应网格剖分设置
- 华为HiLink 云云对接 后台开发的一些细节和坑
- 机电工程专业技术-起重技术(一)
- Peter 的烟题解
- 计算从出生到现在活了多少天
- 萤石春季发布会:4+N产品体系再升级EZVIZ Connect连接智能生活
- html500错误原因1003无标题,web工程中404/500错误页面配置+404页面模板
- 800 篇顶会论文纵览推荐系统的前沿进展
- oracle 中YYYY-MM-DD HH24:MI:SS的使用 和 HH24:MM:SS
- 华清远见嵌入式培训_第七周回顾与反思(上)