如何装载和启动一个程序?
ELF文件格式:
如何启动一个程序呢?在上次的实验中便已经提到程序只有装载到内存中,才能被操作系统唤醒,真正运行起来。程序是静态的,进程是动态的,程序要跑起来,必须加载到内存。但是,要分析程序是怎么装载和运行起来的,首先我们必须得到一个程序,我们必须知道程序这个可执行二进制文件是怎么得到的。
1. 程序编译链接过程及ELF可执行文件格式
程序的编译链接过程:
gcc -E -o hello.cpp hello.c -m32 /* 预处理 */
gcc -x cpp-output -S -o hello.s hello.cpp -m32 /* 编译成汇编语言 */
gcc -x assembler -c hello.s -o hello.o -m32 /* 生成目标文件hello.o */
gcc -o hello hello.o -m32 /* 链接生成hello可执行二进制文件 */
生成的hello可执行二进制文件的格式是
ELF(Executable and Linkable Format)。我们可以用readelf -h hello命令来查看ELF文件的头部信息,如下图
2. 动态链接
在生成二进制可执行程序的过程中,需要经过编译、链接过程。动态链接即是生成的二进制程序通过加载一些库来实现其自身运行时所需要的功能。
动态链接分为可执行程序装载时动态链接和运行时动态链接。
3. gdb调试分析 execve 系统调用内核处理函数 sys_execve,加载可执行程序过程
大致流程:Shell 命令行环境输入我们要运行的程序名称,参数;
Shell会调用 execve,将命令行参数和环境参数传递给可执行程序的main函数;execve 系统调用所对应的系统调用服务例程 sys_execve 中将会解析 ELF 文件的格式;do_execve -> do_execve_common -> exec_binprm
经过仔细阅读代码,装载和启动程序的主要流程如下:
特别关注新的可执行程序是从哪里开始执行的?为什么execve系统调用返回后新的可执行程序能顺利执行?对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
4. 总结
Linux 中程序的装载是通过 execve 这个系统调用实现的。execve系统调用内部会把用户所要的程序装载如内存,然后设置好程序运行的初始位置,之后程序便能成功运行起来了。
陈金雷 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000