郑卓彬 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
1.预处理、编译、链接和目标文件的格式
(1)预处理、编译和链接
shiyanlou:~/ $ cd Code
shiyanlou:Code/ $ vi hello.c
shiyanlou:Code/ $ gcc -E -o hello.cpp hello.c -m32 #预处理
shiyanlou:Code/ $ vi hello.cpp
shiyanlou:Code/ $ gcc -x cpp-output -S -o hello.s hello.cpp -m32 #编译
shiyanlou:Code/ $ vi hello.s
shiyanlou:Code/ $ gcc -x assembler -c hello.s -o hello.o -m32 #汇编
shiyanlou:Code/ $ vi hello.o
shiyanlou:Code/ $ gcc -o hello hello.o -m32 #动态链接
shiyanlou:Code/ $ vi hello
shiyanlou:Code/ $ gcc -o hello.static hello.o -m32 -static #静态链接
shiyanlou:Code/ $ ls -l
(2)ELF( ELF: 可执行连接格式 )中的三种目标文件:
- 一个可重定位文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者一个共享文件。(主要是.o文件 )
- 一个可执行文件保存着一个用来执行的程序;该文件指出了exec如何来创建程序进程映像。
一个共享object(目标)文件保存着代码和合适的数据,用来被下面的两个链接器链接。第一个是链接编辑器,可以和其他的可重定位和共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来文件来创建一个进程映像。
ELF文件格式:
2.编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式
图一 main.c函数
图二 test.c函数
图三 动态连接
图四 执行结果
3.使用gdb跟踪sys_execve内核函数的处理过程
总结:
1、可执行程序的产生:
C语言代码–>编译器预处理–>编译成汇编代码–>汇编器编译成目标代码–>链接成可执行文件,再由操作系统加载到内存中执行。
2、ELF格式中主要有3种可执行文件:可重定位文件.o,可执行文件,共享目标文件。
3、ELF可执行文件会被默认映射到0x8048000这个地址。
4、命令行参数和环境变量是如何进入新程序的堆栈的?
Shell程序–>execve–>sys_execve,然后在初始化新程序堆栈时拷贝进去。
先函数调用参数传递,再系统调用参数传递。
5、当前程序执行到execve系统调用时陷入内核态,在内核中用execve加载可执行文件,把当前进程的可执行文件覆盖掉,execve系统调用返回到新的可执行程序的起点。
6、动态链接库的装载过程是一个图的遍历过程,
ELF格式中的.interp和.dynamic需要依赖动态链接器来解析,entry返回到用户态时不是返回到可执行程序规定的起点,返回到动态链接器的程序入口。