专栏首页MyPanda的学习笔记编译、链接到载入、运行的大致过程----3.载入

编译、链接到载入、运行的大致过程----3.载入

在Linux下,elf文件有三类,分别是: relocatable , shared object, executable. 见下面的例子:

[root@www ~]# file main.obj  /usr/bin/cat /lib/librt-2.17.so 
main.obj:           ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
/usr/bin/cat:       ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=8ac8b57ae50762a4a0480486839107e87b3c284d, stripped
/lib/librt-2.17.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=e9050e3a9543278c0fe04e541644287e67356ff1, for GNU/Linux 2.6.32, not stripped
[root@www ~]# 

其中的relocatable的文件,就是编译后生成的“目标文件”; 而 "shared object", 就是Linux下的动态链接库文件; executable 文件是 可以直接运行的 程序文件; 在这里要注意的是: 部分“shared object” 也是可以直接运行的,并不是所有的“动态链接库文件” 都不可以运行;

从上面的结果中还可以看到: executable的elf文件最后有一个“stripped” 的说明,而另外两种elf文件所对应的是"not stripped", 这表示什么意思呢?

编译的时候,每个文件中涉及到的对其他文件中函数的引用,都会用符号来进行表示,这是因为 当前文件文件中无法确定被引用函数的地址,所以就采用了符号来表示;而在链接的时候,会进行 地址重载,这时候,被引用的符号就被解析成了地址,并生成了最终的程序文件;而"stripped" 就表示 符号 已经被解析为 程序虚拟地址,而"not stripped" 就表示 符号没有被解析为 程序虚拟地址;所以 编译后的文件,其属于"not stripped"的类型,而 链接后的文件又分为两类: "shared object" 类型的文件,一般对外提供 程序接口的,这些对外提供的接口是以符号的方式提供的,而不是以 程序虚拟地址来提供,毕竟我们写代码的时候调用的都是函数名称,而不是用一串地址来调用的;所以 "shared object"的程序是 "not stripped"的,但是也有"shared object"是stripped, 而“executable ” 的elf文件,因为并不对外提供函数的接口,所以其符号 在编译的过程中已经被替换为程序虚拟地址;因此“executable” 的elf文件是"stripped"的;

程序的载入过程:

当我们运行一个程序的时候,操作系统打开程序文件做完相应的处理后,会把控制权交给 程序解释器(比如:/lib/ld-linux.so.2 就是程序解释器的一种 ), 程序解释器根据程序的头部信息,生成程序的 内存虚拟地址的入口,并从程序需要的动态链接库文件中查找对应的符号地址,这些找到的符号地址,被加载器进行了重定向,然后加入到当前程序的虚拟内存地址空间中合适的位置,从而完成 当前程序中的符号解析,至此完成程序虚拟地址到 内存虚拟地址的转换工作;然后程序解释器创建程序的进程映像,创建进程映像之后,会把控制权交给程序的入口地址,从而开始程序的执行;

在这个过程中:

1. 无论是程序本身,还是其依赖的动态链接库,被载入的都是 type=LOAD的segment;其他segment不会在程序的正常加载过程中被载入内存; 2. 载入内存后,在运行时候,访问的地址是: 内存虚拟地址。这个内存虚拟地址 并不是 “程序虚拟地址”,也不是“内存物理地址”;但是 这三者之间是有关系的: A. “程序虚拟地址“是源代码被编译链接之后生成的;这其中要关注的是type=LOAD的segment 对应的地址范围,因为这些segment会被加载到内存;通过 readelf -l 命令来查看segment的地址范围,也可以通过 readelf -S 来获取对应section的地址,从而计算出segment的地址; B. “内存虚拟地址” 是程序被加载后,其进程映像对应的 虚拟地址,它一般是由加载器分配的;如果程序运行过程中发生了或者启动时候发生了常见的segment报错,那么这个segment 地址一般都是 "内存虚拟地址",查看特定文件的内存虚拟地址可以通过命令: cat /proc/{PID_VALUE}/maps | grep FILE_PATH 来获得; C. type=LOAD的segment的地址是以程序虚拟地址来表示的 ,对于executable文件来说,它和内存虚拟地址是一致的,因为编译后的程序中的部分代码可能是地址相关的,所以为了保证 程序能够可靠运行,一般对于"executable"的elf文件来说,其 内存虚拟地址 和程序虚拟地址是相同的, 而 "shared object"的程序虚拟地址(TYPE=LOAD的segment) 总是从0开始,这个地址 和 内存虚拟地址是不同的,即便是 同一个“shared object” 文件,在不同的进程中 映射对应的 内存虚拟地址也是不同的,因为这个地址是 加载器 分配的. 这一点在ldd 命令的结果中体现的非常明显,我们知道ldd的输出结果表示对相应的共享库的依赖,其输出结果的最后一节是一个地址,而这个地址就是:内存虚拟地址;每次用ldd去查看其依赖的时候,这个地址都是发生变化的,因为是 加载器分配的; D. ”内存虚拟地址“和“程序虚拟地址” 都是虚拟地址,并且都采用分页的机制(默认page大小为4KB,也就是0x1000对齐),所以 对于 type=LOAD的segment 尽管在 “程序虚拟地址” 和“内存虚拟地址” 可能并不相同,但是对应的segment 的大小一定是相同的; E. “程序虚拟地址” 通过分析文件获得,依赖于程序文件;而“内存虚拟地址” 是 程序加载器 分配的,所以每次运行程序可能都会发生变化,实际上没有不发生变化的,程序的运行访问的都是"内存虚拟地址" ,所以"内存虚拟地址" 到 “内存物理地址”之间存在mapping, 这个mapping的工作是操作系统来完成的;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • sed与awk处理区间匹配的问题总结---1

    正常情况下,将要处理的行读入pattern space(缓存的一种),然后在pattern space中进行处理,然后再将pattern space中的内容取回...

    qsjs
  • 分享一个shell脚本用于“基于已安装的rpm包,创建tar压缩包”

    有时候,我们不想在系统中安装rpm包,但是又需要这个rpm包的功能,那么可否实现呢? 这个需求是可以实现的,当我们用tar包去安装这个功能的时候就可以实现了....

    qsjs
  • python中更新字典对象

    最近用python做了一个小工具,涉及到如下的字典操作,特做笔记如下: 1. 用update方法更新字典: 用字典的update方法,这时候传递给updat...

    qsjs
  • 程序猿之间的各种鄙视链,你是否也曾经被屌?

    程序员——是一个集思维、情商、行为都异于其他传统岗位的群体。清高自傲、闷骚、会修电脑、宅、不善交际、几百年不洗的衬衫牛仔双肩包…,代表着程序员这个群体的鲜明标签...

    Java技术栈
  • 探索 PHP 与 Vue 通用直出模板方案

    我们通常说的“页面直出”,其实就是服务端渲染(SSR, Server-Side Render)。最初的 JS SPA 方案有个常见的问题,就是脚本没有加载执行完...

    贤羽
  • Android学习之菜单

    android中包含多种菜单,本例带来的是选项菜单和上下文菜单。 1.选项菜单 在android中,开发者可以在xml文档中部署所要添加的菜单,在后台调用即可。...

    水击三千
  • Android应用界面开发——简单控件和Activity间传递数据

    要想开发一个Android App,开发环境是必不可少的,所以学习之前应该先搭建环境,环境如下:

    trampcr
  • Python爬虫-百度模拟登录(一)

    百度模拟登录终于要呈现在大家眼前了,最近比较忙,晚上又得早点休息,这篇文章写了好几天才完成。这个成功以后,我打算试试百度网盘的其他接口实现。看看能不能把服务器文...

    星星在线
  • JupyterLab: 神器Jupyter Notebook的进化版,结合传统编辑器优势,体验更完美

    近年来,Jupyter Notebook作为一种以交互和良好的布局方式显示代码和结果的工具受到了广泛的关注。它当然有助于降低编程的门槛,并有助于教学,因为输入和...

    HuangWeiAI
  • 【死磕Sharding-jdbc】---group by结果合并(1)

    在sharding-jdbc源码之结果合并中已经分析了OrderByStreamResultSetMerger、LimitDecoratorResultSetM...

    用户1655470

扫码关注云+社区

领取腾讯云代金券