可执行程序工作原理

ELF目标文件格式

1、目标文件(ABI,应用程序二进制接口):编译器生成的文件。

2、目标文件的格式:out格式、COFF格式、PE(windows)格式、ELF(Linux)格式。

3、ELF(Executable and Linkable Format)即可执行和可链接的格式,是一个目标文件格式的标准。ELF格式的文件用于存储Linux程序。

4、ELF文件的3钟类型:可重定位文件、可执行文件、共享目标文件。

  • 可重定位文件:这种一般是中间文件,还需要继续处理。由汇编器和编译器创建,一个源代码文件会生成一个可重定位文件。文件中保存着代码和适当的数据,用来和其他的目标文件一起来创建一个可执行文件、静态库文件或者共享目标文件(即动态库文件)。如Linux下.c文件都会生成一个同名的.o文件,这就是可重定位目标文件。
  • 可执行文件:一般由多个可重定位文件结合生成,是完成了所有重定位工作和符号解析(除了运行时解析的共享库符号)的文件,文件中保存着一个用来执行的程序。
  • 共享目标文件:共享库,是指可以被可执行文件或其他库文件使用的目标文件,例如标准C的库文件libc.so。可以简单理解为没有主函数main的“可执行”文件,只有一堆函数可供其他可执行文件调用。Linux下共享库后缀为.so文件。

5、ELF文件作用:ELF文件参与程序的链接(建立一个程序)和程序的执行(运行一个程序)。

  • 如果用于编译和链接(可重定位文件),编译器和链接器将把ELF文件看作节的集合,所有节由节头表描述,程序头表可选。
  • 如果用于加载执行(可执行文件),加载器将把ELF文件看作程序头表描述的段的集合,一个段可能包含多个节和节头表可选。
  • 如果是共享文件,则两者都含有。

6、ELF格式

主体是各种节,还有描述这些节属性的信息(Program header table和Section header table),以及ELF文件的整体描述信息(ELF header)。

  • ELF Header:描述该文件的组织情况以及本ELF文件的属性信息,其中最重要的是段头表(Program header table)和节头表(Section header table)
  • Section Header:节头表是由Section Header组成的表。用于链接的目标文件必须包含节区头部表,其他目标文件有没有这个表皆可。
  • Program Header:段头表和创建进程相关。

程序编译

  • 预处理:gcc -E hello.c -o hello.i
  • 编译:gcc -S hello.i -o hello.s -m32
  • 汇编:gcc -c hello.s -o hello.o -m32
  • 链接:gcc hello.o -o hello -m32 -static

预处理和编译完的文件均为文本文件,可用任意编辑工具查看。汇编和链接完的文件均为ELF文件。

链接与库

1、链接--从过程上讲:符号解析、重定位。根据链接时机:静态链接、动态链接。编译器默认使用动态链接,动态链接分为两种:可执行程序装载时动态链接、运行时动态链接。

2、有定义:函数对应的机器指令地址在当前文件中(有明确的地址)。

符号解析:编译器到其他的共享库中找到无定义符号对应的机器指令片段,然后把该片机器指令与hello.o拼接到一起,生成可执行文件hello。符号解析是一个递归过程。

重定位:把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程,是实现多道程序在内存中同时运行的基础。分如下两步:

  • 重定位节和符号定义;
  • 重定位节中的符号引用。

3、符号表的查看方法:objdump –t xxx.o或readelf –s xxx.o

可重定位表的查看方法:readelf –r xxx.o

查看ELF可执行文件收不信息:readelf –h hello.m32.static(文件名)

程序装载

1、exec函数:execl、execlp、execle、execv、execvp、execve六个用以执行一个可执行文件的函数。

2、调用关系:sys_execve() -> do_execve() -> do_execve_common() -> exec_binprm() -> search_binary_handler() -> load_elf_binary() -> start_thread()

3、fork与execve的区别和联系

  • 都是比较特殊的系统调用
  • fork在陷入内核态后有两次返回,第一次返回到原来父进程的位置继续向下执行,第二次是在子进程返回,这次会返回到ret_from_fork,之后正常返回用户态。
  • execve在执行时陷入内核态,在内核中调用execve加载的可执行文件把当前进程的可执行程序给覆盖了,当其返回时,返回的已经不是原来的那个可执行程序了,而是新的程序,返回的是新的可执行程序执行的起点,即main函数的大致位置(一般地址为0x8048xxx,由编译器设定)。

使用gdb跟踪execve系统调用内核处理函数sys_execve

1、删除并克隆一个新的menu,用test_exec.c将test.c覆盖,然后重新编译rootfs。

