summary refs log tree commit diff
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2017-08-28 14:56:08 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2017-12-13 16:08:18 -0500
commit8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd (patch)
tree1f981fdaa6de98e84214b0feb76795812dbfe10f
parent4f869bccc14fb2fa19df130e76c022765ecda924 (diff)
downloadnixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.tar
nixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.tar.gz
nixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.tar.bz2
nixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.tar.lz
nixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.tar.xz
nixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.tar.zst
nixpkgs-8e557ed2c58e6ce48a8d05dbc57ef84e98b4cecd.zip
bintools-wrapper: Init
Factor a bintools (i.e. binutils / cctools) wrapper out of cc-wrapper. While
only LD is wrapped, the setup hook defines environment variables on behalf of
other utilites.
-rw-r--r--pkgs/build-support/bintools-wrapper/add-flags.sh40
-rw-r--r--pkgs/build-support/bintools-wrapper/add-hardening.sh53
-rw-r--r--pkgs/build-support/bintools-wrapper/default.nix285
-rw-r--r--[-rwxr-xr-x]pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh (renamed from pkgs/build-support/cc-wrapper/ld-solaris-wrapper.sh)0
-rw-r--r--pkgs/build-support/bintools-wrapper/ld-wrapper.sh (renamed from pkgs/build-support/cc-wrapper/ld-wrapper.sh)2
-rw-r--r--pkgs/build-support/bintools-wrapper/macos-sierra-reexport-hack.bash (renamed from pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.bash)4
-rw-r--r--pkgs/build-support/bintools-wrapper/setup-hook.sh67
-rw-r--r--pkgs/build-support/cc-wrapper/add-flags.sh15
-rw-r--r--pkgs/build-support/cc-wrapper/add-hardening.sh10
-rw-r--r--pkgs/build-support/cc-wrapper/cc-wrapper.sh6
-rw-r--r--pkgs/build-support/cc-wrapper/default.nix161
-rw-r--r--pkgs/build-support/cc-wrapper/setup-hook.sh27
-rw-r--r--pkgs/top-level/all-packages.nix1
13 files changed, 506 insertions, 165 deletions
diff --git a/pkgs/build-support/bintools-wrapper/add-flags.sh b/pkgs/build-support/bintools-wrapper/add-flags.sh
new file mode 100644
index 00000000000..7d118d20fc6
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/add-flags.sh
@@ -0,0 +1,40 @@
+# See cc-wrapper for comments.
+var_templates_list=(
+    NIX+IGNORE_LD_THROUGH_GCC
+    NIX+LDFLAGS
+    NIX+LDFLAGS_BEFORE
+    NIX+LDFLAGS_AFTER
+    NIX+LDFLAGS_HARDEN
+)
+var_templates_bool=(
+    NIX+SET_BUILD_ID
+    NIX+DONT_SET_RPATH
+)
+
+declare -a role_infixes=()
+if [ "${NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_BUILD:-}" ]; then
+    role_infixes+=(_BUILD_)
+fi
+if [ "${NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_HOST:-}" ]; then
+    role_infixes+=(_)
+fi
+if [ "${NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_TARGET:-}" ]; then
+    role_infixes+=(_TARGET_)
+fi
+
+for var in "${var_templates_list[@]}"; do
+    mangleVarList "$var" "${role_infixes[@]}"
+done
+for var in "${var_templates_bool[@]}"; do
+    mangleVarBool "$var" "${role_infixes[@]}"
+done
+
+if [ -e @out@/nix-support/libc-ldflags ]; then
+    NIX_@infixSalt@_LDFLAGS+=" $(< @out@/nix-support/libc-ldflags)"
+fi
+
+if [ -e @out@/nix-support/libc-ldflags-before ]; then
+    NIX_@infixSalt@_LDFLAGS_BEFORE="$(< @out@/nix-support/libc-ldflags-before) $NIX_@infixSalt@_LDFLAGS_BEFORE"
+fi
+
+export NIX_BINTOOLS_WRAPPER_@infixSalt@_FLAGS_SET=1
diff --git a/pkgs/build-support/bintools-wrapper/add-hardening.sh b/pkgs/build-support/bintools-wrapper/add-hardening.sh
new file mode 100644
index 00000000000..5282d17fce2
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/add-hardening.sh
@@ -0,0 +1,53 @@
+hardeningFlags=(relro bindnow)
+# Intentionally word-split in case 'hardeningEnable' is defined in
+# Nix. Also, our bootstrap tools version of bash is old enough that
+# undefined arrays trip `set -u`.
+if [[ -v hardeningEnable[@] ]]; then
+  hardeningFlags+=(${hardeningEnable[@]})
+fi
+hardeningLDFlags=()
+
+declare -A hardeningDisableMap
+
+# Intentionally word-split in case 'hardeningDisable' is defined in Nix.
+for flag in ${hardeningDisable[@]:-IGNORED_KEY} @hardening_unsupported_flags@
+do
+  hardeningDisableMap[$flag]=1
+done
+
+if (( "${NIX_DEBUG:-0}" >= 1 )); then
+  printf 'HARDENING: disabled flags:' >&2
+  (( "${#hardeningDisableMap[@]}" )) && printf ' %q' "${!hardeningDisableMap[@]}" >&2
+  echo >&2
+fi
+
+if [[ -z "${hardeningDisableMap[all]:-}" ]]; then
+  if (( "${NIX_DEBUG:-0}" >= 1 )); then
+    echo 'HARDENING: Is active (not completely disabled with "all" flag)' >&2;
+  fi
+  for flag in "${hardeningFlags[@]}"
+  do
+    if [[ -z "${hardeningDisableMap[$flag]:-}" ]]; then
+      case $flag in
+        pie)
+          if [[ ! ("$*" =~ " -shared " || "$*" =~ " -static ") ]]; then
+            if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling LDFlags -pie >&2; fi
+            hardeningLDFlags+=('-pie')
+          fi
+          ;;
+        relro)
+          if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling relro >&2; fi
+          hardeningLDFlags+=('-z' 'relro')
+          ;;
+        bindnow)
+          if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling bindnow >&2; fi
+          hardeningLDFlags+=('-z' 'now')
+          ;;
+        *)
+          # Ignore unsupported. Checked in Nix that at least *some*
+          # tool supports each flag.
+          ;;
+      esac
+    fi
+  done
+fi
diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix
new file mode 100644
index 00000000000..a9155c2c6eb
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/default.nix
@@ -0,0 +1,285 @@
+# The Nixpkgs CC is not directly usable, since it doesn't know where
+# the C library and standard header files are. Therefore the compiler
+# produced by that package cannot be installed directly in a user
+# environment and used from the command line. So we use a wrapper
+# script that sets up the right environment variables so that the
+# compiler and the linker just "work".
+
+{ name ? "", stdenvNoCC, nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
+, bintools ? null, libc ? null
+, coreutils ? null, shell ? stdenvNoCC.shell, gnugrep ? null
+, extraPackages ? [], extraBuildCommands ? ""
+, buildPackages ? {}
+, useMacosReexportHack ? false
+}:
+
+with stdenvNoCC.lib;
+
+assert nativeTools -> nativePrefix != "";
+assert !nativeTools ->
+  bintools != null && coreutils != null && gnugrep != null;
+assert !(nativeLibc && noLibc);
+assert (noLibc || nativeLibc) == (libc == null);
+
+let
+  stdenv = stdenvNoCC;
+  inherit (stdenv) hostPlatform targetPlatform;
+
+  # Prefix for binaries. Customarily ends with a dash separator.
+  #
+  # TODO(@Ericson2314) Make unconditional, or optional but always true by
+  # default.
+  targetPrefix = stdenv.lib.optionalString (targetPlatform != hostPlatform)
+                                        (targetPlatform.config + "-");
+
+  bintoolsVersion = (builtins.parseDrvName bintools.name).version;
+  bintoolsName = (builtins.parseDrvName bintools.name).name;
+
+  libc_bin = if libc == null then null else getBin libc;
+  libc_dev = if libc == null then null else getDev libc;
+  libc_lib = if libc == null then null else getLib libc;
+  bintools_bin = if nativeTools then "" else getBin bintools;
+  # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
+  coreutils_bin = if nativeTools then "" else getBin coreutils;
+
+  dashlessTarget = stdenv.lib.replaceStrings ["-"] ["_"] targetPlatform.config;
+
+  # See description in cc-wrapper.
+  infixSalt = dashlessTarget;
+
+  # The dynamic linker has different names on different platforms. This is a
+  # shell glob that ought to match it.
+  dynamicLinker =
+    /**/ if libc == null then null
+    else if targetPlatform.system == "i686-linux"     then "${libc_lib}/lib/ld-linux.so.2"
+    else if targetPlatform.system == "x86_64-linux"   then "${libc_lib}/lib/ld-linux-x86-64.so.2"
+    # ARM with a wildcard, which can be "" or "-armhf".
+    else if (with targetPlatform; isArm && isLinux)   then "${libc_lib}/lib/ld-linux*.so.3"
+    else if targetPlatform.system == "aarch64-linux"  then "${libc_lib}/lib/ld-linux-aarch64.so.1"
+    else if targetPlatform.system == "powerpc-linux"  then "${libc_lib}/lib/ld.so.1"
+    else if targetPlatform.system == "mips64el-linux" then "${libc_lib}/lib/ld.so.1"
+    else if targetPlatform.isDarwin                   then "/usr/lib/dyld"
+    else if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
+    else null;
+
+  expand-response-params =
+    if buildPackages.stdenv.cc or null != null && buildPackages.stdenv.cc != "/dev/null"
+    then import ../expand-response-params { inherit (buildPackages) stdenv; }
+    else "";
+
+in
+
+stdenv.mkDerivation {
+  name = targetPrefix
+    + (if name != "" then name else "${bintoolsName}-wrapper")
+    + (stdenv.lib.optionalString (bintools != null && bintoolsVersion != "") "-${bintoolsVersion}");
+
+  preferLocalBuild = true;
+
+  inherit bintools_bin libc_bin libc_dev libc_lib coreutils_bin;
+  shell = getBin shell + shell.shellPath or "";
+  gnugrep_bin = if nativeTools then "" else gnugrep;
+
+  inherit targetPrefix infixSalt;
+
+  outputs = [ "out" "man" ];
+
+  passthru = {
+    inherit bintools libc nativeTools nativeLibc nativePrefix;
+
+    emacsBufferSetup = pkgs: ''
+      ; We should handle propagation here too
+      (mapc
+        (lambda (arg)
+          (when (file-directory-p (concat arg "/lib"))
+            (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib")))
+          (when (file-directory-p (concat arg "/lib64"))
+            (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib64"))))
+        '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
+    '';
+  };
+
+  dontBuild = true;
+  dontConfigure = true;
+
+  unpackPhase = ''
+    src=$PWD
+  '';
+
+  installPhase =
+    ''
+      set -u
+
+      mkdir -p $out/bin $out/nix-support $man/nix-support
+
+      wrap() {
+        local dst="$1"
+        local wrapper="$2"
+        export prog="$3"
+        set +u
+        substituteAll "$wrapper" "$out/bin/$dst"
+        set -u
+        chmod +x "$out/bin/$dst"
+      }
+    ''
+
+    + (if nativeTools then ''
+      echo ${nativePrefix} > $out/nix-support/orig-bintools
+
+      ldPath="${nativePrefix}/bin"
+    '' else ''
+      echo $bintools_bin > $out/nix-support/orig-bintools
+
+      ldPath="${bintools_bin}/bin"
+    ''
+
+    + optionalString (targetPlatform.isSunOS && nativePrefix != "") ''
+      # Solaris needs an additional ld wrapper.
+      ldPath="${nativePrefix}/bin"
+      exec="$ldPath/${targetPrefix}ld"
+      wrap ld-solaris ${./ld-solaris-wrapper.sh}
+    '')
+
+    + ''
+      # Create a symlink to as (the assembler).
+      if [ -e $ldPath/${targetPrefix}as ]; then
+        ln -s $ldPath/${targetPrefix}as $out/bin/${targetPrefix}as
+      fi
+
+    '' + (if !useMacosReexportHack then ''
+      wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
+    '' else ''
+      ldInner="${targetPrefix}ld-reexport-delegate"
+      wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${targetPrefix}ld}
+      wrap "${targetPrefix}ld" ${./ld-wrapper.sh} "$out/bin/$ldInner"
+      unset ldInner
+    '') + ''
+
+      if [ -e ${bintools_bin}/bin/${targetPrefix}ld.gold ]; then
+        wrap ${targetPrefix}ld.gold ${./ld-wrapper.sh} ${bintools_bin}/bin/${targetPrefix}ld.gold
+      fi
+
+      if [ -e ${bintools_bin}/bin/ld.bfd ]; then
+        wrap ${targetPrefix}ld.bfd ${./ld-wrapper.sh} ${bintools_bin}/bin/${targetPrefix}ld.bfd
+      fi
+
+      set +u
+    '';
+
+  propagatedBuildInputs = extraPackages;
+
+  setupHook = ./setup-hook.sh;
+
+  postFixup =
+    ''
+      set -u
+    ''
+
+    + optionalString (libc != null) (''
+      ##
+      ## General libc support
+      ##
+
+      echo "-L${libc_lib}/lib" > $out/nix-support/libc-ldflags
+
+      echo "${libc_lib}" > $out/nix-support/orig-libc
+      echo "${libc_dev}" > $out/nix-support/orig-libc-dev
+
+      ##
+      ## Dynamic linker support
+      ##
+
+      if [[ -z ''${dynamicLinker+x} ]]; then
+        echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2
+        local dynamicLinker="${libc_lib}/lib/ld*.so.?"
+      fi
+
+      # Expand globs to fill array of options
+      dynamicLinker=($dynamicLinker)
+
+      case ''${#dynamicLinker[@]} in
+        0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;;
+        1) echo "Using dynamic linker: '$dynamicLinker'" >&2;;
+        *) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;;
+      esac
+
+      if [ -n "''${dynamicLinker:-}" ]; then
+        echo $dynamicLinker > $out/nix-support/dynamic-linker
+
+    '' + (if targetPlatform.isDarwin then ''
+        printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
+    '' else ''
+        if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then
+          echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
+        fi
+
+        local ldflagsBefore=(-dynamic-linker "$dynamicLinker")
+    '') + ''
+      fi
+
+      # The dynamic linker is passed in `ldflagsBefore' to allow
+      # explicit overrides of the dynamic linker by callers to ld
+      # (the *last* value counts, so ours should come first).
+      printWords "''${ldflagsBefore[@]}" > $out/nix-support/libc-ldflags-before
+    '')
+
+    + optionalString (!nativeTools) ''
+
+      ##
+      ## User env support
+      ##
+
+      # Propagate the underling unwrapped bintools so that if you
+      # install the wrapper, you get tools like objdump, the manpages,
+      # etc. as well (same for any binaries of libc).
+      printWords ${bintools_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages
+    ''
+
+    + ''
+
+      ##
+      ## Hardening support
+      ##
+
+      # some linkers on some platforms don't support specific -z flags
+      export hardening_unsupported_flags=""
+      if [[ "$($ldPath/${targetPrefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
+        hardening_unsupported_flags+=" bindnow"
+      fi
+      if [[ "$($ldPath/${targetPrefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
+        hardening_unsupported_flags+=" relro"
+      fi
+    ''
+
+    + optionalString hostPlatform.isCygwin ''
+      hardening_unsupported_flags+=" pic"
+    ''
+
+    + ''
+      set +u
+      substituteAll ${./add-flags.sh} $out/nix-support/add-flags.sh
+      substituteAll ${./add-hardening.sh} $out/nix-support/add-hardening.sh
+      substituteAll ${../cc-wrapper/utils.sh} $out/nix-support/utils.sh
+
+      ##
+      ## Extra custom steps
+      ##
+
+    ''
+    + extraBuildCommands;
+
+  inherit dynamicLinker expand-response-params;
+
+  # for substitution in utils.sh
+  expandResponseParams = "${expand-response-params}/bin/expand-response-params";
+
+  meta =
+    let bintools_ = if bintools != null then bintools else {}; in
+    (if bintools_ ? meta then removeAttrs bintools.meta ["priority"] else {}) //
+    { description =
+        stdenv.lib.attrByPath ["meta" "description"] "System binary utilities" bintools_
+        + " (wrapper script)";
+  } // optionalAttrs useMacosReexportHack {
+    platforms = stdenv.lib.platforms.darwin;
+  };
+}
diff --git a/pkgs/build-support/cc-wrapper/ld-solaris-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh
index 5d81e34a047..5d81e34a047 100755..100644
--- a/pkgs/build-support/cc-wrapper/ld-solaris-wrapper.sh
+++ b/pkgs/build-support/bintools-wrapper/ld-solaris-wrapper.sh
diff --git a/pkgs/build-support/cc-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
index 4452018866d..136621d27af 100644
--- a/pkgs/build-support/cc-wrapper/ld-wrapper.sh
+++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
@@ -16,7 +16,7 @@ fi
 
 source @out@/nix-support/utils.sh
 
-if [ -z "${NIX_CC_WRAPPER_@infixSalt@_FLAGS_SET:-}" ]; then
+if [ -z "${NIX_BINTOOLS_WRAPPER_@infixSalt@_FLAGS_SET:-}" ]; then
     source @out@/nix-support/add-flags.sh
 fi
 
diff --git a/pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.bash b/pkgs/build-support/bintools-wrapper/macos-sierra-reexport-hack.bash
index 20503545333..a0c4e9edfcd 100644
--- a/pkgs/build-support/cc-wrapper/macos-sierra-reexport-hack.bash
+++ b/pkgs/build-support/bintools-wrapper/macos-sierra-reexport-hack.bash
@@ -81,8 +81,10 @@ else
 
     symbolBloatObject=$outputNameLibless-symbol-hack.o
     if [[ ! -e $symbolBloatObject ]]; then
+        # `-Q` means use GNU Assembler rather than Clang, avoiding an awkward
+        # dependency cycle.
         printf '.private_extern _______child_hack_foo\nchild_hack_foo:\n' \
-            | @targetPrefix@as -- -o $symbolBloatObject
+            | @targetPrefix@as -Q -- -o $symbolBloatObject
     fi
 
     # first half of libs
diff --git a/pkgs/build-support/bintools-wrapper/setup-hook.sh b/pkgs/build-support/bintools-wrapper/setup-hook.sh
new file mode 100644
index 00000000000..43f79ec5920
--- /dev/null
+++ b/pkgs/build-support/bintools-wrapper/setup-hook.sh
@@ -0,0 +1,67 @@
+# Binutils Wrapper hygiene
+#
+# See comments in cc-wrapper's setup hook. This works exactly the same way.
+
+bintoolsWrapper_addLDVars () {
+    case $depOffset in
+        -1) local role='BUILD_' ;;
+        0)  local role='' ;;
+        1)  local role='TARGET_' ;;
+        *)  echo "bintools-wrapper: Error: Cannot be used with $depOffset-offset deps, " >2;
+            return 1 ;;
+    esac
+
+    if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then
+        export NIX_${role}LDFLAGS+=" -L$1/lib64"
+    fi
+
+    if [[ -d "$1/lib" ]]; then
+        export NIX_${role}LDFLAGS+=" -L$1/lib"
+    fi
+}
+
+if [ -n "${crossConfig:-}" ]; then
+    export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_BUILD=1
+    role_pre='BUILD_'
+    role_post='_FOR_BUILD'
+else
+    export NIX_BINTOOLS_WRAPPER_@infixSalt@_TARGET_HOST=1
+    role_pre=""
+    role_post=''
+fi
+
+envHooks+=(bintoolsWrapper_addLDVars)
+
+# shellcheck disable=SC2157
+if [ -n "@bintools_bin@" ]; then
+    addToSearchPath _PATH @bintools_bin@/bin
+fi
+
+# shellcheck disable=SC2157
+if [ -n "@libc_bin@" ]; then
+    addToSearchPath _PATH @libc_bin@/bin
+fi
+
+# shellcheck disable=SC2157
+if [ -n "@coreutils_bin@" ]; then
+    addToSearchPath _PATH @coreutils_bin@/bin
+fi
+
+# Export tool environment variables so various build systems use the right ones.
+
+export NIX_${role_pre}BINTOOLS=@out@
+
+for cmd in \
+    ar as ld nm objcopy objdump readelf ranlib strip strings size windres
+do
+    if
+        PATH=$_PATH type -p "@targetPrefix@${cmd}" > /dev/null
+    then
+        upper_case="$(echo "$cmd" | tr "[:lower:]" "[:upper:]")"
+        export "${role_pre}${upper_case}=@targetPrefix@${cmd}";
+        export "${upper_case}${role_post}=@targetPrefix@${cmd}";
+    fi
+done
+
+# No local scope in sourced file
+unset -v role_pre role_post cmd upper_case
diff --git a/pkgs/build-support/cc-wrapper/add-flags.sh b/pkgs/build-support/cc-wrapper/add-flags.sh
index 978041fb4d8..d8b42244607 100644
--- a/pkgs/build-support/cc-wrapper/add-flags.sh
+++ b/pkgs/build-support/cc-wrapper/add-flags.sh
@@ -10,15 +10,8 @@ var_templates_list=(
     NIX+CXXSTDLIB_COMPILE
     NIX+CXXSTDLIB_LINK
     NIX+GNATFLAGS_COMPILE
-    NIX+IGNORE_LD_THROUGH_GCC
-    NIX+LDFLAGS
-    NIX+LDFLAGS_BEFORE
-    NIX+LDFLAGS_AFTER
 )
-
 var_templates_bool=(
-    NIX+SET_BUILD_ID
-    NIX+DONT_SET_RPATH
     NIX+ENFORCE_NO_NATIVE
 )
 
@@ -62,17 +55,9 @@ if [ -e @out@/nix-support/gnat-cflags ]; then
     NIX_@infixSalt@_GNATFLAGS_COMPILE="$(< @out@/nix-support/gnat-cflags) $NIX_@infixSalt@_GNATFLAGS_COMPILE"
 fi
 
-if [ -e @out@/nix-support/libc-ldflags ]; then
-    NIX_@infixSalt@_LDFLAGS+=" $(< @out@/nix-support/libc-ldflags)"
-fi
-
 if [ -e @out@/nix-support/cc-ldflags ]; then
     NIX_@infixSalt@_LDFLAGS+=" $(< @out@/nix-support/cc-ldflags)"
 fi
 
-if [ -e @out@/nix-support/libc-ldflags-before ]; then
-    NIX_@infixSalt@_LDFLAGS_BEFORE="$(< @out@/nix-support/libc-ldflags-before) $NIX_@infixSalt@_LDFLAGS_BEFORE"
-fi
-
 # That way forked processes will not extend these environment variables again.
 export NIX_CC_WRAPPER_@infixSalt@_FLAGS_SET=1
diff --git a/pkgs/build-support/cc-wrapper/add-hardening.sh b/pkgs/build-support/cc-wrapper/add-hardening.sh
index b0e39e455ff..a35ff3cb426 100644
--- a/pkgs/build-support/cc-wrapper/add-hardening.sh
+++ b/pkgs/build-support/cc-wrapper/add-hardening.sh
@@ -6,7 +6,6 @@ if [[ -v hardeningEnable[@] ]]; then
   hardeningFlags+=(${hardeningEnable[@]})
 fi
 hardeningCFlags=()
-hardeningLDFlags=()
 
 declare -A hardeningDisableMap
 
@@ -44,7 +43,6 @@ if [[ -z "${hardeningDisableMap[all]:-}" ]]; then
           if [[ ! ("$*" =~ " -shared " || "$*" =~ " -static ") ]]; then
             if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling LDFlags -pie >&2; fi
             hardeningCFlags+=('-pie')
-            hardeningLDFlags+=('-pie')
           fi
           ;;
         pic)
@@ -59,14 +57,6 @@ if [[ -z "${hardeningDisableMap[all]:-}" ]]; then
           if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling format >&2; fi
           hardeningCFlags+=('-Wformat' '-Wformat-security' '-Werror=format-security')
           ;;
-        relro)
-          if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling relro >&2; fi
-          hardeningLDFlags+=('-z' 'relro')
-          ;;
-        bindnow)
-          if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling bindnow >&2; fi
-          hardeningLDFlags+=('-z' 'now')
-          ;;
         *)
           # Ignore unsupported. Checked in Nix that at least *some*
           # tool supports each flag.
diff --git a/pkgs/build-support/cc-wrapper/cc-wrapper.sh b/pkgs/build-support/cc-wrapper/cc-wrapper.sh
index df1afef3374..c2e6c140635 100644
--- a/pkgs/build-support/cc-wrapper/cc-wrapper.sh
+++ b/pkgs/build-support/cc-wrapper/cc-wrapper.sh
@@ -17,6 +17,12 @@ fi
 
 source @out@/nix-support/utils.sh
 
+# Flirting with a layer violation here.
+if [ -z "${NIX_BINTOOLS_WRAPPER_@infixSalt@_FLAGS_SET:-}" ]; then
+    source @bintools@/nix-support/add-flags.sh
+fi
+
+# Put this one second so libc ldflags take priority.
 if [ -z "${NIX_CC_WRAPPER_@infixSalt@_FLAGS_SET:-}" ]; then
     source @out@/nix-support/add-flags.sh
 fi
diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix
index b79697b33f0..f554a2425dd 100644
--- a/pkgs/build-support/cc-wrapper/default.nix
+++ b/pkgs/build-support/cc-wrapper/default.nix
@@ -28,6 +28,17 @@ let
   stdenv = stdenvNoCC;
   inherit (stdenv) hostPlatform targetPlatform;
 
+  bintools = import ../bintools-wrapper {
+    bintools = binutils;
+    inherit # name
+      stdenvNoCC nativeTools noLibc nativeLibc nativePrefix
+      libc
+      coreutils shell gnugrep
+      extraPackages extraBuildCommands
+      buildPackages
+      useMacosReexportHack;
+  };
+
   # Prefix for binaries. Customarily ends with a dash separator.
   #
   # TODO(@Ericson2314) Make unconditional, or optional but always true by
@@ -42,7 +53,6 @@ let
   libc_dev = if libc == null then null else getDev libc;
   libc_lib = if libc == null then null else getLib libc;
   cc_solib = getLib cc;
-  binutils_bin = if nativeTools then "" else getBin binutils;
   # The wrapper scripts use 'cat' and 'grep', so we may need coreutils.
   coreutils_bin = if nativeTools then "" else getBin coreutils;
 
@@ -58,21 +68,6 @@ let
   # unstable implementation detail, however.
   infixSalt = dashlessTarget;
 
-  # The dynamic linker has different names on different platforms. This is a
-  # shell glob that ought to match it.
-  dynamicLinker =
-    /**/ if libc == null then null
-    else if targetPlatform.system == "i686-linux"     then "${libc_lib}/lib/ld-linux.so.2"
-    else if targetPlatform.system == "x86_64-linux"   then "${libc_lib}/lib/ld-linux-x86-64.so.2"
-    # ARM with a wildcard, which can be "" or "-armhf".
-    else if (with targetPlatform; isArm && isLinux)   then "${libc_lib}/lib/ld-linux*.so.3"
-    else if targetPlatform.system == "aarch64-linux"  then "${libc_lib}/lib/ld-linux-aarch64.so.1"
-    else if targetPlatform.system == "powerpc-linux"  then "${libc_lib}/lib/ld.so.1"
-    else if targetPlatform.system == "mips64el-linux" then "${libc_lib}/lib/ld.so.1"
-    else if targetPlatform.isDarwin                   then "/usr/lib/dyld"
-    else if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
-    else null;
-
   expand-response-params =
     if buildPackages.stdenv.cc or null != null && buildPackages.stdenv.cc != "/dev/null"
     then import ../expand-response-params { inherit (buildPackages) stdenv; }
@@ -80,6 +75,14 @@ let
 
 in
 
+# Ensure bintools matches
+assert libc_bin == bintools.libc_bin;
+assert libc_dev == bintools.libc_dev;
+assert libc_lib == bintools.libc_lib;
+assert nativeTools == bintools.nativeTools;
+assert nativeLibc == bintools.nativeLibc;
+assert nativePrefix == bintools.nativePrefix;
+
 stdenv.mkDerivation {
   name = targetPrefix
     + (if name != "" then name else "${ccName}-wrapper")
@@ -87,8 +90,8 @@ stdenv.mkDerivation {
 
   preferLocalBuild = true;
 
-  inherit cc libc_bin libc_dev libc_lib binutils_bin coreutils_bin;
-  shell = getBin shell + shell.shellPath or "";
+  inherit cc libc_bin libc_dev libc_lib bintools coreutils_bin;
+  shell = getBin shell + stdenv.lib.optionalString (stdenv ? shellPath) stdenv.shellPath;
   gnugrep_bin = if nativeTools then "" else gnugrep;
 
   inherit targetPrefix infixSalt;
@@ -98,20 +101,18 @@ stdenv.mkDerivation {
   passthru = {
     # "cc" is the generic name for a C compiler, but there is no one for package
     # providing the linker and related tools. The two we use now are GNU
-    # Binutils, and Apple's "cctools"; "binutils" as an attempt to find an
+    # Binutils, and Apple's "cctools"; "bintools" as an attempt to find an
     # unused middle-ground name that evokes both.
-    bintools = binutils_bin;
+    inherit bintools;
     inherit libc nativeTools nativeLibc nativePrefix isGNU isClang default_cxx_stdlib_compile;
 
     emacsBufferSetup = pkgs: ''
       ; We should handle propagation here too
-      (mapc (lambda (arg)
-        (when (file-directory-p (concat arg "/include"))
-          (setenv "NIX_${infixSalt}_CFLAGS_COMPILE" (concat (getenv "NIX_${infixSalt}_CFLAGS_COMPILE") " -isystem " arg "/include")))
-        (when (file-directory-p (concat arg "/lib"))
-          (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib")))
-        (when (file-directory-p (concat arg "/lib64"))
-          (setenv "NIX_${infixSalt}_LDFLAGS" (concat (getenv "NIX_${infixSalt}_LDFLAGS") " -L" arg "/lib64")))) '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
+      (mapc
+        (lambda (arg)
+          (when (file-directory-p (concat arg "/include"))
+            (setenv "NIX_${infixSalt}_CFLAGS_COMPILE" (concat (getenv "NIX_${infixSalt}_CFLAGS_COMPILE") " -isystem " arg "/include"))))
+        '(${concatStringsSep " " (map (pkg: "\"${pkg}\"") pkgs)}))
     '';
   };
 
@@ -141,45 +142,18 @@ stdenv.mkDerivation {
       echo ${if targetPlatform.isDarwin then cc else nativePrefix} > $out/nix-support/orig-cc
 
       ccPath="${if targetPlatform.isDarwin then cc else nativePrefix}/bin"
-      ldPath="${nativePrefix}/bin"
     '' else ''
       echo $cc > $out/nix-support/orig-cc
 
       ccPath="${cc}/bin"
-      ldPath="${binutils_bin}/bin"
-    ''
-
-    + optionalString (targetPlatform.isSunOS && nativePrefix != "") ''
-      # Solaris needs an additional ld wrapper.
-      ldPath="${nativePrefix}/bin"
-      exec="$ldPath/${targetPrefix}ld"
-      wrap ld-solaris ${./ld-solaris-wrapper.sh}
     '')
 
     + ''
-      # Create a symlink to as (the assembler).  This is useful when a
-      # cc-wrapper is installed in a user environment, as it ensures that
-      # the right assembler is called.
-      if [ -e $ldPath/${targetPrefix}as ]; then
-        ln -s $ldPath/${targetPrefix}as $out/bin/${targetPrefix}as
-      fi
-
-    '' + (if !useMacosReexportHack then ''
-      wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
-    '' else ''
-      ldInner="${targetPrefix}ld-reexport-delegate"
-      wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${targetPrefix}ld}
-      wrap "${targetPrefix}ld" ${./ld-wrapper.sh} "$out/bin/$ldInner"
-      unset ldInner
-    '') + ''
-
-      if [ -e ${binutils_bin}/bin/${targetPrefix}ld.gold ]; then
-        wrap ${targetPrefix}ld.gold ${./ld-wrapper.sh} ${binutils_bin}/bin/${targetPrefix}ld.gold
-      fi
-
-      if [ -e ${binutils_bin}/bin/ld.bfd ]; then
-        wrap ${targetPrefix}ld.bfd ${./ld-wrapper.sh} ${binutils_bin}/bin/${targetPrefix}ld.bfd
-      fi
+      # Create symlinks to everything in the bintools wrapper.
+      for bbin in $bintools/bin/*; do
+        mkdir -p "$out/bin"
+        ln -s "$bbin" "$out/bin/$(basename $bbin)"
+      done
 
       # We export environment variables pointing to the wrapped nonstandard
       # cmds, lest some lousy configure script use those to guess compiler
@@ -239,16 +213,28 @@ stdenv.mkDerivation {
       ln -s $ccPath/${targetPrefix}ghdl $out/bin/${targetPrefix}ghdl
     '';
 
-  propagatedBuildInputs = extraPackages;
+  propagatedBuildInputs = [ bintools ] ++ extraPackages;
 
   setupHook = ./setup-hook.sh;
 
   postFixup =
     ''
       set -u
+
+      # Backwards compatability for packages expecting this file, e.g. with
+      # `$NIX_CC/nix-support/dynamic-linker`.
+      #
+      # TODO(@Ericson2314): Remove this after stable release and force
+      # everyone to refer to bintools-wrapper directly.
+      if [[ -f "$bintools/nix-support/dynamic-linker" ]]; then
+        ln -s "$bintools/nix-support/dynamic-linker" "$out/nix-support"
+      fi
+      if [[ -f "$bintools/nix-support/dynamic-linker-m32" ]]; then
+        ln -s "$bintools/nix-support/dynamic-linker-m32" "$out/nix-support"
+      fi
     ''
 
-    + optionalString (libc != null) (''
+    + optionalString (libc != null) ''
       ##
       ## General libc support
       ##
@@ -266,48 +252,9 @@ stdenv.mkDerivation {
       # another -idirafter is necessary to add that directory again.
       echo "-B${libc_lib}/lib/ -idirafter ${libc_dev}/include -idirafter ${cc}/lib/gcc/*/*/include-fixed" > $out/nix-support/libc-cflags
 
-      echo "-L${libc_lib}/lib" > $out/nix-support/libc-ldflags
-
       echo "${libc_lib}" > $out/nix-support/orig-libc
       echo "${libc_dev}" > $out/nix-support/orig-libc-dev
-
-      ##
-      ## Dynamic linker support
-      ##
-
-      if [[ -z ''${dynamicLinker+x} ]]; then
-        echo "Don't know the name of the dynamic linker for platform '${targetPlatform.config}', so guessing instead." >&2
-        local dynamicLinker="${libc_lib}/lib/ld*.so.?"
-      fi
-
-      # Expand globs to fill array of options
-      dynamicLinker=($dynamicLinker)
-
-      case ''${#dynamicLinker[@]} in
-        0) echo "No dynamic linker found for platform '${targetPlatform.config}'." >&2;;
-        1) echo "Using dynamic linker: '$dynamicLinker'" >&2;;
-        *) echo "Multiple dynamic linkers found for platform '${targetPlatform.config}'." >&2;;
-      esac
-
-      if [ -n "''${dynamicLinker:-}" ]; then
-        echo $dynamicLinker > $out/nix-support/dynamic-linker
-
-    '' + (if targetPlatform.isDarwin then ''
-        printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
-    '' else ''
-        if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then
-          echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
-        fi
-
-        local ldflagsBefore=(-dynamic-linker "$dynamicLinker")
-    '') + ''
-      fi
-
-      # The dynamic linker is passed in `ldflagsBefore' to allow
-      # explicit overrides of the dynamic linker by callers to gcc/ld
-      # (the *last* value counts, so ours should come first).
-      printWords "''${ldflagsBefore[@]}" > $out/nix-support/libc-ldflags-before
-    '')
+    ''
 
     + optionalString (!nativeTools) ''
 
@@ -348,7 +295,6 @@ stdenv.mkDerivation {
       # Propagate the wrapped cc so that if you install the wrapper,
       # you get tools like gcov, the manpages, etc. as well (including
       # for binutils and Glibc).
-      printWords ${cc} ${binutils_bin} ${if libc == null then "" else libc_bin} > $out/nix-support/propagated-user-env-packages
       printWords ${cc.man or ""}  > $man/nix-support/propagated-user-env-packages
     ''
 
@@ -358,14 +304,7 @@ stdenv.mkDerivation {
       ## Hardening support
       ##
 
-      # some linkers on some platforms don't support specific -z flags
       export hardening_unsupported_flags=""
-      if [[ "$($ldPath/${targetPrefix}ld -z now 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
-        hardening_unsupported_flags+=" bindnow"
-      fi
-      if [[ "$($ldPath/${targetPrefix}ld -z relro 2>&1 || true)" =~ un(recognized|known)\ option ]]; then
-        hardening_unsupported_flags+=" relro"
-      fi
     ''
 
     + optionalString hostPlatform.isCygwin ''
@@ -384,7 +323,7 @@ stdenv.mkDerivation {
     ''
     + extraBuildCommands;
 
-  inherit dynamicLinker expand-response-params;
+  inherit expand-response-params;
 
   # for substitution in utils.sh
   expandResponseParams = "${expand-response-params}/bin/expand-response-params";
@@ -395,7 +334,5 @@ stdenv.mkDerivation {
     { description =
         stdenv.lib.attrByPath ["meta" "description"] "System C compiler" cc_
         + " (wrapper script)";
-  } // optionalAttrs useMacosReexportHack {
-    platforms = stdenv.lib.platforms.darwin;
   };
 }
diff --git a/pkgs/build-support/cc-wrapper/setup-hook.sh b/pkgs/build-support/cc-wrapper/setup-hook.sh
index 7822b7f84d0..a922193ad2e 100644
--- a/pkgs/build-support/cc-wrapper/setup-hook.sh
+++ b/pkgs/build-support/cc-wrapper/setup-hook.sh
@@ -74,14 +74,6 @@ ccWrapper_addCVars () {
         export NIX_${role}CFLAGS_COMPILE+=" ${ccIncludeFlag:--isystem} $1/include"
     fi
 
-    if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then
-        export NIX_${role}LDFLAGS+=" -L$1/lib64"
-    fi
-
-    if [[ -d "$1/lib" ]]; then
-        export NIX_${role}LDFLAGS+=" -L$1/lib"
-    fi
-
     if [[ -d "$1/Library/Frameworks" ]]; then
         export NIX_${role}CFLAGS_COMPILE+=" -F$1/Library/Frameworks"
     fi
@@ -119,11 +111,6 @@ if [ -n "@cc@" ]; then
 fi
 
 # shellcheck disable=SC2157
-if [ -n "@binutils_bin@" ]; then
-    addToSearchPath _PATH @binutils_bin@/bin
-fi
-
-# shellcheck disable=SC2157
 if [ -n "@libc_bin@" ]; then
     addToSearchPath _PATH @libc_bin@/bin
 fi
@@ -142,17 +129,5 @@ export ${role_pre}CXX=@named_cxx@
 export CC${role_post}=@named_cc@
 export CXX${role_post}=@named_cxx@
 
-for cmd in \
-    ar as ld nm objcopy objdump readelf ranlib strip strings size windres
-do
-    if
-        PATH=$_PATH type -p "@targetPrefix@${cmd}" > /dev/null
-    then
-        upper_case="$(echo "$cmd" | tr "[:lower:]" "[:upper:]")"
-        export "${role_pre}${upper_case}=@targetPrefix@${cmd}";
-        export "${upper_case}${role_post}=@targetPrefix@${cmd}";
-    fi
-done
-
 # No local scope in sourced file
-unset -v role_pre role_post cmd upper_case
+unset -v role_pre role_post
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index d947009defb..d66c4dcd76d 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -5618,6 +5618,7 @@ with pkgs;
         crossStageStatic = true;
         langCC = false;
         libcCross = libcCross1;
+        targetPackages.stdenv.cc.bintools = binutils;
         enableShared = false;
       };
       libc = libcCross1;