On 02/10/2015 01:19 PM, Richard Henderson wrote:
> As an existing issue, I'm not sure why "specified" visibility is any different
> from unspecified visibility.  As far as I'm aware, the "specified" bit simply
> means that the decl doesn't inherit inherit visibility from the class, or from
> the command-line.  But once we're this far, the visibility actually applied to
> the symbol should be all that matters.

The test is there to differentiate explicit visibility from that implied from
the command-line.  Without it, we assume hidden visibility for external symbols
too early, making the command-line option useless.  This is visible even in
building libgcc.

I believe this set of patches does what we want, and cleans things up a bit in
the process.


r~
From bf5d4f20368d1173a8d586f6bdd258b00b807e33 Mon Sep 17 00:00:00 2001
From: Richard Henderson <r...@redhat.com>
Date: Wed, 11 Feb 2015 17:37:48 -0800
Subject: [PATCH 1/5] Replace local_p with direct returns

---
 gcc/varasm.c | 66 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 34 insertions(+), 32 deletions(-)

diff --git a/gcc/varasm.c b/gcc/varasm.c
index 3f62fca..83d9de3 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6814,7 +6814,6 @@ default_binds_local_p (const_tree exp)
 bool
 default_binds_local_p_1 (const_tree exp, int shlib)
 {
-  bool local_p;
   bool resolved_locally = false;
   bool resolved_to_local_def = false;
 
@@ -6845,54 +6844,57 @@ default_binds_local_p_1 (const_tree exp, int shlib)
 
   /* A non-decl is an entry in the constant pool.  */
   if (!DECL_P (exp))
-    local_p = true;
+    return 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))
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp))
 	   || (TREE_CODE (exp) == FUNCTION_DECL
 	       && lookup_attribute ("ifunc", DECL_ATTRIBUTES (exp))))
