Linux内核分析7:Linux内核装载和启动一个可执行程序的分析

来源:互联网 发布:印度美食 知乎 编辑:程序博客网 时间:2024/06/05 20:17

1、编译链接的过程和ELF可执行文件格式

1.1 编译链接的过程
       源文件生成可执行文件的过程主要包括三个部分:
  1. 预处理:主要是编译器对各种预处理命令进行处理,包括头文件的包含、宏定义的扩展、条件编译的选择等;
  2. 编译:把作为中间结果的汇编代码翻译成了机器代码,即目标代码,不过它还不可以运行;
  3. 链接:链接是处理可重定位文件,把它们的各种符号引用和符号定义转换为可执行文件中的合适信息(一般是虚拟内存地址)的过程。链接又分为静态链接和动态链接,前者是程序开发阶段程序员用ld(gcc实际上在后台调用了ld)静态链接器手动链接的过程,而动态链接则是程序运行期间系统调用动态链接器(ld-linux.so)自动链接的过程。

    如下图所示:

                          

分析:以hello.c源文件为例
      (1)预处理阶段:gcc -E -o hello.cpp hello.c -m32 将hello.c文件预处理成hello.cpp文件;预处理负责把include的文件包含进来及宏替换等工作。

      (2) 编译阶段:gcc -x cpp-output -S -o hello.s hello.cpp -m32 将hello.cpp文件编译成hello.s汇编代码
      (3)链接阶段:gcc -x assembler -c hello.s -o hello.o -m32 将目标文件链接成可执行文件hello
1.2 ELF可执行文件格式
        ELF文件由4部分组成:ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。实际上,一个文件中不一定包含全部内容,而且他们的位置也未必如同所示这样安排,只有ELF头的位置是固定的,其余各部分的位置、大小等信息由ELF头中的各项值来决定。
        一个ELF头文件在文件的开始,保存了路线图(road map),描述了该文件的组织情况。程序头表(program header table)告诉系统如何来创建一个进程的内存映像。Section头表(section header table)包含了描述文件sections的信息。每个section在这个表中有一个入口;每个入口给出了该section的名字,大小。
       当创建或增加一个进程映像的时候,系统在理论上将拷贝一个文件的段到一个虚拟的内存段。
ELF可执行文件分为三种:

  1. 一个可重定位(relocatable)文件保存着代码和适当的数据用来和其他的object文件一起来创建一个可执行文件或者一个共享文件;主要是.o文件;
  2. 一个可执行文件(executable)文件保存着一个用来执行的程序;该文件指出了exec(BA_OS)如何来创建程序进程映像;
  3. 一个共享object文件保存着代码和合适的数据,用来被下面的两个链接器链接。第一个是连接编辑器,可以和其他的可重定位和共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来闯进一个进程映像。主要是.so文件。

                          

Elf header格式代码如下:

  typedef struct{  unsigned char e_ident[EI_NIDENT];  Elf32_Half e_type;  Elf32_Half e_machine;  Elf32_Word e_version;  Elf32_Addr e_entry;  Elf32_Off e_phoff;  Elf32_Off e_shoff;  Elf32_Word e_flags;  Elf32_Half e_ehsize;  Elf32_Half e_phentsize;  Elf32_Half e_phnum;  Elf32_Half e_shentsize;  Elf32_Half e_shnum;  Elf32_Half e_shstrndx;}Elf32_Ehdr;
数据类型说明:

名称大小对齐用途Elf32_Addr44无符号程序地址Elf_32_Half22无符号中等大小整数Elf32_Off44无符号文件偏移Elf32_Sword44有符号整数Elf32_Word44无符号大整数unsigned char11无符号小整数


2、静态链接和动态链接

2.1 静态链接
        静态链接在程序的编译期完成的链接。
        静态链接的ELF可执行文件与进程的地址空间,ELF头文件地址:0x08048000
        程序的实际入口:Entry point address:0x08048300;可执行文件加载带内存中开始执行的第一行代码。一般静态链接会将所有代码放在一个代码段。
