This is the mail archive of the
mailing list for the binutils project.
Re: ld unpredictable lookup failure building shared library
"James K. Lowden" <email@example.com> writes:
> 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
> 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.
That all looks basically right. I would say that the compiler is in
error here. The compiler is certainly permitted to refer to a symbol
drawn from a library. But when compiling with -fPIC, any such reference
must not use a R_X86_64_PC32 relocation (it should use a R_X86_64_PLT32
relocation instead). So the error is that compiler emitted a PC32
relocation when it should have emitted a PLT32 relocation.
>> > $ 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.
That's not quite right. The 0x4e is the address of the relocation. The
readelf -r option just dumps the relocation information, and the
relocation refers to the symbol table. To see the entry in the symbol
table, you need to use the readelf -s option.