前言
大一的时候买了深入理解计算机系统(CS:APP),当时有些地方看得不是很理解,而且由于时间长了也有点忘了。这次回家正好带了这本书,于是准备重新读一遍并记录一下自己学习的过程(其实只是抄抄书,浓缩一下书上的内容,再加一点自己想的还有一些乱七八糟的东西罢了hhhh)。
在CS:APP第一章中,hello程序作为讲解的示例,即我们最为熟知的hello world。
#include <stdio.h>
int main()
{
printf("hello, world\n");
}
1.1 信息就是位+上下文
程序的生命周期从源文件开始,即使用文本编辑器输入上述hello程序保存的文本文件。源文件实际上是由0和1组成的位序列,8个位组成一组成为字节。
在英文系统中,使用ASCII码即可表示大部分需要的字符,ASCII码中每一个字节代表一个字符。而在中文系统中,由于汉字的个数远大于英文字母的个数,单个字节代表一个字节是不足以容纳所有的汉字的(1个字节最多仅能2^8个字符,即256个)。所以在ASCII码的基础上,出现了许多用于其它语言的字符集,如我们常用的UTF-8等。下图是本文其中的一段文字,通过emacs的hexl-mode模式查看字符是如何以十六进制表示的。
在图中我们可以发现,在UTF-8中,汉字以及全角状态下的符号是以三个字节表示的,而UTF-8中英文字符仍然以一个字节表示。由于字符集并不是这里的重点,就不再在此深入讨论。
1.2 程序被其他程序翻译成不同的格式
在Unix/Linux中,我们通常使用gcc来编译程序,以生成能够执行的二进制文件。
$gcc -o hello hello.c
在编译的过程中,需要通过预处理、编译、汇编、链接四个阶段处理,执行这四个阶段的程序一起构成了编译系统。
1.预处理(Preprocessing)
预处理器主要处理以#开头的命令,如#include
、#define
、#if
等等。如在hello程序中,在预处理阶段根据程序第一行的#include <stdio.h>
读取stdio.h中的内容并将其插入到程序文本中,生成通常以.i作为后缀的C程序文件。可以使用gcc的-E命令输出预编译的结果。
$gcc -E hello.c -o hello.i
2.编译(Compilation)
编译器的作用主要是将预处理后的.i文件中的每条语句编译得到汇编语言指令,并保存在通常以.s作为后缀的汇编语言文件中,该文件也是文本文件。我们可以用gcc的-S命令输出编译结果。
$gcc -S hello.i -o hello.s
除了使用hello.i进行编译以为,也可以只是使用我们最原始的hello.c文件,只需要将命令中的hello.i替换成hello.c即可。以下即hello.c文件编译得到的汇编文件。
.file "hello.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "hello, world\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB6:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
call ___main
movl $LC0, (%esp)
call _puts
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE6:
.ident "GCC: (GNU) 4.8.1"
.def _puts; .scl 2; .type 32; .endef
3.汇编(Assembly)
在汇编阶段中,汇编器将编译阶段得到的汇编文件翻译成机器语言指令,打包成可重定位目标程序的格式,并通常将结果保存在.o作为后缀的文件中。在此阶段后得到的.o文件就已经是一个二进制文件,若使用文本编辑器打开将会看到乱码。在gcc中可以使用-c选项输出汇编结果。
$gcc -c hello.s -o hello.o
下图是通过emacs的hexl-mode模式查看汇编得到的目标文件。
4.链接(Linking)
在hello程序中,调用了一个名为printf的函数,这是C编译器都会提供的标准库中的一个函数,存在与名为printf.o的目标文件中。在操作系统中通常不会直接存在printf.o文件,而是一般存在于后缀为.so(Linux)或.dll(Windows)的动态链接库文件中。链接器的作用即将hello.o的内容与printf.o的内容合并生成一个可执行文件hello(在Windows中为hello.exe)。
1.3 了解编译系统如何工作是大有益处的
这一小节本来要放到下一部分的,不过看了一下没什么重要的内容就把它加到了这一部分里。在这一小节中介绍了了解编译系统能更好的优化程序性能、理解链接时出现的错误、避免安全漏洞。
(这一节只是来充字数的hhhh)
其它
文中内容主要源自深入理解计算机系统第二版,部分图片来自该书中。