Bug 1713891

Summary: Impossible to link large object files due to glibc/gcc relocation truncation
Product: [Fedora] Fedora Reporter: Yann Droneaud <yann>
Component: glibcAssignee: Carlos O'Donell <codonell>
Status: CLOSED NOTABUG QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: low Docs Contact:
Priority: unspecified    
Version: 30CC: arjun.is, codonell, dj, fweimer, law, mfabian, pfrankli, rth, siddhesh
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-08-22 16:38:08 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Yann Droneaud 2019-05-25 13:10:16 UTC
On x86_64, I'm not able to link a ~2GiBytes object file into an executable or a shared library.

Using:
- binutils-2.31.1-29.fc30.x86_64
- gcc-9.1.1-1.fc30.x86_64
- glibc-devel-2.29-12.fc30.x86_64

Start by assembling the following code:

  $ cat large.S
          .section .rodata
          .globl large
          .p2align 0
          .type  large, @object
          .size  large, SIZE
  large:
          .zero  SIZE

  $ gcc -DSIZE=$((2**31)) -c -o large.o large.S

Then linking the large object as a shared object fails:

  $ gcc -shared -o liblarge.so large.o
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/crti.o: in function `_init':
  (.init+0xb): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `__gmon_start__'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o: in function `deregister_tm_clones':
  crtstuff.c:(.text+0x3): relocation truncated to fit: R_X86_64_PC32 against `.tm_clone_table'
  /usr/bin/ld: crtstuff.c:(.text+0xa): relocation truncated to fit: R_X86_64_PC32 against symbol `__TMC_END__' defined in .got.plt section in liblarge.so
  /usr/bin/ld: crtstuff.c:(.text+0x16): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `_ITM_deregisterTMCloneTable'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o: in function `register_tm_clones':
  crtstuff.c:(.text+0x33): relocation truncated to fit: R_X86_64_PC32 against `.tm_clone_table'
  /usr/bin/ld: crtstuff.c:(.text+0x3a): relocation truncated to fit: R_X86_64_PC32 against symbol `__TMC_END__' defined in .got.plt section in liblarge.so
  /usr/bin/ld: crtstuff.c:(.text+0x57): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `_ITM_registerTMCloneTable'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o: in function `__do_global_dtors_aux':
  crtstuff.c:(.text+0x76): relocation truncated to fit: R_X86_64_PC32 against `.bss'
  /usr/bin/ld: crtstuff.c:(.text+0x81): relocation truncated to fit: R_X86_64_GOTPCREL against symbol `__cxa_finalize@@GLIBC_2.2.5' defined in .text section in //lib64/libc.so.6
  /usr/bin/ld: crtstuff.c:(.text+0x8e): relocation truncated to fit: R_X86_64_PC32 against symbol `__dso_handle' defined in .data.rel.ro.local section in /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o
  /usr/bin/ld: crtstuff.c:(.text+0x9e): additional relocation overflows omitted from the output
  liblarge.so: PC-relative offset overflow in PLT entry for `__cxa_finalize@@GLIBC_2.2.5'
  collect2: error: ld returned 1 exit status

