本博客对于汇编的介绍基于32位机器的Intel x86系列处理器和IA32指令集,也涉及少部分x86-64。由于汇编知识相对复杂,这里只做简单介绍和记录,详细请参照书本!

数据格式

下面这张表格中体现了C语言基本数据类型和IA32的对应表示。

C语言中的声明 Intel 数据类型 汇编代码后缀 大小(字节)
char 字节 b(byte) 1
short w(word) 2
int 双字 l(long) 4
long int 双字 l 4
long long int “四字” - 4
char * 双字 l 4
float 单精度 s 4
double 双精度 l 8
long double 扩展精度 t 10 or 12

大多数的常用数据类型是用双字形式存储的。短整数(short)、普通整数(int)和长整数(long int)的区别是“短”和“普通”整数是固定的2和4字节,而“长”整数使用的是机器的全字长,因为是32位机器,所以这里long int 是4字节。

long long是由8个字节来表示的,在硬件上 IA32 是不支持的这种数据类型的(x86-64可以)。

指针(char *)是使用机器的全字长的,因为指针是存储地址的变量。地址和字长有关,字长(word size)表明整数和指针数据的标称大小(nominal size)。在没有涉及到存储器的细节时,我们会把存储器看成一个非常大的数组,所以字长决定一个很重要的属性是虚拟空间的最大大小(每一个字节都要用一个唯一的数字来标识,而这个数字是要编码的)。对于一个字长为 w 位的机器而言,虚拟地址的范围是0 ~ \((2^w)-1\),程序最多访问\(2^w\) 个字节。

单精度和双精度浮点数是4和8字节,不多说。扩展精度(long double)的大小为10或12字节,扩展精度的作用以后会提到。

汇编代码后缀的意思是大多数汇编代码指令的后面带有一个字符后缀,表明操作数的大小。例如:movb(传送字节)、movw(传送字)、movl(传送双字)。注意:用 l 表示double和4字节整数不会产生歧义,因为浮点数使用的是一套完全不同的指令和寄存器。

寄存器

一个IA32中央处理器单元(CPU,central processing unit)包含一组8个存储32位值的寄存器(register),可以看到寄存器的数量是很少的。下图显示了这八个寄存器的简单表示。它们的名字都以%e开头,实际上它们另有特殊的名字。

在大多数情况下,前六个寄存器可以看成通用寄存器,对它们的使用没有限制(“大多数情况”下分具体情况,具体情况也是用特殊的寄存器)。最后两个寄存器(%ebp和%esp)保存指向程序的栈中重要位置的指针,所以只有根据栈管理的标准才能修改这两个寄存器的值。

可以看到,字节操作指令可以独立地写更短的地位字节。这是为了向后兼容(backwards compatiblity),也就是能让更早的代码正常地工作。下面是x86-64的寄存器,以%r开头的是64位寄存器,可以看到它也是向后兼容的。

数据传送: MOV 指令

将数据从一个位置复制到另一个位置是最频繁使用的指令。我们把指令分成指令类,一类指令执行的操作是一样的,只不过操作数的大小不同。

MOV指令 效果
MOV S, D D ← S
MOVS S, D D ← (符号扩展)S
MOVZ S, D D ← (零扩展)S

例如 MOV 是一类指令,根据传送字节、字还是双字分为三种指令:movb、movw、movl。

MOV 移动的数据的大小和目的位置的大小是一样的。与 MOV 不同,MOVS 和 MOVZ 指令类是将一个较小的数据放到一个较大的数据位置。扩展方式分为符号扩展或者零扩展两种方式。如果要将一个较小的数据放到一个较大的数据位置,要么使用扩展版本的指令,要么就选择正确的 mov 后缀。不能将较大的数据放在一个较小的数据位置。

下面要介绍一个非常重要的概念——寻址。

寻址

大多数指令有一个或多个操作数(operand),操作数可能指代要引用的数据值、数据来源、或者要存放的目标位置。形成操作数的有效地址的过程,被称为寻址(addressing)。

