陈民禾——原创做品转载请注明出处—— 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000编辑器
一.上周内容总结复习函数
上一周学习了Linux 如何存放和表示进程(用task_ struct 和thread_info ),如何建立进程(经过fork(),实际上最终是clone()),如何把新的执行映像装入到地址空间(经过execO 系统调用族〉,如何表示进程的层次关系,父进程又是如何收集其后代的信息(经过wait()系统调用族),以及进程最终如何消亡〈强制或自愿地调用exit()) 。学习
进程的状态大体以下图所示spa
二.几个重要概念3d
可执行程序:可执行程序以C语言代码为例,通过编译器的预处理,处理完以后把它编译成汇编代码,而后有个汇编器将它编译成汇编代码,而后,将其连接成可执行文件。调试
目标文件的格式ELF,常见的目标文件格式:A.out COFF后来发展为PE和ELF,目标文件也常常叫作ABI ,也就是应用程序二进制接口,实际上在二进制兼容的格式这个目标文件已经适应了某种CPU体系结构上的二进制指令,好比说一个32位X86文件链接成arm可执行文件是不能够的,在ELF文件中有三种可执行文件,可重定位文件:保存着代码和适当的数据,用来和其余的object文件一块儿建立一个可执行文件或者是一个共享文件。可执行文件:保存着一个用来执行的程序,该文件指出了exec如何来建立程序进程映像共享object文件:保存着代码和合适的数据,用来被下面两个连接器链接,一个是链接编辑器,能够和其余的可重定位和共享object文件来建立其余的object;第二个是动态连接器,联合一个可执行文件和其余共享的object文件来建立一个进程映像ELF目标文件格式:code
object文件参与程序的联接(建立一个程序)和程序的执行(运行一个程序),orm
动态可执行文件:它要依赖这个可执行程序,须要其余的动态连接库,这个动态连接库,某一个点它也要依赖其余的动态连接库,动态连接库的动态连接库,动态连接库包括可执行文件,实际上动态连接库的依赖关系会造成一个图,ELF格式的文件,假如说都是同样的,就会对ELF文件进行解析,看它依赖了哪些动态连接库,这样它就会加载。blog
三.重要知识和过程接口
可执行文件产生过程:好比咱们以一个hello world程序为例,咱们能够把.c文件作预处理
可执行文件和进程的地址空间:当一个可执行文件ELF加载到内存的时候,它是怎么加载的呢,咱们加载的效果知道,把代码的数据加载到一块内存中来,把数据加载到内存中来,固然代码有不少块代码,不少代码段,加载进来以后默认elf加载到0x8048000从这个位置开始加载,那么加载以后可能以前是一个ELF头部文件的信息,通常来说,这个头部大小的文件信息可能就是会有不一样,因此加载时的入口点的位置可能不一样,这个地方就是程序的实际入口,当启动一个新的程序的时候,它就是从这个地方开始执行,加载到启动一个新的进程,启动一个刚加载过可执行文件的进程,一个新的进程只是fork了原来的一份,它的执行位置仍是执行了原来那个进程的位置,加载了新的可执行文件以后,开始执行的入口点,这个是一个静态连接的ELF可执行文件,这个时候都已经帮咱们连接好了,从这里开始一个文件一个文件的开始执行,怎么压栈出栈,怎么来操做,能把整个程序执行完,也就是从main函数到main函数执行完毕。
装载可执行程序以前的工做:咱们通常是经过share程序来执行一个可执行程序,当咱们装载一个可执行程序,也就是咱们发起一个系统调用execve,咱们还须要准备哪些,这个share环境为咱们准备了哪些可执行的上下文环境,这样咱们就大概在用户态的执行文件大概了解一下,而后咱们看一下一个execve,它怎么把一个可执行文件在内核里面装载起来,又返回到用户态。
四.实验过程截图及分析
打开窗口加载qemu,克隆新版本
查看makefile的代码
查看关键代码:父子进程
冻结窗口开始进行调试:
使用gdb设置断点,能够看到分别在sys_execve和load_elf_binary处设置断点
查看附近的代码:给新栈的赋值。
执行到start_thread的时候有一个问题:
new ip究竟是指向哪里的?
用po(print object)指令:
po new_ip 能够看到一个地址:0x80495ba
readelf -h hello 找到hello这个可执行程序的入口地址。 这是一个静态编译的可执行文件。
new ip是返回用户态的第一条指令的地址。
五.学习本周知识的总结
用一个比较形象的比喻就是实际上咱们把原来的可执行程序,也就是share可执行程序,int 0x80进入到这个execve的系统调用入睡,当他入睡的时候加载到一个新的可执行程序,加载到新的可执行程序,return 返回以后,也就是它醒来了,蝴蝶执行了在蝴蝶内部的程序,它若是加载庄子,这二者老是想相对的,但都是同一进程,只是把进程里面的可执行程序给替换掉了,这就是咱们对进程如何加载和运行的一个基本的描述。