[PATCH] PRs target/65846/65886: Improve copy reloc in PIE
H.J. Lu
hjl.tools@gmail.com
Sat Apr 25 18:05:00 GMT 2015
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
More information about the Gcc-patches
mailing list