by 21035130王川东

Linux内核如何装载和启动一个可执行程序

一、 EIF文件格式:

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

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

  3、ELF头描述了该文件的组织情况,程序投标告诉系统如何创建一个进程的内存映像,section头表包含了描述文件sections的信息。当系统要执行一个文件的时候,理论上讲,他会把程序段拷贝到虚拟内存中某个段。

4、程序从0x804800开始,可执行文件加载到内存中开始执行的第一行代码,一般静态链接将会把所有代码放在同一个代码段,动态连接的进程会有多个代码段

EIF文件头包含的内容:

可执行文件的生成过程:

可执行程序的执行环境:

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

(2)Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身

(3)Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数

(4)库函数exec*都是execve的封装例程

可执行程序的装载:

(1)do_execve()

在用户态下调用execve(),引发系统中断后,在内核态执行的相应函数是do_sys_execve(),而do_sys_execve()会调用do_execve()函数。do_execve()首先会读入可执行文件,如果可执行文件不存在,会报错。然后对可执行文件的权限进行检查。如果文件不是当前用户是可执行的,则execve()会返回-1,报permissiondenied的错误。否则继续读入运行可执行文件时所需的信息。

(2)search_binary_handler()

接着系统调用search_binary_handler(),根据可执行文件的类型,查找到相应的处理函数。系统为每种文件类型创建了一个structlinux_binfmt,并把其串在一个链表上,执行时遍历这个链表,找到相应类型的结构。然后执行相应的load_binary()函数开始加载可执行文件。

(3) load_elf_binary()

加载elf类型文件的handler是load_elf_binary(),它先读入ELF文件的头部,根据ELF文件的头部信息读入各种数据(headerinformation)。再次扫描程序段描述表,找到类型为PT_LOAD的段,将其映射(elf_map())到内存的固定地址上。如果没有动态链接器的描述段,把返回的入口地址设置成应用程序入口。完成这个功能的是start_thread(),start_thread()并不启动一个线程,而只是用来修改了pt_regs中保存的PC等寄存器的值,使其指向加载的应用程序的入口。这样当内核操作结束,返回用户态的时候,接下来执行的就是应用程序了。

(4) load_elf_interp()

如果有动态链接库的存在,那么我们还需要映射动态链接库到共享区域,还要把控制权交给动态连接器(programinterpreter,ld.soinlinux)以处理动态链接的程序。内核搜寻段表,找到标记为PT_INTERP的段中所对应的动态连接器的名称,并使用load_elf_interp()加载其映像,并把返回的入口地址设置成load_elf_interp()的返回值,即动态链接器入口。当execve退出的时候动态链接器接着运行。动态连接器检查应用程序对共享连接库的依赖性,并在需要时对其进行加载,对程序的外部引用进行重定位。然后动态连接器把控制权交给应用程序,从ELF文件头部中定义的程序进入点开始执行。

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

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

(3)sys_execve内部会解析可执行文件格式:do_execve -> do_execve_common -> exec_binprm,earch_binary_handler符合寻找文件格式对应的解析模块

实验过程:

1、更新menu内核

2、查看test.c文件:增加了exec系统调用

3、查看Makefile

4、启动内核,

可以看到exec函数的存在。

5、启动GDB调试进行调试,先停在sys_execve处

6、使用new_ip返回到用户态的第一条指令
退出调试状态,输入redelf -h hello可以查看hello的EIF头部

总结:

多进程、多用户、虚拟存储的操作系统出现以后,可执行文件的装载过程变得非常复杂。引入了进程的虚拟地址空间;然后根据操作系统如何为程序的代码、数据、堆、栈在进程地址空间中分配,它们是如何分布的;最后以页映射的方式将程序映射进程虚拟地址空间。 
      动态链接是一种与静态链接程序不同的概念,即一个单一的可执行文件模块被拆分成若干个模块,在程序运行时进行链接的一种方式。然后根据实际例子do_exece()分析了ELF装载的大致过程,中间实现了动态链接。

