diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /tests/tst-link-needed-runner.sh | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'tests/tst-link-needed-runner.sh')
| -rwxr-xr-x | tests/tst-link-needed-runner.sh | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/tests/tst-link-needed-runner.sh b/tests/tst-link-needed-runner.sh new file mode 100755 index 0000000..8f33986 --- /dev/null +++ b/tests/tst-link-needed-runner.sh @@ -0,0 +1,151 @@ +#!/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" <<EOC +MCPU_LD_SYSTEM_LIBRARY_PATH = $TMP/root/lib; +EOC +"$CPU_LD" --dynamic --stack-size=4096 --no-heap \ + -lfoo -o "$TMP/main-config" "$TMP/main.o" +"$CPU_READELF" -d "$TMP/main-config" | grep -q 'NEEDED.*\[libfoo.so.1\]' + +# A shared object may itself record a direct ABI-v3 dependency. +"$CPU_LD" --shared --soname=libchild.so.1 \ + -lfoo -o "$TMP/libchild.so.1.0.0" "$TMP/bad.o" +"$CPU_READELF" -d "$TMP/libchild.so.1.0.0" > "$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 <name>' + +exit 0 |
