一、理论知识

Linux中,可以从c源代码生产一个可执行程序,这其中要经过预处理、编译和链接的过程。可以参考以下图来理解这个过程:

其中,目标文件中至少有编译后的机器指令代码、数据,也还包括了链接时所须要的一些信息,比如符号表、调试信息、字符串等。这Linux中,可执行文件的格式现在主要是ELF格式(对应于Windows中PE格式)。ELF的格式如下:

其详细介绍,参见:http://www.muppetlabs.com/~breadbox/software/ELF.txt,这里还有个中文版:http://www.xfocus.net/articles/200105/174.html

链接,是收集、组织程序所需的不同代码和数据的过程,以便程序能被装入内存并被执行。链接过程分为两步:1.空间与地址分配;2.符号解析与重定位。

在Linux中,一个程序的执行是做为一个新的进程,使用execve系统调用完成的。execve对应的系统调用是sys_execve,在其内部会解析可执行文件格式。对应的内核代码,就是,在search_binary_handler中寻找符合文件格式对应的解析模块,关键代码如下:

对于ELF文件,retval = fmt->load_binary(bprm)实际上执行的就是load_elf_binary,其内部就是按照ELF文件格式来加载ELF文件的。这里,我们也可以看到Linux是可以支持多种可执行文件格式的,所有的格式处里信息用一个结构体存储在一个链表中,其中的load_binary是一个函数指针,对应于该中格式的可执行文件的加载方式;要想支持一种新的可执行文件,只需要向链表中注册一个新的format结构体就可以了,此种设计类似观察者模式,具有很好的扩展性。

二、实验过程

打开实验楼中的虚拟机,在shell中依次运行以下命令,获取本次实验的代码,并编译运行

cd LinuxKernel

rm menu -rf

git clone https://github.com/mengning/menu.git

cd menu

mv test_exec.c test.c

make rootfs

效果如下:

关闭QEMU窗口,在shell窗口中,cd LinuxKernel回退到LinuxKernel目录,使用下面的命令启动内核并在CPU运行代码前停下以便调试:

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

接下来,我们就可以水平分割一个新的shell窗口出来,依次使用下面的命令启动gdb调试

gdb

(gdb) file linux-3.18.6/vmlinux

(gdb) target remote:1234

并在系统调用sys_execve的入口处设置断点

(gdb) b sys_execve

继续运行程序,在QEMU窗口中输入exec,系统就会停在上面设置的断点处,如图:

接下来我们可以单步跟踪sys_execve的内核代码,也可以通过设置以下断点

b load_elf_binary

b start_thread

来完整地跟踪进程的创建和启动代码!

三、总结

Linux系统可以通过execve API启动一个新进程,该API又呼叫sys_execve系统调用,负责将新的程序代码和数据替换到新的进程中,打开可执行 文件,载入依赖的库文件,申请新的内存空间,最后执行 start_thread(regs, elf_entry, bprm->p) ,设置 new_ip, new_sp ,完成新进程的代码和数据替换,然后返回,接下来就是执行新的进程代码了。

Linux内核分析7的更多相关文章

  1. linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程

    1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...

  2. Linux内核分析作业7:Linux内核如何装载和启动一个可执行程序

            1.可执行文件的格式 在 Linux 平台下主要有以下三种可执行文件格式: 1.a.out(assembler and link editor output 汇编器和链接编辑器的输出) ...

  3. linux内核分析作业6:分析Linux内核创建一个新进程的过程

    task_struct结构: struct task_struct {   volatile long state;进程状态  void *stack; 堆栈  pid_t pid; 进程标识符  u ...

  4. linux内核分析作业5:分析system_call中断处理过程

    1.增加 Menu 内核命令行 调试系统调用. 步骤:删除menu git clone        (tab) make rootfs 这就是我们将 fork 函数写入 Menu 系统内核后的效果, ...

  5. linux内核分析作业:以一简单C程序为例,分析汇编代码理解计算机如何工作

    一.实验 使用gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与他人雷同 int g(int x) { return x + 3; } in ...

  6. linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码

    计算机如何工作 三个法宝:存储程序计算机.函数调用堆栈.中断机制. 堆栈 函数调用框架 传递参数 保存返回地址 提供局部变量空间 堆栈相关的寄存器 Esp 堆栈指针  (stack pointer) ...

  7. linux内核分析作业3:跟踪分析Linux内核的启动过程

    内核源码目录 1. arch:录下x86重点关注 2. init:目录下main.c中的start_kernel是启动内核的起点 3. ipc:进程间通信的目录 实验 使用实验楼的虚拟机打开shell ...

  8. linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...

  9. 《Linux内核分析》期末总结

    Linux内核设计期中总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 前八周博客汇总及总结 Linux内核设计第一周——从汇编语言出发理解计算机工作原理 我们学习了汇编语言的基础知识,这一 ...

  10. 《Linux及安全》期中总结&《Linux内核分析》期终总结

    [5216 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK NINE ...

随机推荐

  1. mysql学习----支持Emoji表情

    但发现了一个问题,iPhone上有Emoji表情,插入Mysql时失败了,报如下异常: java.sql.SQLException: Incorrect string value: '\xF0\x9F ...

  2. 用原生JS实现一个轮播(包含全部代码和详细思路)

    在我看来要想实现轮播主要是要知道当前位于的页面和即将位于的页面.这个案例是通过改变图片的透明度来实现轮播的效果. 我把涉及的知识点分为两个方面,分别是HTML+css和JS. 第一部分(html+cs ...

  3. i3wm随笔 1

    快捷键 mod+0 退出 mod+v 垂直分割 mod+h 水平风格

  4. 图 -数据结构(C语言实现)

    读数据结构与算法分析 坑!待填! 若干定义 一个图G = (V , E)由顶点集V和边集E组成,每条边就是一个点对 如果点对是有序的,那么就叫做有向图 边可能还具有第三种成分,权值 无向图种从每个顶点 ...

  5. 3星|李开复《AI·未来》:中国创业公司有独特优势,人工智能可能会加剧社会的不平等与不稳定

    主要内容:作者对自己一些经历的回顾,对中美两国人工智能行业的回顾与展望. 作者认为中国的创业公司比美国节奏更快工作更拼命,深圳在硬件创新上远远领先于美国,中国创业公司们走出了一条跟美国不同的路. 作者 ...

  6. HIVE简介及安装

    一.简介 百度百科HIVE定义: hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运 ...

  7. @Resource和@Autowired的异同

    相同点: 两者都能做到注入一个Bean. 两者都可应用在Field和Method上面. 两者均为Runtime级别的Retention. 不同点: 使用的场景有差异 @Resource可应用在类(TY ...

  8. 从零开始的Python学习Episode 13——常用模块

    模块 一.time模块 时间戳(timestamp) :时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量. 元组(struct_time)   :struct_time元组共有9 ...

  9. Docker入门与实践之 docker安装与了解

    一.Docker 概述 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源.Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后 ...

  10. wepy中如何使用stylus等样式预处理器

    wepy中如何使用stylus等样式预处理器 一.如何在wepy中使用stylus 1.安装wepy-compiler-stylus(以及stylus, stylus-loader) npm inst ...