一 程序的装载和运行的基本知识补充

   1 当进程开始执行一个新的程序时,从父进程继承的所有页被释放,以便在新的用户地址空间开始执行新的计算,甚至进程的特权都可能发生改变,但是,进程的PID不会改变。

2 进程的信任状和权能

进程的信任状决定一个进程的权限,也就是能做什么,不能做什么。这对多用户系统,系统的稳定性很重要。

进程被创建时,总是继承父进程的信任状。

权能是引入进程信任状的另一种模式。他表示是否允许进程执行一个特定的操作或一组特定的操作。

3 目标文件不能被执行,因为它不含源代码文件所用的全局外部符号名的线性地址,这些地址的分配是由链接程序完成的。链接程序还分析程序所用的库函数。

4 静态链接生成的可执行文件不仅包含原程序的代码,还包含程序所引用的库函数的代码。缺点是占用大量的磁盘空间。

动态链接程序把一个共享库链接到进程时,不拷贝目标代码,仅执行一个内存映射,把库文件的相关部分映射到进程的地址空间中,缺点是程序的启动时间较长。

二 跟踪分析执行程序的系统调用execve()

2.1在以前的代码基础上添加

    

main()添加:

利用qemu查看调试结果(相关的基本设置可以参考前面博客)

设置断点:

执行,停在第一个断点处:

继续执行,停在do_open_exec:

继续执行:

输入exec:

发现程序停在:

执行:

接着执行:

分析:新的可执行程序是从哪里开始执行的?

我们知道只有pc能代表程序的执行流, 父进程fork创造椅子进程,子进程执行新的可执行程序,当子进程“获得”pc时,才是子进程(可执行程序)开始执行的地方。通过GDB跟踪以及阅读源码,

void start_thread(struct pt_regs *regs, unsigned long new_pc,
unsigned long new_sp)
{
regs->pr = 0;
regs->sr = SR_FD;
regs->pc = new_pc;
regs->regs[15] = new_sp; free_thread_xstate(current);
}

  可以看到在函数load_elf_binary()的最后调用了函数start_thread(regself_entrybprm->p),所以elf_entry是可执行程序开始执行的地方。

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

因为在系统调用过程中,父进程的大部分资源被抛弃,堆栈被清空,新的可执行程序根据传递的参数和环境变量配置了一个新的堆栈。所以返回时能够正常执行。

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

在函数load_elf_binary中可以看到如下的一段代码:

