This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] PR rtl-optimization/32219: optimizer causees wrong code in pic/hidden/weak symbol checking
- From: Richard Henderson <rth at redhat dot com>
- To: "H.J. Lu" <hjl dot tools at gmail dot com>
- Cc: Jack Howarth <howarth dot at dot gcc at gmail dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>, Mike Stump <mikestump at comcast dot net>, Iain Sandoe <iain at codesourcery dot com>, Jan Hubicka <hubicka at ucw dot cz>
- Date: Wed, 11 Feb 2015 22:22:55 -0800
- Subject: Re: [PATCH] PR rtl-optimization/32219: optimizer causees wrong code in pic/hidden/weak symbol checking
- Authentication-results: sourceware.org; auth=none
- References: <20150206162314 dot GA12597 at intel dot com> <CAJMcOU9UbX=C2t=6X+DOTynkCurczbGNG3dqZRwjmRe8_U1fCg at mail dot gmail dot com> <CAMe9rOqHHZFHS4YMOAdN16aNyn4hi6eyzxGUrMue2uDn76ydGg at mail dot gmail dot com> <CAJMcOU9+x47s7jwRL4uniLs2z9EHR_Ajfk==HX1mObm97qytCg at mail dot gmail dot com> <CAMe9rOr5Ktk_yhfFX9DHAb6Sq=v2SORaY6TbahSiKF9dB1LNSQ at mail dot gmail dot com> <CAJMcOU-hPQYF1k58CXP4E5K2_-3F50RaMV_rHm3f5R_hXxivWQ at mail dot gmail dot com> <20150207122739 dot GA25185 at gmail dot com> <CAJMcOU-Bk1i9LeaHLpZGspWjDcY_n2qFcNgnCbbEsq30ZPTipA at mail dot gmail dot com> <20150207155606 dot GA14159 at gmail dot com> <20150207164507 dot GA19402 at gmail dot com> <54DA75D2 dot 40402 at redhat dot com>
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 <rth@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 <rth@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 <rth@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 <rth@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 <rth@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