操作数可以被分为三个类型:

  1. 立即数(immediate)

    也就是一个常数值,书写方式是一个美元符号后面跟着一个用标准C表示法表示的整数,例如$0x1F。

  2. 寄存器(register)

    表示某个寄存器的内容。用符号 $ E_a $ 来表示任意寄存器a,用引用 $ R[E_a] $ 来表示它的值。这是将寄存器集合看成一个数组R,用寄存器的名称作为索引。

  3. 存储器引用(memory)

    它根据一个计算出来的地址(称为有效地址)访问某个存储器的位置。因为我们是将存储器看成一个很大的字节数组。我们用M[Addr]表示对存储器中的字节值的引用。存储器寻址的内容就多了,包括:绝对寻址、间接寻址(对啦就是熟悉的指针!)、基址+偏移量寻址、变址寻址、比例变址寻址。在这里除了下面的程序中设计到的寻址方法之外的就不一一讲了。

movq 的后缀 q 是四字的意思,是 x86-64 中支持64位数据的写法。接下来,对下图中的一些寻址方式做简单介绍:

MOV 的第一个操作数是源S,S要么是一个寄存器,要么是一个立即数,要么是一个存储器位置。第二个操作数是目的地D,只能是寄存器或者存储器位置。

①:第一条指令的第一个操作数是 $0x4 ,说明这是一个立即数,也就是常数。第二个数是寄存器的名字,这种寻址方式叫做:寄存器寻址。对应的C语言就是为一个局部变量赋常数值。

②:第二条指令与第一条不同的是第二个操作数的寄存器两边加上了括号。这其是是间接寻址的意思。形如 \((E_a)\) 的格式代表的操作数值是 \(M[R[E_a]]\),也就是说,此时寄存器里存的是一个指针,也就是一个地址,括号可以看成一个C语言的间接引用运算符*。

③:两个寄存器直接的数据传递。

④:把一个局部变量的值复制到一个指针指向的内容。

⑤:把指针指向的内容赋给局部变量temp

这里有一点需要注意的是:不允许MOV指令的两个操作数同时为存储器地址。也许你会感到奇怪:把存储器中一个地方的值传送到另一个地方不是很正常吗为什么没有这条指令?一开始对这个有疑惑是很正常的,这种操作需要两条指令——第一条指令将原值加载到寄存器中,第二条指令将该寄存器里的值写到目的存储器位置。学到后面自然会理解为什么没有两个操作数都是存储器位置的MOV指令。

剩下的寻址方法这里就不介绍了:

数据传送示例:

(图表来自于CSAPP课程网站,本人添加了一点小小的说明性信息)

分析下面这个交换函数的汇编代码,有助于理解寄存器、存储器、寻址、地址等各种概念。

变量 xp 和 yp 是指针,内容是地址,用寄存器 %rdi 和 %rsi 存放。临时变量 t0 和 t1 用寄存器 %rax 和 %rdx 存放。调用 swap 函数后,可以看到在左边的 memory 一列,0x120 和 0x130 里存放了数据 123 和 456,参数 xp 和 yp 已经存到了对应的寄存器。通过间接寻址,将存储器里的值存放到临时变量 t0 和 t1 对应的寄存器里。

交换后,* xp 的值和 * yp 的值成功对调。

前两节的小结:

  • 了解处理器、指令集的历史和发展。

  • 了解C语言、机器语言、汇编语言的区别。

    学习汇编语言能让我们理解更多细节,例如寄存器等等……理解编译器需要为C语言代码做的工作——将一些高级语言的表示方法编译为一些更为基本的指令。

  • 汇编语言基础:寄存器、操作数、数据移动、寻址。


See Also

