Linux内核装载和启动一个可执行程序
作业信息
这个作业属于哪个课程 | <2020-2021-1Linux内核原理与分析)> |
---|---|
这个作业要求在哪里 | <2020-2021-1Linux内核原理与分析第八周作业> |
这个作业的目标 | 跟踪分析一个execve系统调用内核处理函数、了解ELF文件格式 |
作业正文 | https://www.cnblogs.com/TracerElena/p/14046804.html |
跟踪分析一个execve系统调用内核处理函数
cd ~/LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs
MenuOS运行效果如下,可以看到已经增加了一条exec命令。
cd ..
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
在shell2中进行gdb调试:
gdb
file linux-3.18.6/vmlinux
target remote:1234
在sys_execve和load_elf_binary处设置断点
b sys_execve
b load_elf_binary
退出调试之后,查看elf文件头
readelf -h hello
ELF文件格式
ELF (Executable and Linkable Format)即可执行的和可链接的格式,是一个目标文件格式的标准。ELF格式的文件用于存储Linux程序。ELF是一种对象文件的格式,用于定义不同类型的对象文件中都有什么内容、以什么样的格式放这些内容。ELF首部会描绘整个文件的组织结构,它还包括很多节(sections,是在ELF文件里用以装载内容数据的最小容器),这些节有些是系统定义好的,有些是用户在文件中通过。section命令自定义的,链接器会将多个输入目标文件中相同的节合并。
ELF文件的3种类型:
- 可重定位文件:这种一般是中间文件,还需要继续处理。由汇编器和编译器创建,一个源代码文件会生成一个可重定位文件。文件中保存着代码和适当的数据,用来和其他的目标文件一起来创建一个可执行文件、静态库文件或者共享目标文件(即动态库文件)。
- 可执行文件:一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析(除了运行时解析的共享库符号)的文件,文件中保存着一个用来执行的程序。
- 共享目标文件:共享库,是指可以被可执行文件或其他库文件使用的目标文件,例如标准C的库文件libc.so。可以简单理解为没有主函数main的“可执行”文件,只有一堆函数可供其他可执行文件调用。
问题与总结
1. 新的可执行程序是从哪里开始执行的?
- 新的可执行程序起点的一般地址为0x8048xxx的位置,由编译器设定,出于安全上的考虑并不严格固定。
2. 为什么execve系统调用返回后新的可执行程序能顺利执行?
- 在创建一个新的用户态堆栈时,通过指针将命令行参数内容和环境变量内容传递到系统调用内核处理函数,内核处理函数在创建一个新的可执行程序的用户态堆栈时将参数拷贝到用户态堆栈,以此来初始化新的可执行程序的上下文环境。
3. 静态链接和动态链接有什么不同?
-
静态链接:在编译链接时直接将需要的执行代码复制到最终可执行文件中,优点是代码的装载速度快,执行速度也比较快,对外部环境依赖度低。编译时它会把需要的所有代码都链接进去,应用程序相对比较大。缺点是如果多个应用程序使用同一库函数,会被装载多次,浪费内存。
-
动态链接:在编译时不直接复制可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统。操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库去执行代码,最终达到运行时链接的目的。
总结:内核处理可执行程序的装载过程,实际上是执行程序装载的一个系统调用。fork在陷入内核态之后有两次返回,第一次返回到原来的父进程的位置继续向下执行;第二次子进程返回到rer_from_fork后正常返回到用户态。execve在执行时陷入内核态,用execve中加载的程序把当前正在执行的进程覆盖掉,当系统调用返回时也就返回到新的可执行程序起点。