目标文件是指:编译器编译源代码后生成的文件,那么目标文件里面到底存放的是什么呢?或者说我们的源代码在经过编译以后是怎么样存储的呢?

目标文件从结构上将,它是已经编译后的可执行文件格式,只是好没有经过链接的过程,其中可能有些符号或有些地址还没有被调整。其实,目标文件本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。

可执行文件格式涵盖了程序的编译、链接、装载和执行的各个方面。了解可执行文件的格式对认识系统,了解集成编译器背后的运行机理,还是很有好处的。

1.目标文件的格式是什么样的?

现在PC平台流行的可执行文件格式(Executable),主要是Windows下的PE(Portable Executable)和linux的ELF (Executable Linkable Format),他们都是COFF(Common File Format)格式的变种。目标文件就是源代码编译后为进行链接的那些中间文件(Windows下面为.obj文件;Linux下面为.o文件),它和可执行文件的内容和结构很相似,所以一般和可执行文件采用同一种格式进行存储。从广义上来讲,目标文件与可执行文件的格式其实几乎是一模一样的,所以,我们可以广义的将目标文件和可执行文件看成是同一种类型的文件。在Windows下,我们把目标文件和可执行文件都统一称为PE-COFF文件,在Linux下,我们把它们统称为ELF文件。
当然,事情没有这么简单!不光是可执行文件(Windows下面的.exe和Linux下面的ELF文件)按照可执行文件格式存储。动态链接库(DLL,dynamic linking library)[Windows下面的.dll文件和Linux下面的.a文件]以及静态链接库(Static linking Library)[Windows下面的.lib文件和Linux下面的.a文件]都是按照可执行文件格式存储的。只不过,在Windows平台下,他们按照PE-COFF格式存储,而在Linux平台下按照ELF格式进行储存。
ELF文件标准里面把系统中采用ELF格式的文件归为以下四类:
ELF文件类型 说明 实例
可重定位文件
Relocatable File
这类文件包含了代码和数据,可以被用来链接成可执行文件
或共享目标文件,静态链接库也归属于这一类
Linux的.o文件
Windows下的.obj文件
可执行文件
Executable File
这类文件包含了可以直接执行的程序,它的代表就是ELF文
件,他们一般都没有扩展名
比如bin/bash文件
Windows的.exe文件
共享目标文件
shared Object File
这种文件包含了代码和数据,可以在以下两种情况下使用,一
种是链接器可以直接使用这种文件跟其他的可重定位文件和共享
目标文件链接,产生新的目标文件。第二种是动态链接器
可以将几个这样的共享目标文件与可执行文件结合,
作为进程映射的一部分来运行。
Linux的.so文件
Windows下面的.dll文件
核心转储文件
Core Dump File
当进程意外终止时,系统可以将该进程的地址空间的
内容及终止时的一些其他信息转储到核心转储文件中
Linux下面的core dump

2.目标文件与可执行文件格式的小历史

目标文件与可执行文件格式与操作系统和编译器密切相关,所以不同的系统平台下会有不同的格式,但这些格式又大同小异,目标文件格式与可执行文件格式的历史几乎就是操作系统的发展史。
COFF是由Unix System VRelease 3首先提出并且使用的文件规范,后来微软公司基于COFF格式,制定了PE格式标准,并将其用于当时的Windows NT系统。System VRelease 4在COFF的基础上引入了ELF格式,目前流行的Linux系统也是以ELF作为基本的可执行文件格式。这也能解释为什么目前PE和ELF如此相似的主要原因,因为他们都是来源于同一种可执行文件格式COFF。

3.目标文件到底是什么样的?

