On Sat, Apr 25, 2015 at 08:46:58AM -0700, H.J. Lu 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 which assumes > TLS variable. > > 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. > > Since copy relocation in PIE is incompatible with DSO created by > -Wl,-Bsymbolic, this patch also adds a new option, -fsymbolic, which > controls how references to global symbols are bound. The -fsymbolic > option binds references to global symbols to the local definitions > and external references globally. It avoids copy relocations in PIE > and optimizes global symbol references in shared library created > by -Wl,-Bsymbolic. > > OK for master? >
Since -fsymbolic binds references to protected symbols locally, default_binds_local_p_3 should return true for protected symbols with -fsymbolic. H.J. --- gcc/ PR target/65846 PR target/65886 * configure.ac (HAVE_LD_PIE_COPYRELOC): Renamed to ... (HAVE_LD_X86_64_PIE_COPYRELOC): This. (HAVE_LD_386_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 true 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 PR target/65886 * 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. * gcc.target/i386/pr65886-1.c: Likewise. * gcc.target/i386/pr65886-2.c: Likewise. * gcc.target/i386/pr65886-3.c: Likewise. * gcc.target/i386/pr65886-4.c: Likewise. * lib/target-supports.exp (check_effective_target_pie_copyreloc): Check HAVE_LD_X86_64_PIE_COPYRELOC and HAVE_LD_386_PIE_COPYRELOC instead of HAVE_LD_X86_64_PIE_COPYRELOC. --- gcc/common.opt | 4 ++ gcc/config.in | 18 ++++--- gcc/config/i386/i386.c | 44 ++++++++++----- gcc/configure | 68 ++++++++++++++++++++--- gcc/configure.ac | 64 +++++++++++++++++++--- gcc/doc/invoke.texi | 12 ++++- 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/gcc.target/i386/pr65886-1.c | 19 +++++++ gcc/testsuite/gcc.target/i386/pr65886-2.c | 15 ++++++ gcc/testsuite/gcc.target/i386/pr65886-3.c | 17 ++++++ gcc/testsuite/gcc.target/i386/pr65886-4.c | 15 ++++++ gcc/testsuite/lib/target-supports.exp | 10 +++- gcc/varasm.c | 69 ++++++++++++++++++------ 22 files changed, 360 insertions(+), 57 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-10.c create mode 100644 gcc/testsuite/gcc.target/i386/pr65886-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr65886-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr65886-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr65886-4.c diff --git a/gcc/common.opt b/gcc/common.opt index b49ac46..ff95276 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -986,6 +986,10 @@ fcommon Common Report Var(flag_no_common,0) Do not put uninitialized globals in the common section +fsymbolic +Common Report Var(flag_symbolic) +Bind global references locally and external references globally + fcompare-debug Driver ; Converted by the driver to -fcompare-debug= options. diff --git a/gcc/config.in b/gcc/config.in index f2ed301..b1757a7 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1349,6 +1349,12 @@ #endif +/* Define 0/1 if your 386 linker supports -pie option with copy reloc. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_386_PIE_COPYRELOC +#endif + + /* Define if your linker supports --as-needed/--no-as-needed or equivalent options. */ #ifndef USED_FOR_TARGET @@ -1429,12 +1435,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 @@ -1460,6 +1460,12 @@ #endif +/* Define 0/1 if your x86-64 linker supports -pie option with copy reloc. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_X86_64_PIE_COPYRELOC +#endif + + /* Define to 1 if you have the <limits.h> header file. */ #ifndef USED_FOR_TARGET #undef HAVE_LIMITS_H diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index d6c2de8..d793959 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -13230,11 +13230,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; @@ -51802,17 +51798,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 executables or linker supports copy reloc in PIE + executables. */ + +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_X86_64_PIE_COPYRELOC != 0; + else + local_p = HAVE_LD_386_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 @@ -51951,6 +51969,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..920c37d 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 x86-64 linker PIE support with copy reloc" >&5 +$as_echo_n "checking x86-64 linker PIE support with copy reloc... " >&6; } +gcc_cv_ld_x86_64_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_x86_64_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_x86_64_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_X86_64_PIE_COPYRELOC `if test x"$gcc_cv_ld_x86_64_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_x86_64_pie_copyreloc" >&5 +$as_echo "$gcc_cv_ld_x86_64_pie_copyreloc" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking 386 linker PIE support with copy reloc" >&5 +$as_echo_n "checking 386 linker PIE support with copy reloc... " >&6; } +gcc_cv_ld_386_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_386_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_386_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_386_PIE_COPYRELOC `if test x"$gcc_cv_ld_386_pie_copyreloc" = xyes; then echo 1; else echo 0; fi` +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_386_pie_copyreloc" >&5 +$as_echo "$gcc_cv_ld_386_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..434a379 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(x86-64 linker PIE support with copy reloc) +gcc_cv_ld_x86_64_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_x86_64_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_x86_64_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_X86_64_PIE_COPYRELOC, + [`if test x"$gcc_cv_ld_x86_64_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`], + [Define 0/1 if your x86-64 linker supports -pie option with copy reloc.]) +AC_MSG_RESULT($gcc_cv_ld_x86_64_pie_copyreloc) + +AC_MSG_CHECKING(386 linker PIE support with copy reloc) +gcc_cv_ld_386_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_386_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_386_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_386_PIE_COPYRELOC, + [`if test x"$gcc_cv_ld_386_pie_copyreloc" = xyes; then echo 1; else echo 0; fi`], + [Define 0/1 if your 386 linker supports -pie option with copy reloc.]) +AC_MSG_RESULT($gcc_cv_ld_386_pie_copyreloc) AC_MSG_CHECKING(linker EH-compatible garbage collection of sections) gcc_cv_ld_eh_gc_sections=no diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 520c2c5..9d0c3fe 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1121,7 +1121,7 @@ See S/390 and zSeries Options. -finhibit-size-directive -finstrument-functions @gol -finstrument-functions-exclude-function-list=@var{sym},@var{sym},@dots{} @gol -finstrument-functions-exclude-file-list=@var{file},@var{file},@dots{} @gol --fno-common -fno-ident @gol +-fno-common -fsymbolic -fno-ident @gol -fpcc-struct-return -fpic -fPIC -fpie -fPIE @gol -fno-jump-tables @gol -frecord-gcc-switches @gol @@ -23530,6 +23530,16 @@ it provides better performance, or if you wish to verify that the program will work on other systems that always treat uninitialized variable declarations this way. +@item -fsymbolic +@opindex -fsymbolic +This option is similar to ELF linker option, @option{-Bsymbolic}, +which controls how references to global symbols are bound. The +@option{-fsymbolic} option binds references to global symbols to the +local definitions and external references globally. This option +avoids copy relocations in position-independent executables and +optimizes global symbol references in shared library created by +linker option, @option{-Bsymbolic}. + @item -fno-ident @opindex fno-ident Ignore the @code{#ident} directive. 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/gcc.target/i386/pr65886-1.c b/gcc/testsuite/gcc.target/i386/pr65886-1.c new file mode 100644 index 0000000..1234ef3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr65886-1.c @@ -0,0 +1,19 @@ +/* Check that GOTPCREL/GOT is used to access glob_a. */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-require-effective-target pie } */ +/* { dg-options "-O2 -fpie -fsymbolic" } */ + +extern int glob_a; + +int foo () +{ + if (&glob_a != 0) + return glob_a; + else + return 0; +} + +/* 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/pr65886-2.c b/gcc/testsuite/gcc.target/i386/pr65886-2.c new file mode 100644 index 0000000..bfcc736 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr65886-2.c @@ -0,0 +1,15 @@ +/* Check that GOTPCREL/GOT isn't used to access glob_a. */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fsymbolic" } */ + +int glob_a = 1; + +int foo () +{ + return glob_a; +} + +/* 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/pr65886-3.c b/gcc/testsuite/gcc.target/i386/pr65886-3.c new file mode 100644 index 0000000..50f2a2c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr65886-3.c @@ -0,0 +1,17 @@ +/* Check that PLT isn't used to access glob_a. */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fsymbolic" } */ + +int glob_a (void) +{ + return -1; +} + +int foo () +{ + return glob_a (); +} + +/* glob_a should never be accessed with a PLT. */ +/* { dg-final { scan-assembler-not "glob_a@PLT" } } */ +/* { dg-final { scan-assembler-times "movl\[ \t\]\\\$-1, %eax" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr65886-4.c b/gcc/testsuite/gcc.target/i386/pr65886-4.c new file mode 100644 index 0000000..a259b3b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr65886-4.c @@ -0,0 +1,15 @@ +/* Check that GOTPCREL/GOT isn't used to access glob_a. */ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fpic -fsymbolic" } */ + +extern __attribute__((visibility("protected"))) int glob_a; + +int foo () +{ + return glob_a; +} + +/* 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/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index c23d1cb..94dffe0 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -6222,8 +6222,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_X86_64_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_386_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 e8d996c..a95b6e3 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -6117,7 +6117,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) @@ -6811,11 +6811,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)) @@ -6846,10 +6850,33 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, || (!in_lto_p && DECL_INITIAL (exp) == error_mark_node))); - /* 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)); + /* 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); + + bool defined_locally; + if (!DECL_EXTERNAL (exp)) + { + /* When a variable isn't defined externally, it is defined locally + only if it isn't uninitialized COMMON variable or common_local_p + is true and external references aren't bound globally. */ + defined_locally = (!uninited_common + || (common_local_p && !flag_symbolic)); + + } + else + { + /* An undefined variable is defined locally only if it is a + non-TLS non-weak data variable, external references aren't + bound globally and linker can guarantee it will be defined + locally. */ + defined_locally = (!tls + && data_local_p + && !flag_symbolic + && TREE_CODE (exp) != FUNCTION_DECL + && !DECL_WEAK (exp)); + } + if (symtab_node *node = symtab_node::get (exp)) { if (node->in_other_partition) @@ -6859,7 +6886,7 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, else if (resolution_local_p (node->resolution)) resolved_locally = true; } - if (defined_locally && weak_dominate && !shlib) + if (defined_locally && weak_dominate && (!shlib || flag_symbolic)) resolved_locally = true; /* Undefined weak symbols are never defined locally. */ @@ -6872,13 +6899,15 @@ default_binds_local_p_3 (const_tree exp, bool shlib, bool weak_dominate, if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT && (TREE_CODE (exp) == FUNCTION_DECL || !extern_protected_data + || flag_symbolic || DECL_VISIBILITY (exp) != VISIBILITY_PROTECTED) && (DECL_VISIBILITY_SPECIFIED (exp) || defined_locally)) return true; /* If PIC, then assume that any global name can be overridden by - symbols resolved from other modules. */ - if (shlib) + symbols resolved from other modules unless global references are + bound locally */ + if (shlib && !flag_symbolic) return false; /* Variables defined outside this object might not be local. */ @@ -6905,7 +6934,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, true, 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. */ @@ -6913,14 +6951,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, true, 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, true, shlib != 0, false, false, + false, false); } /* Return true when references to DECL must bind to current definition in -- 2.1.0