Files
simplex-chat/scripts/nix/check-elf-comdat-functions.nix
T

111 lines
5.6 KiB
Nix

{ pkgs, compiler }:
assert pkgs.stdenv.hostPlatform.isLinux && pkgs.stdenv.hostPlatform.isx86_64;
let
source = pkgs.applyPatches {
name = "ghc914-rts-single-function-comdat";
src = compiler.configured-src + "/rts";
patches = [ ./ghc914-rts-elf-comdat-functions.patch ];
};
in pkgs.runCommandCC "ghc914-elf-comdat-functions-check" {} ''
set -euo pipefail
mkdir -p "$out"
includes=()
for package in rts rts-headers rts-fs libffi-clib; do
${compiler}/bin/ghc-pkg field "$package" include-dirs --simple-output \
> "$out/$package-include-dirs.txt"
for dir in $(cat "$out/$package-include-dirs.txt"); do
includes+=("-I$dir")
done
done
# Use one consistent set of private headers; installed copies also carry
# pragma-once headers which must not be included as distinct source files.
# The upstream RTS uses GNU C extensions. The fixture itself is assembly.
for variant in baseline patched; do
if [ "$variant" = baseline ]; then tree=${compiler.configured-src}/rts; else tree=${source}; fi
mkdir -p "$out/$variant-objects"
for file in linker/Elf.c Linker.c; do
object=$(basename "$file" .c)
$CC -std=gnu11 -Werror=vla -pedantic -Wall -Wextra -O2 -fPIC \
-mno-avx -mno-avx2 -DCOMPILING_RTS -DINTERNAL_LIBFFI -DFS_NAMESPACE=rts \
-iquote "$tree" -iquote "$tree/linker" \
"''${includes[@]}" -I"$tree" \
-c "$tree/$file" -o "$out/$variant-objects/$object.o" \
2>&1 | tee "$out/$variant-$object-compile.log"
done
done
cp ${./elf-comdat/Probe.hs} Probe.hs
for variant in baseline patched; do
${compiler}/bin/ghc -ignore-dot-ghci -package ghci -j1 -O0 Probe.hs \
"$out/$variant-objects/Elf.o" "$out/$variant-objects/Linker.o" \
-o "$out/$variant" -optl-Wl,-Map="$out/$variant.map"
if grep -E '\.a\((Elf|Linker)\.o\)' "$out/$variant.map"; then
echo 'Original RTS linker object was unexpectedly extracted' >&2
exit 1
fi
done
for variant in a b; do
if [ "$variant" = a ]; then value=17; addend=100; else value=29; addend=200; fi
common=(-DPROBE_VALUE=$value -DPROBE_READER=reader_$variant -DPROBE_ADDEND=$addend -DPROBE_EXTRA=extra_$variant)
for kind in comdat zero-size zero-local-label zero-extra-function zero-extra-object zero-extra-global zero-extra-weak partial strong plain-group different-signature weak; do
flags=(-DGROUP_SIGNATURE=comdat_function)
case "$kind" in
zero-size) flags+=(-DZERO_SIZE_FUNCTION) ;;
zero-local-label) flags+=(-DZERO_SIZE_FUNCTION -DEXTRA_LOCAL_LABEL) ;;
zero-extra-function) flags+=(-DZERO_SIZE_FUNCTION -DEXTRA_FUNCTION) ;;
zero-extra-object) flags+=(-DZERO_SIZE_FUNCTION -DEXTRA_OBJECT) ;;
zero-extra-global) flags+=(-DZERO_SIZE_FUNCTION -DEXTRA_GLOBAL) ;;
zero-extra-weak) flags+=(-DZERO_SIZE_FUNCTION -DEXTRA_WEAK) ;;
partial) flags+=(-DPARTIAL_FUNCTION) ;;
strong) flags+=(-DNO_GROUP) ;;
plain-group) flags+=(-DPLAIN_GROUP) ;;
different-signature) flags=(-DGROUP_SIGNATURE=other_signature -DOTHER_SIGNATURE) ;;
weak) flags+=(-DNO_GROUP -DWEAK_FUNCTION) ;;
esac
$CC -c "''${common[@]}" "''${flags[@]}" ${./elf-comdat/fixture.S} \
-o "$out/$kind-$variant.o"
done
$AR rc "$out/comdat-$variant.a" "$out/comdat-$variant.o"
done
$CC -c -DNO_GROUP -DGROUP_SIGNATURE=comdat_function \
-DPROBE_VALUE=41 -DPROBE_READER=reader_strong -DPROBE_ADDEND=300 \
${./elf-comdat/fixture.S} -o "$out/strong-third.o"
expect_failure() {
name=$1; shift
status=0
timeout 15s "$@" > "$out/$name.log" 2>&1 || status=$?
if [ "$status" -ne 1 ]; then
echo "Expected ordinary failure for $name, got status $status" >&2
exit 1
fi
grep -F 'duplicate definition for symbol' "$out/$name.log"
grep -F 'comdat_function' "$out/$name.log"
}
expect_failure baseline-comdat "$out/baseline" "$out/comdat-a.o" "$out/comdat-b.o"
expect_failure baseline-zero-size "$out/baseline" "$out/zero-size-a.o" "$out/zero-size-b.o"
timeout 15s "$out/patched" "$out/comdat-a.o" "$out/comdat-b.o" | tee "$out/comdat.txt"
grep -Fx '[17,117,217]' "$out/comdat.txt"
timeout 15s "$out/patched" "$out/comdat-b.o" "$out/comdat-a.o" | tee "$out/comdat-reversed.txt"
grep -Fx '[29,129,229]' "$out/comdat-reversed.txt"
for kind in zero-size zero-local-label zero-mixed; do
if [ "$kind" = zero-mixed ]; then first=zero-size; second=comdat; else first=$kind; second=$kind; fi
timeout 15s "$out/patched" "$out/$first-a.o" "$out/$second-b.o" | tee "$out/$kind.txt"
grep -Fx '[17,117,217]' "$out/$kind.txt"
timeout 15s "$out/patched" "$out/$second-b.o" "$out/$first-a.o" | tee "$out/$kind-reversed.txt"
grep -Fx '[29,129,229]' "$out/$kind-reversed.txt"
done
for executable in baseline patched; do
timeout 15s "$out/$executable" "$out/weak-a.o" "$out/weak-b.o" | tee "$out/$executable-weak.txt"
grep -Fx '[17,117,217]' "$out/$executable-weak.txt"
done
for kind in strong plain-group partial zero-extra-function zero-extra-object zero-extra-global zero-extra-weak; do
expect_failure "$kind" "$out/patched" "$out/$kind-a.o" "$out/$kind-b.o"
done
expect_failure different-signature "$out/patched" "$out/different-signature-a.o" "$out/comdat-b.o"
expect_failure mixed-comdat-first "$out/patched" "$out/comdat-a.o" "$out/strong-b.o"
expect_failure mixed-strong-first "$out/patched" "$out/strong-a.o" "$out/comdat-b.o"
expect_failure archive-owner-change "$out/patched" --archive-conflict \
"$out/comdat-a.a" "$out/comdat-b.a" "$out/strong-third.o"
printf '%s\n' 'PASS: scoped COMDAT coalescing preserves relocations and strong conflicts' \
| tee "$out/result.txt"
''