Linux可执行程序的编译、装载与启动过程简析

原创作品转载请注明出处 ,《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-100002900

一、编译链接过程分解

1、下面是hello world代码

2、预处理

 3、生成汇编代码

 4、生成二进制文件

 5、链接生成可执行文件

 最后我们来看一下,两个二进制文件的差别:

 很明显,tmp.o 只是一个可重定位的二进制文件,而 tmp.out 才是真正的可执行文件。

下面是 readelf -h 的返回结果。如果用 readelf -d查看文件的依赖,那么 tmp.o 是没有任何依赖的,相反 tmp.out 则依赖了很多系统链接库。

(你可能需要向右拖动滚动条才能看到全部内容。)

 

二、在代码中使用动态链接和静态链接

这里直接贴出示例代码中的核心部分,版权信息有所删减。

1、动态链接库代码

 2、静态链接库代码

 3、主函数部分

4、编译运行

 

三、相关内核代码注解

1、sys_execve()系统调用,这里不必多言。

 2、do_execve()

 3、do_execve_common()

 4、exec_binprm()

 5、 search_binary_handler()

 6、load_elf_binary()相关代码

 

四、GDB实际调试过程

1、编译生成新的rootfs

 2、启动虚拟机

 3、启动gdb开始调试

 4、部分调试过程摘录

(完整调试过程记录 gdb )

 

五、个人小结

        相较于上周的fork调用分析,这次对于execve的分析似乎不是那么“痛苦”,感觉还是挺顺利的。(也许是因为上次那个task_struct结构体实在是太恐怖了。。。)

        那么现在来谈一谈个人对于“Linux内核装载、启动可执行程序”的理解。

        首先,用户态程序通过sys_execve()系统调用陷入内核,同时也传递了待运行的可执行文件的相关参数。然后内核开始为可执行文件准备环境,包括选择装载模块、分配内核空间、进程描述符和内存等工作。然后通过修改内核的EIP,使其指向新程序的起始地址,退出内核态,转交cpu控制权给处于用户态的新进程,也就是新进程“醒来了”。而之前“创造”该进程的父进程却处于“睡眠”状态,也就是老师所谓的“庄周梦蝶”。

        好了,大概就说这么多了,该睡觉了了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注