[音乐] 下面我们来看一下目标文件的格式
前面呢,我们提到过两类目标文件,一类 就是可重定位的目标文件,就是点o文件
这类目标文件,它的代码和数据 都是可以和其他重定位文件合并的
也就是说,我们链接的对象,就是这种点o文件,可以把多个这种可重定位的
这种点o文件合并起来,生成可执行文件
在这些文件当中,它的代码和数据
的地址,都是从0开始的,也就是每一个函数
它的起始地址都是从0开始,每一个数据段,就是某一个文件,比如说某一个点c文件
它的所有的数据,都结合在一起,这些结合在一起 的数据段的起始地址,也是从0开始的
一个点c文件对应于一个点o文件,这样的话,多个点c
文件构成的程序,最终是分别转换成多个点o文件
来进行链接的,链接生成的文件就是可执行 目标文件,那么在Linux里面呢,就是如果你
不用杠o来指定输出文件名的话,默认的就是
a.out这个文件名,在Windows当中
带exe这种后缀的这些文件,就是可执行目标文件
这种可执行目标文件,它是通过若干个点o文件 合并生成的,所以在这一个可执行文件里面
它有代码,有数据,因为可重定位目标文件里面
有代码,有数据,所以这些多个点o文件,合并起来的这些代码
就构成了可执行文件里面的代码部分,然后 多个点o文件里面的数据部分合并起来,就构成
可执行文件里面的数据部分,而这些在可执行文件里面的
代码部分和数据,就可以直接被复制到内存执行
因为它是一种可执行的文件,所以装入内存以后就可以执行了
在代码和数据当中,所用到的这些地址
都是虚拟地址空间里面的地址,这个我们在前面的例子里面,已经说明过了
在前面我们谈到一种是可执行目标文件,一种是可重定位的目标文件
提到过这样两种目标文件,实际上还有一类目标文件,称为共享的目标文件
这个实际上是在动态链接的时候用到的 一种共享目标文件,它也是由
若干个可重定位目标文件,若干个点o文件 组合起来的一种共享库文件
这种共享库文件,在装入或运行的时候,可以动态的被装入到内存
并且呢,自动被链接到某一个可执行文件 里面去执行,所以它称为共享库文件
它不能单独拿出来执行,它一定是被链接到 一个可执行文件里面去的,只不过它是动态的
它不是在链接的时候,和其他的可重定位文件合并,来生成可执行文件的
而是在装入或运行的时候,动态的被链接的,那么有关这一类的目标文件
我们在后面讲动态链接的时候再介绍
共享的目标文件在Windows里面就是dll文件,是这种
共享的目标文件,在Linux里面呢,它就是点so文件
这个我们前面举过例子,比如说点o文件就是
可重定位的文件,每一个函数的指令,它的地址都是从0开始的
而对于可执行文件,它的地址就是一个
虚拟地址,是合并了以后,在一个虚拟地址空间里面
这条指令在哪个位置,那么对应的这个地址就是那个虚拟地址空间当中的那个虚拟地址
所以它是有具体的地址 我们来看一下目标文件的格式
所谓目标代码,实际上就是 指用编译器或者汇编器
对源代码,也就是高级语言源程序,或者汇编语言写的源程序
也称为源代码,进行相应的转换,进行编译或者汇编
这种转换,以后生成的这种机器语言目标代码
也就是二进制的,用0和1表示的那些指令,构成的这种目标代码
所谓的目标代码我们都是指的机器语言目标 代码,也就是2进制的机器指令构成的目标代码
而目标文件呢是指包含这种 目标代码的文件,它是以文件的形式
存放在磁盘上的,所以我们称为目标文件,那么这个目标文件当中实际上
它的代码呢都是用2进制,也就是机器指令构成的这种代码
最早的目标文件格式都是自有格式,因为那时候大家都没有交流,所以
都是非标准的,各自定义一套,然后随着技术的发展出现了很多标准的
目标文件格式,最早的微软
在推出Windows图形用户界面之前,是一种叫DOS操作系统
用的是命令行的人机交互界面,在DOS系统当中
它用到了一种目标文件的格式叫COM 格式,它的文件名的扩展名都是com
这种目标文件格式,它是最简单的 这个文件当中只有代码和数据
就是你这个程序当中的这些指令和指令处理的数据 仅包含这些,而且呢是被加载到内存的固定位置的
也就是说在这种格式的文件当中,所有代码的地址和数据的地址
都不是虚拟地址而是具体的一个内存的地址
而且是固定的加载的,最早的System
V UNIX版本它用的这种目标文件格式呢是COFF格式
这种格式里面它不仅包含了代码和数据 还包含重定位信息、
调试信息、 符号表等 其它的很多信息,它是由一组严格定义的数据结构序列构成的
什么意思呢?就说这种文件当中,它是
包含了很多除代码数据以外的
其它的一些信息也包含在里面,这每一种信息,比如代码数据
从定位信息、 调试信息,每一类信息或者每一种信息都是一个
确定的一个数据结构描述的,这个数据结构描述的各类信息
按照一定的顺序组合成一个文件,这是早期的COFF这种目标文件格式
Windows当中采用的是PE格式
PE格式实际上也是从COFF格式变化而来的
是一种变种,但是它还是基于它变化而来的
PE的意思就是称为可移植可执行 叫可移植可执行的格式所以叫PE格式
像Linux等等这些类UNIX系统 它采用的是ELF格式,也是从
COFF这个格式变化而来的 它称为可执行可链接的格式
也就是E表示可执行,L表示可链接
的格式,所以它有两个视图,一个叫 执行视图,一个叫链接视图
后面我们主要介绍ELF格式 ELF格式我们刚才讲过了
它的E就表示可执行 L表示可链接,所以它有一种叫链接视图
链接视图就是一种可重定位的目标文件格式
那么也就是说这一类的目标文件是可以被链接,也就是合并的
合并以后生成可执行文件或者是共享的目标文件,就是若干
个.o文件可以生成一个.so文件,若干个.o文件可以生成一个可执行文件
静态的链接库文件实际上就是由若干个可重定位目标文件
组成的,我们前面举过例子,就是main.c和swap.c
通过静态链接,可以生成一个p这样一个可执行文件
在每一个点c文件当中,前面我们提到的,比如说main.c和swap.c
当中,都有相应的代码和数据,数据呢还包含两部分
一部分是已初始化的数据,还一部分是未初始化的数据,已初始化
的数据合到一起,构成一个叫.data节,未初始化的
数据合到一起,构成一个.bss节,未初始化的数据 当然它可以是全局变量,也可以是静态的局部变量
它都是属于一种静态的数据,静态分配的全局数据
在可重定位目标文件当中,还包含一些重定位信息
因为在生成可重定位目标的时候,也就是我们在进行
编译汇编的时候,是不知道将来和什么样的点o文件进行合并
合并以后,它的位置在 哪里,都是不知道的 所以有很多符号需要进行重定位
所以在这个文件当中要指出,哪些符号引用需要进行重定位,这个信息就是指的
重定位的信息,可重定位目标文件,我们前面讲过 扩展名是点o,Windows里面呢,就是点obj文件
比如说我们这有一个例子,这个是一个源程序
这个源程序经过预处理,编译 汇编以后,生成点o文件,也就是
链接视图,最终这个文件当中的这些全局变量
或者是这些静态变量,都是送到相应的
数据节里面的,如果是已经初始化的了的话
这边已经有初始化的话,那么就送到.data节,如果没有初始化,像这个y
和这边的b,它就送到.bss节,对应于这些函数里面的这些语句
是有相应的指令来实现的,也就是它属于一些代码 信息,那么这个代码信息呢就在.text节
另外一个函数,这边是这个函数,这边是主函数,这些函数当中的这些语句
这些语句生成的代码,也会送到相应的.text节里面去
代码都送到一起,数据送到一起,分成已初始化的和未初始化的
这些就是可重定位目标文件里面的信息,也称为是链接视图
将来这个点o文件会和其他的点o文件链接起来,也就是合并起来生成可执行文件的
所以它是一种链接视图,把一个模块里面的代码全放到一起,数据全放到一起
为了进行链接,当然除了刚才我们讲到的代码、 数据以外还有其它的信息
比如说符号表、 重定位信息等等,这些我们都称为是一个一个的Section,叫节
这个是链接视图,前面我们讲过了ELF
它是除了可链接的以外,就是说是
被链接的这种链接视图,被链接生成可执行文件
这样的一种可重定位目标文件以外,它还可以描述
一个执行视图,描述一个可执行目标文件,所以这两种文件
都是ELF格式的文件,这个我们前面讲过的,这是一种链接视图
这里面都很多很多的节构成,这个节就是
像代码信息叫.text节,数据信息叫.data节
未初始化的数据叫.bss节,如果有只读数据的话那就是.rodata节
所以我们可以这样认为,节是ELF文件 当中具有相同特征的最小可处理单位
也就是所有的代码具有相同特征,所以它都在.text节
里面,已经初始化的数据都具有相同的特征,那就放在.data节里面
这是节的概念,ELF还有一个视图就是 执行视图,也就是说描述的是一种被执行的信息的情况
这个执行视图大致的格式是类似的,都有ELF头
都是一个一个节组成的,相同属性的那些节又把它组合成
段,也有节头表,对于链接视图里面这个程序头表可能没有
但是在执行视图里面它有程序头表,这是非常重要的,这个
程序头表它反映了这个里面的每一个节和这个
虚拟地址空间当中的某一个段之间的关系
所以它可以由不同的段构成,然后每个段
又由不同的节构成,所以程序头表就描述了这若干个节
如何组成一个程序段,如何映射到一个程序段中的 比如说.data节和.bss节可以合并成一个
可读可写的数据段,这个是由程序头表来指出的 有关执行视图,后面我们会详细地介绍
下面呢我们先介绍链接视图 [音乐]
[音乐]