CALL和RET指令

call和ret指令都是转移指令,它们都修改IP,或同时修改CS和IP。它们经常被共同用来实现子程序的设计


10.1 ret和retf

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

CPU执行ret指令时,进行下面2步操作(相当于pop IP):

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

CPU执行retf指令时,进行下面4步操作(相当于pop IP AND pop CS):

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

检测点 10.1
补全程序,实现从内存1000:0000处开始执行指令。

assume cs:code
stack segmentdb 16 dup(0)
stack endscode segmentstart:mov ax,stackmov ss,axmov sp,16;补全下面一条指令mov ax,1000hpush ax;补全下面一条指令mov ax,0hpush axretf
code ends
end start

实验结果如下:


10.2 call指令

CPU执行call指令时,进行2步操作:

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

10.3 依据位移进行转移的call指令

指令格式:call 标号(将当前的IP压栈后,转到标号处执行指令)

CPU执行此种格式的call指令时,进行如下操作(相当于执行了push IP AND jmp near ptr 标号):

  1. (sp)=(sp)−2(sp)=(sp)−2(sp)=(sp)-2
  2. ((ss)∗16+(sp))=(IP)((ss)∗16+(sp))=(IP)((ss)*16+(sp))=(IP)
  3. (IP)=(IP)+16位位移(IP)=(IP)+16位位移(IP)=(IP)+16位位移

检测点 10.2
下面的程序执行后,ax中的数值为多少?

内存地址 机器码 汇编指令 ax
1000:0 b8 00 00 mov ax,0 ax=0000h
1000:3 e8 01 00 call s ip=0006h
1000:6 40 inc ax 没有执行
1000:7 58 s:pop ax ax=0006h

发现,push的IP是执行指令后的IP


10.4 转移的目的地址在指令中的call指令

call far ptr 标号实现的是段间转移

CPU执行此种格式的call指令时,进行如下操作(相当于执行push CS AND push IP AND jmp far ptr 标号):

  1. (sp)=(sp)−2(sp)=(sp)−2(sp)=(sp)-2
  2. ((ss)∗16+(sp))=(CS)((ss)∗16+(sp))=(CS)((ss)*16+(sp))=(CS)
  3. (sp)=(sp)−2(sp)=(sp)−2(sp)=(sp)-2
  4. ((ss)∗16+(sp))=(IP)((ss)∗16+(sp))=(IP)((ss)*16+(sp))=(IP)
  5. (CS)=标号所在段的段地址(CS)=标号所在段的段地址(CS)=标号所在段的段地址
  6. (IP)=标号在段中的偏移地址(IP)=标号在段中的偏移地址(IP)=标号在段中的偏移地址

检测点 10.3
下面的程序执行后,ax中的数值为多少?

内存地址 机器码 汇编指令 ax
1000:0 b8 00 00 mov ax,0 ax=0000h
1000:3 9A 09 00 00 10 call far ptr s cs=1000h,ip=0008h
1000:8 40 inc ax 没有执行
1000:9 58 s: pop ax ax=0008h
1000:10 pop ax ax=1000h

10.5 转移地址在寄存器中的call指令

指令格式:call 16为reg
功能:

  1. (sp)=(sp)−2(sp)=(sp)−2(sp)=(sp)-2
  2. ((ss)∗16+(sp))=(IP)((ss)∗16+(sp))=(IP)((ss)*16+(sp))=(IP)
  3. (IP)=(16位reg)(IP)=(16位reg)(IP)=(16位reg)

相当于执行了push IP AND jmp 16位reg

检测点 10.4
下面的程序执行后,ax中的数值为多少?

内存地址 机器码 汇编指令 ax
1000:0 b8 06 00 mov ax,6 ax=0006h
1000:2 ff d0 call ax ip=0005h
1000:5 40 inc ax 没有执行
1000:6 8b ec mov bp,sp bp=sp
1000:8 03 36 00 add ax,[bp] ax=000Ah

注意,最后一条指令是add指令。


10.6 转移地址在内存中的call指令

