summaryrefslogtreecommitdiff
path: root/gcc/configure.ac
diff options
context:
space:
mode:
authorhjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>2014-12-04 19:40:50 +0000
committerhjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>2014-12-04 19:40:50 +0000
commit130f233477ed03a7bdffb832e7eb9f0a366e0d6b (patch)
treedfb0a4ba0d6eed5352695a1798710724f7b48fc5 /gcc/configure.ac
parent4cc5517d6e652247a5989ec58a72d7557a62f397 (diff)
downloadgcc-130f233477ed03a7bdffb832e7eb9f0a366e0d6b.tar.gz
x86-64: Optimize access to globals in PIE with copy reloc
Normally, with -fPIE/-fpie, GCC accesses globals that are extern to the module using the GOT. This is two instructions, one to get the address of the global from the GOT and the other to get the value. If it turns out that the global gets defined in the executable at link-time, it still needs to go through the GOT as it is too late then to generate a direct access. Examples: foo.cc ------ int a_glob; int main () { return a_glob; // defined in this file } With -O2 -fpie -pie, the generated code directly accesses the global via PC-relative insn: 5e0 <main>: mov 0x165a(%rip),%eax # 1c40 <a_glob> foo.cc ------ extern int a_glob; int main () { return a_glob; // defined in this file } With -O2 -fpie -pie, the generated code accesses global via GOT using two memory loads: 6f0 <main>: mov 0x1609(%rip),%rax # 1d00 <_DYNAMIC+0x230> mov (%rax),%eax This is true even if in the latter case the global was defined in the executable through a different file. Some experiments on google benchmarks shows that the extra memory loads affects performance by 1% to 5%. Solution - Copy Relocations: When the linker supports copy relocations, GCC can always assume that the global will be defined in the executable. For globals that are truly extern (come from shared objects), the linker will create copy relocations and have them defined in the executable. Result is that no global access needs to go through the GOT and hence improves performance. This optimization only applies to undefined, non-weak global data. Undefined, weak global data access still must go through the GOT. This patch checks if linker supports PIE with copy reloc, which is enabled in gold and bfd linker in bininutils 2.25, at configure time and enables this optimization if the linker support is available. gcc/ * configure.ac (HAVE_LD_PIE_COPYRELOC): Defined to 1 if Linux/x86-64 linker supports PIE with copy reloc. * config.in: Regenerated. * configure: Likewise. * config/i386/i386.c (legitimate_pic_address_disp_p): Allow pc-relative address for undefined, non-weak, non-function symbol reference in 64-bit PIE if linker supports PIE with copy reloc. * doc/sourcebuild.texi: Document pie_copyreloc target. gcc/testsuite/ * gcc.target/i386/pie-copyrelocs-1.c: New test. * gcc.target/i386/pie-copyrelocs-2.c: Likewise. * gcc.target/i386/pie-copyrelocs-3.c: Likewise. * gcc.target/i386/pie-copyrelocs-4.c: Likewise. * lib/target-supports.exp (check_effective_target_pie_copyreloc): New procedure. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@218397 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/configure.ac')
-rw-r--r--gcc/configure.ac43
1 files changed, 43 insertions, 0 deletions
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 48c8000b249..a33f3a57bb4 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4693,6 +4693,49 @@ if test x"$gcc_cv_ld_pie" = xyes; then
fi
AC_MSG_RESULT($gcc_cv_ld_pie)
+AC_MSG_CHECKING(linker PIE support with copy reloc)
+gcc_cv_ld_pie_copyreloc=no
+if test $gcc_cv_ld_pie = yes ; then
+ if test $in_tree_ld = yes ; then
+ if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 25 -o "$gcc_cv_gld_major_version" -gt 2; then
+ gcc_cv_ld_pie_copyreloc=yes
+ fi
+ elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x ; then
+ # Check if linker supports -pie option with copy reloc
+ case "$target" in
+ i?86-*-linux* | x86_64-*-linux*)
+ cat > conftest1.s <<EOF
+ .globl a_glob
+ .data
+ .type a_glob, @object
+ .size a_glob, 4
+a_glob:
+ .long 2
+EOF
+ cat > conftest2.s <<EOF
+ .text
+ .globl main
+ .type main, @function
+main:
+ movl %eax, a_glob(%rip)
+ .size main, .-main
+EOF
+ if $gcc_cv_as --64 -o conftest1.o conftest1.s > /dev/null 2>&1 \
+ && $gcc_cv_ld -shared -melf_x86_64 -o conftest1.so conftest1.o > /dev/null 2>&1 \
+ && $gcc_cv_as --64 -o conftest2.o conftest2.s > /dev/null 2>&1 \
+ && $gcc_cv_ld -pie -melf_x86_64 -o conftest conftest2.o conftest1.so > /dev/null 2>&1; then
+ gcc_cv_ld_pie_copyreloc=yes
+ fi
+ rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s
+ ;;
+ esac
+ fi
+ AC_DEFINE_UNQUOTED(HAVE_LD_PIE_COPYRELOC,
+ [`if test x"$gcc_cv_ld_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`],
+ [Define 0/1 if your linker supports -pie option with copy reloc.])
+fi
+AC_MSG_RESULT($gcc_cv_ld_pie_copyreloc)
+
AC_MSG_CHECKING(linker EH-compatible garbage collection of sections)
gcc_cv_ld_eh_gc_sections=no
if test $in_tree_ld = yes ; then