Linux 装载可执行程序过程的分析

  • 内容说明
    本次的内容,是一次 MOOC 课程的作业。具体的,是使用汇编对 Linux 系统调用部分进行模拟实现,从而更加直观的验证 Linux 系统的基本机制。

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

  • 实验准备
    1 本次实验并没有使用 MOOC 课程上提供的实验楼的环境,而是自行搭建了 64Bit Ubuntu 虚拟机。
    2 本次试验使用了 Ubuntu 16.04,环境搭建和软件安装部分,可以参照上一篇博客的环境搭建部分。
    3 之前完成过 qemu 的实验,rootfs.img 的制作,gdb 的跟踪等。

  • 实验操作
    1 下载示例中的 menu 代码:Git clone https://github.com/mengning/menu.git ,并使用 test_fork.c 替换 test.c 文件:$ mv test_exec.c test.c
    2 注意:在简易的系统初始化完成之后,再加入断点(否则系统在初始化阶段即进入 sys_execve 等断点)
    3 分别在 sys_execve、load_elf_binary、start_thread等处打入断点
    这里写图片描述
    4 menuos中输入 exec,进行断点观察。在调用 start_thread时,gdb 中键入 po new_ip 来观察程序入口信息,显示输出为 0x8048736。
    事先在外部调用$ readelf -h hello ,显示其 Entry point address: 信息与 new_ip 的地址信息一致。
    这里写图片描述

  • 分析总结
    1 可执行程序使用一定的文件格式来描述该程序的入口信息、数据段、代码段、依赖信息等,目的是加载时使用。
    2 执行目标程序的本质
    就是将目标程序(使用 ELF 等格式描述)加载到“宿主”进程的地址空间中去、覆盖“宿主”进程的栈空间,并将“宿主”进程的 cs:ip 指向目标程序的入口地址。从而,“宿主”进程的执行便转化为目标程序的执行。
    3 Linux 下如何装载一个可执行程序?
    我们使用系统调用 exe*(对 execve 的一系列封装)来装载一个可执行程序,并传递相关参数和环境变量:int execve(const char * filename,char * const argv[],char * const envp[]);
    3.1 系统调用 execve 在陷入内核态后调用 sys_execve,逐层调用了 do_execve, do_execve_common, exec_binprm
    3.2 在 exec_binprm 中,使用 search_binary_handler 实现对不同格式的可执行文件进行不同的解析和执行
    3.3 对于 elf 文件,将使用 load_elf_binary 来进行执行。其中,对于静态链接的程序,将直接传递可执行文件入口地址给 elf_entry;对于动态链接程序,将采用广度优先的搜索方式借助 ld 来加载依赖库和依赖文件,最后才由 ld 返回可执行文件的入口地址。
    3.4 完成加载后,使用 start_thread 来更换当前进程的堆栈信息为目标可执行程序在 ELF 中描述的信息
    3.5 在返回时,当前进程消失,取而代之的是运行“目标可执行程序”的进程
    3.6 参数传递
    参数通过系统调用 execv 传递,并传递到内核中,最终传递给目标进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值