Skip to content

Instantly share code, notes, and snippets.

@rrbutani
Created October 29, 2022 11:32
Show Gist options
  • Save rrbutani/92021b86f1cbfd178d2f580bed440aec to your computer and use it in GitHub Desktop.
Save rrbutani/92021b86f1cbfd178d2f580bed440aec to your computer and use it in GitHub Desktop.
nixpkgs darwin stdenv `LC_UUID`
{
inputs = {
nixpkgs.url = github:NixOS/nixpkgs?ref=60b1608ad793c763ffbeabddc95dba7b4ed9cbc8; # nixos-unstable as of this writing
flu.url = github:numtide/flake-utils;
};
outputs = { nixpkgs, flu, self }:
with flu.lib; eachSystem [ "aarch64-darwin" "x86_64-darwin" ] (system: let
# The `nixpkgs` bintools wrapper passes `-no_uuid` to `ld` when targeting
# macOS which causes `ld` to omit `LC_UUID`.
#
# Some tools (crash reporters, debuggers) use this metadata to associate
# binaries with debug info; other tools (like Xcode Instruments) will
# actually refuse to load symbols (dSYM files) if this UUID is not
# present.
#
# `nixpkgs`'s first started to pass `-no_uuid` on macOS here:
# - https://github.com/NixOS/nixpkgs/commit/a826b49c97bcc9d8365b5d18aeec8087116d195d
# - PR: https://github.com/NixOS/nixpkgs/pull/77632
# - context:
# https://github.com/NixOS/nixpkgs/issues/21629#issuecomment-398266212
#
# Since then this flag has migrated from the macOS stdenv to the bintools
# wrapper:
# https://github.com/NixOS/nixpkgs/blob/19f597b8cc2dd2ab41ae77a4ad607876007a7da8/pkgs/build-support/bintools-wrapper/default.nix#L311-L316
#
# The commit linked above claims that the the `LC_UUID` UUID is
# "semi-random" however:
# - LLD appears to use a hash of the output file's contents:
# https://github.com/llvm/llvm-project/blob/efae1a7cf06bd71f7ec6e8dc9e5c2b085150a451/lld/MachO/Writer.cpp#L504-L509
# - as per [this message](https://groups.google.com/a/chromium.org/g/security-dev/c/xAL44GDnaVI)
# and the source code it references, `ld64` from `cctools` appears to
# hash specific parts of the output
# So, in an attempt to find out whether we can safely drop `-no_uuid` from
# the `nixpkgs` bintools wrapper, the below conjures a stdenv with this
# change applied and then checks the resulting UUIDs of some binaries in
# some packages.
#
# Run `nix flake check` on your x86_64 or apple silicon mac to see if the
# UUIDs your machine produces match mine.
# The proper thing to do here would be to use an overlay but we don't want
# to suffer through a full rebuild of everything...
np = nixpkgs.legacyPackages.${system};
stdenv = let
bintools = np.stdenv.cc.bintools.overrideDerivation (attrs: {
# We're looking to undo this bit:
# https://github.com/NixOS/nixpkgs/blob/19f597b8cc2dd2ab41ae77a4ad607876007a7da8/pkgs/build-support/bintools-wrapper/default.nix#L311-L316
postFixup = attrs.postFixup + ''
sed -i 's/-no_uuid//g' $out/nix-support/libc-ldflags-before
'';
});
cc = np.stdenv.cc.override { inherit bintools; };
in np.stdenv.override { inherit cc; allowedRequisites = null; };
# If you do want to suffer through a rebuild..
npAlt = import nixpkgs {
inherit system;
overlays = [(f: p: {
bintools = p.bintools.overrideDerivation (attrs: {
postFixup = attrs.postFixup + ''
sed -i 's/-no_uuid//g' $out/nix-support/libc-ldflags-before
'';
});
})];
config.replaceStdenv = { pkgs }: pkgs.stdenv.override {
cc = pkgs.stdenv.cc.override {
bintools = pkgs.stdenv.cc.bintools.overrideDerivation (attrs: {
postFixup = attrs.postFixup + ''
sed -i 's/-no_uuid//g' $out/nix-support/libc-ldflags-before
'';
});
};
};
};
checkUuidMatches = { package, uuids, mainProgram ? null }: let
pkg = if mainProgram != null then package // { meta = { inherit mainProgram; }; } else package;
isArm = np.targetPlatform.isAarch64;
expected = uuids.${if isArm then "arm" else "x86"};
in np.runCommand
"check-uuid-${pkg.pname or pkg.name}"
{ nativeBuildInputs = [ np.llvmPackages.bintools-unwrapped ]; }
''
set -e
bin="${np.lib.getExe pkg}"
echo "checking '$bin'"
expected="${expected}"
got=$(
llvm-dwarfdump --uuid "$bin" |
grep "${if isArm then "arm64" else "x86_64"}" |
cut -d' ' -f2 |
head -1
)
if [[ $expected != $got ]]; then
echo "expected UUID: '$expected'"
echo "got UUID: '$got'"
exit 2
fi
echo $got > $out
'';
uuidPair = arm: x86: { inherit arm x86; };
packageUuids = {
hello = {
package = np.hello.override { inherit stdenv; };
uuids = uuidPair "FD76B509-06B2-3E8E-A3F8-A73AB271FEA2" "";
};
fortune = {
package = np.fortune.override { inherit stdenv; };
# uuids = uuidPair "30507B82-1901-34E7-8443-942D32EDAB0C" "";
uuids = uuidPair "DF23713F-5604-36DB-82DA-4965E74AE8CC" "";
};
bat = {
# package = np.bat.override { inherit stdenv rustPlatform; };
package = npAlt.bat;
mainProgram = ".bat-wrapped";
uuids = uuidPair "" "";
};
bash = {
# package = np.bash.override { inherit stdenv; binutils = stdenv.cc.bintools; };
package = npAlt.bash;
uuids = uuidPair "" "";
};
};
in rec {
packages = builtins.mapAttrs (_: { package, ... }: package) packageUuids;
checks = builtins.mapAttrs (_: checkUuidMatches) packageUuids;
});
# Unfortunately, testing the above shows that (when using `ld` from
# cctools) the UUID is not stable (change the fixup addendum a bit and
# rebuild the fortune check -- seems to change as the build directory
# changes).
#
# See: https://bugs.chromium.org/p/chromium/issues/detail?id=1068970
# LLD allegedly does not have this issue (a quick read of the relevant
# source in LLD corroborates this).
#
# However the darwin stdenv does not use LLD (though, it could now that
# mach-o support is there in LLD in LLVM14+).
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment