Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -166,6 +166,10 @@ option(LLVM_ENABLE_ZLIB "Use zlib for compression/decompression if available." ON) +option(LLVM_ENABLE_RNG "Enable random number generation." 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 @@ -1121,6 +1121,23 @@ withval="") AC_SUBST(INTERNAL_PREFIX,[$withval]) +dnl Enable random number generation using openssl (or fallback to a LCG) +AC_ARG_ENABLE(rng, + AS_HELP_STRING([--enable-rng], + [Enable random number generation (default is + YES)]),, + enableval=default) +case "$enableval" in + yes) AC_SUBST(LLVM_ENABLE_RNG,[1]) ;; + no) AC_SUBST(LLVM_ENABLE_RNG,[0]) ;; + default) AC_SUBST(LLVM_ENABLE_RNG,[1]) ;; + *) AC_MSG_ERROR([Invalid setting for --enable-rng. Use "yes" or "no"]) ;; +esac +AC_DEFINE_UNQUOTED([LLVM_ENABLE_RNG],$LLVM_ENABLE_RNG, + [Define if RNG is enabled]) + + + dnl===-----------------------------------------------------------------------=== dnl=== dnl=== SECTION 4: Check for programs we need and that they are the right version @@ -1553,6 +1570,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 +1627,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_ENABLE_RNG AND 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 ( LLVM_ENABLE_RNG AND 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 @@ -720,6 +720,7 @@ CLANG_SRC_ROOT BINUTILS_INCDIR INTERNAL_PREFIX +LLVM_ENABLE_RNG NM ifGNUmake LN_S @@ -777,9 +778,11 @@ XML2CONFIG LIBXML2_LIBS LIBXML2_INC +USE_OPENSSL CXXCPP HAVE_PTHREAD HAVE_LIBZ +HAVE_OPENSSL HUGE_VAL_SANITY MMAP_FILE SHLIBEXT @@ -1457,6 +1460,7 @@ --enable-terminfo Query the terminfo database if available (default is YES) --enable-libffi Check for the presence of libffi (default is NO) + --enable-rng Enable random number generation (default is YES) --enable-ltdl-install install libltdl Optional Packages: @@ -1487,6 +1491,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 @@ -6070,6 +6075,32 @@ INTERNAL_PREFIX=$withval +# Check whether --enable-rng was given. +if test "${enable_rng+set}" = set; then + enableval=$enable_rng; +else + enableval=default +fi + +case "$enableval" in + yes) LLVM_ENABLE_RNG=1 + ;; + no) LLVM_ENABLE_RNG=0 + ;; + default) LLVM_ENABLE_RNG=1 + ;; + *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-rng. Use \"yes\" or \"no\"" >&5 +echo "$as_me: error: Invalid setting for --enable-rng. Use \"yes\" or \"no\"" >&2;} + { (exit 1); exit 1; }; } ;; +esac + +cat >>confdefs.h <<_ACEOF +#define LLVM_ENABLE_RNG $LLVM_ENABLE_RNG +_ACEOF + + + + { echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6; } @@ -10586,7 +10617,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 +16709,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 @@ -23084,6 +23405,7 @@ CLANG_SRC_ROOT!$CLANG_SRC_ROOT$ac_delim BINUTILS_INCDIR!$BINUTILS_INCDIR$ac_delim INTERNAL_PREFIX!$INTERNAL_PREFIX$ac_delim +LLVM_ENABLE_RNG!$LLVM_ENABLE_RNG$ac_delim NM!$NM$ac_delim ifGNUmake!$ifGNUmake$ac_delim LN_S!$LN_S$ac_delim @@ -23141,9 +23463,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 @@ -23157,9 +23481,6 @@ LLVM_INFODIR!$LLVM_INFODIR$ac_delim 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 +23522,9 @@ ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +BINDINGS_TO_BUILD!$BINDINGS_TO_BUILD$ac_delim +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 +23533,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` = 9; 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} @@ -507,6 +513,9 @@ /* Installation directory for documentation */ #cmakedefine LLVM_DOCSDIR "${LLVM_DOCSDIR}" +/* Define if RNG is enabled */ +#cmakedefine01 LLVM_ENABLE_RNG + /* Define if threads enabled */ #cmakedefine01 LLVM_ENABLE_THREADS @@ -650,6 +659,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 @@ -542,6 +551,9 @@ /* Installation directory for documentation */ #undef LLVM_DOCSDIR +/* Define if RNG is enabled */ +#undef LLVM_ENABLE_RNG + /* Define if threads enabled */ #undef LLVM_ENABLE_THREADS @@ -685,6 +697,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,120 @@ +#ifndef RANDOMNUMBERGENERATOR_H_ +#define RANDOMNUMBERGENERATOR_H_ + +#include +#include +#include +#include +#include + +#if HAVE_OPENSSL_AES_H +#include +#endif + +#define AES_KEY_LENGTH 16 // bytes +#define AES_BLOCK_SIZE 16 +#define PBKDF_ITERATIONS 1000 + +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 { +private: + /** Imports state file from disk */ + void ReadStateFile(StringRef StateFilename); + + /** Writes current RNG state to disk */ + void WriteStateFile(StringRef StateFilename); + + RandomNumberGenerator(); + RandomNumberGenerator(RandomNumberGenerator const&); + RandomNumberGenerator& operator=(RandomNumberGenerator const&) { + return *this; + } + + void Reseed(StringRef Password, uint64_t Salt); + + // Internal state +#if USE_OPENSSL + 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]; +#else + uint64_t state; +#endif + +public: + static std::string EntropyData; + + uint64_t Random(); + uint64_t Random(uint64_t Max); + + static RandomNumberGenerator& Generator() { + static RandomNumberGenerator instance; + return instance; + }; + + ~RandomNumberGenerator(); + + /** + * 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]); + } + } + + /** + * 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]); + } + } + + /** + * Shuffles an iplist of type T + */ + template + void shuffle(iplist& list){ + if(list.empty()) return; + SmallVector sv; + for(typename iplist::iterator i = list.begin(); i != list.end(); ){ + /* iplist::remove() actually increments the iterator, so the + * for loop shouldn't increment it either. + */ + T* t = list.remove(i); + sv.push_back(t); + } + shuffle(sv); + 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,19 @@ "sched-avg-ipc", cl::Hidden, cl::init(1), cl::desc("Average inst/cycle whan no target itinerary exists.")); +#if LLVM_ENABLE_RNG +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)); +#endif + + namespace { //===----------------------------------------------------------------------===// /// ScheduleDAGRRList - The actual register reduction list scheduler @@ -1765,6 +1779,19 @@ class RegReductionPriorityQueue : public RegReductionPQBase { SF Picker; +#if LLVM_ENABLE_RNG + 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; + } +#endif + public: RegReductionPriorityQueue(MachineFunction &mf, bool tracksrp, @@ -1785,7 +1812,23 @@ SUnit *pop() { if (Queue.empty()) return NULL; - SUnit *V = popFromQueue(Queue, Picker, scheduleDAG); + SUnit *V; +#if LLVM_ENABLE_RNG + 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 { +#endif + V = popFromQueue(Queue, Picker, scheduleDAG); +#if LLVM_ENABLE_RNG + } +#endif 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 + 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,271 @@ + +// +// 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/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Config/config.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include +#include +#include +#if LLVM_ENABLE_RNG == 1 && HAVE_OPENSSL_AES_H && HAVE_OPENSSL_EVP_H +#include +#include +#endif + +extern int errno; + +using namespace llvm; + +STATISTIC(RandomNumbersGenerated, "Number of random numbers generated"); + +// This is outside the ENABLE_RNG define since it needs to be set +// outside of LLVM, without knowledge of how LLVM was configured. +std::string RandomNumberGenerator::EntropyData; + +#if LLVM_ENABLE_RNG == 1 + +namespace { + static cl::opt + RandomSeed("rng-seed", cl::value_desc("seed"), + cl::desc("Seed for the random number generator")); + + static cl::opt + RNGStateFile("rng-state-file", cl::value_desc("filename"), + cl::desc("State filename for the random number generator")); + + static cl::opt + EntropyDataOpt("entropy-data", cl::desc("Entropy data for the random number generator (testing only, should be set by command line options"), cl::Hidden, cl::location(RandomNumberGenerator::EntropyData)); +} + + +RandomNumberGenerator::~RandomNumberGenerator() { + if (!RNGStateFile.empty()) { + WriteStateFile(RNGStateFile); + } +} + + +#if USE_OPENSSL + +RandomNumberGenerator::RandomNumberGenerator() { + DEBUG(errs() << "AES RNG: Initializing context "); + if (RandomSeed != 0 && !EntropyData.empty()) { + DEBUG(errs() << " with command line seed and entropy data\n"); + + // Seed properly + Reseed(EntropyData, RandomSeed); + + } else if(RNGStateFile != "") { + // Fall back on state file...if provided. + DEBUG(errs() << " with file\n"); + ReadStateFile(RNGStateFile); + } else{ + Reseed("", 0); + DEBUG(errs() << " to default\n"); + DEBUG(errs() << "Warning! Using unseeded random number generator\n"); + } +} + +void RandomNumberGenerator::Reseed(StringRef Password, uint64_t Salt) { + DEBUG(errs() << "Re-Seeding AES RNG context from salt and password\n"); + DEBUG(errs() << "Entropy: " << Password << "\n"); + DEBUG(errs() << "Seed: " << Salt << "\n"); + + unsigned KeyLen = AES_KEY_LENGTH + 2*AES_BLOCK_SIZE; + unsigned char *RandomBytes = (unsigned char*) malloc(KeyLen); + PKCS5_PBKDF2_HMAC_SHA1(Password.data(), Password.size(), (unsigned char*)&Salt, sizeof(Salt), PBKDF_ITERATIONS, KeyLen, RandomBytes); + + // TODO(sjcrane): check return val + memcpy(Key, RandomBytes, AES_KEY_LENGTH); + AES_set_encrypt_key(Key, AES_KEY_LENGTH*8, &AESKey); + memcpy(IV, RandomBytes + AES_KEY_LENGTH, AES_BLOCK_SIZE); + memcpy(Plaintext, RandomBytes + AES_KEY_LENGTH + AES_BLOCK_SIZE, AES_BLOCK_SIZE); + + free(RandomBytes); +} + +void RandomNumberGenerator::ReadStateFile(StringRef StateFilename) { + DEBUG(errs() << "Re-Seeding AES RNG context from state file\n"); + DEBUG(errs() << "File: " << StateFilename << "\n"); + + + struct stat s; + /* Don't read if there's no file specified. + * TODO(tmjackso): This probably shouldn't fail silently. */ + if (StateFilename.empty() || stat(StateFilename.data(), &s) != 0) { + return; + } + + int fhandle = open(StateFilename.data(), O_RDONLY); + int bytes_read = 0; + + uint16_t keylength; + unsigned char* KeyBytes[AES_KEY_LENGTH]; + + /* uint16_t: keysize */ + bytes_read += read(fhandle, (char *)&keylength, sizeof(uint16_t)); + assert(keylength == AES_KEY_LENGTH && "Invalid key length"); + + /* keylength * uint8_t: key */ + bytes_read += read(fhandle, (char *)Key, AES_KEY_LENGTH); + + /* 16 * uint8_t: plaintext */ + bytes_read += read(fhandle, (char *)Plaintext, AES_BLOCK_SIZE); + + /* 8 * uint8_t: IV (nonce+counter) */ + bytes_read += read(fhandle, (char *)IV, AES_BLOCK_SIZE); + + if (bytes_read != s.st_size) { + // We didn't read the whole file + errs() << "Warning: Did not read the entire state file!\n"; + } + + close(fhandle); + + // TODO(sjcrane): check return val + AES_set_encrypt_key(Key, AES_KEY_LENGTH*8, &AESKey); +} + +RandomNumberGenerator::RandomNumberGenerator(RandomNumberGenerator const& a) { + DEBUG(errs() << "Initialising AES RNG context from copy constructor\n"); + AESKey = a.AESKey; + memcpy(Key, a.Key, AES_KEY_LENGTH); + memcpy(IV, a.IV, AES_BLOCK_SIZE); + memcpy(EcountBuffer, a.EcountBuffer, AES_BLOCK_SIZE); + Num = a.Num; +} + +void RandomNumberGenerator::WriteStateFile(StringRef StateFilename) { + DEBUG(errs() << "Writing RNG state file to " << StateFilename << "\n"); + + /* Don't serialise without a file name */ + assert(!StateFilename.empty() && "Cannot serialize RNG state file without a filename"); + + uint16_t keylength = AES_KEY_LENGTH; + + int fhandle = open(StateFilename.data(), O_WRONLY); + int byte_count = 0; + byte_count += write(fhandle, (char *)&keylength, sizeof(uint16_t)); + byte_count += write(fhandle, (char *)Key, AES_KEY_LENGTH); + byte_count += write(fhandle, (char *)Plaintext, AES_BLOCK_SIZE); + byte_count += write(fhandle, (char *)IV, AES_BLOCK_SIZE); + close(fhandle); +} + +uint64_t RandomNumberGenerator::Random() { + RandomNumbersGenerated++; + + 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; +} + +uint64_t RandomNumberGenerator::Random(uint64_t Max) { + uint64_t t = Max * (((uint64_t)1 << 63) / Max); + uint64_t r; + while ((r = Random()) >= t) { /* NOOP */ } + + return r % Max; +} + +#else // do not use libcrypto + +namespace { + static const uint64_t LOW = 0x330e; + static const uint64_t A = 0x5deece66dULL; + static const uint64_t C = 0xb; + static const uint64_t M = 0x0000ffffffffffffULL; +} + +RandomNumberGenerator::RandomNumberGenerator() : state(0) { + DEBUG(errs() << "Fallback RNG: Initializing "); + if (RandomSeed != 0) { + // Seed properly + DEBUG(errs() << " with command line seed\n"); + + state = (RandomSeed << 16) | LOW; + } else if(RNGStateFile != "") { + DEBUG(errs() << " with state file\n"); + + // Fall back on state file...if provided. + ReadStateFile(RNGStateFile); + } else{ + DEBUG(errs() << "Warning! Using unseeded random number generator\n"); + } +} + +RandomNumberGenerator::RandomNumberGenerator(RandomNumberGenerator const& a) : state(0) { + state = a.state; +} + +void RandomNumberGenerator::ReadStateFile(StringRef StateFilename) { + struct stat s; + // Don't read if there's no file specified. + if (StateFilename.empty() || stat(StateFilename.data(), &s) != 0) { + return; + } + + int fhandle = open(StateFilename.data(), O_RDONLY); + int bytes_read = 0; + + + DEBUG(errs() << "Reading RNG state file from " << RNGStateFile << "\n"); + bytes_read += read(fhandle, &state, sizeof(uint64_t)); + + close(fhandle); +} + +void RandomNumberGenerator::WriteStateFile(StringRef StateFilename) { + /* Don't serialise without a file name */ + assert(!StateFilename.empty() && "Cannot serialize RNG state file without a filename"); + + + int fhandle = open(StateFilename.data(), O_WRONLY); + int byte_count = 0; + byte_count += write(fhandle, (char *)&state, sizeof(uint64_t)); + close(fhandle); +} + +/* This RNG only generates 32 bits of randomness, so we have to cast it down + * and then up + */ +uint64_t RandomNumberGenerator::Random() { + RandomNumbersGenerated++; + + state = (A * state + C) & M; + return static_cast(state >> 17); +} + +/* + * With only 32 bits of randomness, we do a proportional shift to ensure we + * get even distribution over the potential max. + */ +uint64_t RandomNumberGenerator::Random(uint64_t max) { + return (static_cast(Random()) / UINT32_MAX) * max; +} + +#endif // USE_OPENSSL + +#endif // LLVM_ENABLE_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,172 @@ +//===- NOPInsertion.cpp - Insert NOPs between instructions ---*- C++ -*-===// +// +// 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; + +#if LLVM_ENABLE_RNG + +namespace { + 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(PreNOPFunctionCount, "Pre-NOP insertion function count"); +STATISTIC(PreNOPBasicBlockCount, "Pre-NOP insertion basic block count"); +STATISTIC(PreNOPInstructionCount, "Pre-NOP insertion instruction count"); +STATISTIC(InsertedInstructions, "Total number of inserted instructions"); +STATISTIC(NumNOPInstructions, "Number of inserted NOP instructions"); +STATISTIC(NumMovEBPInstructions, "Number of inserted MOV EBP, EBP instructions"); +STATISTIC(NumMovESPInstructions, "Number of inserted MOV ESP, ESP instructions"); +STATISTIC(NumLeaESIInstructions, "Number of inserted LEA ESI, ESI instructions"); +STATISTIC(NumLeaEDIInstructions, "Number of inserted LEA EDI, EDI instructions"); + +namespace { +class NOPInsertionPass : public MachineFunctionPass { + + static char ID; + + bool is64Bit; + + void IncrementCounters(int const code); +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 }, +}; + +void NOPInsertionPass::IncrementCounters(int const code) { + ++InsertedInstructions; + switch(code) { + case NOP: ++NumNOPInstructions; break; + case MOV_EBP: ++NumMovEBPInstructions; break; + case MOV_ESP: ++NumMovESPInstructions; break; + case LEA_ESI: ++NumLeaESIInstructions; break; + case LEA_EDI: ++NumLeaEDIInstructions; break; + } +} + +bool NOPInsertionPass::runOnMachineFunction(MachineFunction &Fn) { + const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); + PreNOPFunctionCount++; + static int nopsInserted = 0; + for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { + PreNOPBasicBlockCount++; + PreNOPInstructionCount += BB->size(); + + 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)); + nopsInserted++; + 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); + nopsInserted++; + 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); + nopsInserted++; + break; + } + } + + if (NewMI != NULL) { + IncrementCounters(NOPCode); + NewMI->setFlag(MachineInstr::InsertedNOP); + } + } + I = J; + } + } + return true; +} + +FunctionPass *llvm::createNOPInsertionPass(bool is64Bit) { + return new NOPInsertionPass(is64Bit); +} + +#endif // LLVM_ENABLE_RNG 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,13 @@ ShouldPrint = true; } +#if LLVM_ENABLE_RNG + if (TM->Options.NOPInsertion) { + addPass(createNOPInsertionPass(getX86Subtarget().is64Bit())); + ShouldPrint = true; + } +#endif + return ShouldPrint; } Index: test/CodeGen/X86/nop-insert-percentage.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/nop-insert-percentage.ll @@ -0,0 +1,46 @@ +; 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: movq %rbp, %rbp + +; PERCENT50: leaq (%rdi), %rdi +; PERCENT50: movq %rsp, %rsp +; PERCENT50: movq %rbp, %rbp +; PERCENT50: leaq (%rsi), %rsi +; PERCENT50: nop + +; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: nop +; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: movq %rsp, %rsp +; PERCENT100: movq %rsp, %rsp +; PERCENT100: movq %rbp, %rbp +; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: movq %rsp, %rsp +; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: movq %rbp, %rbp +; PERCENT100: leaq (%rsi), %rsi Index: test/CodeGen/X86/nop-insert.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/nop-insert.ll @@ -0,0 +1,27 @@ +; 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: movq %rbp, %rbp +; SEED1: nop +; SEED1-NOT: movq %rbp, %rbp +; SEED2-NOT: nop +; SEED2-NOT: movq %rbp, %rbp +; SEED3: movq %rbp, %rbp +; SEED3: movq %rbp, %rbp +; SEED3: leaq (%rsi), %rsi +; SEED3-NOT: nop +; ENTROPY: movq %rbp, %rbp +; ENTROPY: nop +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=3 -sched-randomize -sched-randomize-percentage=100 | FileCheck %s --check-prefix=SEED2 +; RUN: llc < %s -entropy-data="entropy" -rng-seed=1 -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,%rsi), %eax +; SEED1-NEXT: addl %edx, %edi +; SEED1-NEXT: imull %edi, %eax +; SEED1-NEXT: addl %edx, %esi +; SEED1-NEXT: imull %esi, %eax + +; SEED2: leal (%rdi,%rdx), %ecx +; SEED2-NEXT: leal (%rdi,%rsi), %eax +; SEED2-NEXT: addl %edx, %esi +; SEED2-NEXT: imull %ecx, %eax +; SEED2-NEXT: imull %esi, %eax + +; PERCENTAGE: leal (%rdi,%rdx), %ecx +; PERCENTAGE-NEXT: leal (%rdi,%rsi), %eax +; PERCENTAGE-NEXT: imull %ecx, %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,13 @@ cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); + // Seed the RNG + std::string seeddata; + 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;