您的位置:首页 > 其它

可执行文件的装载与进程

2015-03-11 11:07 106 查看
每个程序被运行起来后,它将拥有自己独立的虚拟地址空间,这个虚拟地址空间的大小由计算机的硬件平台决定。

一般来说,C语言指针大小的位数与虚拟空间的位数相同。

Linux OS 对进程虚拟地址空间的分配:

Operating System 1GB

0xC0000000 ----------------------------- ----------

User Process 3GB

0x00000000 ----------------------------- ----------

windows默认的是2GB+2GB

---------------------------------------------------------------------------------------------------------------------------

PAE(Physical Address Extension)

缺省

-----------------------------------------

装载的方式

1.覆盖装入

2.页映射

-----------------------------------------

进程的建立

1.创建一个独立的虚拟地址空间

2.读取可执行文件头,并且建立虚拟空间与可执行文件的映射关系(装载过程)

由于可执行文件在装载时实际上是被映射的虚拟空间,所以可执行文件很多时候又被叫做映像文件(Image)。

Linux 中将进程虚拟空间中的一个段叫做虚拟内存区域(VMA);在windows中将其叫做虚拟段(virtual section)。

映射关系保存在OS内部的一个数据结构。

3.将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。

涉及内核堆栈和用户堆栈的切换、CPU运行权限的切换。

从进程的角度可以看做是OS执行了一条跳转指令,直接跳转到可执行文件的入口地址。(如ELF文件头保存有入口地址)

-------------------------------------------------------------------------------------------------------------------------------------

进程虚存空间分布

1.ELF文件链接视图和执行视图

ELF可执行文件引入了一个概念叫做“Segment”,一个“Segment”包含一个或多个属性类似的“Section”。以“Segment”为单位映射,可以减少页内部碎片。

在将目标文件连接成可执行文件时,链接器会尽量把相同权限属性的段分配在同一“Segment”。

描述“Section”(链接视图)的结构叫做段表;描述“Segment”(执行视图)的结构叫做程序头,描述了ELF文件该如何被OS映射到进程的虚拟空间。





查看Section



查看segment



Program Header Table用来保存Segment的信息



----------------------------------------------------------------------------------------------------------------------------------------------

堆和栈

VMA除了用来映射可执行文件中的各个“Segment”以外,还用来对进程的地址空间进行管理。很多情况下,一个进程中的堆和栈分别都有一个对应的VMA。

查看进程的虚拟空间分布



第一列 VMA地址范围

第二列 VMA权限,p表示私有,s表示共享

第三列 偏移,表示VMA对应的Segment在映像文件中的偏移

第四列 映像文件所在设备的主设备号和次设备号

第五列 映像文件的节点号

第六列 映像文件的路径

主设备号和次设备号及文件节点号都是0,表示它们没有映射到文件中,这种VMA叫做匿名虚拟内存区域。

“vdso”是一个内核的模块,进程可以通过访问它来跟内核进行通信。

------------------------------------------------------------------------------------------------------------------------------

进程栈初始化

进程启动时,须知道一些进程运行的环境,最基本的就是系统环境变量和进程的运行参数。

常见做法是OS在进程启动前将这些信息保存到进程的虚拟空间的栈中。

进程在启动后,程序的库部分会把堆栈里的初始化信息中的参数信息传递给main()函数。

-------------------------------------------------------------------------------------------------------------------------------

Linux内核装载ELF过程简介

在bash 下输入命令执行某个ELF程序:

bash进程调用fork()系统调用创建一个新的进程,新的进程调用execve()执行指定的ELF。原先的 bash进程继续返回等待刚才启动的新进程结束。

在进入execve()系统调用之后,Linux内核开始进行真正的装载工作:

1.查找被执行的文件,如果找到文件,读取文件的前128个字节以判断文件的格式。

2.搜索和匹配合适的可执行文件装载处理过程。

1>根据ELF的程序头表的描述,对ELF进行映射。

2>初始化ELF进程环境。

3>将系统调用的返回地址修改为ELF可执行文件的入口点(静态链接为文件头e_entry所指地址;动态链接为动态连接器)。

3.系统调用返回,新的程序开始执行。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------、

Windows PE 的装载

RVA (Relative Virtual Address),表示一个相对虚拟地址,它是相对于PE文件的装载基地址的一个偏移地址。

每个PE文件在装载时都会有一个装载目标地址,即基地址。





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: