程序加载

我们写程序一般都用Visual Studio等集成开发环境(IDE),写好程序后直接点运行就可以出来结果,在Linux中一句简单的命令“gcc -o main main.c”编译连接后就可以执行,那么从我们初始的代码,也就是.c 或 .cpp文件到最后的可执行文件,这一过程真的像我们看到的这么简单吗?那可执行文件.exe是储存在磁盘上的,运行时要加载到内存,它要如何加载,加载那些东西呢?下面来详细探究探究吧。


一个计算机包括CPU、内存、I/O,操作系统为了屏蔽底层硬件系统的差异,提供统一的接口,提供了许多抽象的技术。为了屏蔽I/O层的差异,提供了虚拟文件系统(VFS);为了屏蔽内存和I/O的差异,提供了虚拟储存系统(虚拟内存);为了屏蔽CPU、内存、I/O底层差异,也作为这三个资源调度的一个单位,提供了进程。


程序运行不会直接加载到内存上,每个程序运行起来,内核都会给它分配虚拟地址空间,分配的大小由CPU的位数决定,一般32位分配2的32次方也就是4G大小的虚拟地址空间。这里补充一点,计算机的位数取决于算术逻辑单元(ALU)的宽度,32位一次最大能处理32bit的数据,而不是地址总线的数量或数据总线的数量。8位:地址总线16条,数据总线8条;16位:地址总线20条,数据总线16条;32位恰好地址总线和数据总线都是32条


那4G的虚拟地址空间又是怎样分配的呢?如图所示:


128M的不可访问的段,红色部分在堆还没有被申请的时候称为空洞,为堆的申请预留空间。ZONE_DMA约16M,直接访问内存,加快磁盘和内存交换数据;ZONE_NORMAL约892M;ZONE_HIGHMEM约128M,处理大于1G物理内存的数据。用户空间是独立的,内核空间是共享的。


指令加载到.text,段数据加载到数据段(.data和.bss),初始化的且不为0的数据放在.data段,未初始化的或者初始化为0的数据放在.bss段。都是数据为什么要存放在2个段呢?.bss可以节省空间那它节省的是什么的空间呢?


接下来看看程序的编译链接的具体过程。