第3章“程序的机器级表示”:访问信息

news2024/12/28 5:08:25

文章目录

  • 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/581590.html

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

相关文章

Python - 批量下载ts文件并合并为mp4

(一)ts文件下载 网页文件下载其实都可以通过requests.get以文件流的形式获取,并以字节的形式写入本地文件即可。 代码如下: import os import requests def download(url, filenames, dirname):session requests.Session()for …

uniapp水文【uniapp】

文章目录 1、前言2、历史3、发展4、功能5、优缺点6、总结7、附录7.1、高频使用7.2、使用注意 1、前言 Uniapp是一种跨平台的移动应用开发框架,它允许开发者使用一套代码库,同时生成iOS、Android等多个平台的应用程序。这种技术方案可以大大降低开发成本…

NET框架程序设计-第1章.NET框架开发平台体系架构

1.1 .NET 框架基本组成 .NET 框架的核心便是通用语言运行时(Commomn Language Runtime,简称 CLR),CLR 是一个可被各种不同的编程语言所使用的运行时。 托管模块(mangaed module): 一个需要 CLR 才能执行的标准 Window…

实验 3:图形数据结构的实现与应用

东莞理工学院的同学可以借鉴,请勿抄袭 1.实验目的 通过实验达到: 理解和掌握图的基本概念、基本逻辑结构; 理解和掌握图的邻接矩阵存储结构、邻接链表存储结构; 理解和掌握图的 DFS、BFS 遍历操作的思想及其实现; …

威胁情报如何改进 DDoS 保护

分布式拒绝服务 (DDoS) 攻击已成为各种企业的主要威胁,从最小的跨国公司到最大的跨国公司。 根据 2022年全球威胁分析报告,恶意DDoS攻击较2021年增长了150%。此外,DDoS攻击的频率也出现显着上升,令人担忧。 在全球范围内&#x…

港大、南大、清华抢先开源「复刻」版DragGAN,开箱即用!

来源 |新智元 还记得前几天发布的DragGAN吗? 没错,就是那个「轻轻点两下」1秒修图的工具。 ▲拍的照片表情不好?修!脸型不够瘦?修!脸冲镜头的角度不对?修! ▲搞不好,「让…

https 建立连接过程分析

从真实的抓包开始 根据抓包结果可以看到 从客户端发起请求开始,主要经过以下几个过程: 1、TCP 三次握手 2、浏览器发送 Client Hello 到服务器 3、服务器发送Server Hello 、证书、证书状态、服务端密钥交换,到浏览器 4、浏览器发送 客户端密…

【Linux】搭建SFTP文件服务器

一、协议介绍1.1 FTP 协议1.11 特点1.12 基本工作原理 1.2 SFTP协议1.21 特点1.22 基本工作原理 1.3 ssh协议1.31 特点1.32 基本工作原理 1.4 其他常见文件传输协议 二、搭建Linux的SFTP文件服务器三、连接测试3.1 电脑连接3.2 手机连接 一、协议介绍 1.1 FTP 协议 1.11 特点…

chatgpt赋能python:Python如何实现不换行

Python如何实现不换行 Python是一种高级编程语言,它的应用领域非常广泛,尤其是在数据分析、人工智能、网络爬虫等领域中拥有广泛的应用。而在Python中,有时候需要控制输出内容的样式,比如在输出时避免出现换行,这个需…

Bootstrap中的js插件使用

1. 标签页 1.1 init <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevic…

sqli_labs21-23

less21 这题是cookie注入&#xff0c;如果不登录进去是看不到cookie信息的&#xff0c;所以我们要先登录进去 用户admin&#xff0c;密码admin 抓包后发现cookie字段有base64编码信息&#xff0c;选中后burp自动检测翻译 既然是cookie注入并且字段是被加密了的&#xff0c;说明…

chatgpt赋能python:Python中5/2问题引发的思考

Python中5/2问题引发的思考 在Python中&#xff0c;我们常常遇到数字计算的问题&#xff0c;比如5/2。当我们在Python中执行如下代码时&#xff1a; print(5/2)输出结果为2.5。 但是在其他编程语言中&#xff0c;比如C和Java&#xff0c;同样的计算结果是2&#xff0c;而不是…

chatgpt赋能python:Pythonnumpy库下载教程:学习数据分析必备工具

Python numpy库下载教程&#xff1a;学习数据分析必备工具 介绍 Python是一种优秀的脚本语言&#xff0c;常用于数据分析、机器学习等领域&#xff0c;而Numpy是Python中最基础的科学计算库&#xff0c;提供了大量针对数组及矩阵操作的函数和方法。然而&#xff0c;对于初学者…

jQuery元素操作和尺寸位置

1. 遍历元素 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width,…

Kubernetes_核心组件_kubelet_kubelet服务全解析

文章目录 前言一、查看kubelet当前运行1.1 查看kubelet当前运行1.2 kubelet配置文件1.3 kubelet启动参数文件1.4 kubelet启动全过程 (自定义启动参数文件) 二、kubelet启动过程2.1 kubelet启动过程2.2 自定义kubelet所有文件并运行步骤1&#xff1a;新建静态token文件和user&am…

Fourier分析入门——第11章——Fourier变换

目录 第11章 Fourier变换(Transform) 11.1 引言 11.2 逆向正弦和余弦变换(The Inverse Cosine and Sine Transforms) 11.3 正向正弦和余弦变换(The Forward Cosine and Sine Transforms) 11.4 离散谱对比谱密度(Discret spectra vs. spectral density) 11.5 Fourier变换的…

chatgpt赋能python:Python中4.5/2等于多少?——解密Python的除法运算

Python中4.5/2等于多少&#xff1f;——解密Python的除法运算 Python作为一种常用的编程语言&#xff0c;在业界有着广泛的应用。而除法是Python中常用的运算之一。但是&#xff0c;当我们输入4.5/2时&#xff0c;会得到什么样的结果呢&#xff1f;这篇文章将解密Python的除法…

Spring Boot:从入门到实践的全面指南

文章目录 1. Spring Boot简介及特性1.1 简介&#xff1a;什么是Spring Boot1.2 特性&#xff1a;Spring Boot的优势与特点1.3 四大核心&#xff1a;Spring Boot的核心组成 2. Spring Boot入门案例2.1 Spring Boot项目开发步骤2.2 创建一个Spring MVC的Spring Boot Controller2.…

chatgpt赋能python:Python不能参加奥赛的原因

Python不能参加奥赛的原因 Python 是一种广泛使用的高级编程语言&#xff0c;以其简单易学、可读性高等特点受到了众多程序员的喜爱&#xff0c;但是它在国际奥林匹克竞赛中并不被允许参赛。本文将会介绍 Python 不能参加奥赛的原因&#xff0c;并且分析该限制是否合理。 原因…

使用 GitHub Actions 自动部署 Hexo 个人博客

文章目录 申请 GitHub Token源码仓库配置 Github Action重新设置远程仓库和分支查看部署 每次部署 Hexo 都需要运行 hexo cl & hexo g & hexo d 指令三件套完成推送到远程仓库&#xff0c;随着文章越来越多&#xff0c;编译的时间也会越来越长&#xff0c;通过 Github …