call 和 ret 都是可以改变 ip 或是 cs 和 ip 。经常用来实现子程序设计。

10.1 ret 和 retf

ret指令用栈中的数据,修改IP实现近转移
retf指令用栈中的程序,修改call和ret内容实现远转移。

CPU执行ret指令时:
pop ip

CPU执行retf指令时:
pop ip
pop cs
所以压栈的时候是先压 cs,再压 ip

检测点10.1


mov ax,1000h
mov ax,0

10.2 call 指令

CPU执行call时候,

  1. 压入 ip 或 cs 和 ip。
  2. 转移

cal不能实现短转移,并且原理和jmp相同

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

  1. 将当前sp压栈,push ip ; sp-1,放入ip
  2. IP = IP + 16位位移地址

16位位移 = 目标地址-call指令后一个指令的初始地址。;和 jmp near ptr 标号 类似。

检测点 10.2

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

当 call s 的时候,此时的 CS:IP指向的是 1000:6,所以将 此时的 IP=6 压入栈中。而后再 1000:7的时候,pop 出 6 给 ax。所以 ax最后的数值为 6。

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

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

  1. push cs
    push ip

  2. cs = 标号所在段的段地址
    ip = 标号所在的偏移地址

其实相当于 push cs, push ip,jmp far ptr 标号。

检测点 10.3

先将 CS:IP 压入栈中 push 1000, push 8
pop ax ; ax = 8
add ax,ax; ax = 16
pop bx; bx = 1000
add ax,bx ; ax = 1016
所以ax 最后的值为1016.

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

指令格式: call 16 位 reg

push ip
jmp16位 reg ;ip = 16位 reg

检测点 10.4

mov ax,6 ;ax = 6
call ax; push 5 ,jmp ax
mov bp,sp;
add ax,[bp]; 6 + 5 =11
所以最后ax = 11

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

  1. call word ptr 内存单元地址
    push ip
    jmp word ptr 内存单元地址
  2. call dword ptr 内存单元地址
    push cs
    push ip
    jmp dword ptr 内存单元地址 ; 例如 ds:[0]是cs,ds:[2]是ip

检测点 10.5


call word ptr ds:[0EH] ;将IP = 0011h push栈中,也就是在0EH位置上。ds 和 ss 指向同一个段。所以 ds:[0EH]内容也就是 刚刚才压入的下一条指令的地址。所以继续执行。
所以到了mov ax,4c00h前,ax为3.


ax = 0, bx = 0

10.7 call 和 ret 的配合使用

bx = 1
ax = 1+1=2, ax = 4, ax=8
mov bx,ax,所以 bx= 8

10.8 mul 指令

两个都是8位: 最大255
al * 8位reg / 内存单元=》ax
两个都是16位
ax*16位reg / 内存单元=》 dx ax
格式:

mul reg
mul 内存单元

10.9 模块化程序设计

call 和 ret 指令共同支持了汇编语言编程中的模块化设计。

10.10 参数和结果传递的问题

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

通过寄存器

assume cs:code
data segment dw 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,0mov di,16mov cx,8
s:  mov bx,[si]call cubemov [di],axmov [di].2,dxadd si,2add di,4loop smov ax,4c00hint 21hcube:  mov ax,bxmul bxmul bxret
code ends
end start

10.11 批量数据的传递

当需要传入一个参数,两个参数时,我们勉强还可以用寄存器来存。但如果是10个,20个呢?
所以在这种时候,我们要将参数传入内存中。
例如,将字符串全部大写化:

assume cs:codedata segmentdb 'conversation'
data endscode segment
start:  mov ax,datamov si,0mov cx,12call capitalmov ax,4c00hint 21h; void capital (si, cx)
capital:    and byte ptr [si],11011111binc siloop capitalret
code ends
end start

10.12 寄存器冲突的问题

以上的程序如果在数据段中:

data segmentdb 'helloworld',0
data ends

这样只传入si

;void capital (si)
capital :mov cl,[si]mov ch,0jcxz okand byte ptr [si],11011111binc sijmp short capital
ok :ret

因为是CX判断是否为0跳转,所以如果在外面套上 标号 和 loop 标号,就会出现混乱。

问题10.2

cx 的使用出现了混乱,主程序与子程序共同使用了cx。

解决:

  1. 换其他寄存器
  2. 不要使用其他会产生冲突的寄存器。