Linux系统的运行方式与其他系统有所不同,,虽然有点难懂,但还是尽力学习,习了以后感觉很有趣,越来越有兴趣学习它了

《Linux内核与分析》第七周的更多相关文章

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

    实验步骤 1. 更新menu,用test.c覆盖test_exec.c 2. 把init 和 hello 放到了rootfs.img目录下,执行exec命令的时候自动加载了hello程序 3. 执行e ...

  2. 2019-2020-1 20199303 《Linux内核原理分析》 第一周作业

    2019-2020-1 20199303 <Linux内核原理分析> 第一周作业 1. 环境准备 在众多的Linux发行版中,Ubuntu,小红帽还有类Unix系统的BSD系统,我选择了目 ...

  3. Linux内核及分析 第八周 进程的切换和系统的一般执行过程

    学习笔记: 一.进程调度与进程调度的时机分析 1.不同类型的进程有不同需求的调度需求: 第一种分类: —I/O-bound:频繁的进行I/O,通常会花费很多时间等待I/O操作的完成 —CPU-boun ...

  4. Linux内核及分析 第六周 分析Linux内核创建一个新进程的过程

    实验过程 1.github上克隆相应的mengning/menu.git 2.测试menuOS,测试fork直接执行结果 3.配置调试系统,进入gdb调试,利用file linux-3.18.6/vm ...

  5. Linux内核及分析 第五周 扒开系统调用的三层皮(下)

    实验内容: 1.执行rm menu -rf命令,强制删除原有的menu 2.使用git命令 git clone https://github.com/mengning/menu.git 克隆新的men ...

  6. Linux内核及分析 第三周 Linux内核的启动过程

    实验过程: 打开shell终端,执行以下命令: cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootf ...

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

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

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

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

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

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

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

    Linux内核分析第七周---可执行程序的装载 李雪琦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/US ...

随机推荐

  1. mininet+floodlight使用(一)

    目录 一 .安装Floodlight 1.下载源和相关工具 2.安装(注意,需要java1.8,否则报错) 3.尝试游览器访问管理界面 4.修复查看不了floodlight 二.Mininet自定义拓 ...

  2. 解决mysql远程登录

    MySQL不允许远程登录,所以远程登录失败了,解决方法如下: 在装有MySQL的机器上登录MySQL mysql -u root -p密码 执行use mysql; 执行update user set ...

  3. mybatis xml文件 -- 报错 invalid comparison: java.time.LocalDateTime and java.lang.String

    原配置写法:<if test="assetFlaw.handleTime != null and assetFlaw.handleTime != ''"> and af ...

  4. java 数组基础学习(一维二维数组)

    1.一维数组 1>静态初始化:数据类型[ ] 变量名 = {元素} 例:int[ ] arr = {1,2} 动态初始化:数据类型[ ] 变量名 = new数据类型[数据长度] 例:int[ ] ...

  5. jdbc之Statement和Preparement

    Jdbc DML 操作 Statement:静态SQL操作 每次操作都会将sql语句提交到数据库执行一次,性能比较低 // 1.加载驱动程序 Class.forName(driverName); // ...

  6. hexo博客更换主题

    前边我们已经学会了博客的搭建了,这次我们来看看怎么样让我们的博客更漂亮,更个性化.那就是来更换博客的主题,让我们的博客与众不同起来.我们可以去hexo的主题官网去挑选你自己喜欢的主题风格.里边收录了很 ...

  7. 06.搭建kafka集群环境并测试

    参考: https://www.cnblogs.com/zhangs1986/p/6565639.html https://www.cnblogs.com/frankdeng/p/9403883.ht ...

  8. C语言编程学习不难学,是你没找对方法!

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  9. pgsql 变量赋值方法

    1.网上一般说的方法如下: :=,赋值,比如user_id := 20; select into 赋值,比如 SELECT INTO myrec * FROM emp WHERE empname = ...

  10. 微信小程序 request请求封装

    在utils文件夹新建文件utils.js,封装代码如下: 小程序升级后内部不自带Promise方法,需外部引入Promise方法   var sendRequest = function (url, ...