@@ -2579,6 +2579,10 @@ fsigned-zeros
Common Var(flag_signed_zeros) Init(1) Optimization SetByCombined
Disable floating point optimizations that ignore the IEEE signedness of zero.
+fsingle-global-definition
+Common Var(flag_single_global_definition) Optimization
+Use GOT to access external symbols and make access to protected symbols local.
+
fsingle-precision-constant
Common Var(flag_single_precision_constant) Optimization
Convert floating point constants to single precision constants.
@@ -77,7 +77,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);
@@ -10311,13 +10311,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: -fsingle-global-definition 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
@@ -10325,11 +10329,12 @@ 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_single_global_definition)
+ || (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));
}
@@ -10595,7 +10600,8 @@ 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_single_global_definition
+ && HAVE_LD_PIE_COPYRELOC
&& flag_pie
&& !SYMBOL_REF_WEAK (op0)
&& !SYMBOL_REF_FUNCTION_P (op0)))
@@ -13497,7 +13503,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. */
@@ -21895,10 +21901,10 @@ ix86_stack_protect_fail (void)
int
asm_preferred_eh_data_format (int code, int global)
{
- if (flag_pic)
+ if (flag_pic || flag_single_global_definition)
{
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;
@@ -22986,10 +22992,21 @@ 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)));
+ return default_binds_local_p_3 (exp, flag_shlib != 0, true,
+ !flag_single_global_definition,
+ (!flag_single_global_definition
+ && (!flag_pic
+ || (TARGET_64BIT
+ && HAVE_LD_PIE_COPYRELOC != 0))));
+}
+
+/* If flag_pic or flag_single_global_definition is true, then neither
+ local nor global relocs should be placed in readonly memory. */
+
+static int
+ix86_reloc_rw_mask (void)
+{
+ return (flag_pic || flag_single_global_definition) ? 3 : 0;
}
#endif
@@ -24016,6 +24033,11 @@ ix86_run_selftests (void)
#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
@@ -555,7 +555,7 @@ Objective-C and Objective-C++ Dialects}.
-fselective-scheduling -fselective-scheduling2 @gol
-fsel-sched-pipelining -fsel-sched-pipelining-outer-loops @gol
-fsemantic-interposition -fshrink-wrap -fshrink-wrap-separate @gol
--fsignaling-nans @gol
+-fsignaling-nans -fsingle-global-definition @gol
-fsingle-precision-constant -fsplit-ivs-in-unroller -fsplit-loops@gol
-fsplit-paths @gol
-fsplit-wide-types -fsplit-wide-types-early -fssa-backprop -fssa-phiopt @gol
@@ -16543,6 +16543,12 @@ 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 -fsingle-global-definition
+@opindex fsingle-global-definition
+Avoid copy relocation by using the GOT pointer to access external symbols
+in both position-dependent and position-independent codes. Make access
+to protected symbols local.
+
@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 -fsingle-global-definition" }
+
+#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 -fsingle-global-definition" }
+
+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,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fsingle-global-definition" } */
+
+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,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fno-pic -fsingle-global-definition" } */
+
+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 -fsingle-global-definition" } */
+
+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 -fplt -fno-pic -fsingle-global-definition" } */
+
+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 -fpic -fsingle-global-definition" } */
+
+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,14 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fno-pic -fsingle-global-definition" } */
+
+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,15 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fplt -fpic -fsingle-global-definition" } */
+
+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,41 @@
+/* { dg-do assemble { target { *-*-linux* && { ! ia32 } } } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-mx32 -O2 -fno-pic -fexceptions -fasynchronous-unwind-tables -fsingle-global-definition" } */
+
+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);
+}