From 6c72e46bff8a33df3ab2122e12388ef828ca3b07 Mon Sep 17 00:00:00 2001
From: Roland McGrath <mcgrathr@google.com>
Date: Sat, 27 Apr 2019 00:31:42 +0000
Subject: [PATCH] [build][ldso] Use libprefix for all instrumented variants

Also add an explicit option in environment() to enable a per-variant
libprefix in all variants of a toolchain (or none).  By default, each
variant that has the "instrumented" tag gets "$variant/" appended to its
${toolchain.libprefix} value.  Remove the "asan" variant's explicit
toolchain_vars.libprefix setting, which is now redundant.

The dynamic linker is compiled to request the libprefix from the loader
service, and all executables have the prefixed name in PT_INTERP so they
get the same variant's dynamic linker.

Bug: BLD-429 #done
Bug: ZX-3624 #done
Change-Id: Ia74bc8d449aa6ce3ded00df8940b057e790486f4
---
 zircon/public/gn/config/BUILD.gn            | 16 +++--
 zircon/public/gn/config/standard.gni        |  3 -
 zircon/public/gn/toolchain/environment.gni  | 69 +++++++++++++--------
 zircon/third_party/ulib/musl/ldso/BUILD.gn  |  7 +++
 zircon/third_party/ulib/musl/ldso/dynlink.c |  5 ++
 5 files changed, 67 insertions(+), 33 deletions(-)

diff --git a/zircon/public/gn/config/BUILD.gn b/zircon/public/gn/config/BUILD.gn
index f7ccccbb3a8..23665bc2dac 100644
--- a/zircon/public/gn/config/BUILD.gn
+++ b/zircon/public/gn/config/BUILD.gn
@@ -520,11 +520,17 @@ config("user_executable") {
     compiler_flags = [ "-fPIE" ]
     asmflags = compiler_flags
     cflags = compiler_flags
-    ldflags = compiler_flags
-    ldflags += [
-      "-Wl,-pie",
-      "-Wl,-dynamic-linker,ld.so.1",
-    ]
+    ldflags = compiler_flags + [ "-Wl,-pie" ]
+  } else {
+    ldflags = []
+  }
+
+  # Specify the dynamic linker if building a variant that uses a separate
+  # set of libraries.  With GCC, the dynamic linker must be explicit even
+  # in the default case because the compiler driver is not inherently
+  # configured for Fuchsia as it is in Clang.
+  if (is_gcc || toolchain.libprefix != "") {
+    ldflags += [ "-Wl,-dynamic-linker,${toolchain.libprefix}ld.so.1" ]
   }
 }
 
diff --git a/zircon/public/gn/config/standard.gni b/zircon/public/gn/config/standard.gni
index dd303222d56..9ea36bf1f7b 100644
--- a/zircon/public/gn/config/standard.gni
+++ b/zircon/public/gn/config/standard.gni
@@ -233,9 +233,6 @@ standard_variants = [
           add = [ "$zx/system/core/devmgr:driver_deps.$name" ]
         },
       ]
