This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC 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]

[x86-64] Default HAVE_LD_PIE_COPYRELOC to false


On x86-64, in PIE mode, accesses to external data don't use the conservative GOT-relative address, but rather use pcrel. A copy relocation will be created if the external data is defined in a DSO.

// a.o
// (x) GCC<5, movq a@GOTPCREL(%rip), %rax; movl (%rax), %eax
// (y) GCC>=5 (since commit 130f233477ed03a7bdffb832e7eb9f0a366e0d6b), movl a(%rip), %eax
extern int a; int foo() { return a; }

// b.o or b.so
__attribute__((visibility("protected"))) int a;

(1) When a.o and b.o are linked together with -pie (`a` is non-preemptable)
 If R_X86_64_GOTPCRELX (-mrelax-relocations=yes) is enabled, we get:
 (x) leaq a(%rip),%rax; movl (%rax),%eax (8 bytes, 2 insns)
 (y) movl $a(%rip),%eax (6 bytes, 1 insn)
 See below.

(2) When a.o and b.so are linked together with -pie (`a` is external)
 (x) nothing special
 movq a@gotpcrel(%rip),%rax; movl (%rax),%eax

 For (y), there is a copy relocation, which plays badly with protected data preemption. Linkers don't have an agreement:
 ld.bfd creates a copy relocation
   movl a(%rip),%eax
 gold doesn't allow preemption (after https://sourceware.org/bugzilla/show_bug.cgi?id=19823)
   error: a.o: cannot make copy relocation for protected symbol 'a', defined in b.so
 lld has a similar error
   error: cannot preempt symbol: a\n>>> defined in b.so\n...

ld.bfd creates a copy relocation for (2)(y), that was probably how the option got the name HAVE_LD_PIE_COPYRELOC. To make the pointer equality rule hold, in a DSO, accesses to its own protected data have to go through GOT. This choice is against intuition and appears to violate gABI's description of STV_PROTECTED:

A symbol defined in the current component is protected if it is visible in other components but not preemptable, meaning that any reference to such a symbol from within the defining component must be resolved to the definition in that component, even if there is a definition in another component that would preempt by the default rules.

Lots of fallout was caused by HAVE_LD_PIE_COPYRELOC=1, thus I suggest we make HAVE_LD_PIE_COPYRELOC non-default (there could be a configure option to enable it), to address these issues:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55012 protected data wrongly uses GOT
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65248 (copyrel against protected data) wouldn't become an issue.

When compiling a.c, it is not known whether the actual definition in b.so will be protected or not, so it seems preferable to be conservative (use GOT). See (1)(y), with the link-time relaxation R_X86_64_GOTPCRELX, most inefficiency can be removed. We still get 2 instructions, but the cost is insignificant. Global data is rare. Users who really care about the extra instruction can mark their data as hidden.


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