cd LinuxKernel
rm -rf menu
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs

除了增加了execlp函数以外,还在Makefile中编译了hello.c,然后在生成根文件系统时把int和hello都放到rootfs.img中。

2、利用help命令查看,并执行exec命令

查看test.c,发现增加了exec系统调用的代码。



3、启动内核到调试状态,建立连接,在sys_exec、load_elf_binary、start_thread处设置断点

按“c”继续执行到sys_exec时输入exec命令,结果运行到sys_exec是停住。

继续执行到start_thread时,因为是静态链接,“elf_entry”指向可执行文件中定义的入口地址。使用“po new_ip”指令打印其指向的地址,“new_ip”是返回到用户态的 第一条指令的地址,使用“readelf -h hello”命令查看hello的elf头部,可以看到定义的入口地址与“new_ip”所指向的地址一致。



总结

可执行文件开始执行的起点在修改调用execve系统调用时压入内核堆栈的EIP寄存器的值,此时标志着当前进程的可执行文件已经被完全替换为新的可执行文件,但实际开始执行可执行文件中的指令还需要等到执行可执行文件中定义的入口地址的位置,一般地址为0x8048xxx的位置。通过修改内核堆栈中EIP寄存器的值作为新程序的起点,让execve系统调用返回到用户态时执行新程序。

Linux内核如何支持多种不同的可执行文件格式?

static int init_elf_binfmt(void)
{
register_binfmt(&elf_format); //把变量注册进内核链表,在链表里查找文件的格式
return 0;
}

2019-2020-1 20199319《Linux内核原理与分析》第八周作业的更多相关文章

  1. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  3. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  4. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

  5. 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  6. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

  8. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

  10. 2018-2019-1 20189221《Linux内核原理与分析》第二周作业

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. spring整合mybatis(代理的方式)【我】

    创建项目等同上一篇非代理方式随笔,只说不一样的部分: 项目结构主要是多了下面红框部分: 配置文件: 主要是dao配置文件中多了Mapper代理java类的扫描包路径: applicationConte ...

  2. Windows下查找文件或文件夹被哪个进程占用

    Linux下我们可以使用lsof +D /filepath/,查看到文件被那些进程占用. windows下也会经常遇到文件夹或文件无法删除或无法访问的问题,使用“资源监视器”可以找到占用的进程,可以尝 ...

  3. Opencv中的WMesh

    费了半天劲,终于把这个WMesh类搞懂了,可惜效果不佳,比Matlab中的mesh差多了. 使用WMesh前,需要有一个Mesh对象,Mesh是三维数据点的基本几何信息.颜色信息.索引信息等集成的对象 ...

  4. Skywalking部署+NetCore客户端

    一.介绍 应用官方的说法:Apache SkyWalking是观察性分析平台和应用性能管理系统.提供分布式追踪.服务网格遥测分析.度量聚合和可视化一体化解决方案 GitHub地址:https://gi ...

  5. HNU_团队项目_数据库设计感想_个人感想

    数据库设计感想  个人的一点心得体会 最重要的放在最前面——讨论开会时的123经验 开会前对会议目的及方式要有所考虑: 不要随意无目的开会: 遵守时间,控制会议时间长度: 会议主持人要维持会议只需,有 ...

  6. Python程序猿面试杂谈

    不同的互联网公司面试环节不尽相同,总体而言,一般有技术面(1-3轮).leader面(组长/总监/CTO/CEO...).hr面,面试轮数视公司规模和公司实际具体情况而定.下文将就面试的不同环节阐述下 ...

  7. Kinect数据

    原文链接 Kinect V1 和 V2 比较 Kinect V1 和 V2 的外观比较 Kinect V1 和 V2 的参数比较 Kinect V1 和 V2 随距离增加的误差分布 Kinect V1 ...

  8. powerDesigner连接数据库连接失败

    powerDesigner连接数据库总是提示连接失败 原因是这个软件不能使用64位的jdk只能使用32位的jdk 在软件安装文件夹根目录下创建start.bat Set JAVA_HOME=E:\Ja ...

  9. 合并两个排序的链表递归和非递归C++实现

    题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,要求合成后的链表满足单调不减规则. 1.分析 已知输入的两个链表递增有序,要使输出的链表依然递增有序,可以依次从输入的两个链表中挑选最小的 ...

  10. 解决Eclipse发布到Tomcat丢失依赖jar包的问题

    解决Eclipse发布到Tomcat丢失依赖jar包的问题 如果jar文件是以外部依赖的形式导入的.Eclipse将web项目发布到Tomcat时,是不会自动发布这些依赖的. 可以通过Eclipse在 ...