This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
Re: Static libc.a and weak __pthread_unwind symbol problem
- From: Bryan Ischo <bryan at ischo dot com>
- To: libc-help at sourceware dot org
- Date: Mon, 29 Aug 2011 13:13:20 -0700
- Subject: Re: Static libc.a and weak __pthread_unwind symbol problem
- References: <4E5BE0B4.7040502@ischo.com>
On 08/29/11 11:55, Bryan Ischo wrote:
Hello, I'm trying to diagnose a problem I am getting when linking
against glibc's libc.a. This is for glibc version 2.13 (with
glibc-ports-2.13 although I don't think any ports files are being used).
Hello, I've done some digging; I understand just enough about what is
going on to (probably) make loads of incorrect diagnosis and assumption,
so I apologize if I am way off base here.
From what I read of the binutils bfd code, the problem is caused by the
way that the __pthread_unwind symbol is defined in
nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S; it looks like this:
#ifdef IS_IN_libpthread
# ifdef SHARED
# define __pthread_unwind __GI___pthread_unwind
# endif
#else
# ifndef SHARED
.weak __pthread_unwind
# endif
#endif
When I compile glibc, I am forcing -fPIC and -DPIC for all objects, but
am using --disabled-shared and am thus only building libc.a, albeit with
PIC objects.
Thus, the code that is being assembled in cancellation.S is this line:
.weak __pthread_unwind
This results in a reference to a symbol __pthread_unwind, that is marked
as weak here (I don't really understand what 'weak' means here, since
__pthread_unwind is not defined in this file, I don't know what it means
to declare a weak symbol that is not defined, my understanding of weak
symbols is that they provide a definition of a symbol that can be
overridden by a strong version of the symbol in another file, but
cancellation.S doesn't actually define __pthread_unwind here, unless
it's being brought in by one of the included header files which are
sysdep.h, tcb-offsets.h, kernel-features.h, and lowlevellock.h).
The object file then gets this symbol:
SYMBOL TABLE:
...
0000000000000000 w *UND* 0000000000000000 __pthread_unwind
...
And this relocation record:
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
000000000000004d R_X86_64_PC32 __pthread_unwind+0xfffffffffffffffc
OK then when libgcc_s.so is linked, it is linked against libc.a. I
realize that linking a shared library against a static library is
considered not exactly kosher; but I don't quite understand *why* it is
not kosher, or why it works fine for other system types (i686 works fine
for me) but not x86_64. I *assume* that including -lc when linking
libgcc_s.so just causes all of libc.a's .o files to be included in the
libgcc_s.so library as if those libc object files had been on the link
line of libgcc_s.so, and thus libgcc_s.so is a conglomeration of both
libgcc_s and libc. I realize this is weird but since it's just an
intermediate step in building a toolchain, I don't care as long as it
works (which it doesn't due to the bug in question, so maybe I *should*
care :).
Anyway, binutils bfd code (elf64-x86-64.c) has this:
case R_X86_64_PC8:
case R_X86_64_PC16:
case R_X86_64_PC32:
if (info->shared
&& (input_section->flags & SEC_ALLOC) != 0
&& (input_section->flags & SEC_READONLY) != 0
&& h != NULL)
{
bfd_boolean fail = FALSE;
bfd_boolean branch
= (r_type == R_X86_64_PC32
&& is_32bit_relative_branch (contents, rel->r_offset));
if (SYMBOL_REFERENCES_LOCAL (info, h))
{
/* Symbol is referenced locally. Make sure it is
defined locally or for a branch. */
fail = !h->def_regular && !branch;
}
else
{
/* Symbol isn't referenced locally. We only allow
branch to symbol with non-default visibility. */
fail = (!branch
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT);
}
I don't really know what is going on here, but some instrumentation in
this code reveals to me that when the relocation record for
__pthread_unwind is being consulted when linking libgcc_s.so, the case
that is failing is the second one - it's a branch, but its
ELF_ST_VISIBILIT(h->other) *is* STV_DEFAULT, so the linker emits this error.
Can someone explain why ELF_ST_VISIBILITY(h->other) == STV_DEFAULT is
disallowed here? What would happen if it weren't disallowed? In what
way would the resulting link be faulty?
I noticed that the ELF visibility types are defined thusly (in
elf/common.h):
/* The following constants control how a symbol may be accessed once it has
become part of an executable or shared library. */
#define STV_DEFAULT 0 /* Visibility is specified by binding
type */
#define STV_INTERNAL 1 /* OS specific version of STV_HIDDEN */
#define STV_HIDDEN 2 /* Can only be seen inside currect
component */
#define STV_PROTECTED 3 /* Treat as STB_LOCAL inside current
component */
So it would seem that if __pthread_unwind were marked as one of these
other visibility types, then ld wouldn't complain and would allow the
link to proceed?
What would it mean to set __pthread_unwind as hidden in cancellation.S?
Would that violate some aspect of the code or would it work? I have
tried adding a '.hidden __pthread_unwind' line to cancellation.S, but it
didn't help; although maybe I didn't recompile properly. I'll try again.
Once again, any advice at all would be greatly appreciated. I don't
know very much about ELF or how it is linked and the fog of my confusion
could, I am sure, be cut through very effectively by a small bit of
wisdom imparted by the experts that I am sure are out there somewhere :)
Best wishes,
Bryan