LINUX内核分析第六周学习总结——进程的描述和进程的创建

张忻(原创作品转载请注明出处)

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

一、知识概要

(一)预处理、编译、链接和目标文件的格式

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

2.目标文件的格式ELF

3.静态链接的ELF可执行文件和进程的地址空间

(二)可执行程序、共享库和动态加载

1.装载可执行程序之前的工作

2.装载时动态链接和运行时动态链接应用举例

(三)可执行程序的装载

1.可执行程序的装载相关关键问题分析

2.sys_execve的内部处理过程

3.使用gdb跟踪sys_execve内核函数的处理过程

4.可执行程序的装载与庄生梦蝶的故事

5.浅析动态链接的可执行程序的装载

二、学习笔记

(一)预处理、编译、链接和目标文件的格式

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

C代码——预处理——汇编代码——目标代码——可执行文件

预处理负责把include的文件包含进来及宏替换工作。

hello和hello.o都是ELF格式的文件。

2.目标文件的格式ELF

(1)A.out    COFF      PE、ELF(Linux中)

(2)ABI——应用程序二进制接口

(3)种类:

  1. 一个可重定位(relocatable)文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者是一个共享文件。
  2. 一个可执行(executable)文件保存着一个用来执行的程序;该文件指出了exec(BA_OS)如何来创建程序进程映象。
  3. 一个共享object文件保存着代码和合适的数据,用来被下面的两个链接器链接。第一个是连接编辑器[请参看ld(SD_CMD)],可以和其他的可重定位和共享object文件来创建其他的object。第二个是动态链接器,联合一个可执行文件和其他的共享object文件来创建一个进程映象。

3.静态链接的ELF可执行文件和进程的地址空间

(1)ELF与Linux进程虚拟空间内存的对应关系如下图:

程序从0x804800开始。

可执行文件加载到内存中开始执行的第一行代码。

一般静态链接将会把所有代码放在同一个代码段。

动态连接的进程会有多个代码段。

(二)可执行程序、共享库和动态加载

1.装载可执行程序之前的工作

(1)命令行参数和shell环境,一般我们执行一个程序的Shell环境,我们的实验直接使用execve系统调用。

  • $ ls -l /usr/bin 列出/usr/bin下的目录信息
  • Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身
    • 例如,int main(int argc, char *argv[])
    • 又如, int main(int argc, char *argv[], char *envp[])
  • Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
    • int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
    • 库函数exec*都是execve的封装例程

(2)命令行参数和环境变量是如何传递和保存的

命令行参数和环境串都放在用户态堆栈中

shell——execv——sys_execv

2.装载时动态链接和运行时动态链接应用举例

动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。

  • 准备.so文件

shlibexample.h (1.3 KB) - Interface of Shared Lib Example 
shlibexample.c (1.2 KB) - Implement of Shared Lib Example

编译成libshlibexample.so文件

$ gcc -shared shlibexample.c -o libshlibexample.so -m32

dllibexample.h (1.3 KB) - Interface of Dynamical Loading Lib Example 
dllibexample.c (1.3 KB) - Implement of Dynamical Loading Lib Example

编译成libdllibexample.so文件

$ gcc -shared dllibexample.c -o libdllibexample.so -m32 #编译方式和上面一样
  • 分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件

main.c (1.9 KB) - Main program 
编译main,注意这里只提供shlibexample的-L(库对应的接口头文件所在目录)和-l(库名,如libshlibexample.so去掉lib和.so的部分),并没有提供dllibexample的相关信息,只是指明了-ldl

$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
$ export LD_LIBRARY_PATH=$PWD #将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。
$ ./main
This is a Main program!
Calling SharedLibApi() function of libshlibexample.so!
This is a shared libary!
Calling DynamicalLoadingLibApi() function of libdllibexample.so!
This is a Dynamical Loading libary!

(三)可执行程序的装载

1.可执行程序的装载相关关键问题分析

sys_execve内部会解析可执行文件格式

  • do_execve -> do_execve_common -> exec_binprm
  • search_binary_handler符合寻找文件格式对应的解析模块,如下:
1369    list_for_each_entry(fmt, &formats, lh) {
1370 if (!try_module_get(fmt->module))
1371 continue;
1372 read_unlock(&binfmt_lock);
1373 bprm->recursion_depth++;
1374 retval = fmt->load_binary(bprm);
1375 read_lock(&binfmt_lock);
  • 对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读
  • Linux内核是如何支持多种不同的可执行文件格式的?
82static struct linux_binfmt elf_format = {
83 .module = THIS_MODULE,
84 .load_binary = load_elf_binary,//函数指针
85 .load_shlib = load_elf_library,
86 .core_dump = elf_core_dump,
87 .min_coredump = ELF_EXEC_PAGESIZE,
88};
2198static int __init init_elf_binfmt(void)
2199{
2200 register_binfmt(&elf_format);#注册
2201 return 0;
2202}
  • elf_format 和 init_elf_binfmt,这里是不是就是观察者模式中的观察者?

2.sys_execve的内部处理过程

装载和启动一个可执行程序依次调用以下函数:

sys_execve() -> do_execve() -> do_execve_common() -> exec_binprm() -> search_binary_handler() -> load_elf_binary() -> start_thread()

3.使用gdb跟踪sys_execve内核函数的处理过程(见课后作业)

4.可执行程序的装载与庄生梦蝶的故事

可执行文件开始执行的起点在哪里?如何才能让execve系统调用返回到用户态时执行新程序?

  • 庄生梦蝶 —— 醒来迷惑是庄周梦见了蝴蝶还是蝴蝶梦见了庄周?

  • 庄周(调用execve的可执行程序)入睡(调用execve陷入内核),醒来(系统调用execve返回用户态)发现自己是蝴蝶(被execve加载的可执行程序)

   ( ̄▽ ̄)" 原来都做梦了,睡眠是个好东东;
睡眠前把sp/ip换掉就进入新的程序,这是我认为的
  • 修改int 0x80压入内核堆栈的EIP

  • load_elf_binary -> start_thread

5.浅析动态链接的可执行程序的装载

(1)可以关注ELF格式中的interp和dynamic。

(2)动态链接库的装载过程是一个图的遍历。

(3)装载和连接之后ld将CPU的控制权交给可执行程序。

三、课后作业

1.理解编译链接的过程和ELF可执行文件格式,详细内容参考本周第一节;

答案见第二部分学习笔记(一)预处理、编译、链接和目标文件的格式

2.编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式,详细内容参考本周第二节;

答案见第二部分学习笔记(二)可执行程序、共享库和动态加载

3.使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解,详细内容参考本周第三节;推荐在实验楼Linux虚拟机环境下完成实验。

程序具体代码如下:

Makefile:

make rootfs:

开始调试:

三次执行到如下界面:

此时执行exec发现执行到的地方如图:

列出执行到的代码:

4.特别关注新的可执行程序是从哪里开始执行的?为什么execve系统调用返回后新的可执行程序能顺利执行?对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?

答案见第二部分学习笔记(三)可执行程序的装载

5.根据本周所学知识分析exec*函数对应的系统调用处理过程,撰写一篇署名博客,并在博客文章中注明“真实姓名(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”

总结部分:阐明自己对“Linux内核装载和启动一个可执行程序”的理解

  • 当linux内核或程序(例如shell)用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序。
  • 当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。
  • 因为调用exec并不创建新进程,所以前后的进程ID并未改变。
  • exec只是用一个全新的程序替换了当前进程的正文、数据、堆和栈段。

LINUX内核分析第七周学习总结——可执行程序的装载的更多相关文章

  1. LINUX内核分析第七周学习总结:可执行程序的装载

    LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  2. LINUX内核分析第七周学习总结

    LINUX内核分析第七周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...

  3. Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序

    Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...

  4. Linux内核分析——第七周学习笔记20135308

    第七周 可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么来的 C代码—>预处理—>汇编代码—>目标代码—>可执行文件 .asm汇编代码 .o目标码 ...

  5. LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程

    LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...

  6. Linux内核分析 第七周 可执行程序的装载

    张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第七 ...

  7. LINUX内核分析第六周学习总结——进程的描述与创建

    LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...

  8. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

  9. LINUX内核分析第八周学习总结

    LINUX内核分析第八周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...

随机推荐

  1. 第3章 Git使用人门

    [初识Github] 首先让我们大家一起喊一句“Hello Github”.YEAH!就是这样. Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理 ...

  2. January 04th, 2018 Week 01st Thursday

    Just do what works for you, because there will always be someone who think differently. 就做你自己所能做的,因为 ...

  3. 17秋 软件工程 团队第五次作业 Alpha Scrum1

    题目:团队作业--Alpha冲刺 17秋 软件工程 团队第五次作业 Alpha Scrum1 各个成员在 Alpha 阶段认领的任务 伟航:督促和监督团队进度,协调组内合作 港晨:APP前端页面编写: ...

  4. 17秋 软件工程 团队第五次作业 Alpha Scrum8

    17秋 软件工程 团队第五次作业 Alpha Scrum8 今日完成的任务 世强:部门人员管理界面设计编写: 港晨:设计主页面: 树民:web后端框架与前端对接: 伟航:app前端界面的美工: 陈翔: ...

  5. Windows安装PostgreSQL11.1

    Windows安装PostgreSQL11.1 安装过程如下: 1.下载安装包postgresql-11.1-1-windows-x64.exe 2.点击下一步 3.选择安装位置,默认路径C:\Pro ...

  6. (12)Python异常

  7. 深入理解Intent和IntentFiler(一)

    http://blog.csdn.net/u012637501/article/details/41080891 为了比较深刻的理解并灵活使用Intent,我计划将这部分的学习分为两步:一是深入理解I ...

  8. vs2008内存泄露检測得到完美解决

    版权声明:原创文章.转载请注明出处.本博新地址www.iaccepted.net https://blog.csdn.net/IAccepted/article/details/27646679 Vi ...

  9. java list 排序,建议收藏的排序方法

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code public static void main(String[] args) {    ...

  10. go标准库的学习-io/ioutil

    参考https://studygolang.com/pkgdoc 导入方式: import "io/ioutil" 包ioutil实现了一些I/O实用程序函数. 1.var 变量 ...