Skip to content

[翻译] 简谈编译、汇编、链接和加载 – part II

Tanslated from: http://www.tenouk.com/ModuleW.html

W.2  对象文件与可执行文件

源文件经历汇编后会变成对象文件(文件名通常以.o为后缀),再经过链接后,就变成了可执行文件。

对象文件与可执行文件的格式有几种。如Linux上的ELF (Executable and Linking Format) 格式以及Windows上的 COFF (Common Object-File Format).

对象文件格式 描述
a.out Unix上最初的可执行文件格式.  它包含有三个块(sections):  text, data, and bss, 分别对应程序代码, 初始化过的数据以及未初始化的数据.  此格式无法包含排错信息。它能包括的唯一排错信息是被编码为一套带有不同属性的符号的、称为stabs的东西。
COFF COFF格式 (Common Object File Format) 由Unix SVR3引入 .可包含多个块, 每个块都有一个”块头(header)”. 块的数量是有限的.  COFF标准是包含排错信息的,但是也是有限的。此格式没有文件扩展名。
ECOFF COFF的一种变体.  ECOFF是一种扩展的COFF,最初为Mips 和 Alpha工作站设计.
XCOFF 运行AIX的IBM RS/6000 使用了一种称为XCOFF (eXtended COFF)的格式. 这种格式中,COFF的块, 符号和行数信息被保留,但排错符号则变成了dbx风格的stabs,字符串被放进了.debug 块中 (而不是字符串表).  默认的对象文件名也是 a.out.
PE Windows 9x 和 NT使用了PE (Portable Executable) 作为可执行文件的格式.  PE本质上是带有更多头部信息的COFF格式。文件名后缀是 .exe.
ELF ELF (Executable and Linking Format) 出现在SVR4版本的 Unix.  ELF和COFF是相似的,都是把信息分成多个块来存放,但它解决了COFF的一些局限性.  现在的Unix类系统,包括GNU/Linux, Solaris 和Irix都使用ELF格式。许多嵌入式系统也在使用。
SOM/ESOM SOM (System Object Module)和ESOM (Extended SOM) 是HP的对象和排错信息格式(不要和IBM的SOM搞混了, 那是一个跨语言的应用二进制接口ABI).

查看这些对象文件,我们会发现其中有称为块(section)的部分。块可以存放代码,数据,动态链接信息,排错数据,符号表,重定位信息,注释,字符串表和笔记(notes)。有些块会在程序被加载时一起被加载,有些块则是在编译程序是提供必要的信息,而有些则是只在链接对象文件时使用。

下表中列出了一些所有可执行文件格式通用的块(section):

块(Section) 描述
.text 存放可执行代码指令. 当在一个系统上多次运行此程序是,这个块的内容可在多个进程间共享。这个块通常会有一个可读(READ)和可执行(EXECUTE)权限. 也是被优化选项影响最大的块。
.bss BSS 表示 ‘Block Started by Symbol’. 用于存放未初始化的全局和静态变量. 由于BSS只用于存放未被赋值的变量, 它不需要存储这些变量的镜像(image). BSS在运行时需要的空间记录在对象文件中,但是BSS本身在对象文件中并不占用任何空间(这和data块不同)。
.data 存放已初始化的全局和静态变量以及它们的值. 通常是可执行文件中最大的一部分. 通常有 读/写(READ/WRITE)权限
.rdata 也被称为 .rodata (read-only data) .用于存放常数及不可变字符串.
.reloc 存放加载时重定位镜像(image)所需要的信息。
Symbol table 一个符号就是一个名称及其对应的地址。符号表存放用于定位和重定位程序的符号定义和引用所需的信息。符号表索引则是引用此数列的下标。索引0指定了表的第一项,同时也是未定义的符号的索引。符号表就是一个包含了符号项的数列。
Relocation records 重定位就是把符号引用和符号定义连接起来的过程。比如,当一个程序调用一个函数,相关的调用指令必须把(计算机的)控制权转移到函数所在的地址。可重定位的文件必须具有重定位表项,用于描述如何更改它所在的块的内容,从而允许可执行文件和共享对象文件拥有一个进程对应的二进制文件的正确信息。简单地说,重定位记录(relocation records)就是链接器调整块内容时所需要的信息。

下面的例子就是用readelf程序导出的一个对象文件的内容。也可以使用objdump程序。Windows系统上可以用dumpbin或者是更强大的PEBrowse程序。

/* testprog1.c */
#include <stdio.h>
static void display(int i, int *ptr);
 
