@@ -86,6 +86,8 @@ static tree handle_used_attribute (tree *, tree, tree, int, bool *);
static tree handle_uninitialized_attribute (tree *, tree, tree, int, bool *);
static tree handle_externally_visible_attribute (tree *, tree, tree, int,
bool *);
+static tree handle_nodirect_extern_access_attribute (tree *, tree, tree,
+ int, bool *) ;
static tree handle_no_reorder_attribute (tree *, tree, tree, int,
bool *);
static tree handle_const_attribute (tree *, tree, tree, int, bool *);
@@ -340,6 +342,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_retain_attribute, NULL },
{ "externally_visible", 0, 0, true, false, false, false,
handle_externally_visible_attribute, NULL },
+ { "nodirect_extern_access", 0, 0, true, false, false, false,
+ handle_nodirect_extern_access_attribute, NULL },
{ "no_reorder", 0, 0, true, false, false, false,
handle_no_reorder_attribute, NULL },
/* The same comments as for noreturn attributes apply to const ones. */
@@ -1674,6 +1678,36 @@ handle_externally_visible_attribute (tree *pnode, tree name,
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;
+}
+
/* Handle the "no_reorder" attribute. Arguments as in
struct attribute_spec.handler. */
@@ -1432,6 +1432,10 @@ fdiagnostics-minimum-margin-width=
Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6)
Set minimum width of left margin of source code when showing source.
+fdirect-extern-access
+Common Var(flag_direct_extern_access) Init(1) Optimization
+Do not use GOT to access external symbols.
+
fdisable-
Common Joined RejectNegative Var(common_deferred_options) Defer
-fdisable-[tree|rtl|ipa]-<pass>=range1+range2 Disable an optimization pass.
@@ -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);
@@ -10434,13 +10434,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: -fno-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
@@ -10448,11 +10452,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
+ && (!flag_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));
}
@@ -10724,7 +10733,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
+ || ((flag_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)))
@@ -13640,7 +13653,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. */
@@ -22350,10 +22363,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 || !flag_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;
@@ -23468,10 +23481,26 @@ 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
+ = (flag_direct_extern_access
+ && !(VAR_OR_FUNCTION_DECL_P (exp)
+ && lookup_attribute ("nodirect_extern_access",
+ DECL_ATTRIBUTES (exp))));
+ 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 flag_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 || !flag_direct_extern_access) ? 3 : 0;
}
#endif
@@ -24537,6 +24566,11 @@ ix86_libgcc_floating_mode_supported_p
#define TARGET_GET_MULTILIB_ABI_NAME \
ix86_get_multilib_abi_name
+#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
@@ -2934,6 +2934,12 @@ produced by @command{gold}.
For other linkers that cannot generate resolution file,
explicit @code{externally_visible} attributes are still necessary.
+@item nodirect_extern_access
+@cindex @code{nodirect_extern_access} function attribute
+@opindex fno-direct-extern-access
+This attribute, attached to a global variable or function, is the
+counterpart to option @option{-fno-direct-extern-access}.
+
@item flatten
@cindex @code{flatten} function attribute
Generally, inlining into a function is limited. For a function marked with
@@ -659,6 +659,7 @@ Objective-C and Objective-C++ Dialects}.
-fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol
-fasynchronous-unwind-tables @gol
-fno-gnu-unique @gol
+-fno-direct-extern-access @gol
-finhibit-size-directive -fcommon -fno-ident @gol
-fpcc-struct-return -fpic -fPIC -fpie -fPIE -fno-plt @gol
-fno-jump-tables -fno-bit-tests @gol
@@ -16841,6 +16842,18 @@ through the PLT for specific external functions.
In position-dependent code, a few targets also convert calls to
functions that are marked to not use the PLT to use the GOT instead.
+@item -fno-direct-extern-access
+@opindex fno-direct-extern-access
+@opindex fdirect-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.
+
+@strong{Warning:} shared libraries compiled with
+@option{-fno-direct-extern-access} and executable compiled with
+@option{-fdirect-extern-access} may not be binary compatible if
+protected symbols are used in shared libraries and executable.
+
@item -fno-jump-tables
@opindex fno-jump-tables
@opindex fjump-tables
new file mode 100644
@@ -0,0 +1,25 @@
+// { dg-do run }
+// { dg-options "-O2 -fno-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;
+}
new file mode 100644
@@ -0,0 +1,53 @@
+// { dg-do run }
+// { dg-options "-O2 -fno-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;
+}
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-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 } } } } */
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fdirect-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 } } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fno-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 } } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fdirect-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 } } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie -fno-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 } } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie -fdirect-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 } } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -fdirect-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 } } } */
new file mode 100644
@@ -0,0 +1,41 @@
+/* { dg-do assemble { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-mx32 -O2 -fno-pic -fexceptions -fasynchronous-unwind-tables -fno-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);
+}
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fno-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 } } } */
new file mode 100644
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic -fdirect-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 } } } */