diff --git a/gcc/common.opt b/gcc/common.opt
index 12ca0d6..6148e49 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1010,6 +1010,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 48d7e64..77b3862 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1408,6 +1408,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
@@ -1494,12 +1500,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
@@ -1525,6 +1525,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 6fd4a56..c66cb8c 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -14517,11 +14517,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;
@@ -53496,17 +53492,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
 
@@ -53734,6 +53752,8 @@ ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
 #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 3122499..e388318 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -27525,13 +27525,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
@@ -27562,7 +27562,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
       ;;
@@ -27571,11 +27571,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 a30bb3b..7d5cc9a 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4844,12 +4844,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
@@ -4880,17 +4880,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 cd82544..5293a25 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1139,7 +1139,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 -fno-plt @gol
 -fno-jump-tables @gol
 -frecord-gcc-switches @gol
@@ -23944,6 +23944,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 e6f712a..2f191b2 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -7248,6 +7248,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 6f0c252..920ffa9 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -5038,6 +5038,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 4ce6eea..865e03c 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -583,9 +583,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 e4bc249..63b2939 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2934,6 +2934,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..c0d0aaa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr65886-1.c
@@ -0,0 +1,17 @@
+/* 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;
+}
+
+/* { dg-final { scan-assembler "glob_a@GOTPCREL" { target { ! ia32 } } } } */
+/* { 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..b89aaf0
--- /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;
+}
+
+/* { dg-final { scan-assembler "glob_a\\(%rip\\)" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "glob_a@GOTOFF\\(" { target ia32 } } } */
+/* { 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..ae24fd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr65886-3.c
@@ -0,0 +1,16 @@
+/* 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 ();
+}
+
+/* { 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..5f00508
--- /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;
+}
+
+/* { dg-final { scan-assembler "glob_a\\(%rip\\)" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "glob_a@GOTOFF\\(" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "glob_a@GOT\\(" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr65886-5.c b/gcc/testsuite/gcc.target/i386/pr65886-5.c
new file mode 100644
index 0000000..a37e2f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr65886-5.c
@@ -0,0 +1,18 @@
+/* Check that GOTPCREL/GOT isn't used to access glob_a.  */
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fsymbolic" } */
+
+int glob_a __attribute__((weak));
+
+int foo ()
+{
+  if (&glob_a != 0)
+    return glob_a;
+  else
+    return 0;
+}
+
+/* { dg-final { scan-assembler "glob_a\\(%rip\\)" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "glob_a@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "glob_a@GOTOFF\\(" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "glob_a@GOT\\(" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr65886-6.c b/gcc/testsuite/gcc.target/i386/pr65886-6.c
new file mode 100644
index 0000000..934f53f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr65886-6.c
@@ -0,0 +1,18 @@
+/* Check that PLT isn't used to access glob_a.  */
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fsymbolic" } */
+
+int
+__attribute__((weak))
+glob_a (void)
+{
+  return -1;
+}
+
+int foo ()
+{
+  return glob_a ();
+}
+
+/* { dg-final { scan-assembler-not "glob_a@PLT" } } */
+/* { dg-final { scan-assembler-times "movl\[ \t\]\\\$-1, %eax" 1 } } */
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 166b19a..2de8fac 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -6443,8 +6443,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 9cb7ac1..140f913 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6062,7 +6062,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)
@@ -6756,11 +6756,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))
@@ -6791,10 +6795,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)
@@ -6804,7 +6831,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.  */
@@ -6817,13 +6844,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.  */
@@ -6850,7 +6879,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 and
@@ -6859,14 +6897,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, true,
-				  !flag_pic);
+  return default_binds_local_p_3 (exp, true, flag_shlib != 0, true, true,
+				  !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
