summaryrefslogtreecommitdiff
path: root/tests/tst-symbol-scope-runner.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-symbol-scope-runner.sh')
-rwxr-xr-xtests/tst-symbol-scope-runner.sh276
1 files changed, 276 insertions, 0 deletions
diff --git a/tests/tst-symbol-scope-runner.sh b/tests/tst-symbol-scope-runner.sh
new file mode 100755
index 0000000..8a4154e
--- /dev/null
+++ b/tests/tst-symbol-scope-runner.sh
@@ -0,0 +1,276 @@
+#!/bin/sh
+set -eu
+
+: "${CPU_AS:?}" "${CPU_LD:?}" "${CPU_RUN:?}"
+
+TMP=${TMPDIR:-/tmp}/libmcpu-symbol-scope-$$
+mkdir -p "$TMP/lib"
+trap 'rm -rf "$TMP"' EXIT HUP INT TERM
+
+cat > "$TMP/main-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
+
+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-import.o" "$TMP/main-import.s"
+"$CPU_AS" -o "$TMP/a.o" "$TMP/a.s"
+"$CPU_AS" -o "$TMP/b.o" "$TMP/b.s"
+"$CPU_LD" --shared --soname=liba.so.1 -o "$TMP/lib/liba.so.1.0.0" "$TMP/a.o"
+"$CPU_LD" --shared --soname=libb.so.1 -o "$TMP/lib/libb.so.1.0.0" "$TMP/b.o"
+ln -s liba.so.1.0.0 "$TMP/lib/liba.so.1"
+ln -s liba.so.1 "$TMP/lib/liba.so"
+ln -s libb.so.1.0.0 "$TMP/lib/libb.so.1"
+ln -s libb.so.1 "$TMP/lib/libb.so"
+
+# Normal DT_NEEDED scope is breadth-first and left-to-right. For equal
+# GLOBAL definitions the first direct dependency wins.
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
+ -L"$TMP/lib" -la -lb -o "$TMP/main-ab" "$TMP/main-import.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --int-reg=r64@0x00018 "$TMP/main-ab"`" = 42 ]
+
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
+ -L"$TMP/lib" -lb -la -o "$TMP/main-ba" "$TMP/main-import.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --int-reg=r64@0x00018 "$TMP/main-ba"`" = 43 ]
+
+# A main-executable GLOBAL outranks normal dependencies.
+cat > "$TMP/main-own.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
+"$CPU_AS" -o "$TMP/main-own.o" "$TMP/main-own.s"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
+ -L"$TMP/lib" -la -o "$TMP/main-own" "$TMP/main-own.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --int-reg=r64@0x00018 "$TMP/main-own"`" = 41 ]
+
+# Explicit preload is the intentional override scope. Equal-strength GLOBAL
+# preloads keep the historical rightmost-higher-priority rule.
+[ "`"$CPU_RUN" --library-path="$TMP/lib" \
+ --ldpreload=liba.so:libb.so \
+ --int-reg=r64@0x00018 "$TMP/main-own"`" = 43 ]
+[ "`"$CPU_RUN" --library-path="$TMP/lib" \
+ --ldpreload=libb.so:liba.so \
+ --int-reg=r64@0x00018 "$TMP/main-own"`" = 42 ]
+
+# Binding strength outranks scope class: a WEAK preload must not preempt a
+# normal GLOBAL definition.
+cat > "$TMP/weak.s" <<'EOS'
+.weak foo
+.text
+foo:
+ LDI r64@0x00008, 9
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+"$CPU_AS" -o "$TMP/weak.o" "$TMP/weak.s"
+"$CPU_LD" --shared --soname=libweak.so.1 -o "$TMP/libweak.so" "$TMP/weak.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --ldpreload="$TMP/libweak.so" \
+ --int-reg=r64@0x00018 "$TMP/main-ab"`" = 42 ]
+
+# If only WEAK definitions exist, the same scope ordering applies: first normal
+# dependency wins, while rightmost explicit preload wins.
+cat > "$TMP/weak-main.s" <<'EOS'
+.global _life
+.weak 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/wa.s" <<'EOS'
+.weak foo
+.text
+foo:
+ LDI r64@0x00008, 2
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/wb.s" <<'EOS'
+.weak foo
+.text
+foo:
+ LDI r64@0x00008, 3
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+"$CPU_AS" -o "$TMP/weak-main.o" "$TMP/weak-main.s"
+"$CPU_AS" -o "$TMP/wa.o" "$TMP/wa.s"
+"$CPU_AS" -o "$TMP/wb.o" "$TMP/wb.s"
+"$CPU_LD" --shared --soname=libwa.so.1 -o "$TMP/lib/libwa.so.1" "$TMP/wa.o"
+"$CPU_LD" --shared --soname=libwb.so.1 -o "$TMP/lib/libwb.so.1" "$TMP/wb.o"
+ln -s libwa.so.1 "$TMP/lib/libwa.so"
+ln -s libwb.so.1 "$TMP/lib/libwb.so"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
+ -L"$TMP/lib" -lwa -lwb -o "$TMP/weak-main" "$TMP/weak-main.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --int-reg=r64@0x00018 "$TMP/weak-main"`" = 42 ]
+[ "`"$CPU_RUN" --ldpreload="$TMP/lib/libwa.so.1:$TMP/lib/libwb.so.1" \
+ --int-reg=r64@0x00018 "$TMP/weak-main"`" = 43 ]
+
+# A direct dependency outranks a conflicting transitive dependency. The
+# resolver must therefore build a true breadth-first scope rather than expose
+# DFS traversal order to symbol resolution.
+cat > "$TMP/deep.s" <<'EOS'
+.global deep_anchor
+.global foo
+.text
+deep_anchor:
+ RET
+foo:
+ LDI r64@0x00008, 9
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/mid.s" <<'EOS'
+.global mid_anchor
+.extern deep_anchor
+.text
+mid_anchor:
+ CALL deep_anchor
+ RET
+EOS
+cat > "$TMP/direct.s" <<'EOS'
+.global foo
+.text
+foo:
+ LDI r64@0x00008, 3
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/bfs-main.s" <<'EOS'
+.global _life
+.extern mid_anchor
+.extern foo
+.text
+_start_life:
+ LDI r64@0x00000, 40
+ CALL mid_anchor
+ CALL foo
+ MOV r64@0x00018, r64@0x00000
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+"$CPU_AS" -o "$TMP/deep.o" "$TMP/deep.s"
+"$CPU_AS" -o "$TMP/mid.o" "$TMP/mid.s"
+"$CPU_AS" -o "$TMP/direct.o" "$TMP/direct.s"
+"$CPU_AS" -o "$TMP/bfs-main.o" "$TMP/bfs-main.s"
+"$CPU_LD" --shared --soname=libdeep.so.1 -o "$TMP/lib/libdeep.so.1.0.0" "$TMP/deep.o"
+ln -s libdeep.so.1.0.0 "$TMP/lib/libdeep.so.1"
+ln -s libdeep.so.1 "$TMP/lib/libdeep.so"
+"$CPU_LD" --shared --soname=libmid.so.1 -L"$TMP/lib" -ldeep \
+ -o "$TMP/lib/libmid.so.1.0.0" "$TMP/mid.o"
+ln -s libmid.so.1.0.0 "$TMP/lib/libmid.so.1"
+ln -s libmid.so.1 "$TMP/lib/libmid.so"
+"$CPU_LD" --shared --soname=libdirect.so.1 -o "$TMP/lib/libdirect.so.1.0.0" "$TMP/direct.o"
+ln -s libdirect.so.1.0.0 "$TMP/lib/libdirect.so.1"
+ln -s libdirect.so.1 "$TMP/lib/libdirect.so"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
+ -L"$TMP/lib" -lmid -ldirect -o "$TMP/bfs-main" "$TMP/bfs-main.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --int-reg=r64@0x00018 "$TMP/bfs-main"`" = 43 ]
+
+# Diamond graph: A and B both depend on C. SONAME deduplication loads C once,
+# while the direct A/B scope still follows left-to-right order.
+cat > "$TMP/common.s" <<'EOS'
+.global common_anchor
+.text
+common_anchor:
+ RET
+EOS
+cat > "$TMP/da.s" <<'EOS'
+.global a_anchor
+.global foo
+.extern common_anchor
+.text
+a_anchor:
+ CALL common_anchor
+ RET
+foo:
+ LDI r64@0x00008, 2
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/db.s" <<'EOS'
+.global b_anchor
+.global foo
+.extern common_anchor
+.text
+b_anchor:
+ CALL common_anchor
+ RET
+foo:
+ LDI r64@0x00008, 3
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/diamond-main.s" <<'EOS'
+.global _life
+.extern a_anchor
+.extern b_anchor
+.extern foo
+.text
+_start_life:
+ LDI r64@0x00000, 40
+ CALL a_anchor
+ CALL b_anchor
+ CALL foo
+ MOV r64@0x00018, r64@0x00000
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+"$CPU_AS" -o "$TMP/common.o" "$TMP/common.s"
+"$CPU_AS" -o "$TMP/da.o" "$TMP/da.s"
+"$CPU_AS" -o "$TMP/db.o" "$TMP/db.s"
+"$CPU_AS" -o "$TMP/diamond-main.o" "$TMP/diamond-main.s"
+"$CPU_LD" --shared --soname=libcommon.so.1 -o "$TMP/lib/libcommon.so.1.0.0" "$TMP/common.o"
+ln -s libcommon.so.1.0.0 "$TMP/lib/libcommon.so.1"
+ln -s libcommon.so.1 "$TMP/lib/libcommon.so"
+"$CPU_LD" --shared --soname=libda.so.1 -L"$TMP/lib" -lcommon \
+ -o "$TMP/lib/libda.so.1.0.0" "$TMP/da.o"
+ln -s libda.so.1.0.0 "$TMP/lib/libda.so.1"
+ln -s libda.so.1 "$TMP/lib/libda.so"
+"$CPU_LD" --shared --soname=libdb.so.1 -L"$TMP/lib" -lcommon \
+ -o "$TMP/lib/libdb.so.1.0.0" "$TMP/db.o"
+ln -s libdb.so.1.0.0 "$TMP/lib/libdb.so.1"
+ln -s libdb.so.1 "$TMP/lib/libdb.so"
+"$CPU_LD" --dynamic --stack-size=4096 --no-heap \
+ -L"$TMP/lib" -lda -ldb -o "$TMP/diamond-main" "$TMP/diamond-main.o"
+[ "`"$CPU_RUN" --library-path="$TMP/lib" --int-reg=r64@0x00018 "$TMP/diamond-main"`" = 42 ]
+
+exit 0