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内核分析》第七周笔记 可执行程序的装载的更多相关文章

  1. Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序

    Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...

  2. LINUX内核分析第七周学习总结:可执行程序的装载

    LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  3. Linux内核分析 第七周 可执行程序的装载

    张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第七 ...

  4. Linux内核分析第七周———可执行程序的装载

    Linux内核分析第七周---可执行程序的装载 李雪琦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/US ...

  5. LINUX内核分析第七周学习总结

    LINUX内核分析第七周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...

  6. LINUX内核分析第七周学习总结——可执行程序的装载

    LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  7. 20135327郭皓--Linux内核分析第七周 可执行程序的装载

    第七周 可执行程序的装载 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 ...

  8. linux内核分析 第七周

    一.课堂相关 (一)预处理.编译.链接和目标文件的格式 1.可执行程序是怎么得来的 C代码--预处理--汇编代码--目标代码--可执行文件 预处理负责把include的文件包含进来及宏替换工作. he ...

  9. "Linux内核分析"第七周

    可执行程序的装载 张文俊+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.预 ...

随机推荐

  1. windows系统安装python3.6.3和python3.7.0

    一.装备好从官网下载的python软件包(3.6.3和3.7.0) 二.先安装python3.6.3 1.运行python3.6.3文件 2.选择默认 3.下一步,等待安装 4.检查是否安装成功 ,安 ...

  2. 团队项目管理:Github项目误删恢复记录

    参考: 准备更换git托管,如何迁移原git仓库 Github项目误删恢复记录 今天正常上线打卡,发现组织的线上Github仓库被误删了..本来是一场悲剧,所幸在本地的垃圾箱中翻出了还没有删除的本地仓 ...

  3. Java实现数据库的读写分离

    引言 1.读写分离:可以通过Spring提供的AbstractRoutingDataSource类,重写determineCurrentLookupKey方法,实现动态切换数据源的功能:读写分离可以有 ...

  4. 计算机基础-BIOS

    BIOS--硬件和软件的纽带(Basic Input Output System) 1.含义:基本的输入输出系统,它是一组固化到计算机内主板上的一个ROM存储芯片上的程序 2.性质:它保存着计算机最重 ...

  5. 【CSS3】transition过渡和animation动画

    转自:http://blog.csdn.net/XIAOZHUXMEN/article/details/52003135 写在前面的话: 最近写css动画发现把tansition和animation弄 ...

  6. centos7下安装docker(12.4容器如何与外部进行通信)

    1.容器如何访问外部 前面我们做了很多试验:只要host能连外网,使用默认bridge(docker0)创建得容器就能访问外网,那么容器是怎样访问外网的呢? 注:这里的外网不仅是internet,包括 ...

  7. 高精度(x ,/, +, -, %)良心模板

    该模板不是本人的,但是该是加了个头文件哒.不然在某个oj上编译错误. #include <iostream> #include <string> #include <cs ...

  8. 【转】字符编码笔记:ASCII、Unicode、UTF-8 和 Base64

    1. ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态(-128~127),这被称为一 ...

  9. Java字节码里的invoke操作&&编译时的静态绑定与动态绑定

    一个一直运行正常的应用突然无法运行了.在类库被更新之后,返回下面的错误. Exception in thread "main" java.lang.NoSuchMethodErro ...

  10. 一、java虚拟机内存区域

    内存区域 java虚拟机在java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.java虚拟机规范将JVM管理的内存分为:程序计数器.本地方法栈.Java虚拟机栈.方法区.Java堆.如下 ...