《汇编语言》- 读书笔记 - 第10章-CALL 和 RET 指令

《汇编语言》- 读书笔记 - 第10章-CALL 和 RET 指令

  • 10.1 ret 和 retf
    • 检测点 10.1
  • 10.2 call 指令
  • 10.3 依据位移进行转移的 call 指令
    • 检测点 10.2
  • 10.4 转移的目的地址在指令中的 call 指令
    • 检测点 10.3
  • 10.5 转移地址在寄存器中的 call 指令
  • 10.6 转移地址在内存中的 call 指令
    • 检测点 10.5
  • 10.7 call 和 ret 的配合使用
    • 问题 10.1
  • 10.8 mul 指令
    • 例1. 计算 100*10
    • 例2. 计算 100*10000
  • 10.9 模块化程序设计
  • 10.10 参数和结果传递的问题
  • 10.11 批量数据的传递
  • 10.12 寄存器冲突的问题
    • 问题举例:
    • 解决思路:
    • 子程序的标准框架
      • 改进后的子程序 capital
  • 实验 10 编写子程序

callret 指令都是转移指令,都有修改 IPCS:IP两个版本。
callret 指令共同支撑了汇编语言中的 模块化设计实现。
call 指令用于 调用子程序,它将 返回地址压入 堆栈并跳转至 子程序入口地址。
ret 指令在 子程序执行 完毕后从 堆栈中弹出 返回地址,并跳转回 主程序调用点继续执行。

10.1 ret 和 retf

指令修改CS修改IP行为用途
ret
(Return from Procedure)
POP IP:将栈顶的值弹出,并送进IP从子程序返回。
retf
(Return from Procedure Far)
POP IP将栈顶的值弹出,送进IP
POP CS将从栈中弹出一个值,送进CS
从远过程(far subroutine)返回

检测点 10.1

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.1

10.2 call 指令

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

  1. 将当前的 IPCSIP 压入栈中;
  2. 转移。(与 jmp 唯一的不同在于没有短转移 : jmp short 标号 )
