#!/bin/sh set -eu : "${CPU_AS:?}" "${CPU_LD:?}" "${CPU_RUN:?}" TMP=${TMPDIR:-/tmp}/libmcpu-env-preload-$$ mkdir -p "$TMP/lib" trap 'rm -rf "$TMP"' EXIT HUP INT TERM cat > "$TMP/main.s" <<'EOS' .global _life .global foo .text _start_life: LDI r64@0x00000, 40 CALL foo MOV r64@0x00018, r64@0x00000 LDI r32@0x00030, 0 EXIT r32@0x00030 foo: LDI r64@0x00008, 1 IADD r64@0x00000, r64@0x00000, r64@0x00008 RET EOS cat > "$TMP/a.s" <<'EOS' .global foo .text foo: LDI r64@0x00008, 2 IADD r64@0x00000, r64@0x00000, r64@0x00008 RET EOS cat > "$TMP/b.s" <<'EOS' .global foo .text foo: LDI r64@0x00008, 3 IADD r64@0x00000, r64@0x00000, r64@0x00008 RET EOS "$CPU_AS" -o "$TMP/main.o" "$TMP/main.s" "$CPU_AS" -o "$TMP/a.o" "$TMP/a.s" "$CPU_AS" -o "$TMP/b.o" "$TMP/b.s" "$CPU_LD" --dynamic --stack-size=4096 --no-heap -o "$TMP/main" "$TMP/main.o" "$CPU_LD" --shared --soname=liba.so.1 -o "$TMP/lib/liba.so.1" "$TMP/a.o" "$CPU_LD" --shared --soname=libb.so.1 -o "$TMP/lib/libb.so.1" "$TMP/b.o" ln -s liba.so.1 "$TMP/lib/liba.so" ln -s libb.so.1 "$TMP/lib/libb.so" # Empty environment is the normal no-preload baseline. [ "`MCPU_LD_PRELOAD= "$CPU_RUN" --library-path="$TMP/lib" \ --int-reg=r64@0x00018 "$TMP/main"`" = 41 ] # Environment-only preload uses the same resolver and rightmost-wins ordering. [ "`MCPU_LD_PRELOAD=liba.so "$CPU_RUN" --library-path="$TMP/lib" \ --int-reg=r64@0x00018 "$TMP/main"`" = 42 ] [ "`MCPU_LD_PRELOAD=liba.so:libb.so "$CPU_RUN" --library-path="$TMP/lib" \ --int-reg=r64@0x00018 "$TMP/main"`" = 43 ] [ "`MCPU_LD_PRELOAD=libb.so:liba.so "$CPU_RUN" --library-path="$TMP/lib" \ --int-reg=r64@0x00018 "$TMP/main"`" = 42 ] # Command-line preload entries are appended after environment entries, so the # established rightmost-higher-priority rule makes command line stronger. [ "`MCPU_LD_PRELOAD=liba.so "$CPU_RUN" --library-path="$TMP/lib" \ --ldpreload=libb.so --int-reg=r64@0x00018 "$TMP/main"`" = 43 ] [ "`MCPU_LD_PRELOAD=libb.so "$CPU_RUN" --library-path="$TMP/lib" \ --ldpreload=liba.so --int-reg=r64@0x00018 "$TMP/main"`" = 42 ] [ "`MCPU_LD_PRELOAD=liba.so:libb.so "$CPU_RUN" --library-path="$TMP/lib" \ --ldpreload=libb.so:liba.so --int-reg=r64@0x00018 "$TMP/main"`" = 42 ] # Environment preload is equivalent to --ldpreload for ABI compatibility: an # ABI-v1 static executable must reject it just as it rejects the CLI option. "$CPU_LD" --stack-size=4096 --no-heap -o "$TMP/static" "$TMP/main.o" if MCPU_LD_PRELOAD="$TMP/lib/liba.so.1" "$CPU_RUN" "$TMP/static" \ >/dev/null 2>"$TMP/static.err"; then echo "ABI-v1 executable unexpectedly accepted MCPU_LD_PRELOAD" >&2 exit 1 fi grep -q 'dynamic modules require' "$TMP/static.err" # The environment preload is independent of configuration suppression. An # explicit pathname therefore still works under --no-config. [ "`MCPU_LD_PRELOAD="$TMP/lib/liba.so.1" "$CPU_RUN" --no-config \ --int-reg=r64@0x00018 "$TMP/main"`" = 42 ] # Environment preload remains an explicit override above a normal dependency. cat > "$TMP/import.s" <<'EOS' .global _life .extern foo .text _start_life: LDI r64@0x00000, 40 CALL foo MOV r64@0x00018, r64@0x00000 LDI r32@0x00030, 0 EXIT r32@0x00030 EOS "$CPU_AS" -o "$TMP/import.o" "$TMP/import.s" "$CPU_LD" --dynamic --stack-size=4096 --no-heap -L"$TMP/lib" -la \ -o "$TMP/import" "$TMP/import.o" [ "`MCPU_LD_PRELOAD=libb.so "$CPU_RUN" --library-path="$TMP/lib" \ --int-reg=r64@0x00018 "$TMP/import"`" = 43 ] # Invalid environment lists and missing names are hard errors. if MCPU_LD_PRELOAD=liba.so::libb.so "$CPU_RUN" --library-path="$TMP/lib" \ "$TMP/main" >/dev/null 2>"$TMP/bad-list.err"; then echo "malformed MCPU_LD_PRELOAD unexpectedly accepted" >&2 exit 1 fi grep -q 'MCPU_LD_PRELOAD' "$TMP/bad-list.err" if MCPU_LD_PRELOAD=does-not-exist.so "$CPU_RUN" --library-path="$TMP/lib" \ "$TMP/main" >/dev/null 2>"$TMP/missing.err"; then echo "missing MCPU_LD_PRELOAD library unexpectedly accepted" >&2 exit 1 fi grep -q 'MCPU_LD_PRELOAD' "$TMP/missing.err" MCPU_LD_PRELOAD= "$CPU_RUN" --help 2>&1 | grep -q 'MCPU_LD_PRELOAD' exit 0