Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -166,6 +166,8 @@ option(LLVM_ENABLE_ZLIB "Use zlib for compression/decompression if available." ON) +option(LLVM_WITH_OPENSSL "Use the OpenSSL libcrypto library." OFF) + if( LLVM_TARGETS_TO_BUILD STREQUAL "all" ) set( LLVM_TARGETS_TO_BUILD ${LLVM_ALL_TARGETS} ) endif() Index: Makefile.config.in =================================================================== --- Makefile.config.in +++ Makefile.config.in @@ -406,3 +406,6 @@ ifeq ($(USE_OPROFILE), 1) OPTIONAL_COMPONENTS += OProfileJIT endif + +# Do we want to enable openssl support? +USE_OPENSSL := @USE_OPENSSL@ Index: autoconf/configure.ac =================================================================== --- autoconf/configure.ac +++ autoconf/configure.ac @@ -1553,6 +1553,22 @@ AC_SUBST(LIBXML2_LIBS) AC_SUBST(LIBXML2_INC) +dnl openssl is optional; used for RNG +AC_ARG_WITH(openssl, + AS_HELP_STRING([--with-openssl], + [Use the openssl libcrypto library]), + [ + AC_SUBST(USE_OPENSSL, [1]) + AC_CHECK_LIB(crypto, AES_ctr128_encrypt, [], [ + echo "Error! You need to have openssl installed." + exit -1 + ]) + ], + AC_SUBST(USE_OPENSSL, [0])) +AC_DEFINE_UNQUOTED([USE_OPENSSL],$USE_OPENSSL, + [Define if use the openssl libcrypto library]) + + dnl===-----------------------------------------------------------------------=== dnl=== dnl=== SECTION 6: Check for header files @@ -1594,6 +1610,13 @@ else AC_SUBST(HAVE_LIBZ, 0) fi +if test "$USE_OPENSSL" -eq 1 ; then + AC_CHECK_HEADERS([openssl/aes.h openssl/evp.h], + AC_SUBST(HAVE_OPENSSL, 1), + AC_SUBST(HAVE_OPENSSL, 0)) +else + AC_SUBST(HAVE_OPENSSL, 0) +fi dnl Try to find ffi.h. if test "$llvm_cv_enable_libffi" = "yes" ; then Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -67,6 +67,8 @@ check_include_file(utime.h HAVE_UTIME_H) check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) check_include_file(zlib.h HAVE_ZLIB_H) +check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H) +check_include_file(openssl/evp.h HAVE_OPENSSL_EVP_H) check_include_file(fenv.h HAVE_FENV_H) check_symbol_exists(FE_ALL_EXCEPT "fenv.h" HAVE_DECL_FE_ALL_EXCEPT) check_symbol_exists(FE_INEXACT "fenv.h" HAVE_DECL_FE_INEXACT) @@ -111,6 +113,11 @@ else() set(HAVE_TERMINFO 0) endif() + if (LLVM_WITH_OPENSSL) + check_library_exists(crypto AES_ctr128_encrypt "" HAVE_OPENSSL) + else() + set(HAVE_OPENSSL 0) + endif() endif() # function checks @@ -474,6 +481,14 @@ endif() endif() +if( LLVM_WITH_OPENSSL ) + if( NOT HAVE_OPENSSL_AES_H OR NOT HAVE_OPENSSL_EVP_H OR NOT HAVE_OPENSSL ) + set(LLVM_WITH_OPENSSL 0) + else() + set(USE_OPENSSL 1) + endif() +endif() + set(LLVM_PREFIX ${CMAKE_INSTALL_PREFIX}) if (LLVM_ENABLE_DOXYGEN) Index: cmake/modules/LLVM-Config.cmake =================================================================== --- cmake/modules/LLVM-Config.cmake +++ cmake/modules/LLVM-Config.cmake @@ -21,6 +21,9 @@ if ( LLVM_ENABLE_ZLIB AND HAVE_LIBZ ) set(system_libs ${system_libs} z) endif() + if ( USE_OPENSSL ) + set(system_libs ${system_libs} crypto) + endif() endif( MINGW ) endif( NOT MSVC ) set(${return_var} ${system_libs} PARENT_SCOPE) Index: configure =================================================================== --- configure +++ configure @@ -777,9 +777,11 @@ XML2CONFIG LIBXML2_LIBS LIBXML2_INC +USE_OPENSSL CXXCPP HAVE_PTHREAD HAVE_LIBZ +HAVE_OPENSSL HUGE_VAL_SANITY MMAP_FILE SHLIBEXT @@ -1487,6 +1489,7 @@ Tell OProfile >= 0.9.4 how to symbolize JIT output --with-intel-jitevents Notify Intel JIT profiling API of generated code + --with-openssl Use the openssl libcrypto library Some influential environment variables: CC C compiler command @@ -6071,6 +6074,7 @@ + { echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6; } if test "${lt_cv_path_NM+set}" = set; then @@ -10586,7 +10590,7 @@ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <&5 +echo $ECHO_N "checking for AES_ctr128_encrypt in -lcrypto... $ECHO_C" >&6; } +if test "${ac_cv_lib_crypto_AES_ctr128_encrypt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char AES_ctr128_encrypt (); +int +main () +{ +return AES_ctr128_encrypt (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypto_AES_ctr128_encrypt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_crypto_AES_ctr128_encrypt=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_AES_ctr128_encrypt" >&5 +echo "${ECHO_T}$ac_cv_lib_crypto_AES_ctr128_encrypt" >&6; } +if test $ac_cv_lib_crypto_AES_ctr128_encrypt = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPTO 1 +_ACEOF + + LIBS="-lcrypto $LIBS" + +else + + echo "Error! You need to have openssl installed." + exit -1 + +fi + + +else + USE_OPENSSL=0 + +fi + + +cat >>confdefs.h <<_ACEOF +#define USE_OPENSSL $USE_OPENSSL +_ACEOF + + + + @@ -16567,6 +16682,185 @@ HAVE_LIBZ=0 fi +if test "$USE_OPENSSL" -eq 1 ; then + + +for ac_header in openssl/aes.h openssl/evp.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ------------------------------------ ## +## Report this to http://llvm.org/bugs/ ## +## ------------------------------------ ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + HAVE_OPENSSL=1 + +else + HAVE_OPENSSL=0 + +fi + +done + +else + HAVE_OPENSSL=0 + +fi if test "$llvm_cv_enable_libffi" = "yes" ; then @@ -23141,9 +23435,11 @@ XML2CONFIG!$XML2CONFIG$ac_delim LIBXML2_LIBS!$LIBXML2_LIBS$ac_delim LIBXML2_INC!$LIBXML2_INC$ac_delim +USE_OPENSSL!$USE_OPENSSL$ac_delim CXXCPP!$CXXCPP$ac_delim HAVE_PTHREAD!$HAVE_PTHREAD$ac_delim HAVE_LIBZ!$HAVE_LIBZ$ac_delim +HAVE_OPENSSL!$HAVE_OPENSSL$ac_delim HUGE_VAL_SANITY!$HUGE_VAL_SANITY$ac_delim MMAP_FILE!$MMAP_FILE$ac_delim SHLIBEXT!$SHLIBEXT$ac_delim @@ -23158,8 +23454,6 @@ LLVM_MANDIR!$LLVM_MANDIR$ac_delim LLVM_CONFIGTIME!$LLVM_CONFIGTIME$ac_delim BINDINGS_TO_BUILD!$BINDINGS_TO_BUILD$ac_delim -ALL_BINDINGS!$ALL_BINDINGS$ac_delim -OCAML_LIBDIR!$OCAML_LIBDIR$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -23201,6 +23495,8 @@ ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +ALL_BINDINGS!$ALL_BINDINGS$ac_delim +OCAML_LIBDIR!$OCAML_LIBDIR$ac_delim ENABLE_VISIBILITY_INLINES_HIDDEN!$ENABLE_VISIBILITY_INLINES_HIDDEN$ac_delim RPATH!$RPATH$ac_delim RDYNAMIC!$RDYNAMIC$ac_delim @@ -23209,7 +23505,7 @@ LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 6; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 8; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 Index: include/llvm/CodeGen/CommandFlags.h =================================================================== --- include/llvm/CodeGen/CommandFlags.h +++ include/llvm/CodeGen/CommandFlags.h @@ -210,4 +210,9 @@ cl::value_desc("pass-name"), cl::init("")); +cl::opt +NOPInsertion("nop-insertion", + cl::desc("Randomly add NOPs."), + cl::init(false)); + #endif Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -64,7 +64,8 @@ FrameSetup = 1 << 0, // Instruction is used as a part of // function frame setup code. BundledPred = 1 << 1, // Instruction has bundled predecessors. - BundledSucc = 1 << 2 // Instruction has bundled successors. + BundledSucc = 1 << 2, // Instruction has bundled successors. + InsertedNOP = 1 << 3 }; private: const MCInstrDesc *MCID; // Instruction descriptor. @@ -709,6 +710,12 @@ } } + /// isInsertedNOP - Return true if the instruction is an + /// artificially inserted NOP + bool isInsertedNOP() const { + return getFlag(InsertedNOP); + } + /// Return the number of instructions inside the MI bundle, excluding the /// bundle header. /// Index: include/llvm/Config/config.h.cmake =================================================================== --- include/llvm/Config/config.h.cmake +++ include/llvm/Config/config.h.cmake @@ -438,6 +438,12 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H} +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_AES_H ${HAVE_OPENSSL_AES_H} + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_EVP_H ${HAVE_OPENSSL_EVP_H} + /* Have host's _alloca */ #cmakedefine HAVE__ALLOCA ${HAVE__ALLOCA} @@ -650,6 +656,9 @@ /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME +/* Define if use the openssl libcrypto library */ +#cmakedefine USE_OPENSSL ${USE_OPENSSL} + /* Define if use udis86 library */ #undef USE_UDIS86 Index: include/llvm/Config/config.h.in =================================================================== --- include/llvm/Config/config.h.in +++ include/llvm/Config/config.h.in @@ -202,6 +202,9 @@ /* Set to 1 if the isnan function is found in */ #undef HAVE_ISNAN_IN_MATH_H +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + /* Define if you have the libdl library or equivalent. */ #undef HAVE_LIBDL @@ -297,6 +300,12 @@ /* Define to 1 if you have the `opendir' function. */ #undef HAVE_OPENDIR +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_AES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_EVP_H + /* Define to 1 if you have the `posix_spawn' function. */ #undef HAVE_POSIX_SPAWN @@ -685,6 +694,9 @@ /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME +/* Define if use the openssl libcrypto library */ +#undef USE_OPENSSL + /* Define if use udis86 library */ #undef USE_UDIS86 Index: include/llvm/MC/MCRegisterInfo.h =================================================================== --- include/llvm/MC/MCRegisterInfo.h +++ include/llvm/MC/MCRegisterInfo.h @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/RandomNumberGenerator.h" #include namespace llvm { Index: include/llvm/Support/RandomNumberGenerator.h =================================================================== --- /dev/null +++ include/llvm/Support/RandomNumberGenerator.h @@ -0,0 +1,114 @@ +//==- llvm/Support/RandomNumberGenerator.h - RNG for diversity ---*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Random Number Generator interface. If OpenSSL +// is available, this RNG is crypto-secure. Otherwise, a fallback, +// insecure RNG is available, which should not be used for any +// security purposes. +// +//===----------------------------------------------------------------------===// + +#ifndef RANDOMNUMBERGENERATOR_H_ +#define RANDOMNUMBERGENERATOR_H_ + +#include "llvm/Config/config.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/ThreadLocal.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +#if HAVE_OPENSSL_AES_H +#include +#endif + +namespace llvm { + +class StringRef; + +/// Random number generator based on either the AES block cipher from +/// openssl or an integrated linear congruential generator. DO NOT use +/// the LCG for any security application. +class RandomNumberGenerator { +protected: + RandomNumberGenerator() {}; + + // Noncopyable. + RandomNumberGenerator(const RandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + RandomNumberGenerator &operator=(const RandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + + virtual ~RandomNumberGenerator() {}; + + virtual void Reseed(StringRef Password, uint64_t Salt) = 0; + +public: + /// Initialized by the frontend. Should contain unique, + /// deterministic data. Currently initialized to command-line + /// paramater string, without any randomly generated arguments. + static std::string EntropyData; + + virtual uint64_t Random() = 0; + + static RandomNumberGenerator *Generator(); + + /// \brief Returns a random number in the range [0, Max) + /// + /// Uses sampling to make sure that the result is not biased because + /// Max does not divide evenly into 2^64 + uint64_t Random(uint64_t Max) { + uint64_t t = Max * (((uint64_t)1 << 63) / Max); + uint64_t r; + while ((r = Random()) >= t) { /* NOOP */ } + + return r % Max; + } + + /// \brief Shuffles an *array* of type T. + /// + /// Uses the Durstenfeld version of the Fisher-Yates method (aka the Knuth + /// method). See http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle + template + void shuffle(T* array, size_t length) { + for (size_t i = length - 1; i > 0; i--) { + size_t j = Random(i + 1); + if (j < i) + std::swap(array[j], array[i]); + } + } + + /// \brief Shuffles a SmallVector of type T, default size N + template + void shuffle(SmallVector& sv) { + if (sv.empty()) return; + for (size_t i = sv.size() - 1; i > 0; i--) { + size_t j = Random(i + 1); + if (j < i) + std::swap(sv[j], sv[i]); + } + } + + /// \brief Shuffles an iplist of type T + template + void shuffle(iplist& list){ + if (list.empty()) return; + SmallVector sv(list.begin(), list.end()); + shuffle(sv); + list.clear(); + for (typename SmallVector::size_type i = 0; i < sv.size(); i++) { + list.push_back(sv[i]); + } + } + +}; + +} + +#endif Index: include/llvm/Target/TargetOptions.h =================================================================== --- include/llvm/Target/TargetOptions.h +++ include/llvm/Target/TargetOptions.h @@ -50,8 +50,9 @@ GuaranteedTailCallOpt(false), DisableTailCalls(false), StackAlignmentOverride(0), EnableFastISel(false), PositionIndependentExecutable(false), - EnableSegmentedStacks(false), UseInitArray(false), TrapFuncName(""), - FloatABIType(FloatABI::Default), AllowFPOpFusion(FPOpFusion::Standard) + EnableSegmentedStacks(false), NOPInsertion(false), UseInitArray(false), + TrapFuncName(""), FloatABIType(FloatABI::Default), + AllowFPOpFusion(FPOpFusion::Standard) {} /// PrintMachineCode - This flag is enabled when the -print-machineinstrs @@ -154,6 +155,9 @@ unsigned EnableSegmentedStacks : 1; + /// Attempt to insert NOPs + unsigned NOPInsertion : 1; + /// UseInitArray - Use .init_array instead of .ctors for static /// constructors. unsigned UseInitArray : 1; Index: lib/CodeGen/LLVMBuild.txt =================================================================== --- lib/CodeGen/LLVMBuild.txt +++ lib/CodeGen/LLVMBuild.txt @@ -22,4 +22,4 @@ type = Library name = CodeGen parent = Libraries -required_libraries = Analysis Core MC Scalar Support Target TransformUtils ObjCARC +required_libraries = Analysis Core Instrumentation MC Scalar Support Target TransformUtils ObjCARC Index: lib/CodeGen/MachineBasicBlock.cpp =================================================================== --- lib/CodeGen/MachineBasicBlock.cpp +++ lib/CodeGen/MachineBasicBlock.cpp @@ -171,7 +171,7 @@ MachineBasicBlock::iterator MachineBasicBlock::getFirstTerminator() { iterator B = begin(), E = end(), I = E; - while (I != B && ((--I)->isTerminator() || I->isDebugValue())) + while (I != B && ((--I)->isTerminator() || I->isDebugValue() || I->isInsertedNOP())) ; /*noop */ while (I != E && !I->isTerminator()) ++I; @@ -181,7 +181,7 @@ MachineBasicBlock::const_iterator MachineBasicBlock::getFirstTerminator() const { const_iterator B = begin(), E = end(), I = E; - while (I != B && ((--I)->isTerminator() || I->isDebugValue())) + while (I != B && ((--I)->isTerminator() || I->isDebugValue() || I->isInsertedNOP())) ; /*noop */ while (I != E && !I->isTerminator()) ++I; @@ -190,7 +190,7 @@ MachineBasicBlock::instr_iterator MachineBasicBlock::getFirstInstrTerminator() { instr_iterator B = instr_begin(), E = instr_end(), I = E; - while (I != B && ((--I)->isTerminator() || I->isDebugValue())) + while (I != B && ((--I)->isTerminator() || I->isDebugValue() || I->isInsertedNOP())) ; /*noop */ while (I != E && !I->isTerminator()) ++I; Index: lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp =================================================================== --- lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp +++ lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp @@ -28,6 +28,7 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" @@ -103,6 +104,17 @@ "sched-avg-ipc", cl::Hidden, cl::init(1), cl::desc("Average inst/cycle whan no target itinerary exists.")); +static cl::opt RandomizeSchedule( + "sched-randomize", + cl::desc("Enable randomization of scheduling"), + cl::init(false)); + +static cl::opt SchedRandPercentage( + "sched-randomize-percentage", + cl::desc("Percentage of instructions where schedule is randomized"), + cl::init(50)); + + namespace { //===----------------------------------------------------------------------===// /// ScheduleDAGRRList - The actual register reduction list scheduler @@ -1765,6 +1777,17 @@ class RegReductionPriorityQueue : public RegReductionPQBase { SF Picker; + static SUnit *popRandom(std::vector &Q) { + RandomNumberGenerator *randGen = + RandomNumberGenerator::Generator(); + size_t randIndex = randGen->Random(Q.size()); + SUnit *V = Q[randIndex]; + if (randIndex < Q.size() - 1) + std::swap(Q[randIndex], Q.back()); + Q.pop_back(); + return V; + } + public: RegReductionPriorityQueue(MachineFunction &mf, bool tracksrp, @@ -1785,7 +1808,19 @@ SUnit *pop() { if (Queue.empty()) return NULL; - SUnit *V = popFromQueue(Queue, Picker, scheduleDAG); + SUnit *V; + if (RandomizeSchedule) { + RandomNumberGenerator *randGen = + RandomNumberGenerator::Generator(); + unsigned int Roll = randGen->Random(100); + if (Roll < SchedRandPercentage) { + V = popRandom(Queue); + } else { + V = popFromQueue(Queue, Picker, scheduleDAG); + } + } else { + V = popFromQueue(Queue, Picker, scheduleDAG); + } V->NodeQueueId = 0; return V; } Index: lib/LTO/LTOCodeGenerator.cpp =================================================================== --- lib/LTO/LTOCodeGenerator.cpp +++ lib/LTO/LTOCodeGenerator.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -410,7 +411,20 @@ Module *mergedModule = Linker.getModule(); - // Mark which symbols can not be internalized + // if options were requested, set them + if ( !CodegenOptions.empty() ) + cl::ParseCommandLineOptions(CodegenOptions.size(), + const_cast(&CodegenOptions[0])); + + // Seed the RNG with command line paramaters + std::string SeedData; + for (std::vector::iterator I = CodegenOptions.begin(), + E = CodegenOptions.end(); I != E; ++I) { + SeedData += *I; + } + RandomNumberGenerator::EntropyData = SeedData; + + // mark which symbols can not be internalized this->applyScopeRestrictions(); // Instantiate the pass manager to organize the passes. Index: lib/LTO/LTOModule.cpp =================================================================== --- lib/LTO/LTOModule.cpp +++ lib/LTO/LTOModule.cpp @@ -33,11 +33,13 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" #include "llvm/Target/TargetRegisterInfo.h" + using namespace llvm; LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t) @@ -94,6 +96,7 @@ errMsg = ec.message(); return NULL; } + RandomNumberGenerator::EntropyData.append(path); return makeLTOModule(buffer.take(), options, errMsg); } @@ -114,6 +117,7 @@ errMsg = ec.message(); return NULL; } + RandomNumberGenerator::EntropyData.append(path); return makeLTOModule(buffer.take(), options, errMsg); } Index: lib/Support/CMakeLists.txt =================================================================== --- lib/Support/CMakeLists.txt +++ lib/Support/CMakeLists.txt @@ -38,6 +38,7 @@ MD5.cpp PluginLoader.cpp PrettyStackTrace.cpp + RandomNumberGenerator.cpp Regex.cpp SmallPtrSet.cpp SmallVector.cpp Index: lib/Support/RandomNumberGenerator.cpp =================================================================== --- /dev/null +++ lib/Support/RandomNumberGenerator.cpp @@ -0,0 +1,228 @@ +//===-- RandomNumberGenerator.cpp - Implement RNG class -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements cryptographically secure random number generation +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "rng" +#include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/raw_ostream.h" +#if HAVE_OPENSSL_AES_H && HAVE_OPENSSL_EVP_H +#include +#include +#endif + +using namespace llvm; + +// Only read by threads, so no locking +std::string RandomNumberGenerator::EntropyData; + +static cl::opt +RandomSeed("rng-seed", cl::value_desc("seed"), + cl::desc("Seed for the random number generator"), + cl::init(0)); + +static cl::opt +EntropyDataOpt("entropy-data", + cl::desc("Entropy data for the RNG (testing only, should be set " + "by command line options"), + cl::Hidden, cl::location(RandomNumberGenerator::EntropyData)); + +static ManagedStatic > Instance; +static unsigned InstanceCount = 0; + +namespace { + +#if USE_OPENSSL + +static sys::SmartMutex *OpenSSLMutexes; + +static void OpenSSLLockingFunction(int mode, int n, const char* file, int line) { + if (mode & CRYPTO_LOCK) + OpenSSLMutexes[n].acquire(); + else + OpenSSLMutexes[n].release(); +} + +/// Returns a unique id for each thread +static unsigned long OpenSSLThreadIDFunction() { + // Since Instance is a thread-local, the address returned will be + // different for each thread + return (unsigned long) Instance->get(); +} + +static ManagedStatic > InstanceCountMutex; + +#define AES_KEY_LENGTH 16 // bytes +#define AES_BLOCK_SIZE 16 +#define PBKDF_ITERATIONS 1000 + +/// This RNG is an implementation of the standard NIST SP 800-90A +/// CTR_DRBG random number generator, with AES128 as the block +/// cipher. In addition, the initial seed and additional entropy from +/// the list of command-line arguments are ran through a standard +/// PBKDF2 key stretching algorithm to produce enough bits to +/// initialize the RNG. +class OpenSSLRandomNumberGenerator : public RandomNumberGenerator { +private: + unsigned char IV[AES_BLOCK_SIZE]; + AES_KEY AESKey; + unsigned char Key[AES_KEY_LENGTH]; + unsigned char EcountBuffer[AES_BLOCK_SIZE]; + unsigned int Num; + unsigned char Plaintext[AES_KEY_LENGTH]; + + // Noncopyable. + OpenSSLRandomNumberGenerator(const OpenSSLRandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + OpenSSLRandomNumberGenerator &operator=(const OpenSSLRandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + + // Set up OpenSSL to be thread-safe + void InitializeGlobals() { + // create enough mutexes for OpenSSL + // CRYPTO_num_locks() returns the maximum number of locks which + // will be required + OpenSSLMutexes = new sys::SmartMutex[CRYPTO_num_locks()]; + + // set up callbacks which OpenSSL needs to provide thread-safety + CRYPTO_set_locking_callback(OpenSSLLockingFunction); + CRYPTO_set_id_callback(OpenSSLThreadIDFunction); + } + + void Reseed(StringRef Entropy, uint64_t Seed) { + DEBUG(dbgs() << "Re-Seeding AES RNG context from entropy and seed\n"); + DEBUG(dbgs() << "Entropy: " << Entropy << "\n"); + DEBUG(dbgs() << "Seed: " << Seed << "\n"); + + unsigned KeyLen = AES_KEY_LENGTH + 2*AES_BLOCK_SIZE; + unsigned char *SeedBuffer = new unsigned char[KeyLen]; + + // Hash entropy with seed into SeedBuffer to get more bytes to + // initialize the AES construction + PKCS5_PBKDF2_HMAC_SHA1((char*)&Seed, sizeof(Seed), + (unsigned char*)Entropy.data(), Entropy.size(), PBKDF_ITERATIONS, + KeyLen, SeedBuffer); + + memcpy(Key, SeedBuffer, AES_KEY_LENGTH); + AES_set_encrypt_key(Key, AES_KEY_LENGTH*8, &AESKey); + memcpy(IV, SeedBuffer + AES_KEY_LENGTH, AES_BLOCK_SIZE); + memcpy(Plaintext, SeedBuffer + AES_KEY_LENGTH + AES_BLOCK_SIZE, + AES_BLOCK_SIZE); + memset(EcountBuffer, 0, AES_BLOCK_SIZE); + Num = 0; + + delete[] SeedBuffer; + } + +public: + OpenSSLRandomNumberGenerator() { + InstanceCountMutex->acquire(); + + if (InstanceCount == 0) + InitializeGlobals(); + + // Make sure each thread is seeded with a different seed + unsigned InstanceID = InstanceCount++; + + InstanceCountMutex->release(); + + if (RandomSeed != 0 && !EntropyData.empty()) { + Reseed(EntropyData, RandomSeed+InstanceID); + } else { + DEBUG(errs() << "Warning! Using unseeded random number generator\n"); + Reseed("", 0); + } + } + + uint64_t Random() { + unsigned char Output[AES_BLOCK_SIZE]; + AES_ctr128_encrypt(Plaintext, Output, AES_BLOCK_SIZE, &AESKey, IV, + EcountBuffer, &Num); + + uint64_t OutValue; + memcpy(&OutValue, Output, sizeof(uint64_t)); + return OutValue; + } +}; + +#else // not USE_OPENSSL + +/// This is a simple, insecure 32-bit linear-congruential +/// generator. DO NOT USE for security purposes, since the output is +/// easily predictable. +class LCGRandomNumberGenerator : public RandomNumberGenerator { +private: + uint64_t state; + + static const uint64_t LOW = 0x330e; + static const uint64_t A = 0x5deece66dULL; + static const uint64_t C = 0xb; + static const uint64_t M = 0x0000ffffffffffffULL; + + // Noncopyable. + LCGRandomNumberGenerator(const LCGRandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + LCGRandomNumberGenerator &operator=(const LCGRandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + + void Reseed(StringRef Entropy, uint64_t Seed) { + state = (Seed << 16) | LOW; + } + +public: + LCGRandomNumberGenerator() { + if (RandomSeed != 0 && !EntropyData.empty()) { + unsigned ThreadID = sys::AtomicIncrement(&InstanceCount); + Reseed(EntropyData, RandomSeed+ThreadID); + } else { + DEBUG(errs() << "Warning! Using unseeded random number generator\n"); + Reseed("", 0); + } + } + + uint64_t Random() { + uint64_t result; + + // need to run two iterations of the RNG, because it only + // generates 32-bits of randomness + state = (A * state + C) & M; + result = (state >> 17) & 0xffffffff; + + state = (A * state + C) & M; + result &= ((state >> 17) & 0xffffffff) << 32; + + return result; + } +}; + +#endif + +} + +RandomNumberGenerator *RandomNumberGenerator::Generator() { + RandomNumberGenerator *RNG = const_cast(Instance->get()); + if (RNG == 0) { + +#if USE_OPENSSL + RNG = new OpenSSLRandomNumberGenerator; +#else + RNG = new LCGRandomNumberGenerator; +#endif + + Instance->set(RNG); + } + + return RNG; +} Index: lib/Target/X86/CMakeLists.txt =================================================================== --- lib/Target/X86/CMakeLists.txt +++ lib/Target/X86/CMakeLists.txt @@ -13,6 +13,7 @@ add_public_tablegen_target(X86CommonTableGen) set(sources + NOPInsertion.cpp X86AsmPrinter.cpp X86COFFMachineModuleInfo.cpp X86CodeEmitter.cpp Index: lib/Target/X86/NOPInsertion.cpp =================================================================== --- /dev/null +++ lib/Target/X86/NOPInsertion.cpp @@ -0,0 +1,139 @@ +//===- NOPInsertion.cpp - Insert NOPs between instructions ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the NOPInsertion pass. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "nop-insertion" +#include "X86InstrBuilder.h" +#include "X86InstrInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +static cl::opt +NOPInsertionPercentage( + "nop-insertion-percentage", + cl::desc("Percentage of instructions that have NOPs prepended"), + cl::init(50)); + +static cl::opt +MaxNOPsPerInstruction( + "max-nops-per-instruction", + llvm::cl::desc("Maximum number of NOPs per instruction"), + llvm::cl::init(1)); + + +STATISTIC(InsertedNOPs, + "Total number of noop type instructions inserted for diversity"); + +namespace { +class NOPInsertionPass : public MachineFunctionPass { + + static char ID; + + bool is64Bit; + +public: + NOPInsertionPass(bool is64Bit_) : + MachineFunctionPass(ID), is64Bit(is64Bit_) { + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "NOP insertion pass"; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } +}; +} + +char NOPInsertionPass::ID = 0; + +enum { NOP, + MOV_EBP, MOV_ESP, + LEA_ESI, LEA_EDI, + MAX_NOPS }; + +static const unsigned nopRegs[MAX_NOPS][2] = { + { 0, 0 }, + { X86::EBP, X86::RBP }, + { X86::ESP, X86::RSP }, + { X86::ESI, X86::RSI }, + { X86::EDI, X86::RDI }, +}; + +bool NOPInsertionPass::runOnMachineFunction(MachineFunction &Fn) { + const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); + for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { + for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { + MachineBasicBlock::iterator J = next(I); + if (I->isPseudo()) { + I = J; + continue; + } + for (unsigned int i = 0; i < MaxNOPsPerInstruction; i++) { + unsigned int Roll = RandomNumberGenerator::Generator()->Random(100); + if (Roll >= NOPInsertionPercentage) + continue; + + int NOPCode = RandomNumberGenerator::Generator()->Random(MAX_NOPS); + + MachineInstr *NewMI = NULL; + unsigned reg = nopRegs[NOPCode][!!is64Bit]; + switch (NOPCode) { + case NOP: + NewMI = BuildMI(*BB, I, I->getDebugLoc(), TII->get(X86::NOOP)); + break; + case MOV_EBP: + case MOV_ESP: { + unsigned opc = is64Bit ? X86::MOV64rr : X86::MOV32rr; + NewMI = BuildMI(*BB, I, I->getDebugLoc(), TII->get(opc), reg) + .addReg(reg); + break; + } + + case LEA_ESI: + case LEA_EDI: { + unsigned opc = is64Bit ? X86::LEA64r : X86::LEA32r; + NewMI = addRegOffset(BuildMI(*BB, I, I->getDebugLoc(), + TII->get(opc), reg), + reg, false, 0); + break; + } + } + + if (NewMI != NULL) { + ++InsertedNOPs; + NewMI->setFlag(MachineInstr::InsertedNOP); + } + } + I = J; + } + } + return true; +} + +FunctionPass *llvm::createNOPInsertionPass(bool is64Bit) { + return new NOPInsertionPass(is64Bit); +} Index: lib/Target/X86/X86.h =================================================================== --- lib/Target/X86/X86.h +++ lib/Target/X86/X86.h @@ -52,6 +52,10 @@ /// AVX and SSE. FunctionPass *createX86IssueVZeroUpperPass(); +/// createNOPInsertionPass - This pass adds NOPs at random between +/// instructions. +FunctionPass *createNOPInsertionPass(bool is64Bit); + /// createX86CodeEmitterPass - Return a pass that emits the collected X86 code /// to the specified MCE object. FunctionPass *createX86JITCodeEmitterPass(X86TargetMachine &TM, Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -223,6 +223,11 @@ ShouldPrint = true; } + if (TM->Options.NOPInsertion) { + addPass(createNOPInsertionPass(getX86Subtarget().is64Bit())); + ShouldPrint = true; + } + return ShouldPrint; } Index: test/CodeGen/X86/nop-insert-percentage.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/nop-insert-percentage.ll @@ -0,0 +1,47 @@ +; RUN: llc < %s -entropy-data="entropy" -rng-seed=1 -nop-insertion -nop-insertion-percentage=10 \ +; RUN: | FileCheck %s --check-prefix=PERCENT10 +; RUN: llc < %s -entropy-data="entropy" -rng-seed=1 -nop-insertion -nop-insertion-percentage=50 \ +; RUN: | FileCheck %s --check-prefix=PERCENT50 +; RUN: llc < %s -entropy-data="entropy" -rng-seed=1 -nop-insertion -nop-insertion-percentage=100 \ +; RUN: | FileCheck %s --check-prefix=PERCENT100 +; REQUIRES: openssl + +; This test case tests NOP insertion at varying percentage levels. + +define i32 @test(i32 %x, i32 %y, i32 %z) { +entry: + %t1 = add i32 %x, %y + %t2 = mul i32 %t1, %z + %t3 = add i32 %t2, %x + %t4 = mul i32 %t3, %z + %t5 = add i32 %t4, %x + %t6 = mul i32 %t5, %z + %t7 = add i32 %t6, %x + %t8 = mul i32 %t7, %z + %t9 = add i32 %t8, %x + %t10 = mul i32 %t9, %z + %t11 = add i32 %t10, %x + ret i32 %t11 +} + +; PERCENT10: nop + +; PERCENT50: nop +; PERCENT50: movq %rsp, %rsp +; PERCENT50: movq %rsp, %rsp +; PERCENT50: nop +; PERCENT50: leaq (%rdi), %rdi +; PERCENT50: nop + +; PERCENT100: nop +; PERCENT100: movq %rsp, %rsp +; PERCENT100: nop +; PERCENT100: leaq (%rdi), %rdi +; PERCENT100: nop +; PERCENT100: movq %rbp, %rbp +; PERCENT100: nop +; PERCENT100: leaq (%rdi), %rdi +; PERCENT100: nop +; PERCENT100: nop +; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: nop Index: test/CodeGen/X86/nop-insert.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/nop-insert.ll @@ -0,0 +1,33 @@ +; RUN: llc < %s -nop-insertion | FileCheck %s +; RUN: llc < %s -nop-insertion -entropy-data="test" -rng-seed=10 | FileCheck %s --check-prefix=SEED1 +; RUN: llc < %s -nop-insertion -entropy-data="test" -rng-seed=25 | FileCheck %s --check-prefix=SEED2 +; RUN: llc < %s -nop-insertion -entropy-data="test" -rng-seed=1534 | FileCheck %s --check-prefix=SEED3 +; RUN: llc < %s -nop-insertion -entropy-data="different entropy" -rng-seed=10 | FileCheck %s --check-prefix=ENTROPY +; REQUIRES: openssl + +; This test case checks that NOPs are inserted, and that the RNG seed +; affects both the placement and choice of these NOPs. + +; CHECK: leaq (%rsi), %rsi +; CHECK: leaq (%rdi), %rdi + +; SEED1: nop +; SEED1: movq %rbp, %rbp +; SEED1-NOT: leaq (%rsi), %rsi +; SEED1-NOT: leaq (%rdi), %rdi + +; SEED2: nop +; SEED2: movq %rsp, %rsp + +; SEED3: leaq (%rdi), %rdi + +; ENTROPY: nop +; ENTROPY: leaq (%rdi), %rdi +; ENTROPY-NOT: movq %rbp, %rbp + +define i32 @test1(i32 %x, i32 %y, i32 %z) { +entry: + %tmp = mul i32 %x, %y + %tmp2 = add i32 %tmp, %z + ret i32 %tmp2 +} Index: test/CodeGen/X86/sched-rnd-test.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/sched-rnd-test.ll @@ -0,0 +1,37 @@ +; RUN: llc < %s -entropy-data="entropy" -rng-seed=1 -sched-randomize -sched-randomize-percentage=100 | FileCheck %s --check-prefix=SEED1 +; RUN: llc < %s -entropy-data="entropy" -rng-seed=2 -sched-randomize -sched-randomize-percentage=100 | FileCheck %s --check-prefix=SEED2 +; RUN: llc < %s -entropy-data="entropy" -rng-seed=2 -sched-randomize -sched-randomize-percentage=50 | FileCheck %s --check-prefix=PERCENTAGE +; REQUIRES: openssl + +; This test case checks that the schedule randomization is changing +; scheduling decisions, that different seeds result in different +; schedules, and that the percentage alters the amount of +; randomization + +define i32 @test(i32 %x, i32 %y, i32 %z) { +entry: + %a = add i32 %x, %y + %b = add i32 %x, %z + %c = add i32 %y, %z + %d = mul i32 %a, %b + %e = mul i32 %d, %c + ret i32 %e +} + +; SEED1: leal (%rdi,%rdx), %ecx +; SEED1-NEXT: leal (%rdi,%rsi), %eax +; SEED1-NEXT: imull %ecx, %eax +; SEED1-NEXT: addl %edx, %esi +; SEED1-NEXT: imull %esi, %eax + +; SEED2: leal (%rdi,%rdx), %ecx +; SEED2-NEXT: addl %esi, %edx +; SEED2-NEXT: leal (%rdi,%rsi), %eax +; SEED2-NEXT: imull %ecx, %eax +; SEED2-NEXT: imull %edx, %eax + +; PERCENTAGE: leal (%rdi,%rsi), %eax +; PERCENTAGE-NEXT: addl %edx, %edi +; PERCENTAGE-NEXT: imull %edi, %eax +; PERCENTAGE-NEXT: addl %edx, %esi +; PERCENTAGE-NEXT: imull %esi, %eax Index: test/Makefile =================================================================== --- test/Makefile +++ test/Makefile @@ -134,6 +134,7 @@ @$(ECHOPATH) s=@HOST_OS@=$(HOST_OS)=g >> lit.tmp @$(ECHOPATH) s=@HOST_ARCH@=$(HOST_ARCH)=g >> lit.tmp @$(ECHOPATH) s=@HAVE_LIBZ@=$(HAVE_LIBZ)=g >> lit.tmp + @$(ECHOPATH) s=@USE_OPENSSL@=$(USE_OPENSSL)=g >> lit.tmp @sed -f lit.tmp $(PROJ_SRC_DIR)/lit.site.cfg.in > $@ @-rm -f lit.tmp Index: test/lit.cfg =================================================================== --- test/lit.cfg +++ test/lit.cfg @@ -281,6 +281,9 @@ if config.have_zlib == "1": config.available_features.add("zlib") +if config.use_openssl == "1": + config.available_features.add("openssl") + # Native compilation: host arch == target arch if config.host_arch in config.target_triple: config.available_features.add("native") Index: test/lit.site.cfg.in =================================================================== --- test/lit.site.cfg.in +++ test/lit.site.cfg.in @@ -21,6 +21,7 @@ config.llvm_use_intel_jitevents = "@LLVM_USE_INTEL_JITEVENTS@" config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.have_zlib = "@HAVE_LIBZ@" +config.use_openssl = "@USE_OPENSSL@" # Support substitution of the tools_dir with user parameters. This is # used when we can't determine the tool dir at configuration time. Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" @@ -191,6 +192,16 @@ cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + // Seed the RNG + // If entropy already set (for predictable testing), ignore + if (RandomNumberGenerator::EntropyData.empty()) { + std::string SeedData; + for (int i = 0; i < argc; ++i) { + SeedData += argv[i]; + } + RandomNumberGenerator::EntropyData = SeedData; + } + // Compile the module TimeCompilations times to give better compile time // metrics. for (unsigned I = TimeCompilations; I; --I) @@ -279,6 +290,7 @@ Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; + Options.NOPInsertion = NOPInsertion; OwningPtr target(TheTarget->createTargetMachine(TheTriple.getTriple(), Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" @@ -523,6 +524,7 @@ Options.PositionIndependentExecutable = EnablePIE; Options.EnableSegmentedStacks = SegmentedStacks; Options.UseInitArray = UseInitArray; + Options.NOPInsertion = NOPInsertion; return Options; } @@ -595,6 +597,16 @@ cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); + // Seed the RNG + std::string SeedData; + // If entropy already set (for predictable testing), ignore + if (RandomNumberGenerator::EntropyData.empty()) { + for (int i = 0; i < argc; ++i) { + SeedData += argv[i]; + } + RandomNumberGenerator::EntropyData = SeedData; + } + if (AnalyzeOnly && NoOutput) { errs() << argv[0] << ": analyze mode conflicts with no-output mode.\n"; return 1;