summaryrefslogtreecommitdiff
path: root/tests/tst-partial-link-runner.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tests/tst-partial-link-runner.sh')
-rwxr-xr-xtests/tst-partial-link-runner.sh276
1 files changed, 276 insertions, 0 deletions
diff --git a/tests/tst-partial-link-runner.sh b/tests/tst-partial-link-runner.sh
new file mode 100755
index 0000000..2f08e16
--- /dev/null
+++ b/tests/tst-partial-link-runner.sh
@@ -0,0 +1,276 @@
+#!/bin/bash
+set -e
+
+CPU_AS=${CPU_AS:-../utils/mcpu-as}
+CPU_LD=${CPU_LD:-../utils/mcpu-ld}
+CPU_RUN=${CPU_RUN:-../utils/mcpu-run}
+CPU_READELF=${CPU_READELF:-../utils/mcpu-readelf}
+CPU_AR=${CPU_AR:-../utils/mcpu-ar}
+
+TMP=${TMPDIR:-/tmp}/libmcpu-partial-link-$$
+trap 'rm -rf "$TMP"' EXIT HUP INT TERM
+mkdir -p "$TMP/lib"
+
+cat > "$TMP/main.s" <<'EOS'
+.global _life
+.extern add_two
+.extern shared_value
+.text
+_start_life:
+ LDI r64@0x00000, 40
+ CALL add_two
+ STORE shared_value, r64@0x00000
+ LOAD r64@0x00018, shared_value
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+
+cat > "$TMP/lib.s" <<'EOS'
+.global add_two
+.global shared_value
+.global shared_ptr
+.global add_two_ptr
+.data
+.align 32
+shared_value:
+ .integer 64, 0
+shared_ptr:
+ .ptr shared_value
+add_two_ptr:
+ .cptr add_two
+.text
+add_two:
+ LDI r64@0x00008, 2
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+
+"$CPU_AS" -o "$TMP/main.o" "$TMP/main.s"
+"$CPU_AS" -o "$TMP/lib.o" "$TMP/lib.s"
+
+# A complete partial link is still ET_REL and may be used as the sole input
+# object of a later final link.
+"$CPU_LD" -r -o "$TMP/combined.o" "$TMP/main.o" "$TMP/lib.o"
+"$CPU_READELF" -h "$TMP/combined.o" > "$TMP/combined.header"
+"$CPU_READELF" -s "$TMP/combined.o" > "$TMP/combined.symbols"
+"$CPU_READELF" -r "$TMP/combined.o" > "$TMP/combined.relocs"
+grep -q 'Type:.*REL (Relocatable file)' "$TMP/combined.header"
+grep -q 'add_two' "$TMP/combined.symbols"
+grep -q 'shared_value' "$TMP/combined.symbols"
+grep -q 'add_two' "$TMP/combined.relocs"
+grep -q 'shared_value' "$TMP/combined.relocs"
+
+"$CPU_LD" --stack-size=4096 --no-heap -o "$TMP/combined-app" "$TMP/combined.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/combined-app"`" = 42 ]
+
+# -r does not require lifecycle completeness and preserves unresolved symbols.
+"$CPU_LD" -r -o "$TMP/main-partial.o" "$TMP/main.o"
+"$CPU_READELF" -s "$TMP/main-partial.o" | grep -q 'UND.*add_two'
+"$CPU_LD" --stack-size=4096 --no-heap \
+ -o "$TMP/late-app" "$TMP/main-partial.o" "$TMP/lib.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/late-app"`" = 42 ]
+
+"$CPU_LD" -r -o "$TMP/library-only.o" "$TMP/lib.o"
+"$CPU_READELF" -h "$TMP/library-only.o" | grep -q 'REL (Relocatable file)'
+
+# LOCAL symbols from separate objects remain private even when they have the
+# same spelling. Their relocations must still refer to their own definitions.
+cat > "$TMP/local-a.s" <<'EOS'
+.global fa
+.text
+fa:
+ CALL local_helper
+ RET
+local_helper:
+ LDI r64@0x00008, 1
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/local-b.s" <<'EOS'
+.global fb
+.text
+fb:
+ CALL local_helper
+ RET
+local_helper:
+ LDI r64@0x00008, 2
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/local-main.s" <<'EOS'
+.global _life
+.extern fa
+.extern fb
+.text
+_start_life:
+ LDI r64@0x00000, 39
+ CALL fa
+ CALL fb
+ MOV r64@0x00018, r64@0x00000
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+"$CPU_AS" -o "$TMP/local-a.o" "$TMP/local-a.s"
+"$CPU_AS" -o "$TMP/local-b.o" "$TMP/local-b.s"
+"$CPU_AS" -o "$TMP/local-main.o" "$TMP/local-main.s"
+"$CPU_LD" -r -o "$TMP/local-combined.o" "$TMP/local-a.o" "$TMP/local-b.o"
+"$CPU_LD" --stack-size=4096 --no-heap \
+ -o "$TMP/local-app" "$TMP/local-main.o" "$TMP/local-combined.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/local-app"`" = 42 ]
+
+# A strong GLOBAL definition replaces a WEAK definition in partial output.
+cat > "$TMP/weak.s" <<'EOS'
+.weak pick
+.text
+pick:
+ LDI r64@0x00008, 1
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/strong.s" <<'EOS'
+.global pick
+.text
+pick:
+ LDI r64@0x00008, 2
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/pick-main.s" <<'EOS'
+.global _life
+.extern pick
+.text
+_start_life:
+ LDI r64@0x00000, 40
+ CALL pick
+ MOV r64@0x00018, r64@0x00000
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+"$CPU_AS" -o "$TMP/weak.o" "$TMP/weak.s"
+"$CPU_AS" -o "$TMP/strong.o" "$TMP/strong.s"
+"$CPU_AS" -o "$TMP/pick-main.o" "$TMP/pick-main.s"
+"$CPU_LD" -r -o "$TMP/pick.o" "$TMP/weak.o" "$TMP/strong.o"
+"$CPU_LD" --stack-size=4096 --no-heap \
+ -o "$TMP/pick-app" "$TMP/pick-main.o" "$TMP/pick.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/pick-app"`" = 42 ]
+
+# Two strong definitions are already an error at partial-link time.
+cat > "$TMP/clash-a.s" <<'EOS'
+.global clash
+.text
+clash:
+ RET
+EOS
+cat > "$TMP/clash-b.s" <<'EOS'
+.global clash
+.text
+clash:
+ RET
+EOS
+"$CPU_AS" -o "$TMP/clash-a.o" "$TMP/clash-a.s"
+"$CPU_AS" -o "$TMP/clash-b.o" "$TMP/clash-b.s"
+if "$CPU_LD" -r -o "$TMP/clash.o" "$TMP/clash-a.o" "$TMP/clash-b.o" \
+ > /dev/null 2> "$TMP/clash.err"; then
+ echo "partial link unexpectedly accepted duplicate GLOBAL definitions" >&2
+ exit 1
+fi
+grep -q 'multiple definition of global symbol: clash' "$TMP/clash.err"
+
+# -r may extract required ET_REL members from libNAME.a, but never consumes a
+# same-named shared object. The unused archive member must stay outside the
+# partial object even though it contains an unresolved reference of its own.
+cat > "$TMP/usepart.s" <<'EOS'
+.global call_part
+.extern part
+.text
+call_part:
+ CALL part
+ RET
+EOS
+cat > "$TMP/part-static.s" <<'EOS'
+.global part
+.text
+part:
+ LDI r64@0x00008, 2
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/part-shared.s" <<'EOS'
+.global part
+.text
+part:
+ LDI r64@0x00008, 3
+ IADD r64@0x00000, r64@0x00000, r64@0x00008
+ RET
+EOS
+cat > "$TMP/unused.s" <<'EOS'
+.global unused_archive_member
+.extern missing_from_unused_member
+.text
+unused_archive_member:
+ CALL missing_from_unused_member
+ RET
+EOS
+cat > "$TMP/archive-main.s" <<'EOS'
+.global _life
+.extern call_part
+.text
+_start_life:
+ LDI r64@0x00000, 40
+ CALL call_part
+ MOV r64@0x00018, r64@0x00000
+ LDI r32@0x00030, 0
+ EXIT r32@0x00030
+EOS
+"$CPU_AS" -o "$TMP/usepart.o" "$TMP/usepart.s"
+"$CPU_AS" -o "$TMP/part-static.o" "$TMP/part-static.s"
+"$CPU_AS" -o "$TMP/part-shared.o" "$TMP/part-shared.s"
+"$CPU_AS" -o "$TMP/unused.o" "$TMP/unused.s"
+"$CPU_AS" -o "$TMP/archive-main.o" "$TMP/archive-main.s"
+"$CPU_AR" rcs "$TMP/lib/libpart.a" "$TMP/part-static.o" "$TMP/unused.o"
+"$CPU_LD" --shared --soname=libpart.so.1 \
+ -o "$TMP/lib/libpart.so.1.0.0" "$TMP/part-shared.o"
+ln -s libpart.so.1.0.0 "$TMP/lib/libpart.so.1"
+ln -s libpart.so.1 "$TMP/lib/libpart.so"
+
+"$CPU_LD" -r -L"$TMP/lib" -lpart -o "$TMP/from-archive.o" "$TMP/usepart.o"
+"$CPU_READELF" -s "$TMP/from-archive.o" > "$TMP/from-archive.symbols"
+grep -q ' part$' "$TMP/from-archive.symbols"
+if grep -q 'unused_archive_member' "$TMP/from-archive.symbols"; then
+ echo "partial link unexpectedly extracted an unused archive member" >&2
+ exit 1
+fi
+"$CPU_LD" --stack-size=4096 --no-heap \
+ -o "$TMP/archive-app" "$TMP/archive-main.o" "$TMP/from-archive.o"
+[ "`"$CPU_RUN" --int-reg=r64@0x00018 "$TMP/archive-app"`" = 42 ]
+
+# The resulting partial object is an ordinary ET_REL and can itself be stored
+# in a static archive.
+"$CPU_AR" rcs "$TMP/libcombined.a" "$TMP/combined.o"
+[ "`"$CPU_AR" t "$TMP/libcombined.a"`" = combined.o ]
+
+# Options that describe final executable/shared-image state are invalid in -r.
+if "$CPU_LD" -r --dynamic -o "$TMP/bad.o" "$TMP/lib.o" >/dev/null 2>&1; then
+ echo "-r --dynamic unexpectedly accepted" >&2
+ exit 1
+fi
+if "$CPU_LD" -r --shared --soname=bad.so -o "$TMP/bad.o" "$TMP/lib.o" >/dev/null 2>&1; then
+ echo "-r --shared unexpectedly accepted" >&2
+ exit 1
+fi
+if "$CPU_LD" -r --stack-size=4096 -o "$TMP/bad.o" "$TMP/lib.o" >/dev/null 2>&1; then
+ echo "-r --stack-size unexpectedly accepted" >&2
+ exit 1
+fi
+if "$CPU_LD" -r --no-heap -o "$TMP/bad.o" "$TMP/lib.o" >/dev/null 2>&1; then
+ echo "-r --no-heap unexpectedly accepted" >&2
+ exit 1
+fi
+if "$CPU_LD" -r --soname=bad.so -o "$TMP/bad.o" "$TMP/lib.o" >/dev/null 2>&1; then
+ echo "-r --soname unexpectedly accepted" >&2
+ exit 1
+fi
+
+"$CPU_LD" --help 2>&1 | grep -q -- '-r.*partial-link MELF ET_REL'
+
+exit 0