diff --git a/gcc/config/i386/gnu-property.cc b/gcc/config/i386/gnu-property.cc
index f08984f32a1..ea63c1ec58c 100644
--- a/gcc/config/i386/gnu-property.cc
+++ b/gcc/config/i386/gnu-property.cc
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "output.h"
 #include "linux-common.h"
+#include "i386-protos.h"
 
 static void
 emit_gnu_property (unsigned int type, unsigned int data)
@@ -60,7 +61,9 @@ file_end_indicate_exec_stack_and_gnu_property (void)
 {
   file_end_indicate_exec_stack ();
 
-  if (flag_cf_protection == CF_NONE && !ix86_needed)
+  if (flag_cf_protection == CF_NONE
+      && !ix86_needed
+      && !ix86_has_no_direct_extern_access)
     return;
 
   unsigned int feature_1 = 0;
@@ -121,4 +124,9 @@ file_end_indicate_exec_stack_and_gnu_property (void)
   /* Generate GNU_PROPERTY_X86_ISA_1_NEEDED.  */
   if (isa_1)
     emit_gnu_property (0xc0008002, isa_1);
+
+  if (ix86_has_no_direct_extern_access)
+    /* Emite a GNU_PROPERTY_1_NEEDED note with
+       GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.  */
+    emit_gnu_property (0xb0008000, (1U << 0));
 }
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index 715d9a15ff5..b82f7060007 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3775,6 +3775,36 @@ ix86_handle_fentry_name (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+/* Handle a "nodirect_extern_access" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_nodirect_extern_access_attribute (tree *pnode, tree name,
+					 tree ARG_UNUSED (args),
+					 int ARG_UNUSED (flags),
+					 bool *no_add_attrs)
+{
+  tree node = *pnode;
+
+  if (VAR_OR_FUNCTION_DECL_P (node))
+    {
+      if ((!TREE_STATIC (node) && TREE_CODE (node) != FUNCTION_DECL
+	   && !DECL_EXTERNAL (node)) || !TREE_PUBLIC (node))
+	{
+	  warning (OPT_Wattributes,
+		   "%qE attribute have effect only on public objects", name);
+	  *no_add_attrs = true;
+	}
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Table of valid machine attributes.  */
 const struct attribute_spec ix86_attribute_table[] =
 {
@@ -3855,6 +3885,8 @@ const struct attribute_spec ix86_attribute_table[] =
     ix86_handle_fentry_name, NULL },
   { "cf_check", 0, 0, true, false, false, false,
     ix86_handle_fndecl_attribute, NULL },
+  { "nodirect_extern_access", 0, 0, true, false, false, false,
+    handle_nodirect_extern_access_attribute, NULL },
 
   /* End element.  */
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 6b3c9516a7f..b7e9aa75d25 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -79,7 +79,7 @@ extern bool ix86_expand_cmpstrn_or_cmpmem (rtx, rtx, rtx, rtx, rtx, bool);
 extern bool constant_address_p (rtx);
 extern bool legitimate_pic_operand_p (rtx);
 extern bool legitimate_pic_address_disp_p (rtx);
-extern bool ix86_force_load_from_GOT_p (rtx);
+extern bool ix86_force_load_from_GOT_p (rtx, bool = false);
 extern void print_reg (rtx, int, FILE*);
 extern void ix86_print_operand (FILE *, rtx, int);
 
@@ -401,3 +401,5 @@ extern rtl_opt_pass *make_pass_insert_endbr_and_patchable_area
   (gcc::context *);
 extern rtl_opt_pass *make_pass_remove_partial_avx_dependency
   (gcc::context *);
+
+extern bool ix86_has_no_direct_extern_access;
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index ad5a5caa413..3f520c007bd 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -363,6 +363,9 @@ unsigned int ix86_default_incoming_stack_boundary;
 /* Alignment for incoming stack boundary in bits.  */
 unsigned int ix86_incoming_stack_boundary;
 
+/* True if there is no direct access to extern symbols.  */
+bool ix86_has_no_direct_extern_access;
+
 /* Calling abi specific va_list type nodes.  */
 tree sysv_va_list_type_node;
 tree ms_va_list_type_node;
@@ -10513,13 +10516,17 @@ darwin_local_data_pic (rtx disp)
 }
 
 /* True if the function symbol operand X should be loaded from GOT.
+   If CALL_P is true, X is a call operand.
+
+   NB: -mno-direct-extern-access doesn't force load from GOT for
+   call.
 
    NB: In 32-bit mode, only non-PIC is allowed in inline assembly
    statements, since a PIC register could not be available at the
    call site.  */
 
 bool
