本文共 3626 字,大约阅读时间需要 12 分钟。
hello.c源程序实际上是由0和1组成的比特序列.其中八个比特被组织为一组,称为字节.
现代计算机大部分用ASCII标准表示字符,一个字节大小的整数值表示每一个字符.c的ASCII表示如下图:hello.c的每条c语句都必须被转化为一系列低级机器语言指令,然后这些指令按照一种可执行目标程序的格式打包好,并以二进制的磁盘文件的形式存放起来.
预处理阶段
通过#include <stido.h>告诉预处理器,读取hello.c的系统头文件stdio.h的内容并查到程序文本中,得到hello.i. 编译阶段 编译器将hello.i翻译成文本文件hello.s.他包含一个汇编语言程序. 汇编阶段 汇编器将hello.s翻译成机器语言指令。叫做可重定位目标程序的格式。并保存到hello.o文件中,这是个二进制文件。 链接阶段 由于hello程序调用了printf函数,这个函数是每个c编译器都提供的一个函数,它存在于一个名为printf.o的单独预编译好目标文件中。这个文件以某种形式合并到我们的hello.o程序中。而链接器就是处理这种合并,得到hello文件,进而加载到内存中,由系统执行。整体流程如下图:
处理器处理储存在内存中的指令
shell将加载并运行hello程序。总线
贯穿整个系统的一组电子管道称作总线,负责携带信息字节并在各个部件之间传递。 备注:总线通常被设计成传送定长的字节块,就是字。字的字节数是系统的一个基本参数。大多数机器的机器为4个字节或者8个字节,即我们通常见到的32位系统或者64位系统。I/O设备
每个I/O设备都通过控制器(主板上的芯片组)或适配器(一块插在主板插槽上的卡)和I/O总线相连。主存
一个临时存储设备,用来存放程序和程序处理的数据。处理器
是执行存储在主存中指令的引擎。 处理器的核心是一个大小位一个字的存储设备(即寄存器),被称为程序计数器(即PC)。任何时刻,PC都指向主存中的某条机器语言指令。从系统通电开始直到系统断电,处理器在不断执行PC指向的指令。 处理器的执行是按照指令集架构决定的。系统的硬件组成如下图:
1.shell程序执行指令,等待我们输入命令。
2.我们键盘输入“./hello”后,shell将字符逐一读入寄存器,再将它存放到内存中。如图:3.接着我们键入回车键,shell确认我们输入结束,便会执行指令来加载可执行hello文件。将hello目标文件终端代码和数据从磁盘复制到主存。其中包括最终被输出的字符串"hello world\n"。
备注:通过DMA(直接存储器存取)技术,数据可以不通过处理器直接从磁盘到达主存。如图: 4.目标文件hello中的代码和数据加载到主存,处理器开始执行hello程序的main程序中的机器语言指令。这些指令从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上。如下图:上面执行hello程序的过程我们可以得知,系统大量时间把信息从一个地方挪到了另一个地方。系统设计者的目标就是使得这些工作的时间尽可能快的完成。
例如,一个典型的寄存器文件只存几百字节的信息,而主存中存几十亿字节。处理器从寄存器文件中读取数据比从主存读取快几乎100倍数,随着处理器的运行速度的提示这个倍数还在加大。 针对处理器和主存的这种差异,系统设计者采用了更小更快的存储设备,称为高速缓存,用于存储近期可能需要用到的数据。 L1高速缓存:其中位于处理器上的L1高速缓存容量可达几万字节,但是访问速度可以和寄存器一样快。 L2高速缓存:容量位数十万到数百万字节,通过特殊的总线连接到处理器。进程访问L2高速缓存的速度比L1慢5倍,但是仍然比访问主存快5~10倍。 备注:L1和L2高速缓存是使用一种叫做SRAM的硬件技术实现的。同时目前很多cpu已经实现更强大的三级高速缓存。 高速缓存的硬件设计如下图:在处理器和一个较大较慢的设备之间插入一个更小更快的存储设备已经称为一个普遍的观念。而每个计算机系统中的存储设备也都被设计成一个存储器层次结构,如图:
其中主要的思想就是上一层的存储器作为低一层存储器的高速缓存。操作系统的两个基本功能如下:
1.防止防止硬件被失控的应用程序滥用 我们可以吧操作系统看作是应用程序和硬件之间的一层软件,如下图:2.向应用程序提供简单一致的机制来控制复杂而且大不相同的硬件设备。
操作系统通过几个基本的抽象概念来实现,可表示如图:
进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程,每个进程好像在独占硬件。
**上下文切换:**并发运行指的是一个进程的指令和另一个进程的指令是交错执行的。无论在单核还是多核的cpu中,一个cpu看起来好像都是在并发执行多个进程,这其实是通过处理器在进程间切换来实现的。操作系统实现这种交错执行的机制,称为上下文切换。操作系统保持跟踪进程运行所需要的所有状态信息,比如PC和寄存器的当前值和主存的内容。 任何一个时刻单个处理器只能执行一个进程的代码,操作系统决定要把控制器从当前进程转移到某个新进程时候,就会进行上下文切换。即保存当前进程的上下文,恢复新进程的上下文,接着把控制器交给新进程。通过shell进程执行hello进程
现代操作系统中,一个进程实际上由多个线程的执行单元组成,每个线程都运行在进程的上下文中,共享同样的代码和全局数据。
多线程之间比多进程之间更容易共享数据,而且线程一般比进程更加高效,所以成为重要的编程模型。 虚拟内存 我们知道硬件上,很多情况下我们只有一个主存。但是在系统中,从进程的角度去看,每个进程看到的内存都是一致的。这是为什么呢? 答案就是虚拟内存,虚拟内存也叫做虚拟地址空间。它为每个进程提供了一个假象,好像每个进程都在独占着内存一样。 如图是linux的虚拟内存: 下面逐个解析每个地址空间端,地址从最下面开始:文件就是字节序列。
其中,每个I/O设备、键盘、显示器甚至网络都可以看做是文件。 文件这个简单的概念非常强大,主要原因是他为应用程序提供了一个统一的视图来看待系统中所有的I/O设备。抽象在计算机系统中的重要性
抽象的使用是计算机最为重要的概念之一。例如,为一个函数规定一个简单的API就是一个抽象,程序员无需了解内部的实现就可以使用这些代码。 前面我们了解到以下这些抽象:虚拟机
这里我们新增一个抽象,虚拟机。 虚拟机提供了对整个操作系统的抽象,包括了操作系统、处理器和程序。虚拟机的思想是IBM提出来的,因为一些计算机必须能够同时运行为不同的操作系统,例如windows、macOS、linux。–文献参考:《深入理解计算机系统(第三版)》
转载地址:http://plyni.baihongyu.com/