文章目录
1 hello程序如何翻译为可执行文件?
hello.c源程序:
#include <stdio.h>
int main(){
printf("hello, world\n");
return 0;
}
hello程序是从C语言程序开始,因为这种形式方便被人读懂。但要在系统上运行,必须要转换为机器能够识别的格式。在Linux系统中,从源文件到目标文件的转化是由GCC编译器完成的。
Linux> gcc -o hello hello.c
GCC编译器将hello.c源文件翻译为可执行目标文件hello。这个过程主要有四个阶段完成,执行四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统。
- 预处理阶段。预处理器主要对原始C程序中的头文件和宏定义进行处理和替换。得到hello.i文件。
- 编译阶段。编译器将hello.i文件翻译成hello.s,这是一个汇编语言程序。
- 汇编阶段。汇编器将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并保存在hello.o二进制文件中。
- 链接阶段。链接器将标准C库中的printf函数合并到hello.o程序中。最后得到可执行文件hello。
2 hello运行经历了哪些环节?
2.2 系统的硬件组成
一个典型系统的硬件组织如下图:
- 总线。总线主要携带信息字节在各部件间传递,常被设计为传送特定字长的字节块,也就是字。字中的字节数是一个基本的系统参数,也就是我们说的32位(4个字节)操作系统,64位(8个字节)操作系统。
- I/O设备。输入输出设备是系统与外界的连接纽带,比如上图中的鼠标、键盘、显示器和磁盘。
- 主存。 主存是一个临时的存储设备,在处理器执行程序时,用来存放程序和处理的数据。
- 处理器。 CPU解释或执行存储在主存中的指令。CPU的核心是大小为一个字的寄存器,也叫程序计数器(PC)。在任何时候,PC指针都指向主存中的某条机器指令,PC指针存放着该指令的地址。
从系统上电到断电的过程中,处理器不断执行PC指向的指令,再更新PC,使其指向下一条指令。处理器从PC指向的内存处读取指令,解释指令中的位,执行指令的操作,然后更新PC,继续执行下去。
常见英文注释:
CPU: central processing unit
ALU: arithmentic/logic unit
PC: program counter,现在也常被用为personal computer的简写
USB: Universal Serial Bus
I/O: input/output
2.3 运行hello
1.从键盘上读取hello命令
初始,启动shell终端,等待我们输入命令。当我们在键盘上输入“./hello”后,shell将字符逐一读入寄存器,再写入主存中。
2.从磁盘加载可执行文件到主存
当敲下回车时,shell将执行一系列指令来加载可执行hello文件,从而将hello目标文件的代码和数据从磁盘复制到主存。
3.将字符串从主存写到显示器
一旦目标文件hello中的代码和数据加载到了主存,处理器就开始执行hello程序的main函数中的机器指令。这些指令将“hello, world\n”字符串的字节从主存复制到寄存器文件,再从寄存器文件按复制到显示器,最终显示在屏幕上。
3 计算机中的一些重要概念
3.1 高速缓存
hello的示例揭示了一个重要的问题,系统花费大量的时间把信息从一个地方挪到另一个地方。当程序加载时,存放在磁盘上的hello程序被复制到主存中;当程序开始执行时,指令又从主存复制到处理器。同样,“hello, world\n”字符串开始在磁盘,然后复制到主存,再从主存上复制寄存器,最后复制到显示器。这些复制的开销阻碍了程序运行的速度。
对处理器而言,从磁盘读取一个字的时间开销比从主存中读取的开销大1000万倍,从寄存器文件中读数据比从主存中读取几乎要快100倍。针对处理器与主存之间的差异,系统的设计者通过高速缓存器(cache memory),作为暂时的集结区域,存放处理器近期可能会用到的信息。
在处理器和一个较大较慢的设备(例如主存)之间插入一个更小更快的存储设备(例如高速缓存)是一个很普遍的观念。实际上,每个计算机系统的存储设备组织成了一个存储器层次结构。
SRAM: static random access memory
DRAM: dynamic random access memory
3.2 操作系统管理硬件
操作系统让我们更安全方便地使用和管理硬件,而不是直接操作硬件。我们可以把操作系统看作应用程序和硬件之间插入的一层软件。
操作系统的两个功能:
- 防止硬件被失控的应用程序滥用。
- 向应用程序提供简单一致的机制来控制复杂又大不相同的低级硬件设备。
操作系统通过几个抽象的概念来实现了这两个功能:
- 文件。对I/O设备的抽象表示。
- 虚拟内存。对主存和磁盘I/O设备的抽象表示。
- 进程。对处理器、主存和IO设备的抽象表示。
抽象是一个最为重要的概念之一。在处理器中,指令集架构提供了对实际处理器硬件的抽象。使用这个抽象,机器代码程序表现得就好像运行在一个一次只执行一条指令的处理器上。
再增加一个新的抽象:虚拟机,它提供对整个计算机的抽象,包括操作系统、处理器和程序。
比较容器Docker和虚拟机VM的不同?
容器和虚拟机具有相似的资源隔离和分配优势,但功能不同,因为容器虚拟化了操作系统,而不是硬件。 容器更便携,更高效。
容器
容器是app层的抽象,将代码和依赖项打包在一起。多个容器可以在同一台机器上运行,并与其他容器共享OS的内核,每个容器在用户空间中作为隔离的进程运行。容器占用的空间比VM少(容器映像的大小通常为几十MB),可以处理更多的应用程序,并且需要的VM和操作系统更少。
虚拟机
虚拟机是将一台服务器转变为多台服务器的物理硬件的抽象。多个虚拟机可以在一台机器上同时运行。每个VM包括操作系统、应用程序、必要的二进制文件和库的完整副本(占用数十GBs)。虚拟机启动也可能很慢。
3.3 系统之间利用网络通信
现代系统通过网络和其他系统连接在一起。从一个单独的系统来看,网络可以被视为一种IO设备。当系统从主存复制一串字符串到网络适配器时,数据流经网络到达另外一台机器。系统也可以从网络适配器中读取从其他机器发送来的数据,并把数据复制到自己的主存。从而实现了不同机器之间的通信。
参考:Computer Systems A Programmer’s Perspective THIRD EDITION