所以说不如直接换用栈来存储。

实验10 编写子程序

assume cs:code, ds:datadata segment db 'Welcome to masm!',0
data endscode segment
start:mov dh,8mov dl,3mov cl,2mov ax,datamov ds,axmov si,0call show_strmov ax,4c00hint 21h; void show_str (dh,dl,cl,ds:si)
show_str:mov ax,0b800hmov es,ax ;要显示的起始段 esmov al,160mul dhmov dh,0add dx,dxadd ax,dxmov di,ax ;要显示的起始位置 dimov ah,cl  s:    mov ch,0mov cl,[si]jcxz s0mov ch,ah; 字符所在寄存器 cxmov es:[di],cxadd di,2inc sijmp ss0: retcode ends
end start

运行结果:

assume cs:code
code segment
start:mov ax,4240hmov dx,000Fhmov cx,000Ahcall divdwmov ax,4c00hint 21hdivdw: ;dx,ax,cx divdw(dx,ax,cx)mov di,dxmov si,ax;X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N;=左边+右边mov ax,dx ;右边mov dx,0hdiv cxmov ax,sidiv cx    ;dx,axmov bx,dx ;16余mov si,ax ;低16商mov ax,di ;左边mov dx,0div cxmov dx,ax ;高16商mov ax,si ;低16商mov cx,bx ;16余retcode ends
end start

运行结果:

;X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N = 左+右
这个公式中的65536是 1 0000h,也就是将ax放到dx中
所以,左边得到的就是高16位的商。右边多了/L,得到的余数就是最终的余数,得到的商就是低16位的商。


assume cs:code,ds:datadata segmentdb 10 dup(0)
data endsstack segmentdb 128 dup(0)
stack endscode segment
start:mov ax,stackmov ss,axmov sp,16mov ax,12666mov bx,datamov ds,bxmov si,0call dtocmov dh,8mov dl,3mov cl,2mov di,0mov si,0call show_strmov ax,4c00hint 21hshow_str: ;函数mov ax,0b800hmov es,ax ;要显示的起始段 esmov al,160mul dhmov dh,0add dx,dxadd ax,dxmov di,ax ;要显示的起始位置 dimov ah,cl  s2:  mov ch,0mov cl,[si]jcxz s3mov ch,ah; 字符所在寄存器 cxmov es:[di],cxadd di,2inc sijmp s2s3:    retdivdw: ;dx,ax,cx divdw(dx,ax,cx) 商h商l 余数push bxpush dipush simov di,dxmov si,ax;X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N;=左边+右边mov ax,dx ;右边mov dx,0hdiv cxmov ax,sidiv cx    ;dx,axmov bx,dx ;16余mov si,ax ;低16商mov ax,di ;左边mov dx,0div cxmov dx,ax ;高16商mov ax,si ;低16商mov cx,bx ;16余pop sipop dipop bxretdtoc: ;函数mov bx,ax ;备份axmov cx,10;准备条件mov dx,0mov si,1 ;初始一个数dtoc1:call divdwmov cx,dxor cx,axjcxz dtoc2inc simov cx,10jmp dtoc1dtoc2: inc simov byte ptr [si],0 ;假设一个五个数,那下标最大到4,所以下标5的地方设置一个 \0mov cx,sisub si,1mov ax,bxmov dx,0sub cx,1sub si,1
dtoc3:push cxmov cx,10call divdwmov [si],cladd byte ptr [si],'0' ; 填充字符sub si,1pop cxloop dtoc3retcode ends
end start

运行结果:

课程设计1

更改dtoc

