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

一、实验内容

1.预处理、编译和链接 实践

  ELF头部在文件的开始,描述文件的总体格式,保存了路线图,描述该文件的组织情况,即生成该文件系统的字的大小和字节顺序 段头部表用来描述ELF可执行文件与连续的存储段之间的映射关系。节头表包含了描述文件节区的信息,每个节区在表中都有一个项,给出节区的名称、节区大小这类心里。用于链接的目标文件(可重定向文件)必须包含节区头部表,而可执行文件可以没有。

2.可执行程序的执行环境

命令行参数和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的封装例程

3.可执行程序的装载

(1)do_execve()

(2)search_binary_handler()

(3) load_elf_binary()

(4) load_elf_interp()

二、实验步骤及截图

  1. 更新menu内核

    rm menu -rf
  2. 查看test.c文件(shift+G直接到文件尾):可以看到新增加了exec系统调用,其源代码与之前的fork类似
  3. 启动内核并验证execv函数
  4. 冻结内核,启动GDB调试
  5. 进行调试
    • 先停在sys_execve处,再设置其它断点;按c一路运行下去直到断点sys_execve
    • 按s跳入函数内单步执行
  6. 退出调试状态,输入redelf -h hello可以查看hello的EIF头部

三、Linux系统加载可执行程序所需处理过程的理解

1. 新的可执行程序是从哪里开始执行的?

当execve()系统调用终止且进程重新恢复它在用户态执行时,执行上下文被大幅度改变,要执行的新程序已被映射到进程空间,从elf头中的程序入口点开始执行新程序。

如果这个新程序是静态链接的,那么这个程序就可以独立运行,elf头中的这个入口地址就是本程序的入口地址。

如果这个新程序是动态链接的,那么此时还需要装载共享库,elf头中的这个入口地址是动态链接器ld的入口地址。

2.为什么execve系统调用返回后新的可执行程序能顺利执行?

新的可执行程序执行: 
1. 需要的库函数。 
2. 属于它的进程空间:代码段,数据段,内核栈,用户栈等。 
3. 需要的运行参数。 
4. 需要的系统资源。 
如果满足以上4个条件,那么新的可执行程序就会处于可运行态,只要被调度到,就可以正常执行。
条件1:如果新进程是静态链接的,那么库函数已经在可执行程序文件中,条件满足。如果是动态链接的,新进程的入口地址是动态链接器ld的起始地址,可以完成对所需库函数的加载,也能满足条件。 
条件2:execve系统调用通过大幅度修改执行上下文,将用户态堆栈清空,将老进程的进程空间替换为新进程的进程空间,新进程从老进程那里继承了所需要的进程空间,条件满足。 
条件3:我们一般在shell中,输入可执行程序所需要的参数,shell程序把这些参数用函数参数传递的方式传给给execve系统调用,然后execve系统调用以系统调用参数传递的方式传给sys_execve,最后sys_execve在初始化新程序的用户态堆栈时,将这些参数放在main函数取参数的位置上。条件满足。 
条件4:如果当前系统中没有所需要的资源,那么新进程会被挂起,直到资源有了,唤醒新进程,变为可运行态,条件可以满足。 
综上,新的可执行程序可以顺利执行。

3.对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?

execve系统调用会调用sys_execve,然后sys_execve调用do_execve,然后do_execve调用do_execve_common,然后do_execve_common调用exec_binprm。

对于ELF文件格式,fmt函数指针实际会执行load_elf_binary,load_elf_binary会调用start_thread,在start_thread中通过修改内核堆栈中EIP的值,使其指向elf_entry,跳转到elf_entry执行。 
对于静态链接的可执行程序,elf_entry是新程序的执行起点。对于动态链接的可执行程序,需要先加载链接器ld, 
elf_entry = load_elf_interp(…) 
将CPU控制权交给ld来加载依赖库,再由ld在完成加载工作后将CPU控制权还给新进程。

四.总结

在Linux中,fork是进程创建另一个进程的唯一方法。只有第一个进程也就是被称作 init 的进程需要 手工创建 。所有其他进程都是用fork这个系统调用创建的。fork系统调用只是复制了父进程的数据和堆栈,并在这两个进程之间共享文本区。fork系统调用采用比较聪明的方式— 写时拷贝(copy-on-write) 技术,使得fork结束后并不立刻复制父进程的内容,而是到了真正实用的时候才复制,这样使效率大大提高。fork函数创建了一个子进程后,子进程会调用exec族函数执行另外一个程序。
      多进程、多用户、虚拟存储的操作系统出现以后,可执行文件的装载过程变得非常复杂。引入了进程的虚拟地址空间;然后根据操作系统如何为程序的代码、数据、堆、栈在进程地址空间中分配,它们是如何分布的;最后以页映射的方式将程序映射进程虚拟地址空间。 
      动态链接是一种与静态链接程序不同的概念,即一个单一的可执行文件模块被拆分成若干个模块,在程序运行时进行链接的一种方式。然后根据实际例子do_exece()分析了ELF装载的大致过程,中间实现了动态链接。