转移地址在内存中的call指令有两种格式
(1)call word ptr 内存单元地址,相当于push IP AND jmp word ptr 内存单元地址
(2)call dword ptr 内存单元地址,相当于push CS AND push IP AND jmp dword ptr 内存单元地址

检测点 10.5
(1)下面的程序执行后,ax中的数值为多少?(注意:用call指令的原理来分析,不要在Debug中单步跟踪来验证你的结论。对于此程序,在Debug中单步跟踪的结果,不能代表CPU的实际执行结果)

assume cs:code
stack segmentdw 8 dup(0)
stack ends
code segmentstart:mov ax,stack                ;ax=stackmov ss,ax                   ;ss=axmov sp,16                   ;sp=16mov ds,ax                   ;ds=axmov ax,0                    ;ax=0call word ptr ds:[0EH]      ;push ip AND jmp ds:[0eh]inc ax                      ;上面的应该是这条指令的ip,jmp ds:[0eh]应该;转跳这条指令,那么ax=1inc ax                      ;ax=2inc ax                      ;ax=3mov ax,4c00hint 21h
code ends
end start

这真的很奇怪的程序,会懵!

(2)下面的程序执行后,ax和bx中的数值为多少?

assume cs:code
data segmentdw 8 dup(0)
data ends
code segmentstart:mov ax,data                     ;ax=datamov ss,ax                       ;ss=axmov sp,16                       ;sp=16mov word ptr ss:[0],offset s    ;ss:[0]=s的地址mov ss:[2],cs                   ;ss:[2]=cscall dword ptr ss:[0]           ;call (cs):(s的地址)nop                             ;ss:[0ch]=这条指令的地址;ss:[0eh]=css:mov ax,offset s                 ;ax=s的地址sub ax,ss:[0ch]                 ;ax=ax-ss:[0ch] = 1mov bx,cs                       ;bx=cssub bx,ss:[0eh]                 ;bx=bx-cs=0mov ax,4c00hint 21h
code ends
end start

实验结果如下:


10.7 call和ret的配合使用

现在来看一下,如何将它们配合使用来实现子程序的机制

问题 10.1
下面程序返回前,bx中的值是多少?

assume cs:code
code segmentstart:mov ax,1        ;1.ax=1mov cx,3        ;2.cx=3call s          ;3.push 下一条指令的IP,jmp s处mov bx,ax       ;6.(bx)=8mov ax,4c00hint 21hs:add ax,ax       loop s          ;4.ax=2^3次方,后结束这个loopret             ;5.pop ip,就返回到6处
code ends
end start

具有子程序的源程序框架如下:

assume cs:code
code segmentmain: ....call sub1    ;调用子程序sub1..mov ax,4c00hint 21hsub1:..           ;子程序sub1开始call sub2    ;调用子程序sub2..ret          ;sub1子程序返回sub2:..           ;子程序sub2开始..ret          ;sub2子程序返回
code ends
end main

10.8 mul指令

mul是乘法指令,使用mul做乘法的时候注意以下两点
(1)两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果是8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中;如果是16位,一个默认在AX中,另一个放在16位reg或内存单元中。
(2)结果:如果是8位乘法,结果默认放在AX中;如果是16位乘法,结果高位默认在DX中存放,低位在AX中存放。

格式如下:

mul reg
mul 内存单元

示例程序:计算100*10000

mov ax,100
mov bx,100000
mul bx

结果:(ax)=4240H,(dx)=000FH(ax)=4240H,(dx)=000FH(ax)=4240H,(dx)=000FH。


10.9 模块化程序设计

call与ret指令共同支持了汇编语言编程中的模块化设计。在实际编程中,程序的模块化是必不可少的。因为现实的问题比较复杂,对现实问题进行分析时,把它转化成互相联系、不同层次的子问题,是必须的解决方法,我们可以用简捷的方法,实现多个相互联系、功能独立的子程序来解决一个复杂的问题


10.10 参数和结果传递的问题

子程序一般都要根据提供的参数处理一定的事务,处理后,将结果(返回值)提供给调用者