assume cs:code,ds:datadata segmentdb 10 dup(0)
data endsstack segmentdb 128 dup(0)
stack endscode segment
start:mov ax,stackmov ss,axmov sp,16mov dx,00ffhmov ax,65535;12666 将值换成16,777,215mov bx,datamov ds,bxmov si,0call dtocmov dh,8mov dl,3mov cl,2mov di,0mov si,0call show_strmov ax,4c00hint 21hshow_str: ;函数mov ax,0b800hmov es,ax ;要显示的起始段 esmov al,160mul dhmov dh,0add dx,dxadd ax,dxmov di,ax ;要显示的起始位置 dimov ah,cl  s2:   mov ch,0mov cl,[si]jcxz s3mov ch,ah; 字符所在寄存器 cxmov es:[di],cxadd di,2inc sijmp s2s3:    retdivdw: ;dx,ax,cx divdw(dx,ax,cx) 商h商l 余数push bxpush dipush simov di,dxmov si,ax;X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N;=左边+右边mov ax,dx ;右边mov dx,0hdiv cxmov ax,sidiv cx    ;dx,axmov bx,dx ;16余mov si,ax ;低16商mov ax,di ;左边mov dx,0div cxmov dx,ax ;高16商mov ax,si ;低16商mov cx,bx ;16余pop sipop dipop bxretdtoc: ;函数push di  ;提前压入栈中mov di,dx ;更改 将dx存放在di中mov bx,axmov cx,10mov si,1dtoc1:call divdwmov cx,dxor cx,axjcxz dtoc2inc simov cx,10jmp dtoc1dtoc2: inc simov byte ptr [si],0mov cx,sisub si,1mov dx,di ;弹出dimov ax,bx ;弹出axsub cx,1sub si,1
dtoc3:push cxmov cx,10call divdwmov [si],cladd byte ptr [si],'0'sub si,1pop cxloop dtoc3pop di    ;最后不忘弹出diretcode ends
end start

运行结果:

任务,将实验7中的Power idea公司的数据按照图10.2所示的格式在屏幕上显示出来。

修改后的显示ax中的数字:

assume cs:code,ds:datadata segmentdb '1234',10 dup(0)
data endsstack segmentdb 128 dup(0)
stack endscode segment
start:mov ax,stackmov ss,axmov sp,16mov dx,00ffhmov ax,65535;12666 将值换成16,777,215mov bx,datamov ds,bxmov si,3call dtocmov dh,8mov dl,3mov cl,2mov di,0mov si,0call show_strmov ax,4c00hint 21hshow_str: ;函数 (dh,dl,cl,ds:si)push axpush bxpush dimov ax,0b800hmov es,ax ;要显示的起始段 esmov al,160; 一行160字节mul dh      ;乘以dh行mov dh,0add dx,dx     ;加上该行第几个add ax,dxmov di,ax ;要显示的起始位置 dimov ah,cl  ;字符属性s2:  mov ch,0    mov cl,[si] ;将字符放在该位置,结尾0结束jcxz s3mov ch,ah; 字符所在寄存器 cxmov es:[di],cxadd di,2inc sijmp s2s3: pop dipop bxpop axretdivdw: ;dx,ax,cx divdw(dx,ax,cx) 商h商l 余数push bxpush dipush simov di,dxmov si,ax;X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N;=左边+右边mov ax,dx ;右边mov dx,0hdiv cxmov ax,sidiv cx    ;dx,axmov bx,dx ;16余mov si,ax ;低16商mov ax,di ;左边mov dx,0div cxmov dx,ax ;高16商mov ax,si ;低16商mov cx,bx ;16余pop sipop dipop bxretdtoc: ;函数 dtoc(dx,ax,ds:si)push bxpush cxpush di    ;提前压入栈中push dx ;更改 将dx存放在di中push axmov cx,10mov di,1dtoc1:call divdwmov cx,dxor  cx,axjcxz dtoc2inc dimov cx,10jmp dtoc1dtoc2:add si,dimov byte ptr [si],0mov cx,disub si,1pop ax ;弹出dipop dx ;弹出ax;sub cx,1;sub si,1
dtoc3:push cxmov cx,10call divdwmov [si],cladd byte ptr [si],'0'sub si,1pop cxloop dtoc3pop di    ;最后不忘弹出dipop cxpop bxretcode ends
end start

