编译链接运行原理---链接与ELF文件

(一)什么是目标文件

编译器编译源代码后生成的文件叫做目标文件,目标文件从结构上讲,它是已经编译后的可执行文件格式,只是还没有经过链接的过程,其中也有些符号或有些地址还没有被调整。其本身是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍微有些不同。可执行文件格式涵盖了程序的编译、链接、装载和执行的各个方面。

编译链接运行原理---链接与ELF文件

(二)目标文件的格式

现在PC平台流行的可执行文件的格式主要是Windows下的PE和Linux下的ELF,它们都是COFF格式的变种。目标文件就是源代码编译后但未进行链接的那些中间文件。(Windows的 .obj 和 Linux下 .o)与可执行文件的内容结构相似一般采用一种格式存储(Windows的 PE_COFF文件格式 和 Linux下 ELF文件格式)。动态链接库(Windows的 .dll和 Linux下 .so)及静态链接库(Windows的 .lib 和 Linux下 .a)文件都是按照可执行文件存储。

ELF格式文件类型:

 

                                编译链接运行原理---链接与ELF文件

(三)目标文件是什么样

目标文件中内容至少有编译后的机器指令代码、数据。除了这些还包括连接时所须要的一些信息,比如:符号表、调试信息、字符串等。一般会将这些信息按不同的属性,以“节”(section)的形式存储也叫“段”(segment) 。

举例大致了解ELF轮廓:

编译链接运行原理---链接与ELF文件

ELF Header:描述整个文件的文件属性,包括文件是否可执行、是静态链接还是动态链接及入口地址(如果是可执行文件)、目标硬件、目标操作系统等信息,文件头还包括一个段表(Section Table),段表其实是一个描述文件中各个段的数组。描述了各个段在文件中的偏移位置及段的属性等从段表可以得到每个段(程序指令和程序数据)的所有信息。

.text(.code)代码段:保存程序源代码编译或的机器指令
.rodata只读数据段:read-only数据,比如常量字符串。
.data数据段:保存已初始化且初始化不为0的全局变量和局部静态变量。
.bss段:保存未初始化或初始化为0的全局变量和局部静态变量,仅仅是占位符,未初始化不需要占据实际磁盘空间。

其他段:

                            编译链接运行原理---链接与ELF文件

ELF结构:

                                                              编译链接运行原理---链接与ELF文件

  • ELF头部(ELF_Header): 每个ELF文件都必须存在一个ELF_Header,这里存放了很多重要的信息用来描述整个文件的组织,如: 版本信息,入口信息,偏移信息等。程序执行也必须依靠其提供的信息。
  • 节区头部表(Section_Header_Table): 类似与Program_Header_Table,但与其相对应的是节区(Section)。
  • 节区(Section): 将文件分成一个个节区,每个节区都有其对应的功能,如符号表,哈希表等。

补充:强符号与弱符号,已初始化的全局变量称为强符号,未定义的全局变量称为弱符号;在不同语言和不同的编译器中,有些编译器会将全局的未初始化变量存放在目标文件.bss段,有些则不存放,只是预留一个未定义的全局变量(COMMON块中)等到最终链接成可执行文件的时候再在.bss段分配地址空间。

强弱规则:

两个强符号,重定义错误

一强一弱,选强符号

两个弱符号