`

进程的创建与可执行程序的加载-总结

阅读更多
原帖地址:http://www.cnblogs.com/justcxtoworld/archive/2013/05/28/3103571.html

根据前两篇博文中的实验

1:Linux进程地址空间之初探:一

2:Linux进程地址空间之初探:二 

现对进程的创建和可执行程序的加载过程总结如下:

一:进程地址空间的组成及相关数据结构

 

       Linux为每个进程都维持了一个独立的虚拟地址空间,进程地址空间又被分为几个虚拟内存区域:代码段、数据段、堆段、栈段、共享库段。进程地址空间中的任何有效地址都只能位于唯一的区域,这些区域不能相互覆盖。通过mmap/munmap函数,内核可以创建/删除一个虚拟内存区域。

 

         主要的数据结构有

        task_struct : 进程描述符结构,定义在<linux/sched.h>文件中,描述了该进程打开的文件、进程的地址空间、进程的状态等信息。

        mm_struct :进程虚拟内存描述符,定义在<linux/sched.h>文件中,该结构包含了和进程地址空间相关的全部信息。

        vm_area_struct:虚拟内存区域描述符,定义在<linux/mm.h>文件中,该结构体描述了指定地址空间内连续区间上的一个独立的内存范围(比如进程用户空间栈、代码段、数据段等)。

        三个结构之间的关系

        task_struct 中的一个 字段 mm 指向当前进程的虚拟地址空间描述符 mm_struct , mm_struct中的字段 mmap 指向一个vm_area_struct组成的链表,其中每个vm_area_struct 都描述了当前虚拟地址空间的一个区域。

        这里涉及的一些关键结构的具体信息可查看我前面的博文 :Linux进程地址空间之初探:一

 

二:fork 和 exec 函数及加载器的执行过程

         fork( )函数通过拷贝当前进程创建一个子进程,子进程与父进程的区别仅仅在在于PID、PPID和某些资源和统计量(例如,挂起的信号,它没必要被继承),Linux中fork是通过clone( )实现的,clone( )再调用do_fork( )。

         执行过程:

     1)为新进程创建一个内核栈、thread_info结构和task_struct 结构,这些结构的值与当前进程的值相同。此时子进程和父进程的描述符是完全相同。

     2)子进程开始使自己与父进程区别开来。进程描述符内的许多成员要被清零或设为初始值。

     3)子进程的状态被设置为TASK_UNINTERRUPTIBLE,以保证不会透入运行。

     4)设置task_struct中的相应flags标志,例如权限

     5 ) 为新进程分配一个有效PID

     6)根据传递给clone( )的参数标志进行拷贝或者共享打开的文件、文件系统信息、进程地址空间和命名空间等。

     7)最后返回子进程的PID。

 

       exec( )函数:exec函数在当前进程的上下文中加载并运行一个新的程序,只有在出错的情况下exec 函数才会返回到调用程序中,所以与fork函数调用一次返回两次不同,exec调用一次并从不返回

       exec( )执行过程:

      1)删除当前进程虚拟地址空间的用户部门已经存在的区域结构。

      2)加载可执行文件,用可执行文件中的内容覆盖当前进程地址空间相应区域

      3)设置程序计数器即eip中的值,使它指向新的代码区的入口点,调用启动代码,启动代码设置栈,控制传给新程序的主函数。

 

     其中加载可执行文件的执行过程如下:

 

      1)启动加载器,加载器删除子进程现有的虚拟地址段

      2)加载器根据可执行目标文件中的段头部表信息,创建一组新的代码段、数据段、堆段和栈段。新的堆、栈段初始化为零。代码段和数据段映射为可执行文件的代码段和数据段。

      3)根据可执行文件 ELF 中的.interp段查找动态链接器ld.so的路径名,动态链接器实际上也是一个共享对象,加载器同样通过映射的方式将它加载到进程的地址空间。然后把控制权交给动态链接器的入口地址(与可执行文件一样,共享对象也有入口地址),当动态链接器得到控制权后,进行一系列初始化操作,然后根据可执行文件ELF中.dynamic段,这个段里保存了动态链接器所需要的相关信息,比如依赖于哪些共享对象(例如libc.so)、动态链接符号表位置、动态链接重定位表的位置、共享对象初始化代码的地址等信息,根据它们查找和加载可执行文件所依赖的共享对象,并映射到进程地址空间的共享区域中。

      4)当所有动态链接工作完成以后,动态连接器会将控制权交给可执行文件的入口地址,即跳转到可执行文件的_start 启动代码并调用新程序中的main函数开始执行。

   这里提到的 .interp 、.dynamic、段头部表的查看方法及具体信息可查看我上篇博文:Linux进程地址空间之初探:二 

 

三:task_struct进程控制块,ELF文件格式与进程地址空间的联系

     task_struct进程控制块中的mm字段所指向的mm_struct结构描述了进程地址空间的信息,包括代码段、数据段、堆段、栈段所在地址空间里的起始和结束地址等信息。

      ELF文件格式中的 ELF头部、段头部表、.init、.text、.rodata段对应进程地址空间中的代码段,在加载可执行文件时,会把它们映射到进程地址空间中的代码段区域。

      ELF文件格式中的 .data、.bss段 对应 进程地址空间中的 数据段,在加载可执行文件时,会把它们映射到进程地址空间的数据段区域。

      具体的对应关系图请见 上篇博文:Linux进程地址空间之初探:二 

 

四:动态链接库在ELF文件格式中与进程地址空间中的表现形式

    动态链接库在ELF文件中对应着.dynamic段所包含的信息:包括动态链接器所需要的相关信息,比如依赖于哪些共享对象(例如libc.so)、动态链接符号表位置、动态链接重定位表的位置、共享对象初始化代码的地址等信息。

     动态链接库最后被映射到进程地址空间的共享库区域段。

     ELF文件格式图、可执行文件加载完后进程地址空间的状态图、及dynamic段的信息见上篇博文:Linux进程地址空间之初探:二

    

 

 

本文链接

分享到:
评论

相关推荐

    操作系统实验——进程创建与进程间通信

    这种方式常用于动态加载可执行文件,例如在shell脚本中执行命令。 三、进程间通信(管道) 进程间通信(IPC, Inter-Process Communication)是操作系统中实现不同进程间数据交换的关键技术。管道是一种半双工通信...

    QT通过QProcess调用外部可执行程序,并将其嵌入到主窗口中

    总结来说,QT通过QProcess调用外部可执行程序并嵌入到主窗口中的步骤包括: 1. 创建QProcess对象。 2. 启动外部程序并设置工作目录。 3. 连接QProcess的信号到相应的槽,以便处理输出。 4. 在槽函数中读取并显示输出...

    windows进程监听程序

    - `CreateProcess`:这是创建新进程的主要函数,它不仅启动一个新进程,还会加载指定的可执行文件。 - `OpenProcess`:用于获取对已存在进程的访问权限,以便进一步监控或控制。 - `GetProcessId`:获取进程的...

    2023程序人生-Hello’s P2P

    在这个过程中,操作系统会将进程创建,并将程序加载到内存中。 8. 代码执行的概念与作用 代码执行是程序执行的过程,程序会将代码加载到内存中,并执行代码。在这个过程中,程序会将代码加载到内存中,并执行代码,...

    (12.2)--可执行文件的加载1

    main函数是可执行程序的入口点,其原型形式如下:`int main(int argc, char argv, char envp);`或者:`int main(int argc, char *argv[], char *envp[]);`其中,`argc`指定参数个数,参数列表中第一个总是命令名(可...

    操作系统实验进程的创建源代码及文档

    这个函数负责加载可执行文件,初始化进程和线程,为新进程分配内存,以及设置进程和线程的属性。以下是`CreateProcess`的基本调用格式: ```cpp BOOL CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout...

    进程加载_END.rar

    1. **程序加载**:操作系统读取程序的可执行文件(如.exe或.dll),通常是PE(Portable Executable)格式的文件,到内存中。 2. **地址空间初始化**:为进程分配虚拟内存空间,包括代码段、数据段、堆和栈。 3. **...

    实现exe从资源中加载到内存中运行

    在Windows操作系统中,有时为了软件的安全性和便携性,开发者会尝试将可执行文件(exe)嵌入到主程序的资源中,然后在程序运行时动态地从资源中加载到内存并执行。这种方式避免了单独分发多个文件,也可以防止恶意...

    Linux进程学习总结.pdf

    - 进程是动态的,代表程序在内存中的执行实例,而程序是静态的,是存储在磁盘上的可执行代码。 - 进程包含程序的执行上下文,包括程序计数器、栈、全局变量等。 4. **进程的优点与缺点**: - 优点:支持并发执行...

    进程和程序:编写命令解释器sh

    ### 进程与程序:编写命令解释器sh ...通过以上内容的学习,我们可以更好地理解进程和程序的概念,以及如何使用Unix系统中的Shell来管理和执行程序。这对于深入理解操作系统工作原理和进行系统级编程具有重要意义。

    可以把进程注入 Dll到其他进程中的一个程序

    DLL是Dynamic Link Library的缩写,它是一种可执行文件格式,包含可由多个程序同时使用的代码和数据。通过进程注入,我们可以将一个DLL加载到另一个正在运行的进程中,使得该DLL的函数和资源可以在目标进程中使用。 ...

    监视进程创建 实现 源码

    这个函数允许程序启动一个新的可执行文件,并为其创建一个新进程和线程。它接收一系列参数,如应用程序名称、命令行参数、进程和线程的安全属性等,然后执行一系列操作,包括加载映像文件、分配内存、设置初始堆栈和...

    在C#中使用进程加载应用程序.rar

    当我们谈论在C#中使用进程加载应用程序时,我们通常是指利用System.Diagnostics命名空间中的Process类来启动、控制或与另一个应用程序交互。这个过程可以分为几个关键步骤,包括创建Process对象、配置启动信息以及...

    Windows程序设计-进程线程模块查看器

    **模块** 在Windows程序中,通常指的是可执行文件(.exe)和动态链接库(.dll)。模块包含了进程运行所需的代码和数据。当进程启动时,它的主模块(通常是.exe文件)会被加载到内存中,随后可能根据需要加载其他.dll...

    进程创建示例

    `CreateProcess`函数是Windows API的一部分,它负责初始化新进程的内存空间,加载可执行文件,并执行该文件的入口点。其原型如下: ```cpp BOOL CreateProcess( LPCTSTR lpApplicationName, LPTSTR lpCommandLine...

    VS2008-免注册-单进程创建多个大漠对象-例子

    这通常是为了避免注册过程中的权限问题或避免对系统注册表造成过多修改,从而提高程序的可移植性和稳定性。 【标签】:“大漠”标签明确了我们的讨论是围绕大漠插件展开的。大漠插件由一系列API组成,可以实现对...

    CreateProcess创建暂停进程进行DLL注入-[VC.Dll+VB.Code]

    `CreateProcess`是Windows API中的一个关键函数,它负责启动新的进程并可选地创建新的线程。这个函数提供了对新进程的详细控制,包括进程的启动参数、工作目录以及环境变量等。在创建进程时,我们可以通过指定`...

    在Android中调用二进制可执行程序

    在深入探讨如何在Android环境中调用二进制可执行程序之前,首先需要理解Android系统的基本架构以及它与传统Linux系统之间的区别。Android基于Linux内核构建,因此支持许多与Linux相似的功能,比如可以运行二进制可...

    OS.rar_fork孙子进程_创建孙子进程

    比如,我们可以在创建了子进程后,使用`exec()`来加载并运行一个新的可执行文件,这样子进程就不再是父进程的副本,而是执行了新的程序。 创建孙子进程的过程通常涉及以下步骤: 1. 父进程调用`fork()`,创建子进程...

    操作系统实验1 进程控制

    1. **进程创建**:使用`fork()`函数可以创建一个新的进程。`fork()`返回值为0表示子进程,非零值表示父进程,这样我们就能区分父子进程,并进行不同的操作。 2. **进程执行**:在创建进程后,可以使用`exec()`系列...

Global site tag (gtag.js) - Google Analytics