#!/bin/sh set -eu : "${CPU_AS:?}" "${CPU_LD:?}" "${CPU_RUN:?}" "${CPU_READELF:?}" TMP=${TMPDIR:-/tmp}/libmcpu-link-needed-$$ HOME="$TMP/home" export HOME mkdir -p "$HOME/.mcpu/etc" "$TMP/root/lib" "$TMP/first" trap 'rm -rf "$TMP"' EXIT HUP INT TERM cat > "$TMP/main.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 cat > "$TMP/good.s" <<'EOS' .global foo .text foo: LDI r64@0x00008, 2 IADD r64@0x00000, r64@0x00000, r64@0x00008 RET EOS cat > "$TMP/alt.s" <<'EOS' .global foo .text foo: LDI r64@0x00008, 3 IADD r64@0x00000, r64@0x00000, r64@0x00008 RET EOS cat > "$TMP/bad.s" <<'EOS' .global other .text other: RET EOS "$CPU_AS" -o "$TMP/main.o" "$TMP/main.s" "$CPU_AS" -o "$TMP/good.o" "$TMP/good.s" "$CPU_AS" -o "$TMP/alt.o" "$TMP/alt.s" "$CPU_AS" -o "$TMP/bad.o" "$TMP/bad.s" # The development link name is libfoo.so, but the ABI identity recorded in # DT_NEEDED comes from the validated library SONAME. "$CPU_LD" --shared --soname=libfoo.so.1 \ -o "$TMP/root/lib/libfoo.so.1.2.3" "$TMP/good.o" ln -s libfoo.so.1.2.3 "$TMP/root/lib/libfoo.so.1" ln -s libfoo.so.1 "$TMP/root/lib/libfoo.so" "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L"$TMP/root/lib" -lfoo -o "$TMP/main" "$TMP/main.o" "$CPU_READELF" -d "$TMP/main" > "$TMP/main.dynamic" grep -q 'NEEDED.*\[libfoo.so.1\]' "$TMP/main.dynamic" [ "`grep -c 'NEEDED' "$TMP/main.dynamic"`" -eq 1 ] if grep -q 'libfoo.so.1.2.3' "$TMP/main.dynamic"; then echo "DT_NEEDED unexpectedly contains physical library filename" >&2 exit 1 fi # The separated -l NAME spelling is equivalent. "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L "$TMP/root/lib" -l foo -o "$TMP/main-separated" "$TMP/main.o" "$CPU_READELF" -d "$TMP/main-separated" | grep -q 'NEEDED.*\[libfoo.so.1\]' # Repeated requests resolving to the same SONAME produce one dependency. "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L"$TMP/root/lib" -lfoo -lfoo -o "$TMP/main-duplicate" "$TMP/main.o" "$CPU_READELF" -d "$TMP/main-duplicate" > "$TMP/main-duplicate.dynamic" [ "`grep -c 'NEEDED' "$TMP/main-duplicate.dynamic"`" -eq 1 ] # -L order is real link-name search order. The selected object's SONAME, # not the requested link name, is recorded. "$CPU_LD" --shared --soname=libfoo-alt.so.7 \ -o "$TMP/first/libfoo.so" "$TMP/alt.o" "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L"$TMP/first" -L"$TMP/root/lib" -lfoo \ -o "$TMP/main-first" "$TMP/main.o" "$CPU_READELF" -d "$TMP/main-first" | grep -q 'NEEDED.*\[libfoo-alt.so.7\]' # The configured system library tree is also used by -l. cat > "$HOME/.mcpu/etc/mcpu-ld.conf" < "$TMP/child.dynamic" grep -q 'SONAME.*\[libchild.so.1\]' "$TMP/child.dynamic" grep -q 'NEEDED.*\[libfoo.so.1\]' "$TMP/child.dynamic" # A named dependency must exist and must be a valid ABI-v3 ET_DYN object. if "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L"$TMP/root/lib" -lmissing -o "$TMP/missing" "$TMP/main.o" \ >/dev/null 2>&1; then echo "missing -l dependency unexpectedly linked" >&2 exit 1 fi cp "$TMP/main" "$TMP/root/lib/libexec.so" if "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L"$TMP/root/lib" -lexec -o "$TMP/from-exec" "$TMP/main.o" \ >/dev/null 2>&1; then echo "ET_EXEC unexpectedly accepted as -l provider" >&2 exit 1 fi # Existing file, valid shared object, wrong exports: link must fail before # producing an executable. "$CPU_LD" --shared --soname=libbad.so.1 \ -o "$TMP/root/lib/libbad.so" "$TMP/bad.o" rm -f "$TMP/no-provider" if "$CPU_LD" --dynamic --stack-size=4096 --no-heap \ -L"$TMP/root/lib" -lbad -o "$TMP/no-provider" "$TMP/main.o" \ >"$TMP/no-provider.out" 2>"$TMP/no-provider.err"; then echo "library without required export unexpectedly linked" >&2 exit 1 fi grep -q 'undefined symbol not provided by linked libraries: foo' \ "$TMP/no-provider.err" [ ! -e "$TMP/no-provider" ] # ABI-v1 -l searches only for a static archive. This directory contains # only libfoo.so, so the static link must fail instead of using ET_DYN. if "$CPU_LD" -L"$TMP/root/lib" -lfoo -o "$TMP/static" "$TMP/main.o" \ >/dev/null 2>&1; then echo "ABI-v1 unexpectedly selected a shared -l provider" >&2 exit 1 fi # 0.2.16 resolves the recorded SONAME at runtime through the same system # library search policy. No explicit --ldpreload is required. [ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/main"`" = 42 ] "$CPU_LD" --help 2>&1 | grep -q -- '-l ' exit 0