目标文件格式

375 阅读8分钟

典型的可重定向文件结构

Untitled.png

  • .text : 代码段,包含函数的指令
  • .data : 数据段,保存已经初始化的全局静态变量和局部静态变量
  • .rodata : 只读数据,只读变量(const 修饰的变量)和字符串常量
  • .bss : 未初始化的全局变量和局部静态变量

Snipaste_2022-10-21_10-08-14.png

以下面这段代码为例:

/*
 * SimpleSection.c
 * gcc -c SimpleSection.c
 */
int printf(const char *format, ...);

int global_init_var = 84;
int global_uninit_var;

void func1(int i)
{
        printf("%d\n", i);
}

int main(void)
{
        static int static_var = 85;
        static int static_var2;

        int a = 1;
        int b;

        func1(static_var + static_var2 + a + b);

        return 0;
}
gcc -c SimpleSection.c -o SimpleSection.o

hexdump SimpleSection.o

ELF Header

typedef struct elf64_hdr {
  unsigned char	e_ident[EI_NIDENT];	/* ELF "magic number" */
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;		/* Entry point virtual address */
  Elf64_Off e_phoff;		/* Program header table file offset */
  Elf64_Off e_shoff;		/* Section header table file offset */
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
} Elf64_Ehdr;
00000000:  7f45 4c46 0201 0100 0000 0000 0000 0000 0100 3e00 0100 0000  :.ELF..............>.....
00000018:  0000 0000 0000 0000 0000 0000 0000 0000 0804 0000 0000 0000  :........................
00000030:  0000 0000 4000 0000 0000 4000 0e00 0d00
字段占位(字节)示意HEX
e_ident16Magic…7f45 4c46 0201 0100 0000 0000 0000 000
e_type2ELF 文件类型
- 1 : REL
-2 : EXEC
-3 : DYN
0001
e_machine2CPU 平台属性003e
e_version4ELF 版本号0000 0001
e_entry8入口地址0000 0000 0000 0000
e_phoff8start of program header0000 0000 0000 0000
e_shoff8start of section header0000 0000 0000 0408
e_flags4标志位0000 0000
e_ehsize2size of header0040(64)
e_phentsize2size of program header0000
e_phnum2number of program header0000
e_shentsize2size of section header0040
e_shnum2number of section header000e(14)
e_shstrndx2section header string table index
(段表字符串表)
000d(13)

使用 readelf 查看

readelf -h SimpleSection.o

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1032 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         14
  Section header string table index: 13

通过上面的信息,可以得出该 .o 文件的结构大致如下:

SHT.png

Section header table(SHT)

Section Header

typedef struct elf64_shdr {
  Elf64_Word sh_name;		/* Section name, index in string tbl */
  Elf64_Word sh_type;		/* Type of section */
  Elf64_Xword sh_flags;		/* Miscellaneous section attributes */
  Elf64_Addr sh_addr;		/* Section virtual addr at execution */
  Elf64_Off sh_offset;		/* Section file offset */
  Elf64_Xword sh_size;		/* Size of section in bytes */
  Elf64_Word sh_link;		/* Index of another section */
  Elf64_Word sh_info;		/* Additional section information */
  Elf64_Xword sh_addralign;	/* Section alignment */
  Elf64_Xword sh_entsize;	/* Entry size if section holds table */
} Elf64_Shdr;

以 .text 为例(其它的 section 同理):

2000 0000 0100 0000 0600 0000 0000 0000 
0000 0000 0000 0000 4000 0000 0000 0000 
6400 0000 0000 0000 0000 0000 0000 0000 
0100 0000 0000 0000 0000 0000 0000 0000
字段占位(字节)示意HEX
sh_name4section name,它位于 “.shstrtab” 的字符串表,sh_name 是段名字符串在 “.shstrtab” 中的偏移0000 0020
sh_type4类型
- 0:SHT_NULL
- 1:SHT_PROGBITS
- 2:SHT_SYMTAB 符号表
- 3:SHT_STRTAB 字符串表
- 4:SHT_RELA 重定位表
- 5:SHT_HASH
- 6:SHT_DYNAMIC 动态链接信息
- 7:SHT_NOTE
- 8:SHT_NOBITS
- 9:SHT_REL 重定位信息
- 10:SHT_SHLIB
- 11:SHT_DNYSYM 动态链接符号表
0000 0001
sh_flags8标志位0000 0000 0000 0006
sh_addr8段虚拟地址。如果该段可以被加载,则表示该段被加载后在进程地址空间的虚拟地址。0000 0000 0000 0000
sh_offset8该段在文件中的偏移0000 0000 0000 0040(64)
sh_size8段的长度0000 0000 0000 0064(100)
sh_link40000 0000
sh_info40000 0000
sh_addralign8段地址对齐0000 0000 0000 0001
sh_entsize8section entry size:项的长度0000 0000 0000 0000

