进程的创建与可执行程序的加载
SA1***6*69 张*铭
实验环境:ubuntu 12.04 LTS
当在Linux下编写一个源程序,经过编译链接之后生成可执行程序,在终端shell命令行下输入./(可执行程序的名字)来执行的过程,实际上是shell创建一个子进程,在子进程中加载可执行程序进行执行的过程,具体的子进程加载可执行程序之前的准备工作过程以及fork、exec的工作原理分别在
Linux操作系统学习_用户进程之由新进程创建到可执行程序的加载
Linux操作系统学习_用户进程之fork()与exec函数族篇
1、task_struct进程控制块
为了管理进程,内核必须对每个进程所做的事情进行清楚的描述,这正是进程描述符的作用。进程描述符都是task_struct类型结构,它的字段包含了与一个进程相关的所有信息。当一个进程被创建时,系统就为该进程建立一个task_struct任务结构体。当进程运行结束时,系统撤消该进程的任务结构体。进程的任务结构体是进程存在的唯一标志。Linux在内存空间中开辟了一个专门的区域存放所有进程的任务结构体。
2、ELF文件格式与进程地址空间的联系
ELF文件的结构如下图:
关于ELF Header,即ELF文件头其作用这里不再赘述,上面Linux操作系统学习_用户进程之由新进程创建到可执行程序的加载一文中已有阐述。.text单元中主要存储的是ELF文件的程序正文部分。.data单元存储的是已经初始化了的数据。.bss单元中存储的主要是未初始化的数据。
进程地址空间中的存储区情况:
可以看到堆是向上增长的,而栈是向下增长的。
所以,在加载可执行文件时,ELF文件中的ELF文件头和程序正文区域.text会映射到存储区域的相应的程序文件区中,而ELF文件的数据区,包括已初始化的数据和未初始化的数据会分别映射到存储区域的.data区域和.bss区域。而链接时的库文件则主要映射到存储区域中的存储器映射区域。
3、动态链接库在ELF文件格式中与进程地址空间中的表现形式
调用定义好的函数,然后再用连接器与函数库连接。这样产生的可执行文件就会很大。因为连接器把程序需要用的所有函数的代码都复制到了可执行文件中去了。这种连接方式就是所谓的静态连接,与之相对的就是动态连接。连接器在可执行文件中标记出程序调用外部函数的位置,并不把代码复制进去,只是标出函数在动态连接库中的位置。用这样的方式生成的特殊可执行文件就是动态连接。在运行这种动态程序时,系统在运行时把该程序调用的外部函数地址映射到程序地址,系统有一个程序叫做动态连接器,用以完成动态链接过程。动态连接器是由ELF可执行文件中的.interp段来指定的,该段的内容就是一个简单的字符串。ELF可执行程序依赖的动态链接库保存在ELF的.dynamic段中。
可以看到libc文件即为程序forkexample2的动态链接库,而ld文件即为相应的动态链接器。
可以使用readelf命令来查看ELF文件相应的信息,-h选项查看前面提到的ELF文件头的信息:
Magic:字段是一个标识符,只要Magic字段是7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00的文件都是elf文件。Class:字段是表示elf的版本,这是一个32位的elf。Machine:字段是指出目标文件的平台信息,这里是 Intel 80386平台。其他的字段可以从其字面上看出它的意义,这里就不一一解释了。
可以使用-d选项查看ELF文件的.dynamic段中动态链接库的信息: