作业信息
这个作业属于哪个课程 | <2020-2021-1Linux内核原理与分析)> |
---|---|
这个作业要求在哪里 | <2020-2021-1Linux内核原理与分析第八周作业> |
这个作业的目标 | <ELF目标文件,程序编译,静态链接与动态链接,程序装载,使用gdb跟踪分析一个execve系统调用内核处理函数> |
作业正文 | ... 本博客链接 |
可执行程序工作原理
1.ELF目标文件
- ELF文件的三种类型:
(1)可重定位文件:这种文件一般是中间文件,还需要继续处理。由编译器和汇编器创建,一个源代码会生成一个可重定位文件。文件中保存着代码和适当的数据,用来和其他目标文件一起来创建一个可执行文件、静态库文件或者共享目标文件。
(2)可执行文件:一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析的文件。
(3)共享目标文件:共享库,是指被可执行文件或其他库文件使用的目标文件。可以简单理解为没有主函数main的“可执行”文件,只有一堆函数可供其它可执行文件调用。
- ELF文件的作用:
(1)如果用于编译和链接(可重定位文件),则编译器和链接器将把ELF文件看作是节头表描述的节的集合,程序头表可选。
(2)如果用于加载执行(可执行文件),则加载器则将把ELF文件看作是程序头表描述的段的集合,一个段可能包含多个节和节头表可选。
(3)如果是共享文件,则两者都含有。
- ELF文件索引表
2.程序编译
程序从源代码到可执行文件的步骤:预处理,编译,汇编,衔接。以下实例使用hello.c,4步分别对应的指令如下:
-
预处理: gcc -E hello.c -o hello.i
-
编译:gcc -S hello.i -o hello.s -m32
-
汇编:gcc -c hello.s -o hello.o -m32
-
链接:gcc hello.o -o hello -m32 -static
3.静态链接与动态链接
-
链接从过程上讲分为符号解析和重定位两部分;根据链接时机的不同,又分为静态链接和动态链接。
-
重定位是把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程,也就是说在装入时对目标程序中指令和数据的修改过程,它是实现多道程序在内存中同时运行的基础。
-
静态链接:在编译链接时直接将需要的执行代码复制到可执行文件中,优点是代码的装载速度快,执行速度也比较快,对外部环境依赖度低,编译时它会把需要的所有代码都链接进去,应用程序相对比较大。
-
动态链接:在编译时不直接复制可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统。操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库去执行代码,最终达到运行时链接的目的。
4.程序装载
内核处理可执行程序的装载过程,实际上是执行程序装载的一个系统调用,和前面分析的fork及其它的系统调用的主要过程是一样的。但是execve这个系统调用的内核处理过程和fork一样也是比较特殊的。正常的一个系统调用都是陷入内核态,再返回到用户态,然后继续执行系统调用后的下一条指令。fork和其它系统调用不同之处是它在陷入内核态之后有两次返回,第一次返回到原来的父进程的位置继续向下执行,这和其它的系统调用是一样的。在子进程中fork也返回了一次,会返回到一个特殊的点-ret_from_fork,通过内核构造的堆栈环境,它可以正常返回到用户态,所以它稍微特殊一点。同样,execve也比较特殊,当前的可执行程序在执行,执行到execve时陷入内核态,在内核里面用execve加载的可执行文件把当前进程的可执行程序给覆盖掉了。当execve的系统调用返回到,返回的已经不是原来的那个可执行程序了,而是新的可执行程序。execve返回的是新的可执行程序执行的起点。
5.使用gdb跟踪分析一个execve系统调用内核处理函数
将exec添加进MenuOs中
可看到已经将exec命令加入到MenuOs中
启动gdb调试
在sys_execve和load_elf_binary处设置断点
使用readelf -h hello命令查看elf文件头