【CSAPP笔记】5. 汇编语言——数据的更多相关文章

  1. Android笔记——Android中数据的存储方式(二)

    我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...

  2. 微信小程序开发:学习笔记[9]——本地数据缓存

    微信小程序开发:学习笔记[9]——本地数据缓存 快速开始 说明 本地数据缓存是小程序存储在当前设备上硬盘上的数据,本地数据缓存有非常多的用途,我们可以利用本地数据缓存来存储用户在小程序上产生的操作,在 ...

  3. springmvc学习笔记(18)-json数据交互

    springmvc学习笔记(18)-json数据交互 标签: springmvc springmvc学习笔记18-json数据交互 springmvc进行json交互 环境准备 加入json转换的依赖 ...

  4. 六星经典CSAPP笔记系列 - 作者:西代零零发

    六星经典CSAPP笔记(1)计算机系统巡游 六星经典CSAPP笔记(2)信息的操作和表示 六星经典CSAPP-笔记(3)程序的机器级表示

  5. 【笔记】求数据前n个主成分以及对高维数据映射为低维数据

    求数据前n个主成分并进行高维数据映射为低维数据的操作 求数据前n个主成分 先前的将多个样本映射到一个轴上以求使其降维的操作,其中的样本点本身是二维的样本点,将其映射到新的轴上以后,还不是一维的数据,对 ...

  6. 【CSAPP笔记】8. 汇编语言——数据存储

    下面介绍一些C语言中常见的特殊的数据存储方式,以及它们在汇编语言中是如何表示的. 数组 数组是一种将标量数据聚集成更大数据类型的方式.实现数组的方式其实十分简单,也非常容易翻译成机器代码.C语言的一个 ...

  7. 【CSAPP笔记】4. 汇编语言——基础知识

    程序的机器级表示 计算机能读懂是机器代码(machine code)-- 用字节序列编码的低级操作 -- 也就是0和1.编译器基于编程语言的规则.目标机器的指令集和操作系统的规则,经过一系列阶段产生机 ...

  8. 【CSAPP笔记】9. 汇编语言——缓冲区溢出

    x86-64 Linux 内存结构 先来看看一个程序在内存中是如何组织的.Linux 为每个进程维持了一段单独的虚拟地址空间.(进程是计算机科学中很深刻.很成功的一个概念.当我们在运行一个程序时,会得 ...

  9. 【CSAPP笔记】7. 汇编语言——过程调用

    一个过程调用包括将数据(以参数和返回值的形式)与控制从代码的一部分传递到另一部分.除此之外,在进入时为过程的局部变量分配空间,在退出的时候释放这些空间.数据传递.局部变量的分配和释放通过操纵程序栈来实 ...

随机推荐

  1. 飞控入门之C语言指针回顾

    指针 何为指针?来个官方定义:指针是一个值为内存地址的变量(或数据对象). 一.指针的声明 //示例 int *pi; //pi是指向int类型变量的指针 char *pc; // pi是指向char ...

  2. Python的open函数文件读写线程不安全,logging模型文件读写线程安全!

    工作中遇到的问题:如何在多线程的程序中同时记录日志? 最初图省事,使用了最原始的open函数来写日志,因为开始使用的写文件模式的是追加('a'),发现并没有线程不安全的现象,各个线程的的日志信息都写入 ...

  3. MS522低功耗寻卡

    方案:单片机处于低功耗模式,MS522处于软掉电模式.单片机用RTC定时(比如每隔1s)唤醒,单片机唤醒后唤醒MS522寻卡.寻到卡则做进一步处理,否则MS522继续进入软掉电模式,单片机进入低功耗模 ...

  4. 20155338《网络对抗》Exp2 后门原理与实践

    20155338<网络对抗>Exp2 后门原理与实践 一. 基础问题 (1)例举你能想到的一个后门进入到你系统中的可能方式? 答:游览网站中附带的广告或弹出的不正规软件. (2)例举你知道 ...

  5. WPF 自定义ComboBox样式,自定义多选控件

    原文:WPF 自定义ComboBox样式,自定义多选控件 一.ComboBox基本样式 ComboBox有两种状态,可编辑和不可编辑状态.通过设置IsEditable属性可以切换控件状态. 先看基本样 ...

  6. WPF之ComboBox的VisualTreeHelper

    原文:WPF之ComboBox的VisualTreeHelper 用WPF的ComboBox控件的时候,需要用到TextChanged属性,但是这个属性属于TextBox控件,不用担心,ComboBo ...

  7. log4j配置单独日志文件输出

    log4j.logger.batteryHistory=ERROR,BD log4j.appender.BD=org.apache.log4j.FileAppender log4j.appender. ...

  8. OpenStack入门篇(二十)之实现阿里云ESC多FLAT网络

    1.给两台虚拟机增加网卡,使用仅主机模式,网段为:192.168.57.0/24 2.修改两台主机网卡配置 [root@linux-node1 ~]# cp /etc/sysconfig/networ ...

  9. Python distribute到底使用package_data还是MANIFEST.in?

    今天看Flask的文档,里面提到如何通过distribute发布你自己的Python包.讲包含文件的时候,提到要用MANIFEST.in并将include_package_data设置为True. 由 ...

  10. 详解华为云基因容器服务GCS

    基因测序,作为“下一个能够改变世界”的技术,已经由实验室研究演变到临床使用,为人类预测罹患多种疾病的可能性,提前预防和治疗疾病提供了一套可靠的方法和手段.而基于基因测序在预防和治疗疾病方面的准确和可靠 ...