第七周 linux如何装载和启动一个可执行文件的更多相关文章

  1. Linux内核装载和启动一个可执行程序

    “平安的祝福 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 理解编 ...

  2. 20135323符运锦----第七周:Linux内核如何装载和启动一个可执行程序

    可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 ①编译器预处理 gcc -E -o XX.cpp XX.c (-m32)// 注:把include的文件包含进来, ...

  3. Linux内核设计第七周 ——可执行程序的装载

    Linux内核设计第七周 ——可执行程序的装载 第一部分 知识点总结 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 编译链接的过程 预处理阶段 gcc -E -o XX.cpp ...

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

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

  5. 作业七:Linux内核如何装载和启动一个可执行程序

    作业七:Linux内核如何装载和启动一个可执行程序 一.编译链接的过程和ELF可执行文件格式 可执行文件的创建——预处理.编译和链接 在object文件中有三种主要的类型. 一个可重定位(reloca ...

  6. 实验七:Linux内核如何装载和启动一个可执行程序

    原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 题目自拟,内容围绕对Linu ...

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

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

  8. linux内核分析 第七周 Linux内核如何装载和启动一个可执行程序

    一.编译链接的过程和ELF可执行文件格式 vi hello.c gcc -E -o hello.cpp hello.c -m32 //预处理.c文件,预处理包括把include的文件包含进来以及宏替换 ...

  9. Linux内核设计第七周学习总结 Linux内核如何装载和启动一个可执行程序

    陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 实验目的 使用gdb跟踪s ...

随机推荐

  1. 随机生成&部门匹配

    整体概况 1.完整程序概况 (1)程序整体构架 (2)生成程序模型 (3)匹配算法模型 (4)生成结果评估 (5)命名规范 (6)先期和后期分工 2.心路历程与对全新的java认识(心得体会篇) (1 ...

  2. DataUtils对Connection的获取、释放和关闭的操作学习

    DataSourceUitls介绍 DataSourceUitls类位于org.springframework.jdbc.datasource包下,提供了很多的静态方法去从一个javax.sql.Da ...

  3. JAVA获取本机IP和Mac地址

       在项目中,时常需要获取本机的Ip或是Mac地址,进行身份和权限验证,本文就是通过java代码获取ip和Mac. package com.svse.query;import java.net.In ...

  4. 新鲜出炉的jquery fileupload 插件

    内容属原创,转载请注明出处 为什么做这个东东 项目中需要用到一个多附件上传的控件,找了一圈没找到中意的(唯一一个中意点的还不开源,费用比较高),这不,只得自己抡刀上了. 需求是什么 这么个上传的东东, ...

  5. <20180923>中秋节日期间的维护日志

    (一) 陌生环境下断网是有风险的,提前做好准备. 1.1 某企业的机柜自2017年5月开始就没有作硬件更新和维护了: 趁着这次节日空挡可做一个机柜的重新整理维护: 首先看了下是老款某知名品牌的型号为6 ...

  6. 点击事件click和onclick的区别

    一句话:$(selector).click()事件只能绑定静态元素.$(selector).on('click',function(){ })支持动态绑定元素. 如果是动态生成的元素,绑定事件只能用o ...

  7. java 中,如何获取文件的MD5值呢?如何比较两个文件是否完全相同呢?

    /** * Get MD5 of one file:hex string,test OK! * * @param file * @return */ public static String getF ...

  8. Nginx完美解决前后端分离端口号不同导致的跨域问题

    笔者在做前后端分离系统时,出现了很多坑,比如前后端的url域名相同,但是端口号不同.例如前端页面为:http://127.0.0.1/ , 后端api根路径为 http://127.0.0.1:888 ...

  9. YOCVM

    一.热补丁的本质 对于线上紧急的bug,重新提审AppStore的时间过长.因此,能够下发一段补丁代码到线上运行,并结合Runtime,实时改变App原有的行为,就显得极为重要.补丁代码的形式可以有很 ...

  10. HTTPS深入理解

    HTTPS = HTTP + TLS