汇编语言(第三版)第十章 CALL 和 RET 指令 笔记相关推荐

  1. 王爽老师汇编语言第四版第十章CALL和RET指令——小白笔记

    目录 10.1 ret和retf (1)  ret: (2)retf: 10.2 call指令 10.3依据位移进行转移的CALL指令 10.4 转移的目的地址在指令中的CALL指令 10.5转移地址 ...

  2. 开发日记-20190915 关键词 汇编语言王爽版 第十章

    第十章 CALL和RET指令 call 和ret指令都是转移指令,他们都修改IP,或同时修改CS和IP.他们经常被共同用来实现子程序的设计. 10.1 ret和retf ret指令用栈中的数据,修改I ...

  3. 非递归遍历二叉树(算法导论第三版第十章10.4-5)

    非递归遍历二叉树(算法导论第三版第十章10.4-5) template<typename T> void TraverseBinaryTreeNonRecursive(BinaryTree ...

  4. 给定一个n节点二叉树,写出一个O(n)时间的非递归的过程,将该树每个结点的关键字输出(算法导论第三版第十章10.4-5)

    给定一个n节点二叉树,写出一个O(n)时间的非递归的过程,将该树每个结点的关键字输出.要求除该树本树的存储空间外只能使用固定量的额外存储空间,且过程中不得修改该树,即使是暂时的修改也不允许. (算法导 ...

  5. Θ(n)反转单链表(算法导论第三版第十章10.2-7)

    Θ(n)反转单链表 (算法导论第三版第十章10.2-7) template<typename T> void reverses(Single_L<T> &l) {if( ...

  6. Deque(双向队列 c++模版实现 算法导论第三版第十章10.1-5题)

    Deque(双向队列 c++模版实现 ) 算法导论第三版第十章10.1-5题 #ifndef C11LEARN_DEQUE_H #define C11LEARN_DEQUE_H template< ...

  7. CSAPP 第三版 第十章 家庭作业and so on

    CSAPP 第三版 第十章 作业 自己做的 仅供参考 可能出现错误 注: 10.7之后 mark一下,寒假补坑,学校只教了一点,近期又在复习--于是直接照搬了学长的答案 https://www.cnb ...

  8. 读书笔记:汇编语言 第三版 王爽 清华出版社 章六 章七 章八 章九 章十

    第六章 包含多个段的程序6.0 概述合法地通过操作系统取得的空间都是安全的操作系统不会让多个程序之间发生空间冲突程序向操作系统获得空间的方法程序加载时分配在程序中定义各种段程序运行时分配通过指令向操作 ...

  9. 读书笔记:汇编语言 第三版 王爽 清华出版社 前言 章一 章二 章三 章四 章五

    汇编语言 第三版 王爽 清华出版社文档记录创建 2020年8月9日15:21:11初稿完成 2020年9月5日15:38:22前言汇编语言,CPU提供的机器指令的助记符的集合不同处理器,机器指令可能不 ...

最新文章

  1. 服务器模型——从单线程阻塞到多线程非阻塞(下)
  2. 什么是堆,栈,内存泄漏和内存溢出?
  3. 【tensorflow】tf.reshape函数说明:重塑张量
  4. MySQL双主io线程起不来_解决master and slave have equal MySQL server UUIDs导致Slave_IO_thread起不来问题...
  5. 搭建Redis服务器
  6. 使用.NET Core优雅获取并展示最新疫情数据
  7. LeetCode MySQL 1127. 用户购买平台 *
  8. 菜鸟学习笔记:Java基础篇6(数组、字符串)
  9. android控件之间的过渡动画效果,Android - 交换控件位置:基于LayoutParams的瞬间交换与基于ObjectAnimator动画效果交换...
  10. gssh推送 Warning: Permanently added 'gitee.com’to the list of known hosts.
  11. 客户价值分析—RFM模型及变形
  12. Oracle 定时任务(dbms_jobs)、expdp 与 impdp 数据泵导入导出
  13. 不要迷失在技术的海洋中(转)
  14. 让图片自适应屏幕大小
  15. 幼儿园故事导入语案例_幼儿园大班语言故事
  16. windows oracle部署碰到的问题:ORA-12541: TNS: 无监听程序/未找到wfmlrsvcapp.ear/导入命令
  17. MegaCli命令关闭jbod模式
  18. 解决 您的安全设置不允许将此应用程序安装到您的计算机上的问题
  19. Airtest自动化测试——批量执行脚本(实测)
  20. 全国计算机三级网络技术电子版,全国计算机三级网络技术最新版笔试电子教材(完全免费版).doc...

热门文章

  1. 湖北5G继续加码!今年投资64亿元,新建5G基站5万个
  2. NOIP 2005 篝火晚会
  3. Python 自动化办公
  4. 怎么批量提取html文件中的链接,excel怎么批量提取超链接
  5. Android处理二维码扫码枪数据
  6. C++/MFC 面试题(一)
  7. 消息队列:SpringBoot集成RocketMQ的那些坑(真实有效、附源码)
  8. webrtc-audio-processing pulseaudio最新版本1.0交叉编译到ARM
  9. iOS 保存图片到手机的几种方法--(OC)
  10. docker logs日志清除