ID:fuchen1994
实验要求:
理解编译链接的过程和ELF可执行文件格式,详细内容参考本周第一节;
编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式,详细内容参考本周第二节;
使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解,详细内容参考本周第三节;推荐在实验楼Linux虚拟机环境下完成实验。
特别关注新的可执行程序是从哪里开始执行的?为什么execve系统调用返回后新的可执行程序能顺利执行?对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
实验过程:
1.编译链接的过程和ELF可执行文件格式:
这里有一个GCC的使用说明:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2287738.html
编译链接的过程:
C语言代码-->编译器预处理-->编译成汇编代码-->汇编器编译成目标代码-->链接成可执行文件,再由操作系统加载到内存中执行
(1)预处理.cpp:负责把include的文件包含进来及宏替换等工作。
gcc -E -o hello.cpp hello.c -m32
(2)编译成汇编代码.s:gcc -x cpp-output -S -o hello.s hello.cpp -m32
(3)编译成目标代码.o:gcc -x assembler -c hello.s -o hello.o -m32
hello.o中是二进制的文件,有机器指令。
(4)链接成可执行文件:gcc -o hello hello.o -m32
ELF的可执行文件格式:
(1)格式的发展:
PE在Windows系统,ELF在Linux系统。
(2)ELF:Executable And Linkable Format
目标文件也叫ABI---应用程序二进制接口,在目标文件中已经是二进制兼容的格式,目标文件已经是适应到某一种CPU体系结构上的二进制指令。
(3)ELF中的三种目标文件
Object文件参与程序的链接(创建一个程序)和程序的执行(运行一个程序):
入口地址Entry point address:程序的起点。
(4)当创建或增加一个进程映像的时候,系统在理论上将拷贝一个文件的段到一个虚拟的内存段。
3、静态链接的ELF可执行文件与进程的地址空间
(1)ELF可执行文件加载到内存时默认地址是0x8048000;其前面一般是ELF文件头部的信息,大小可能不同,入口点的位置0x8048x00,这里是程序的实际入口,是可执行文件加载到内存中开始执行的第一行代码。
(2)一般静态链接会将所有代码放在一个代码段。
动态链接的进程会有多个代码段。
3.实验过程
本宝宝不开心了,无法下载到相应代码,所以这个部分暂时略过
新的可执行程序是从哪里开始执行的?
新的可执行程序通过修改内核堆栈eip作为新程序的起点,从new_ip开始执行后start_thread把返回到用户态的位置从int 0x80的下一条指令变成新加载的可执行文件的入口位置。
为什么execve系统调用返回后新的可执行程序能顺利执行?
当执行到execve系统调用时,进入内核态,用execve()加载的可执行文件覆盖当前进程的可执行程序,当execve系统调用返回时,返回新的可执行程序的执行起点(main函数),所以execve系统调用返回后新的可执行程序能顺利执行。
对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
execve系统调用返回时,如果是静态链接,elf_entry指向可执行文件规定的头部(main函数对应的位置0x8048***);如果需要依赖动态链接库,elf_entry指向动态链接器的起点。动态链接主要是由动态链接器ld来完成的。