Bug 26659 - x86_64 pe relocation truncated to fit: R_X86_64_PC32 against undefined symbol
Summary: x86_64 pe relocation truncated to fit: R_X86_64_PC32 against undefined symbol
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.36
: P2 normal
Target Milestone: ---
Assignee: Tamar Christina
URL:
Keywords:
Depends on:
Blocks: 19011
  Show dependency treegraph
 
Reported: 2020-09-23 20:29 UTC by sourceware-bugzilla
Modified: 2021-10-01 10:25 UTC (History)
5 users (show)

See Also:
Host:
Target: x86_64 pe
Build:
Last reconfirmed: 2021-03-29 00:00:00


Attachments
testcase source from msys2 #6986 (1.46 KB, application/x-zip-compressed)
2020-09-29 01:58 UTC, sourceware-bugzilla
Details
testcase objects from msys2 #6986 (5.02 KB, application/x-zip-compressed)
2020-09-29 01:58 UTC, sourceware-bugzilla
Details

Note You need to log in before you can comment on or make changes to this bug.
Description sourceware-bugzilla 2020-09-23 20:29:24 UTC
After the change in default image base addresses in PR #19011, undefined weak symbols are resulting in the message
relocation truncated to fit: R_X86_64_PC32 against undefined symbol
Comment 1 Mateusz Mikuła 2020-09-28 19:14:42 UTC
There is discussion about this issue in https://github.com/msys2/MINGW-packages/issues/6986

I tested it with GCC 10.2, Binutils 2.35, Clang/LLD 11.
Using reproducer in shared.zip by calling ./build.sh (designed to run under MSYS2) GCC+ld.bfd fails with this error:

