summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cgraphunit.c4
-rw-r--r--gcc/testsuite/gcc.dg/visibility-22.c17
-rw-r--r--gcc/testsuite/gcc.dg/visibility-23.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-1.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-2.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-3.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-4.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-5.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-6.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-7.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr32219-8.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr64317.c2
-rw-r--r--gcc/varasm.c95
13 files changed, 260 insertions, 5 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index f2c40d43d71..057eedb3429 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -803,8 +803,10 @@ varpool_node::finalize_decl (tree decl)
if (node->definition)
return;
- notice_global_symbol (decl);
+ /* Set definition first before calling notice_global_symbol so that
+ it is available to notice_global_symbol. */
node->definition = true;
+ notice_global_symbol (decl);
if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
/* Traditionally we do not eliminate static variables when not
optimizing and when not doing toplevel reoder. */
diff --git a/gcc/testsuite/gcc.dg/visibility-22.c b/gcc/testsuite/gcc.dg/visibility-22.c
new file mode 100644
index 00000000000..52f59be3341
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/visibility-22.c
@@ -0,0 +1,17 @@
+/* PR target/32219 */
+/* { dg-do run } */
+/* { dg-require-visibility "" } */
+/* { dg-options "-O2 -fPIC" { target fpic } } */
+/* This test requires support for undefined weak symbols. This support
+ is not available on hppa*-*-hpux*. The test is skipped rather than
+ xfailed to suppress the warning that would otherwise arise. */
+/* { dg-skip-if "" { "hppa*-*-hpux*" "*-*-aix*" "*-*-darwin*" } "*" { "" } } */
+
+extern void foo () __attribute__((weak,visibility("hidden")));
+int
+main()
+{
+ if (foo)
+ foo ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/visibility-23.c b/gcc/testsuite/gcc.dg/visibility-23.c
new file mode 100644
index 00000000000..0fa9ef4c3e2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/visibility-23.c
@@ -0,0 +1,15 @@
+/* PR target/32219 */
+/* { dg-do compile } */
+/* { dg-require-visibility "" } */
+/* { dg-final { scan-hidden "foo" } } */
+/* { dg-options "-O2 -fPIC" { target fpic } } */
+/* { dg-skip-if "" { "hppa*-*-hpux*" "*-*-aix*" "*-*-darwin*" } "*" { "" } } */
+
+extern void foo () __attribute__((weak,visibility("hidden")));
+int
+main()
+{
+ if (foo)
+ foo ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-1.c b/gcc/testsuite/gcc.target/i386/pr32219-1.c
new file mode 100644
index 00000000000..5bd80a0cd47
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie" } */
+
+/* Common symbol with -fpie. */
+int xxx;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-2.c b/gcc/testsuite/gcc.target/i386/pr32219-2.c
new file mode 100644
index 00000000000..0cf2eb565c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic" } */
+
+/* Common symbol with -fpic. */
+int xxx;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-3.c b/gcc/testsuite/gcc.target/i386/pr32219-3.c
new file mode 100644
index 00000000000..911f2a56d5d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-3.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie" } */
+
+/* Weak common symbol with -fpie. */
+__attribute__((weak))
+int xxx;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-4.c b/gcc/testsuite/gcc.target/i386/pr32219-4.c
new file mode 100644
index 00000000000..3d434393538
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-4.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic" } */
+
+/* Weak common symbol with -fpic. */
+__attribute__((weak))
+int xxx;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-5.c b/gcc/testsuite/gcc.target/i386/pr32219-5.c
new file mode 100644
index 00000000000..ee7442eb803
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-5.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie" } */
+
+/* Initialized symbol with -fpie. */
+int xxx = -1;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-6.c b/gcc/testsuite/gcc.target/i386/pr32219-6.c
new file mode 100644
index 00000000000..f261433538e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-6.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic" } */
+
+/* Initialized symbol with -fpic. */
+int xxx = -1;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-7.c b/gcc/testsuite/gcc.target/i386/pr32219-7.c
new file mode 100644
index 00000000000..12aaf7224d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-7.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpie" } */
+
+/* Weak initialized symbol with -fpie. */
+__attribute__((weak))
+int xxx = -1;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr32219-8.c b/gcc/testsuite/gcc.target/i386/pr32219-8.c
new file mode 100644
index 00000000000..2e4fba07a05
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr32219-8.c
@@ -0,0 +1,17 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -fpic" } */
+
+/* Weak initialized symbol with -fpic. */
+__attribute__((weak))
+int xxx = -1;
+
+int
+foo ()
+{
+ return xxx;
+}
+
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx\\(%rip\\), %eax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "xxx@GOTPCREL" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "movl\[ \t\]xxx@GOTOFF\\(%\[^,\]*\\), %eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "movl\[ \t\]xxx@GOT\\(%\[^,\]*\\), %eax" { target ia32 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr64317.c b/gcc/testsuite/gcc.target/i386/pr64317.c
index 33f5b5d7002..32969fc689a 100644
--- a/gcc/testsuite/gcc.target/i386/pr64317.c
+++ b/gcc/testsuite/gcc.target/i386/pr64317.c
@@ -1,7 +1,7 @@
/* { dg-do compile { target { *-*-linux* && ia32 } } } */
/* { dg-options "-O2 -fpie" } */
/* { dg-final { scan-assembler "addl\[ \\t\]+\[$\]_GLOBAL_OFFSET_TABLE_, %ebx" } } */
-/* { dg-final { scan-assembler "movl\[ \\t\]+c@GOT\[(\]%ebx\[)\]" } } */
+/* { dg-final { scan-assembler "movl\[ \\t\]+c@GOTOFF\[(\]%ebx\[)\]" } } */
/* { dg-final { scan-assembler-not "movl\[ \\t\]+\[0-9]+\[(\]%esp\[)\], %ebx" } } */
long c;
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 3f62fca04de..7b1ead0a3d1 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6802,13 +6802,101 @@ resolution_local_p (enum ld_plugin_symbol_resolution resolution)
|| resolution == LDPR_RESOLVED_EXEC);
}
+static bool
+default_binds_local_p_2 (const_tree exp, int shlib)
+{
+ bool local_p;
+ bool resolved_locally = false;
+ bool resolved_to_local_def = false;
+
+ /* With resolution file in hands, take look into resolutions.
+ We can't just return true for resolved_locally symbols,
+ because dynamic linking might overwrite symbols
+ in shared libraries. */
+ if (TREE_CODE (exp) == VAR_DECL && TREE_PUBLIC (exp)
+ && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
+ {
+ varpool_node *vnode = varpool_node::get (exp);
+ /* If not building shared library, common or initialized symbols
+ are also resolved locally, regardless they are weak or not. */
+ if (vnode)
+ {
+ if ((!shlib && vnode->definition)
+ || vnode->in_other_partition
+ || resolution_local_p (vnode->resolution))
+ resolved_locally = true;
+ if (resolution_to_local_definition_p (vnode->resolution))
+ resolved_to_local_def = true;
+ }
+ }
+ else if (TREE_CODE (exp) == FUNCTION_DECL && TREE_PUBLIC (exp))
+ {
+ struct cgraph_node *node = cgraph_node::get (exp);
+ if (node
+ && (resolution_local_p (node->resolution) || node->in_other_partition))
+ resolved_locally = true;
+ if (node
+ && resolution_to_local_definition_p (node->resolution))
+ resolved_to_local_def = true;
+ }
+
+ /* A non-decl is an entry in the constant pool. */
+ if (!DECL_P (exp))
+ local_p = true;
+ /* Weakrefs may not bind locally, even though the weakref itself is always
+ static and therefore local. Similarly, the resolver for ifunc functions
+ might resolve to a non-local function.
+ FIXME: We can resolve the weakref case more curefuly by looking at the
+ weakref alias. */
+ else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp))
+ || (TREE_CODE (exp) == FUNCTION_DECL
+ && lookup_attribute ("ifunc", DECL_ATTRIBUTES (exp))))
+ local_p = false;
+ /* Static variables are always local. */
+ else if (! TREE_PUBLIC (exp))
+ local_p = true;
+ /* A variable is local if the user has said explicitly that it will
+ be and it is resolved or defined locally, not compiling for PIC or
+ not weak. */
+ else if ((DECL_VISIBILITY_SPECIFIED (exp)
+ || resolved_to_local_def)
+ && (resolved_locally
+ || !flag_pic
+ || !DECL_EXTERNAL (exp)
+ || !DECL_WEAK (exp))
+ && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ local_p = true;
+ /* Variables defined outside this object might not be local. */
+ else if (DECL_EXTERNAL (exp) && !resolved_locally)
+ local_p = false;
+ /* If defined in this object and visibility is not default, must be
+ local. */
+ else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+ local_p = true;
+ /* Default visibility weak data can be overridden by a strong symbol
+ in another module and so are not local. */
+ else if (DECL_WEAK (exp)
+ && !resolved_locally)
+ local_p = false;
+ /* If PIC, then assume that any global name can be overridden by
+ symbols resolved from other modules. */
+ else if (shlib)
+ local_p = false;
+ /* Otherwise we're left with initialized (or non-common) global data
+ which is of necessity defined locally. */
+ else
+ local_p = true;
+
+ return local_p;
+}
+
/* Assume ELF-ish defaults, since that's pretty much the most liberal
wrt cross-module name binding. */
bool
default_binds_local_p (const_tree exp)
{
- return default_binds_local_p_1 (exp, flag_shlib);
+ return default_binds_local_p_2 (exp, flag_shlib);
}
bool
@@ -7449,9 +7537,10 @@ default_elf_asm_output_external (FILE *file ATTRIBUTE_UNUSED,
{
/* We output the name if and only if TREE_SYMBOL_REFERENCED is
set in order to avoid putting out names that are never really
- used. */
+ used. Always output visibility specified in the source. */
if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
- && targetm.binds_local_p (decl))
+ && (DECL_VISIBILITY_SPECIFIED (decl)
+ || targetm.binds_local_p (decl)))
maybe_assemble_visibility (decl);
}