第3章“程序的机器级表示”:数据传送指令

news2024/11/20 0:46:44

文章目录

  • 3.4 访问信息
    • 3.4.1 操作数指示符
    • 3.4.2 数据传送指令
    • 3.4.3 数据传送示例

3.4 访问信息

一个 IA32 中央处理单元(CPU)包含一组八个存储 32 位值的寄存器,这些寄存器用来存储整数数据和指针。

下图显示了这八个寄存器。它们的名字都是以 %e 开头的,不过它们都有特殊的名字。
在这里插入图片描述
在最初的 8086 中,寄存器是 16 位的,每个都有特殊的用途。选择的名字就是用来反映各种用途的。在平面寻址中,对特殊寄存器的需求已经大为降低了。

在大多数情况中,前六个寄存器都可以看成通用寄存器,对它们的使用没有限制。之所以说“在大多数情况中”,是因为有些指令是以固定的寄存器作为源和/或目的的。

另外,在过程(procedures)处理中,对前三个寄存器(%eax%ecx%edx)的保存和恢复惯例将不同于接下来的三个寄存器(%ebx%edi%esi)。

最后两个寄存器(%ebp%esp)保存着指向程序栈中重要位置的指针,只有根据栈管理的标准惯例才能修改这两个寄存器中的值。

如上图所示,字节操作指令可以独立地读或者写前四个寄存器的两个低位字节。8086 中提供这样的特性是为了向后兼容 8008 和 8080,8008 和 8080 是两款可以追溯到 1974 年的微处理器。当一条字节指令更新这些单字节 “寄存器元素” 中的一个时,该寄存器余下的三个字节不会被改变。类似地,字操作指令可以读或者写每个寄存器的低 16 位。这个特性源自 IA32 是从 16 位微处理器演化而来的。

3.4.1 操作数指示符

大多数指令有一个或多个操作数(operand),指示出执行一个操作中要引用的源数据值,以及放置结果的目的位置。

IA32 支持多种操作数格式,如下图所示:
在这里插入图片描述
源数据值可以以常数形式给出,或是从寄存器或存储器中读出,结果可以存放在寄存器或存储器中。因此,各种操作数的可能性被分为三种类型。

  • 第一种是立即数(immediate),也就是常数值。在GAS中,采用标准 C 的表示方法,立即数的书写方式是 “ $ ” 后面跟一个整数,比如,$-577 或 $0x1F。任何32位的字都可以用作立即数,不过汇编器在可能时会使用一个或两个字节的编码。
  • 第二种类型是寄存器(register),它表示某个寄存器的内容。对双字操作来说,可以是八个 32 位寄存器中的一个(如 %eax);对字节操作来说,可以是八个单字节寄存器元素中的一个(如 %al)。在上图中,用符号 E a E_a Ea 来表示任意寄存器 a a a,用引用 R [ E a ] R[E_a] R[Ea] 来表示它的值,这是将寄存器集合看成一个数组 R R R,用寄存器标识符作为索引。
  • 第三类操作数是存储器引用,它会根据计算出来的地址(通常称为有效地址)访问某个存储器位置。因为将存储器看成一个很大的字节数组,用符号 M b [ A d d r ] M_b[Addr] Mb[Addr] 表示对存储在存储器中从地址 Addr 开始的 b b b 字节值的引用。为了简便,通常省去写在下方的 b b b

如上图所示,有多种不同的寻址模式,允许不同形式的存储器引用。表中底部的 I m m ( E b , E i , s ) Imm(E_b, E_i, s) Imm(Eb,Ei,s) 是最通常的形式。这样的引用有四个部分:一个立即数偏移 I m m Imm Imm,一个基址寄存器 E b E_b Eb,一个变址或索引寄存器 E i E_i Ei 和一个伸缩因子(scale factor) s s s,这里 s s s 必须是 1、2、4 或者 8。然后,有效地址被计算为 I m m + R [ E b ] + R [ E i ] ⋅ s Imm + R[E_b] + R[E_i] · s Imm+R[Eb]+R[Ei]s。引用数组元素时,会用到这种通用形式。其他形式只是这种通用形式的特殊情况,省略了某些部分。正如即将看到的,当引用数组和结构元素时,比较复杂的寻址模式是很有用的。

3.4.2 数据传送指令

最频繁使用的指令是执行数据传送的指令。操作数符号的通用性使得一条简单的传送指令能够完成许多机器中要好几条指令才能完成的功能。

下图列出的是一些重要的数据传送指令,最常用的是传送双字的 movl 指令。
在这里插入图片描述
源操作数指定一个值,它可以是立即数,可以存放在寄存器中,也可以存放在存储器中。

