2010-06-15 107 views
42

在C或C++编译的各个阶段,我知道生成了一个目标文件(即any_name.o文件)。这个.o文件中包含什么?我无法打开它,因为它是一个二进制文件。目标文件包含什么内容?

有人能帮我吗?目标文件的内容主要依赖于我们在Unix上使用的编译器吗?

+1

有一大堆* nix工具用于查看目标文件内部:以nm开头,http://unixhelp.ed.ac.uk/CGI/man-cgi?nm – 2010-06-15 13:48:25

回答

45

对象文件可以包含一堆东西:基本上它的部分或全部下表中:

  • 符号名
  • 编译代码
  • 恒定的数据,例如。字符串
  • 导入 - 编译代码引用的哪些符号(通过链接器得到修复)
  • 导出 - 目标文件可用于OTHER对象文件的哪些符号。

链接器通过匹配所有导入和导出,修改编译后的代码,将一堆目标文件转换为可执行文件,以便调用正确的函数。

3

对于这样的事情使用file命令。这是一个在现代Linux系统上的ELF目标文件。例如。如果编译为32位x86。

ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped 

相反,动态链接的可执行文件看起来像:

ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped 

要查看标题,包括部分的名称,你可以使用:

objdump -x any_name.o 

要拆卸:

objdump -d any_name.o 
3

对象文件是编译后的源文件。

这意味着它是机器代码,它依赖于目标平台(如果您真的想在Windows上编译Unix的话)以及使用的编译器。不同的编译器会从同一个源文件中产生不同的机器码。

1

该文件包含必须通过linker运行,以生成可执行的二进制数据。它本质上是一堆带有命名部分的机器代码指令(与您的功能相对应)。维基百科的“Object File”的文章:

在计算机科学中,目标文件是 的机器 代码分离, 命名序列的有组织的收集[来源请求]。每个序列, 或对象,通常包含 指令主机到 完成一些任务,可能是 伴随着相关的数据和 元数据(例如重定位 信息,栈展开 信息,评论,节目 符号,调试或分析 信息)。链接器通常是 ,用于通过组合对象 文件的部分来生成可执行文件或 库。

7

有几种标准格式(Unix上的COFF,ELF),基本上它们是用于可执行文件但缺少某些信息的相同格式的变体。这些缺少的信息将在链接时完成。

对象的文件格式基本上包含相同的信息:

  • 所得编译的二进制代码(对目标处理器)
  • 通过的那部分程序使用的静态数据(如恒定字符串等)。您可以更好地区分BSS(导出数据)和文本(不会被程序修改的数据)。但是这对于编译器和链接器来说非常重要。请注意,与二进制代码一样,数据也依赖于目标(大端,小端,32位,64位)。由程序的这部分导出的符号的
  • 表(主要是功能入口点)由程序

当对象将被链接的代码的部分组合在一起的这部分使用的外部码元的

  • 表指的是外部符号将被实际值取代(当然,这仍然过于简化,在运行程序时加载时会完成最后一部分,但这就是想法)。

    目标文件还可能包含更多符号信息,这些信息对于解析导入和导出(对调试有用)是严格必需的。该信息可以使用strip命令删除。

  • 1

    在GNU编译环境中,您可以使用objdump在可执行文件和目标文件中查看。

    正如您所看到的,该对象只包含编译文件中声明/引用的函数的代码(该文件仅包含带有scanf调用和printf调用的主函数)。

    $ objdump -t scanf_sample.o 
    
    scanf_sample.o:  file format pe-i386 
    
    SYMBOL TABLE: 
    [ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 scanf_sample.c 
    File 
    [ 2](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x00000000 _main 
    [ 3](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text 
    AUX scnlen 0x91 nreloc 9 nlnno 0 
    [ 5](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data 
    AUX scnlen 0x0 nreloc 0 nlnno 0 
    [ 7](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss 
    AUX scnlen 0x0 nreloc 0 nlnno 0 
    [ 9](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rdata 
    AUX scnlen 0x54 nreloc 0 nlnno 0 
    [ 11](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 1) 0x00000000 ___main 
    AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0 
    [ 13](sec 0)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 __alloca 
    [ 14](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x00000000 _memset 
    [ 15](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x00000000 _scanf 
    [ 16](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x00000000 _printf 
    

    如果你在一个可执行使用objdump的,你可以看到很多更功能(除了那些对象内部发现的)。这证明目标文件只包含源文件中定义的函数并引用其他函数。这些引用将在链接阶段解决。

    阅读更多关于linkingcompilationobjects

    +0

    我在Windows下使用了MinGW for the上面的示例 - 它在* nix下工作相同 – INS 2010-06-15 14:11:32

    3

    首先,二进制文件可以打开!不要害怕它,你只需要正确的工具!作为二进制数据,文本编辑器当然不是正确的工具;一个正确的工具可能是一个十六进制编辑器,或者像emacs这样的高级编辑器,或者是一种工具,它不是简单地以其“十六进制”表示方式“输出”字节,而是让您独自解释数据,知道特定的格式和“在某种程度上解释“数据”(例如,GIMP将PNG文件解释为图像并显示它,PNG分析器将“分解”PNG部分内的数据,显示特定字节中的标志,等等)。

    就你而言,一般的答案是,目标文件包含你的编译代码(和数据),加上链接器所需的所有额外信息,最终还有更多。

    这些信息如何“组织”,在某些情况下“最终更多”是什么,它取决于具体的对象格式。一些上市的可能性,一些维基百科链接thisthisthisthis ...

    每一种可能的工具来分析的内容;例如readelf为ELF,objdump为几种格式(尝试objdump -i)取决于它如何编译。