call和ret都是用来修改ip或cs:ip,可以用来实现子程序的设计;
1.ret和retf
ret ->修改ip的内容,从而实现近转移;
retf ->同时修改cs和ip,从而实现远转移;
执行ret时:相当于 pop ip
1】(ip)=((ss)*16+(sp));也就是将栈顶的值赋值给ip;
2】(sp)=(sp)+2;也就是栈顶指向栈的下一个字;
执行retf时:相当于pop ip,pop cs
1】(ip)=((ss)*16+(sp))
2】(sp)=(sp)+2
3】(cs)=((ss)*16+(sp))
4】(sp)=(sp)+2
例如:下面的程序执行retf后,cs:ip指向代码第一条指令,也就是程序返回的代码 mov ax,4cooh
stack segment
db 16 dup (0)
stack ends
code segment
mov ax,4c00h
int 21h
start:mov ax,stack
mov ss,ax
mov sp,16
mov ax,0
push cs
push ax
retf
code ends
2.call指令
call ->将当前的ip或cs:ip压入栈中,然后转移;
call指令和jmp指令相似,但不能实现短转移,有多种格式;
1)依据位移进行转移的call指令
格式:
call 标号
例如:
执行的操作:将当前的ip压入栈后转移到标号处执行指令;
1】(sp)=(sp)-2,((ss)*16+(sp))=(ip)
2】(ip)=(ip)+16位位移
2.1】16位位移=标号处的地址-call指令后的第一个字节的地址
2.2】16位的位移范围是-32768~32767
2.3】16位位移在编译时由编译器计算出来
相当于:
push ip
jmp near ptr 标号
2)转移目标地址在指令中的call指令
格式:
call far ptr 标号
例如:
执行的操作:段间转移,将当前cs和ip分别入栈后转移到标号处;
1】(sp)=(sp)-2
((ss)*16+(sp))=(cs)
(sp)=(sp)-2
((ss)*16+(sp))=(ip)
2】(cs)=标号所在段的段地址
(ip)=标号所在段的偏移地址
相当于:
push cs
push ip
jmp far ptr 标号
3)转移目标地址在寄存器中的call指令
格式:
call 16位寄存器
例如:
执行的操作:当前ip入栈,ip的值设为寄存器中的值
(sp)=(sp)-2
((ss)*16+sp)=(ip)
(ip)=16位寄存器的值
相当于:
push ip
jmp 16位寄存器
4)转移地址在内存中的call指令
有两种格式:
1】call word ptr 内存单元地址
相当于:
push ip
jmp word ptr 内存单元地址
2】call dword ptr 内存单元地址
相当于:
push cs
push ip
jmp dword ptr 内存单元地址
3.call和ret配合使用
利用call和ret配合,可以实现具有一定功能的程序的,也叫子程序;
用call指令执行子程序中的代码,将后面的指令地址入栈;
执行完子程序后用ret指令用栈中的数据设置ip,依次保证程序继续向下执行;
框架:
.png)
例如:下面是计算2的3次方的代码
assume cs:code,ss:stack
stack segment
db 8 dup (0)
dp 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
4.mul指令
mul是乘法指令;
格式:
1】mul 寄存器
2】mul 内存单元
mul byte ptr ds:[0]
mul word ptr ds:[0]
执行过程:
两个数相乘,要么都是8位,要么都是16位;
如果都是8位,一个默认放在al中,另一个放在8位寄存器或内存字节单元中;
如果都是16位,一个默认在ax中,另一个放在16位寄存器或内存字单元中;
执行结果:
如果是两个8位的数相乘,结果默认放在ax中;
如果两个16位的数相乘,结果高位在dx中,低位在ax中;
例如:计算100*10000,因为10000大于255超出了8位的限制,只能做16位乘法
mov ax,100
mov bx,10000
mul bx
5.参数和结果的传递
子程序一般根据提供的参数处理后将结果返回给调用者;
因此需要考虑参数和结果的储存在哪的问题;
1)用寄存器来储存参数和结果
调用者将参数存入参数寄存器,从结果寄存器中获取返回值;
子程序从参数寄存器中获取参数,将处理结果存入结果寄存器;
例如:计算3次方的子程序
;...省略
mov bx,5
call cube ;调用子程序,用bx作参数寄存器
mov ds:[0],ax ;从结果寄存器ax,dx中获取结果的低位和高位
mov ds:[2],dx
cube: mov ax,bx ;计算3次方的子程序
mul bx
mul bx
2)批量数据的传递
如果参数或结果较少,可以用寄存器来存放;
但是如果有参数过多,就不太合适了,因为寄存器的数量有限;
可以考虑将批量数据存放在内存中,寄存器中存放数据所在内存的首地址、cx中存放数据长度、用loop指令循环调取;
例如:将字符串转为大写
assume cs:code,ds:data
data segment
db 'helloworld'
data ends
code segment
start: mov ax,data
mov ds,ax
mov si,0 ;ds:[si]存放数据首地址
mov cx,10 ;cx存放数据长度长度
call method
mov ax,4c00h
int 21h
method: and byte ptr [si],11011111b ;转为大写
inc si
loop method
ret
code ends
end start
3)用栈传递参数
这种技术常用在高级语言编译器中;
例如:计算(3-1)的3次方
mov ax,1
push ax ;将参数压入栈中
mov ax,3
push ax ;注意入栈顺序
call difcube
mov ax,4c00h
int 21h
difcube: push bp ;将bp原来的值入栈,处理完后再pop回去
mov bp,sp
mov ax,[bp+4] ;将栈中的值3送入ax
sub ax,[bp+6] ;3-1=2,将2送入ax
mov bp,ax
mul bp
mul bp
pop bp
ret 4 ;程序返回,并且将栈顶回复到初始状态,因为两个参数还占4个字节的空间,所以sp要多移动4个字节
栈的变化:
.png)
6.寄存器的冲突
如果子程序中需要用到调用者使用的寄存器时,可能产生冲突;
例如:调用者为了做循环需要用到寄存器cx,子程序中也需要做循环也要用到cx;
而子程序循环完成后cx的值已经被修改了,调用者因此受到了影响;
解决思路:
1】避免在子程序中使用调用者用过的寄存器;
2】避免在调用者中使用子程序用过的寄存器;
问题:
因为调用的不确定性,上面两种方案行不通,我们希望编写子程序和调用者时不要被寄存器的冲突限制;
可行方案:
可以考虑在编写子程序时,将子程序需要使用的寄存器值先入栈;
当子程序执行完后,在出栈,将寄存器的值还原;
例如:
method:push cx ;用到的寄存器入栈
push si
;...业务代码,需要用到寄存器cx和si
ok: pop si ;业务代码完成后,寄存器出栈还原,主义出栈顺序
pop cx
ret
- 汇编语言---call和ret指令
汇编语言--call和ret指令 call和ret指令 call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP. 它们经常被共同用来实现子程序的设计. ret和retf ret指令用栈 ...
- 汇编学习笔记(7)call和ret指令
ret和retf CPU执行ret指令时进行以下两步操作: (IP)=((ss)*16+(sp)) (sp)=(sp)+2 这相当于pop IP CPU执行retf指令时进行以下四步操作: (IP)= ...
- [汇编学习笔记][第十章 CALL和RET指令]
第十章 CALL和RET指令 call和ret指令都是转移指令,它们都修改CS和IP.经常被共同用于实现子程序的设计.这一章,我们讲解call和ret指令的原理 10.1 ret和retf ret指令 ...
- call 和 ret 指令
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- 汇编-10.0-CALL和RET指令
call和ret指令都是转移指令,他们都是修改IP,或同时修改CS和IP.它们常被共同用来实现子程序设计. 1.ret和retf ret指令用栈中的数据,修改IP的内容,从而实现近转移: retf指令 ...
- 第十章 Call 和 Ret 指令
引言 想想程序之间的加载返回过程. call 和 ret 指令都是转移指令,它们都修改 IP,或同时修改 CS 和 IP. call 和 ret 经常被共同用来实现自程序的设计. 这一章,我们讲解 c ...
- 汇编语言笔记 CALL和RET指令
转载地址:http://www.cnblogs.com/dennisOne ☞模块化程序设计 模块化程序设计 汇编语言通过call和ret指令实现了模块化程序设计.可以实现多个相互联系.功能独立的子程 ...
- 自己总结:汇编CALL和RET指令
ret指令,相当于 pop IP:修改IP的内容,从而实现近转移 retf指令,相当于 pop IP pop CS:修改CS和IP的内容,从而实现远转移 -------------- CPU执行cal ...
- 王爽汇编第十章,call和ret指令
目录 王爽汇编第十章,call和ret指令 call和ret指令概述: ret和retf ret指令 retf指令 call 和 ret 的配合使用 call指令详解 call原理 call指令所有写 ...
随机推荐
- Golang Module快速入门
前言: 在Golang1.11之前的版本中,官方没有提供依赖和包管理工具.开发者通常会使用vendor或者glide的方式来管理依赖(也有直接使用GOPATH多环境方式),而在Golang1.11之后 ...
- pycharm虚拟环境的搭建
目录 优点 windows 安装 配置虚拟环境管理器工作目录 MacOS.Linux 安装 工作文件 配置 使用 pycharm使用 新建项目 添加环境 使用环境 优点 1.使不同应用开发环境相互独立 ...
- jwt认证规则
目录 认证规则图 django不分离 drf分类 认证规则演变图 数据库session认证:低效 缓存认证:高效 jwt认证:高效 缓存认证:不易并发 jwt认证:易并发 JWT认证规则 优点 格式 ...
- C# 添加log4net日志
一.添加log4net的Nuget包 二.在Web.config或者App.config文件中添加log4net配置 代码: <log4net> <!-- OFF, FATAL, E ...
- 【opencv源码解析】 二、 cvtColor
这里以CV_BGR2YUV_I420来讲 1. opencv244 core.cpp void cv::cvtColor( InputArray _src, OutputArray _dst, int ...
- form表单中的enctype 属性以及post请求里Content-Type方式
对于form表单中的enctype 属性之前理解的一般,就知道是类似于一种编码形式.后来公司做一个form表单提交数据的时候,重点是这个form表单里有文件上传,而我又要用vue来模拟form表单提交 ...
- 把json1赋值给json2,修改json2的属性,json1的属性也一起变化
let json1 = { a: 1}let json2 = json1json2.a = 5 console.log(json1.a) // 5 console.log(json2.a) // 5 ...
- python list按字典的key值排序
方法1: result_list = sorted(origin_list, key=lambda e: e.__getitem__('order_key')) 方法2: import operato ...
- kali工具的总结
由于篇幅有限,只列举部分,ps:第一次发有什么不对的 还望各位大大指正 nc 瑞士军刀 [v1.10-41] 使用格式: nc [-参数] 主机名 端口[s] [端口] … 侦听入站: nc -l - ...
- Oracle【二维表的维护】
二维表的维护 --添加新的字段:alter table 表名 add 字段名 类型 [一般不加约束条件] ) 原表:新增字段后的表:修改原有的字段:[修改字段类型.修改字段名.删除字段] --修改字段 ...