命令说明修改的
寄存器
例子(假设有标号叫 label
call 标号位移跳转,实现段内转移。位移范围在:-32768 ~ 32767
将当前IP压栈后,转到标号处执行指令。相当于:
1. push IP
2.jmp near ptr 标号
IPcall label
call far ptr 标号目标地址,实现段间转移。相当于:
1. push CS
2. push IP
3.jmp far ptr 标号
CS:IPcall far ptr label
call 16位寄存器转移地址在寄存器中,相当于:
1. push IP
2.jmp 16位寄存器
IPcall ax
call word ptr [内存]转移地址在内存中,实现段内转移。相当于:
1. push IP
2.jmp word ptr 内存单元地址
IPcall word ptr ds:[0]
call dword ptr [内存]转移地址在内存中,实现段间转移。相当于:
1. push CS
2. push IP
3.jmp dword ptr 内存单元地址
IPcall dword ptr ds:[0]

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

检测点 10.2

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.2

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

检测点 10.3

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.3

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

## 检测点 10.4
《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.4

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

检测点 10.5

《汇编语言》- 读书笔记 - 各章检测点归档 - 检测点 10.5

10.7 call 和 ret 的配合使用

问题 10.1

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

assume cs:code 
code segment
start:	mov ax,1mov cx,3call smov bx,ax		;(bx)=?mov ax,4c00hint 21h
s:		add ax,axloop sret
code ends
end start
  1. call s 会将当前 IP 存入栈中,跳到 s 处执行。
  2. s 标号这里是一个 loop 循环 cx 初始为 3 所以会循环 3 次。
    2.1. 第一次 add ax, ax, ax = 1+1 = 2;
    2.2. 第二次 add ax, ax, ax = 2+2 = 4;
    2.3. 第三次 add ax, ax, ax = 4+4 = 8;
  3. loop 循环结束后 ret 返回 call s 处,继续执行它下面的指令。此时 ax = 8
    sret这段实现的是计算2n 次方,ncx 提供。
  4. 所以 mov bx, ax 的结果是 bx = 8
  5. 下一句 mov ax,4c00h 退出程序,最终程序返回前 bx 中的值是 8

通过对问题 10.1的探讨,引出:利用 callret 来实现子程序的机制。
子程序的框架如下:

标号:指令ret

具有子程序的源程序的框架如下:
在这里插入图片描述

10.8 mul 指令

mul 是乘法指令。两个相乘的数,要么都是8位,要么都是 16 位

  1. 乘数:可以是816位。
    1.1. 但两个乘数必须都是 8位,或都是16位。(不能一8位,一个16位)
    1.2. 如果是8位乘法:一个乘数默认在 AL 中,另一个在8位寄存器内存【字节】单元中。
    1.3. 如果是16位乘法:一个乘数默认在 AX 中,另一个在16位寄存器内存【字】单元中。

  2. 结果
    2.1. 8位乘法:结果在AX
    2.2. 16位乘法:结果高16位DX低16位AX

乘法位数乘数A乘数B结果例子
8位乘法ALah | bl | bh | cl
| ch | dl | dh | [字节单元]
AXmul bl
mul byte ptr ds:[0]
16位乘法AXbx | cx | dx | [字单元]DX AXmul bx
mul word ptr [bx+si+8]

例1. 计算 100*10

assume cs:code 
code segment
start:	mov al,100mov bl,10mul bl
code ends
end start

在这里插入图片描述

parseInt('03E8', 16); // 1000

例2. 计算 100*10000

assume cs:code 
code segment
start:	mov ax,100mov bx,10000mul bx
code ends
end start

在这里插入图片描述

parseInt('F4240', 16); // 1000_000

10.9 模块化程序设计

  1. 模块化设计在汇编语言中至关重要,通过拆解复杂问题为相互关联的子问题
  2. callret 指令支持模块化编程,分别用于调用返回子程序。
  3. 子程序利用这两指令实现功能独立逻辑分离,便于解决复杂问题。

总之,callret 提供了实现子程序的基础,以解决复杂的编程问题。什么提高代码可读性、可维护性和复用性,布啦布啦布啦。。。

10.10 参数和结果传递的问题

  1. 在设计函数经常要考虑的就是怎么传参、怎么返回值。
    1.2. 优先使用寄存器,比较方便。寄存器不够用,就使用内存。
  2. 注释要写清楚。起码以后自己要能看懂(不要高估和曾经那个自己之间的默契)

编程,计算 data 段中第一组数据的3次方,结果保存在后面一组 dword 单元中。

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,data		; 设置数据段mov ds,axmov si,0		;ds:si 指向第一组 word 单元mov di,16		;ds:di 指向第二组 dword 单元mov cx,8		; 设置循环次数 8s:	mov bx,[si]		; 主程序,读取数据到 bx ("用 bx 传参")call cubemov [di],ax		; 先存低16"主程序拿到子程序放在 ax 中的返回值"mov [di].2,dx	; 再存高16"主程序拿到子程序放在 dx 中的返回值"add si,2		;ds:si 指向下一个 word 单元add di,4		;ds:di 指向下一个 dword 单元loop smov ax,4c00hint 21h; cube 子程序:计算 n 的 3 次方cube:	mov ax,bx		; 子程序从("bx 读取传参")mul bxmul bxret				; 子程序返回 "(返回值)""ax,dx" 中
code ends
end start

在这里插入图片描述

计算 3 次方的数12345678
内存中结果
低位在前,高位在后
(高16位都是0忽略)
01 0008 001B 0040 007D 00D8 0057 0100 02
调整一下顺序00010008001B0040007D00D8015702 00
转成10进制182764125216343512

10.11 批量数据的传递

数据大了就需要用内存传参返回了。
寄存器用来传递内存地址。

assume cs:code 
data segmentdb 'conversation'
data endscode segment
start:	mov ax,data		; 设置数据段mov ds,axmov si,0		; ds:si 指向字符串(批量数据)所在空间的首地址mov cx,12		; cx存放字符串的长度call capital	; 调用子程序mov ax,4c00hint 21h; 子程序:转大写
capital:and byte ptr [si],11011111b ; 转为大写字符inc siloop capital				; 循环处理字符ret
code ends
end start

在这里插入图片描述

10.12 寄存器冲突的问题

本节用一个子程序 举例,在主程序子程序使用了同样的寄存器,那么将产生冲突。

问题举例:

  1. 首先:主程序在 CX 中保存了循环次数。
  2. 然后:子程序中的循环计数也用到了CX
  3. 结果:当从子程序返回主程序时,主程序的循环计数已经丢失。程序无法按预期执行。

解决思路:

  1. 子程序具体业务代码开始前,把会用到的寄存器保存到中。
  2. 子程序返回前出栈还原寄存器
  3. 注意入栈出栈时的顺序。(后入的先出)

子程序的标准框架

最终得出编写子程序的标准框架如下:

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

改进后的子程序 capital

capital:push cxpush sichange:mov cl,[si]mov ch,0jcxz okand byte ptr [si],11011111binc sijmp short changeok:pop sipop cxret

关于大小写的相关知识,详见:第7章 7.4 大小写转换的问题

实验 10 编写子程序

《汇编语言》- 读书笔记 - 实验 10 编写子程序

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/690604.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据模型概念

一、概念 (1) 定义 在数据库系统中针对不同的使用对象和应用目的,采用不同的数据模型。根据模型的应用的不同目的,可以将这些模型划分为两类: (2) 分类 A:概念数据模型 它也称信息模型它是按用户的观点(观念世界&…

Android 基础技术——Synchonized 关键字

笔者希望做一个系列,整理 Android 基础技术,本章是关于Synchonized 关键字 Synchronized 关键字的作用是什么? 原子性:确保线程互斥访问同步代码 可见性:保证共享变量的修改能够及时可见,就是通过 Java 内存…

JVM(2)实战篇

1 内存调优 1.1 内存溢出和内存泄漏 内存泄漏(memory leak):在Java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收,这种情况就称之为内存泄漏。 内存泄漏绝…

5G LAN

5G LAN定义 5G LAN 是企业专用蜂窝网络解决方案。5G LAN 集成到组织现有的 IT 基础设施中以提供 5G 的所有优势,以确定的性能和延迟为整个企业的关键任务数字计划创建高速可预测的无线连接。根据定义,5G LAN 消除了在企业自己的环境中采用私有 5G 无线技…

单调队列和优先队列

本篇记录下一下关于单调队列和优先队列(堆)的方法以及解题思路. 文章目录 一. 单调队列1. 绝对差不超过限制得最长连续子数组2. 跳跃游戏 VI3. 设计自助结算系统4. 和至少为k的最短子数组5. 满足不等式的最大值 二. 优先队列1. 最后一块石头的重量2. 数据…

SQL实现模糊查询的四种方法总结

目录 一、一般模糊查询 二、利用通配符查询 1. _ 表示任意的单个字符 2. % 表示匹配任意多个任意字符 3. [ ]表示筛选范围 4. 查询包含通配符的字符串 一、一般模糊查询 1. 单条件查询 //查询所有姓名包含“张”的记录select * from student where name like 张 2. 多条…

十二:枚举与注解

文章目录 01、枚举类的使用1.1、枚举类的理解1.2、自定义枚举类1.3、使用enum关键字定义枚举类1.4、Enum类中的常用方法1.5、使用enum关键字定义的枚举类实现接口 02、注解的使用2.1、注解的理解2.3、如何自定义注解2.4、jdk中4个基本的元注解的使用12.5、jdk中4个基本的元注解…

uniapp 适配鸿蒙next调研

1.官方的一些回答 DCloud有资源第一时间得到鸿蒙无apk手机的上市计划。我们和华为保持着紧密沟通,会把握好节奏,不用担心。大家可以观察一个信号,等微信的鸿蒙next版敲定了,鸿蒙无apk手机就可以明确上市计划了。鸿蒙的开发语言是a…

算法竞赛STL:bitset使用方法

STL-bitset使用方法 文章目录 STL-bitset使用方法 容器描述: bitset是一种特殊的数组,它的每一个元素只能是0或1。每个元素只占用1bit空间,所以它是一种空间效率极高的数据结构。bitset在处理大量的位级数据时非常有用。 使用方法&#xff1…

数据结构:动态内存分配+内存分区+宏+结构体

一、作业 1.定义一个学生结构体&#xff0c;包含结构体成员&#xff1a;身高&#xff0c;姓名&#xff0c;成绩&#xff1b;定义一个结构体数组有7个成员&#xff0c;要求终端输入结构体成员的值&#xff0c;根据学生成绩&#xff0c;进行冒泡排序。 #include <stdio.h>…

UE蓝图 Cast节点和源码

系列文章目录 UE蓝图 Cast节点和源码 文章目录 系列文章目录Cast节点功能一、Cast节点用法二、Cast节点使用场景三、Cast节点实现步骤四、Cast节点源码 Cast节点功能 在Unreal Engine&#xff08;UE&#xff09;中&#xff0c;Cast节点是一种蓝图系统中的节点&#xff0c;用于…

【性能测试入门必看】性能测试理论知识

一、性能测试理论知识 1、常用的七种性能测试方法 (1) 后端性能测试&#xff1a;其实&#xff0c;你平时听到的性能测试&#xff0c;大多数情况下指的是后端性能测试&#xff0c;也就是服务器端性能测试。后端性能测试&#xff0c;是通过性能测试工具模拟大量的并发用户请求&…

linux系统Grafana关联zabbix显示

Grafana关联zabbix 服务器下载浏览器配置开启zabbix插件配置zabbix数据源可视化Zabbix数据 服务器下载 grafana-cli plugins list-remote grafana-cli plugins list-remote|grep -i zabbix grafana-cli plugins install alexanderzobnin-zabbix-appsystemctl restart grafana-…

HBase 进阶

参考来源: B站尚硅谷HBase2.x 目录 Master 架构RegionServer 架构写流程MemStore Flush读流程HFile 结构读流程合并读取数据优化 StoreFile CompactionRegion Split预分区&#xff08;自定义分区&#xff09;系统拆分 Master 架构 Master详细架构 1&#xff09;Meta 表格介…

抵御数据攻击:有效应对.360勒索病毒的方法

导言&#xff1a; 在数字时代&#xff0c;恶意软件已经成为网络安全的一大挑战&#xff0c;而.360勒索病毒则是其中一种具有破坏性的恶意软件。本文91数据恢复将介绍.360勒索病毒的特点、恢复被其加密的数据文件的方法以及预防措施&#xff0c;以帮助读者更好地了解和对抗这种…

Mysql查询统计最近12个月,每个月的数量,并且显示每个月份,如果月份没有数据量需要以“0”填充

文章目录 第一种&#xff1a;第二种&#xff1a;第三种&#xff1a;第四种&#xff1a;MySQL 5.8以下 是不支持 WITH RECURSIVE 的 第一种&#xff1a; 可以使用MySQL的日期和时间函数来生成包含最近12个月的日期&#xff0c;并且使用LEFT JOIN 和 GROUP BY 语句来统计每个月的…

Vue | (一)Vue核心(上) | 尚硅谷Vue2.0+Vue3.0全套教程

文章目录 &#x1f4da;Vue简介&#x1f4da;初识Vue&#x1f4da;模板语法&#x1f4da;数据绑定&#x1f4da;MVVM模型&#x1f4da;数据代理&#x1f407;回顾Object.defineproperty方法&#x1f407;何为数据代理&#x1f407;Vue中的数据代理 &#x1f4da;事件处理&#…

游戏分组/王者荣耀

题目描述 部门准备举办一场王者荣耀表演赛&#xff0c;有 10 名游戏爱好者参与&#xff0c;分 5 为两队&#xff0c;每队 5 人。 每位参与者都有一个评分&#xff0c;代表着他的游戏水平。 为了表演赛尽可能精彩&#xff0c;我们需要把 10 名参赛者分为实力尽量相近的两队。一…

C语言 判断当前存储大小端问题

1.代码1 #include<stdio.h>int check_sys(){int a1;return *(char*)&a;//将int*强制转换为char* 判断一个字节的内容就知道当前存储模式 } int main(){if(1check_sys())printf("小端");elseprintf("大端");return 0; }2.代码2 使用联合体判断大…

优先队列的用法

介绍 英文名-priority_queue队首元素为当前优先级最高的 访问 只能通过top()函数来访问队首元素 #include <iostream> #include <queue>//调用queue头文件 using namespace std; int main(){priority_queue<int> pq1;//定义&#xff1a;默认数字越大优先…