Gcc 无法解释的填充到ELF部分

Gcc 无法解释的填充到ELF部分,gcc,alignment,padding,offset,elf,Gcc,Alignment,Padding,Offset,Elf,我试图更好地理解ELF格式。为此,我编写了一个名为share.C的小C文件,并从中创建了一个名为share.so的共享对象。以下是share.c的内容: static int count = 0; void increment() { count++; } 下面是我用来创建share.so的命令: gcc -fPIC -shared -o share.so share.c Elf file type is DYN (Shared object file) Entry point

我试图更好地理解ELF格式。为此,我编写了一个名为share.C的小C文件,并从中创建了一个名为share.so的共享对象。以下是share.c的内容:

static int count = 0;

void increment()
{
     count++;
}
下面是我用来创建share.so的命令:

gcc -fPIC -shared -o share.so share.c
Elf file type is DYN (Shared object file)
Entry point 0x550
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000006f4 0x00000000000006f4  R E    200000
  LOAD           0x0000000000000e30 0x0000000000200e30 0x0000000000200e30
                 0x00000000000001f0 0x00000000000001f8  RW     200000
  DYNAMIC        0x0000000000000e48 0x0000000000200e48 0x0000000000200e48
                 0x0000000000000190 0x0000000000000190  RW     8
  NOTE           0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
                 0x0000000000000024 0x0000000000000024  R      4
  GNU_EH_FRAME   0x0000000000000674 0x0000000000000674 0x0000000000000674
                 0x000000000000001c 0x000000000000001c  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e30 0x0000000000200e30 0x0000000000200e30
                 0x00000000000001d0 0x00000000000001d0  R      1

 Section to Segment mapping:
  Segment Sections...
   00     .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .init .plt .plt.got .text .fini .eh_frame_hdr .eh_frame 
   01     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
   02     .dynamic 
   03     .note.gnu.build-id 
   04     .eh_frame_hdr 
   05     
   06     .init_array .fini_array .jcr .dynamic .got 
There are 27 section headers, starting at offset 0x1820:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.build-i NOTE             00000000000001c8  000001c8
       0000000000000024  0000000000000000   A       0     0     4
  [ 2] .gnu.hash         GNU_HASH         00000000000001f0  000001f0
       000000000000003c  0000000000000000   A       3     0     8
  [ 3] .dynsym           DYNSYM           0000000000000230  00000230
       0000000000000138  0000000000000018   A       4     2     8
  [ 4] .dynstr           STRTAB           0000000000000368  00000368
       00000000000000ad  0000000000000000   A       0     0     1
  [ 5] .gnu.version      VERSYM           0000000000000416  00000416
       000000000000001a  0000000000000002   A       3     0     2
  [ 6] .gnu.version_r    VERNEED          0000000000000430  00000430
       0000000000000020  0000000000000000   A       4     1     8
  [ 7] .rela.dyn         RELA             0000000000000450  00000450
       00000000000000c0  0000000000000018   A       3     0     8
  [ 8] .init             PROGBITS         0000000000000510  00000510
       000000000000001a  0000000000000000  AX       0     0     4
  [ 9] .plt              PROGBITS         0000000000000530  00000530
       0000000000000010  0000000000000010  AX       0     0     16
  [10] .plt.got          PROGBITS         0000000000000540  00000540
       0000000000000010  0000000000000000  AX       0     0     8
  [11] .text             PROGBITS         0000000000000550  00000550
       0000000000000116  0000000000000000  AX       0     0     16
  [12] .fini             PROGBITS         0000000000000668  00000668
       0000000000000009  0000000000000000  AX       0     0     4
  [13] .eh_frame_hdr     PROGBITS         0000000000000674  00000674
       000000000000001c  0000000000000000   A       0     0     4
  [14] .eh_frame         PROGBITS         0000000000000690  00000690
       0000000000000064  0000000000000000   A       0     0     8
  [15] .init_array       INIT_ARRAY       0000000000200e30  00000e30
       0000000000000008  0000000000000000  WA       0     0     8
  [16] .fini_array       FINI_ARRAY       0000000000200e38  00000e38
       0000000000000008  0000000000000000  WA       0     0     8
  [17] .jcr              PROGBITS         0000000000200e40  00000e40
       0000000000000008  0000000000000000  WA       0     0     8
  [18] .dynamic          DYNAMIC          0000000000200e48  00000e48
       0000000000000190  0000000000000010  WA       4     0     8
  [19] .got              PROGBITS         0000000000200fd8  00000fd8
       0000000000000028  0000000000000008  WA       0     0     8
  [20] .got.plt          PROGBITS         0000000000201000  00001000
       0000000000000018  0000000000000008  WA       0     0     8
  [21] .data             PROGBITS         0000000000201018  00001018
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .bss              NOBITS           0000000000201020  00001020
       0000000000000008  0000000000000000  WA       0     0     4
  [23] .comment          PROGBITS         0000000000000000  00001020
       0000000000000034  0000000000000001  MS       0     0     1
  [24] .shstrtab         STRTAB           0000000000000000  0000173b
       00000000000000e4  0000000000000000           0     0     1
  [25] .symtab           SYMTAB           0000000000000000  00001058
       0000000000000528  0000000000000018          26    44     8
  [26] .strtab           STRTAB           0000000000000000  00001580
       00000000000001bb  0000000000000000           0     0     1
