1.3 It Pays to Understand How Compilation Systems Work
为什么程序员需要理解编译系统是怎么工作的?本书给出如下解答:
1. Optimizing program performance.
为了能够make good coding decisions in our programs,我们需要对机器级的代码和编译器如何把C转化成机器代码有一定的了解。
这个make good coding decisions举例来说就是:什么时候选用swith,什么时候选用if-else;什么时候选用while,什么时候选用for;什么时候选用指针,什么时候选用数组索引这一系列平时的coding过程很难细细思考的问题。
第三章会介绍x86-64汇编语言;第五章会学习如何在已写好的C的基础上做一些小改动就能够帮助编译器更好的运行;第六章将学习memory系统,使程序更高效的运行。
2. Understanding link-time errors.
从经验来看,一些最难以解决的coding错误往往与链接器有关,尤其是试图构建large software systems的时候。这些问题在第七章会详细讨论(emm,距离第七章还有很长的路要走)。
3. Avoiding security holes.
要学一些处理buffer overflow的技术(第三章),也要学一些在programmer、compiler和operating system角度降低攻击威胁的方法。
1.4 Processors Read and Interpret Instructions Stored in Memory
处理器读取和解释存储在内存中的指令
现在假设我们的hello.c已经编成了hello,并且存放在disk上。假设我们是Unix系统,需要在shell上运行这个玩意。
linux> ./hello
hello, world
linux>
shell加载并运行hello这个可执行的程序,得到了hello, world输出,然后结束,等待下一条指令。
1.4.1 Hardware Organization of a System
为了理解运行hello程序时发生了什么,就得先理解一个典型系统的硬件组织结构,如下图所示。
CPU:central processing unit;ALU:arithmetic/logic unit;PC:program counter;
USB:universal serial bus
下面分别介绍一些关键词汇:
Buses
在整个系统中运行的是一系列叫做buses的electrical conduits(电子导管?),这些导管里装了一大堆bytes,用于在不同的component之间来回传递信息。
buses通常被设计为传输固定大小的bytes,起个名叫做word。一个word里byte的个数在不同的系统里是不同的,现在大多机器的word包含4个byte或者8个byte,也就说常说的32位或者64位。
I/O Devices
这就是输入输出设备,用来连接当前的system和外部世界。一般来说system有四个IO设备:键盘、鼠标、显示器、硬盘。
每个IO设备通过控制器(controller)和适配器(adapter)与bus相连。控制器是设备本身或者系统主板上的芯片组(chip sets);适配器是插在主板上的卡。两个东西都是为了在IObus和IO设备之间来回传输信息。
Main Memory
这玩意是个临时存储器,在处理器执行程序的时候,它保存程序和要被处理的数据。从物理上说,这玩意由一组动态随机存取器(dynamic random access memory, DRAM)组成。从逻辑上说,这玩意被组织为一个线性字节数组,每个字节都有一个唯一的地址,且地址从0开始。
Processor
处理器这玩意是解释/执行存储在main memory中的指令的引擎。它的核心是一个word大小的存储设备(寄存器)叫做程序计数器(program counter, PC)。在任意时刻,PC都指向main memory中的某些机器指令。
处理器似乎是根据其指令体系结构定义的非常简单的指令执行模型来进行操作的。这在个模型里,指令按着顺序严格执行,并且执行一条指令需要一系列步骤。处理器从程序计数器(PC)指向的内存中读取指令,解释指令中的bit,执行指令指示的一些简单操作,然后更新PC以指向下一条指令,该指令在内存中可能与刚刚执行的指令相邻,也可能不相邻。
这些操作只有少数几个,它们围绕main memory、register file和ALU展开,如下图所示。
1.4.2 Running the hello Program
前边聊这么多,介绍了每个component,下面梳理运行hello程序的流程。
首先是我们在shell键入hello,shell将每个字符存到register里,最终存到main memory里。流程图如下:
然后当敲完回车之后,shell加载可执行文件hello。这一步是把hello文件中的代码和指令存到main memory里面。如下图说是
当代码和数据都在memory之后,处理器开始执行。从main memory中拷贝到register里,再拷贝到display里: