All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniele Buono <dbuono@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
	"Thomas Huth" <thuth@redhat.com>,
	"Daniel P . Berrangé" <berrange@redhat.com>,
	"Daniele Buono" <dbuono@linux.vnet.ibm.com>,
	"Alexander Bulekov" <alxndr@bu.edu>
Subject: [PATCH v2 3/6] configure: add option to enable LTO
Date: Fri, 23 Oct 2020 16:06:41 -0400	[thread overview]
Message-ID: <20201023200645.1055-4-dbuono@linux.vnet.ibm.com> (raw)
In-Reply-To: <20201023200645.1055-1-dbuono@linux.vnet.ibm.com>

This patch allows to compile QEMU with link-time optimization (LTO).
Compilation with LTO is handled directly by meson. This patch adds checks
in configure to make sure the toolchain supports LTO.

Currently, allow LTO only with clang, since I have found a couple of issues
with gcc-based LTO.

In case fuzzing is enabled, automatically switch to llvm's linker (lld).
The standard bfd linker has a bug where function wrapping (used by the fuzz*
targets) is used in conjunction with LTO.

Tested with all major versions of clang from 6 to 12

Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>
---
 configure   | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 meson.build |   1 +
 2 files changed, 129 insertions(+)

diff --git a/configure b/configure
index 9dc05cfb8a..e964040522 100755
--- a/configure
+++ b/configure
@@ -76,6 +76,7 @@ fi
 TMPB="qemu-conf"
 TMPC="${TMPDIR1}/${TMPB}.c"
 TMPO="${TMPDIR1}/${TMPB}.o"
+TMPA="${TMPDIR1}/lib${TMPB}.a"
 TMPCXX="${TMPDIR1}/${TMPB}.cxx"
 TMPE="${TMPDIR1}/${TMPB}.exe"
 TMPTXT="${TMPDIR1}/${TMPB}.txt"
@@ -180,6 +181,32 @@ compile_prog() {
       $LDFLAGS $CONFIGURE_LDFLAGS $QEMU_LDFLAGS $local_ldflags
 }
 
+do_run_filter() {
+    # Run a generic program, capturing its output to the log,
+    # but also filtering the output with grep.
+    # Returns the return value of grep.
+    # First argument is the filter string.
+    # Second argument is binary to execute.
+    local filter="$1"
+    local filter_pattern=""
+    if test "$filter" = "yes"; then
+      shift
+      filter_pattern="$1"
+    fi
+    shift
+    local program="$1"
+    shift
+    echo $program $@ >> config.log
+    $program $@ >> config.log 2>&1 || return $?
+    if test "$filter" = "yes"; then
+      $program $@ 2>&1 | grep "${filter_pattern}" >> /dev/null || return $?
+    fi
+}
+
+create_library() {
+  do_run_filter "no" "$ar" -rc${1} $TMPA $TMPO
+}
+
 # symbolically link $1 to $2.  Portable version of "ln -sf".
 symlink() {
   rm -rf "$2"
@@ -242,6 +269,7 @@ host_cc="cc"
 audio_win_int=""
 libs_qga=""
 debug_info="yes"
+lto="false"
 stack_protector=""
 safe_stack=""
 use_containers="yes"
@@ -1159,6 +1187,10 @@ for opt do
   ;;
   --disable-werror) werror="no"
   ;;
+  --enable-lto) lto="true"
+  ;;
+  --disable-lto) lto="false"
+  ;;
   --enable-stack-protector) stack_protector="yes"
   ;;
   --disable-stack-protector) stack_protector="no"
@@ -1735,6 +1767,8 @@ disabled with --disable-FEATURE, default is enabled if available:
   module-upgrades try to load modules from alternate paths for upgrades
   debug-tcg       TCG debugging (default is disabled)
   debug-info      debugging information
+  lto             Enable Link-Time Optimization.
+                  Depends on clang/llvm >=6.0
   sparse          sparse checker
   safe-stack      SafeStack Stack Smash Protection. Depends on
                   clang/llvm >= 3.7 and requires coroutine backend ucontext.
