This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Discrepancy with .reloc section between PE and PE+ emulations when linking -r.
- From: Dave Korn <dave dot korn dot cygwin at googlemail dot com>
- To: binutils at sourceware dot org
- Date: Fri, 13 Feb 2009 03:29:52 +0000
- Subject: Discrepancy with .reloc section between PE and PE+ emulations when linking -r.
Hi everyone,
The promised follow-up. Here's a trivial assembler source file:
/usr/build/obj-binutils-clean $ cat
/usr/build/src-binutils/ld/testsuite/ld-pe/longsecn.s
.text
.global _start
_start:
.byte 1
.global data
.data
data:
.byte 2
.section .text.very.long.section.name,"rx"
vls:
.byte 3
.section .data$1,"wd"
.byte 4
.section .rodata$1,"rd"
.byte 5
.section .data$123,"wd"
.byte 4
.section .rodata$123,"rd"
.byte 5
.section .data$123456789,"wd"
.byte 4
.section .rodata$123456789,"rd"
.byte 5
.section .data.very.long.section,"wd"
.byte 6
.section .rodata.very.long.section,"rd"
.byte 7
.section .data.very.long.section$1,"wd"
.byte 6
.section .rodata.very.long.section$1,"rd"
.byte 7
.section .data.very.long.section$1234,"wd"
.byte 6
.section .rodata.very.long.section$1234,"rd"
.byte 7
.end
I've built binutils HEAD for i686-pc-cygwin (native) and x86_64-pc-mingw32
(cross); the first is PE, the second PE+. I assemble it with each toolchain
to get an object file, then I link it with each toolchain, both with and
without -r, like so:
/usr/build/obj-binutils-clean $ cd ld
/usr/build/obj-binutils-clean/ld $ ../gas/as-new -o tmpdir/dump0.o
/usr/build/src-binutils/ld/testsuite/ld-pe/longsecn.s
/usr/build/obj-binutils-clean/ld $ ./ld-new
-L/usr/build/src-binutils/ld/testsuite/ld-pe -r -o tmpdir/dump.r tmpdir/dump0.o
/usr/build/obj-binutils-clean/ld $ ./ld-new
-L/usr/build/src-binutils/ld/testsuite/ld-pe -o tmpdir/dump tmpdir/dump0.o
And then I use objdump to view the section headers, like so:
/usr/build/obj-binutils-64-clean/ld $ ../binutils/objdump -h tmpdir/dump.r
To cut to the chase: the assembled .o files, and the fully-linked
executables both contain exactly the same section lists; but the
relocatably-linked dump.r files have a difference. The one generated by the
pe-i386 (32-bit) target contains an extra section, compared to the one
generated by the pe-x86-64 (PE+) target:
/usr/build/obj-binutils-clean/ld $ ../binutils/objdump -h tmpdir/dump.r
tmpdir/dump.r: file format pe-i386
Sections:
Idx Name Size VMA LMA File off Algn
[ ... snip ... ]
16 .reloc 00000004 00000000 00000000 000002fc 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
Closer examination shows a difference in the logic that creates the output
BFDs between the pe.em and pep.em files, in the
gld_${EMULATION_NAME}_after_open() function. In pe.em, this reads:
#if defined (TARGET_IS_i386pe) \
|| defined (TARGET_IS_armpe) \
|| defined (TARGET_IS_arm_epoc_pe) \
|| defined (TARGET_IS_arm_wince_pe)
if (!link_info.relocatable)
pe_dll_build_sections (link_info.output_bfd, &link_info);
else
pe_exe_build_sections (link_info.output_bfd, &link_info);
#else
if (link_info.shared)
pe_dll_build_sections (link_info.output_bfd, &link_info);
#endif
... whereas in pep.em, the corresponding section reads:
#ifndef TARGET_IS_i386pep
if (link_info.shared)
#else
if (!link_info.relocatable)
#endif
pep_dll_build_sections (link_info.output_bfd, &link_info);
#ifndef TARGET_IS_i386pep
else
pep_exe_build_sections (link_info.output_bfd, &link_info);
#endif
A close reading shows that for the i386pe target, one of
pe_dll_build_sections or pe_exe_build_sections is always called. In the
equivalent section for i386pep, pep_exe_build_sections is never called.
The pe*_???_build_sections() functions create output BFDs for .edata (in the
case of DLLs only) and .reloc sections, and the presence of the .reloc section
in the PE relocatable is directly attributable to the call to
pe_exe_build_sections, just as the absence of the .reloc section in the PE+
relocatable is directly attributable to the absense of any such call.
I haven't found out yet which one is right and which one is wrong, I have to
study the spec to figure out what's going on here, so the first thing I'd like
to ask is if anybody knows whether this is deliberate by design behaviour, or
is one of the emulations doing it wrong?
The code looks suggestive like maybe someone reversed the ordering of the if
() conditions, in order that they could both share the same call to
pep_dll_build_sections in their then clauses, requiring them to change the
#ifdef test in the pe.em version into an #ifndef in pep.em, and then maybe
cut-n-pastoed that "#ifndef" to wrap the "else ... pep_exe_build_sections"
clause, but it could be entirely deliberate and correct for all I know. I
have tested changing the second "#ifndef" in the pep.em snippet to "#ifdef",
and that gets me a relocatable object with a .reloc section, as on plain old
PE32, but I'm not sure yet if it's right; does anyone know for sure off the
top of their head?
cheers,
DaveK