2.2 动态链接
        动态链接在程序的运行期完成的链接。
        动态链接分为可执行程序装载时动态链接和运行时动态链接。

3、实验过程:编程使用exec*库函数加载一个可执行文件

3.1实验要求

        使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证对Linux系统加载可执行程序所需处理过程的理解,详细内容参考本周第三节;推荐在实验楼Linux虚拟机环境下完成实验。

3.2 实验过程

    3.2.1 打开实验楼虚拟机环境,进入LinuxKernel文件夹,然后重新下载menu文件:

          

    3.2.2 使用qemu命令进入跟踪调试环境:

         

    3.2.3 设置断点:sys_execve,load_elf_binary,start_thread 

        

    3.2.4 执行程序

        

    3.2.5 进入sys_execve系统调用

        

    3.2.6  单步执行sys_execve系统调用的指令

       

    3.2.7 执行start_thread函数,这里的new_ip是返回到用户态的第一条指令的地址

        

    3.2.8 在这里我们通过readelf命令,可以看到可执行文件hello的第一条指令地址就是:0x8048d0a

        

4、实验分析

(1)内核是如何支持多种不同可执行文件格式的?
         Load_elf_binary->start-thread中:调用这个函数是实现修改内核堆栈中EIP的值作为新程序的起点。New_id是通过start_thread函数中第二个参数elf_entry来传递。
(2)命令行参数和环境变量是如何保存和传递到新程序堆栈的?
        新创建一个用户态堆栈的时候,实际上是把命令行参数的内容和环境变量的内容通过指针的方式传递到系统调用内核处理函数,然后内核处理函数创建出一个新的用户态堆栈的时候,会把参数和变量拷贝到用户态堆栈中。
先函数调用参数传递,再系统调用参数传递。如果仅仅是加载一个静态链接的可执行程序的话,我们只需要传递一个命令行参数和环境变量即可。但对于大多数程序来说,需要加载动态链接。
(3)为什么execve系统调用返回后新的可执行程序能顺利执行?
        Execve系统调用过程也是很特殊的系统调用过程。子进程是从ret_from_fork开始执行然后返回用户态。
当执行到execve系统调用的时候陷入内核态,在内核里面,sys_execve函数会利用execve加载的可执行文件把当前进程的可执行程序给覆盖掉,系统调用返回的时候,返回的已经不是原来的可执行程序了,而是新的可执行程序的起始位置(一般是新可执行程序的main()函数处)。
(4)对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
        sys_execve系统调用的处理过程
        do_execve(getname(filename),argv,envp)//getname是传递文件名,argv,envp是传递环境变量。把环境变量转化为结构之后,再调用do_execve_common(filename,argv,envp)函数。

5、总结:“Linux内核装载和启动一个可执行程序”的理解

        Linux内核装载一个可执行程序:首先创建新进程,该进程通过execve()系统调用执行指定的ELF文件,再调用execve()系统调用对应的内核的入口函数sys_execve(),sys_execve()服务例程修改当前进程的执行上下文

        上述步骤完成后,该进程开始执行可执行文件代码。当ELF被load_elf_binary()装载完成后,函数返回至do_execve()在返回至sys_execve()。ELF可执行文件的入口点取决于程序的链接方式,对于静态链接的可执行文件,若是静态链接的,elf_entry就是指向可执行文件里边规定的那个头部,即main函数对应的位置,若这个可执行文件是需要依赖其它动态链接库的话,则elf_entry就是指向动态链接器的起点。



参考资料:

              http://baike.baidu.com/link?url=HCC0EFQk-PFws3q_PjRTMUblzoIFLE-M5CXW3BG6jGEXD4NqI3_gkTvNY6C2NfVfhXJIxYiVjmmr4Pgm4LkDwKrXnThq-zMUxJIL_vb3Vda

0 0
原创粉丝点击