@@ -5222,6 +5256,62 @@ if  test "$plugins" = "yes" &&
 fi
 
 ########################################
+# lto (Link-Time Optimization)
+
+if test "$lto" = "true"; then
+  # Test compiler/ar/linker support for lto.
+  # compilation with lto is handled by meson. Just make sure that compiler
+  # support is fully functional, and add additional compatibility flags
+  # if necessary.
+
+  if ! echo | $cc -dM -E - | grep __clang__ > /dev/null 2>&1 ; then
+    # LTO with GCC and other compilers is not tested, and possibly broken
+    error_exit "QEMU only supports LTO with CLANG"
+  fi
+
+  # Check that lto is supported.
+  # Need to check for:
+  # - Valid compiler, that supports lto flags
+  # - Valid ar, able to support intermediate code
+  # - Valid linker, able to support intermediate code
+
+  #### Check for a valid *ar* for link-time optimization.
+  # Test it by creating a static library and linking it
+  # Compile an object first
+  cat > $TMPC << EOF
+int fun(int val);
+
+int fun(int val) {
+    return val;
+}
+EOF
+  if ! compile_object "-Werror -flto"; then
+    error_exit "LTO is not supported by your compiler"
+  fi
+  # Create a library out of it
+  if ! create_library "s" ; then
+    error_exit "LTO is not supported by ar. This usually happens when mixing GNU and LLVM toolchain."
+  fi
+  # Now create a binary using the library
+  cat > $TMPC << EOF
+int fun(int val);
+
+int main(int argc, char *argv[]) {
+  return fun(0);
+}
+EOF
+  if ! compile_prog "-Werror" "$test_ldflag -flto ${TMPA}"; then
+    error_exit "LTO is not supported by ar or the linker. This usually happens when mixing GNU and LLVM toolchain."
+  fi
+
+  #### All good, add the flags for CFI to our CFLAGS and LDFLAGS
+  # Flag needed both at compilation and at linking
+  QEMU_LDFLAGS="$QEMU_LDFLAGS $test_ldflag"
+  # Add -flto to CONFIGURE_*FLAGS since we need it in configure,
+  # but will be added by meson later
+  CONFIGURE_CFLAGS="$QEMU_CFLAGS -flto"
+  CONFIGURE_LDFLAGS="$QEMU_LDFLAGS -flto"
+fi
 # See if __attribute__((alias)) is supported.
 # This false for Xcode 9, but has been remedied for Xcode 10.
 # Unfortunately, travis uses Xcode 9 by default.
@@ -5532,6 +5622,43 @@ if test "$fuzzing" = "yes" && test -z "${LIB_FUZZING_ENGINE+xxx}"; then
     error_exit "Your compiler doesn't support -fsanitize=fuzzer"
     exit 1
   fi
+  # Make sure that the linker supports a custom linker script
+  # If LTO is enabled, switch linker to lld, since at the moment
+  # it is the only linker that works with lto and fuzzing:
+  # - gold does not support a custom script
+  # - bfd does not support wrapping functions with LTO
+  cat > $TMPC << EOF
+#include <stdlib.h>
+#include <stdio.h>
+void* __real_malloc(size_t size);
+void* __wrap_malloc(size_t size);
+
+void* __wrap_malloc(size_t size){
+  printf("Inside wrap_malloc\n");
+  return __real_malloc(size);
+}
+
+int main(int argc, char *argv[]) {
+  int *myint = (void*) malloc(sizeof(int));
+  *myint = 0;
+  return *myint;
+}
+EOF
+  extra_cflags="$CPU_CFLAGS -Werror"
+  extra_ldflags="-Wl,-T,${source_path}/tests/qtest/fuzz/fork_fuzz.ld"
+  extra_ldflags="${extra_ldflags} -Wl,--wrap,malloc"
+  if test "$lto" = "true"; then
+     extra_ldflags="${extra_ldflags} -fuse-ld=lld"
+  fi
+  if ! compile_prog "$extra_cflags" "$extra_ldflags"; then
+    error_exit "Your linker does not support our linker script"
+  fi
+  if ! do_run_filter "yes" "Inside wrap_malloc" ${TMPE} ""; then
+    error_exit "Your linker does not support our linker script"
+  fi
+  if test "$lto" = "true"; then
+     QEMU_LDFLAGS="${QEMU_LDFLAGS} -fuse-ld=lld"
+  fi
 fi
 
 # Thread sanitizer is, for now, much noisier than the other sanitizers;
