The Proccess of Loading and Executing a Specific Program in Linux Kernel
来源:互联网 发布:淘宝客日赚 编辑:程序博客网 时间:2024/06/06 14:00
Chapter 1 Environment
Ubuntu 14.10
Linux Kernel 3.18.6
第二章 调试
Chapter 2 Debug
What we need to pay attention is that we shouldn't set breakpoint when the kernel start. Otherwise, it will be extremely hard to start.
Breakpoints:
sys_execv
load_elf_binary
第三章 分析
主要是以下的代码:
binfmt_elf.c和exec.c
先分析一个原始的可执行文件:a.out。
其数据结构为:参考文献:http://blog.chinaunix.net/uid-11469366-id-1747286.html
struct exec { unsigned long a_midmag; /* 魔数和其它信息 */ unsigned long a_text; /* 文本段的长度 */ unsigned long a_data; /* 数据段的长度 */ unsigned long a_bss; /* BSS段的长度 */ unsigned long a_syms; /* 符号表的长度 */ unsigned long a_entry; /* 程序进入点 */ unsigned long a_trsize; /* 文本重定位表的长度 */ unsigned long a_drsize; /* 数据重定位表的长度 */};
魔数:通过文件头的前几个数来判断这个文件的类型。
在do_execve中真正地实现了对程序的执行。这个函数定义了一个名为linux_binprm的结构体来存储所要运行进程的信息。
struct linux_binprm{ char buf[BINPRM_BUF_SIZE]; //保存可执行文件的头128字节 struct page *page[MAX_ARG_PAGES]; struct mm_struct *mm; unsigned long p; //当前内存页最高地址 int sh_bang; struct file * file; //要执行的文件 int e_uid, e_gid; //要执行的进程的有效用户ID和有效组ID kernel_cap_t cap_inheritable, cap_permitted, cap_effective; void *security; int argc, envc; //命令行参数和环境变量数目 char * filename; //要执行的文件的名称 char * interp; //要执行的文件的真实名称,通常和filename相同 unsigned interp_flags; unsigned interp_data; unsigned long loader, exec;};
然后用do_open_exec()来打开文件,加载文件头部,把环境变量和参数调入至调用函数中。list_for_each_entry()尝试寻找可以解析当前可执行文件的代码。实际上调用的是load_elf_binary。
load_elf_binary:
加载elf类型文件的handler是load_elf_binary(),它先读入ELF文件的头部,根据ELF文件的头部信息读入各种数据(header information)。再次扫描程序段描述表,找到类型为PT_LOAD的段,将其映射(elf_map())到内存的固定地址上。如果没有动态链接器的描述段,把返回的入口地址设置成应用程序入口。完成这个功能的是start_thread(),start_thread()并不启动一个线程,而只是用来修改了pt_regs中保存的PC等寄存器的值,使其指向加载的应用程序的入口。这样当内核操作结束,返回用户态的时候,接下来执行的就是应用程序了。
参考资料:http://www.cnblogs.com/li-hao/archive/2011/09/24/2189504.html
如果是要使用动态链接的话,则要将连接器ld先加载进来,就是调用load_elf_interp()函数。
load_elf_interp()
如果应用程序中使用了动态链接库,就没有那么简单了,内核除了加载指定的可执行文件,还要把控制权交给动态连接器(program interpreter,ld.so in linux)以处理动态链接的程序。内核搜寻段表,找到标记为PT_INTERP的段中所对应的动态连接器的名称,并使用load_elf_interp()加载其映像,并把返回的入口地址设置成load_elf_interp()的返回值,即动态链接器入口。当execve退出的时候动态链接器接着运行。动态连接器检查应用程序对共享连接库的依赖性,并在需要时对其进行加载,对程序的外部引用进行重定位。然后动态连接器把控制权交给应用程序,从ELF文件头部中定义的程序进入点开始执行。(比如test.c中使用了userlib.so中函数foo(),在编译的时候这个信息被放进了test这个ELF文件中,相应的语句也变成了call fakefoo()。当加载test的时候,知道foo()是一个外部调用,于是求助于动态链接器,加载userlib.so,解析foo()函数地址,然后让fakefoo()重定向到foo(),这样call foo()就成功了。)
参考资料:http://www.cnblogs.com/li-hao/archive/2011/09/24/2189504.html
CPU将控制权交给ld来对环境变量中的依赖库进行广度优先或深度优先的检索,来进行动态链接。最后加载程序。
Chapter 4 Conclusion
sys_execve可以让程序链接的时候选择动态编译还是静态编译。在静态编译下,申请的地址空间往往是静态的,而且是连续的。而动态编译的情况下,是一块一块不连续的内存段。这也就印证了操作系统原理的内容,就是段式管理和页式管理。
从do_execve中开始,系统先对程序文件和路径进行记录,然后通过通过load_elf_binary对文件进行连接,加载一些依赖的库和检测系统参数。最终记录并返回eip的内存地址,产生新的线程让程序运行。
在学数据结构时,一直质疑这些内容对以后的编程是否能帮助。Linux内核分析使我明白:广度优先算法在分析依赖库上十分有帮助,可以快速检索所需要的库,而且不会出错。并且也深刻理解了离散数学对图的分析。
记得在寒假,我在使用《Unix网络环境编程》时,曾经十分深刻地接触了.so文件的生成。当时在调试有关环境时,生成了.so文件却不知道它的作用。唯一感觉得到的便是,很多自定义命令不再提示未定义。却没想到后面还有很多内容。
Appendix
Luxuan + Writen by the author, Please let me know if you want to take it as a reference + Linux Kernel Analyzation a course of MOOC website:http://mooc.study.163.com/course/USTC-1000029000
- The Proccess of Loading and Executing a Specific Program in Linux Kernel
- 4 Ways of Executing a Shell Script in UNIX / Linux
- 7 Strace Examples to Debug the Execution of a Program in Linux
- 7 Strace Examples to Debug the Execution of a Program in Linux
- Where to download Linux Kernel source code of a specific version?
- The Program of Algorithms ------- Diveide and Conquer ---- Powering a number
- Linux kernel 2.6.X, a method that repace of the default logo in Ubuntu 10.04
- Identify in details the consumption of memory from a specific session
- Three case of kernel loading in SkyEye
- Please change the value of 'Security.salt' in app/config/core.php to a salt value specific to your a
- The Detailed explanation of __setup macro in linux kernel
- The Detailed explanation of __initdata macro in linux kernel
- Abuse of the Linux Kernel for Fun and Profit
- Basic Data Structures and Algorithms in the Linux kernel
- Basic Data Structures and Algorithms in the Linux Kernel
- Basic Data Structures and Algorithms in the Linux Kernel--reference
- unable to find the sources of your current Linux kernel. Specify KERN_DIR=<directory> and run Make a
- Add a system call to the linux kernel in Ubuntu
- 转载:HDFS小文件问题及解决方案
- Single Number---leetcode c# solution
- 转载:Hadoop Streaming 编程
- maven教程初稿
- Linux装载和执行可执行程序的分析
- The Proccess of Loading and Executing a Specific Program in Linux Kernel
- 二分查找算法实例注释
- Linux下vim配置文件
- (others)TCP协议的实现
- TCP/IP,HTTP,SOCKET的区别
- Unity3D手机中Input类touch详解
- TCP实现1
- 网络通信协议的实现
- 在vim和macvim中使用中文帮助文档!