summaryrefslogtreecommitdiff
path: root/tests/tst-dynamic-runner.sh
diff options
context:
space:
mode:
authorkx <kx@radix-linux.su>2026-10-09 18:00:15 +0300
committerkx <kx@radix-linux.su>2026-10-09 18:00:15 +0300
commit065da3509019b15dd0e678072e6be629e5330bef (patch)
tree69c934c9e786ac048b4fbe8f4c4c5571661521f4 /tests/tst-dynamic-runner.sh
parentd130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff)
downloadlibmcpu-0.4.0.tar.xz
Version 0.4.00.4.0
Diffstat (limited to 'tests/tst-dynamic-runner.sh')
-rwxr-xr-xtests/tst-dynamic-runner.sh96
1 files changed, 96 insertions, 0 deletions
diff --git a/tests/tst-dynamic-runner.sh b/tests/tst-dynamic-runner.sh
new file mode 100755
index 0000000..2ebc76f
--- /dev/null
+++ b/tests/tst-dynamic-runner.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+set -eu
+: "${CPU_AS:?}" "${CPU_LD:?}" "${CPU_RUN:?}" "${TEST_SRCDIR:?}"
+TMP=${TMPDIR:-/tmp}/libcpu-dynamic-$$
+mkdir -p "$TMP"
+trap 'rm -rf "$TMP"' EXIT HUP INT TERM
+EXAMPLES=`cd "$TEST_SRCDIR/fixtures/shared-libs" && pwd`
+"$CPU_AS" -o "$TMP/main.o" "$EXAMPLES/dynamic-main.s"
+"$CPU_AS" -o "$TMP/a.o" "$EXAMPLES/dynamic-liba.s"
+"$CPU_AS" -o "$TMP/b.o" "$EXAMPLES/dynamic-libb.s"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap -o "$TMP/main-program" "$TMP/main.o"
+"$CPU_LD" --shared --soname=liba.so.1 -o "$TMP/liba.so" "$TMP/a.o"
+"$CPU_LD" --shared --soname=libb.so.1 -o "$TMP/libb.so" "$TMP/b.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/main-program"`" = 41 ]
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 --ldpreload="$TMP/liba.so" "$TMP/main-program"`" = 42 ]
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 --ldpreload="$TMP/liba.so:$TMP/libb.so" "$TMP/main-program"`" = 43 ]
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 --ldpreload="$TMP/libb.so:$TMP/liba.so" "$TMP/main-program"`" = 42 ]
+
+# LOCAL references inside ET_DYN are private to that module, but their
+# section-relative values still need startup rebasing by the module base.
+# local_helper is deliberately not exported. Without LOCAL ET_DYN runtime
+# relocation the CALL below contains the shared-object-relative offset and
+# jumps to the wrong process PROGRAM address after the library is placed
+# behind the executable.
+cat > "$TMP/local-main.s" <<'EOS'
+.global _life
+.extern local_api
+.text
+_start_life:
+ LDI r64@0x00000, 40
+ CALL local_api
+ MOV r64@0x00018, r64@0x00000
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+cat > "$TMP/local-lib.s" <<'EOS'
+.global local_api
+.text
+local_api:
+ CALL local_helper
+ RET
+local_helper:
+ LDI r64@0x00008, 7
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+"$CPU_AS" -o "$TMP/local-main.o" "$TMP/local-main.s"
+"$CPU_AS" -o "$TMP/local-lib.o" "$TMP/local-lib.s"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap -o "$TMP/local-program" "$TMP/local-main.o"
+"$CPU_LD" --shared --soname=local.so.1 -o "$TMP/local.so" "$TMP/local-lib.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 --ldpreload="$TMP/local.so" "$TMP/local-program"`" = 47 ]
+
+# ABI-v1 static executable must reject preload rather than silently relink.
+"$CPU_LD" --stack-size=4096 --no-heap -o "$TMP/static-program" "$TMP/main.o"
+if "$CPU_RUN" --ldpreload="$TMP/liba.so" "$TMP/static-program" >/dev/null 2>&1; then
+ echo "ABI-v1 executable unexpectedly accepted --ldpreload" >&2
+ exit 1
+fi
+
+# An ABI-v3 executable with an unresolved import but no DT_NEEDED provider
+# remains a startup load error. Recursive loading cannot invent dependencies.
+cat > "$TMP/missing.s" <<'EOS'
+.global _life
+.extern missing_function
+.text
+_start_life:
+ CALL missing_function
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+"$CPU_AS" -o "$TMP/missing.o" "$TMP/missing.s"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap -o "$TMP/missing-program" "$TMP/missing.o"
+if "$CPU_RUN" "$TMP/missing-program" >/dev/null 2>&1; then
+ echo "unresolved dynamic symbol unexpectedly reached execution" >&2
+ exit 1
+fi
+
+# Shared objects own no process STACK/HEAP policy.
+if "$CPU_LD" --shared --soname=bad.so.1 --stack-size=4096 -o "$TMP/bad.so" "$TMP/a.o" >/dev/null 2>&1; then
+ echo "cpu-ld --shared unexpectedly accepted --stack-size" >&2
+ exit 1
+fi
+if "$CPU_LD" --shared -o "$TMP/no-soname.so" "$TMP/a.o" >/dev/null 2>&1; then
+ echo "ABI-v3 shared object unexpectedly accepted without SONAME" >&2
+ exit 1
+fi
+if "$CPU_LD" --shared --soname=path/bad.so.1 -o "$TMP/bad-soname.so" "$TMP/a.o" >/dev/null 2>&1; then
+ echo "ABI-v3 shared object unexpectedly accepted pathname SONAME" >&2
+ exit 1
+fi
+if "$CPU_LD" --dynamic --soname=main.so.1 --stack-size=4096 --no-heap \
+ -o "$TMP/bad-main" "$TMP/main.o" >/dev/null 2>&1; then
+ echo "ABI-v3 executable unexpectedly accepted SONAME" >&2
+ exit 1
+fi
+exit 0