我使用readelf工具查看share.so中的程序头和节头。以下是share.so中的程序标题:

gcc -fPIC -shared -o share.so share.c
Elf file type is DYN (Shared object file)
Entry point 0x550
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000006f4 0x00000000000006f4  R E    200000
  LOAD           0x0000000000000e30 0x0000000000200e30 0x0000000000200e30
                 0x00000000000001f0 0x00000000000001f8  RW     200000
  DYNAMIC        0x0000000000000e48 0x0000000000200e48 0x0000000000200e48
                 0x0000000000000190 0x0000000000000190  RW     8
  NOTE           0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
                 0x0000000000000024 0x0000000000000024  R      4
  GNU_EH_FRAME   0x0000000000000674 0x0000000000000674 0x0000000000000674
                 0x000000000000001c 0x000000000000001c  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e30 0x0000000000200e30 0x0000000000200e30
                 0x00000000000001d0 0x00000000000001d0  R      1

 Section to Segment mapping:
  Segment Sections...
   00     .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .init .plt .plt.got .text .fini .eh_frame_hdr .eh_frame 
   01     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
   02     .dynamic 
   03     .note.gnu.build-id 
   04     .eh_frame_hdr 
   05     
   06     .init_array .fini_array .jcr .dynamic .got 
There are 27 section headers, starting at offset 0x1820:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.build-i NOTE             00000000000001c8  000001c8
       0000000000000024  0000000000000000   A       0     0     4
  [ 2] .gnu.hash         GNU_HASH         00000000000001f0  000001f0
       000000000000003c  0000000000000000   A       3     0     8
  [ 3] .dynsym           DYNSYM           0000000000000230  00000230
       0000000000000138  0000000000000018   A       4     2     8
  [ 4] .dynstr           STRTAB           0000000000000368  00000368
       00000000000000ad  0000000000000000   A       0     0     1
  [ 5] .gnu.version      VERSYM           0000000000000416  00000416
       000000000000001a  0000000000000002   A       3     0     2
  [ 6] .gnu.version_r    VERNEED          0000000000000430  00000430
       0000000000000020  0000000000000000   A       4     1     8
  [ 7] .rela.dyn         RELA             0000000000000450  00000450
       00000000000000c0  0000000000000018   A       3     0     8
  [ 8] .init             PROGBITS         0000000000000510  00000510
       000000000000001a  0000000000000000  AX       0     0     4
  [ 9] .plt              PROGBITS         0000000000000530  00000530
       0000000000000010  0000000000000010  AX       0     0     16
  [10] .plt.got          PROGBITS         0000000000000540  00000540
       0000000000000010  0000000000000000  AX       0     0     8
  [11] .text             PROGBITS         0000000000000550  00000550
       0000000000000116  0000000000000000  AX       0     0     16
  [12] .fini             PROGBITS         0000000000000668  00000668
       0000000000000009  0000000000000000  AX       0     0     4
  [13] .eh_frame_hdr     PROGBITS         0000000000000674  00000674
       000000000000001c  0000000000000000   A       0     0     4
  [14] .eh_frame         PROGBITS         0000000000000690  00000690
       0000000000000064  0000000000000000   A       0     0     8
  [15] .init_array       INIT_ARRAY       0000000000200e30  00000e30
       0000000000000008  0000000000000000  WA       0     0     8
  [16] .fini_array       FINI_ARRAY       0000000000200e38  00000e38
       0000000000000008  0000000000000000  WA       0     0     8
  [17] .jcr              PROGBITS         0000000000200e40  00000e40
       0000000000000008  0000000000000000  WA       0     0     8
  [18] .dynamic          DYNAMIC          0000000000200e48  00000e48
       0000000000000190  0000000000000010  WA       4     0     8
  [19] .got              PROGBITS         0000000000200fd8  00000fd8
       0000000000000028  0000000000000008  WA       0     0     8
  [20] .got.plt          PROGBITS         0000000000201000  00001000
       0000000000000018  0000000000000008  WA       0     0     8
  [21] .data             PROGBITS         0000000000201018  00001018
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .bss              NOBITS           0000000000201020  00001020
       0000000000000008  0000000000000000  WA       0     0     4
  [23] .comment          PROGBITS         0000000000000000  00001020
       0000000000000034  0000000000000001  MS       0     0     1
  [24] .shstrtab         STRTAB           0000000000000000  0000173b
       00000000000000e4  0000000000000000           0     0     1
  [25] .symtab           SYMTAB           0000000000000000  00001058
       0000000000000528  0000000000000018          26    44     8
  [26] .strtab           STRTAB           0000000000000000  00001580
       00000000000001bb  0000000000000000           0     0     1
