程序的机器级表示(一)
闲聊:这即将是一个非常非常重要的系列,参考mooc上南京大学的计算机系统基础和经典书目《深入理解计算机系统》,也是我每次上新课都得返回去学旧知识的课,周而复始,感触颇深,
综述:这章重点是机器级语言,机器级语言分为机器语言和汇编语言,这章主要学习的是IA-32指令系统下的汇编语言,mooc表述基础是x86-32,csapp表述基础是x86-64,前期概念都是一样的,指令集的差异会单独列出
更新(2021.4.8):没想到这么快一年就过去了,重新看了一遍之前写的博客,发现很多当时看不懂的内容都在计组和微机原理里学习到了,现在微机原理在学8086指令集,觉得那本教材学的太抽象了,决定回味一下CSAPP的魅力。
没想到一年过去了,我还是那么喜欢小鬼!
指令系统概述
计算机执行机器代码,编码都是以字节为单位,汇编代码是与特定机器密切相关的
一.程序转换概述
-
基本知识回顾
1 存储程序的工作方式
2 程序由一系列指令构成,开始指令和数据都存储在存储器中,在存储器中都是以二进制方式编码,不进行区分。根据PC取指令,译码,取操作数,执行操作,回写结果,修改PC的值,根据PC取下一条指令(IF-ID-EX-MEM-WB)
3 当指令执行时,将数据和指令从存储器取到相应的寄存器,指令在IR中,数据在GPRs中
4 指令的信息
(1)操作码(2)立即数,寄存器编号,存储地址(3)目的操作数地址(结果应该回写到什么地方)
5 指令的地址都存放在PC中(这里有个测试题是指令中包含的信息是否包括下条指令的地址,学了计组后开始纠结到底有没有,回想跳转指令好像没有直接给pc赋值的,都需要进行寄存器寻址或者pc相对寻址,所以应该没有指令直接包含下条指令的地址)
存储地址的描述和存储方式与数据结构有关(根据不同的格式进行寻址) -
计算机如何处理数据
1 使用机器代码,用字节序列编码
2 层次语言的转换:指令就是软硬件的接口
-
指令:微指令,伪指令,机器指令
机器指令在硬件和软件交界面,0-1序列,书写困难,所以引入汇编指令方便阅读
微指令属于硬件,相当于一条条控制信号
伪指令属于软件,相当于很多指令组成的一个集合,比如RISC-V指令集中的j指令
汇编指令是用符号(助记符)表示的指令, 机器指令和汇编指令一一对应
机器级指令与硬件息息相关,包括汇编指令和机器指令
以下是机器指令格式示意图(梦回计组)
这里的M[]非常重要,后续会影响是取地址还是取值 -
GCC编译器套件 让我们看看源程序怎么生成可执行文件,初学高级语言时经常听到GCC这个词,但是不知道是干啥的,这里给出了解释。GCC实际上包括编译器,汇编器和链接器
1 预处理:将头文件和#define声明的相关内容插入源程序中
2 编译 转换为汇编语言
3 汇编 转换为可重定位机器语言目标代码(后续介绍重定位的概念)
4 链接 将一些函数链接进去(printf()什么的,用早已生成的机器代码插入),生成最终的可执行目标文件。 -
GCC使用实例
1.语句解读
gcc-O1 main.c test.c-o test
表示使用gcc编译套件,使用一级优化(其实就是对代码优化一下)
计组老师上课举了个例子:将>=优化为>,结果导致了数据溢出
两个.c文件链接生成test文件
以上图片显示了三种汇编语言,分别是由源程序编译得到的,可重定位目标文件反汇编形成的,可执行目标文件反汇编形成的,我们来对比他们的区别。
1 可重定位比编译:
(1)指令的地址有相对于函数首地址的偏移量
(2)没有长度后缀
(3)用16进制表示,编译得到的是十进制。
2 当汇编得到可执行文件时,地址成为了确切的虚拟地址,未重定位时所有的地址都是偏移地址,并且这个偏移地址是相对于整个文件的。
Hello.o和hello反汇编得到的程序指令完全一致,只是地址不同。 -
回顾:机器级代码的两种抽象:ISA(Instruction Set Architecture)和虚拟地址
ISA: 对软件如何使用硬件的描述
高级程序语言对于机器来说非常难理解,ISA就是一个对硬件使用的描述,比如一个数据应该是多少位,小鬼的名字应该有多长
计算机组成和指令集的区别:计算机的组成应该满足于某一种指令集,一种指令集可能对应多种计算机组成
二.IA-32指令系统概述
以下内容和x86-64有所不同,但只是格式有些区别,思想没有差异。
- 硬件描述:
(1)8个GPR(0-7)
(2)一个标志寄存器
(3)PC(EIP):给出将要执行的下一条指令在内存中的地址
(4)可寻址空间为4GB - 标志寄存器
(1)条件标志 OF CF SF ZF(条件码):在控制语句中使用
AF(进位辅助标志) PF(奇偶标志)
(2)控制标志
… - 计算机中的计算问题
一些重要的认识:
(1)计算机中所有运算都基于加法器
(2)加法器不能区分所运算的是带符号数还是无符号数
(3)加法器不能判定结果对错,总是取低n位作为结果,并产生标志信息 - 数据格式:根据操作数据长度不同,汇编指令后缀也有所不同。
- 寻址方式:如何根据指令中信息找到操作数
1 根据操作数所在的位置
(1)指令中直接出现:立即寻址
(2)寄存器中:寄存器寻址
(3)存储单元中:属于存储器操作数,按字节编址:其他寻址方式
2 存储器操作数的寻址方式与工作模式有关
实地址模式:如8086,实地址模式是为了向前兼容
保护模式 加电过程采用实地址模式,加电结束后使用虚拟地址(起保护作用)
3 保护模式下的寻址方式:
(1)立即寻址
(2)寄存器寻址
(3)其他寻址方式
SR:段基址
有效地址:操作数所在段的偏移地址
相对寻址:与现在的指令执行情况有关(与pc有关) - 举例(高级语言对于比例变址的需求决定了复杂的寻址方式)
- IA-32机器指令格式(变长指令字,变长操作码)
1 位移量和立即数可以是一个字节(b),两个字节(w),和四个字节(l)
2 SIB中的基址B和变址I可以是GPR中任一个(变址指的是其形式地址可以改变,基址中的形式地址往往是个常量,比如CS,DS,段基址一般是个常量)SS是比例因子,比例因子为1 2 4 8,因此用两位表示
简单实践
见csappP114代码示例,如果不想装虚拟机可以在educoder实训中使用其命令行服务。