《Linux内核分析》第七周笔记 可执行程序的装载
20135132陈雨鑫 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”
一、预处理、编译和链接和目标文件的格式
1、可执行程序是怎么来的?
理解编译链接的过程和ELF可执行文件格式

过程:
.c文件汇编成汇编代码.asm,
再汇编成目标码.o,
链接成可执行文件a.out,
最后可执行文件就可以加载到内存中执行。
2、目标文件的格式ELF
1)主要有三种目标文件
可重定位文件、可执行文件、共享文件

2)ELF文件加载到内存是如何加载的呢?
代码、数据都加载到内存中,默认ELF文件从0x开始加载,开始加载的是头部,会有一些信息,所以入口地址0x(这个地方就是程序的实际入口,可执行文件加载到内存中开始执行的第一行代码从这里开始)
3、静态链接的ELF可执行文件和进程的地址空间

入口地址为0x8048*00
二、可执行程序、共享库和动态链接
1、使用exec*库函数加载一个可执行文件
(1)动态链接分为可执行程序转载时动态链接和运行时动态链接
1)在linux下动态链接的文件是.so
2)libshlibexample.so文件(生成一个共享库文件)
libdllibexample.so(生成可动态加载文件)
(2)若是静态链接的,elf_entry就是指向可执行文件里边规定的那个头部,即main函数对应的位置,若这个可执行文件是需要依赖其它动态链接库的话,则elf_entry就是指向动态链接器的起点
2、
(1)execve:当前的可执行程序在执行execve这个系统调用的时候,它陷入到内核态,在内核态里它用这个execve加载的这个可执行文件把当前进程的可执行程序给覆盖掉,当execve这个系统调用返回的时候,返回的不是原来的那个可执行程序了,而是新的可执行程序了,它返回的是新的可执行程序的起点,即main函数大致的位置
(2)ELF文件加载到内存是如何加载的呢?
代码、数据都加载到内存中,默认ELF文件从0x开始加载,开始加载的是头部,会有一些信息,所以入口地址0x(这个地方就是程序的实际入口,可执行文件加载到内存中开始执行的第一行代码从这里开始)
•命令行参数和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的封装例程
命令行参数和环境串都放在用户态堆栈中

装载时动态链接和运行时动态链接应用举例
动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。
•准备.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 -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文件
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的相关信息,只是指明了-ldl
1.$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
2.$ export LD_LIBRARY_PATH=$PWD #将当前目录加入默认路径,否则main找不到依赖的库文件,当然也可以将库文件copy到默认路径下。
3.$ ./main
4.This is a Main program!
5.Calling SharedLibApi() function of libshlibexample.so!
6.This is a shared libary!
7.Calling DynamicalLoadingLibApi() function of libdllibexample.so!
8.This is a Dynamical Loading libary!
三、可执行程序的装载
1.可执行程序的装载相关关键问题分析
(1)可执行程序的装载实际上相当于系统调用。execve系统调用比较特殊。
(2)sys_execve内核处理过程:
- do_execve -> do_execve_common -> exec_binprm
- 最后根据给出的文件名加载文件头部信息寻找对应的文件格式处理模块。
(3)fmt->load_binary(bprm):用来解析ELF格式文件的执行的位置,这个位置是load_elf_binary。
(4)内核是如何支持多种不同可执行文件格式的?
本质上是观察者模式,通过修改内核堆栈中EIP的值作为新程序的起点。
(5)庄周(调用execve的可执行程序)入睡(调用execve陷入内核),醒来(系统调用execve返回用户态)发现自己是蝴蝶(被execve加载的可执行程序)。
2. sys_execve的内部处理过程
do_ execve调用do_ execve_ common,do_ execve_ common主要依靠exec_ binprm,其中重要的函数:search_binary_handler(bprm)。
- 打开file文件,找到文件头部,把命令行参数和环境变量copy到结构体中:
retval=copy_strings(bprm->envc, envp, bprm); - 寻找打开的可执行文件处理函数:
ret= search_binary_handler(bprm); - 寻找能够解析当前可执行文件的模块,load_ binary加载这个模块,实际调用的是binfmt_ elf.c:
retval=fmt->load_binary(bprm); - ELF可执行文件会被默认映射到0X8048000这个地址;
- 需要动态链接的可执行文件先加载连接器ld;否则直接把ELF文件entry地址赋值给entry;
- start_ thread(regs, elf_ entry, bprm->p)将CPU控制权交给ld来加载依赖库并完成动态链接。对于静态链接的文件elf_entry是新程序执行的起点
通过实验用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证对Linux系统加载可执行程序所需处理过程的理解
实验过程:
把menu删掉,重新克隆一份

