简单描述hello world中到底发生了什么

最近啃了啃书,这里记录一些个人觉得比较重要的部分

#include <stdio.h>

int main(){
     printf("hello world");
     return 0;  
}

简单的一句hello world,从编译到执行到底发生了一些什么呢.下面简单的描述一下

这样一个hello.c文件写完后,只是一个有ascii字符组成的普通文本文件而已

首先是需要用编译器将其编译成可执行程序

gcc -o hello hello.c

在这个编译过程中,实际上给我们做了4步操作,分别是预处理、汇编、编译、链接

预编译阶段:实际是处理这个hello.c中的所有#开头的命令来修改这个原文件,生成一个hello.i的文件,例如#include,#define

汇编阶段:将这个预处理完毕的hello.i文件翻译成汇编版本的文本文件hello.s

编译阶段:将这个汇编的文本文件翻译成机器语言指令.并将这些目标指令打包成一种可重定位目标程序的格式,将这个结果保存在hello.o的文件中,这个hello.o就是一个二进制文件了

链接阶段:根据hello中调用到的函数去找对应的目标二进制文件printf.o合并到我们的hello.o程序中,最后生成了hello文件,这是一个可执行目标文件,可以被加载到内存,由系统执行

======================分割线==========================

生成出来的hello在执行过程中又发生了什么呢,这里我们需要先知道一下系统硬件的组成

总线:贯穿整个系统的一组电子管道,负责携带信息在各个硬件之间传递,通常会传递定长的字节块大多数系统都是4个字节(32位)或者8个字节(64位)

I/O设备:系统与外部世界的连接通道,通常的io是设备一般有作为用户输入的键盘,鼠标,作为用户输出的显示器,存储数据和程序的磁盘,IO设备都是通过控制器或适配器与IO总线相连

主存:临时存储设备,也就是内存咯,在处理器执行程序时用来存放程序和程序处理的数据,逻辑上可以把主存看成一个线性的字节数组

处理器:简称CPU,解释执行存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(一般是寄存器),称为程序计数器,处理器从程序计数器指向的内存处读取指令,解释指令中的位,并执行该指令

cpu在指令的要求下可能会执行下面的操作

加载:从主存复制一个字节或者一个字到寄存器,覆盖之前的内容

存储:从寄存器复制一个字或字节到主存某个位置,覆盖之前的内容

操作:把两个寄存器的内容复制到ALU(算数/逻辑单元),ALU对两个字进行算数运算,并将结果存放到一个寄存器中

跳转:从指令本身中抽取一个字,并将这个字复制到程序计数器中

======================分割线==========================

用了以上的一个基础硬件的了解后,我们再看看当在shell中执行一个hello发生了什么

首先是在终端输入了./hello

USB控制器从键盘接收了用户的输入,通过I/O总线将输入数据传递到总线,然后总线接口将字符逐一存入寄存器,然后再从寄存器放入主存

然后我们敲下回车,看到了显示hello world

回车时shell程序知道我们已经结束了命令输入,然后执行了一系列指令来加载这个可执行的hello

这些指令将目标文件从磁盘复制到了主存,然后处理器开始执行hello的main中的机器语言指令。

机器语言指令将hello world字符串从主存复制到了寄存器,然后再从寄存器复制到了显示设备,最后输出了结果

这里的信息传递都是通过总线接口和I/O总线来进行传递的。

到这里,这个hello.c就执行完毕了

======================分割线==========================

从上面这个例子可以简单看出来,系统花费了大量时间将信息从一个地方挪到另一个地方,比如从I/O输入传递到了寄存器,然后再放到主存、从主存复制到寄存器再到I\O设备显示器输出

这些复制就是开销,减慢了程序真正的工作。所以系统的一个主要目标就是让这些复制尽可能的快一些。

根据机器原理,较大空间的存储设备运行速度会比较小的存储设备运行的慢,例如从磁盘读取数据要比从主存读取数据的效率低1000万倍,从主存读取要比从寄存器读取效率低100倍。

为了针对寄存器和主存的差异,系统设计者采用了更小更快的存储设备,高速缓存存储器,这里存放处理器近期可能会需要用到的信息

高速缓存可以分为三个档次L1、L2、L3

L1高速缓存器容量可以达到数万字节,并且访问速度几乎和寄存器一样快

L2高速缓存器容量是数十万到数百万,访问速度比L1高速缓存器慢5倍

通过让高速缓存里存放可能经常访问的数据,大部分的内存操作都能再快速的高速缓存中完成,寄存器不用走总线去主存中拿数据,直接从高速缓存中复制即可

======================分割线==========================

hello的例子中的运行流程可以看到我们的程序并没有直接访问键盘,显示器,主存,磁盘。而是通过操作系统提供的服务来进行的。我们可以把操作系统看成应用程序和硬件之间的一层软件。

所有应用程序对硬件的操作都必须通过操作系统。

猜你喜欢

转载自www.cnblogs.com/kings0/p/9848651.html
今日推荐