Message ID | 20150422163432.GA1053@intel.com |
---|---|
State | New |
Headers | show |
On Wed, Apr 22, 2015 at 5:34 PM, H.J. Lu <hongjiu.lu@intel.com> wrote: > Normally, with PIE, GCC accesses globals that are extern to the module > using GOT. This is two instructions, one to get the address of the global > from GOT and the other to get the value. Examples: > > --- > extern int a_glob; > int > main () > { > return a_glob; > } > --- > > With PIE, the generated code accesses global via GOT using two memory > loads: > > movq a_glob@GOTPCREL(%rip), %rax > movl (%rax), %eax > > for 64-bit or > > movl a_glob@GOT(%ecx), %eax > movl (%eax), %eax > > for 32-bit. > > Some experiments on google and SPEC CPU benchmarks show that the extra > instruction 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 GOT and hence improves performance. > We can generate > > movl a_glob(%rip), %eax > > for 64-bit and > > movl a_glob@GOTOFF(%eax), %eax > > for 32-bit. This optimization only applies to undefined non-weak > non-TLS global data. Undefined weak global or TLS data access still > must go through GOT. > > This patch reverts legitimate_pic_address_disp_p change made in revision > 218397, which only applies to x86-64. Instead, this patch updates > targetm.binds_local_p to indicate if undefined non-weak non-TLS global > data is defined locally in PIE. It also introduces a new target hook, > binds_tls_local_p to distinguish TLS variable from non-TLS variable. By > default, binds_tls_local_p is the same as binds_local_p. > > This patch checks if 32-bit and 64-bit linkers support PIE with copy > reloc at configure time. 64-bit linker is enabled in binutils 2.25 > and 32-bit linker is enabled in binutils 2.26. This optimization > is enabled only if the linker support is available. > > Tested on Linux/x86-64 with -m32 and -m64, using linkers with and without > support for copy relocation in PIE. OK for trunk? > > Thanks. Looking at this my first reaction was that surely most (if not all ? ) targets that use ELF and had copy relocs would benefit from this ? Couldn't we find a simpler way for targets to have this support ? I don't have a more constructive suggestion to make at the minute but getting this to work just from the targetm.binds_local_p (decl) interface would probably be better ? It's late in the evening and I probably won't have time to look at this in more detail till Friday afternoon given other personal commitments. regards, Ramana > > H.J. > --- > gcc/ > > PR target/65846 > * configure.ac (HAVE_LD_PIE_COPYRELOC): Renamed to ... > (HAVE_LD_64BIT_PIE_COPYRELOC): This. > (HAVE_LD_32BIT_PIE_COPYRELOC): New. Defined to 1 if Linux/ia32 > linker supports PIE with copy reloc. > * output.h (default_binds_tls_local_p): New. > (default_binds_local_p_3): Add 2 bool arguments. > * target.def (binds_tls_local_p): New target hook. > * varasm.c (decl_default_tls_model): Replace targetm.binds_local_p > with targetm.binds_tls_local_p. > (default_binds_local_p_3): Add a bool argument to indicate TLS > variable and a bool argument to indicate if an undefined non-TLS > non-weak data is local. Double check TLS variable. If an > undefined non-TLS non-weak data is local, treat it as defined > locally. > (default_binds_local_p): Pass false and false to > default_binds_local_p_3. > (default_binds_local_p_2): Likewise. > (default_binds_local_p_1): Likewise. > (default_binds_tls_local_p): New. > * config.in: Regenerated. > * configure: Likewise. > * doc/tm.texi: Likewise. > * config/i386/i386.c (legitimate_pic_address_disp_p): Don't > check HAVE_LD_PIE_COPYRELOC here. > (ix86_binds_local): New. > (ix86_binds_tls_local_p): Likewise. > (ix86_binds_local_p): Use it. > (TARGET_BINDS_TLS_LOCAL_P): New. > * doc/tm.texi.in (TARGET_BINDS_TLS_LOCAL_P): New hook. > > gcc/testsuite/ > > PR target/65846 > * gcc.target/i386/pie-copyrelocs-1.c: Updated for ia32. > * gcc.target/i386/pie-copyrelocs-2.c: Likewise. > * gcc.target/i386/pie-copyrelocs-3.c: Likewise. > * gcc.target/i386/pie-copyrelocs-4.c: Likewise. > * gcc.target/i386/pr32219-9.c: Likewise. > * gcc.target/i386/pr32219-10.c: New file. > > * lib/target-supports.exp (check_effective_target_pie_copyreloc): > Check HAVE_LD_64BIT_PIE_COPYRELOC and HAVE_LD_32BIT_PIE_COPYRELOC > instead of HAVE_LD_64BIT_PIE_COPYRELOC. > --- > gcc/config.in | 18 ++++--- > gcc/config/i386/i386.c | 44 ++++++++++----- > gcc/configure | 68 +++++++++++++++++++++--- > gcc/configure.ac | 64 +++++++++++++++++++--- > gcc/doc/tm.texi | 10 ++++ > gcc/doc/tm.texi.in | 2 + > gcc/output.h | 4 +- > gcc/target.def | 14 +++++ > gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c | 4 +- > gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c | 4 +- > gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c | 2 +- > gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c | 4 +- > gcc/testsuite/gcc.target/i386/pr32219-10.c | 16 ++++++ > gcc/testsuite/gcc.target/i386/pr32219-9.c | 2 + > gcc/testsuite/lib/target-supports.exp | 10 +++- > gcc/varasm.c | 47 ++++++++++++---- > 16 files changed, 261 insertions(+), 52 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-10.c > > diff --git a/gcc/config.in b/gcc/config.in > index f2ed301..a8ea34d 100644 > --- a/gcc/config.in > +++ b/gcc/config.in > @@ -1349,6 +1349,18 @@ > #endif > > > +/* Define 0/1 if your 32-bit linker supports -pie option with copy reloc. */ > +#ifndef USED_FOR_TARGET > +#undef HAVE_LD_32BIT_PIE_COPYRELOC > +#endif > + > + > +/* Define 0/1 if your 64-bit linker supports -pie option with copy reloc. */ > +#ifndef USED_FOR_TARGET > +#undef HAVE_LD_64BIT_PIE_COPYRELOC > +#endif > + > + > /* Define if your linker supports --as-needed/--no-as-needed or equivalent > options. */ > #ifndef USED_FOR_TARGET > @@ -1429,12 +1441,6 @@ > #endif > > > -/* Define 0/1 if your linker supports -pie option with copy reloc. */ > -#ifndef USED_FOR_TARGET > -#undef HAVE_LD_PIE_COPYRELOC > -#endif > - > - > /* Define if your linker links a mix of read-only and read-write sections into > a read-write section. */ > #ifndef USED_FOR_TARGET > diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c > index bdc3652..eb9b27f 100644 > --- a/gcc/config/i386/i386.c > +++ b/gcc/config/i386/i386.c > @@ -13231,11 +13231,7 @@ legitimate_pic_address_disp_p (rtx disp) > return true; > } > else if (!SYMBOL_REF_FAR_ADDR_P (op0) > - && (SYMBOL_REF_LOCAL_P (op0) > - || (HAVE_LD_PIE_COPYRELOC > - && flag_pie > - && !SYMBOL_REF_WEAK (op0) > - && !SYMBOL_REF_FUNCTION_P (op0))) > + && SYMBOL_REF_LOCAL_P (op0) > && ix86_cmodel != CM_LARGE_PIC) > return true; > break; > @@ -51712,17 +51708,39 @@ ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts) > } > > #if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES > -/* For i386, common symbol is local only for non-PIE binaries. For > - x86-64, common symbol is local only for non-PIE binaries or linker > - supports copy reloc in PIE binaries. */ > +/* Common and undefined, non-TLS, non-weak data symbols are local > + only for non-PIE binaries or linker supports copy reloc in PIE > + binaries. */ > + > +static bool > +ix86_binds_local (const_tree exp, bool tls) > +{ > + bool local_p; > + if (!flag_pic) > + local_p = true; > + else if (flag_pie) > + { > + if (TARGET_64BIT) > + local_p = HAVE_LD_64BIT_PIE_COPYRELOC != 0; > + else > + local_p = HAVE_LD_32BIT_PIE_COPYRELOC != 0; > + } > + else > + local_p = false; > + return default_binds_local_p_3 (exp, tls, flag_shlib != 0, true, > + true, local_p, local_p); > +} > > static bool > ix86_binds_local_p (const_tree exp) > { > - return default_binds_local_p_3 (exp, flag_shlib != 0, true, true, > - (!flag_pic > - || (TARGET_64BIT > - && HAVE_LD_PIE_COPYRELOC != 0))); > + return ix86_binds_local (exp, false); > +} > + > +static bool > +ix86_binds_tls_local_p (const_tree exp) > +{ > + return ix86_binds_local (exp, true); > } > #endif > > @@ -51861,6 +51879,8 @@ ix86_binds_local_p (const_tree exp) > #else > #undef TARGET_BINDS_LOCAL_P > #define TARGET_BINDS_LOCAL_P ix86_binds_local_p > +#undef TARGET_BINDS_TLS_LOCAL_P > +#define TARGET_BINDS_TLS_LOCAL_P ix86_binds_tls_local_p > #endif > #if TARGET_DLLIMPORT_DECL_ATTRIBUTES > #undef TARGET_BINDS_LOCAL_P > diff --git a/gcc/configure b/gcc/configure > index 9523773..9566d71 100755 > --- a/gcc/configure > +++ b/gcc/configure > @@ -27095,13 +27095,13 @@ fi > { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_pie" >&5 > $as_echo "$gcc_cv_ld_pie" >&6; } > > -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker PIE support with copy reloc" >&5 > -$as_echo_n "checking linker PIE support with copy reloc... " >&6; } > -gcc_cv_ld_pie_copyreloc=no > +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking 64-bit linker PIE support with copy reloc" >&5 > +$as_echo_n "checking 64-bit linker PIE support with copy reloc... " >&6; } > +gcc_cv_ld_64bit_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 > + gcc_cv_ld_64bit_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 > @@ -27132,7 +27132,7 @@ EOF > && $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 > + gcc_cv_ld_64bit_pie_copyreloc=yes > fi > rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s > ;; > @@ -27141,11 +27141,63 @@ EOF > fi > > cat >>confdefs.h <<_ACEOF > -#define HAVE_LD_PIE_COPYRELOC `if test x"$gcc_cv_ld_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` > +#define HAVE_LD_64BIT_PIE_COPYRELOC `if test x"$gcc_cv_ld_64bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` > _ACEOF > > -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_pie_copyreloc" >&5 > -$as_echo "$gcc_cv_ld_pie_copyreloc" >&6; } > +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_64bit_pie_copyreloc" >&5 > +$as_echo "$gcc_cv_ld_64bit_pie_copyreloc" >&6; } > + > +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking 32-bit linker PIE support with copy reloc" >&5 > +$as_echo_n "checking 32-bit linker PIE support with copy reloc... " >&6; } > +gcc_cv_ld_32bit_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 26 -o "$gcc_cv_gld_major_version" -gt 2; then > + gcc_cv_ld_32bit_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 a_glob@GOTOFF(%ebx), %eax > + .size main, .-main > + .globl ptr > + .section .data.rel,"aw",@progbits > + .type ptr, @object > +ptr: > + .long a_glob > +EOF > + if $gcc_cv_as --32 -o conftest1.o conftest1.s > /dev/null 2>&1 \ > + && $gcc_cv_ld -shared -melf_i386 -o conftest1.so conftest1.o > /dev/null 2>&1 \ > + && $gcc_cv_as --32 -o conftest2.o conftest2.s > /dev/null 2>&1 \ > + && $gcc_cv_ld -pie -melf_i386 -o conftest conftest2.o conftest1.so > /dev/null 2>&1; then > + gcc_cv_ld_32bit_pie_copyreloc=yes > + fi > + rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s > + ;; > + esac > + fi > +fi > + > +cat >>confdefs.h <<_ACEOF > +#define HAVE_LD_32BIT_PIE_COPYRELOC `if test x"$gcc_cv_ld_32bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` > +_ACEOF > + > +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_32bit_pie_copyreloc" >&5 > +$as_echo "$gcc_cv_ld_32bit_pie_copyreloc" >&6; } > > { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker EH-compatible garbage collection of sections" >&5 > $as_echo_n "checking linker EH-compatible garbage collection of sections... " >&6; } > diff --git a/gcc/configure.ac b/gcc/configure.ac > index 68b0ee8..53adc4b 100644 > --- a/gcc/configure.ac > +++ b/gcc/configure.ac > @@ -4705,12 +4705,12 @@ 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 > +AC_MSG_CHECKING(64-bit linker PIE support with copy reloc) > +gcc_cv_ld_64bit_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 > + gcc_cv_ld_64bit_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 > @@ -4741,17 +4741,65 @@ EOF > && $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 > + gcc_cv_ld_64bit_pie_copyreloc=yes > fi > rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s > ;; > esac > fi > 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.]) > -AC_MSG_RESULT($gcc_cv_ld_pie_copyreloc) > +AC_DEFINE_UNQUOTED(HAVE_LD_64BIT_PIE_COPYRELOC, > + [`if test x"$gcc_cv_ld_64bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`], > + [Define 0/1 if your 64-bit linker supports -pie option with copy reloc.]) > +AC_MSG_RESULT($gcc_cv_ld_64bit_pie_copyreloc) > + > +AC_MSG_CHECKING(32-bit linker PIE support with copy reloc) > +gcc_cv_ld_32bit_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 26 -o "$gcc_cv_gld_major_version" -gt 2; then > + gcc_cv_ld_32bit_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 a_glob@GOTOFF(%ebx), %eax > + .size main, .-main > + .globl ptr > + .section .data.rel,"aw",@progbits > + .type ptr, @object > +ptr: > + .long a_glob > +EOF > + if $gcc_cv_as --32 -o conftest1.o conftest1.s > /dev/null 2>&1 \ > + && $gcc_cv_ld -shared -melf_i386 -o conftest1.so conftest1.o > /dev/null 2>&1 \ > + && $gcc_cv_as --32 -o conftest2.o conftest2.s > /dev/null 2>&1 \ > + && $gcc_cv_ld -pie -melf_i386 -o conftest conftest2.o conftest1.so > /dev/null 2>&1; then > + gcc_cv_ld_32bit_pie_copyreloc=yes > + fi > + rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s > + ;; > + esac > + fi > +fi > +AC_DEFINE_UNQUOTED(HAVE_LD_32BIT_PIE_COPYRELOC, > + [`if test x"$gcc_cv_ld_32bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`], > + [Define 0/1 if your 32-bit linker supports -pie option with copy reloc.]) > +AC_MSG_RESULT($gcc_cv_ld_32bit_pie_copyreloc) > > AC_MSG_CHECKING(linker EH-compatible garbage collection of sections) > gcc_cv_ld_eh_gc_sections=no > diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi > index 6c5bfab..5a73c8a 100644 > --- a/gcc/doc/tm.texi > +++ b/gcc/doc/tm.texi > @@ -7219,6 +7219,16 @@ for ELF, which has a looser model of global name binding than other > currently supported object file formats. > @end deftypefn > > +@deftypefn {Target Hook} bool TARGET_BINDS_TLS_LOCAL_P (const_tree @var{exp}) > +Returns true if TLS variable @var{exp} names an object for which name > +resolution rules must resolve to the current ``module'' (dynamic shared > +library or executable image). > + > +The default version of this hook implements the name resolution rules > +for ELF, which has a looser model of global name binding than other > +currently supported object file formats. > +@end deftypefn > + > @deftypevr {Target Hook} bool TARGET_HAVE_TLS > Contains the value true if the target supports thread-local storage. > The default value is false. > diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in > index 8d6dfbc..c0316be 100644 > --- a/gcc/doc/tm.texi.in > +++ b/gcc/doc/tm.texi.in > @@ -5034,6 +5034,8 @@ it is unlikely to be called. > > @hook TARGET_BINDS_LOCAL_P > > +@hook TARGET_BINDS_TLS_LOCAL_P > + > @hook TARGET_HAVE_TLS > > > diff --git a/gcc/output.h b/gcc/output.h > index 81d2ad2..52e094c 100644 > --- a/gcc/output.h > +++ b/gcc/output.h > @@ -585,9 +585,11 @@ extern const char *default_strip_name_encoding (const char *); > extern void default_asm_output_anchor (rtx); > extern bool default_use_anchors_for_symbol_p (const_rtx); > extern bool default_binds_local_p (const_tree); > +extern bool default_binds_tls_local_p (const_tree); > extern bool default_binds_local_p_1 (const_tree, int); > extern bool default_binds_local_p_2 (const_tree); > -extern bool default_binds_local_p_3 (const_tree, bool, bool, bool, bool); > +extern bool default_binds_local_p_3 (const_tree, bool, bool, bool, bool, > + bool, bool); > extern void default_globalize_label (FILE *, const char *); > extern void default_globalize_decl_name (FILE *, tree); > extern void default_emit_unwind_label (FILE *, tree, int, int); > diff --git a/gcc/target.def b/gcc/target.def > index a00181a..4a3e0d9 100644 > --- a/gcc/target.def > +++ b/gcc/target.def > @@ -2891,6 +2891,20 @@ currently supported object file formats.", > bool, (const_tree exp), > default_binds_local_p) > > +/* True if TLS variable EXP names an object for which name resolution must > + resolve to the current executable or shared library. */ > +DEFHOOK > +(binds_tls_local_p, > + "Returns true if TLS variable @var{exp} names an object for which name\n\ > +resolution rules must resolve to the current ``module'' (dynamic shared\n\ > +library or executable image).\n\ > +\n\ > +The default version of this hook implements the name resolution rules\n\ > +for ELF, which has a looser model of global name binding than other\n\ > +currently supported object file formats.", > + bool, (const_tree exp), > + default_binds_tls_local_p) > + > /* Check if profiling code is before or after prologue. */ > DEFHOOK > (profile_before_prologue, > diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c > index 7af851b..69e3f6e 100644 > --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c > +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c > @@ -1,4 +1,4 @@ > -/* Check that GOTPCREL isn't used to access glob_a. */ > +/* Check that GOTPCREL/GOT isn't used to access glob_a. */ > /* { dg-do compile { target *-*-linux* } } */ > /* { dg-require-effective-target pie_copyreloc } */ > /* { dg-options "-O2 -fpie" } */ > @@ -12,3 +12,5 @@ int foo () > > /* glob_a should never be accessed with a GOTPCREL. */ > /* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */ > +/* glob_a should never be accessed with a GOT. */ > +/* { dg-final { scan-assembler-not "glob_a@GOT\\(" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c > index 19cb97e..eb0724b 100644 > --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c > +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c > @@ -1,4 +1,4 @@ > -/* Check that GOTPCREL isn't used to access glob_a. */ > +/* Check that GOTPCREL/GOT isn't used to access glob_a. */ > /* { dg-do compile { target *-*-linux* } } */ > /* { dg-require-effective-target pie_copyreloc } */ > /* { dg-options "-O2 -fpie" } */ > @@ -12,3 +12,5 @@ int foo () > > /* glob_a should never be accessed with a GOTPCREL. */ > /* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */ > +/* glob_a should never be accessed with a GOT. */ > +/* { dg-final { scan-assembler-not "glob_a@GOT\\(" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c > index c2fa896..1123bd8 100644 > --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c > +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c > @@ -11,4 +11,4 @@ int foo () > } > > /* glob_a should be accessed with a PLT. */ > -/* { dg-final { scan-assembler "glob_a@PLT" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "glob_a@PLT" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c > index 413cdf3..4724ede 100644 > --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c > +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c > @@ -1,4 +1,4 @@ > -/* Check that GOTPCREL is used to access glob_a. */ > +/* Check that GOTPCREL/GOT is used to access glob_a. */ > /* { dg-do compile { target *-*-linux* } } */ > /* { dg-require-effective-target pie_copyreloc } */ > /* { dg-options "-O2 -fpie" } */ > @@ -15,3 +15,5 @@ int foo () > > /* weak glob_a should be accessed with a GOTPCREL. */ > /* { dg-final { scan-assembler "glob_a@GOTPCREL" { target { ! ia32 } } } } */ > +/* weak glob_a should be accessed with a GOT. */ > +/* { dg-final { scan-assembler "glob_a@GOT\\(" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr32219-10.c b/gcc/testsuite/gcc.target/i386/pr32219-10.c > new file mode 100644 > index 0000000..3cd95f0 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr32219-10.c > @@ -0,0 +1,16 @@ > +/* Check that tpoff/ntpoff isn't used to access glob_a. */ > +/* { dg-do compile { target *-*-linux* } } */ > +/* { dg-require-effective-target pie } */ > +/* { dg-options "-O2 -fpie" } */ > + > +extern __thread int glob_a; > + > +int foo () > +{ > + return glob_a; > +} > + > +/* glob_a should never be accessed with a tpoff. */ > +/* { dg-final { scan-assembler-not "glob_a@tpoff" { target { ! ia32 } } } } */ > +/* glob_a should never be accessed with a ntpoff. */ > +/* { dg-final { scan-assembler-not "glob_a@ntpoff" { target ia32 } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/pr32219-9.c b/gcc/testsuite/gcc.target/i386/pr32219-9.c > index 8c21826..77330be 100644 > --- a/gcc/testsuite/gcc.target/i386/pr32219-9.c > +++ b/gcc/testsuite/gcc.target/i386/pr32219-9.c > @@ -13,3 +13,5 @@ foo () > > /* { dg-final { scan-assembler "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */ > /* { dg-final { scan-assembler-not "xxx@GOTPCREL" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler "xxx@GOTOFF" { target ia32 } } } */ > +/* { dg-final { scan-assembler-not "xxx@GOT\\(" { target ia32 } } } */ > diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp > index f632d00..153024d 100644 > --- a/gcc/testsuite/lib/target-supports.exp > +++ b/gcc/testsuite/lib/target-supports.exp > @@ -6220,8 +6220,14 @@ proc check_effective_target_pie_copyreloc { } { > > set f [open $src "w"] > puts $f "#include \"../../auto-host.h\"" > - puts $f "#if HAVE_LD_PIE_COPYRELOC == 0" > - puts $f "# error Linker does not support PIE with copy reloc." > + puts $f "#ifdef __x86_64__" > + puts $f "# if HAVE_LD_64BIT_PIE_COPYRELOC == 0" > + puts $f "# error 64-bit linker does not support PIE with copy reloc." > + puts $f "# endif" > + puts $f "#else" > + puts $f "# if HAVE_LD_32BIT_PIE_COPYRELOC == 0" > + puts $f "# error 32-bit linker does not support PIE with copy reloc." > + puts $f "# endif" > puts $f "#endif" > close $f > > diff --git a/gcc/varasm.c b/gcc/varasm.c > index 1597de1..ef78995 100644 > --- a/gcc/varasm.c > +++ b/gcc/varasm.c > @@ -6115,7 +6115,7 @@ decl_default_tls_model (const_tree decl) > enum tls_model kind; > bool is_local; > > - is_local = targetm.binds_local_p (decl); > + is_local = targetm.binds_tls_local_p (decl); > if (!flag_shlib) > { > if (is_local) > @@ -6809,11 +6809,15 @@ resolution_local_p (enum ld_plugin_symbol_resolution resolution) > > /* COMMON_LOCAL_P is true means that the linker can guarantee that an > uninitialized common symbol in the executable will still be defined > - (through COPY relocation) in the executable. */ > + (through COPY relocation) in the executable. DATA_LOCAL_P is true > + means that the linker can guarantee that undefined, non-TLS, non-weak > + data in the executable will still be defined (through COPY relocation) > + in the executable. */ > > bool > -default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, > - bool extern_protected_data, bool common_local_p) > +default_binds_local_p_3 (const_tree exp, bool tls, bool shlib, > + bool weak_dominate, bool extern_protected_data, > + bool common_local_p, bool data_local_p) > { > /* A non-decl is an entry in the constant pool. */ > if (!DECL_P (exp)) > @@ -6844,10 +6848,21 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, > || (!in_lto_p > && DECL_INITIAL (exp) == error_mark_node))); > > + /* If TLS is false, double check if EXP is a TLS variable. */ > + if (!tls) > + tls = TREE_CODE (exp) == VAR_DECL && DECL_THREAD_LOCAL_P (exp); > + > /* A non-external variable is defined locally only if it isn't > - uninitialized COMMON variable or common_local_p is true. */ > - bool defined_locally = (!DECL_EXTERNAL (exp) > - && (!uninited_common || common_local_p)); > + uninitialized COMMON variable or common_local_p is true. A > + undefined data variable is defined locally only if it isn't > + weak nor a TLS variable and linker can guarantee it will be > + defined locally. */ > + bool defined_locally = ((!tls > + && TREE_CODE (exp) != FUNCTION_DECL > + && !DECL_WEAK (exp) > + && data_local_p) > + || (!DECL_EXTERNAL (exp) > + && (!uninited_common || common_local_p))); > if (symtab_node *node = symtab_node::get (exp)) > { > if (node->in_other_partition) > @@ -6903,7 +6918,16 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, > bool > default_binds_local_p (const_tree exp) > { > - return default_binds_local_p_3 (exp, flag_shlib != 0, true, false, false); > + return default_binds_local_p_3 (exp, false, flag_shlib != 0, true, > + false, false, false); > +} > + > +/* Similar to default_binds_local_p, but for TLS variable. */ > + > +bool > +default_binds_tls_local_p (const_tree exp) > +{ > + return targetm.binds_local_p (exp); > } > > /* Similar to default_binds_local_p, but common symbol may be local. */ > @@ -6911,14 +6935,15 @@ default_binds_local_p (const_tree exp) > bool > default_binds_local_p_2 (const_tree exp) > { > - return default_binds_local_p_3 (exp, flag_shlib != 0, true, false, > - !flag_pic); > + return default_binds_local_p_3 (exp, false, flag_shlib != 0, true, > + false, !flag_pic, false); > } > > bool > default_binds_local_p_1 (const_tree exp, int shlib) > { > - return default_binds_local_p_3 (exp, shlib != 0, false, false, false); > + return default_binds_local_p_3 (exp, false, shlib != 0, false, false, > + false, false); > } > > /* Return true when references to DECL must bind to current definition in > -- > 1.9.3 >
On Wed, Apr 22, 2015 at 3:15 PM, Ramana Radhakrishnan <ramana.gcc@googlemail.com> wrote: > On Wed, Apr 22, 2015 at 5:34 PM, H.J. Lu <hongjiu.lu@intel.com> wrote: >> Normally, with PIE, GCC accesses globals that are extern to the module >> using GOT. This is two instructions, one to get the address of the global >> from GOT and the other to get the value. Examples: >> >> --- >> extern int a_glob; >> int >> main () >> { >> return a_glob; >> } >> --- >> >> With PIE, the generated code accesses global via GOT using two memory >> loads: >> >> movq a_glob@GOTPCREL(%rip), %rax >> movl (%rax), %eax >> >> for 64-bit or >> >> movl a_glob@GOT(%ecx), %eax >> movl (%eax), %eax >> >> for 32-bit. >> >> Some experiments on google and SPEC CPU benchmarks show that the extra >> instruction 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 GOT and hence improves performance. >> We can generate >> >> movl a_glob(%rip), %eax >> >> for 64-bit and >> >> movl a_glob@GOTOFF(%eax), %eax >> >> for 32-bit. This optimization only applies to undefined non-weak >> non-TLS global data. Undefined weak global or TLS data access still >> must go through GOT. >> >> This patch reverts legitimate_pic_address_disp_p change made in revision >> 218397, which only applies to x86-64. Instead, this patch updates >> targetm.binds_local_p to indicate if undefined non-weak non-TLS global >> data is defined locally in PIE. It also introduces a new target hook, >> binds_tls_local_p to distinguish TLS variable from non-TLS variable. By >> default, binds_tls_local_p is the same as binds_local_p. >> >> This patch checks if 32-bit and 64-bit linkers support PIE with copy >> reloc at configure time. 64-bit linker is enabled in binutils 2.25 >> and 32-bit linker is enabled in binutils 2.26. This optimization >> is enabled only if the linker support is available. >> >> Tested on Linux/x86-64 with -m32 and -m64, using linkers with and without >> support for copy relocation in PIE. OK for trunk? >> >> Thanks. > > > Looking at this my first reaction was that surely most (if not all ? ) > targets that use ELF and had copy relocs would benefit from this ? > Couldn't we find a simpler way for targets to have this support ? I > don't have a more constructive suggestion to make at the minute but > getting this to work just from the targetm.binds_local_p (decl) > interface would probably be better ? default_binds_local_p_3 is a global function which is used to implement targetm.binds_local_p in x86 backend. Any backend can use it to optimize for copy relocation.
diff --git a/gcc/config.in b/gcc/config.in index f2ed301..a8ea34d 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1349,6 +1349,18 @@ #endif +/* Define 0/1 if your 32-bit linker supports -pie option with copy reloc. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_32BIT_PIE_COPYRELOC +#endif + + +/* Define 0/1 if your 64-bit linker supports -pie option with copy reloc. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_64BIT_PIE_COPYRELOC +#endif + + /* Define if your linker supports --as-needed/--no-as-needed or equivalent options. */ #ifndef USED_FOR_TARGET @@ -1429,12 +1441,6 @@ #endif -/* Define 0/1 if your linker supports -pie option with copy reloc. */ -#ifndef USED_FOR_TARGET -#undef HAVE_LD_PIE_COPYRELOC -#endif - - /* Define if your linker links a mix of read-only and read-write sections into a read-write section. */ #ifndef USED_FOR_TARGET diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index bdc3652..eb9b27f 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -13231,11 +13231,7 @@ legitimate_pic_address_disp_p (rtx disp) return true; } else if (!SYMBOL_REF_FAR_ADDR_P (op0) - && (SYMBOL_REF_LOCAL_P (op0) - || (HAVE_LD_PIE_COPYRELOC - && flag_pie - && !SYMBOL_REF_WEAK (op0) - && !SYMBOL_REF_FUNCTION_P (op0))) + && SYMBOL_REF_LOCAL_P (op0) && ix86_cmodel != CM_LARGE_PIC) return true; break; @@ -51712,17 +51708,39 @@ ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts) } #if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES -/* For i386, common symbol is local only for non-PIE binaries. For - x86-64, common symbol is local only for non-PIE binaries or linker - supports copy reloc in PIE binaries. */ +/* Common and undefined, non-TLS, non-weak data symbols are local + only for non-PIE binaries or linker supports copy reloc in PIE + binaries. */ + +static bool +ix86_binds_local (const_tree exp, bool tls) +{ + bool local_p; + if (!flag_pic) + local_p = true; + else if (flag_pie) + { + if (TARGET_64BIT) + local_p = HAVE_LD_64BIT_PIE_COPYRELOC != 0; + else + local_p = HAVE_LD_32BIT_PIE_COPYRELOC != 0; + } + else + local_p = false; + return default_binds_local_p_3 (exp, tls, flag_shlib != 0, true, + true, local_p, local_p); +} static bool ix86_binds_local_p (const_tree exp) { - return default_binds_local_p_3 (exp, flag_shlib != 0, true, true, - (!flag_pic - || (TARGET_64BIT - && HAVE_LD_PIE_COPYRELOC != 0))); + return ix86_binds_local (exp, false); +} + +static bool +ix86_binds_tls_local_p (const_tree exp) +{ + return ix86_binds_local (exp, true); } #endif @@ -51861,6 +51879,8 @@ ix86_binds_local_p (const_tree exp) #else #undef TARGET_BINDS_LOCAL_P #define TARGET_BINDS_LOCAL_P ix86_binds_local_p +#undef TARGET_BINDS_TLS_LOCAL_P +#define TARGET_BINDS_TLS_LOCAL_P ix86_binds_tls_local_p #endif #if TARGET_DLLIMPORT_DECL_ATTRIBUTES #undef TARGET_BINDS_LOCAL_P diff --git a/gcc/configure b/gcc/configure index 9523773..9566d71 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27095,13 +27095,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_pie" >&5 $as_echo "$gcc_cv_ld_pie" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker PIE support with copy reloc" >&5 -$as_echo_n "checking linker PIE support with copy reloc... " >&6; } -gcc_cv_ld_pie_copyreloc=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking 64-bit linker PIE support with copy reloc" >&5 +$as_echo_n "checking 64-bit linker PIE support with copy reloc... " >&6; } +gcc_cv_ld_64bit_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 + gcc_cv_ld_64bit_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 @@ -27132,7 +27132,7 @@ EOF && $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 + gcc_cv_ld_64bit_pie_copyreloc=yes fi rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s ;; @@ -27141,11 +27141,63 @@ EOF fi cat >>confdefs.h <<_ACEOF -#define HAVE_LD_PIE_COPYRELOC `if test x"$gcc_cv_ld_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` +#define HAVE_LD_64BIT_PIE_COPYRELOC `if test x"$gcc_cv_ld_64bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` _ACEOF -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_pie_copyreloc" >&5 -$as_echo "$gcc_cv_ld_pie_copyreloc" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_64bit_pie_copyreloc" >&5 +$as_echo "$gcc_cv_ld_64bit_pie_copyreloc" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking 32-bit linker PIE support with copy reloc" >&5 +$as_echo_n "checking 32-bit linker PIE support with copy reloc... " >&6; } +gcc_cv_ld_32bit_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 26 -o "$gcc_cv_gld_major_version" -gt 2; then + gcc_cv_ld_32bit_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 a_glob@GOTOFF(%ebx), %eax + .size main, .-main + .globl ptr + .section .data.rel,"aw",@progbits + .type ptr, @object +ptr: + .long a_glob +EOF + if $gcc_cv_as --32 -o conftest1.o conftest1.s > /dev/null 2>&1 \ + && $gcc_cv_ld -shared -melf_i386 -o conftest1.so conftest1.o > /dev/null 2>&1 \ + && $gcc_cv_as --32 -o conftest2.o conftest2.s > /dev/null 2>&1 \ + && $gcc_cv_ld -pie -melf_i386 -o conftest conftest2.o conftest1.so > /dev/null 2>&1; then + gcc_cv_ld_32bit_pie_copyreloc=yes + fi + rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s + ;; + esac + fi +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_LD_32BIT_PIE_COPYRELOC `if test x"$gcc_cv_ld_32bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_32bit_pie_copyreloc" >&5 +$as_echo "$gcc_cv_ld_32bit_pie_copyreloc" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker EH-compatible garbage collection of sections" >&5 $as_echo_n "checking linker EH-compatible garbage collection of sections... " >&6; } diff --git a/gcc/configure.ac b/gcc/configure.ac index 68b0ee8..53adc4b 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4705,12 +4705,12 @@ 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 +AC_MSG_CHECKING(64-bit linker PIE support with copy reloc) +gcc_cv_ld_64bit_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 + gcc_cv_ld_64bit_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 @@ -4741,17 +4741,65 @@ EOF && $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 + gcc_cv_ld_64bit_pie_copyreloc=yes fi rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s ;; esac fi 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.]) -AC_MSG_RESULT($gcc_cv_ld_pie_copyreloc) +AC_DEFINE_UNQUOTED(HAVE_LD_64BIT_PIE_COPYRELOC, + [`if test x"$gcc_cv_ld_64bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`], + [Define 0/1 if your 64-bit linker supports -pie option with copy reloc.]) +AC_MSG_RESULT($gcc_cv_ld_64bit_pie_copyreloc) + +AC_MSG_CHECKING(32-bit linker PIE support with copy reloc) +gcc_cv_ld_32bit_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 26 -o "$gcc_cv_gld_major_version" -gt 2; then + gcc_cv_ld_32bit_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 a_glob@GOTOFF(%ebx), %eax + .size main, .-main + .globl ptr + .section .data.rel,"aw",@progbits + .type ptr, @object +ptr: + .long a_glob +EOF + if $gcc_cv_as --32 -o conftest1.o conftest1.s > /dev/null 2>&1 \ + && $gcc_cv_ld -shared -melf_i386 -o conftest1.so conftest1.o > /dev/null 2>&1 \ + && $gcc_cv_as --32 -o conftest2.o conftest2.s > /dev/null 2>&1 \ + && $gcc_cv_ld -pie -melf_i386 -o conftest conftest2.o conftest1.so > /dev/null 2>&1; then + gcc_cv_ld_32bit_pie_copyreloc=yes + fi + rm -f conftest conftest1.so conftest1.o conftest2.o conftest1.s conftest2.s + ;; + esac + fi +fi +AC_DEFINE_UNQUOTED(HAVE_LD_32BIT_PIE_COPYRELOC, + [`if test x"$gcc_cv_ld_32bit_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`], + [Define 0/1 if your 32-bit linker supports -pie option with copy reloc.]) +AC_MSG_RESULT($gcc_cv_ld_32bit_pie_copyreloc) AC_MSG_CHECKING(linker EH-compatible garbage collection of sections) gcc_cv_ld_eh_gc_sections=no diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 6c5bfab..5a73c8a 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -7219,6 +7219,16 @@ for ELF, which has a looser model of global name binding than other currently supported object file formats. @end deftypefn +@deftypefn {Target Hook} bool TARGET_BINDS_TLS_LOCAL_P (const_tree @var{exp}) +Returns true if TLS variable @var{exp} names an object for which name +resolution rules must resolve to the current ``module'' (dynamic shared +library or executable image). + +The default version of this hook implements the name resolution rules +for ELF, which has a looser model of global name binding than other +currently supported object file formats. +@end deftypefn + @deftypevr {Target Hook} bool TARGET_HAVE_TLS Contains the value true if the target supports thread-local storage. The default value is false. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 8d6dfbc..c0316be 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -5034,6 +5034,8 @@ it is unlikely to be called. @hook TARGET_BINDS_LOCAL_P +@hook TARGET_BINDS_TLS_LOCAL_P + @hook TARGET_HAVE_TLS diff --git a/gcc/output.h b/gcc/output.h index 81d2ad2..52e094c 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -585,9 +585,11 @@ extern const char *default_strip_name_encoding (const char *); extern void default_asm_output_anchor (rtx); extern bool default_use_anchors_for_symbol_p (const_rtx); extern bool default_binds_local_p (const_tree); +extern bool default_binds_tls_local_p (const_tree); extern bool default_binds_local_p_1 (const_tree, int); extern bool default_binds_local_p_2 (const_tree); -extern bool default_binds_local_p_3 (const_tree, bool, bool, bool, bool); +extern bool default_binds_local_p_3 (const_tree, bool, bool, bool, bool, + bool, bool); extern void default_globalize_label (FILE *, const char *); extern void default_globalize_decl_name (FILE *, tree); extern void default_emit_unwind_label (FILE *, tree, int, int); diff --git a/gcc/target.def b/gcc/target.def index a00181a..4a3e0d9 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2891,6 +2891,20 @@ currently supported object file formats.", bool, (const_tree exp), default_binds_local_p) +/* True if TLS variable EXP names an object for which name resolution must + resolve to the current executable or shared library. */ +DEFHOOK +(binds_tls_local_p, + "Returns true if TLS variable @var{exp} names an object for which name\n\ +resolution rules must resolve to the current ``module'' (dynamic shared\n\ +library or executable image).\n\ +\n\ +The default version of this hook implements the name resolution rules\n\ +for ELF, which has a looser model of global name binding than other\n\ +currently supported object file formats.", + bool, (const_tree exp), + default_binds_tls_local_p) + /* Check if profiling code is before or after prologue. */ DEFHOOK (profile_before_prologue, diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c index 7af851b..69e3f6e 100644 --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-1.c @@ -1,4 +1,4 @@ -/* Check that GOTPCREL isn't used to access glob_a. */ +/* Check that GOTPCREL/GOT isn't used to access glob_a. */ /* { dg-do compile { target *-*-linux* } } */ /* { dg-require-effective-target pie_copyreloc } */ /* { dg-options "-O2 -fpie" } */ @@ -12,3 +12,5 @@ int foo () /* glob_a should never be accessed with a GOTPCREL. */ /* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */ +/* glob_a should never be accessed with a GOT. */ +/* { dg-final { scan-assembler-not "glob_a@GOT\\(" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c index 19cb97e..eb0724b 100644 --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-2.c @@ -1,4 +1,4 @@ -/* Check that GOTPCREL isn't used to access glob_a. */ +/* Check that GOTPCREL/GOT isn't used to access glob_a. */ /* { dg-do compile { target *-*-linux* } } */ /* { dg-require-effective-target pie_copyreloc } */ /* { dg-options "-O2 -fpie" } */ @@ -12,3 +12,5 @@ int foo () /* glob_a should never be accessed with a GOTPCREL. */ /* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */ +/* glob_a should never be accessed with a GOT. */ +/* { dg-final { scan-assembler-not "glob_a@GOT\\(" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c index c2fa896..1123bd8 100644 --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-3.c @@ -11,4 +11,4 @@ int foo () } /* glob_a should be accessed with a PLT. */ -/* { dg-final { scan-assembler "glob_a@PLT" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "glob_a@PLT" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c index 413cdf3..4724ede 100644 --- a/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c +++ b/gcc/testsuite/gcc.target/i386/pie-copyrelocs-4.c @@ -1,4 +1,4 @@ -/* Check that GOTPCREL is used to access glob_a. */ +/* Check that GOTPCREL/GOT is used to access glob_a. */ /* { dg-do compile { target *-*-linux* } } */ /* { dg-require-effective-target pie_copyreloc } */ /* { dg-options "-O2 -fpie" } */ @@ -15,3 +15,5 @@ int foo () /* weak glob_a should be accessed with a GOTPCREL. */ /* { dg-final { scan-assembler "glob_a@GOTPCREL" { target { ! ia32 } } } } */ +/* weak glob_a should be accessed with a GOT. */ +/* { dg-final { scan-assembler "glob_a@GOT\\(" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr32219-10.c b/gcc/testsuite/gcc.target/i386/pr32219-10.c new file mode 100644 index 0000000..3cd95f0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr32219-10.c @@ -0,0 +1,16 @@ +/* Check that tpoff/ntpoff isn't used to access glob_a. */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-require-effective-target pie } */ +/* { dg-options "-O2 -fpie" } */ + +extern __thread int glob_a; + +int foo () +{ + return glob_a; +} + +/* glob_a should never be accessed with a tpoff. */ +/* { dg-final { scan-assembler-not "glob_a@tpoff" { target { ! ia32 } } } } */ +/* glob_a should never be accessed with a ntpoff. */ +/* { dg-final { scan-assembler-not "glob_a@ntpoff" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr32219-9.c b/gcc/testsuite/gcc.target/i386/pr32219-9.c index 8c21826..77330be 100644 --- a/gcc/testsuite/gcc.target/i386/pr32219-9.c +++ b/gcc/testsuite/gcc.target/i386/pr32219-9.c @@ -13,3 +13,5 @@ foo () /* { dg-final { scan-assembler "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */ /* { dg-final { scan-assembler-not "xxx@GOTPCREL" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "xxx@GOTOFF" { target ia32 } } } */ +/* { dg-final { scan-assembler-not "xxx@GOT\\(" { target ia32 } } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index f632d00..153024d 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6220,8 +6220,14 @@ proc check_effective_target_pie_copyreloc { } { set f [open $src "w"] puts $f "#include \"../../auto-host.h\"" - puts $f "#if HAVE_LD_PIE_COPYRELOC == 0" - puts $f "# error Linker does not support PIE with copy reloc." + puts $f "#ifdef __x86_64__" + puts $f "# if HAVE_LD_64BIT_PIE_COPYRELOC == 0" + puts $f "# error 64-bit linker does not support PIE with copy reloc." + puts $f "# endif" + puts $f "#else" + puts $f "# if HAVE_LD_32BIT_PIE_COPYRELOC == 0" + puts $f "# error 32-bit linker does not support PIE with copy reloc." + puts $f "# endif" puts $f "#endif" close $f diff --git a/gcc/varasm.c b/gcc/varasm.c index 1597de1..ef78995 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -6115,7 +6115,7 @@ decl_default_tls_model (const_tree decl) enum tls_model kind; bool is_local; - is_local = targetm.binds_local_p (decl); + is_local = targetm.binds_tls_local_p (decl); if (!flag_shlib) { if (is_local) @@ -6809,11 +6809,15 @@ resolution_local_p (enum ld_plugin_symbol_resolution resolution) /* COMMON_LOCAL_P is true means that the linker can guarantee that an uninitialized common symbol in the executable will still be defined - (through COPY relocation) in the executable. */ + (through COPY relocation) in the executable. DATA_LOCAL_P is true + means that the linker can guarantee that undefined, non-TLS, non-weak + data in the executable will still be defined (through COPY relocation) + in the executable. */ bool -default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, - bool extern_protected_data, bool common_local_p) +default_binds_local_p_3 (const_tree exp, bool tls, bool shlib, + bool weak_dominate, bool extern_protected_data, + bool common_local_p, bool data_local_p) { /* A non-decl is an entry in the constant pool. */ if (!DECL_P (exp)) @@ -6844,10 +6848,21 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, || (!in_lto_p && DECL_INITIAL (exp) == error_mark_node))); + /* If TLS is false, double check if EXP is a TLS variable. */ + if (!tls) + tls = TREE_CODE (exp) == VAR_DECL && DECL_THREAD_LOCAL_P (exp); + /* A non-external variable is defined locally only if it isn't - uninitialized COMMON variable or common_local_p is true. */ - bool defined_locally = (!DECL_EXTERNAL (exp) - && (!uninited_common || common_local_p)); + uninitialized COMMON variable or common_local_p is true. A + undefined data variable is defined locally only if it isn't + weak nor a TLS variable and linker can guarantee it will be + defined locally. */ + bool defined_locally = ((!tls + && TREE_CODE (exp) != FUNCTION_DECL + && !DECL_WEAK (exp) + && data_local_p) + || (!DECL_EXTERNAL (exp) + && (!uninited_common || common_local_p))); if (symtab_node *node = symtab_node::get (exp)) { if (node->in_other_partition) @@ -6903,7 +6918,16 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, bool default_binds_local_p (const_tree exp) { - return default_binds_local_p_3 (exp, flag_shlib != 0, true, false, false); + return default_binds_local_p_3 (exp, false, flag_shlib != 0, true, + false, false, false); +} + +/* Similar to default_binds_local_p, but for TLS variable. */ + +bool +default_binds_tls_local_p (const_tree exp) +{ + return targetm.binds_local_p (exp); } /* Similar to default_binds_local_p, but common symbol may be local. */ @@ -6911,14 +6935,15 @@ default_binds_local_p (const_tree exp) bool default_binds_local_p_2 (const_tree exp) { - return default_binds_local_p_3 (exp, flag_shlib != 0, true, false, - !flag_pic); + return default_binds_local_p_3 (exp, false, flag_shlib != 0, true, + false, !flag_pic, false); } bool default_binds_local_p_1 (const_tree exp, int shlib) { - return default_binds_local_p_3 (exp, shlib != 0, false, false, false); + return default_binds_local_p_3 (exp, false, shlib != 0, false, false, + false, false); } /* Return true when references to DECL must bind to current definition in