猜也可以猜到,目标文件中的内容至少有编译后的机器指令代码、数据。没错,除了这些内容以外,目标文件中还包含了链接时所需要的一些信息,比如符号表、调试信息、字符串等。一般目标文件将这些信息按不同的属性,以“节”(section)的形式存储,有时候也叫“段”(segment),在一般情况下,他们都表示一个一定长度的区域,基本上不加以区别,唯一的区别是在ELF的链接视图和装载视图的时候,需要特别注意。
程序源代码编译后的机器指令经常放在代码段(Code Section)里,代码段常见的字有“.code”和“.text”;全局变量和局部变量数据经常放在数据段(Data Section),数据段的一段名字都叫“.data”。下面是一个简单的程序被编译成目标后的结构,如下图所示:
假设上图的可执行文件格式是ELF,从图中可以看到,ELF文件的开头是一个“文件头”,他描述了整个文件的文件属性,包括文件是否可执行、是静态链接还是动态链接以及入口地址(如果是可执行文件)、目标硬件、目标操作系统等信息。头文件包含一个段表(Section Table),段表事实是一个描述文件中各个段的数组。段表描述了文件中各个段在文件中的偏移位置及段的属性,从段表里面可以得到每个段的所有信息。文件头后面就是各个段的内容,比如代码段保存的就是程序的指令,数据段里面保存的就是程序的静态变量等。
从上图我们也能看出,
一般C语言的编译后执行语句都编译成机器代码,保存在.text段;
已初始化的全局变量和局部静态变量都保存在.data段;
未初始化的全局变量和局部静态变量一般放在一个叫.bss的段里。
我们知道未初始化的全局变量和局部静态变量默认值都为零,本来他们也可以被放在.data段里的,但是因为他们都是0,所以为他们在.data段里分配空间并且存放数据0是没有必要的。程序运行的时候他们的确是要占用内存空间的,并且可执行文件必须记录所有未初始化的全局变量和局部静态变量的大小总和,记为“.bss”段。所以,.bss段只是为未初始化的全局变量和局部静态变量预留位置而已。他并没有内容,所以他在文件中也不占据空间

4.程序的指令和数据为什么要分开存放?

总体来说,程序源代码被编译以后主要分成两种段:程序指令和程序数据。代码段属于程序指令,而数据段和.bss段属于程序数据。
这样,我们可能就会产生疑问:为什么要这样麻烦,把程序的指令和数据的存储分开?混杂的放在一个段里面岂不是会更简单?其实数据和指令分段的好处有很多,主要如下:
#1:当程序被装载后,数据和指令分别被映射到两个虚存区域。由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写或只读。这样可以防止程序的指令被有意或无意地改写
#2:对现在的CPU来说,他们有着极为强大的缓存(Cache)体系。由于缓存在现代的计算机中地位非常重要,所以程序必须尽量提高缓存的命中率。指令区和数据区的分离有利于提高程序的局限性。现在CPU的缓存一般都被设计成数据缓存和指令缓存分离,所以程序的指令和数据被分开存放对CPU的缓存命中率提高有好处。
#3:这是最重要的原因!就是当系统中运行着多个改程序的副本时,他们的指令都是一样的,所以内存中只需保存一份该程序的指令部分。对于指令这种制度的区域来说是这样的,对于其他的只读数据也是这样的。比如,很多程序里面带有的图标、图片、文本等资源也是属于可以共享的。当然每个副本进程的数据区域是不一样的,他们是进程私有的。在动态链接的系统中,该种方式可以节省大量内存。比如我们常用的Windows Internet Explorer 7.0 运行起来以后,他的总虚存空间为112844KB,他的私有数据是15944KB,既有96900KB的空间是共享部分!!!