-ix86_force_load_from_GOT_p (rtx x)
+ix86_force_load_from_GOT_p (rtx x, bool call_p)
 {
   return ((TARGET_64BIT || (!flag_pic && HAVE_AS_IX86_GOT32X))
 	  && !TARGET_PECOFF && !TARGET_MACHO
@@ -10527,11 +10534,16 @@ ix86_force_load_from_GOT_p (rtx x)
 	  && ix86_cmodel != CM_LARGE
 	  && ix86_cmodel != CM_LARGE_PIC
 	  && GET_CODE (x) == SYMBOL_REF
-	  && SYMBOL_REF_FUNCTION_P (x)
-	  && (!flag_plt
-	      || (SYMBOL_REF_DECL (x)
-		  && lookup_attribute ("noplt",
-				       DECL_ATTRIBUTES (SYMBOL_REF_DECL (x)))))
+	  && ((!call_p
+	       && (!ix86_direct_extern_access
+		   || (SYMBOL_REF_DECL (x)
+		       && lookup_attribute ("nodirect_extern_access",
+					    DECL_ATTRIBUTES (SYMBOL_REF_DECL (x))))))
+	      || (SYMBOL_REF_FUNCTION_P (x)
+		  && (!flag_plt
+		      || (SYMBOL_REF_DECL (x)
+			  && lookup_attribute ("noplt",
+					       DECL_ATTRIBUTES (SYMBOL_REF_DECL (x)))))))
 	  && !SYMBOL_REF_LOCAL_P (x));
 }
 