D:\tmp\weak\shared-wiki\build-bfd/../power_slow.c:15:(.text+0x18): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `user_hook'

The same code works as expected when using GCC+ld.lld, Clang+ld.bfd, Clang+ld.lld.

Extracted details from issue in MSYS2 repo (I couldn't find anything beyond what was already said there):

Relocations:
Clang:
  Section (1) .text {
    0xB IMAGE_REL_AMD64_REL32 .refptr.user_hook (10)
    0x1F IMAGE_REL_AMD64_REL32 .refptr.user_hook (10)
    0x4D IMAGE_REL_AMD64_REL32 power2 (24)
  }

GCC:
  Section (1) .text {
    0xE IMAGE_REL_AMD64_REL32 .refptr.user_hook (29)
    0x18 IMAGE_REL_AMD64_REL32 user_hook (33)
    0x37 IMAGE_REL_AMD64_REL32 power2 (31)
  }

Relevant symbols:
  Symbol {
    Name: user_hook
    Value: 0
    Section: IMAGE_SYM_UNDEFINED (0)
    BaseType: Null (0x0)
    ComplexType: Function (0x2)
    StorageClass: WeakExternal (0x69)
    AuxSymbolCount: 1
    AuxWeakExternal {
      Linked: .weak.user_hook.power3 (30)
      Search: NoLibrary (0x1)
    }
  }
Symbol {
    Name: .rdata$.refptr.user_hook
    Value: 0
    Section: .rdata$.refptr.user_hook (12)
    BaseType: Null (0x0)
    ComplexType: Null (0x0)
    StorageClass: Static (0x3)
    AuxSymbolCount: 1
    AuxSectionDef {
      Length: 8
      RelocationCount: 1
      LineNumberCount: 0
      Checksum: 0x0
      Number: 0
      Selection: Any (0x2)
    }
  }
  Symbol {
    Name: .refptr.user_hook
    Value: 0
    Section: .rdata$.refptr.user_hook (12)
    BaseType: Null (0x0)
    ComplexType: Null (0x0)
    StorageClass: External (0x2)
    AuxSymbolCount: 0
  }

Assembly and object file are included in objects.zip.
Comment 2 sourceware-bugzilla 2020-09-29 01:58:13 UTC
Created attachment 12867 [details]
testcase source from msys2 #6986
Comment 3 sourceware-bugzilla 2020-09-29 01:58:49 UTC
Created attachment 12868 [details]
testcase objects from msys2 #6986
Comment 4 Tamar Christina 2021-03-29 14:25:13 UTC
Confirmed, this is breaking a lot of projects on Windows including GHC.
Comment 5 Tamar Christina 2021-04-01 11:09:23 UTC
testing patch.
Comment 6 Sourceware Commits 2021-04-01 16:55:35 UTC
The master branch has been updated by Tamar Christina <tnfchris@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=74edb473c9ecf5e2053ecf8e429ee608feafb9e1

commit 74edb473c9ecf5e2053ecf8e429ee608feafb9e1
Author: Tamar Christina <tamar.christina@arm.com>
Date:   Thu Apr 1 17:10:38 2021 +0100

    PE/Windows x86_64: Fix weak undef symbols after image base change
    
    The change in PR19011 changed the image load address from being in the lower
    32-bit address space to the higher 64-bit address space.
    
    However when you have a weak undef symbol which stays undef at the end of
    linking the linker has to resolve this (Windows loader does not support undef
    symbols).  As such typically these would resolve to 0.
    
    The relocation used for these weak symbols are the normal 32-bit PC_REL call
    relocs.  So when doing the overflow check LD checks if the distance between the
    symbol and the call is within range.  However now that the load address is
    > 32-bits and the symbol val is 0 this overflow check will always fail.
    
    As such the linker gives a bogus error.  This patch makes the linker not emit
    the overflow failure but chooses to still let the check be performed (as it's
    mid-end code).
    
    One down side of this is that it does break the common convention that the call
    be to sym at 0x0. i.e. before you'd get
    
          401015:   74 05                   je     40101c
          401017:   e8 e4 ef bf ff          callq  0
    
    and now you get
    
       140001015:   74 05                   je     14000101c
       140001017:   e8 e4 ef ff bf          call   100000000
    
    since the call is PC_REL there's no way to get the range large enough to
    resolve to 0.  As such I have chosen to leave it as the furthest simple range
    that we can still represent.
    
    By only ignoring the error we leave the symbol value itself to still be 0
    such that the if(<symbol>) checks still work correctly.
    
    bfd/ChangeLog:
    
    2021-04-01  Tamar Christina  <tamar.christina@arm.com>
    
            PR ld/26659
            * cofflink.c (_bfd_coff_generic_relocate_section): Ignore overflow.
    
    ld/ChangeLog:
    
    2021-04-01  Tamar Christina  <tamar.christina@arm.com>
    
            PR ld/26659
            * testsuite/ld-pe/pe.exp: Add test.
            * testsuite/ld-pe/pr26659-weak-undef-sym.d: New test.
            * testsuite/ld-pe/pr26659-weak-undef-sym.s: New test.
Comment 7 Sourceware Commits 2021-04-01 17:07:56 UTC
The binutils-2_36-branch branch has been updated by Tamar Christina <tnfchris@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0ff9fad8bf790eebb21a1c1ee378f1c2dd1971af

commit 0ff9fad8bf790eebb21a1c1ee378f1c2dd1971af
Author: Tamar Christina <tamar.christina@arm.com>
Date:   Thu Apr 1 17:10:38 2021 +0100

    PE/Windows x86_64: Fix weak undef symbols after image base change
    
    The change in PR19011 changed the image load address from being in the lower
    32-bit address space to the higher 64-bit address space.
    
    However when you have a weak undef symbol which stays undef at the end of
    linking the linker has to resolve this (Windows loader does not support undef
    symbols).  As such typically these would resolve to 0.
    
    The relocation used for these weak symbols are the normal 32-bit PC_REL call
    relocs.  So when doing the overflow check LD checks if the distance between the
    symbol and the call is within range.  However now that the load address is
    > 32-bits and the symbol val is 0 this overflow check will always fail.
    
    As such the linker gives a bogus error.  This patch makes the linker not emit
    the overflow failure but chooses to still let the check be performed (as it's
    mid-end code).
    
    One down side of this is that it does break the common convention that the call
    be to sym at 0x0. i.e. before you'd get
    
          401015:   74 05                   je     40101c
          401017:   e8 e4 ef bf ff          callq  0
    
    and now you get
    
       140001015:   74 05                   je     14000101c
       140001017:   e8 e4 ef ff bf          call   100000000
    
    since the call is PC_REL there's no way to get the range large enough to
    resolve to 0.  As such I have chosen to leave it as the furthest simple range
    that we can still represent.
    
    By only ignoring the error we leave the symbol value itself to still be 0
    such that the if(<symbol>) checks still work correctly.
    
    bfd/ChangeLog:
    
    2021-04-01  Tamar Christina  <tamar.christina@arm.com>
    
            PR ld/26659
            * cofflink.c (_bfd_coff_generic_relocate_section): Ignore overflow.
    
    ld/ChangeLog:
    
    2021-04-01  Tamar Christina  <tamar.christina@arm.com>
    
            PR ld/26659
            * testsuite/ld-pe/pe.exp: Add test.
            * testsuite/ld-pe/pr26659-weak-undef-sym.d: New test.
            * testsuite/ld-pe/pr26659-weak-undef-sym.s: New test.
    
    (cherry picked from commit 74edb473c9ecf5e2053ecf8e429ee608feafb9e1)
Comment 8 Tamar Christina 2021-04-01 17:11:12 UTC
Fixed in mainline and 2.36.
Comment 9 Sourceware Commits 2021-04-22 08:55:20 UTC
The master branch has been updated by Jan Beulich <jbeulich@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d018cd835ccdbfcfbc1e144a836974a9b9c385b6

commit d018cd835ccdbfcfbc1e144a836974a9b9c385b6
Author: Jan Beulich <jbeulich@suse.com>
Date:   Thu Apr 22 10:55:07 2021 +0200

    x86-64/PE: adjust PR ld/26659 testcase for Cygwin
    
    While the testcase put in place by 74edb473c9ec ("PE/Windows x86_64: Fix
    weak undef symbols after image base change") is fine for MingW, it fails
    for Cygwin. This is because the default image base is different there
    (for whatever reason).