898 words
4 minutes
CSAPP 3.2&3.3
程序编码
以书上所举的编译p1、p2两个c语言文件的过程为例,可以将gcc编译的过程大致分为如下几步:
- C preprocessor(预处理器)进行预编译,简单理解为将带有”#“符号的语句进行编译,包括但不限于对头文件、宏定义、全局变量的编译。
- compiler(编译器)进行汇编,生成.s文件。
- assembler(汇编器)将汇编代码转化成机器可执行的二进制代码(目标代码),生成.o文件。
- linker(链接器)将所用函数链接到动态或静态库,产生最终的可执行文件。
书中所用到的两种抽象
计算机系统中为了便于理解,采用了两种较为重要的抽象:
第一种采用了ISA(instruction set architecture)将处理器的运作进行抽象,简化为每条指令按顺序进行,一条结束后再进行下一条。实际的处理器运行更为复杂,能够同时处理多条指令。
第二种将内存地址抽象为虚拟地址,表现为某种字节数组。实际的内存地址是硬件存储器和系统软件组合实现的。
可见的处理器状态
- PC(Program Counter,程序计数器,在x86-64中用%rip表示),会给出下一条待执行指令在内存中的位置。
- 整数寄存器(integer register file)包含了16个命名的位置,它们都能够存储64位的值。寄存器能够存储地址或整数数据。一些寄存器用来保存程序的重要章台,一些用来保存临时数据,例如参数和局部变量,以及函数返回值。
- 条件码寄存器(condition code register)保存最近进行的逻辑或算术运算的结果,用于控制条件变化,如if和while语句。
- 向量寄存器(vector register)用于存放一个或多个整型或浮点型数据。
程序内存中包含的内容
- 可执行的机器代码
- 操作系统需要的一些信息
- 用于管理运行过程中的函数调用与返回的栈
- 用户申请分配的内存
机器级代码
机器级代码通常难以阅读和理解,为了查看机器级代码的内容,需要用到反汇编器(disassembler),将机器级代码转化为类似汇编代码的形式。
有关于机器级代码和反汇编器有如下特征:
- x86-64的指令长度有1至15字节不等,常用的、或是运算对象少的一些指令所需的字节更少。
- 字节能够与汇编指令一一对应。
- 反汇编程序只根据字节进行反汇编,不需要访问源代码或汇编代码。
- 汇编代码中的后缀代表数据类型,反汇编代码中的后缀添加在call或ret指令后,均可忽略。
数据格式
在计算机系统中,使用”word”表示16位数据类型,“double words”表示32位数据类型,“quad words”表示64位数据类型。
在x86-64的指令集中,包括了对各种数据类型以及指针的操作指令。
下表中列举了汇编代码中的后缀对应的数据类型,以及它们的数据大小。
C语言对应的数据类型 | Intel系统下的数据类型 | 汇编代码中对应后缀 | 数据大小(单位:Byte) |
---|---|---|---|
char | Byte | b | 1 |
short | Word | w | 2 |
int | Double Word | l | 4 |
long | Quad Word | q | 8 |
char * | Quad Word | q | 8 |
float | Single precision | s | 4 |
double | Double precision | l | 8 |
在64位的操作系统中,指针是8Byte的。
CSAPP 3.2&3.3
https://ankate.github.io/posts/csapp-3233/