编译器编译源代码后生成的文件叫做目标文件。
目标代码是指源代码经过编译程序产生的能被cpu直接识别二进制代码。
目标文件是源代码经过编译但未链接的那些中间文件。
windows上为.obj文件,linux上为.o文件
目标文件与可执行文件的内容和结构很相似。所以在广义上来看,目标文件与可执行文件可以看成是一种文件
在windows下,可以统称为PE-COFF文件格式。
在linux下,我们可以统称为ELF文件
目前PC平台流行以下两种可执行文件格式:
windows下的PE文件,linux上的ELF文件格式
这两种均为COFF格式的变种
可重定位文件:包含代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库可以归为这一类型。
windows的.obj文件,linux的.o文件
可执行文件:包含可以直接执行的程序
windows 下的.exe文件,linux下/bin/bash文件
共享目标文件:包含代码和数据,可以在一下两种情况使用。
①链接器使用其与其他可重定位文件和共享目标文件链接,产生新的目标文件。
②动态链接器将几个这种共享目标文件与可执行文件相结合,作为进程映像的一部分。
windows下的DLL文件,linux下的.so文件
核心转储文件:当进程意外终止时,系统用来储存该进程地址空间的内容以及终止时的一些其他信息
linxu下的core dump
目标文件将其中编译后的机器指令代码、数据、符号表、调试信息、字符串等以节(有的时候也叫段)存储。
代码段(.text):程序源代码编译后的机器指令存放位置
数据段(.data):初始化不为 0 的全局和静态数据存放位置
数据段(.bss):未初始化或初始化为 0 的全局和静态数据存放位置
程序源代码被编译后主要分为两种段:程序指令和程序数据。代码段属于程序指令,而数据段和.bss段属于程序数据。
代码段通常是指用来存放程序执行代码的一块内存区域。
这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
.data段保存到是哪些已经初始化了的全局静态变量和局部静态变量
.rodata段存放的是只读数据,一般是程序里面的只读变量(const修饰)和字符串常量。
如printf(“%d\n”, x);
其中的“%d\n”
就存放在.rodata段中。
.bss段存放的是未初始化的全局变量和静态局部变量。
实际上,有些编译器知识对.bss段变量预留一个未定义的全局变量符号。
实际并不占用目标文件的空间(磁盘),只有当运行时被使用到才会真正的占用空间(内存)。
其他段都是用来保存与程序相关的其他信息,知道就行,没啥大的卵用。
.rodatal:存放只读数据,跟.rodata段一样
.comment:存放编译器版本信息
.debug: 存放调试信息
.dynamic:存放动态链接信息
.hash: 符号哈希表
.line: 存放调试用的行号表
.note: 存放额外的编译器信息
.strtab: 存放ELF文件中用到的各种字符串
.symtab: 符号表
.shstrtab:段名表
.plt&.got:动态链接的跳转表和全局入口表
.init&.fini:程序初始化与终结代码段
.rel.text: 重定位表
ELF目标文件格式的最前部就是ELF文件头。它包含了描述整个文件的基本属性,比如ELF文件版本、目标机器型号、程序入口地址等。
以下是文件头中各个成员及其含义:
ELF魔数:确认文件类型。我们可以看到第一个e_ident这个成员。其中前四个字节称为ELF文件的魔数(如 0x45 E,0x4c L,0x46 F 代表的就是ELF文件)。
几乎所有的可执行文件开始几个字节都是魔数
文件类型:e_type成员用来表示ELF文件类型,通常是一个常量。系统通过常量来判断ELF真正的文件类型,而不是文件的扩展名。
段表是一个被用来保存段的的基本属性的结构。
编译器、链接器和装载器都是依靠段表来定位和访问各个段的属性的。
以下是段表中各个成员及其含义:
在其他段的介绍中,有个.rel.text的重定位表段,其中存放了符号的重定位信息。而.text段中对符号的引用都要参考重定位表来实现符号的地址无关。
字符串表存储了字符串信息,编译器将所有字符串集中起来存放到一个表,然后使用字符串表中的偏移来引用字符串。
[1] 俞甲子 石凡 潘爱明.程序员的自我修养.电子工业出版社,2009.4.
[2] 百度百科 https://baike.baidu.com/item/%E4%BB%A3%E7%A0%81%E6%AE%B5