比如,设计一个子程序,可以根据提供的N,来计算N的3次方。这里面就有两个问题:

  1. 将参数N存储在什么地方?
  2. 计算得到的数值,存储在什么地方?

显然,可以用寄存器来存储,可以将参数放在bx中;因为子程序中要计算N^3,可以使用多个mul指令,为了方便,可将结果放在dx和ax中。子程序如下。

;说明:计算N的3次方
;参数:(bx)=N
;结果:(dx:ax)=N^3
cube:mov ax,bxmul bxmul bxret

10.11 批量数据的传递

如果有两个参数,那么可以用两个寄存器来存储,可是如果需要传递的数据有3个、4个或更多直至N个,该怎样存储呢?

这种时候,我们将批量数据放在内存中,然后将它们所在的内存空间的首地址放在寄存器中,传递给需要的子程序。对于具有批量数据的放回结果,也可用同样的方法

例如:编程,将data段中的字符串转化为大写。

assume cs:codedb 'conversation'
data ends
code segmentstart:mov ax,datamov ds,axmov si,0          ;ds:si指向字符串所在空间的首地址mov cx,12         ;cx存放字符串的长度call capitalmov ax,4c00hint 21hcapital:and byte ptr [si],11011111binc siloop capitalret
code ends
end start

10.12 寄存器冲突的问题

寄存器出现冲突,可以使用栈来解决。这个小节比较细,自己看书!

以后,我们编写子程序的标准框架如下:

子程序开始:子程序中使用的寄存器入栈子程序内容子程序中使用的寄存器出栈返回(ret、retf)

实验10 编写子程序

1. 显示字符串
问题:
显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使调用者可以决定显示的位置(行、列)、内容和颜色。
子程序描述
名称: show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:
(dh)=行号(取值范围0 24,(dl)=列号(取值范围0 79))(dh)=行号(取值范围024,(dl)=列号(取值范围079))(dh)=行号(取值范围0~24,(dl)=列号(取值范围0~79))
(cl)=颜色,ds:si指向字符串的首地址(cl)=颜色,ds:si指向字符串的首地址(cl)=颜色,ds:si指向字符串的首地址
返回:
应用举例:在屏幕的8行3列,用绿色显示data段中的字符串。

assume cs:code
data segmentdb 'Welcome to masm!',0
data endscode segmentstart:mov dh,8mov dl,3mov cl,2mov ax,datamov ds,axmov si,0call show_strmov ax,4c00hint 21hshow_str:push axpush bxpush cxpush es     push si;屏幕是B8000~BFFFFF这段;开始位置应该为dh*80*2+dl*2且MAX=4160<2^15mov ax,0B800hmov es,ax;计算开始位置;计算行mov ah,0mov al,dhmov bh,160;乘8位,dx不变mul bh;计算具体开始位置mov bh,0mov bl,dladd ax,bxadd ax,bx;得到开始位置mov bx,ax;开始显示mov ah,clcolor:mov cl,ds:[si]mov ch,0jcxz okmov al,ds:[si]mov es:[bx],almov es:[bx+1],ahadd bx,2inc sijmp short colorok:pop sipop espop cxpop bxpop axretcode ends
end start

实验结果:

2. 解决除法溢出的问题
问题:
前面讲过,div指令可以做除法。当进行8位除法的时候,用al存储结果的商,ah存储结果的余数;进行16位除法的时候,用ax存储结果的商,dx存储结果的余数。可是,现在有一个问题,如果结果的商大于al或ax所能存储的最大值,那么将如何?

比如:

mov bh,1
mov ax,1000
div bh

此时,al放不下1000,这就是除法溢出

子程序描述
**名称:**divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
参数:
(ax)=dword型数据的低16位(ax)=dword型数据的低16位(ax)=dword型数据的低16位
(dx)=dword型数据的高16位(dx)=dword型数据的高16位(dx)=dword型数据的高16位
(cx)=除数(cx)=除数(cx)=除数
返回:
(dx)=结果的高16位(dx)=结果的高16位(dx)=结果的高16位
(ax)=结果的低16位(ax)=结果的低16位(ax)=结果的低16位
(cx)=余数(cx)=余数(cx)=余数
应用举例:计算1000000/10(F4240H/0AH)

