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. 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