-    local_p = false;
+    return 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.  */
-  else if ((DECL_VISIBILITY_SPECIFIED (exp)
-	    || resolved_to_local_def)
-	   && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
-    local_p = true;
+  if (! TREE_PUBLIC (exp))
+    return true;
+
+  /* A variable is local if the user has said explicitly that it will be.  */
+  if ((DECL_VISIBILITY_SPECIFIED (exp) || resolved_to_local_def)
+      && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+    return 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;
+  if (DECL_EXTERNAL (exp) && !resolved_locally)
+    return false;
+
+  /* If defined in this object and visibility is not default,
+     must be local.  */
+  if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
+    return 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 (DECL_WEAK (exp) && !resolved_locally)
+    return false;
+
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
-  else if (shlib)
-    local_p = false;
+  if (shlib)
+    return false;
+
   /* Uninitialized COMMON variable may be unified with symbols
      resolved from other modules.  */
-  else if (DECL_COMMON (exp)
-	   && !resolved_locally
-	   && (DECL_INITIAL (exp) == NULL
-	       || (!in_lto_p && DECL_INITIAL (exp) == error_mark_node)))
-    local_p = false;
+  if (DECL_COMMON (exp)
+      && !resolved_locally
+      && (DECL_INITIAL (exp) == NULL
+	  || (!in_lto_p && DECL_INITIAL (exp) == error_mark_node)))
+    return 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;
+  return true;
 }
 
 /* Return true when references to DECL must bind to current definition in
-- 
2.1.0

From 0b1ac37c688093d720a99b5ae446602a0c1120b3 Mon Sep 17 00:00:00 2001
From: Richard Henderson <r...@redhat.com>
Date: Wed, 11 Feb 2015 19:27:14 -0800
Subject: [PATCH 2/5] Use symtab_node to unify var and function handling

Delay that until after static symbols are eliminated.
---
 gcc/varasm.c | 59 +++++++++++++++++++----------------------------------------
 1 file changed, 19 insertions(+), 40 deletions(-)

diff --git a/gcc/varasm.c b/gcc/varasm.c
index 83d9de3..dcc70e3 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6814,34 +6814,6 @@ default_binds_local_p (const_tree exp)
 bool
 default_binds_local_p_1 (const_tree exp, int shlib)
 {
-  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 (vnode && (resolution_local_p (vnode->resolution) || vnode->in_other_partition))
-	resolved_locally = true;
-      if (vnode
-	  && 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))
     return true;
@@ -6860,6 +6832,21 @@ default_binds_local_p_1 (const_tree exp, int shlib)
   if (! TREE_PUBLIC (exp))
     return true;
 
+  /* With resolution file in hand, take look into resolutions.
+     We can't just return true for resolved_locally symbols,
+     because dynamic linking might overwrite symbols
+     in shared libraries.  */
+  bool resolved_locally = false;
+  bool resolved_to_local_def = false;
+  if (symtab_node *node = symtab_node::get (exp))
+    {
+      if (node->in_other_partition
+	  || resolution_local_p (node->resolution))
+	resolved_locally = true;
+      if (resolution_to_local_definition_p (node->resolution))
+	resolved_to_local_def = true;
+    }
+
   /* A variable is local if the user has said explicitly that it will be.  */
   if ((DECL_VISIBILITY_SPECIFIED (exp) || resolved_to_local_def)
       && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
@@ -6916,22 +6903,14 @@ decl_binds_to_current_def_p (const_tree decl)
     return false;
   if (!TREE_PUBLIC (decl))
     return true;
+
   /* When resolution is available, just use it.  */
-  if (TREE_CODE (decl) == VAR_DECL
-      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+  if (symtab_node *node = symtab_node::get (decl))
     {
-      varpool_node *vnode = varpool_node::get (decl);
-      if (vnode
-	  && vnode->resolution != LDPR_UNKNOWN)
-	return resolution_to_local_definition_p (vnode->resolution);
-    }
-  else if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      struct cgraph_node *node = cgraph_node::get (decl);
-      if (node
-	  && node->resolution != LDPR_UNKNOWN)
+      if (node->resolution != LDPR_UNKNOWN)
 	return resolution_to_local_definition_p (node->resolution);
     }
+
   /* Otherwise we have to assume the worst for DECL_WEAK (hidden weaks
      binds locally but still can be overwritten), DECL_COMMON (can be merged
      with a non-common definition somewhere in the same module) or
-- 
2.1.0

From 2a5208dfd10bf5d9b9c63c1f7464c6b6cacbcd51 Mon Sep 17 00:00:00 2001
From: Richard Henderson <r...@redhat.com>
Date: Wed, 11 Feb 2015 19:37:25 -0800
Subject: [PATCH 3/5] Don't use resolution_to_local_definition_p in
 binds_local_p

---
 gcc/varasm.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/gcc/varasm.c b/gcc/varasm.c
index dcc70e3..f467cc0 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6837,18 +6837,15 @@ default_binds_local_p_1 (const_tree exp, int shlib)
      because dynamic linking might overwrite symbols
      in shared libraries.  */
   bool resolved_locally = false;
-  bool resolved_to_local_def = false;
   if (symtab_node *node = symtab_node::get (exp))
     {
       if (node->in_other_partition
 	  || resolution_local_p (node->resolution))
 	resolved_locally = true;
-      if (resolution_to_local_definition_p (node->resolution))
-	resolved_to_local_def = true;
     }
 
   /* A variable is local if the user has said explicitly that it will be.  */
-  if ((DECL_VISIBILITY_SPECIFIED (exp) || resolved_to_local_def)
+  if (DECL_VISIBILITY_SPECIFIED (exp)
       && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     return true;
 
-- 
2.1.0

From aa50d80d97a27e99cc295e3f2a00662dc73ce235 Mon Sep 17 00:00:00 2001
From: Richard Henderson <r...@redhat.com>
Date: Wed, 11 Feb 2015 20:11:09 -0800
Subject: [PATCH 4/5] Add weak_dominate logic

---
 gcc/varasm.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/gcc/varasm.c b/gcc/varasm.c
index f467cc0..dea9b36 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -6802,17 +6802,8 @@ resolution_local_p (enum ld_plugin_symbol_resolution resolution)
 	  || resolution == LDPR_RESOLVED_EXEC);
 }
 
-/* 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);
-}
-
-bool
-default_binds_local_p_1 (const_tree exp, int shlib)
+static bool
+default_binds_local_p_2 (const_tree exp, bool shlib, bool weak_dominate)
 {
   /* A non-decl is an entry in the constant pool.  */
   if (!DECL_P (exp))
@@ -6839,11 +6830,18 @@ default_binds_local_p_1 (const_tree exp, int shlib)
   bool resolved_locally = false;
   if (symtab_node *node = symtab_node::get (exp))
     {
-      if (node->in_other_partition
+      /* When not building shared library and weak_dominate is true:
+         weak, common or initialized symbols are resolved locally.  */
+      if ((weak_dominate && !shlib && node->definition)
+	  || node->in_other_partition
 	  || resolution_local_p (node->resolution))
 	resolved_locally = true;
     }
 
+  /* Undefined (or non-dominant) weak symbols are not defined locally.  */
+  if (DECL_WEAK (exp) && !resolved_locally)
+    return false;
+
   /* A variable is local if the user has said explicitly that it will be.  */
   if (DECL_VISIBILITY_SPECIFIED (exp)
       && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
@@ -6858,11 +6856,6 @@ default_binds_local_p_1 (const_tree exp, int shlib)
   if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     return true;
 
-  /* Default visibility weak data can be overridden by a strong symbol
-     in another module and so are not local.  */
-  if (DECL_WEAK (exp) && !resolved_locally)
-    return false;
-
   /* If PIC, then assume that any global name can be overridden by
      symbols resolved from other modules.  */
   if (shlib)
@@ -6881,6 +6874,21 @@ default_binds_local_p_1 (const_tree exp, int shlib)
   return true;
 }
 
+/* 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_2 (exp, flag_shlib != 0, true);
+}
+
+bool
+default_binds_local_p_1 (const_tree exp, int shlib)
+{
+  return default_binds_local_p_2 (exp, shlib != 0, false);
+}
+
 /* Return true when references to DECL must bind to current definition in
    final executable.
 
-- 
2.1.0

From 81db9e951ac27c9a7f94f88546d90c852a927d54 Mon Sep 17 00:00:00 2001
From: Richard Henderson <r...@redhat.com>
Date: Wed, 11 Feb 2015 22:16:38 -0800
Subject: [PATCH 5/5] Rest of HJL patch

---
 gcc/cgraphunit.c                          |  4 +++-
 gcc/testsuite/gcc.dg/visibility-22.c      | 17 +++++++++++++++++
 gcc/testsuite/gcc.dg/visibility-23.c      | 15 +++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-1.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-2.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-3.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-4.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-5.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-6.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-7.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr32219-8.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr64317.c   |  2 +-
 gcc/varasm.c                              |  5 +++--
 13 files changed, 171 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/visibility-22.c
 create mode 100644 gcc/testsuite/gcc.dg/visibility-23.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr32219-8.c

diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index f2c40d4..057eedb 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 0000000..52f59be
--- /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 0000000..0fa9ef4
--- /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 0000000..5bd80a0
--- /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 0000000..0cf2eb5
--- /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 0000000..911f2a5
--- /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 0000000..3d43439
--- /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 0000000..ee7442e
--- /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 0000000..f261433
--- /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 0000000..12aaf72
--- /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 0000000..2e4fba0
--- /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 33f5b5d..32969fc 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 dea9b36..9f79416 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -7435,9 +7435,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);
 }
 
-- 
2.1.0

Reply via email to