text.png

readelf -SW SimpleSection.o

There are 14 section headers, starting at offset 0x408:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000000000 000040 000064 00  AX  0   0  1
  [ 2] .rela.text        RELA            0000000000000000 0002e8 000078 18   I 11   1  8
  [ 3] .data             PROGBITS        0000000000000000 0000a4 000008 00  WA  0   0  4
  [ 4] .bss              NOBITS          0000000000000000 0000ac 000008 00  WA  0   0  4
  [ 5] .rodata           PROGBITS        0000000000000000 0000ac 000004 00   A  0   0  1
  [ 6] .comment          PROGBITS        0000000000000000 0000b0 000027 01  MS  0   0  1
  [ 7] .note.GNU-stack   PROGBITS        0000000000000000 0000d7 000000 00      0   0  1
  [ 8] .note.gnu.property NOTE            0000000000000000 0000d8 000020 00   A  0   0  8
  [ 9] .eh_frame         PROGBITS        0000000000000000 0000f8 000058 00   A  0   0  8
  [10] .rela.eh_frame    RELA            0000000000000000 000360 000030 18   I 11   9  8
  [11] .symtab           SYMTAB          0000000000000000 000150 000138 18     12   8  8
  [12] .strtab           STRTAB          0000000000000000 000288 000060 00      0   0  1
  [13] .shstrtab         STRTAB          0000000000000000 000390 000074 00      0   0  1

Symtab 符号表

这个表里记录目标文件中所有用到的所有符号,每个符号有一个对应的符号值(Symbol Value),对于变量和函数来说,符号值就是它们的地址。

typedef struct elf64_sym {
  Elf64_Word st_name;		/* Symbol name, index in string tbl */
  unsigned char	st_info;	/* Type and binding attributes */
  unsigned char	st_other;	/* No defined meaning, 0 */
  Elf64_Half st_shndx;		/* Associated section index */
  Elf64_Addr st_value;		/* Value of the symbol */
  Elf64_Xword st_size;		/* Associated symbol size */
} Elf64_Sym;

func1 为例*:*

.symtab 在 SHT[11] 位置,它在文件的偏移量为 0x150

func1 **在 .symtab[10] 位置

4e00 0000 1200 0100 0000 0000 0000 0000 2b00 0000 0000 0000
字段占位(字节)示意HEX
st_name4符号名。在符号表中的偏移004e 0000(func1)
st_info1符号类型和绑定信息12
st_other1-00
st_shndx2符号所在段0001
st_value8符号相对应的值0000 0000 0000 0000
st_size8符号大小0000 0000 0000 00b2
st_name = strtab + 4e = 0x288 + 0x4e = 0x2D6 
        = { 6675 6e63 3100 }
转换成   = func1

符号值(st_value)

  • 在目标文件中,该符号定义不是“COMMON”块,则 st_value 表示该符号在段中的偏移。即符号所对应的函数或者变量位于由 st_shndx 指定的段,偏移 st_value 的位置。
  • 在目标文件中,该符号是“COMMON”块,则 st_value 表示该符号的对齐属性。
  • 在可执行文件中,st_value 表示符号的虚拟地址。
readelf -s SimpleSection.o

Symbol table '.symtab' contains 13 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS SimpleSection.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .text
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 .data
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 .bss
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 .rodata
     6: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    3 static_var.1
     7: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    4 static_var2.0
     8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_init_var
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    4 global_uninit_var
    10: 0000000000000000    43 FUNC    GLOBAL DEFAULT    1 func1
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
    12: 000000000000002b    57 FUNC    GLOBAL DEFAULT    1 main