zoukankan      html  css  js  c++  java
  • 一个可执行文件的生成过程到进程在内存中的分布


    可执行文件的生成

    http://www.cnblogs.com/web21/p/6201735.html

    总:一个可执行文件(linux elf格式文件)是通过什么方式从ELF格式文件加装从而成为进程来执行的

    在Linux系统中,可以通过fork()函数来创建进程,然而创建的子进程完全复制父进程的资源,但是我们在子进程中可以使用exec函数族系统调用来创建一个自己进程,它可以根据指定的文件名或者路径名找到可执行文件(ELF文件),并用来取代原调用进程的数据段,代码段和堆栈段,在执行完后,原调用的进程内容除了进程号外,其他全部被替换了,最终执行可执行文件变为进程的概念。而我们输入的常用指令就是可执行文件,另一方面对于exec函数族,系统调用有几种形式,可以通过传入不同的参数来实现可执行文件到进程的转变。

    进程的装载 (覆盖装入(Overlay)和页映射(Paging)是两种典型的动态装载方法,现在覆盖装入已经不用了。)

    创建一个进程,然后装载相应的可执行文件并且执行。最开始只需要做三件事情:
    ①创建一个独立的虚拟地址空间。主要是分配一个页目录(Page Directory)。

    ·····elf文件的载入、详细见下文·····

    ②读取可执行文件的头,并且建立虚拟空间和可执行文件的映射关系。主要是把可执行文件映射到虚拟地址空间,即做虚拟页和物理页的映射,以便“缺页”时载入。

    ③将CPU的指令寄存器设置成可执行文件的入口地址,启动运行。从ELF文件中的入口地址开始执行程序。

    缺页中断科普

    http://baike.baidu.com/link?url=TPe3gsJlB9NzLk7L8TzE8-Px1W2jM0R4bhPLB5gLT6OGLZ--w8Jhc5u4pozZT2qfr5cdx4QmTrpYhuu9V2Y1N6hv85FxHX59TnSujCBknXPhQJg9dkk118c7DZcVCAg0

    例如: bash(一个终端对应一个bash进程)调用fork()系统调用创建一个新的进程,然后新的进程调用execve()系统调用执行指定的ELF文件。 bash进程继续返回等待新进程执行结束,然后重新等待用户输入命令。execve()系统调用被定义在unistd.h,它的原型如下:

       int execve(const char *filenarne, char *const argv[], char *const envp[]);

     它的三个参数分别是被执行的程序文件名、执行参数和环境变量。Glibc对execve()系统调用进行了包装,提供了execl(), execlp(), execle(), execv()和execvp()等5个不同形式的exec系列API,它们只是在调用的参数形式上有所区别,但最终都会回到execve()系统调用中。

    调用execve()系统调用之后,再调用内核的入口sys_execve()。 sys_execve()进行一些参数的检查复制之后,调用do_execve()。 因为可执行文件不止ELF一种,还有Java程序和以“#!”开始的脚本程序等, 所以do_execve()会首先检查被执行文件,读取前128个字节,特别是开头4个字节的魔数,用以判断可执行文件的格式。 如果是解释型语言的脚本,前两个字节“#!"就构成了魔数,系统一旦判断到这两个字节,就对后面的字符串进行解析,以确定程序解释器的路径。
    当do_execve()读取了这128个字节的文件头部之后,然后调用search_binary_handle()去搜索和匹配合适的可执行文件装载处理过程。Linux中所有被支持的可执行文件格式都有相应的装载处理过程,search_binary_handle()会通过判断文件头部的魔数确定文件的格式,并且调用相应的装载处理过程。如ELF用load_elf_binary(),a.out用load_aout_binary(),脚本用load_script()。

    ELF文件的装载
    ①检查ELF可执行文件格式的有效性,比如魔数、程序头表中段(Segment)的数量。
    ②寻找动态链接的”.interp”段(该段保存可执行文件所需要的动态链接器的路径),设置动态链接器路径。
    ③根据ELF可执行文件的程序头表的描述,对ELF文件进行映射,比如代码、数据、只读数据。
    ④初始化ELF进程环境,比如进程启动时EDX寄存器的地址应该是DT_FINI的地址(结束代码地址)。
    ⑤将系统调用的返回地址修改成ELF可执行文件的入口点,这个入口点取决于程序的链接方式,对于静态链接的ELF可执行文件,这个程序入口就是ELF文件的文件头中e_entry所指的地址;对于动态链接的ELF可执行文件,程序入口点是动态链接器。

    当ELF被load_elf_binary()装载完成后,函数返回至do_execve()在返回至sys_execve()。在load_elf_binary()中(第5步)系统调用的返回地址已经被改成ELF程序的入口地址了。 所以当sys_execve()系统调用从内核态返回到用户态时,EIP寄存器直接跳转到了ELF程序的入口地址,于是新的程序开始执行,ELF可执行文件装载完成。

     ELF文件头分析  http://www.cnblogs.com/cdcode/p/5551649.html   http://blog.csdn.net/hhhbbb/article/details/6855004

    原文:http://blog.csdn.net/cj_kano/article/details/42374993

  • 相关阅读:
    mysql 存储过程
    python 模块 SQLalchemy
    python 模块 DButils
    转:6410中断控制详解
    ARM中MMU地址转换理解
    ok6410内存初始化
    ARM时钟初始化
    ARM处理器启动流程
    uboot启动流程
    ARM处理器启动流程
  • 原文地址:https://www.cnblogs.com/web21/p/6222547.html
Copyright © 2011-2022 走看看