评论区的非零地址值有什么用?
what is the use of the non-zero address value of the comment section?
我们正在努力重现与参考相同的 .elf 文件。我们就快完成了,除了注释部分的地址之外,文件完全相同(其余部分在二进制方面 100% 相同)。
使用 readelf -e
转储其中一个 .elf 文件如下(目标是 powerpc,但我认为它不是很重要):
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: PowerPC
Version: 0x1
Entry point address: 0x1800f88
Start of program headers: 52 (bytes into file)
Start of section headers: 1367724 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 5
Size of section headers: 40 (bytes)
Number of section headers: 20
Section header string table index: 19
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 018000f4 0000f4 000011 00 A 0 0 1
[ 2] .hash HASH 01800108 000108 000248 04 A 3 0 4
[ 3] .dynsym DYNSYM 01800350 000350 0004d0 10 A 4 1 4
[ 4] .dynstr STRTAB 01800820 000820 000473 00 A 0 0 1
[ 5] .rela.plt RELA 01800c94 000c94 0002dc 0c A 3 16 4
[ 6] .rela.sbss RELA 01800f70 000f70 000018 0c A 3 15 4
[ 7] .text PROGBITS 01800f88 000f88 0e4f78 00 AX 0 0 4
[ 8] .rodata PROGBITS 018e5f00 0e5f00 064708 00 A 0 0 8
[ 9] .sdata2 PROGBITS 0194a608 14a608 000000 00 A 0 0 4
[10] .data PROGBITS 0198a608 14a608 000b5c 00 WA 0 0 8
[11] .dynamic DYNAMIC 0198b164 14b164 000090 08 WA 4 0 4
[12] .got2 PROGBITS 0198b1f4 14b1f4 000024 00 WA 0 0 1
[13] .got PROGBITS 0198b218 14b218 000010 04 WA 0 0 4
[14] .sdata PROGBITS 0198b228 14b228 001814 00 WA 0 0 8
[15] .sbss NOBITS 0198ca40 14ca40 00064c 00 WA 0 0 8
[16] .plt NOBITS 0198d08c 14ca40 000324 00 WAX 0 0 4
[17] .bss NOBITS 0198d3b0 14ca40 223920 00 WA 0 0 16
[18] .comment PROGBITS 0026a8bd 14ca40 0013cb 00 0 0 1
[19] .shstrtab STRTAB 00000000 14de0b 00009e 00 0 0 1
地址为 0
的部分是有意义的:加载程序时不会映射这些部分。其他 0x18xxxxx
值由链接器规范文件指定。
但是为什么注释部分有一个非零地址(其中包含编译器版本和执行平台等详细信息),链的哪个部分使用它(调试器?),以及链接器如何决定在哪里放?
链接描述文件甚至没有提到这个 .comment
部分:
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc",
"elf32-powerpc")
OUTPUT_ARCH(powerpc)
ENTRY(_start)
SEARCH_DIR(/opt/gnu/powerpc-wrs-vxworks/lib);
/* Do we need any of these for elf?
__DYNAMIC = 0; */
PROVIDE (__stack = 0);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x01800000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rela.got : { *(.rela.got) }
.rela.got1 : { *(.rela.got1) }
.rela.got2 : { *(.rela.got2) }
.rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) }
.rela.init : { *(.rela.init) }
.rela.fini : { *(.rela.fini) }
.rela.bss : { *(.rela.bss) }
.rela.plt : { *(.rela.plt) }
.rela.sdata : { *(.rela.sdata) }
.rela.sbss : { *(.rela.sbss) }
.rela.sdata2 : { *(.rela.sdata2) }
.rela.sbss2 : { *(.rela.sbss2) }
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0
.init : { *(.init) } =0
.fini : { *(.fini) } =0
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
_etext = .;
PROVIDE (etext = .);
.sdata2 : { *(.sdata2) }
.sbss2 : { *(.sbss2) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. It would
be more correct to do this:
. = ALIGN(0x40000) + (ALIGN(8) & (0x40000 - 1));
The current expression does not correctly handle the case of a
text segment ending precisely at the end of a page; it causes the
data segment to skip a page. The above expression does not have
this problem, but it will currently (2/95) cause BFD to allocate
a single segment, combining both text and data, for this case.
This will prevent the text segment from being shared among
multiple executions of the program; I think that is more
important than losing a page of the virtual address space (note
that no actual memory is lost; the page which is skipped can not
be referenced). */
. = ALIGN(8) + 0x40000;
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.got1 : { *(.got1) }
.dynamic : { *(.dynamic) }
/* Put .ctors and .dtors next to the .got2 section, so that the pointers
get relocated with -mrelocatable. Also put in the .fixup pointers.
The current compiler no longer needs this, but keep it around for 2.7.2 */
PROVIDE (_GOT2_START_ = .);
.got2 : { *(.got2) }
PROVIDE (__CTOR_LIST__ = .);
.ctors : { *(.ctors) }
PROVIDE (__CTOR_END__ = .);
PROVIDE (__DTOR_LIST__ = .);
.dtors : { *(.dtors) }
PROVIDE (__DTOR_END__ = .);
PROVIDE (_FIXUP_START_ = .);
.fixup : { *(.fixup) }
PROVIDE (_FIXUP_END_ = .);
PROVIDE (_GOT2_END_ = .);
PROVIDE (_GOT_START_ = .);
.got : { *(.got) }
.got.plt : { *(.got.plt) }
PROVIDE (_GOT_END_ = .);
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
.sbss :
{
PROVIDE (__sbss_start = .);
*(.sbss)
*(.scommon)
*(.dynsbss)
PROVIDE (__sbss_end = .);
}
.plt : { *(.plt) }
.bss :
{
PROVIDE (__bss_start = .);
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* These are needed for ELF backends which have not yet been
converted to the new style linker. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}
链接器版本也很旧(是的,我知道...):
GNU ld 2.9.1
Copyright 1997 Free Software Foundation, Inc.
But why is there a non-zero address for the comment section
链接器中很可能存在错误,它将未初始化的数据放在那里(数据无关紧要,但可重现的构建 是 的设计目标,因此无法实现可重现的构建 是 一个错误)。
您没有说您使用的是哪个链接器(以及哪个版本)。
使用 GNU ld (GNU Binutils for Debian) 2.34
或 GNU gold (GNU Binutils for Debian 2.34) 1.16
,对于 .comment
部分的 Addr
.
,我始终得到 00000000
我们正在努力重现与参考相同的 .elf 文件。我们就快完成了,除了注释部分的地址之外,文件完全相同(其余部分在二进制方面 100% 相同)。
使用 readelf -e
转储其中一个 .elf 文件如下(目标是 powerpc,但我认为它不是很重要):
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: PowerPC
Version: 0x1
Entry point address: 0x1800f88
Start of program headers: 52 (bytes into file)
Start of section headers: 1367724 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 5
Size of section headers: 40 (bytes)
Number of section headers: 20
Section header string table index: 19
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 018000f4 0000f4 000011 00 A 0 0 1
[ 2] .hash HASH 01800108 000108 000248 04 A 3 0 4
[ 3] .dynsym DYNSYM 01800350 000350 0004d0 10 A 4 1 4
[ 4] .dynstr STRTAB 01800820 000820 000473 00 A 0 0 1
[ 5] .rela.plt RELA 01800c94 000c94 0002dc 0c A 3 16 4
[ 6] .rela.sbss RELA 01800f70 000f70 000018 0c A 3 15 4
[ 7] .text PROGBITS 01800f88 000f88 0e4f78 00 AX 0 0 4
[ 8] .rodata PROGBITS 018e5f00 0e5f00 064708 00 A 0 0 8
[ 9] .sdata2 PROGBITS 0194a608 14a608 000000 00 A 0 0 4
[10] .data PROGBITS 0198a608 14a608 000b5c 00 WA 0 0 8
[11] .dynamic DYNAMIC 0198b164 14b164 000090 08 WA 4 0 4
[12] .got2 PROGBITS 0198b1f4 14b1f4 000024 00 WA 0 0 1
[13] .got PROGBITS 0198b218 14b218 000010 04 WA 0 0 4
[14] .sdata PROGBITS 0198b228 14b228 001814 00 WA 0 0 8
[15] .sbss NOBITS 0198ca40 14ca40 00064c 00 WA 0 0 8
[16] .plt NOBITS 0198d08c 14ca40 000324 00 WAX 0 0 4
[17] .bss NOBITS 0198d3b0 14ca40 223920 00 WA 0 0 16
[18] .comment PROGBITS 0026a8bd 14ca40 0013cb 00 0 0 1
[19] .shstrtab STRTAB 00000000 14de0b 00009e 00 0 0 1
地址为 0
的部分是有意义的:加载程序时不会映射这些部分。其他 0x18xxxxx
值由链接器规范文件指定。
但是为什么注释部分有一个非零地址(其中包含编译器版本和执行平台等详细信息),链的哪个部分使用它(调试器?),以及链接器如何决定在哪里放?
链接描述文件甚至没有提到这个 .comment
部分:
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc",
"elf32-powerpc")
OUTPUT_ARCH(powerpc)
ENTRY(_start)
SEARCH_DIR(/opt/gnu/powerpc-wrs-vxworks/lib);
/* Do we need any of these for elf?
__DYNAMIC = 0; */
PROVIDE (__stack = 0);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x01800000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rela.got : { *(.rela.got) }
.rela.got1 : { *(.rela.got1) }
.rela.got2 : { *(.rela.got2) }
.rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) }
.rela.init : { *(.rela.init) }
.rela.fini : { *(.rela.fini) }
.rela.bss : { *(.rela.bss) }
.rela.plt : { *(.rela.plt) }
.rela.sdata : { *(.rela.sdata) }
.rela.sbss : { *(.rela.sbss) }
.rela.sdata2 : { *(.rela.sdata2) }
.rela.sbss2 : { *(.rela.sbss2) }
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0
.init : { *(.init) } =0
.fini : { *(.fini) } =0
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
_etext = .;
PROVIDE (etext = .);
.sdata2 : { *(.sdata2) }
.sbss2 : { *(.sbss2) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. It would
be more correct to do this:
. = ALIGN(0x40000) + (ALIGN(8) & (0x40000 - 1));
The current expression does not correctly handle the case of a
text segment ending precisely at the end of a page; it causes the
data segment to skip a page. The above expression does not have
this problem, but it will currently (2/95) cause BFD to allocate
a single segment, combining both text and data, for this case.
This will prevent the text segment from being shared among
multiple executions of the program; I think that is more
important than losing a page of the virtual address space (note
that no actual memory is lost; the page which is skipped can not
be referenced). */
. = ALIGN(8) + 0x40000;
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.got1 : { *(.got1) }
.dynamic : { *(.dynamic) }
/* Put .ctors and .dtors next to the .got2 section, so that the pointers
get relocated with -mrelocatable. Also put in the .fixup pointers.
The current compiler no longer needs this, but keep it around for 2.7.2 */
PROVIDE (_GOT2_START_ = .);
.got2 : { *(.got2) }
PROVIDE (__CTOR_LIST__ = .);
.ctors : { *(.ctors) }
PROVIDE (__CTOR_END__ = .);
PROVIDE (__DTOR_LIST__ = .);
.dtors : { *(.dtors) }
PROVIDE (__DTOR_END__ = .);
PROVIDE (_FIXUP_START_ = .);
.fixup : { *(.fixup) }
PROVIDE (_FIXUP_END_ = .);
PROVIDE (_GOT2_END_ = .);
PROVIDE (_GOT_START_ = .);
.got : { *(.got) }
.got.plt : { *(.got.plt) }
PROVIDE (_GOT_END_ = .);
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
.sbss :
{
PROVIDE (__sbss_start = .);
*(.sbss)
*(.scommon)
*(.dynsbss)
PROVIDE (__sbss_end = .);
}
.plt : { *(.plt) }
.bss :
{
PROVIDE (__bss_start = .);
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* These are needed for ELF backends which have not yet been
converted to the new style linker. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}
链接器版本也很旧(是的,我知道...):
GNU ld 2.9.1
Copyright 1997 Free Software Foundation, Inc.
But why is there a non-zero address for the comment section
链接器中很可能存在错误,它将未初始化的数据放在那里(数据无关紧要,但可重现的构建 是 的设计目标,因此无法实现可重现的构建 是 一个错误)。
您没有说您使用的是哪个链接器(以及哪个版本)。
使用 GNU ld (GNU Binutils for Debian) 2.34
或 GNU gold (GNU Binutils for Debian 2.34) 1.16
,对于 .comment
部分的 Addr
.
00000000