This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]