Linux内核分析第七周总结
第七章 可执行程序的装载
可执行程序的生成
可执行程序的生成:
c语言代码--->经过编译器的预处理--->编译成汇编代码--->由汇编器编译成目标代码--->链接成可执行文件
预处理负责把include的文件包含进来及宏替换等工作
以HelloWorld.c文件作为例子:
目标文件的格式
目标文件:
- 以".o"作为后缀的文件
- 可执行文件
常用的目标文件格式:
PE文件:Windos操作系统
ELF文件:Linux操作系统(可执行,可链接)
以ELF文件为例:(目标文件)
- 可重定位文件(.o文件)
- 可执行文件
- 共享目标文件
静态链接的ELF可执行文件与进程的地址空间
默认从0x8048000处开始加载
可执行文件加载到内存中开始执行的第一行代码
一般静态链接会将所有代码放在一个代码段
动态链接的进程会有多个代码段
装载可执行程序之前的工作
可执行程序的执行环境
命令行参数:
- shell命令行
- main函数的参数
- execve的参数
命令行参数和环境串都放在用户态堆栈中
在创建一个新的用户态堆栈的时候,实际上是把命令行参数的内容和环境变量的内容通过指针的方式传递到系统调用的内核处理函数的,内核处理函数在创建一个新的可执行堆栈的时候会将命令行参数的内容和环境变量的内容拷贝到用户态堆栈里面来初始化新的可执行程序执行的上下文环境
shell程序 -> execve -> sys_execve
先函数调用参数传递,在系统调用参数传递
装载时动态链接和运行时动态链接应用举例
动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。
- 准备.so文件
- 编译成libshlibexample.so文件
- 编译成libdllibexample.so文件
- 分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件
- 编译main
可执行程序的装载
- 可执行程序的装载相关关键问题分析
sys_execve内部会解析可执行文件格式
do_execve -> do_execve_common -> exec_binprm
sys_execve的内部处理过程
装载和启动一个可执行程序依次调用以下函数:
sys_execve() -> do_execve() -> do_execve_common() -> exec_binprm() -> search_binary_handler() -> load_elf_binary() -> start_thread()
实验
总结:
当前进程的正文、数据、堆和栈段被exec覆盖了,当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。
因为调用exec并不创建新进程,所以前后的进程ID并未改变。