目的操作数指定一个位置,它可以是寄存器,也可以是存储器地址。

IA32 加了一条限制,传送指令的两个操作数不能都指向存储器位置。将一个值从一个存储器位置拷到另一个存储器位置需要两条指令——第一条指令将源值加载到寄存器中,第二条将该寄存器值写入目的位置。

下面这个 movl 指令示例给出了源和目的类型的五种可能组合。回想一下,第一个是源操作数,第二个是目的操作数:

在这里插入图片描述
movb 指令是类似的,除了它只传送一个字节。当一个操作数是寄存器时,它必须是图3.2中所示的八个单字节寄存器元素中的一个。

类似地,movw 指令传送两个字节。当它的一个操作数为寄存器时,它必须是上图3.2中所示的八个两字节寄存器元素中的一个。

movsblmovzbl 指令负责拷贝一个字节,并设置目的操作数中其余的位。movsbl 指令的源操作数是单字节的,它执行符号扩展到 32 位(也就是,将高 24 位设置为源字节的最高位),然后拷贝到双字的目的中。类似地,movzbl 指令的源操作数是单字节的,在前面加 24 个 0 扩展到 32 位,并将结果拷贝到双字的目的中。

字节传送指令比较

三个字节传送指令 movbmovsblmovzbl 之间有细微的差别,这里有一个示例:
在这里插入图片描述
在这些例子中,都是将寄存器 %eax 的低位字节设置成 %ebx 的第二个字节。movb 指令不改变其他三个字节。根据源字节的最高位,movsbl 指令将其他三个字节设为全1或全0。movzbl 指令无论如何都是将其他三个字节设为全0。


最后两个数据传送操作是用来将数据压入栈中和从栈中弹出数据的。正如即将看到的,栈在处理过程调用中起到至关重要的作用。pushlpopl 指令都只有一个操作数——用于压入的源数据和用于弹出的目的数据。

程序栈存放在存储器中某个区域。如下图3.5 所示,栈向下增长,这样一来,栈顶元素的地址是所有栈中元素地址中最低的。(根据惯例,栈是倒过来画的,栈“顶” 在图的底部。)
在这里插入图片描述

栈指针 %esp 保存着栈顶元素的地址。

将一个双字值压入栈中,首先要将栈指针减4,然后将值写到新的栈顶地址。因此,指令 pushl %ebp 的行为等价于下面这样两条指令:

subl $4, %esp
movl %ebp, (%esp)

它们之间的区别是在目标代码中 pushl 指令是编码为 1 个字节的,而上面那两条指令一共需要 6 个字节。图中前两栏给出的是当 %esp 为 0x108 和 %eax 为 0x123 时,执行指令 pushl %eax 的效果。首先 %esp 会减4,得到 0x104,然后会将 0x123 存放到存储器地址 0x104 处。

弹出一个双字这样的操作将包括从栈顶位置读出数据,然后将栈指针加 4。因此,指令 popl %eax 等价于下面这样两条指令:

movl (%esp), %eax
addl $4, %esp

图3.5 的第三栏说明的是在执行完 pushl 后立即执行指令 popl %edx 的效果。先从存储器中读出值 0x123,再写到寄存器 %edx 中,然后,寄存器 %esp 的值将增加为 0x108。如图中所示,值 0x123 仍然会保持在存储器位置 0x104 中,直到被另一条入栈操作覆盖。无论如何,%esp 指向的地址总是栈顶。

因为栈和程序代码以及其他形式的程序数据都是放在同样的存储器中,所以程序可以用标准的存储器寻址方法访问栈内任意位置。例如,假设栈顶元素是双字,指令 movl 4(%esp),%edx 会将第二个双字从栈中拷贝到寄存器 %edx

3.4.3 数据传送示例

一些指针的示例

函数 exchange 提供了一个关于 C 中指针使用的很好说明。

在这里插入图片描述

参数 xp 是一个指向整数的指针,而 y 是一个整数。

语句

int x = *xp;

表示我们将读存储在 xp 所指位置中的值,并将它存放到名字为 x 的局部变量中。这个读操作称为指针的间接引用(pointer dereferencing)C 操作符 * 执行指针的间接引用

语句

*xp = y;

正好相反——它将参数 y 的值写到 xp 所指的位置。这也是一种间接引用的形式(所以有操作符 *),但是它表明的是一个写操作,因为它是在赋值语句的左边。

下面是一个使用 exchange 的例子:

int a = 4;
int b = exchange(&a, 3);
printf("a = %d, b = %d\n", a, b);

