2019-2020-1 20199306《Linux内核原理与分析》第八周作业

Linux内核如何装载和启动一个可执行程序

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

ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。它自最早在 System V 系统上出现后,被 xNIX 世界所广泛接受,作为缺省的二进制文件格式来使用。
所谓对象文件(Object files)有三个种类:

1) 可重定位的对象文件(Relocatable file)

这是由汇编器汇编生成的 .o 文件。后面的链接器(link editor)拿一个或一些 Relocatable object files 作为输入,经链接处理后,生成一个可执行的对象文件 (Executable file) 或者一个可被共享的对象文件(Shared object file)。我们可以使用 ar 工具将众多的 .o Relocatable object files 归档(archive)成 .a 静态库文件。

2) 可执行的对象文件(Executable file)

文本编辑器vi、调式用的工具gdb、播放mp3歌曲的软件mplayer等等都是Executable object file。

3) 可被共享的对象文件(Shared object file)

这些就是所谓的动态库文件,也即 .so 文件。如果拿前面的静态库来生成可执行程序,那每个生成的可执行程序中都会有一份库代码的拷贝。如果在磁盘中存储这些可执行程序,那就会占用额外的磁盘空间;另外如果拿它们放到Linux系统上一起运行,也会浪费掉宝贵的物理内存。如果将静态库换成动态库,那么这些问题都不会出现。动态库在发挥作用的过程中,必须经过两个步骤:

  • 链接编辑器(link editor)拿它和其他Relocatable object file以及其他shared object file作为输入,经链接处理后,生存另外的 shared object file 或者 executable file。

  • 在运行时,动态链接器(dynamic linker)拿它和一个Executable file以及另外一些 Shared object file 来一起处理,在Linux系统里面创建一个进程映像。

ELF文件由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。实际上,一个文件中不一定包含全部内容,而且他们的位置也未必如同所示这样安排,只有ELF头的位置是固定的,其余各部分的位置、大小等信息有ELF头中的各项值来决定。

ELF文件:ELF(Excutable and Linking Format)是一个文件格式的标准。通过readelf-h hello查看可执行文件hello的头部(-a查看全部信息,-h只查看头部信息),头部里面注明了目标文件类型ELF32。Entry point address是程序入口,地址为0x400440

exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件,如果不是可以执行的文件,那么就解释成为一个shell文件,shell执行。

实验:使用gdb跟踪分析一个execve系统调用内核处理函数

  • 更新menu内核
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第1张图片
  • 查看test.c文件,可以看到新增加了exec系统调用
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第2张图片
  • 启动内核并验证execv函数
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第3张图片
  • 启动GDB调试
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第4张图片
  • 停在sys_execve处,再设置其它断点;按c一路运行下去直到断点sys_execve
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第5张图片
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第6张图片
  • 退出调试状态,输入readelf -h hello可以查看hello的EIF头部
    2019-2020-1 20199306《Linux内核原理与分析》第八周作业_第7张图片

总结

当Linux内核或程序使用fork函数创建子进程后,子进程往往要调用一种exec函数(exec家族的一种)以执行另一个程序;在调用一种exec函数时,该进程执行的程序完全被替换为新程序,而新程序则从其main函数处开始执行,因为调用exec函数并不创建新进程,所以前后的进程ID并未改变,或者说exec函数只是用了一个全新的程序替换了当前进程的正文、数据段和堆栈段。

你可能感兴趣的:(2019-2020-1 20199306《Linux内核原理与分析》第八周作业)