This comes up in a glibc dynamic linker test. See elf/vis{main,mod[123]}.c in the sourceware glibc tree. Here vismod1.c generates an STV_PROTECTED definition of "protinmod" and code with a R_X86_64_GOTPCREL taking its address. vismain.c generates an undefined reference to protinmod, and uses both &protinmod and direct calls to protinmod; so it has a PLT entry for protinmod that is the canonical function pointer address for &protinmod. BFD ld -shared building vismod1.so emits an R_X86_64_GLOB_DAT for the R_X86_64_GOTPCREL referencing protinmod. gold -shared generates an R_X86_64_RELATIVE instead. This yields the wrong address for &protinmind (the DSO real definition address rather than the non-PIC executable's PLT entry). There may be other similar cases, but I suspect all the failures in this test are the same bug or ones obviously related enough you will find them by looking at your code.
CVSROOT: /cvs/src Module name: src Changes by: ian@sourceware.org 2011-07-12 22:29:09 Modified files: gold : ChangeLog i386.cc x86_64.cc gold/testsuite : protected_1.cc protected_main_1.cc Log message: PR gold/12980 * i386.cc (Target_i386::Scan::global): For a GOT reloc, use a GLOB_DAT relocation rather than a RELATIVE relocation for a protected symbol when creating a shared library. * x86_64.cc (Target_x86_64::Scan::global): Likewise. * testsuite/protected_1.cc (f2, get_f2_addr): New functions. * testsuite/protected_main_1.cc (main): Test that protected function has same address. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/gold/ChangeLog.diff?cvsroot=src&r1=1.803&r2=1.804 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gold/i386.cc.diff?cvsroot=src&r1=1.138&r2=1.139 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gold/x86_64.cc.diff?cvsroot=src&r1=1.136&r2=1.137 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gold/testsuite/protected_1.cc.diff?cvsroot=src&r1=1.1&r2=1.2 http://sourceware.org/cgi-bin/cvsweb.cgi/src/gold/testsuite/protected_main_1.cc.diff?cvsroot=src&r1=1.1&r2=1.2
I'm not convinced that this case is very interesting. The test fails when using gcc's visibility attribute, because in that case gcc generates a PC-relative reloc (on x86_64) and there is no way that the function addresses can match. It only works for glibc because glibc uses .protected in an asm rather than using the visibility attribute. On the other hand, for the same reason, it doesn't cost very much; normal code will never use a GOT entry for a protected variable. So I went ahead and implemented this in gold in the spirit of keeping glibc happy.
I tend to think that the aforementioned GCC behavior is a bug. But I haven't looked at the spec for visibility handling lately. At any rate, it is a Good Thing for such subtleties to have the same behavior in both ld implementations. So if this glibc test's expectation is actually wrong, then BFD ld should be fixed instead.