ld unpredictable lookup failure building shared library

James K. Lowden jklowden@schemamania.org
Sun Apr 22 19:21:00 GMT 2012


On Sat, 21 Apr 2012 22:39:34 -0700
Ian Lance Taylor <iant@google.com> wrote:
> "James K. Lowden" <jklowden@schemamania.org> writes:
>> > $ /usr/pkg/bin/gnu-ld @linker.options
>> > /usr/pkg/bin/gnu-ld: /usr/pkgsrc/wip/clang/work/llvm/Release/lib/libLLVMCodeGen.a
>> > (ShrinkWrapping.o): relocation R_X86_64_PC32 against undefined
>> > symbol `_ZNSs4_Rep10_M_disposeERKSaIcE'
>> > can not be used when making a shared object; recompile with -fPIC
> 
> As the error message says, it's a problem to have a R_X86_64_PC32
> relocation against an undefined symbol.  It's not a problem to have
> such a relocation against a defined symbol.

Hi Ian, 

I think I get it now.  In my own words:

1.  With -fPIC, the compiler may generate R_X86_64_PC32.  It is
"normal" to have an R_X86_64_PC32 against *defined* symbols, but not
strictly necessary.  

2.  Such defined symbols must  be local or have non-default
visibility.  (As a C programmer, I think that means such symbols have
no external linkage i.e. they are declared static.  But that
contradicts #1.)

3.  The object file in question was compiled with -fPIC and furthermore
contains artifacts of being compiled with -fPIC.  

4.  When the linker is generating a shared library, every R_X86_64_PC32
relocation (directive? instruction?) must refer to a symbol defined in
an object file passed to the linker, not in any shared library.  

5.  The linker reports finding a symbol with an R_X86_64_PC32
relocation for an undefined symbol.  That appears to be correct,
insofar as I have been unable to find a definition for that symbol
among the object files mentioned on the linker command line using
objdump and readelf.  

6.  Ergo, the the build is in error.  

If I could generate one tiny .o with a definition for
_ZNSs4_Rep10_M_disposeERKSaIcE, the link would work. But that should
not be necessary because the compiler should never have emitted a file
lacking that definition in the first place.  (Although the symbol can
be defined in another .o, the compiler has no right to assume there
will be another .o.  It's possible to build a .so using just one .cpp
file.)

Or the compiler is in error?  Much rests on the meaning of "normal"
above.  It is unclear to me why the compiler would sometimes not define
a symbol that cannot be drawn from a library.  

> > $ readelf -rw  ../../lib/CodeGen/Release/ShrinkWrapping.o \
> > 	| grep -c '_ZNSs4_Rep10_M_disposeERKSaIcE' 
> > 0
> 
> The readelf program is (in my opinion) broken in that you have to use
> the --wide option to get reliable results.

That's what -rw was meant to do but didn't.  Here it is corrected
(wrapped for email):

$ readelf -rW  ../../lib/CodeGen/Release/ShrinkWrapping.o \
	| grep '_ZNSs4_Rep10_M_disposeERKSaIcE' 
000000000000004e  0000013300000002
R_X86_64_PC32          0000000000000000 _ZNSs4_Rep10_M_disposeERKSaIcE
+ fffffffffffffffc

Apart from truncating symbols by default, the readelf program has
another serious flaw: the documentation is long on inputs and silent on
the meaning of the outputs.  

I'm guessing that the zeros for the "value" in column 3 indicate the
symbol appears at offset 0x4E but is not defined.  That of course
is consistent with the linker message.  

> I don't know whether you are linking libstdc++.so itself or not.  

No.  Just to clarify, the -o on the command line indicated a clang
shared object.  It references libstdc++ implicitly.  

> Hope that makes more sense.

Yes, I'm in the process of building gcc 4.7 now to see if that changes
anything.  I would like to understand whether or not the compiler can
legitimately choose not to define the symbol, and if so how it
decides.  That would also tell me (I hope) how to generate a tiny file
defining the symbol to satisfy the linker.  

> the symbol definition is likely to be out of range from the reference.

http://www.technovelty.org/code/c/amd64-pic.html

>From that post I gather that R_X86_64_PC32 is 32-bits, permitting the
symbol to be defined at an address up to 2 GB distant from the
reference.  The linker can control this; it knows all the static
offsets and can bomb out if the whole .so cannot be contructed in that
space.  On a 64-bit architecture, no such guarantee can be made by the
runtime linker.  It could "try" but it would sometimes fail, and fail
catastrophically.  Discretion being the better part of valor, it
instead insists on larger (?) relocations that can assuredly be
resolved at runtime.  

I would be interested in your comments on my surmise.  I'm sure others
would, too.  

Thank you again for your help.  It has been quite an education.  

Regards, 

--jkl



More information about the Binutils mailing list