以下是share.so中的节标题:

gcc -fPIC -shared -o share.so share.c
Elf file type is DYN (Shared object file)
Entry point 0x550
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000006f4 0x00000000000006f4  R E    200000
  LOAD           0x0000000000000e30 0x0000000000200e30 0x0000000000200e30
                 0x00000000000001f0 0x00000000000001f8  RW     200000
  DYNAMIC        0x0000000000000e48 0x0000000000200e48 0x0000000000200e48
                 0x0000000000000190 0x0000000000000190  RW     8
  NOTE           0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
                 0x0000000000000024 0x0000000000000024  R      4
  GNU_EH_FRAME   0x0000000000000674 0x0000000000000674 0x0000000000000674
                 0x000000000000001c 0x000000000000001c  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e30 0x0000000000200e30 0x0000000000200e30
                 0x00000000000001d0 0x00000000000001d0  R      1

 Section to Segment mapping:
  Segment Sections...
   00     .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .init .plt .plt.got .text .fini .eh_frame_hdr .eh_frame 
   01     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
   02     .dynamic 
   03     .note.gnu.build-id 
   04     .eh_frame_hdr 
   05     
   06     .init_array .fini_array .jcr .dynamic .got 
There are 27 section headers, starting at offset 0x1820:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.build-i NOTE             00000000000001c8  000001c8
       0000000000000024  0000000000000000   A       0     0     4
  [ 2] .gnu.hash         GNU_HASH         00000000000001f0  000001f0
       000000000000003c  0000000000000000   A       3     0     8
  [ 3] .dynsym           DYNSYM           0000000000000230  00000230
       0000000000000138  0000000000000018   A       4     2     8
  [ 4] .dynstr           STRTAB           0000000000000368  00000368
       00000000000000ad  0000000000000000   A       0     0     1
  [ 5] .gnu.version      VERSYM           0000000000000416  00000416
       000000000000001a  0000000000000002   A       3     0     2
  [ 6] .gnu.version_r    VERNEED          0000000000000430  00000430
       0000000000000020  0000000000000000   A       4     1     8
  [ 7] .rela.dyn         RELA             0000000000000450  00000450
       00000000000000c0  0000000000000018   A       3     0     8
  [ 8] .init             PROGBITS         0000000000000510  00000510
       000000000000001a  0000000000000000  AX       0     0     4
  [ 9] .plt              PROGBITS         0000000000000530  00000530
       0000000000000010  0000000000000010  AX       0     0     16
  [10] .plt.got          PROGBITS         0000000000000540  00000540
       0000000000000010  0000000000000000  AX       0     0     8
  [11] .text             PROGBITS         0000000000000550  00000550
       0000000000000116  0000000000000000  AX       0     0     16
  [12] .fini             PROGBITS         0000000000000668  00000668
       0000000000000009  0000000000000000  AX       0     0     4
  [13] .eh_frame_hdr     PROGBITS         0000000000000674  00000674
       000000000000001c  0000000000000000   A       0     0     4
  [14] .eh_frame         PROGBITS         0000000000000690  00000690
       0000000000000064  0000000000000000   A       0     0     8
  [15] .init_array       INIT_ARRAY       0000000000200e30  00000e30
       0000000000000008  0000000000000000  WA       0     0     8
  [16] .fini_array       FINI_ARRAY       0000000000200e38  00000e38
       0000000000000008  0000000000000000  WA       0     0     8
  [17] .jcr              PROGBITS         0000000000200e40  00000e40
       0000000000000008  0000000000000000  WA       0     0     8
  [18] .dynamic          DYNAMIC          0000000000200e48  00000e48
       0000000000000190  0000000000000010  WA       4     0     8
  [19] .got              PROGBITS         0000000000200fd8  00000fd8
       0000000000000028  0000000000000008  WA       0     0     8
  [20] .got.plt          PROGBITS         0000000000201000  00001000
       0000000000000018  0000000000000008  WA       0     0     8
  [21] .data             PROGBITS         0000000000201018  00001018
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .bss              NOBITS           0000000000201020  00001020
       0000000000000008  0000000000000000  WA       0     0     4
  [23] .comment          PROGBITS         0000000000000000  00001020
       0000000000000034  0000000000000001  MS       0     0     1
  [24] .shstrtab         STRTAB           0000000000000000  0000173b
       00000000000000e4  0000000000000000           0     0     1
  [25] .symtab           SYMTAB           0000000000000000  00001058
       0000000000000528  0000000000000018          26    44     8
  [26] .strtab           STRTAB           0000000000000000  00001580
       00000000000001bb  0000000000000000           0     0     1