这段代码会打印出:

a = 3, b = 4

C操作符 & (称为 “取址” 操作符)创建一个指针,在本例中,该指针指向保存局部变量 a 的位置。然后,函数 exchange 将用 3 覆盖存储在 a 中的值,但是返回 4 作为函数的值。注意如何将指针传递给 exchange,它能修改存在某个远处位置的数据。


作为一个使用数据传送指令的代码示例,考虑图 3.6 中所示的数据交换函数,既有 C 代码,也有 GCC 产生的汇编代码。省略了过程入口处的汇编代码,这些代码用来为运行时栈分配空间,以及在过程返回前回收栈空间的代码。除此之外剩下的代码,我们称之为 “过程体(body)”。

当过程体开始执行时,过程参数 xpy 存储在相对于寄存器 %ebp 中地址值的偏移 8 和 12 的地方。

  • 指令 1 和 2 会将这些参数传送寄存器 %eax%edx
  • 指令 3 间接引用 xp,并将值存储在寄存器 %ecx 中,对应于程序值 x
  • 指令 4 将 y 存储在xp
  • 指令 5 将 x 传送到寄存器 %eax。根据惯例,所有返回整数或指针值的函数都是通过将结果放在寄存器 %eax 中来达到目的的,因此这条指令实现了 C 代码中第 6 行的功能。

这个例子说明 movl 执行是如何用于从存储器中读值到寄存器的(指令 1 ~ 3),如何从寄存器写到存储器的(指令 4),以及如何从一个寄存器拷贝到另一个寄存器的(指令 5)。

关于这段汇编代码有两点需要注意:

  • 首先,我们看到 C 中所谓的“指针” 其实就是地址。间接引用指针就是将该指针放在一个寄存器中,然后在间接存储器引用中使用这个寄存器。
  • 其次,像 x 这样的局部变量通常是保存在寄存器中,而不是存储器中。寄存器访问比存储器访问要快得多。

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

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

相关文章

element-ui拖拽上传及问题解决(drag的使用注意事项)

element-ui拖拽上传及问题解决(drag的使用注意事项) 上传组件(:drag“true”) <template><el-uploadclass"avatar-uploader"action"":show-file-list"false":on-success"handleAvatarSuccess":before-upload"beforeAva…

如何获得铁粉(弯道超车的攻略)

文章目录 一、提供有价值的内容二、保持更新频率三、与读者互动四、优化SEO五、提供专栏订阅服务 CSDN(China Software Developer Network)是中国最大的IT社区和在线学习平台之一&#xff0c;成立于1999年。它是一个面向软件开发者的知识共享社区&#xff0c;提供有关编程语言、…

Docker容器技术|最强王者篇

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

行业领先生物制药企业在冷链物流运输中采用虹科LIBERO温度记录解决方案

中国首个获得世界卫生组织国际通用名的生物Ⅰ类新药是用于抗血管内皮生长因子的融合蛋白&#xff0c;该药物通过结合血管内皮生长因子VEGF&#xff0c;竞争性抑制VEGF与受体结合并阻止VEGF家族受体的激活&#xff0c;从而抑制内皮细胞增殖和血管新生&#xff0c;达到治疗湿性年…

自学网络安全遇到问题怎么解决?路线是什么

自学网络安全很容易学着学着就迷茫了&#xff0c;找到源头问题&#xff0c;解决它就可以了&#xff0c;所以首先咱们聊聊&#xff0c;学习网络安全方向通常会有哪些问题&#xff0c;看到后面有惊喜哦 1、打基础时间太长 学基础花费很长时间&#xff0c;光语言都有几门&#xf…

什么样的程序员在 35 岁以后依然被公司抢着要?

什么样的程序员在35岁就会被优化&#xff1f; 程序员的35岁危机是一个老生常谈的话题&#xff0c;与其问什么样的程序员在35岁会被公司抢着要&#xff0c;不如踏实一点&#xff0c;来讨论下什么样的程序员在35岁之后不会被淘汰。 T0级别&#xff1a;有技术壁垒 这类人大概占程…

高通滤波和低通滤波理性到感性分析

高通滤波和低通滤波理性到感性分析 文章目录 高通滤波和低通滤波理性到感性分析高通低通滤波辨析Python仿真代码参考资料 高通低通滤波辨析 物理意义&#xff1a; 从频率角度&#xff0c;高通滤掉低频信息&#xff0c;低通滤掉高频信息从采样点看&#xff0c;低通使样点前后变…

【2023 · CANN训练营第一季】应用开发(初级)——第一章 AscendCL概述

