从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • 计算机简史

  • 数字电路

  • 计算机组成原理

    • 计算机组成原理(北大-陆俊林)

      • 概述-计算机组成原理(北大-陆俊林)
      • 第1周-计算机组成章节视频简介
      • 101-电子计算机的兴起
      • 102-冯·诺依曼结构的要点
      • 103-冯·诺依曼结构的小故事
      • 104-计算机结构的简化模型
      • 105-计算机执行指令的过程
      • 106-计算机输入和输出
      • 107-冯诺依曼结构和具体实现
      • 201-设计自己的计算机
      • 202-x86 体系结构
      • 203-x86 指令简介
      • 204-复杂的 x86 指令举例
      • 205-MIPS 体系结构
      • 206-MIPS 指令简介
      • 301-算术运算和逻辑运算
      • 302-门电路的基本原理
      • 303-寄存器的基本原理
      • 304-逻辑运算的实现
      • 305-加法和减法的实现
      • 306-加法器的优化
      • 401-乘法的运算过程
      • 402-乘法器的实现
      • 403-乘法器的优化 1
      • 404-乘法器的优化 2
      • 405-除法的运算过程
      • 406-除法器的实现
      • 407-除法器的优化
      • 501-处理器的设计步骤
      • 502-数据通路的建立
      • 503-运算指令的控制信号
      • 504-访存指令的控制信号
      • 505-分支指令的控制信号
      • 506-控制信号的集成
      • 601-流水线的基本原理
      • 602-流水线的优化
      • 603-超标量流水线
      • 604-流水线的冒险
      • 605-数据冒险的处理
      • 606-控制冒险的处理
      • 701-存储层次结构概况
      • 702-DRAM 和 SRAM
      • 703-主存的工作原理
      • 704-主存技术的发展
      • 705-高速缓存的工作原理
      • 706-高速缓存的组织结构
      • 707-存储容量的计算
      • 801-中断和异常的来源
      • 802-中断向量表的结构
      • 803-中断向量表的发展
      • 804-中断的处理过程
      • 805-内部中断分类说明
      • 806-基于中断的功能调用
      • 901-输入输出接口的基本功能
      • 902-输入输出接口的编址方式
      • 903-输入输出的控制方式
      • 904-中断控制方式
      • 905-外部中断的处理过程
      • 906-直接存储器访问方式
    • 字符编码入门

  • 操作系统

  • Linux

  • 计算机网络

  • 数据库

  • 编程工具

  • 装机

  • 计算机基础
  • 计算机组成原理
  • 计算机组成原理(北大-陆俊林)
2023-06-13

204-复杂的 x86 指令举例

# 204-复杂的 x86 指令举例

x86 作为复杂指令系统的代表,自然会有不少相当复杂的指令。 在这一节我们将会看到其中有代表性的一些例子。

‍

串操作指令是将存储器中的数据串进行每次一个元素的操作。 所谓一个元素可以是字节或者是字。 这个串可以很长,能够达到 64KB, x86 提供了 5 种不同的串操作指令, 并且还有 3 种重复前缀,可以与串操作指令配合使用。

​

这张表就展示了这 5 种串操作指令和 3 种重复前缀。 我们来选择其中一组进行介绍。

​

这个指令的格式非常简单,没有任何的操作数, 它的功能就是在存储器中将指定位置的 一个字节单元传送到存储器的另一个指定的位置。 与它配合的经常是这个重复前缀 REP, x86 的体系结构中有很多种的前缀,这个前缀的含义是当 CX 寄存器的值不等于 0 时,就重复执行这个串操作指令。 那么很奇怪的是这个指令没有任何操作数。

其实大家要注意 x86 当中有很多这样的没有操作数的指令,但这并不意味着它们比那些有操作数的指令要简单。 因为它们不写操作数,不是因为没有操作数, 很可能是因为操作数太多了,在指令中实在写不下, 因此它们实际上是有一些隐含的操作数。 对于这这条串传送指令,它要传送的数据串称为源串。 源串的地址默认放在 DS:SI 这组寄存器指向的位置。

而要传送的目的,我们称为目的串地址,默认放在 ES:DI 这组寄存器指向的位置, 而要传送的串的长度则放在 CX 寄存器当中。 我们可以看到,虽然没有写操作数,但是它实际有 5 个寄存器作为它的操作数。 不仅它有隐含的操作数,还有一些隐含的操作,除了进行串的传送之外,在完成这个操作之后,硬件上还会自动完成这些操作: 第一修改 SI 和 DI 寄存器,以指向下一个串元素。 然后再判断是否使用了重复前缀, 如果是,则将 CX 寄存器的内容减 1, 需要注意的是这些操作都是硬件自动完成的, 不需要程序员在软件中特别指定。

​

