实验七:Linux内核如何装载和启动一个可执行程序
原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
题目自拟,内容围绕对Linux内核如何装载和启动一个可执行程序
可以结合实验截图、ELF可执行文件格式、用户态的相关代码等
博客内容中需要仔细分析新可执行程序的执行起点及对应的堆栈状态等
总结部分需要阐明自己对“Linux内核装载和启动一个可执行程序”的理解
实验报告:
理解编译链接的过程和ELF可执行文件格式;
- C代码——预处理——汇编代码——目标代码——可执行文件
gcc -E hello.c -o hello.i
gcc –S hello.i –o hello.s
gcc –c hello.s –o hello.o- ELF可执行文件格式

- 预处理负责把include的文件包含进来及宏替换工作。 hello和hello.o都是ELF格式的文件
- ELF是一个可重定位(relocatable)文件保存着代码和适当的数据,用来和其他的object文件一起来创建一个可执行文件或者是一个共享文件
编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式;
- 静态链接的ELF可执行文件和进程的地址空间
程序从0x804800开始 - 动态链接加载前准备的工作
(1)命令行参数和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的封装例程
(2)命令行参数和环境变量是如何传递和保存的
命令行参数和环境串都放在用户态堆栈中
- 装载时动态链接和运行时动态链接应用举例
动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。
- 准备.so文件
shlibexample.h (1.3 KB) - Interface of Shared Lib Example
shlibexample.c (1.2 KB) - Implement of Shared Lib Example编译成libshlibexample.so文件
1$ gcc -shared shlibexample.c -o libshlibexample.so -m32dllibexample.h (1.3 KB) - Interface of Dynamical Loading Lib Example
dllibexample.c (1.3 KB) - Implement of Dynamical Loading Lib Example编译成libdllibexample.so文件
1$ gcc -shared dllibexample.c -o libdllibexample.so -m32 #编译方式和上面一样- 分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件
main.c (1.9 KB) - Main program
编译main,注意这里只提供shlibexample的-L(库对应的接口头文件所在目录)和-l(库名,如libshlibexample.so去掉lib和.so的部分),并没有提供dllibexample的相关信息,只是指明了-ldl12345678$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32$ export LD_LIBRARY_PATH=$PWD #将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。$ ./mainThisisa Main program!Calling SharedLibApi() function of libshlibexample.so!Thisisa shared libary!Calling DynamicalLoadingLibApi() function of libdllibexample.so!Thisisa Dynamical Loading libary!
- 静态链接的ELF可执行文件和进程的地址空间
使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解
1.首先将exec函数写入test.c 函数
2.重新make rootfs 发现已经成功写进一个exec 函数

3.运行一下exec
4.正式来调试了设置断点