@@ -10798,7 +10810,11 @@ legitimate_pic_address_disp_p (rtx disp)
 	    }
 	  else if (!SYMBOL_REF_FAR_ADDR_P (op0)
 		   && (SYMBOL_REF_LOCAL_P (op0)
-		       || (HAVE_LD_PIE_COPYRELOC
+		       || ((ix86_direct_extern_access
+			    && !(SYMBOL_REF_DECL (op0)
+				 && lookup_attribute ("nodirect_extern_access",
+						      DECL_ATTRIBUTES (SYMBOL_REF_DECL (op0)))))
+			   && HAVE_LD_PIE_COPYRELOC
 			   && flag_pie
 			   && !SYMBOL_REF_WEAK (op0)
 			   && !SYMBOL_REF_FUNCTION_P (op0)))
@@ -13754,7 +13770,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
 
       if (code == 'P')
 	{
-	  if (ix86_force_load_from_GOT_p (x))
+	  if (ix86_force_load_from_GOT_p (x, true))
 	    {
 	      /* For inline assembly statement, load function address
 		 from GOT with 'P' operand modifier to avoid PLT.  */
@@ -22520,10 +22536,10 @@ int
 asm_preferred_eh_data_format (int code, int global)
 {
   /* PE-COFF is effectively always -fPIC because of the .reloc section.  */
-  if (flag_pic || TARGET_PECOFF)
+  if (flag_pic || TARGET_PECOFF || !ix86_direct_extern_access)
     {
       int type = DW_EH_PE_sdata8;
-      if (!TARGET_64BIT
+      if (ptr_mode == SImode
 	  || ix86_cmodel == CM_SMALL_PIC
 	  || (ix86_cmodel == CM_MEDIUM_PIC && (global || code)))
 	type = DW_EH_PE_sdata4;
@@ -23613,10 +23629,28 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
 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)));
+  bool direct_extern_access
+    = (ix86_direct_extern_access
+       && !(VAR_OR_FUNCTION_DECL_P (exp)
+	    && lookup_attribute ("nodirect_extern_access",
+				 DECL_ATTRIBUTES (exp))));
+  if (!direct_extern_access)
+    ix86_has_no_direct_extern_access = true;
+  return default_binds_local_p_3 (exp, flag_shlib != 0, true,
+				  direct_extern_access,
+				  (direct_extern_access
+				   && (!flag_pic
+				       || (TARGET_64BIT
+					   && HAVE_LD_PIE_COPYRELOC != 0))));
+}
+
+/* If flag_pic or ix86_direct_extern_access is false, then neither
+   local nor global relocs should be placed in readonly memory.  */
+
+static int
+ix86_reloc_rw_mask (void)
+{
+  return (flag_pic || !ix86_direct_extern_access) ? 3 : 0;
 }
 #endif
 
@@ -24681,6 +24715,11 @@ ix86_libgcc_floating_mode_supported_p
 #undef TARGET_IFUNC_REF_LOCAL_OK
 #define TARGET_IFUNC_REF_LOCAL_OK hook_bool_void_true
 
+#if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES
+# undef TARGET_ASM_RELOC_RW_MASK
+# define TARGET_ASM_RELOC_RW_MASK ix86_reloc_rw_mask
+#endif
+
 static bool ix86_libc_has_fast_function (int fcode ATTRIBUTE_UNUSED)
 {
 #ifdef OPTION_GLIBC
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index eb829d13d40..d8e8656a8ab 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -1206,3 +1206,7 @@ Support MWAIT and MONITOR built-in functions and code generation.
 mavx512fp16
 Target Mask(ISA2_AVX512FP16) Var(ix86_isa_flags2) Save
 Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2, AVX512F and AVX512FP16 built-in functions and code generation.
+
+mdirect-extern-access
+Target Var(ix86_direct_extern_access) Init(1)
+Do not use GOT to access external symbols.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index a961fc4e0a2..dbc453c7108 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7220,6 +7220,12 @@ On x86 targets, the @code{fentry_section} attribute sets the name
 of the section to record function entry instrumentation calls in when
 enabled with @option{-pg -mrecord-mcount}
 
+@item nodirect_extern_access
+@cindex @code{nodirect_extern_access} function attribute
+@opindex mno-direct-extern-access
+This attribute, attached to a global variable or function, is the
+counterpart to option @option{-mno-direct-extern-access}.
+
 @end table
 
 @node Xstormy16 Function Attributes
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9e588db4fce..7f2de745f48 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1436,7 +1436,7 @@ See RS/6000 and PowerPC Options.
 -mgeneral-regs-only  -mcall-ms2sysv-xlogues -mrelax-cmpxchg-loop @gol
 -mindirect-branch=@var{choice}  -mfunction-return=@var{choice} @gol
 -mindirect-branch-register -mharden-sls=@var{choice} @gol
--mindirect-branch-cs-prefix -mneeded}
+-mindirect-branch-cs-prefix -mneeded -mno-direct-extern-access}
 
 @emph{x86 Windows Options}
 @gccoptlist{-mconsole  -mcygwin  -mno-cygwin  -mdll @gol
@@ -32789,6 +32789,19 @@ x32 environments.
 @opindex mneeded
 Emit GNU_PROPERTY_X86_ISA_1_NEEDED GNU property for Linux target to
 indicate the micro-architecture ISA level required to execute the binary.
+
+@item -mno-direct-extern-access
+@opindex mno-direct-extern-access
+@opindex mdirect-extern-access
+Without @option{-fpic} nor @option{-fPIC}, always use the GOT pointer
+to access external symbols.  With @option{-fpic} or @option{-fPIC},
+treat access to protected symbols as local symbols.  The default is
+@option{-mdirect-extern-access}.
+
+@strong{Warning:} shared libraries compiled with
+@option{-mno-direct-extern-access} and executable compiled with
+@option{-mdirect-extern-access} may not be binary compatible if
+protected symbols are used in shared libraries and executable.
 @end table
 
 @node x86 Windows Options
diff --git a/gcc/testsuite/g++.target/i386/pr35513-1.C b/gcc/testsuite/g++.target/i386/pr35513-1.C
new file mode 100644
index 00000000000..6f8db37fb7c
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr35513-1.C
@@ -0,0 +1,25 @@
+// { dg-do run }
+// { dg-options "-O2 -mno-direct-extern-access" }
+
+#include <iostream>
+
+class Bug
+{
+};
+
+int throw_bug()
+{
+  throw Bug();
+
+  return 0;
+}
+
+int main()
+{
+  try {
+      std::cout << throw_bug();
+  } catch (Bug bug) {
+  };
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.target/i386/pr35513-2.C b/gcc/testsuite/g++.target/i386/pr35513-2.C
new file mode 100644
index 00000000000..9143ff3f0a5
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr35513-2.C
@@ -0,0 +1,53 @@
+// { dg-do run  }
+// { dg-options "-O2 -mno-direct-extern-access" }
+
+class Foo 
+{
+public:
+  Foo(int n) : n_(n) { }
+  int f() { return n_; }
+
+  int badTest();
+  int goodTest();
+
+private:
+
+  int n_;
+};
+
+int Foo::badTest()
+{
+  try {
+      throw int(99);
+  }
+
+  catch (int &i) {
+      n_ = 16;
+  }
+
+  return n_;
+}
+
+
+int Foo::goodTest()
+{
+  int	n;
+
+  try {
+      throw int(99);
+  }
+
+  catch (int &i) {
+      n = 16;
+  }
+
+  return n_;
+}
+
+int main() 
+{
+  Foo foo(5);
+  foo.goodTest();
+  foo.badTest();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-10a.c b/gcc/testsuite/gcc.target/i386/pr35513-10a.c
new file mode 100644
index 00000000000..d7b5c98fa8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-10a.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mno-direct-extern-access" } */
+
+/* Weak common symbol with -fpic.  */
+__attribute__((weak, visibility("protected")))
+int xxx;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-10b.c b/gcc/testsuite/gcc.target/i386/pr35513-10b.c
new file mode 100644
index 00000000000..a40692e6e3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-10b.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mdirect-extern-access" } */
+
+/* Weak common symbol with -fpic.  */
+__attribute__((weak, visibility("protected"),nodirect_extern_access))
+int xxx;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-11a.c b/gcc/testsuite/gcc.target/i386/pr35513-11a.c
new file mode 100644
index 00000000000..5489f1e5cee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-11a.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mno-direct-extern-access" } */
+
+/* Initialized symbol with -fpic.  */
+__attribute__((visibility("protected")))
+int xxx = -1;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-11b.c b/gcc/testsuite/gcc.target/i386/pr35513-11b.c
new file mode 100644
index 00000000000..2704900fed5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-11b.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mdirect-extern-access" } */
+
+/* Initialized symbol with -fpic.  */
+__attribute__((visibility("protected"), nodirect_extern_access))
+int xxx = -1;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-12a.c b/gcc/testsuite/gcc.target/i386/pr35513-12a.c
new file mode 100644
index 00000000000..8b3123f9042
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-12a.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mno-direct-extern-access" } */
+
+/* Weak initialized symbol with -fpic.  */
+__attribute__((weak, visibility("protected")))
+int xxx = -1;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-12b.c b/gcc/testsuite/gcc.target/i386/pr35513-12b.c
new file mode 100644
index 00000000000..a1b6b9e92df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-12b.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mdirect-extern-access" } */
+
+/* Weak initialized symbol with -fpic.  */
+__attribute__((weak, visibility("protected"), nodirect_extern_access))
+int xxx = -1;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-1a.c b/gcc/testsuite/gcc.target/i386/pr35513-1a.c
new file mode 100644
index 00000000000..972542423cb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-1a.c
@@ -0,0 +1,19 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-direct-extern-access" } */
+
+extern void bar (void);
+extern void *p;
+
+void
+foo (void)
+{
+  p = &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-1b.c b/gcc/testsuite/gcc.target/i386/pr35513-1b.c
new file mode 100644
index 00000000000..54a579a9e37
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-1b.c
@@ -0,0 +1,19 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mdirect-extern-access" } */
+
+extern void bar (void) __attribute__ ((nodirect_extern_access));
+extern void *p;
+
+void
+foo (void)
+{
+  p = &bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-2a.c b/gcc/testsuite/gcc.target/i386/pr35513-2a.c
new file mode 100644
index 00000000000..74fa8fc9d97
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-2a.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mno-direct-extern-access" } */
+
+extern int bar;
+
+int
+foo (void)
+{
+  return bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-2b.c b/gcc/testsuite/gcc.target/i386/pr35513-2b.c
new file mode 100644
index 00000000000..ae2edff8d93
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-2b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -mdirect-extern-access" } */
+
+extern int bar __attribute__ ((nodirect_extern_access));
+
+int
+foo (void)
+{
+  return bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-3a.c b/gcc/testsuite/gcc.target/i386/pr35513-3a.c
new file mode 100644
index 00000000000..4ca4332c4ab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-3a.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie -mno-direct-extern-access" } */
+
+extern int bar;
+
+int
+foo (void)
+{
+  return bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-3b.c b/gcc/testsuite/gcc.target/i386/pr35513-3b.c
new file mode 100644
index 00000000000..c3888039834
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-3b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie -mdirect-extern-access" } */
+
+extern int bar __attribute__ ((nodirect_extern_access));
+
+int
+foo (void)
+{
+  return bar;
+}
+
+/* { dg-final { scan-assembler "mov\(l|q\)\[ \t\]*bar@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]*bar@GOT" { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "mov\(l|q\)\[ \t\]*\\\$bar," { target { ia32 && got32x_reloc } } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-4a.c b/gcc/testsuite/gcc.target/i386/pr35513-4a.c
new file mode 100644
index 00000000000..9c3a199404c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-4a.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -mno-direct-extern-access" } */
+
+extern void foo (void);
+
+int
+bar (void)
+{
+  foo ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*foo" } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-4b.c b/gcc/testsuite/gcc.target/i386/pr35513-4b.c
new file mode 100644
index 00000000000..e1a50784bf9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-4b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -mdirect-extern-access" } */
+
+extern void foo (void) __attribute__ ((nodirect_extern_access));
+
+int
+bar (void)
+{
+  foo ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*foo" } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-5a.c b/gcc/testsuite/gcc.target/i386/pr35513-5a.c
new file mode 100644
index 00000000000..4d2e1732838
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-5a.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -mno-direct-extern-access" } */
+
+extern void foo (void);
+
+int
+bar (void)
+{
+  foo ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-5b.c b/gcc/testsuite/gcc.target/i386/pr35513-5b.c
new file mode 100644
index 00000000000..81e98ed7836
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-5b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -mdirect-extern-access" } */
+
+extern void foo (void) __attribute__ ((nodirect_extern_access));
+
+int
+bar (void)
+{
+  foo ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-6a.c b/gcc/testsuite/gcc.target/i386/pr35513-6a.c
new file mode 100644
index 00000000000..ece878e3c3a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-6a.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -mno-direct-extern-access" } */
+
+extern void foo (void);
+
+void
+bar (void)
+{
+  foo ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*foo" } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-6b.c b/gcc/testsuite/gcc.target/i386/pr35513-6b.c
new file mode 100644
index 00000000000..3f679defdab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-6b.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -mdirect-extern-access" } */
+
+extern void foo (void) __attribute__ ((nodirect_extern_access));
+
+void
+bar (void)
+{
+  foo ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*foo" } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-7a.c b/gcc/testsuite/gcc.target/i386/pr35513-7a.c
new file mode 100644
index 00000000000..1de014d39c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-7a.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -mno-direct-extern-access" } */
+
+extern void foo (void);
+
+void
+bar (void)
+{
+  foo ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*foo@PLT" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-7b.c b/gcc/testsuite/gcc.target/i386/pr35513-7b.c
new file mode 100644
index 00000000000..984e2dc2752
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-7b.c
@@ -0,0 +1,18 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -mdirect-extern-access" } */
+
+extern void foo (void) __attribute__ ((nodirect_extern_access));
+
+void
+bar (void)
+{
+  foo ();
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*foo@PLT" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*foo@PLT" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "foo@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "foo@GOT" { target ia32 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-8.c b/gcc/testsuite/gcc.target/i386/pr35513-8.c
new file mode 100644
index 00000000000..7ba67de2156
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-8.c
@@ -0,0 +1,44 @@
+/* { dg-do assemble { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-mx32 -O2 -fno-pic -fexceptions -fasynchronous-unwind-tables -mno-direct-extern-access" } */
+
+extern int foo (int);
+extern void exit (int __status) __attribute__ ((__nothrow__ )) __attribute__ ((__noreturn__));
+struct __pthread_cleanup_frame
+{
+  void (*__cancel_routine) (void *);
+  void *__cancel_arg;
+  int __do_it;
+  int __cancel_type;
+};
+extern __inline void
+__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame)
+{
+  if (__frame->__do_it)
+    __frame->__cancel_routine (__frame->__cancel_arg);
+}
+static int cl_called;
+
+static void
+cl (void *arg)
+{
+  ++cl_called;
+}
+
+
+void *
+tf_usleep (void *arg)
+{
+
+  do { struct __pthread_cleanup_frame __clframe __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) = { .__cancel_routine = (cl), .__cancel_arg = (
+																			 ((void *)0)), .__do_it = 1 };;
+
+    foo (arg == ((void *)0) ? (0x7fffffffL * 2UL + 1UL) : 0);
+
+    __clframe.__do_it = (0); } while (0);
+
+  exit (1);
+}
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-9a.c b/gcc/testsuite/gcc.target/i386/pr35513-9a.c
new file mode 100644
index 00000000000..533f1d2ddb4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-9a.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mno-direct-extern-access" } */
+
+/* Common symbol with -fpic.  */
+__attribute__((visibility("protected")))
+int xxx;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/pr35513-9b.c b/gcc/testsuite/gcc.target/i386/pr35513-9b.c
new file mode 100644
index 00000000000..b6c66f43b40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr35513-9b.c
@@ -0,0 +1,20 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -mdirect-extern-access" } */
+
+/* Common symbol with -fpic.  */
+__attribute__((visibility("protected"), nodirect_extern_access))
+int xxx;
+
+int
+foo ()
+{
+  return xxx;
+}
+
+/* { dg-final { scan-assembler "xxx\\(%rip\\)" { 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 } } } */
+/* { dg-final { scan-assembler "\.section\[ \t]+.note.gnu.property," } } */
+/* { dg-final { scan-assembler "\.long\[ \t]+0xb0008000" } } */
+
