Fix (of sorts) for an obscure problem one is only likely to see while
in shared object hell on a 64-bit Linux system (eg, while attempting
to statically link OpenSSL code into a Python extension module). At
present the problem appears to be Linux-specific, but all we really
know so far is that this shows up on 64-bit Linux systems but does not
show up on 64-bit FreeBSD or MacOSX or any 32-bit system we've tested.
Symptom:
Linkage of shared object fails with an obscure message from the GNU
loader such as:
/usr/bin/ld: /home/foo/bar/libcrypto.a(x86_64cpuid.o):
relocation R_X86_64_PC32 against `OPENSSL_cpuid_setup' can not
be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
Which is odd, given that all the code in question *was* compiled
with -fPIC. Yes, it's a .a file, but OpenSSL was configured to
build shared libraries, so all the code was built with -fPIC, as was
the code for the Python extension that this is trying to link. So
this should have worked, it doesn't, and the error message is wrong.
To cut a long fishing story short: the problem turns out to be an
obscure violation of the rules for ELF shared libraries triggered by
assembly code attempting to reference global symbols while linking
the library. One can confirm that the assembly code is (somehow)
the trigger by rebuilding the OpenSSL libraries with no-asm, at
which point everything links correctly. So the question becomes how
to fix the violation so that one can re-enable the assembly code.
References:
http://sourceware.org/ml/binutils/2006-09/msg00151.html
http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
Fix:
The attached patch is based on the advice given by Alan Modra in the
sourceware.org thread referenced above. This hasn't been tested
extensively, but initial results look good (code links and runs).
The patch needs minor cleanup and is intended to demonstrate the
technique rather than to be incorporated directly. It needs some
kind of conditional wrapper to keep it from breaking non-gcc
compilers (and possibly even gcc on other platforms, has not been
tested enough to know yet), but since almost all the references I
found to this problem were from frustrated coders banging their
heads against the wall for lack of a solution, I thought it best to
post the basic fix immediately and let somebody who understands
OpenSSL's configuration system better than I do figure out how to
pretty this up for production use.
Let me know if you need help testing this. I do have a
reproduceable test case, but it's buried deep within another
software package with a complex build system of its own. If
necessary, I can probably construct a minimal test case that
demonstrates the problem.
--- openssl-1.0.0b/crypto/cryptlib.h.~1~ 2010-01-26 08:55:32.000000000
-0500
+++ openssl-1.0.0b/crypto/cryptlib.h 2011-03-04 18:17:41.000000000 -0500
@@ -98,8 +98,22 @@
#define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1)
#define HEX_SIZE(type) (sizeof(type)*2)
+#if 0 /* [sra] */
void OPENSSL_cpuid_setup(void);
extern unsigned long OPENSSL_ia32cap_P;
+#else
+void
+/* [sra]
+ * See http://sourceware.org/ml/binutils/2006-09/msg00151.html and
+ * http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+ */
+__attribute__ ((visibility ("hidden")))
+OPENSSL_cpuid_setup(void);
+
+extern unsigned long OPENSSL_ia32cap_P
+__attribute__ ((visibility ("hidden")));
+#endif /* [sra] */
+extern unsigned long OPENSSL_ia32cap_P;
void OPENSSL_showfatal(const char *,...);
void *OPENSSL_stderr(void);
extern int OPENSSL_NONPIC_relocated;