Solaris (Command Line)

From Crypto++ Wiki
Jump to: navigation, search

Crypto++ mostly supports the Solaris operating system. Crypto++ 5.6.3 and below had mediocre support for Solaris and Sun Studio because it was effectively running with CRYPTOPP_DISABLE_ASM enabled, even on i86 platforms. Crypto++ 5.6.4 added first class support for the Solaris Intel platform, and benchmarks for 5.6.4 will run considerably faster than 5.6.3 and below. This wiki page will detail how to compile the Crypto++ library and programs on Solaris, and how to get the most out of the i86 platform. The page will also provide information in the context of SunCC, which is is Oracle's C++ compiler.

The Sun C++ compiler was endowed with GCC-style inline ASM at SunCC 5.10, which is part of Sun Studio 12. Also see GCC-style asm inlining support in Sun Studio 12 compilers. The inline assembly support means there is opportunity to have Crypto++ perform as well on Solaris as it does other Linux and Unix platforms. Crypto++ first offered Sun C++ compiler integration at 5.6.4 with Commit b1df5736a7191eb1.

Be certain you have enough virtual memory before you attempt to compile some of the heavier files, like bench.cpp or regetst.cpp. If you don't have enough virtual memory, then you will experience bizarre unexplained failures when running gmake. We were surprised to learn our test machine, Proliant G5 server with 8GB of RAM and 100+ GB of free storage, was running out of virtual memory. Also see Verify there's enough memory and storage to compile a file? on Super User.

Finally, be certain you use the same compiler, the same compiler options, and the same C++ runtimes to build the library and your programs. Do not mix and match them. Also see GNUmakefile | Creating Programs on the Crypto++ wiki. This nuance has caused so many issues over the years we cannot recount them all.

Make and GNUmake

You must use GNU's make to build the library on Solaris. Sun's default make program will produce unexplained errors, and CMake will use random flags.

$ cd cryptopp
$ make
make: Fatal error: No arguments to build

$ make -f GNUmakefile
make: Fatal error in reader: GNUmakefile, line 5: Badly formed macro assignment

By default, the GNUmakefile will use whatever the C++ compiler is. To build the library with the default compiler run gmake:

$ gmake -j 4
g++ -DNDEBUG -g2 -O2 -fPIC -march=native -m64 -Wa,--divide -pipe -c cryptlib.cpp
g++ -DNDEBUG -g2 -O2 -fPIC -march=native -m64 -Wa,--divide -pipe -c cpu.cpp
g++ -DNDEBUG -g2 -O2 -fPIC -march=native -m64 -Wa,--divide -pipe -c integer.cpp
...

If you want to use Sun's C++ compiler, then specify it in CXX. Also see C++ Compiler below for more on the Sun compiler.

$ CXX=/opt/solarisstudio12.4/bin/CC gmake -j 4
/opt/solarisstudio12.4/bin/CC -DNDEBUG -g3 -xO2 -m64 -native -KPIC -template=no%extdef -c cryptlib.cpp
/opt/solarisstudio12.4/bin/CC -DNDEBUG -g3 -xO2 -m64 -native -KPIC -template=no%extdef -c cpu.cpp
/opt/solarisstudio12.4/bin/CC -DNDEBUG -g3 -xO2 -m64 -native -KPIC -template=no%extdef -c integer.cpp
...

C++ Compiler

Oracle's C++ compiler is known as SunCC in Crypto++. Each version of Sun Studio or Solaris Studio will supply the compiler called CC. There will probably be a few of them installed if different version of Sun Studio are available:

$ find /opt -name CC | grep bin
/opt/developerstudio12.5/bin/CC
/opt/solarisstudio12.4/bin/CC
/opt/solarisstudio12.3/bin/CC
/opt/solstudio12.2/bin/CC

SunCC differs from GCC in a number of ways. The SunCC does not consume -march=native, and there's no way to tell which -xarch was specified because the compiler does not signal it to the library or program. Preprocessor defines, like __SSE2__, __SSE3__, __SSE4_1__, __SSE4_2__, __AES__, __BMI__, and __AVX__, are simply missing. This detail was the biggest gap to close when providing better SunCC support.

As of this writing, -std=c++03 and -std=c++11 are almost incompatible with -xarch when -xarch uses aes and above (i.e., -xarch=aes or -xarch=avx). See C++03 and C++11 below for more details.

To compile Crypto++ to the equivalent of -march=native you will need to supply the preprocessor macros. Additionally, you may need to use -xarch depending on the compiler version. The Crypto++ library test script, cryptest.sh, goes to great lengths to determine processor features, and then provide the proper set of defines and -xarch options. You will likely need to perform the same to get the best performance from the library.

Library Defines

Th Crypto++ library depends upon GCC style preprocessor macros like __SSE2__, __SSE3__ and __AES__ to enable code paths. Here's an example of a simple one-liner from misc.h that uses BMI's BLSR instruction:

#if defined(__GNUC__) && defined(__BMI__)
template <>
inline bool IsPowerOf2<word32>(const word32 &value)
{
    return value > 0 && _blsr_u32(value) == 0;
}
#endif

At Crypto++ 5.6.4 the library unconditionally defined __SSE2__ in config.h for SunCC at Commit b1df5736a7191eb1. By defining __SSE2__ in config.h all users enjoy at least SSE2 support. SSE2 is the majority of the specialized implementations, and it includes both SSE2 ASM and SSE2 intrinsics.

#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(__SSE2__) && defined(__x86_64__) && (__SUNPRO_CC >= 0x5100)
# define __SSE2__ 1
#endif

To take advantage of additional CPU features you will have to manually define the missing preprocessor macros. The library's test script cryptest.sh does so in an effort to test the code paths by checking the cpu flags with isainfo -v, and then manually adding -D__XXX__ defines to CXXFLAGS. isainfo is similar to Linux's /proc/cpuinfo. Below is a sample output from isainfo.

$ isainfo -v
64-bit amd64 applications
        avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp ahf cx16 sse3 
        sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpu rdrand 
32-bit i386 applications
        avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp ahf cx16 sse3 
        sse2 sse fxsr mmx cmov sep cx8 tsc fpu rdrand

If all you want are the CXXFLAGS, then simply run cryptest.sh and note the PLATFORM_CXXFLAGS. Below is from a HP Proliant G5 with Dual-Xeon's.

$ ./cryptest.sh 

IS_SOLARIS: 1
IS_X64: 1
...
Compiler: Studio 12.5 Sun C++ 5.14 SunOS_i386 2016/05/31
Pathname: /opt/developerstudio12.5/bin/CC
...
PLATFORM_CXXFLAGS: -D__SSE2__ -D__SSE3__ -D__SSSE3__ -xarch=ssse3

Here is another example from a Solaris workstation running on a 4th generation Core i5. The 4th gen Core i5 provides up to AVX.

$ ./cryptest.sh 

IS_SOLARIS: 1
IS_X64: 1
...
Compiler: Sun C++ 5.13 SunOS_i386 2014/10/20
Pathname: /opt/solarisstudio12.4/bin/CC
...
PLATFORM_CXXFLAGS: -D__SSE2__ -D__SSE3__ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -D__PCLMUL__
                   -D__AES__ -D__RDRND__ -D__AVX__ -xarch=avx

And here is one from a 5th generation Core i5, which includes BMI and ADX.

$ ./cryptest.sh 

IS_SOLARIS: 1
IS_X64: 1
...
Compiler: Studio 12.5 Sun C++ 5.14 SunOS_i386 2016/05/31
Pathname: /opt/developerstudio12.5/bin/CC
...
PLATFORM_CXXFLAGS: -D__SSE2__ -D__SSE3__ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -D__PCLMUL__
                   -D__AES__ -D__RDRND__ -D__RDSEED__ -D__AVX__ -D__AVX2__ -D__BMI__ -D__BMI2__
                   -D__ADX__ -xarch=avx2_i

From the three example above, it can be seen -xarch=XXX is also a moving target dependent upon both CPU feature flags and compiler version. The compiler will give you a good error message with respect to -xarch, so it will be fairly easy to get right. Also see ube error: _mm_aeskeygenassist_si128 intrinsic requires at least -xarch=aes on Stack Overflow.

One non-obvious note you need -xarch=avx2_i to enable ADX. ADX provides Add-with-Carry/Add-with-Overflow, which allows pipelining some big integer operations. Also see New Instructions Supporting Large Integer Arithmetic on Intel Architecture Processors whitepaper.

Building Crypto++

Now that you know where the compiler and how to define flags, all you have to do is build the library and test it. All of this is covered in GNUmakefile, but its restated here for completeness. Since you are modifying the default CXXFLAGS, you also have to set the Debug/Release build configuration information. The build configuration information is the -DNDEBUG -g2 -O2 below.

The makefile will add the remainder of the flags, like -m64 -native -KPIC. If you need to change flags like -m64 -native or -pipe, then you will need to edit the makefile. There's another way to change flags, and it is discussed in the GNUmakefile wiki article.

# Set the preprocessor macros to enable code paths
$ export CXXFLAGS="-DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3__ -D__SSE4_1
__ -D__SSE4_2__ -D__PCLMUL__ -D__AES__ -D__RDRND__ -D__RDSEED__ -D__AVX__ -D__AV
X2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i"

# Build it!
$ CXX=/opt/developerstudio12.5/bin/CC gmake -j 2

/opt/developerstudio12.5/bin/CC -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3
__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__RDSEED__ -D_
_AVX__ -D__AVX2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i -m64 -native -KPI
C -template=no%extdef -c cryptlib.cpp
/opt/developerstudio12.5/bin/CC -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3
__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__RDSEED__ -D_
_AVX__ -D__AVX2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i -m64 -native -KPI
C -template=no%extdef -c cpu.cpp
/opt/developerstudio12.5/bin/CC -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3
__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__RDSEED__ -D_
_AVX__ -D__AVX2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i -m64 -native -KPI
C -template=no%extdef -c integer.cpp
/opt/developerstudio12.5/bin/CC -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3
__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__RDSEED__ -D_
_AVX__ -D__AVX2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i -m64 -native -KPI
C -template=no%extdef -c shacal2.cpp
...

Testing Crypto++

Once the library builds, you must run the validation suite and test vectors. Solaris is effectively a new platform since the ASM was enabled en masse, so the build must be functionally tested to provide assurances that are taken for granted on Linux and Unix.

You run the tests with cryptest.exe v and cryptest.exe tv all. There should be 0 failures as shown below.

$ ./cryptest.exe v
Using seed: 1473740352

Testing Settings...
...
All tests passed!

And:

$ ./cryptest.exe tv all
Using seed: 1473740479

Testing FileList algorithm all.txt collection.
...
Tests complete. Total tests = 5248. Failed tests = 0.

Once the library tests OK, its ready to be installed and used by programs.

Mapfile

The makefile uses a mapfile on i.86pc targets to allow object files to mask or hide additional hardware capability. The mapfile is named cryptopp.mapfile, and the recipe is shown below. The library does so because the it will often build for more capable machines. For example, the library will include SHA hardware instructions on an early iCore even though an early iCore cannot execute them.

You can disable the extra code with CRYPTOPP_DISABLE_XXX, where XXX is a feature like AESNI, AVX or SHA.

# For SunOS, create a Mapfile that allows our object files to
# contain additional bits (like SSE4 and AES on old Xeon)
ifeq ($(IS_SUN)$(SUN_COMPILER),11)
ifneq ($(IS_X86)$(IS_X32)$(IS_X64),000)
ifeq ($(findstring -DCRYPTOPP_DISABLE_ASM,$(CXXFLAGS)),)
ifeq ($(wildcard cryptopp.mapfile),)
$(shell echo "hwcap_1 = SSE SSE2 OVERRIDE;" > cryptopp.mapfile)
$(shell echo "" >> cryptopp.mapfile)
endif  # Write mapfile
LDFLAGS += -M cryptopp.mapfile
endif  # No CRYPTOPP_DISABLE_ASM
endif  # X86/X32/X64
endif  # SunOS

C++03 and C++11

As of this writing (September 2016), the library will fail to compile with Sun Studio 12.4/SunCC 5.13 with -std=c++03 or -std=c++11. We don't know why the compiler crashes as shown below, but we have an open question on Stack Overflow and we reached out to a friend of the project who works for Oracle.

First, this how the compile is supposed to look (using Sun Studio 12.5):

$ /opt/developerstudio12.5/bin/CC -std=c++03 -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE
3__ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D_
_RDSEED__ -D__AVX__ -D__AVX2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i -m64
 -native -KPIC -template=no%extdef -c gcm.cpp

The next two are the failures when using -std=c++03 or -std=c++11.

# Fail with C++03
$ /opt/solarisstudio12.4/bin/CC -std=c++03 -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3_
_ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__A
VX__ -xarch=avx -m64 -native -KPIC -template=no%extdef -c gcm.cpp
 >> Assertion:   (../lnk/g3mangler.cc, line 825)
    while processing gcm.cpp at line 413.
# Fail with C++11
$ /opt/solarisstudio12.4/bin/CC -std=c++11 -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3_
_ -D__SSSE3__ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__A
VX__ -xarch=avx -m64 -native -KPIC -template=no%extdef -c gcm.cpp
 >> Assertion:   (../lnk/g3mangler.cc, line 825)
    while processing gcm.cpp at line 413.

