Linux内核设计第七周 ——可执行程序的装载
Linux内核设计第七周
——可执行程序的装载
第一部分 知识点总结
一、预处理、编译、链接和目标文件的格式
1、可执行程序是怎么得来的
编译链接的过程
- 预处理阶段
gcc -E -o XX.cpp XX.c -m32
XX.cpp是预处理文件
- 编译器生成汇编代码阶段
gcc -x cpp-output -S -o hello.s hello.cpp -m32
XX.s是汇编代码
- 汇编器生成目标代码阶段
gcc -x assembler -c hello.s -o hello.o -m32
XX.o是目标代码
- 链接器生成可执行文件阶段
gcc -o hello.static hello.c -m32 -static
- 查看hello和hello.static的区别:
ls -l
2、目标文件的格式ELF
(1)ELF目标文件格式的分类:
(2)ABI和目标文件格式的关系?
ABI是应用程序二进制接口。
目标文件是二进制兼容,目标文件已经适应到一种CPU体系结构的二进制指令。
可以说二者可以相互交换,基本上是一样的。
(3)ELF文件格式
- 查看ELF文件的头部
shiyanlou:Code/ $ readelf -h hello
- 查看该ELF文件依赖的共享库
shiyanlou:sharelib/ $ ldd main
linux-gate.so.1 => (0xf774e000) # 这个是vdso - virtual DSO:dynamically shared object,并不存在这个共享库文件,它是内核的一部分,为了解决libc与新版本内核的系统调用不同步的问题,linux-gate.so.1里封装的系统调用与内核支持的系统调用完全匹配,因为它就是内核的一部分嘛。而libc里封装的系统调用与内核并不完全一致,因为它们各自都在版本更新。
libshlibexample.so => /home/shiyanlou/LinuxKernel/sharelib/libshlibexample.so (0xf7749000)
libdl.so.2 => /lib32/libdl.so.2 (0xf7734000)
libc.so.6 => /lib32/libc.so.6 (0xf7588000)
/lib/ld-linux.so.2 (0xf774f000)
shiyanlou:sharelib/ $ ldd /lib32/libc.so.6
/lib/ld-linux.so.2 (0xf779e000)
linux-gate.so.1 => (0xf779d000)
- readelf -d 也可以看依赖的so文件
shiyanlou:sharelib/ $ readelf -d main
Dynamic section at offset 0xf04 contains 26 entries:
0x00000001 (NEEDED) 共享库:[libshlibexample.so]
0x00000001 (NEEDED) 共享库:[libdl.so.2]
0x00000001 (NEEDED) 共享库:[libc.so.6]
0x0000000c (INIT) 0x80484f0
0x0000000d (FINI) 0x8048804
0x00000019 (INIT_ARRAY) 0x8049ef8
3、静态链接的ELF可执行文件和进程的地址空间
- 静态链接将会把所有代码放到代码段
- 动态链接的进程会有多个代码段
二、可执行程序、共享库和动态加载
1.装载可执行程序之前的工作
(1)可执行程序的执行环境
- 一般我们执行一个程序的Shell环境,我们的实验直接使用execve系统调用。
- Shell本身不限制命令行参数的个数,命令行参数的个数受限于命令自身。
int main(int argc, char *argv[])
int main(int argc, char argv[], char envp[])//envp是shell的执行环境
- Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
库函数exec*都是execve的封装例程
shell中使用fork()来创建新进程。
命令行参数和环境串都放在用户态堆栈中。
2.装载时动态链接和运行时动态链接应用举例
动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。
(1)准备.so文件
共享库
shlibexample.h (1.3 KB) - Interface of Shared Lib Example shlibexample.c (1.2 KB) - Implement of Shared Lib Example
- 编译成libshlibexample.so文件
$ gcc -shared shlibexample.c -o libshlibexample.so -m32
动态链接库
dllibexample.h (1.3 KB) - Interface of Dynamical Loading Lib Example
dllibexample.c (1.3 KB) - Implement of Dynamical Loading Lib Example
- 编译成libdllibexample.so文件
$ gcc -shared dllibexample.c -o libdllibexample.so -m32
分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件。
编译main,只提供
- shlibexample的-L(库对应的接口头文件所在目录)
- -l(库名,如libshlibexample.so去掉lib和.so的部分)
并没有提供dllibexample的相关信息,只是指明了-ldl。
$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
$ export LDLIBRARYPATH=$PWD
# 将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。
$ ./main
三、可执行程序的装载
1.可执行程序的装载相关关键问题分析
(1)execve与fork比较
execve用它加载的可执行文件把当前的进程覆盖掉,返回之后就不是原来的程序而是新的可执行程序起点;
- 是同一个进程,只不过是进程执行的可执行程序被换成了新的,只返回一次。
fork函数的返回点ret_ from_ fork是用户态起点。
- 进入内核态后,返回两次。
(2)sys_ execve内核处理过程
do_ execve -> do_ execve_ common -> exec_ binprm
最后,根据文件头部信息寻找对应的文件格式处理模块
list_for_each_entry(fmt, &formats, lh) {//在链表中寻找可以处理这种格式(比如ELF)的模块
if (!try_module_get(fmt->module))
continue;
read_unlock(&binfmt_lock);
bprm->recursion_depth++;
retval = fmt->load_binary(bprm);
//对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读
read_lock(&binfmt_lock);
(3)Linux内核是如何支持多种不同的可执行文件格式的?
2.sys_execve的内部处理过程
elf_interpreter:需要动态链接
startthread(regs,elfentry,bprm->p)中的elf_entry
3.使用gdb跟踪sys_execve内核函数的处理过程
见实验部分
4.可执行程序的装载与庄生梦蝶的故事
庄周梦蝶
庄周(调用execve的可执行程序)入睡(调用execve陷入内核),醒来(系统调用execve返回用户态)发现自己是蝴蝶(被execve加载的可执行程序)。
5.浅析动态链接的可执行程序的装载
- 动态链接的过程中,内核做了什么
(1)可执行程序需要依赖动态链接库,而这个动态链接库可能会依赖其他的库,这样形成了一个关系图——动态链接库会生成依赖树。
(2)依赖动态链接器进行加载库并进行解析(这就是一个图的遍历),装载所有需要的动态链接库;之后ld将CPU的控制权交给可执行程序
(3)动态链接的过程主要是动态链接器在起作用,而不是内核完成的。
第二部分 实验部分
1、更新内核
2、查看test.c文件,更新如图所示代码。
3、在exec函数中执行了动态链接代码。
4、查看makefile内容,添加对hello程序的处理代码。并修改相关代码。
5、图为Menu系统运行的结果
6、gdb调试过程中,执行到start_ thread,查看new_ ip的内容。
如上图所示,new_ ip中存储的地址就是静态链接中程序的进入地址。
7、图为建立新堆栈的具体步骤
总结:
阐明对“Linux内核装载和启动一个可执行程序”的理解。
- linux内核首先经过预处理、编译、汇编生成一个可执行文件。
- 然后使用链接器对该可执行程序进行链接,生成可执行程序。
- 在连接的过程中,又分为动态链接和静态链接,动态链接过程主要是有链接器ld完成的,而不是内核完成的。
宋宸宁+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程、http://mooc.study.163.com/course/USTC-1000029000
Linux内核设计第七周 ——可执行程序的装载的更多相关文章
- linux内核设计第七周——可执行程序的装载
- Linux内核分析第七周———可执行程序的装载
Linux内核分析第七周---可执行程序的装载 李雪琦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/US ...
- Linux内核分析 第七周 可执行程序的装载
张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第七 ...
- 20135327郭皓--Linux内核分析第七周 可执行程序的装载
第七周 可执行程序的装载 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 ...
- LINUX内核分析第七周——可执行程序的装载
一.得到一个可执行程序 1. 预处理.编译.链接 gcc hello.c -o hello.exe gcc编译源代码生成最终可执行的二进制程序,GCC后台隐含执行了四个阶段步骤. 预处理 => ...
- Linux内核设计第七周学习总结 Linux内核如何装载和启动一个可执行程序
陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 实验目的 使用gdb跟踪s ...
- LINUX内核分析第七周学习总结:可执行程序的装载
LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序
Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...
- Linux内核分析——第七周学习笔记20135308
第七周 可执行程序的装载 一.预处理.编译.链接和目标文件的格式 1.可执行程序是怎么来的 C代码—>预处理—>汇编代码—>目标代码—>可执行文件 .asm汇编代码 .o目标码 ...
随机推荐
- 如何让Ue4画面产生振动效果
可以使用CameraShake蓝图类,对应的C++类为UCameraShake. 这个类是通过修改PlayerController来达到效果
- C# 词法分析器(三)正则表达式
系列导航 (一)词法分析介绍 (二)输入缓冲和代码定位 (三)正则表达式 (四)构造 NFA (五)转换 DFA (六)构造词法分析器 (七)总结 正则表达式是一种描述词素的重要表示方法.虽然正则表达 ...
- datagrid点击标题进行排序
步骤: 1.页面上首先设置datagrid的AllowSorting="true",以及指定排序方法OnSortCommand="DataGrid1_SortComman ...
- BZOJ3084 : [Algorithmic Engagements 2011]The Shortest Period
枚举答案长度$L$,设$A$和$B$分别为第一个循环节和反串的第一个循环节. 1.坏点不在$A$,那么可以暴力匹配检验. 2.坏点不在$B$,那么把串翻转后不在$A$中,转化为1. 3.坏点在$A$和 ...
- BZOJ2061 : Country
记忆化搜索,设$f[i][j]$表示符号$i$一开始kmp指针为$j$,中间匹配了多少次,$g[i][j]$则表示匹配结束后kmp指针的位置. 时间复杂度$O(nl^2)$. #include< ...
- Codeforces Round #243 (Div. 2) A. Sereja and Mugs
#include <iostream> #include <vector> #include <algorithm> #include <numeric> ...
- 【BZOJ1003】1003: [ZJOI2006]物流运输trans SPFA+DP
Description 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格 ...
- XML CDATA节点
术语CDATA指字符数据.CDATA定义为文本块,但识别为标记. 预定义实体的同位素;,密度,并且与放大器;需要打字并且通常难以阅读的标记.在这种情况下,CDATA部分都可以使用.通过使用CDATA节 ...
- 在Eclipse中使用JSHint检查JavaScript
之前使用 JSlint 来校验 JavaScript 代码,发现灵活性不够,因此改用 JSHint.按照官方的说法,JSHint 是一个社区驱动(community-driven)的工具,用于检测Ja ...
- Eclipse安装nodeclipse插件
1. Start Eclipse, then select Help > Install New Software... 2. Enter the update site URL into th ...