Or linking the large object as an executable fails:

  $ cat main.c
  int main(void)
  {
          return 0;
  }

  $ gcc -c -o main.o main.c

  $ gcc -o large main.o large.o 
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/crt1.o: in function `_start':
  (.text+0x2a): relocation truncated to fit: R_X86_64_GOTPCRELX against symbol `__libc_start_main@@GLIBC_2.2.5' defined in .text section in //lib64/libc.so.6
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/crt1.o:(.eh_frame+0x20): relocation truncated to fit: R_X86_64_PC32 against `.text'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/crt1.o:(.eh_frame+0x50): relocation truncated to fit: R_X86_64_PC32 against `.text'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/crti.o: in function `_init':
  (.init+0xb): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `__gmon_start__'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbegin.o: in function `deregister_tm_clones':
  crtstuff.c:(.text+0x7): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbegin.o: in function `register_tm_clones':
  crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_32S against `.tm_clone_table'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbegin.o: in function `__do_global_dtors_aux':
  crtstuff.c:(.text+0x76): relocation truncated to fit: R_X86_64_PC32 against `.bss'
  /usr/bin/ld: crtstuff.c:(.text+0x88): relocation truncated to fit: R_X86_64_PC32 against `.bss'
  /usr/bin/ld: main.o:(.eh_frame+0x20): relocation truncated to fit: R_X86_64_PC32 against `.text'
  /usr/bin/ld: //usr/lib64/libc_nonshared.a(elf-init.oS): in function `__libc_csu_init':
  (.text+0x9): relocation truncated to fit: R_X86_64_PC32 against symbol `__init_array_start' defined in .init_array section in large
  /usr/bin/ld: (.text+0x20): additional relocation overflows omitted from the output
  collect2: error: ld returned 1 exit status

Or linking the large object as an position independent executable (PIE) fails:

  $ gcc -fPIE -c -o main.o main.c

  $ gcc -pie -fPIE -o large main.o large.o 
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/Scrt1.o: in function `_start':
  (.text+0x2a): relocation truncated to fit: R_X86_64_GOTPCRELX against symbol `__libc_start_main@@GLIBC_2.2.5' defined in .text section in //lib64/libc.so.6
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/Scrt1.o:(.eh_frame+0x20): relocation truncated to fit: R_X86_64_PC32 against `.text'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/../../../../lib64/crti.o: in function `_init':
  (.init+0xb): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `__gmon_start__'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o: in function `deregister_tm_clones':
  crtstuff.c:(.text+0x3): relocation truncated to fit: R_X86_64_PC32 against `.tm_clone_table'
  /usr/bin/ld: crtstuff.c:(.text+0xa): relocation truncated to fit: R_X86_64_PC32 against symbol `__TMC_END__' defined in .data section in large
  /usr/bin/ld: crtstuff.c:(.text+0x16): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `_ITM_deregisterTMCloneTable'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o: in function `register_tm_clones':
  crtstuff.c:(.text+0x33): relocation truncated to fit: R_X86_64_PC32 against `.tm_clone_table'
  /usr/bin/ld: crtstuff.c:(.text+0x3a): relocation truncated to fit: R_X86_64_PC32 against symbol `__TMC_END__' defined in .data section in large
  /usr/bin/ld: crtstuff.c:(.text+0x57): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `_ITM_registerTMCloneTable'
  /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/9/crtbeginS.o: in function `__do_global_dtors_aux':
  crtstuff.c:(.text+0x76): relocation truncated to fit: R_X86_64_PC32 against `.bss'
  /usr/bin/ld: crtstuff.c:(.text+0x81): additional relocation overflows omitted from the output
  large: PC-relative offset overflow in PLT entry for `__cxa_finalize@@GLIBC_2.2.5'
  collect2: error: ld returned 1 exit status

Perhaps Glibc and GCC runtimes should probably be generated in a way allowing large relocation

(Note: SIZE define can be smaller than 2GiBytes. In particular is has to be anything larger than 2147474944 to trigger the error when building a shared library)

Comment 1 Yann Droneaud 2019-05-25 13:25:44 UTC
(In reply to Yann Droneaud from comment #0)

> Perhaps Glibc and GCC runtimes should probably be generated in a way
> allowing large relocation

I'm thinking about

  -mcmodel=large

      Generate code for the large model. This model makes no assumptions about addresses and sizes of sections.

https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/x86-Options.html#index-mcmodel_003dlarge-3

But the option description for ARMv8 AArch64 scares me a bit:

  -mcmodel=large

      Generate code for the large code model. This makes no assumptions about addresses and sizes of sections. Programs can be statically linked only.

https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/AArch64-Options.html#index-mcmodel_003dlarge

Comment 2 Florian Weimer 2019-05-25 13:51:00 UTC
The x86-64 instruction encoding only offers 32-bit PC-relative addressing.  This is far more than your typical RISC architecture, but it is still a limit that can be reached on today's machines.  -mcmodel=large works around this, at a performance cost, which is why this option is not enabled by default.  I do not think there is a bug here; this is working as designed.

(The AArch64 architecture is very different and has different limitations.)

Comment 3 Carlos O'Donell 2019-08-22 16:38:08 UTC
I'm marking this CLOSED/NOTABUG. There are limits to the size of objects you can link. We would need a strong rationale to support such objects by default by making it possible for the entire runtime to support such large objects.