The -std=c++03 or -std=c++11 crash can be reproduced using Sun Studio 12.3/SunCC 5.12 by using upto -D__AES__ -D__PCLMUL__ and -xarch=aes.

We know of two rather poor work-arounds. First, you can clamp features at -D__SSE4_1__ -D__SSE4_2__ and -xarch=sse4_2. Second, you can avoid using -std=c++03 or -std=c++11.

AES-NI and CLMUL

As of this writing (September 2016), AES-NI and Carryless Multiply under Sun Studio 12.3/SunCC 5.12 is another Solaris issue we are struggling with. It does not appear to be related to C++03 and C++011 errors:

$ /opt/solarisstudio12.3/bin/CC -DNDEBUG -g -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3_
_ -D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -xarch=aes -m64 -KPIC -templa
te=no%extdef -c gcm.cpp

assertion failed in function bfd_asm_lf_dump() @ bfd_asm.c:3286
assert(mit_alternates_has_(op, IMM_ALTERNATE))

CC: ube failed for gcm.cpp

We isolated the issue to GCM_Reduce_CLMUL and reported it to Oracle though a private contact (we don't have a service contract). The work around for the issue is to avoid CLMUL when using Sun Studio 12.3 and 12.4. We disabled CLMUL in GCM for SunCC 12.3 and 12.4:

// http://github.com/weidai11/cryptopp/issues/226
#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5130)
# undef CRYPTOPP_CLMUL_AVAILABLE
#endif

Solaris 10 and below

The previous information was based on Solaris 11 on Intel hardware using Sun Studio 12. We purchased an UltrSparc for testing Solaris 10. However, the machine arrived and it was an Intel Core2 Duo (and not an UltraSparc), and it lacked an Operating System. Oracle does not make the older Operating Systems available; nor do they make the older Sun Studio's available. Finally, Oracle does not answer email requests for the same.

We were not able to do any testing with Solaris 10 or Sun Studio 11. It may work, or it may not work. "Patches are welcomed", as they say. Also see the section below on it used to Work!!!.

Sparc and UltraSparc

We lack access to a Sparc or UltraSparc machine so there's nothing interesting to discuss. A Sparc and UltraSparc should have vanilla flags, and it should look similar to the following. Again, it may work, or it may not work. "Patches are welcomed", as they say.

$ gmake -j 2
CC -DNDEBUG -g2 -O2 -m64 -native -KPIC -template=no%extdef -c cryptlib.cpp
CC -DNDEBUG -g2 -O2 -m64 -native -KPIC -template=no%extdef -c cpu.cpp
CC -DNDEBUG -g2 -O2 -m64 -native -KPIC -template=no%extdef -c integer.cpp
CC -DNDEBUG -g2 -O2 -m64 -native -KPIC -template=no%extdef -c shacal2.cpp
...

It used to work!!!

If Crypto++ used to work for you under Crypto++ 5.6.2, but fails to work as expected under 5.6.3 or 5.6.4, then its probably due to GNUmakefile changes or changes in the source code. You can use Git to go back in time to help isolate the problem. The example below uses the Crypto++ 5.6.2 makefile to build the latest sources.

$ git clone https://github.com/weidai11/cryptopp cryptopp-past-and-present
Cloning into 'cryptopp-past-and-present'...
...

$ cd cryptopp-past-and-present
$ git checkout CRYPTOPP_5_6_2
Note: checking out 'CRYPTOPP_5_6_2'. You are in 'detached HEAD' state...
$ cp GNUmakefile GNUmakefile-5.6.2   # save the old makefile

$ git checkout master -f             # or 'checkout CRYPTOPP_5_6_5'
$ cp bench1.cpp bench.cpp            # account for the bench.cpp -> bench1.cpp rename
                                     # which occurred at Crypto++ 5.6.3 (5.6.2 lacks it)

$ make -f GNUmakefile-5.6.2          # use the old makefile
c++ -DNDEBUG -g -O2 -DCRYPTOPP_DISABLE_ASM -pipe -c shacal2.cpp
c++ -DNDEBUG -g -O2 -DCRYPTOPP_DISABLE_ASM -pipe -c md5.cpp
c++ -DNDEBUG -g -O2 -DCRYPTOPP_DISABLE_ASM -pipe -c shark.cpp
c++ -DNDEBUG -g -O2 -DCRYPTOPP_DISABLE_ASM -pipe -c zinflate.cpp
...

We use the technique above often to determine if we introduced a break.