@@ -7018,6 +7145,7 @@ NINJA=$ninja $meson setup \
         -Dcapstone=$capstone -Dslirp=$slirp -Dfdt=$fdt \
         -Diconv=$iconv -Dcurses=$curses -Dlibudev=$libudev\
         -Ddocs=$docs -Dsphinx_build=$sphinx_build \
+        -Db_lto=$lto \
         $cross_arg \
         "$PWD" "$source_path"
 
diff --git a/meson.build b/meson.build
index 7627a0ae46..50e5c527df 100644
--- a/meson.build
+++ b/meson.build
@@ -1959,6 +1959,7 @@ summary_info += {'gprof enabled':     config_host.has_key('CONFIG_GPROF')}
 summary_info += {'sparse enabled':    sparse.found()}
 summary_info += {'strip binaries':    get_option('strip')}
 summary_info += {'profiler':          config_host.has_key('CONFIG_PROFILER')}
+summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
 summary_info += {'static build':      config_host.has_key('CONFIG_STATIC')}
 if targetos == 'darwin'
   summary_info += {'Cocoa support': config_host.has_key('CONFIG_COCOA')}
-- 
2.17.1



  parent reply	other threads:[~2020-10-23 20:09 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-23 20:06 [PATCH v2 0/6] Add support for Control-Flow Integrity Daniele Buono
2020-10-23 20:06 ` [PATCH v2 1/6] fuzz: Make fork_fuzz.ld compatible with LLVM's LLD Daniele Buono
2020-10-23 20:06 ` [PATCH v2 2/6] configure: avoid new clang 11+ warnings Daniele Buono
2020-10-24  5:17   ` Thomas Huth
2020-10-24 12:42     ` Daniele Buono
2020-10-26  9:50   ` Paolo Bonzini
2020-10-26 15:03     ` Daniele Buono
2020-10-26 15:12       ` Paolo Bonzini
2020-10-26 21:40         ` Daniele Buono
2020-10-26 22:08         ` Peter Maydell
2020-10-27 11:26         ` Thomas Huth
2020-10-27 11:38           ` Cornelia Huck
2020-10-27 16:17             ` Daniele Buono
2020-10-23 20:06 ` Daniele Buono [this message]
2020-10-26  9:51   ` [PATCH v2 3/6] configure: add option to enable LTO Paolo Bonzini
2020-10-26 15:50     ` Daniel P. Berrangé
2020-10-27 14:57       ` Daniele Buono
2020-10-27 15:17         ` Daniel P. Berrangé
2020-10-27 20:42           ` Daniele Buono
2020-10-28  6:44             ` Paolo Bonzini
2020-10-28 18:22               ` Daniele Buono
2020-10-29 10:19                 ` Paolo Bonzini
2020-10-28  9:35         ` Alex Bennée
2020-10-28 18:47           ` Daniele Buono
2020-10-23 20:06 ` [PATCH v2 4/6] cfi: Initial support for cfi-icall in QEMU Daniele Buono
2020-10-26  9:52   ` Paolo Bonzini
2020-10-27 10:11   ` Alex Bennée
2020-10-23 20:06 ` [PATCH v2 5/6] check-block: enable iotests with cfi-icall Daniele Buono
2020-10-23 20:06 ` [PATCH v2 6/6] configure: add support for Control-Flow Integrity Daniele Buono
2020-10-26 10:00   ` Paolo Bonzini
2020-10-23 20:33 ` [PATCH v2 0/6] Add " Eric Blake
2020-10-24 11:58   ` Daniele Buono
2020-10-26  9:26   ` Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201023200645.1055-4-dbuono@linux.vnet.ibm.com \
    --to=dbuono@linux.vnet.ibm.com \
    --cc=alxndr@bu.edu \
    --cc=berrange@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.