6

I have build libcrypto.a and libssl.a myself from source, specifying darwin64-x86_64-cc (for 64-bit) and darwin-i386-cc (for 32-bit) to OpenSSL's configure script.
Created the fat libraries with lipo and added them as a dependency in my Xcode project.

However, I'am getting an undefined symbol error:

undefined symbols for architecture x86_64:
  "_OPENSSL_ia32cap_P", referenced from:
      _AES_cbc_encrypt in libcrypto.a(aes-x86_64.o)
ld: symbol(s) not found for architecture x86_64

Note: Using the same technique works fine for iOS, though.

lipo -detailed_info libcrypto.a reveals:

Fat header in: libcrypto.a
fat_magic 0xcafebabe
nfat_arch 2
architecture i386
    cputype CPU_TYPE_I386
    cpusubtype CPU_SUBTYPE_I386_ALL
    offset 48
    size 2700624
    align 2^2 (4)
architecture x86_64
    cputype CPU_TYPE_X86_64
    cpusubtype CPU_SUBTYPE_X86_64_ALL
    offset 2700672
    size 3938432
    align 2^2 (4)
jww
  • 97,681
  • 90
  • 411
  • 885
Leandros
  • 16,805
  • 9
  • 69
  • 108
  • Do you have the header files for those libraries installed? Often there is a binaries package distro, which just has libraries, and a separate devel package for libraries and associated headers for coding against the libraries. – JohnH Mar 09 '15 at 15:37
  • I've included the correct headers. – Leandros Mar 09 '15 at 16:12
  • 1
    The headers are slightly different for i386 and x86_64. While the fat library builds correctly (or combines correctly with `lipo`), the headers will be slightly off for all but one of the slices. But Petesh is right. I seem to recall that's exported in some case (like static archive), but not others (like shared object). The issue is mentioned at [How can I check if OpenSSL is suport/use the Intel AES-NI?](http://stackoverflow.com/q/25284119) – jww May 10 '15 at 03:37

2 Answers2

16

It looks to be a bug in the code generator for x64 in the static library case.

The easiest, non patch openssl change workaround is to add a reference to OPENSSL_cleanse somewhere in your code, even if it's not used. That will fix up the link-time reference.

What's actually happening is that the symbol is being referenced in some assembly code.

The assembly code simply says that _OPENSSL_ia32cap_P is an extern symbol, without making the cross-link to state that it needs to be linked in. This works for libcrypto.dylib because the reference is resolved when generating the .dylib file; however the reference is never resolved in the .a case because the only code that actually contains the symbol is x86_64cpuid.o, which only gets linked in if you use any of the routines provided by that .o.

Symbols in this file includes OPENSSL_cleanse, so if you reference this routine, the link works.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • 2
    Here's what using your advice I ended up doing: `extern int OPENSSL_cleanse(void *ptr, size_t len);` – carlossless Apr 26 '15 at 19:50
  • 2
    And somewhere arbitrary in the code: `OPENSSL_cleanse(nil, 0);` – carlossless Apr 26 '15 at 19:51
  • I encountered similar issue when compiled libevent. I added OPENSSL_cleanse to the code but failed to fix it , at last I add x86_64cpuid.o path to relative Makefile to fix it. Thanks! – Dan Aug 21 '16 at 16:07
1

I stumbled upon the same linker error, and I also tried adding the line extern int OPENSSL_cleanse(void *ptr, size_t len); without success.

What ended up working for me was adding the following line, anywhere in your code files:

uint32_t OPENSSL_ia32cap_P[4] = { 0 };

Also, I used the following link as reference: https://boringssl.googlesource.com/boringssl/+/517073cd4b/crypto/cpu-intel.c#76

Jaime Ivan Cervantes
  • 3,579
  • 1
  • 40
  • 38