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-partial-link-runner.sh | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'tests/tst-partial-link-runner.sh')
| -rwxr-xr-x | tests/tst-partial-link-runner.sh | 276 |
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 |