assume cs:code,ss:stackstack segmentdw 8 dup(0)
stack endscode segmentstart:mov ax,4240hmov dx,000fhmov cx,0ahcall divdwmov ax,4c00hint 21hdivdw:push bxpush es;高mov es,dx;低mov bx,ax;X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N;int(H/N);rem(H/N)mov ax,esmov dx,0div cx;int(H/N)*65536,ax存储商,es存储高位结果mov es,ax;rem(H/N)*65536+L,dx存储余数,dx存储高位,bx是低位mov ax,bx;[rem(H/N)*65536+L]/N,得到低位结果,用ax存储div cx;余数是dxmov cx,dx;此时得出2个结果了,低位结果在AX中,高位结果在es中mov dx,espop espop bxretcode ends
end start

实验结果:

3. 数值显示
问题:
编程,将data段中的数据以十进制的形式显示出来。
子程序描述:
名称: dtoc
功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。
参数:
(ax)=word型数据(ax)=word型数据(ax)=word型数据
ds:si指向字符串的首地址ds:si指向字符串的首地址ds:si指向字符串的首地址
返回:
应用举例:编程,将数据12666以十进制的形式在屏幕的8行3列,用绿色显示出来。在显示时,我们调用本次实验中的第一个子程序show_str

assume cs:code,ds:datadata segmentdb 10 dup (0)
data endscode segmentstart:mov ax,12666mov bx,datamov ds,bxmov si,0call dtocmov dh,8mov dl,3mov cl,2call show_strmov ax,4c00hint 21hdtoc:push axpush bxpush cxpush dxpush sipush di;初始化mov bx,10mov dx,0mov di,0;求余数s:mov cx,axjcxz revdiv bx;ax是商,dx是余数add dl,30hmov ds:[si],dlinc si;dx需要置0mov dx,0jmp short srev:push cx;逆序,循环si/2次结束mov dx,0mov ax,simov bx,2div bxmov cx,ax;si是长度,下标是从0开始,所以需要-1dec sirev_loop:;前缀mov al,ds:[di];后缀mov ah,ds:[si];交换mov ds:[si],almov ds:[di],ah;前缀自增inc di;后缀自减dec siloop rev_looppop cxjmp okok:pop dipop sipop dxpop cxpop bxpop axretshow_str:push axpush bxpush cxpush espush si;屏幕是B8000~BFFFFF这段;开始位置应该为dh*80*2+dl*2且MAX=4160<2^15mov ax,0B800hmov es,ax;计算开始位置;计算行mov ah,0mov al,dhmov bh,160;乘8位,dx不变mul bh;计算具体开始位置mov bh,0mov bl,dladd ax,bxadd ax,bx;得到开始位置mov bx,ax;开始显示mov ah,clcolor:mov cl,ds:[si]mov ch,0jcxz ok1mov al,ds:[si]mov es:[bx],almov es:[bx+1],ahadd bx,2inc sijmp short colorok1:pop sipop espop cxpop bxpop axretcode ends
end start

这题做了一天,出错地方在div bx那条语句,如果直接执行div bx,会出现死循环,可是debug又不出现死循环。最后将dx置0即可

课程设计

改天做,这里放置超链接!