目标文件里面到底有什么(1)?相关推荐

  1. 目标文件里面到底有什么(2)?

    真正了不起的程序员对自己的程序的每一个字节都了如指掌! 前面对于目标文件只是做了概念上的阐述,如果不彻底深入目标文件的具体细节,这样的分析就是泛泛而谈没有意义,也没有深入的理解.就象知道TCP/IP协 ...

  2. 《程序员的自我修养-链接-装载与库》第三章 目标文件里有什么(1)

    目录 0.引言 1.目标文件的格式 1.1 目标文件的格式及ELF文件格式的文件的分类 1.2 目标文件与可执行文件格式的小历史 2.目标文件是什么样的 2.1 程序与目标文件简介 2.2 BSS历史 ...

  3. Lichee(三) Android4.0该产品的目标文件夹,Lichee链接---extract-bsp

    由<Lichee() 在sun4i_crane平台下的编译>介绍了编译lichee的基本情况,我们终于得到了编译后的结果例如以下: out/ ├── android │   ├── bIm ...

  4. 如何修复GIT错误:目标文件为空?

    本文翻译自:how to fix GIT error: object file is empty? When I try to commit changes, I get this error: 当我 ...

  5. build文件_把编译时间加入到目标文件

    出处:https://www.cnblogs.com/pingwen/p/8183728.html 1.问题背景:如何保证发布出去的bin文件是最终测试通过的版本? 一般的来讲,代码到了测试后期,ma ...

  6. 把编译时间加入到目标文件

    原文:https://www.cnblogs.com/pingwen/p/8183728.html 1.问题背景:如何保证发布出去的bin文件是最终测试通过的版本? 一般的来讲,代码到了测试后期,ma ...

  7. linux下几种目标文件的分析

    本文中用到的命令: gcc -c addvec.c  生成可重定位目标文件addvec.o readelf addvec.o -a 读取可重定位目标文件addvec.o gcc -O2 -c main ...

  8. 如何分析linux下的几种目标文件

    为什么80%的码农都做不了架构师?>>>    作者:snsn1984 本文中用到的命令: gcc -c addvec.c 生成可重定位目标文件addvec.o readelf ad ...

  9. 浅显易懂 Makefile 入门 (03)— 目标文件搜索(VPATH 和 vpath 的区别和使用)、隐含规则

    1. 目标文件搜索(VPATH和vpath) 如果需要的文件是存在于不同的路径下(即源文件与 Makefile 文件不在同一个路径下),在编译的时候就用到了 Makefile 中为我们提供的目录搜索文 ...

最新文章

  1. 【廖雪峰python入门笔记】变量
  2. Linux的关机命令和重启命令
  3. 虚拟机nat固定IP上网配置
  4. js一个大盒子中有三个小盒子_寒假预习:一万有多大,数一数估一估,亲身感觉一万有多大...
  5. java servlet练习测试
  6. Mysql笔记-对left join使用的进一步认识(多表查询的正确使用及认识)
  7. 一加7 Pro详细配置规格曝光:售价妥妥破5000
  8. android studio中把c/c++文件编译成.so库(一)
  9. ecshop修改后台登陆密码
  10. GDAL的一个BUG
  11. linux卸载HBA卡驱动
  12. 利用ArcGIS Pro进行时空数据挖掘和可视化呈现
  13. Gmail priority inbox帮助你减少工作量
  14. Faiss从入门到实战精通
  15. 算法:回溯十六 Add and Search Word添加并查找单词
  16. 2019数据安装勾选_Solidworks 2019安装包免费下载附安装教程
  17. 计算机考试祝福,考试前说的祝福语汇编35句 参加考试前的祝福语
  18. Android总结笔记04:仿QQ空间登录UI,解决软键盘弹出挡住输入框的问题
  19. 如何设置或更改代理?这些方法你知道吗?
  20. csgo修改服务器最大人数,国服CSGO为满足大环境,需全方位多处修改

热门文章

  1. 在tomcat中使用context节点部署工程
  2. 【读书】正则指引-3-括号
  3. asp.net MVC的EF与easyui DataGrid数据绑定
  4. eclipse 拨打电话、拨号,发短信
  5. VS2010 C++下编译调试MongoDB源码
  6. leetcode之Tow Sum两数之和的三种思路
  7. Cascade R-CNN的一些记录
  8. Ubuntu16.04下Hadoop的本地安装与配置
  9. 怎样在黑窗口中查找各种端口
  10. 七月算法--12月机器学习在线班-第七次课笔记—最大熵