887	if (elf_interpreter) {
888 unsigned long interp_map_addr = 0;
889
890 elf_entry = load_elf_interp(&loc->interp_elf_ex,
891 interpreter,
892 &interp_map_addr,
893 load_bias);
894 if (!IS_ERR((void *)elf_entry)) {
895 /*
896 * load_elf_interp() returns relocation
897 * adjustment
898 */
899 interp_load_addr = elf_entry;
900 elf_entry += loc->interp_elf_ex.e_entry;
901 }
902 if (BAD_ADDR(elf_entry)) {
903 retval = IS_ERR((void *)elf_entry) ?
904 (int)elf_entry : -EINVAL;
905 goto out_free_dentry;
906 }
907 reloc_func_desc = interp_load_addr;
908
909 allow_write_access(interpreter);
910 fput(interpreter);
911 kfree(elf_interpreter);
912 } else {
913 elf_entry = loc->elf_ex.e_entry;
914 if (BAD_ADDR(elf_entry)) {
915 retval = -EINVAL;
916 goto out_free_dentry;
917 }

 我们知道 elf_entry是系统调用返回时可执行文件开始执行的地方,由以上代码,通过静态链接返回时,elf_entry代表的是可执行文件规定的头部,而动态链接,elf_entry代表的是动态链接器的起点。

三 总结

自己对“Linux内核装载和启动一个可执行程序”的理解

通过以上的学习,我们知道装载和启动一个可执行程序主要是通过系统调用execve()来实现的,和普通的系统调用不同,execve系统调用返回时不是INT $0x80语句的后面一条语句,而是变成了一个新的进程,按照用户要求(参数和环境变量)创建的可执行程序。

通过一系列函数调用:do_execve()->do_execve_common()->exec_binprm()->search_binary_handler()->list_for_each_entry()->load_binary()->load_elf_binary()->start_thread(),

start_thread(regself_entrybprm->p)中修改了ip,elf_entry是可执行程序开始执行的地方。

by:方龙伟

原创作品 转载请注明出处

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

linux内核学习之七 可执行程序的装载和运行的更多相关文章

  1. Linux内核分析之可执行程序的装载和启动

    一.内容分析 1.可执行文件的创建 (1)预处理阶段 预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行相应的转换,预处理过程还会删除程序中的注释和多余的空白字符.其中预处理指令主 ...

  2. Linux第七周学习总结——可执行程序的装载

    Linux第七周学习总结--可执行程序的装载 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/course/ ...

  3. Linux内核分析——Linux内核学习总结

    马悦+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核学习总结 一 ...

  4. Linux内核学习期末总结(网课)

    标签(空格分隔): 20135321余佳源 余佳源(原创作品转载请注明出处) <Linux内核分析> MOOC课程http://mooc.study.163.com/course/USTC ...

  5. 关于Linux内核学习的一点点总结

    关于Linux内核学习的一点点总结 关键词:Linux, 操作系统,内核 博客列表 由反汇编C程序来理解计算机是如何工作的 通过分析一个简化版时间片轮转多道程序内核代码来认识操作系统中的进程调度 通过 ...

  6. linux内核学习之二:编译内核

    在linux内核学习系列的第一课中讲述了搭建学习环境的过程(http://www.cnblogs.com/xiongyuanxiong/p/3523306.html),环境搭好后,马上就进入到下一环节 ...

  7. Linux内核学习笔记-1.简介和入门

    原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  8. 20135316王剑桥Linux内核学习笔记

    王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...

  9. Linux 内核学习的经典书籍及途径

    from:http://www.zhihu.com/question/19606660 知乎 Linux 内核学习的经典书籍及途径?修改 修改 写补充说明 举报   添加评论 分享 • 邀请回答   ...

随机推荐

  1. Oracle 修改文件所有者

        # chown -R gpadmin /usr/local/greenplum-db     # chgrp -R gpadmin /usr/local/greenplum-db

  2. JS新API标准 地理定位(navigator.geolocation)

    在新的API标准中,可以通过navigator.geolocation来获取设备的当前位置,返回一个位置对象,用户可以从这个对象中得到一些经纬度的相关信息. navigator.geolocation ...

  3. Git和.gitignore

    http://blog.csdn.net/cscmaker/article/details/8553980 在git中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .giti ...

  4. Pod 的安装

    1.如果之前已经安装过的 gem list --local | grep cocoapods 会看到如下输出: cocoapods (1.1.1)cocoapods-deintegrate (1.0. ...

  5. 使用layer.open时content属性传值记录

    最近在做一个后台项目,正好碰上了要使用layer.open,就顺手记录一下,方便以后遇到了有个参考 - 2016/11/7 layer 这个是一个web弹层组件,挺好用的...然后项目框架是SSM.. ...

  6. C# GDI+发生一般性错误(A generic error occurred in GDI+))

    解决思路: 1. 因为 .net GDI+ 是对底层 的封装. 所以可以尝试用 Marshal.GetLastWin32Error();函数获得底层错误代码. try{ image.Save(file ...

  7. ssh框架的工作原理

    struts2的工作原理 1 客户端初始化一个指向Servlet容器(例如Tomcat)的请求 2 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextClea ...

  8. instanceof 与isAssignableFrom

    instanceof 针对实例 isAssignableFrom针对class对象 isAssignableFrom   是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的超类或 ...

  9. bean生命周期

    一.Bean的定义Spring通常通过配置文件定义Bean.如:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:s ...

  10. VPS/云主机 如何试用远程连接登录主机服务器_

    1.windows主机如何远程登录 点本地电脑开始>运行(或者按"window+R")>输入mstsc点确定 弹出远程连接的框输入IP连接,  如果是VPS,直接输入I ...