5.单步进入第一个断点
6.单步进入第二个断点
7.单步进入第三个断点
8.查看new_ip 地址
9.查看hello文件信息 ==》 发现elf文件的hello入口地址就是new_ip的地址
特别关注新的可执行程序是从哪里开始执行的?为什么execve系统调用返回后新的可执行程序能顺利执行?对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
新的可执行程序通过修改内核堆栈eip作为新程序的起点,
从new_ip开始执行后start_thread把返回到用户态的位置从int 0x80的下一条指令变成新加载的可执行文件的入口位置。当执行到execve系统调用时,进入内核态,用execve()加载的可执行文件覆盖当前进程的可执行程序,
当execve系统调用返回时,返回新的可执行程序的执行起点(main函数),所以execve系统调用返回后新的可执行程序能顺利执行。execve系统调用返回时,如果是静态链接,elf_entry指向可执行文件规定的头部(main函数对应的位置0x8048***);如果需要依赖动态链接库,elf_entry指向动态链接器的起点。动态链接主要是由动态链接器ld来完成的。
- 总结
装载和启动一个可执行程序依次调用以下函数:
sys_execve() -> do_execve() -> do_execve_common() -> exec_binprm() -> search_binary_handler() -> load_elf_binary() -> start_thread()
可执行程序的装载与庄生梦蝶的故事
可执行文件开始执行的起点在哪里?如何才能让execve系统调用返回到用户态时执行新程序?
庄生梦蝶 —— 醒来迷惑是庄周梦见了蝴蝶还是蝴蝶梦见了庄周?
庄周(调用execve的可执行程序)入睡(调用execve陷入内核),醒来(系统调用execve返回用户态)发现自己是蝴蝶(被execve加载的可执行程序)
修改int 0x80压入内核堆栈的EIP
load_elf_binary -> start_thread
浅析动态链接的可执行程序的装载
(1)可以关注ELF格式中的interp和dynamic。
(2)动态链接库的装载过程是一个图的遍历。
(3)装载和连接之后ld将CPU的控制权交给可执行程序。
实验七:Linux内核如何装载和启动一个可执行程序的更多相关文章
- 20135202闫佳歆--week 7 Linux内核如何装载和启动一个可执行程序--实验及总结
week 7 实验:Linux内核如何装载和启动一个可执行程序 1.环境搭建: rm menu -rf git clone https://github.com/megnning/menu.git c ...
- 作业七:Linux内核如何装载和启动一个可执行程序
作业七:Linux内核如何装载和启动一个可执行程序 一.编译链接的过程和ELF可执行文件格式 可执行文件的创建——预处理.编译和链接 在object文件中有三种主要的类型. 一个可重定位(reloca ...
- Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序
Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...
- linux内核分析 第七周 Linux内核如何装载和启动一个可执行程序
一.编译链接的过程和ELF可执行文件格式 vi hello.c gcc -E -o hello.cpp hello.c -m32 //预处理.c文件,预处理包括把include的文件包含进来以及宏替换 ...
- Linux内核设计第七周学习总结 Linux内核如何装载和启动一个可执行程序
陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 实验目的 使用gdb跟踪s ...
- Linux内核如何装载和启动一个可执行程序(转)
原文:http://www.cnblogs.com/petede/p/5351696.html 实验七:Linux内核如何装载和启动一个可执行程序 姓名:李冬辉 学号:20133201 注: 原创作品 ...
- 20135323符运锦----第七周:Linux内核如何装载和启动一个可执行程序
可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 ①编译器预处理 gcc -E -o XX.cpp XX.c (-m32)// 注:把include的文件包含进来, ...
- 第七周——Linux内核如何装载和启动一个可执行程序
万子惠 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 part1 实验 ...
- linux内核分析第七周-Linux内核如何装载和启动一个可执行程序
一.可执行文件的创建 可执行文件的创建就是三步:预处理.编译和链接. cd Code vi hello.c #写入最简单的helloworld的c程序 gcc -E -o hello.cpp hell ...
随机推荐
- SRM 390(1-250pt)
DIV1 250pt 题意:给定整数n和k,问最少需要多少个n连接在一起形成的新整数t,使得t是k的倍数.如果不能形成倍数,输出-1.k <= 10^5,n <= 10^9. 解法:不断增 ...
- [置顶] SpecDD系列:6个确保您执行“充分”QA测试的技巧
确保团队执行 “足够的” 测试覆盖面是非常困难的,尤其是对敏捷开发团队来说.对于初学者而言,一个开发Sprint中要完成多少的质量保证工作才够呢?我们知道,敏捷的标准是在开发Sprint结束的时候要完 ...
- Gridview导出到Excel
#region #导出到Excel protected void Button2_Click(object sender, EventArgs e) { Respons ...
- POJ 2075 Tangled in Cables (c++/java)
http://poj.org/problem?id=2075 题目大意: 给你一些人名,然后给你n条连接这些人名所拥有的房子的路,求用最小的代价求连接这些房子的花费是否满足要求. 思路: 昨天20分钟 ...
- cocos2d-x3.0 Physics新的物理引擎
1.说明: 3.0以后将box2d和chipmunk这两个物理引擎进行了封装,使用起来很的便利 2.详细用法: 1.创建物理世界场景 auto scene = Scene::createWithPhy ...
- 边走边学Nodejs (基础入门篇)
1.什么是Node.js Nodejs ,或者node, 是一个基于ChromeJavaScript执行时建立的平台.用于方便地搭建响应速度快.易于扩展的网络应用.Node.js 使用事件驱动, 非堵 ...
- ios创建的sqlite数据库文件如何从ios模拟器中导出
为了验证数据库的结构,有的时候需要使用一些管理工具来直接查看sqlite数据库的内容,在windows下有sqlite3的专用工具下载,而在ios下也可以使用火狐浏览器的插件sqlitemanager ...
- Java基础知识强化之IO流笔记13:递归之不死神兔问题(斐波那契数列)
1.这个问题是如下的: 有一对兔子,从出生后第3个月起,每个月都生一对兔子,小兔子长到第3个月又生一对兔子,加入兔子都不死,问第20个月兔子的对数? 分析:我们找规律 兔子对数第1个月: 1 ...
- linux命令行计算器 <转>
转自 http://blog.chinaunix.net/uid-26959241-id-3207711.html 详细文档请 man bc 在windows下,大家都知道直接运行calc,(c:\w ...
- HDU -2298 Toxophily(三分法)
这道题目,可以推出物理公式直接来做,但是如果推不出来就必须用程序的一种算法来实现了,物理公式只是适合这一个或者某个题,但是这种下面这种解决问题的方法确实解决了一类问题 ----三分法,大家可能都听说过 ...