第一章 计算机系统漫游
计算机系统是由硬件和系统软件组成的。
跟踪 hello 程序的生命周期开始对系统的学习
1
2
3
4
5
6
#include <stdio.h>
int main(){
printf("hello world\n");
return;
}
程序的每个字符根据 ASCII 标准转换为字节,hello.c 程序是以字节序列的方式储存在文件中
系统中的所有信息都是由一串比特表示的,区别不同数据对象的方法是读到数据对象时的上下文
GCC 编译驱动程序读取源程序文件 hello.c ,并把它翻译成一个可执行文件 hello。这个翻译过程可分为四个阶段。
- 预处理阶段,预处理器(cpp)根据字符 # 开头的命令,修改原始的 C 程序,得到 .i 文件
- 编译阶段,编译器(ccl)将 .i 文件翻译成 .s 文件,它包含一个汇编语言程序,该程序包含函数 main 的定义
- 汇编阶段,汇编器(as)将 .s 文件翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在 .o 文件
- 链接阶段,hello 程序调用了 printf 函数,它位于 printf.o 中,这个文件必须合并到 hello.o 中,连接器(ld)就负责处理这种合并。结果得到 hello 文件,是一个可执行文件,可以被加载到内存中,由系统执行。
虚拟内存,下面从低地址到高地址介绍
- 程序代码和数据,进程开始运行时指定大小
- 堆,运行时堆,用 malloc 和 free 可以动态扩展和收缩堆
- 共享库,存放 C 标准库和数学库这样的共享库的代码和数据
- 栈,编译器用栈来实现函数调用,可以动态扩展和收缩
- 内核虚拟内存,为内核保留,不允许应用程序读写
操作系统内核是应用程序和硬件之间的媒介,它提供了三个抽象
- 文件,对 I/O 设备的抽象
- 虚拟内存,对程序存储器(主存、磁盘)的抽象
- 进程,对正在运行程序(处理器、主存、I/O 设备)的抽象
虚拟机,对计算机的抽象
第一部分 程序结构和执行
第二章 信息的表示和处理
三种最重要的数字表示:无符号编码,补码编码,浮点数编码
字长,决定虚拟地址空间的最大大小
-
C 语言中的位级运算(按位)
-
,OR - &,AND
- ~,NOT
- ^,异或
位级运算的常见用法是掩码运算
-
-
C 语言中的逻辑运算
-
,OR - &&,AND
- !,NOT
-
-
C 语言中的移位运算
- 左移
- 右移,算术右移和逻辑右移
第三章 程序的机器级表示
编译选项
-
-Og,-O1,-O2,从低到高表示不同优化级别
- -S,生成汇编文件,.s 文件
- -c,生成目标代码文件,.o 文件
- prog,生成可执行文件
汇编语言
数据对齐
许多计算机系统对基本数据类型的合法地址做出了一些限制,要求某种类型对象的地址必须是某个值的 K(通常是 2,4 或 8) 的倍数。
任何 K 字节的基本对象的地址必须是 K 的倍数
无论数据是否对其,都能正确工作,但对齐后执行的内存访问次数少
GNU 的调试器 GDB
第四章 处理器体系结构
第五章 优化程序性能
内存别名使用
在只执行安全的优化中,编译器必须假设不同的指针可能会指向内存中同一个位置
用内联函数替换优化函数调用
使用命令行选项 “-finline”,或者优化等级 -O1 及以上
消除循环的低效率
减少过程调用
消除不必要的内存引用