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;

Reply via email to