进入test.c中查看:
进入makefile中查看:

开始使用gdb跟踪:


new_ip是返回到用户态的第一条指令的地址 看该可执行程序的入口点地址,发现和new_ip的位置是一样的。
退出调试状态,输入redelf -h hello可以查看hello的EIF头部:

四、浅谈Linux内核装载和启动一个可执行程序
检查ELF可执行文件的有效性,寻找动态链接的“.interp”段,设置动态链接器路径(与动态链接有关),根据ELF可执行文件的程序头表的描述,对ELF文件进行映射,比如代码,数据,只读数据,代码、数据都加载到内存中,默认ELF文件从0x开始加载,开始加载的是头部,会有一些信息,所以入口地址0x(这个地方就是程序的实际入口,可执行文件加载到内存中开始执行的第一行代码从这里开始),初始化ELF进程环境,比如进程启动时EDX寄存器的地址应该是DT_FINI的地址(和动态链接有关),将系统调用的返回地址修改为ELF可执行文件的入口,这个入口点取决于程序的链接方式,对于静态链接的可执行文件,若是静态链接的,elf_entry就是指向可执行文件里边规定的那个头部,即main函数对应的位置,若这个可执行文件是需要依赖其它动态链接库的话,则elf_entry就是指向动态链接器的起点。
《Linux内核分析》第七周笔记 可执行程序的装载的更多相关文章
- Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序
Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...
- LINUX内核分析第七周学习总结:可执行程序的装载
LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- Linux内核分析 第七周 可执行程序的装载
张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第七 ...
- Linux内核分析第七周———可执行程序的装载
Linux内核分析第七周---可执行程序的装载 李雪琦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/US ...
- LINUX内核分析第七周学习总结
LINUX内核分析第七周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...
- LINUX内核分析第七周学习总结——可执行程序的装载
LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- 20135327郭皓--Linux内核分析第七周 可执行程序的装载
第七周 可执行程序的装载 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 ...
- linux内核分析 第七周
一.课堂相关 (一)预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 C代码--预处理--汇编代码--目标代码--可执行文件 预处理负责把include的文件包含进来及宏替换工作. he ...
- "Linux内核分析"第七周
可执行程序的装载 张文俊+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.预 ...
随机推荐
- redis数据库的简单介绍
NoSQL:一类新出现的数据库(not only sql) 泛指非关系型的数据库 不支持SQL语法 存储结构跟传统关系型数据库中的那种关系表完全不同,nosql中存储的数据都是KV形式 NoSQL的世 ...
- python学习-判断是否是IP地址
1.使用正则表达式 首先分析IP地址的组成,十进制的合法IP地址由32位数字组成 使用.分割开 每个分组可出现的情况: 第一个分组: 1-9:一位数字 10-99:两位数字 100-199:三位数字且 ...
- 管道流_PipedInputStream与PipedOutputStream
输入和输出可以直接进行连接,通过结合线程使用(一个线程用于写,另一个用于读,因为管道输入流(读)是要读取管道输出流的数据的,又因为输入流中的read方法是阻塞式的,当两个流在同一个线程中时,输入流的r ...
- Java日志框架Slf4j+Log4j入门
一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...
- IOS - 执行时 (经常使用函数)
能够通过NSObject的一些方法获取运行时信息或动态运行一些消息: /*Returns a Boolean value that indicates whether the receiving cl ...
- Tribonacci UVA - 12470 (简单的斐波拉契数列)(矩阵快速幂)
题意:a1=0;a2=1;a3=2; a(n)=a(n-1)+a(n-2)+a(n-3); 求a(n) 思路:矩阵快速幂 #include<cstdio> #include<cst ...
- kubernetes statefulset kafka 部署后, 外部访问超时问题解决
k8s 内部的kafka要映射到外网,直接把 kafka 通过 expose 把pod 映射成服务,使用nodeport 连接,出现超时问题, 解决思路: 1. 查看zk中,kafka的注册信息,P ...
- WebService之nginx+(php-fpm)结构模型剖析及优化
随着php脚本语言使用的普及,目前webserice服务大部分都在用nginx+(php-fpm)的结构,了解了其工作过程后才可以在各个方面想办法做调整优化和故障排查,从以下几点总结一下这种模型. 一 ...
- win10下乌龟git安装和使用(转)
文章转自http://blog.csdn.net/jdsjlzx/article/details/51098588 一.安装git for windows 首先下载Git for windows客户端 ...
- 在MongoDB数据库中查询数据(上)
在MongoDB数据库中查询数据(上) 在MongoDB数据库中,可以使用Collection对象的find方法从一个集合中查询多个数据文档,find方法使用方法如下所示: collection.fi ...