Bug 46713 - -fvisibility=hidden generates broken code
Summary: -fvisibility=hidden generates broken code
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.5.1
: P3 major
Target Milestone: ---
Assignee: Not yet assigned to anyone
: 47529 (view as bug list)
Depends on:
Reported: 2010-11-29 21:15 UTC by River Tarnell
Modified: 2013-08-09 17:16 UTC (History)
2 users (show)

See Also:
Host: i386-pc-solaris2.10
Target: i386-pc-solaris2.10
Build: i386-pc-solaris2.10
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description River Tarnell 2010-11-29 21:15:40 UTC
This seems to be identical to a previous problem report on gcc-help[0], which I ran into recently.

hemlock% gcc -v
Using built-in specs.
Target: i386-pc-solaris2.10
Configured with: .././configure --prefix=/opt/ts --bindir=/opt/ts/bin --libdir=/opt/ts/lib --mandir=/opt/ts/share/man --datadir=/opt/ts/share --includedir=/opt/ts/include --infodir=/opt/ts/share/info --libexecdir=/opt/ts/lib --sysconfdir=/etc/opt/ts --enable-nls --disable-static --with-gnu-as --with-as=/opt/ts/binutils/bin/as --with-gnu-ld --with-ld=/opt/ts/binutils/bin/ld --enable-threads=posix --enable-shared --enable-multilib --without-x --with-system-zlib --enable-languages=c,c++,fortran,objc --with-mpfr=/opt/ts --with-gmp=/opt/ts --with-pkgversion=Toolserver --with-local-prefix=/opt/ts
Thread model: posix
gcc version 4.5.1 (Toolserver) 

GNU assembler version 2.20.1 (i386-pc-solaris2.10) using BFD version (GNU Binutils)
GNU ld (GNU Binutils)
also reproducible with: ld: Software Generation Utilities - Solaris Link Editors: 5.10-1.500

SunOS hemlock 5.10 Generic_142910-17 i86pc i386 i86pc

Test case (test.c):

struct A;
typedef int (*F)(struct A*);
extern const struct A a;
struct A { F f; };
static int f(struct A* x) { return (x==&a); }
const struct A a = { f };

The problem is that when -fvisibility=hidden is used, GCC produces code which is not accepted by the linker.  Removing -fvisibility=hidden fixes the problem.  This is somewhat surprising since GCC claims -fvisibility=hidden is ignored; so why does it make a difference?

hemlock% gcc -m64 -fPIC -O2 -shared test.c -o test               
hemlock% gcc -m64 -fPIC -O2 -shared test.c -o test -fvisibility=hidden
test.c:6:14: warning: visibility attribute not supported in this configuration; ignored
/opt/ts/binutils/bin/ld: /var/tmp//ccezimpZ.o: relocation R_X86_64_PC32 against symbol `a' can not be used when making a shared object; recompile with -fPIC
/opt/ts/binutils/bin/ld: final link failed: Bad value
collect2: ld returned 1 exit status

With GNU ld, the tested example works fine in 32-bit mode, but the problem occurs in 64-bit mode (-m64).  With Sun ld, both 32- and 64-bit versions are broken.

This is a diff of the working asm output, and the broken output (with -fvisibility) in 64-bit mode:

hemlock% diff -u test.s.working test.s
--- test.s.working      2010-11-29 21:10:20.293575000 +0000
+++ test.s      2010-11-29 21:10:26.449154000 +0000
@@ -4,9 +4,10 @@
        .type   f, @function
-       xorl    %eax, %eax
-       cmpq    a@GOTPCREL(%rip), %rdi
+       leaq    a(%rip), %rax
+       cmpq    %rax, %rdi
        sete    %al
+       movzbl  %al, %eax
        .size   f, .-f

And the 32-bit diff:

hemlock% diff -u test.s.working test.s
--- test.s.working      2010-11-29 21:14:36.120019000 +0000
+++ test.s      2010-11-29 21:14:37.509620000 +0000
@@ -5,7 +5,7 @@
        call    .LPR2
        addl    $_GLOBAL_OFFSET_TABLE_, %ecx
-       movl    a@GOT(%ecx), %eax
+       leal    a@GOTOFF(%ecx), %eax
        cmpl    %eax, 4(%esp)
        sete    %al
        movzbl  %al, %eax

[0] http://gcc.gnu.org/ml/gcc-help/2008-02/msg00042.html
Comment 1 Andrew Pinski 2010-11-29 21:28:31 UTC
HAVE_GAS_HIDDEN should have been defined as far as I can tell.

  warning (OPT_Wattributes, "visibility attribute not supported "
           "in this configuration; ignored");

Otherwise default_binds_local_p_1 does not have the correct checks around the checks for visibility.
Comment 2 River Tarnell 2010-11-29 21:33:17 UTC
It was not:

hemlock% grep HAVE_GAS_HIDDEN auto-host.h 
/* #undef HAVE_GAS_HIDDEN */

Relevant extract from config.log:

configure:21227: checking assembler for .hidden
configure:21242: /opt/ts/binutils/bin/as    -o conftest.o conftest.s >&5
configure:21245: $? = 0
configure:21284: result: no
configure:21321: checking linker for .hidden support
configure:21370: result: yes

I'm not sure where the first "no" comes from, since as appeared to run correctly.
Comment 3 River Tarnell 2010-11-29 22:58:37 UTC
Okay, so the problem seems to be that objdump (from binutils) wasn't in $PATH when GCC was built, which makes configure mis-detect 'as' as not supporting .hidden when it actually does.  I rebuilt GCC with objdump, and the test case now works fine.

* The configure test should probably be more reliable; or,
* If that's not possible, then if .hidden is not detected, the resulting compiler should still produce correct data (i.e. -fvisibility=hidden should really be ignored)
Comment 4 Andrew Pinski 2011-01-29 19:52:51 UTC
*** Bug 47529 has been marked as a duplicate of this bug. ***
Comment 5 Andrew Pinski 2011-01-29 19:54:09 UTC
This is invalid as you need objdump in the PATH to able to detect hidden support.
Comment 6 Yuri 2011-01-29 20:07:34 UTC

You can change the warning message to be a bit more proactive:
"visibility attribute not supported in this configuration (as during configuration wasn't from binutils?); ignored"
Comment 7 River Tarnell 2011-01-29 23:09:23 UTC
I don't agree that this is invalid.  If objdump is not found, GCC should either generate an error and fail during build, or continue to build but generate correct code, albeit without visibility support.  Building and silently generating incorrect code cannot be right, surely?