CALL和RET指令---汇编学习笔记相关推荐

  1. [BX] 和 loop 指令---汇编学习笔记

    [BX] 和 loop 指令 [bx]和内存单元的描述 loop 我们定义的描述性的符号:"()","()"中的元素可以有3中类型:寄存器名.段寄存器名.内存单 ...

  2. int指令---汇编学习笔记

    int指令 int指令可以引发中断 13.1 int指令 int指令格式:int n,n为中断类型码,它的功能是引发中断过程. CPU执行int n指令,相当于引发一个n号中断的中断过程,执行过程如下 ...

  3. E8/E9/FF 15/FF25指令--汇编学习笔记

    E8/FF 15:这两个指令都是call指令,两个指令后面跟的数据有不同的含义. 011472A1 E8 9F A3 FF FF call Sub_1 (01141645h) 011472B6 FF ...

  4. 汇编学习笔记——汇编指令

    目录 汇编指令 nop指令 mov.add.sub指令 adc.sbb指令 and.or指令 移位指令 逻辑左/右移指令 循环左/右移指令 算术左/右移指令 带进位循环左/右移指令 inc指令 pus ...

  5. 汇编学习笔记——伪指令

    目录 伪指令 段定义 结束标记 段关联标记 数据定义 标号 offset指令 seg指令 地址标号 数据标号 代码分段 程序标识 多文件系统 字符输入 重复定义 注释 重复汇编伪指令 伪指令汇总 伪指 ...

  6. 汇编学习笔记:对抗反汇编实验2019092801

    汇编学习笔记:对抗反汇编实验2019092801 实验描述 实验环境 实验过程 实验结论 实验描述 使用相连的jz和jnz指令跳转到紧接着jnz指令的call指令的第二个字节.call指令实际上无效. ...

  7. Vue学习(入门实例、常用指令)-学习笔记

    文章目录 Vue学习(入门实例.常用指令)-学习笔记 实例 常用指令 v-on v-bind v-for v-html v-if event v-model 双向数据绑定实现 - defineProp ...

  8. Vue -- 指令【学习笔记】(持续更新)

    Vue – 指令[学习笔记](持续更新) 记录了Vue第三天的学习笔记 v-show 注意,v-show 不支持 <template> 元素,也不支持 v-else. 带有 v-show ...

  9. 汇编学习笔记(二):转移指令

    章节目录 转移指令原理 jmp 指令 jcxz 指令 loop 指令 ret 和 retf 指令 call 指令 call+ret 作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人 ...

最新文章

  1. php对应 c int16,PHP中十进制 和十六进制的转换问题
  2. css超出一行省略号:text-overflow和white-space超出隐藏显示省略号
  3. Java黑皮书课后题第4章:*4.15(电话键盘)电话上的国际标准字母/数字映射如下所示。编写程序,提示用户输入一个小写或大写字母,然后显示对应数字。对于非字母输入,提示非法输入
  4. JavaScript更改class和id的方法
  5. python 动态编译代码,Python:在运行时动态创建函数
  6. 7005.element-ui组件
  7. web前端基础(05htmlimg标签和滚动标签)
  8. react大数据量渲染_UseEffect在React中运行无限渲染(超过最大更新深度)
  9. 无法打开登录所请求的数据库 sa。登录失败。 用户 sa 登录失败。
  10. VMware vSphere常见问题汇总(十九)
  11. 典型的异步服务器端套接字构建
  12. 如何用一头死驴赚到998元
  13. 项目中用了spring这些牛逼的开发技巧,经理请我吃饭了
  14. 销售记账管理系统php源码,crm客户销售管理系统销售统计ERP系统源php源码源码办公审批管理...
  15. 韩顺平Java学习 面向对象【高级】(笔记)
  16. short 的算术运算
  17. C++类学习---------step1
  18. 道里云公司网络虚拟化架构NVI技术开放源代码--序言
  19. 视觉享受,兼顾人文观感和几何特征的字体「GitHub 热点速览 v.22.46」
  20. 苹果iPhone 12系列发布会:四款新机亮相均支持5G

热门文章

  1. 分享一款多功能免费SEO工具箱-从0开始打造高流量网站
  2. 线性回归基础相关公式
  3. 一款不愿透露姓名的绿色小说软件
  4. 埃森哲java笔试_【埃森哲Java面试】埃森哲java面试-看准网
  5. 计算机专业生物信息方向博士,我是这样拿到宾大生物信息学全奖博士offer的
  6. 时间进度管理-甘特图
  7. autogen.sh出错
  8. Linux arping命令测试IP地址冲突
  9. arping常见用法
  10. 如何为Android Activity设置背景图片?