From 545f95b0b0ce09d552fbd9f822f9ee7767b5d4c6 Mon Sep 17 00:00:00 2001 From: pcc Date: Wed, 6 Apr 2016 19:32:39 -0700 Subject: [PATCH] Enable whole-program virtual function optimization in LTO mode. Also move LTO config out of sanitizer config, and enable function sections on all architectures (not just ARM) as it improves the linker's ability to do ICF. BUG=580389 Review URL: https://codereview.chromium.org/1809273002 Cr-Original-Commit-Position: refs/heads/master@{#385630} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 5f4ec37b6548c11b0b470ce824a3d28f7f54fcd1 --- common.gypi | 37 ++++++++++++-------- config/compiler/BUILD.gn | 47 +++++++++++++++++++++++++ config/sanitizers/BUILD.gn | 59 +++++++++----------------------- config/sanitizers/sanitizers.gni | 6 ++-- toolchain/gcc_toolchain.gni | 5 +-- toolchain/toolchain.gni | 8 +++++ toolchain/win/BUILD.gn | 7 +--- 7 files changed, 100 insertions(+), 69 deletions(-) diff --git a/common.gypi b/common.gypi index 03416541d..0e88c8b86 100644 --- a/common.gypi +++ b/common.gypi @@ -6149,6 +6149,11 @@ ['_toolset=="target"', { 'ldflags': [ '-Wl,--plugin-opt,O1', + # Allows the linker to apply ICF to the LTO object file. Also, when + # targeting ARM, wWithout this flag, LTO produces a .text section + # that is larger than the maximum call displacement, preventing the + # linker from relocating calls (http://llvm.org/PR22999). + '-Wl,--plugin-opt,-function-sections', ], }], ['_toolset=="target" and _type!="static_library"', { @@ -6168,20 +6173,6 @@ }, }, }], - ['use_lto==1 and clang==1 and target_arch=="arm"', { - 'target_defaults': { - 'target_conditions': [ - ['_toolset=="target"', { - # Without this flag, LTO produces a .text section that is larger - # than the maximum call displacement, preventing the linker from - # relocating calls (http://llvm.org/PR22999). - 'ldflags': [ - '-Wl,-plugin-opt,-function-sections', - ], - }], - ], - }, - }], ['(use_lto==1 or use_lto_o2==1) and clang==0', { 'target_defaults': { 'target_conditions': [ @@ -6327,6 +6318,24 @@ ], }, }], + # TODO(pcc): Make these flags work correctly with CFI. + ['use_lto!=0 and cfi_vptr==0', { + 'target_defaults': { + 'target_conditions': [ + ['_toolset=="target"', { + 'cflags': [ + '-fwhole-program-vtables', + # TODO(pcc): Remove this flag once the upstream interface change + # (http://reviews.llvm.org/D18635) lands. + '-fwhole-program-vtables-blacklist=<(cfi_blacklist)', + ], + 'ldflags': [ + '-fwhole-program-vtables', + ], + }], + ], + }, + }], ], 'xcode_settings': { # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT! diff --git a/config/compiler/BUILD.gn b/config/compiler/BUILD.gn index 0da129f5a..a59907bc8 100644 --- a/config/compiler/BUILD.gn +++ b/config/compiler/BUILD.gn @@ -7,6 +7,7 @@ import("//build/config/chrome_build.gni") import("//build/config/compiler/compiler.gni") import("//build/config/nacl/config.gni") import("//build/toolchain/cc_wrapper.gni") +import("//build/toolchain/toolchain.gni") if (current_cpu == "arm") { import("//build/config/arm.gni") @@ -378,6 +379,52 @@ config("compiler") { } } + # Add flags for link-time optimization. These flags enable + # optimizations/transformations that require whole-program visibility at link + # time, so they need to be applied to all translation units, and we may end up + # with miscompiles if only part of the program is compiled with LTO flags. For + # that reason, we cannot allow targets to enable or disable these flags, for + # example by disabling the optimize configuration. + # TODO(pcc): Make this conditional on is_official_build rather than on gn + # flags for specific features. + if (!is_debug && (allow_posix_link_time_opt || is_cfi) && !is_nacl) { + cflags += [ "-flto" ] + ldflags += [ "-flto" ] + + # Apply a lower LTO optimization level as the default is too slow. + if (is_linux) { + ldflags += [ "-Wl,-plugin-opt,O1" ] + } else if (is_mac) { + ldflags += [ "-Wl,-mllvm,-O1" ] + } + + # Work-around for http://openradar.appspot.com/20356002 + if (is_mac) { + ldflags += [ "-Wl,-all_load" ] + } + + # Allows the linker to apply ICF to the LTO object file. Also, when + # targeting ARM, without this flag, LTO produces a .text section that is + # larger than the maximum call displacement, preventing the linker from + # relocating calls (http://llvm.org/PR22999). + if (is_linux) { + ldflags += [ "-Wl,-plugin-opt,-function-sections" ] + } + + # TODO(pcc): Make these flags work correctly with CFI. + if (!is_cfi) { + cflags += [ + "-fwhole-program-vtables", + + # TODO(pcc): Remove this flag once the upstream interface change + # (http://reviews.llvm.org/D18635) lands. + "-fwhole-program-vtables-blacklist=" + + rebase_path("//tools/cfi/blacklist.txt", root_build_dir), + ] + ldflags += [ "-fwhole-program-vtables" ] + } + } + # Pass the same C/C++ flags to the objective C/C++ compiler. cflags_objc += cflags_c cflags_objcc += cflags_cc diff --git a/config/sanitizers/BUILD.gn b/config/sanitizers/BUILD.gn index 33497235a..29bb7f1c0 100644 --- a/config/sanitizers/BUILD.gn +++ b/config/sanitizers/BUILD.gn @@ -94,36 +94,13 @@ config("default_sanitizer_ldflags") { if (is_ubsan_vptr) { ldflags += [ "-fsanitize=vptr" ] } - if (is_lto && !is_nacl) { - ldflags += [ "-flto" ] - - # Apply a lower LTO optimization level as the default is too slow. - if (is_linux) { - ldflags += [ "-Wl,-plugin-opt,O1" ] - } else if (is_mac) { - ldflags += [ "-Wl,-mllvm,-O1" ] - } - - # Work-around for http://openradar.appspot.com/20356002 - if (is_mac) { - ldflags += [ "-Wl,-all_load" ] - } - - # Without this flag, LTO produces a .text section that is larger - # than the maximum call displacement, preventing the linker from - # relocating calls (http://llvm.org/PR22999). - if (current_cpu == "arm") { - ldflags += [ "-Wl,-plugin-opt,-function-sections" ] - } - - if (is_cfi) { - ldflags += [ - "-fsanitize=cfi-vcall", - "-fsanitize=cfi-derived-cast", - "-fsanitize=cfi-unrelated-cast", - ] - } + if (is_cfi && !is_nacl) { + ldflags += [ + "-fsanitize=cfi-vcall", + "-fsanitize=cfi-derived-cast", + "-fsanitize=cfi-unrelated-cast", + ] if (use_cfi_diag) { ldflags += [ "-fno-sanitize-trap=cfi", @@ -156,7 +133,7 @@ config("default_sanitizer_flags") { # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer, # MemorySanitizer and non-official CFI builds. - if (using_sanitizer || (is_lto && !is_official_build)) { + if (using_sanitizer || (is_cfi && !is_official_build)) { if (is_posix) { cflags += [ "-fno-omit-frame-pointer" ] } else { @@ -282,19 +259,15 @@ config("default_sanitizer_flags") { "-fsanitize-blacklist=$ubsan_blacklist_path", ] } - if (is_lto && !is_nacl) { - cflags += [ "-flto" ] - - if (is_cfi) { - cfi_blacklist_path = - rebase_path("//tools/cfi/blacklist.txt", root_build_dir) - cflags += [ - "-fsanitize=cfi-vcall", - "-fsanitize=cfi-derived-cast", - "-fsanitize=cfi-unrelated-cast", - "-fsanitize-blacklist=$cfi_blacklist_path", - ] - } + if (is_cfi && !is_nacl) { + cfi_blacklist_path = + rebase_path("//tools/cfi/blacklist.txt", root_build_dir) + cflags += [ + "-fsanitize=cfi-vcall", + "-fsanitize=cfi-derived-cast", + "-fsanitize=cfi-unrelated-cast", + "-fsanitize-blacklist=$cfi_blacklist_path", + ] if (use_cfi_diag) { cflags += [ diff --git a/config/sanitizers/sanitizers.gni b/config/sanitizers/sanitizers.gni index fd0989fac..f407498ef 100644 --- a/config/sanitizers/sanitizers.gni +++ b/config/sanitizers/sanitizers.gni @@ -39,6 +39,8 @@ declare_args() { # Compile with Control Flow Integrity to protect virtual calls and casts. # See http://clang.llvm.org/docs/ControlFlowIntegrity.html + # + # TODO(pcc): Remove this flag if/when CFI is enabled in official builds. is_cfi = false # By default, Control Flow Integrity will crash the program if it detects a @@ -72,10 +74,6 @@ declare_args() { use_custom_libcxx = (is_asan && is_linux) || is_tsan || is_msan || is_ubsan || is_ubsan_security || use_libfuzzer - # Enable Link Time Optimization (output programs runs faster, - # but linking is up to 5-20x slower. - is_lto = is_cfi - use_sanitizer_coverage = use_libfuzzer } diff --git a/toolchain/gcc_toolchain.gni b/toolchain/gcc_toolchain.gni index 90f77793f..e2b98e069 100644 --- a/toolchain/gcc_toolchain.gni +++ b/toolchain/gcc_toolchain.gni @@ -9,7 +9,7 @@ import("//build/toolchain/goma.gni") import("//build/toolchain/toolchain.gni") # This value will be inherited in the toolchain below. -if (is_lto) { +if (allow_posix_link_time_opt || is_cfi) { concurrent_links = exec_script("get_concurrent_links.py", [ "--lto" ], "value") } else { @@ -217,7 +217,8 @@ template("gcc_toolchain") { tool("alink") { rspfile = "{{output}}.rsp" arflags = "" - if (is_lto && invoker.toolchain_os != "nacl") { + if ((allow_posix_link_time_opt || is_cfi) && + invoker.toolchain_os != "nacl") { gold_plugin_path = rebase_path( "//third_party/llvm-build/Release+Asserts/lib/LLVMgold.so", root_build_dir) diff --git a/toolchain/toolchain.gni b/toolchain/toolchain.gni index e7f43792a..41daacc66 100644 --- a/toolchain/toolchain.gni +++ b/toolchain/toolchain.gni @@ -5,6 +5,14 @@ # Toolchain-related configuration that may be needed outside the context of the # toolchain() rules themselves. +declare_args() { + # Enable Link Time Optimization in optimized builds (output programs run + # faster, but linking is up to 5-20x slower). + # + # TODO(pcc): Remove this flag if/when LTO is enabled in official builds. + allow_posix_link_time_opt = false +} + # Subdirectory within root_out_dir for shared library files. # TODO(agrieve): GYP sets this to "lib" for Linux & Android, but this won't work # in GN until support for loadable_module() is added. diff --git a/toolchain/win/BUILD.gn b/toolchain/win/BUILD.gn index c469c4302..b0c5e279d 100644 --- a/toolchain/win/BUILD.gn +++ b/toolchain/win/BUILD.gn @@ -25,12 +25,7 @@ if (use_goma) { } # This value will be inherited in the toolchain below. -if (is_lto) { - concurrent_links = - exec_script("../get_concurrent_links.py", [ "--lto" ], "value") -} else { - concurrent_links = exec_script("../get_concurrent_links.py", [], "value") -} +concurrent_links = exec_script("../get_concurrent_links.py", [], "value") # Copy the VS runtime DLL for the default toolchain to the root build directory # so things will run.