Linux内核分析实验七

来源:互联网 发布:网络监控软件 编辑:程序博客网 时间:2024/04/29 16:09

-------------------------------------------------------------------------

刘旸 + 原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

-------------------------------------------------------------------------

基础知识:

1. 可执行程序是怎么得来的:

     

 

2. 目标文件的格式ELF

  三种:可重定位目标文件、共享目标文件、可执行目标文件

  一个可重定位文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者是一个共享文件。

  一个可执行文件保存着一个用来执行的程序;该文件指出了exec(BA_OS)如何来创建程序进程映象。

  一个共享object文件保存着代码和合适的数据,用来被下面的两个链接器链接。第一个是连接编辑器[请参看ld(SD_CMD)],可以和其他的可重定位和共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来创建一个进程映象。

 

3. 可执行程序的装载

  execvefork是比较特殊的系统调用,execve用它加载的可执行文件把当前的进程覆盖掉,返回之后就不是原来的程序而是新的可执行程序起点。

  sys_execve内部会解析可执行文件格式:do_execve -> do_execve_common -> exec_binprmearch_binary_handler符合寻找文件格式对应的解析模块。

  ELF可执行文件默认映射到0x8048000这个地址,需要动态链接的可执行文件先加载连接器ld,否则直接把elf文件entry地址赋值给entry即可。start_thread(regs, elf_entry, bprm->p)会将CPU控制权交给ld来加载依赖库并完成动态链接;对于静态链接的文件elf_entry是新程序执行的起点。

 

下面我们通过实验来验证上述的过程:

1. 首先更新menu文件夹。


2. 查看更新后的menu文件夹,发现多了一个test_exec.c文件和一个hello.c文件:


3. 查看test_exec.c的代码,发现相较test.c,加入了exec命令:


4. 再查看hello.c的代码,发现其目的是为了打印hello world:


5. 用test_exec.c文件替换掉原来的test.c文件。


6. 查看Makefile文件内容:


7. 使用make rootfs命令将MenuOS运行起来:


8. 在MenuOS中键入help,发现新添加了exec命令;键入exec命令,效果如下:


9. 使用qemu命令重新编译运行MenuOS。


10. 分割出一个窗口,使用gdb的一系列命令调试MenuOS。断点设置如下:


11. continue到可以在MenuOS中键入命令;键入命令exec,可以看到程序停在了sys_exec处:


12. 使用s命令进入sys_exec中,跟踪它的行为。


13. continue至第三个断点处。

         可以看到start_thread函数将会修改ip和sp


14. 查看new_ip的地址:


15. 使用readelf -h hello命令查看可执行文件hello的elf文件:

         可以看到hello的入口地址就是上面new_ip的地址。


分析与总结:

    新的可执行程序通过修改内核堆栈eip作为新程序的起点,从new_ip开始执行后start_thread把返回到用户态的位置从int 0x80的下一条指令变成新加载的可执行文件的入口位置。

    当执行到execve系统调用时,进入内核态,用execve()加载的可执行文件覆盖当前进程的可执行程序,当execve系统调用返回时,返回新的可执行程序的执行起点(main函数),所以execve系统调用返回后新的可执行程序能顺利执行。

    execve系统调用返回时,如果是静态链接,elf_entry指向可执行文件规定的头部(main函数对应的位置0x8048***);如果需要依赖动态链接库,elf_entry指向动态链接器的起点。动态链接主要是由动态链接器ld来完成的。


附上sys_execve系统调用过程的简易示意图:

1 0
原创粉丝点击