有了这些信息,我可以看到ELF头和程序头构成了文件的第一个0x1C8字节,这就是为什么第一节(.note.gnu.build-I)从偏移量0x1C8开始。当您考虑对齐要求时,在.init_数组之前但不包括.init_数组的所有截面的报告偏移都是有意义的

对我来说没有意义的是section.init_数组的偏移量。此节的对齐要求为8字节,上一节(.eh_帧)的结尾位于偏移量0x6F4处。这似乎意味着下一节应该位于0x6F8(4字节的填充)。但是,readelf报告.init_数组部分从偏移量0xE30开始

我认为可能在这个意外的间隙中插入了一些其他有用的信息,但是hextump只显示空字节。这让我相信这是某种填充。包含.init_数组段的加载段的对齐要求似乎不能解释这种填充。链接器为此共享对象创建的映射文件的一部分如下所示:

.eh_frame       0x0000000000000690       0x64
 *(.eh_frame)
 .eh_frame      0x0000000000000690       0x40 /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o
 .eh_frame      0x00000000000006d0       0x20 /tmp/ccDzwTL8.o
                                         0x38 (size before relaxing)
 .eh_frame      0x00000000000006f0        0x4 /usr/lib/gcc/x86_64-linux-gnu/5/crtendS.o
 *(.eh_frame.*)

.gcc_except_table
 *(.gcc_except_table .gcc_except_table.*)

.gnu_extab
 *(.gnu_extab*)

.exception_ranges
 *(.exception_ranges .exception_ranges*)
                0x0000000000200e30                . = DATA_SEGMENT_ALIGN (0x200000, 0x1000)

.eh_frame
 *(.eh_frame)
 *(.eh_frame.*)

.gnu_extab
 *(.gnu_extab)

.gcc_except_table
 *(.gcc_except_table .gcc_except_table.*)

.exception_ranges
 *(.exception_ranges .exception_ranges*)

.tdata
 *(.tdata .tdata.* .gnu.linkonce.td.*)

.tbss
 *(.tbss .tbss.* .gnu.linkonce.tb.*)
 *(.tcommon)

.preinit_array
 *(.preinit_array)

.init_array     0x0000000000200e30        0x8
 *(SORT(.init_array.*) SORT(.ctors.*))
 *(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors)
 .init_array    0x0000000000200e30        0x8 /usr/lib/gcc/x86_64-linux-gnu/5/crtbeginS.o
带有注释“=DATA\u SEGMENT\u ALIGN(0x200000,0x1000)”的行似乎也不能解释这种填充。我希望位置计数器的值为0x000000000002006F8


对ELF格式的细节有更多经验的人对这种意外的填充有什么解释吗?

我发现了填充的来源。根据这一点,Ubuntu提供的AMD64工具链可能会使用-z relro选项作为默认选项。这解释了为什么程序头表中有GNU_RELRO条目。内置的默认链接器脚本在.get.plt节之前包含一个DATA_SEGMENT_RELRO_END(offset,exp)指令。据此:

当'-z relro'选项不存在时,数据段\u relro\u END不存在 无,否则将填充数据段对齐,以便exp+偏移 与最常用的特定页面边界对齐 目标

这将解释为什么.get.plt部分的偏移量与最近的页面(0x1000)对齐。因此,从.init_数组到.get的部分被放置在上一页的末尾,该页在.eh_框架部分之后引入了神秘的填充

使用以下命令生成share.so时,程序头表中的GNU_RELRO条目和填充将消失:

gcc -fPIC -shared -Wl,-z,norelro -o share.so share.c

天才!谢谢分享!还有-对抗膨胀!