ACL基本概念 ACL基本概念 Host&#xff1a; Host指与Device相连接的X86服务器、ARM服务器&#xff0c;会利用Device提供的NN (Neural-Network )计算能力&#xff0c;完成业务。Device: Device指安装了芯片的硬件设备&#xff0c;利用PCle接口与Host侧连接&#xff0c;为Host提…

[黑盾CTF 2023] secret_message 复现

赛后拿到题目和pwn_ckyan的WP&#xff0c;复现一下&#xff0c;这个题坑还是不小的。120分钟的比赛&#xff0c;只作这一个题还差不多。 先看题。 __int64 __fastcall main(__int64 a1, char **a2, char **a3) {char buf[48]; // [rsp0h] [rbp-30h] BYREFinit_0();if ( check…

Fiddler抓包工具之fiddler界面工具栏介绍

fiddler界面工具栏介绍 ​ &#xff08;1&#xff09;WinConfig&#xff1a;windows 使用了一种叫做“AppContainer”的隔离技术&#xff0c;使得一些流量无法正常捕获&#xff0c;在 fiddler中点击 WinConfig 按钮可以解除这个诅咒&#xff0c;这个与菜单栏 Tools→Win8 Loopb…

Python 的 type() 和 isinstance() 函数

type()、isinstance()都是对象类型操作函数&#xff0c;用于判定对象类型&#xff0c;用哪个函数更好哩&#xff1f; 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;…

Git—常用指令

示意图 指令 描述 git -v 查看版本号 git init 创建仓库&#xff0c;初始化 git clone 仓库地址 下载远程仓库 git config user.name 名称 配置名称 git config user.email 邮箱 配置邮箱 git config --global user.name 名称 全局配置名称 git config --global …

水下图像1

d_r_26_.jpg 一个男子拿着一个标定板在站在水中 一个穿着黑色短裤的男子拿着标定板站在水中 一个戴着潜水镜的男子拿着标定板站在水中 一名男子正在水下潜水 有一个潜水员双手拿着一个标定板在站在水中 A man is standing in the water with a calibration board A man we…

信号在MATLAB中的运算——信号的积分和微分

信号在MATLAB中的运算——信号的积分和微分 对于连续时间信号&#xff0c;其微分运算是用 diff 函数来完成的&#xff0c; 其调用格式为&#xff1a;diff(function, variable, n)&#xff0c; 其中 function&#xff1a;为需要进行求导运算的信号&#xff08;或被赋值的符号…

关于esp8266模块与stm32f103模块的连接,问题分析

文章目录 模块和芯片实验目的连接方式main.hesp8266.cesp8266.htcp.ctcp.h实验中出现的问题源代码 模块和芯片 stm32f103c8t6 单片机 esp8266 wift 模块 实验目的 实现esp8266 模块的通讯&#xff08;客户端&#xff09; 连接方式 这个是我所使用的模块ESP-01S 类型的&…

C++中stack的用法(超详细,入门必看)

博主简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的人。 博主主页&#xff1a;陈童学哦 所属专栏&#xff1a;CSTL 前言&#xff1a;Hello各位小伙伴们好&#xff01;欢迎来到本专栏CSTL的学习&#xff0c;本专栏旨在帮助大家了解…

s2020gc56收集数据

作答区域&#xff1a; #include<bits/stdc.h> using namespace std; int n,k,s1,s2,h1,h2,he,ans,r2,r1,l2,l11,f[1000009]; int main() {cin>>n>>k;for(int i1;i<n;i)cin>>f[i];for(int i1;;i){s1;if(s1>k)break;h1h1f[i];}for(int in;;i--){…

神经网络实验--卷积神经网络

本实验主要为了掌握深度学习的基本原理&#xff1b;能够使用TensorFlow实现卷积神经网络&#xff0c;完成图像识别任务。 文章目录 1. 实验目的 2. 实验内容 3. 实验过程 题目一&#xff1a; 题目二&#xff1a; 实验小结&讨论题 1. 实验目的 ①掌握深度学习的基本原…

spring练习1

1、练习网站案例 1、建好相应的java类 package spring;public class Player {public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getPosit…

自学软件测试怎么学?新增软件测试(全栈),笔试及面试全套方法

既然是自学&#xff0c;那就如下方面着手吧。 1、面试(此篇文章的重磅) 2、思路 3、心态 4、技能 真所谓&#xff0c;“面试造飞机&#xff0c;工作拧螺丝”。咱们先从第一个&#xff0c;面试着手&#xff0c;这就好比写文章先列好提纲一样&#xff0c;要知道你这个行业具体有那…