我们来看一个例子。假设我们在存储器中要进行一次数据串的传送。源串的位置在 12040 这个地址开始, 一共三个字节,我们希望传送到 12060 开始的地方。 那我们编写的程序是这样的,假设事先已配置好了数据段寄存器 DS 为 1000, 这个程序的前两条指令实际是将数据段寄存器的内容传送到附加段寄存器当中。只不过段寄存器之间不能直接传送,所以借用了 AX, 然后在 SI 寄存器当中保存源串的偏移地址, 在 DI 寄存器当中放入目的串的偏移地址, 这样 DS 和 SI 这组寄存器就指向了源串。 而 ES 和 DI 这组寄存器就指向了目的串。 下一条指令 CLD,这是确定传送的方向,一会再进行解释。

然后在 CX 寄存器当中存入 3,然后才是这条串传送指令。 前面加上了重复前缀,这样的配置就相当于连续执行了三次这条串传送指令。 当执行第一次传送之后,第一个字节被传送到了目的串的位置, 传送完成后,SI 和 DI 自动被增加,CX 自动被减 1. 这些操作都是由 CPU 完成的。

​ ‍

同时我还要说明,所谓的传送这个字节实际上是被 CPU 发起的向 12040 地址的读操作,读入到 CPU 中,再发起一次向 12060 地址的存储器写操作, 写入到对应的字节单元。在第二次传送后, SI 和 DI 又被加 1,CX 又被减 1, 第三次传送完之后,虽然 SI 和 DI 继续加 1, 但 CX 已经减为 0,所以不再继续执行。

​

还需要说明一点的是串传送的方向也是可以设置的。 如果设置 DF=0,则是从源串的低地址开始传送, 在传送过程中,SI 和 DI 是自动增量的修改。 如果设置 DF-=1,则是从源串的高地址开始传送, 传送过程中,SI 和 DI 自动减量的修改。 这个表格就说明了 SI 和 DI 的修改方法。那如何修改 DF 标志位呢? 其实 x86 提供了两条控制指令,对标志位进行操作。 STD 就是把 DF 标志置 1。CLD 就是我们刚才的例子中的那条指令,是把 DF 清 0。 这就可以确定串传送的方向。

​ ‍

设置这样的方向 实际上是为了应对源串和目的串有可能重叠的问题。 我们简单来看一个释意。如果源串和目的串在内存中是互相不重叠的,那这时候设置 DF 为 0,或者为 1,都没有关系。 但是如果你的源串和目的串有一个重叠, 那必须设置 DF 为 1,从高地址依次向低地址开始传送,不然图中绿色的重叠部分,就会在传送的一开始被覆盖,从而导致结果的错误。 ‍ 那如果源串和目的串是这样的重叠的形式,则必须设置 DF 为 0。 从低地址开始传送,原因也是一样的。

​​

除了串传送指令,还有其他类型的串操作。例如在一个数据 串种,查找特定的数据,或者比较两个数据串是否相同。 这样程序员有了很便利的手段,对一大块数据进行操作。 因此串操作指令是功能非常强大的指令,不过由于数据串当中的 元素数量有可能很多,因此串操作指令的执行时间也可能很长, 这是需要注意的。

最后我们从 一个有趣的例子来看一看 x86 指令的复杂程度。 这张图是 x86 指令的通用格式。 每一个小格都是指令格式中特定的位域。 那么我们可以人为写出一条指令来,这条指令是一个加法,而且 有一个前缀 LOCK,这和我们刚才学到的 REP 一样,都是指令的前缀。 这个加法,其中一个源操作数是 32 位的立即数。另一个源操作数以及目的操作数,是内存当中的一个 32 位的存储单元。 这个存储单元本应默认在数据段,但这里强制指定为在附加段, 这个存储单元的地址由 EAX 寄存器,ECX 寄存器 和一个立即数计算而得。要计算这个内存地址需要一次乘法,两次加法得到偏移地址,再和段机制 进行移位并相加的操作,然后访问这个存储单元得到 32 位数。 在与 1 2 3 4 5 6 7 8 这个立即数相加, 然后再访问这个存储单元,将这个数存进去, 这条指令的编码一共有 15 个字节, 可以认为是一条最长的 x86 指令 ,x86 指令的复杂程度由此可见一斑。

​

编程人员只用给出一条简短的指令, 计算机就可以完成非常复杂的工作,这自然是一件很好的事情。 计算机似乎就应该这么设计,可惜世界没有这么简单, 有人提出了完全相反的做法,我们下一节再说。

上次更新: 2025/6/3 17:50:46
203-x86 指令简介
205-MIPS 体系结构

← 203-x86 指令简介 205-MIPS 体系结构→

最近更新
01
语雀文档一键下载至本地教程
07-04
02
要成功,就不要低估环境对你的影响
07-03
03
血泪教训:电子设备要定期开机
07-02
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式