首页 > 代码库 > 程序员的自我修养-链接、装载与库-6 可执行文件的装载与进程
程序员的自我修养-链接、装载与库-6 可执行文件的装载与进程
可执行文件的装载与进程
可执行文件只有装载到内存后才能被CPU执行。基本过程就是把程序从外部存储器中读取到内存中的某个位置。
程序(可执行文件)是一个静态的概念。就是一些预编译好的指令和数据组成的一个文件。进程则是一个动态的概念。很多时候,把动态库叫作运行时。
每个程序在执行时,都拥有自己独立的 虚拟地址空间。
虽然,内存中的虚拟地址空间很大,但是任意一个程序都必须在OS的监督下使用资源,不能任意访问或者占用内存。大多数时候我们在Windows下碰到的"进程因非法操作需要关闭" 和 Linux下“”Segmentation fault“错误都是因为访问了未经允许的内存地址。
32位的操作系统上最多能够支持的物理内存大小为4GB(无PAE情况下) ; 硬件MMU提供地址转换功能;
页映射:
页映射是虚拟存储机制的一部分,它随着虚拟存储的发明而诞生。页映射不是一下子就把程序的所有数据和指令都装入内存,而是将内存和所有磁盘中的数据和指令按照“页”“Page”为单位划分成若干页,以后装载和操作的基本单位就是页。4096 8192bytes 2Mb 4Mb等。
换页规则:FIFO先进先出;LUR最少使用算法;
从操作系统的角度看程序的装载:
创建一个程序然后装载相应的可执行文件并且执行。在有虚拟存储的情况下,上述过程最开始哦需要做三件事情:
1.创建一个独立的虚拟地址空间。
2.读取可执行文件头,并且建立虚拟地址空间与可执行文件的映射关系;
3.将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。
页错误
程序在运行的时候,CPU是由程序控制的,一旦发生页错误,也就是所需要访问的页并不在内存中,那就CPU控制权交还给系统。系统有专门负责处理页错误的功能。将上述第二部中的 虚拟地址空间与可执行文件的数据结构,OS查询出该页的虚拟地址,然后找出该页在可执行文件中的偏移量,然后在物理内存中开辟一个页大小的地址,然后将虚拟内存与分配的物理页之间建立映射关系,然后把控制权交还给进程。
进程虚拟空间分布
正常情况下,每个页面包含多个段,那么有可能会造成页资源的浪费(很简单因为一个也里面不一定包含页面大小个段)。机智的操作系统找到了一种简单的方案:
那就是按照段的权限来分类合并到一起当做一个段来进行映射。将小的段Section-》大的段Segment组成一个页映射到内存。这样有效的减少了页面内部碎片,从而节省了内存空间。
Section与Segment : ELF目标文件按照Section来存储,ELF按照Segment来划分
ELF可执行文件引入了一个概念“Segment”,一个Segment包含一个或者多个属性类似的“”section“”。
查看一个ELF可执行文件的Section:
查看Segment是这样的:
总的来说,Segment与Section是从不同角度来划分一个ELF文件。在ELF中被称为不同的视图(View)从Section角度看ELF文件就是链接视图(Linking View)
从Segment的角度来看就是执行视图(Execution View)
段对齐:
使用Segment装载依然会出现内存浪费的情况,内存利用率很低。机智的OS采用了一个很取巧的办法:就是让那些各个段接壤部分共享一个物理页面。然后将该物理页面映射两次(有两个虚拟内存,让两个段以为是两个地址 )。这种映射方法下,对于一个物理页面可能包含两个段的数据,甚至可能是多个段。
程序员的自我修养-链接、装载与库-6 可执行文件的装载与进程