int main(void)
{
      int x = 5;
      int *xptr = &x;
      printf("In main() program:\n");
      printf("x value is %d and is stored at address %p.\n", x, &x);
      printf("xptr pointer points to address %p which holds a value of %d.\n", xptr, *xptr);
      display(x, xptr);
      return 0;
}
 
void display(int y, int *yptr)
{
      char var[7] = "ABCDEF"; 
      printf("In display() function:\n");
      printf("y value is %d and is stored at address %p.\n", y, &y);
      printf("yptr pointer points to address %p which holds a value of %d.\n", yptr, *yptr);
}
[bodo@bakawali test]$ gcc -c testprog1.c
[bodo@bakawali test]$ readelf -a testprog1.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                                  ELF32
  Data:                                   2's complement, little endian
  Version:                                1 (current)
  OS/ABI:            UNIX - System V
  ABI Version:              0
  Type:              REL (Relocatable file)
  Machine:           Intel 80386
  Version:           0x1
  Entry point address:      0x0
  Start of program headers: 0 (bytes into file)
  Start of section headers: 672 (bytes into file)
  Flags:                    0x0
  Size of this header:      52 (bytes)
  Size of program headers:  0 (bytes)
  Number of program headers:       0
  Size of section headers:         40 (bytes)
  Number of section headers:       11
  Section header string table index:      8
 
Section Headers:
  [Nr] Name          Type          Addr     Off        Size     ES Flg Lk Inf Al
  [ 0]               NULL          00000000 000000 000000 00      0   0  0
  [ 1] .text         PROGBITS      00000000 000034 0000de 00  AX   0   0  4
  [ 2] .rel.text     REL           00000000 00052c 000068 08      9   1  4
  [ 3] .data         PROGBIT       00000000 000114 000000 00         WA  0   0  4
  [ 4] .bss          NOBIT         00000000 000114 000000 00  WA  0   0  4
  [ 5] .rodata              PROGBITS      00000000 000114 00010a 00      A  0   0  4
  [ 6] .note.GNU-stack      PROGBITS      00000000 00021e 000000 00      0   0  1
  [ 7] .comment      PROGBITS      00000000 00021e 000031 00      0   0  1
  [ 8] .shstrtab     STRTAB 00000000 00024f 000051 00       0   0  1
  [ 9] .symtab              SYMTAB 00000000 000458 0000b0 10     10  9  4
  [10] .strtab              STRTAB 00000000 000508 000021 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
 
There are no program headers in this file.
 
Relocation section '.rel.text' at offset 0x52c contains 13 entries:
 Offset       Info                 Type   Sym.Value  Sym. Name
0000002d  00000501 R_386_32 00000000   .rodata
00000032  00000a02 R_386_PC32      00000000   printf
00000044  00000501 R_386_32 00000000   .rodata
00000049  00000a02 R_386_PC32      00000000   printf
0000005c  00000501 R_386_32 00000000   .rodata
00000061  00000a02 R_386_PC32      00000000   printf
0000008c  00000501 R_386_32 00000000   .rodata
0000009c  00000501 R_386_32 00000000   .rodata
000000a1  00000a02 R_386_PC32      00000000   printf
000000b3  00000501 R_386_32 00000000   .rodata
000000b8  00000a02 R_386_PC32      00000000   printf
000000cb  00000501 R_386_32 00000000   .rodata
000000d0  00000a02 R_386_PC32      00000000   printf
 
There are no unwind sections in this file.
 
Symbol table '.symtab' contains 11 entries:
   Num:    Value     Size Type    Bind        Vis             Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS testprog1.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1
     3: 00000000     0 SECTION LOCAL  DEFAULT    3
     4: 00000000     0 SECTION LOCAL  DEFAULT    4
     5: 00000000     0 SECTION LOCAL  DEFAULT    5
     6: 00000080     94 FUNC   LOCAL  DEFAULT    1 display
     7: 00000000     0 SECTION LOCAL  DEFAULT    6
     8: 00000000     0 SECTION LOCAL  DEFAULT    7
     9: 00000000     128 FUNC  GLOBAL DEFAULT    1 main
    10: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
 
No version information found in this file.

 

–待续

Avatar

专业Linux/Unix/Windows系统管理员,开源技术爱好者。对操作系统底层技术,TCP/IP协议栈以及信息系统安全有强烈兴趣。电脑技术之外,则喜欢书法,古典诗词,数码摄影和背包行。

Sidebar