-      toolchain_vars = {
-        libprefix = "asan/"
-      }
       tags = [
         "instrumented",
         "useronly",
diff --git a/zircon/public/gn/toolchain/environment.gni b/zircon/public/gn/toolchain/environment.gni
index 6acbdf2dfb6..13ee1b9ba23 100644
--- a/zircon/public/gn/toolchain/environment.gni
+++ b/zircon/public/gn/toolchain/environment.gni
@@ -38,19 +38,21 @@ declare_args() {
   # Selector scope parameters
   #
   #   * variant
-  #     - Required: The variant to use when this selector matches.  If this is a
-  #     string then it must match a fully-defined variant elsewhere in the
-  #     list (or in $default_variants + $standard_variants, which is appended
-  #     implicitly to the $variants list).  If it's a scope then it defines a
-  #     new variant (see details below).
+  #     - Required: The variant to use when this selector matches.  If this
+  #     is a string then it must match a fully-defined variant elsewhere in
+  #     the list (or in $default_variants + $standard_variants, which is
+  #     appended implicitly to the $variants list).  If it's a scope then
+  #     it defines a new variant (see details below).
   #     - Type: string or scope, described below
   #
   #   * cpu
-  #     - Optional: If nonempty, match only when $current_cpu is one in the list.
+  #     - Optional: If nonempty, match only when $current_cpu is one in the
+  #     - list.
   #     - Type: list(string)
   #
   #   * os
-  #     - Optional: If nonempty, match only when $current_os is one in the list.
+  #     - Optional: If nonempty, match only when $current_os is one in the
+  #     - list.
   #     - Type: list(string)
   #
   #   * host
@@ -82,8 +84,9 @@ declare_args() {
   #     - Type: list(string)
   #
   #   * target_type
-  #     - Optional: If nonempty, a list of target types to match.  This is one of
-  #     "executable", "host_tool", "loadable_module", "driver", or "test".
+  #     - Optional: If nonempty, a list of target types to match.  This is
+  #     one of "executable", "host_tool", "loadable_module", "driver", or
+  #     "test".
   #     Note, test_driver() matches as "driver".
   #     - Type: list(string)
   #
@@ -106,9 +109,10 @@ declare_args() {
   #     - Type: list(label_no_toolchain)
   #
   #   * output_name
-  #     - Optional: If nonempty, match only when the `output_name` of the target
-  #     is one in the list.  Note `output_name` defaults to `target_name`,
-  #     and does not include prefixes or suffixes like ".so" or ".exe".
+  #     - Optional: If nonempty, match only when the `output_name` of the
+  #     target is one in the list.  Note `output_name` defaults to
+  #     `target_name`, and does not include prefixes or suffixes like ".so"
+  #     or ".exe".
   #     - Type: list(string)
   #
   # An element with a scope for `.variant` defines a new variant.  Each
@@ -297,14 +301,23 @@ declare_args() {
 #     This is just like $toolchain_args passed to toolchain() in bare GN.
 #
 #   * toolchain_vars
-#     - Optional: A scope imported into the $toolchain scope in these toolchains.
-#     This can store useful toolchain-specific variables that should be
-#     available within the toolchain.  $toolchain automatically contains
-#     `tool_dir`, `tool_prefix`, `cc, and `cxx`, from c_toolchain().
-#     If `variant_suffix` is defined here, terminal targets in the environment
-#     will have "$target_name$variant_suffix" aliases that get the same thing
-#     but in that particular variant installed under the suffixed name.
-#     The default `variant_suffix` is ".$variant" in each variant.
+#     - Optional: A scope imported into the $toolchain scope in these
+#     toolchains.  This can store useful toolchain-specific variables that
+#     should be available within the toolchain.  $toolchain automatically
+#     contains `tool_dir`, `tool_prefix`, `cc, and `cxx`, from
+#     c_toolchain().  If `variant_suffix` is defined here, terminal targets
+#     in the environment will have "$target_name$variant_suffix" aliases
+#     that get the same thing but in that particular variant installed
+#     under the suffixed name.  The default `variant_suffix` is ".$variant"
+#     in each variant.
+#
+#   * variant_libprefix
+#     - Optional: If true, each variant's name is used to form the
+#     ${toolchain.libprefix} value in that variant.  The final libprefix
+#     is "${toolchain_vars.libprefix}${toolchain.variant}/".  By default,
+#     this is true *only* in variants that have the "instrumented" tag.
+#     If explicitly set to true or false, that applies to *all* variants.
+#     - Type: bool
 #
 #   * variant_selectors
 #     - Optional: A list in the schema of the $variants build argument.  This
@@ -324,7 +337,7 @@ declare_args() {
 #     .variant scope.  If any of these strings appears in a .variant scope,
 #     then $variant_selectors elements using that variant will be silently
 #     ignored in this environment's toolchains.  e.g. an environment that is
-#     incompatbile with instrumentation could list the "instrumentation" tag
+#     incompatbile with instrumentation could list the "instrumented" tag
 #     and variants that enable instrumentation will be defined with that tag.
 #     Then simple `variants=["asan"]` user configurations that would apply
 #     ordinarily to all targets don't break the special-case execution
@@ -905,15 +918,21 @@ template("environment") {
           # `variant`, so it can't be used any more in this block.)
           variant = variant.name
 
+          if (!defined(libprefix)) {
+            libprefix = ""
+          }
+          if ((defined(invoker.variant_libprefix) &&
+               invoker.variant_libprefix) ||
+              (!defined(invoker.variant_libprefix) &&
+               tags + [ "instrumented" ] - [ "instrumented" ] != tags)) {
+            libprefix += "$variant/"
+          }
+
           # Plumb through the suffix of this variant and the list of others.
           if (!defined(variant_suffix)) {
             variant_suffix = ".$variant"
           }
 
-          if (!defined(libprefix)) {
-            libprefix = ""
-          }
-
           other_variants = []
           foreach(other_variant, toolchain_variants) {
             if (other_variant.name != variant) {
diff --git a/zircon/third_party/ulib/musl/ldso/BUILD.gn b/zircon/third_party/ulib/musl/ldso/BUILD.gn
index 71b4c4da4c6..493979e2840 100644
--- a/zircon/third_party/ulib/musl/ldso/BUILD.gn
+++ b/zircon/third_party/ulib/musl/ldso/BUILD.gn
@@ -13,4 +13,11 @@ source_set("ldso") {
     "dynlink-sancov.S",
     "dynlink.c",
   ]
+  if (toolchain.libprefix != "") {
+    # The libprefix always ends with a / but that's not part of the
+    # "config" string in the loader-service protocol.
+    ldsvc_config = get_path_info("${toolchain.libprefix}libfoo.so", "dir")
+    assert(ldsvc_config != "" && ldsvc_config != ".")
+    defines = [ "DYNLINK_LDSVC_CONFIG=\"$ldsvc_config\"" ]
+  }
 }
diff --git a/zircon/third_party/ulib/musl/ldso/dynlink.c b/zircon/third_party/ulib/musl/ldso/dynlink.c
index ee8d26fad67..bf724807676 100644
--- a/zircon/third_party/ulib/musl/ldso/dynlink.c
+++ b/zircon/third_party/ulib/musl/ldso/dynlink.c
@@ -2090,6 +2090,11 @@ __NO_SAFESTACK NO_ASAN static dl_start_return_t __dls3(void* start_arg) {
 __NO_SAFESTACK NO_ASAN static void early_init(void) {
 #if __has_feature(address_sanitizer)
     __asan_early_init();
+#endif
+#ifdef DYNLINK_LDSVC_CONFIG
+    // Inform the loader service to look for libraries of the right variant.
+    loader_svc_config(DYNLINK_LDSVC_CONFIG);
+#elif __has_feature(address_sanitizer)
     // Inform the loader service that we prefer ASan-supporting libraries.
     loader_svc_config("asan");
 #endif
-- 
GitLab