This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Static libc.a and weak __pthread_unwind symbol problem


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]