【合集】CSAPP-深入理解计算机系统_哔哩哔哩_bilibili
Computer Systems: A Programmer’s Perspective
第一章 计算机系统漫游
计算机系统是硬件和系统团结互相交织的集合体,它们必须共同协作以达到运行应用程序的最终目的
通过介绍 helloworld 程序的生命周期(从它被程序员创建开始,到在系统上运行,输出简单的信息,然后终止),对计算机系统的主要概念做一个概述
信息就是位+上下文,计算机内部的信息被表示为一组组的位,它们依据上下文有不同的解释方式。
hello.c
#include <stdio.h>
int main() {
printf("hello world!\n");
return 0;
}
经过 gcc -o hello hell.c
编译成可执行程序 hello,hello 程序的生命周期是从让人能看懂的高级 C 语言程序开始的,为了在系统上运行,每条 C 语句都必须被其他程序转化为一系列的低级机器语言指令。
程序被其他程序翻译成不同的形式,开始时是ASCII文本,然后被编译器和链接器翻译成二进制可执行文件
hello.c 的 ASCII 文本表示:
编译
GCC编译器驱动程序读取源程序文件 hello.c,并把他翻译成一个可执行目标文件 hello,翻译过程可分为四个阶段,由预处理器、编译器、汇编器、链接器四个阶段的程序一起构成了编译系统:
-
预处理阶段
会根据以#
开头的命令,来修改原始程序,如 hello 程序中引入了头文件——stdio.h,预处理器会读取该头文件中的内容,将其中的内容直接插入到程序文本中,结果得到另一个C
程序,通常以 .i 为文件扩展名,就是hello.c
文件经过预处理得到hello.i
文件(仍然是文本文件) -
编译阶段
将hello.i
文件翻译成hello.s
文件,它包含一个汇编语言程序,该程序包含函数 main 的定义,此阶段包括词法分析、语法分析、语义分析、中间代码生成以及优化等一系列中间操作 -
汇编阶段
汇编器根据指令集将汇编程序hello.s
翻译成机器指令,并将这些机器指令按照一种称为可执行目标程序的格式打好包,得到可重定位目标文件——hello.o
(二进制文件,但还不能执行) -
链接阶段
上面代码中,调用了 printf() 函数,它是标准C
库中的一个函数,每个C
语言编译器都会提供,用来在打印输出内容,该函数在 printf.o 文件中
链接器(ld)负责把hello.o
和 printf.o 遵循一定规则进行合并,因为链接器要对hello.o
和 printf.o 进行调整, 所以hello.o
才会被称为可重定位目标文件
经过链接阶段最终得到可执行目标文件——hello
为什么程序员需要理解编译系统是如何工作的?
-
理解编译系统可以优化程序性能
问题
一个 switch 语句是不是要比一连串的 if-else 高效的多?
一个函数调用的开销有多大?
while 循环比 for 循环更高效吗?
学完第三、五章会得到答案 -
理解链接时出现的错误
问题
构建大型程序时,涉及到各种函数库的调用,一些奇怪的错误都是与连接器有关的,如:
静态变量和全局变量的区别是什么?
静态库和动态库的区别是什么?
严重的是一些链接错误到程序运行时才会出现
学完第七章会得到答案 -
避免安全漏洞
问题
缓冲区溢出(buffer overflow)是导致互联网安全漏洞的主要原因
如何避免写出的代码存在安全漏洞,第一步就是要理解数据和控制信息在程序栈上是如何存储的,了解不严谨不规范的书写方式会引起什么样的后果
在用 shell 运行 hello 程序时系统发生了什么?
经过编译得到的可执行程序 hello 已经存在系统磁盘上,如何运行?
linux 系统上运行可执行程序:
打开一个 shell 程序,然后在 shell 中输入相应可执行程序的文件名,shell 加载并运行 hello
程序,屏幕上显示 hello world 内容,hello
程序运行结束并退出, shell 继续等待下一个命令
- 首先看一下计算机系统的硬件组成。