kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

run.sh (18910B)


      1 #!/usr/bin/env bash
      2 # test/link/elf-dso-aa64/run.sh — ELF shared-library harness, aarch64 target.
      3 #
      4 # Kit lanes: kit cc compiles PIC objects, kit ld links DSOs, kit cc links the
      5 # consumers, then readelf and podman verify the result. Lane B links a produced
      6 # DSO against libc.so so the loader must resolve a dependency of a dependency.
      7 #
      8 # Prerequisites (checked at runtime; missing prereqs produce SKIP, not FAIL):
      9 #   build/kit — built kit binary
     10 #   readelf — llvm-readelf or GNU readelf (structural checks)
     11 #   podman  — for runtime execution inside an aarch64 container
     12 #             images: alpine (musl) and/or debian:bookworm-slim (glibc)
     13 #
     14 # Usage:
     15 #   bash test/link/elf-dso-aa64/run.sh          # all structural + runtime
     16 #   KIT_TEST_ALLOW_SKIP=1 bash ...              # allow skips (CI-friendly)
     17 #
     18 # Output: structured pass/fail via kit_sh_report.sh; exit 0 = all pass.
     19 
     20 set -u
     21 
     22 ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
     23 BUILD_DIR="$ROOT/build/test/link/elf-dso-aa64"
     24 mkdir -p "$BUILD_DIR"
     25 
     26 KIT_KIT_DIR="$ROOT/test/lib"
     27 . "$ROOT/test/lib/kit_sh_kit.sh"
     28 kit_report_init
     29 
     30 KIT_SKIP_IS_FAILURE="${KIT_SKIP_IS_FAILURE:-0}"
     31 
     32 KIT="$ROOT/build/kit"
     33 KIT_TARGET="-target aarch64-linux"
     34 work="$BUILD_DIR"
     35 
     36 # ---- tool detection -----------------------------------------------------------
     37 
     38 have_readelf=0
     39 READELF_BIN=""
     40 if command -v llvm-readelf >/dev/null 2>&1; then
     41     READELF_BIN="$(command -v llvm-readelf)"; have_readelf=1
     42 elif command -v readelf >/dev/null 2>&1; then
     43     READELF_BIN="$(command -v readelf)"; have_readelf=1
     44 fi
     45 
     46 # exec_target.sh requirements
     47 have_qemu=0
     48 QEMU_BIN=""
     49 have_podman=0
     50 is_aarch64=0
     51 arch_raw="$(uname -m 2>/dev/null || true)"
     52 { [ "$arch_raw" = "aarch64" ] || [ "$arch_raw" = "arm64" ]; } && is_aarch64=1
     53 command -v podman >/dev/null 2>&1 && have_podman=1
     54 
     55 EXEC_TARGET_MOUNT_ROOT="$BUILD_DIR"
     56 export have_qemu QEMU_BIN have_podman is_aarch64 EXEC_TARGET_MOUNT_ROOT
     57 
     58 # shellcheck source=../../lib/exec_target.sh
     59 . "$ROOT/test/lib/exec_target.sh"
     60 
     61 # ---- exec_dso_podman ----------------------------------------------------------
     62 # Like exec_target_run but podman-only. Dynamically linked DSO consumers need a
     63 # full OS environment (dynamic linker + libc); qemu-user alone cannot satisfy
     64 # that without a sysroot. Both files (libfoo.so + consumer) must live in the
     65 # same directory; the consumer's RPATH $ORIGIN then resolves to /work inside the
     66 # container (exec_target_run mounts the directory as /work).
     67 #
     68 # Sets RUN_RC to the container exit code, or 127 when podman is unavailable /
     69 # the image is not provisioned.
     70 exec_dso_podman() {
     71     local tag="$1" exe="$2" out="$3" err="$4"
     72     RUN_RC=127
     73     [ "${have_podman:-0}" -eq 1 ] || return 0
     74     _exec_target_image_present "$tag" || return 0
     75     local dir base platform image platform_flag=()
     76     dir="$(cd "$(dirname "$exe")" && pwd)"
     77     base="$(basename "$exe")"
     78     platform="$(_exec_target_platform "$tag")"
     79     image="$(_exec_target_image "$tag")"
     80     if ! _exec_target_podman_native "$tag"; then
     81         platform_flag=(--platform "$platform")
     82     fi
     83     # Mount the directory as /work so both the consumer and libfoo.so are
     84     # accessible at the same relative paths ($ORIGIN expands to /work).
     85     podman run --rm --pull=never \
     86         ${platform_flag[@]+"${platform_flag[@]}"} \
     87         --net=none \
     88         -v "$dir":/work:Z -w /work \
     89         "$image" "./$base" \
     90         >"$out" 2>"$err"
     91     RUN_RC=$?
     92 }
     93 
     94 # ---- kit shared-library path -------------------------------------------------
     95 #
     96 # Structural checks (require build/kit + readelf):
     97 #   A/build-lib        compile lib_foo.c -fPIC and link libfoo.so
     98 #   A/header-dyn       ET_DYN, e_entry = 0
     99 #   A/no-interp        no PT_INTERP in program headers
    100 #   A/has-dynamic      PT_DYNAMIC present
    101 #   A/soname           DT_SONAME = libfoo.so
    102 #   A/export-foo-add   foo_add in .dynsym as GLOBAL defined
    103 #   A/export-foo-ctr   foo_counter in .dynsym as GLOBAL defined
    104 #   A/export-foo-get   foo_get_counter in .dynsym as GLOBAL defined
    105 #   A/hidden-absent    foo_hidden NOT in .dynsym as a GLOBAL defined symbol
    106 #   A/import-bar       bar_external in .dynsym as UND
    107 #
    108 # Runtime checks (require podman + provisioned image; SKIP if unavailable):
    109 #   A/run-musl         consumer-musl exits 0 inside alpine (musl) container
    110 #   A/run-glibc        consumer-glibc exits 0 inside debian (glibc) container
    111 #
    112 # Libc-dependency checks (require extracted aarch64 musl sysroot):
    113 #   B/build-libc-lib   compile lib_foo_libc.c and link libfoo_libc.so with libc.so
    114 #   B/libc-needed      libfoo_libc.so has a libc DT_NEEDED entry
    115 #   B/import-malloc    malloc is UND in libfoo_libc.so .dynsym
    116 #   B/run-musl         consumer-libc-musl exits 0 inside alpine container
    117 
    118 # ---- A: prerequisites --------------------------------------------------------
    119 
    120 if [ ! -x "$KIT" ]; then
    121     skip_test "A" "build/kit unavailable (run: make bin)"
    122     kit_summary test-link-dso-aa64; kit_exit
    123 fi
    124 if [ $have_readelf -eq 0 ]; then
    125     skip_test "A" "readelf / llvm-readelf unavailable (needed for structural checks)"
    126     kit_summary test-link-dso-aa64; kit_exit
    127 fi
    128 
    129 LIBFOO_O="$work/lib_foo.o"
    130 LIBFOO_SO="$work/libfoo.so"
    131 CONSUMER_O="$work/consumer.o"
    132 CONSUMER_MUSL="$work/consumer-musl"
    133 CONSUMER_GLIBC="$work/consumer-glibc"
    134 LIBFOO_LIBC_O="$work/lib_foo_libc.o"
    135 LIBFOO_LIBC_SO="$work/libfoo_libc.so"
    136 CONSUMER_LIBC_MUSL="$work/consumer-libc-musl"
    137 MUSL_SYSROOT="${KIT_MUSL_SYSROOT:-${XDG_CACHE_HOME:-$HOME/.cache}/kit/sysroots/linux-musl}"
    138 
    139 SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
    140 
    141 # ---- A/build-lib: compile lib_foo.c + link libfoo.so -------------------------
    142 
    143 if ! "$KIT" cc $KIT_TARGET \
    144         -O1 -fPIC \
    145         -c "$SRC_DIR/lib_foo.c" -o "$LIBFOO_O" \
    146         >"$work/compile-lib.out" 2>"$work/compile-lib.err"; then
    147     not_ok "A/build-lib" "$work/compile-lib.err"
    148     kit_summary test-link-dso-aa64; kit_exit
    149 fi
    150 
    151 # bar_external is intentionally unresolved in the DSO; it will appear as UND
    152 # in .dynsym and be satisfied at runtime by the consumer.
    153 if ! "$KIT" ld \
    154         -shared \
    155         -soname libfoo.so \
    156         "$LIBFOO_O" -o "$LIBFOO_SO" \
    157         >"$work/link-lib.out" 2>"$work/link-lib.err"; then
    158     not_ok "A/build-lib" "$work/link-lib.err"
    159     kit_summary test-link-dso-aa64; kit_exit
    160 fi
    161 ok "A/build-lib"
    162 
    163 # ---- A: structural checks on libfoo.so ---------------------------------------
    164 
    165 # Dump ELF header, program headers, dynamic section, and dynamic symbol table
    166 # once each into per-check files; all grep/awk checks read those cached files.
    167 DUMP_HDR="$work/readelf-hdr.txt"
    168 DUMP_PHDR="$work/readelf-phdr.txt"
    169 DUMP_DYN="$work/readelf-dyn.txt"
    170 DUMP_DYNSYM="$work/readelf-dynsym.txt"
    171 
    172 "$READELF_BIN" -h         "$LIBFOO_SO" >"$DUMP_HDR"    2>/dev/null
    173 "$READELF_BIN" -l         "$LIBFOO_SO" >"$DUMP_PHDR"   2>/dev/null
    174 "$READELF_BIN" -d         "$LIBFOO_SO" >"$DUMP_DYN"    2>/dev/null
    175 "$READELF_BIN" --dyn-syms "$LIBFOO_SO" >"$DUMP_DYNSYM" 2>/dev/null
    176 
    177 # A/header-dyn: ELF type must be DYN, entry address must be 0x0
    178 if grep -q "Type:.*DYN" "$DUMP_HDR" && \
    179    grep -qE "Entry point address:\s+0x0\b" "$DUMP_HDR"; then
    180     ok "A/header-dyn"
    181 else
    182     printf 'FAIL: expected Type: DYN and entry 0x0\n' >"$work/A-header-dyn.diag"
    183     grep "Type:\|Entry point" "$DUMP_HDR" >>"$work/A-header-dyn.diag"
    184     not_ok "A/header-dyn" "$work/A-header-dyn.diag"
    185 fi
    186 
    187 # A/no-interp: PT_INTERP must be absent (DSOs are loaded by another program's
    188 # interpreter, not their own)
    189 if grep -q "INTERP" "$DUMP_PHDR"; then
    190     printf 'FAIL: unexpected PT_INTERP in DSO program headers\n' >"$work/A-no-interp.diag"
    191     grep "INTERP" "$DUMP_PHDR" >>"$work/A-no-interp.diag"
    192     not_ok "A/no-interp" "$work/A-no-interp.diag"
    193 else
    194     ok "A/no-interp"
    195 fi
    196 
    197 # A/has-dynamic: PT_DYNAMIC must be present
    198 if grep -q "DYNAMIC" "$DUMP_PHDR"; then
    199     ok "A/has-dynamic"
    200 else
    201     printf 'FAIL: PT_DYNAMIC absent from DSO program headers\n' >"$work/A-has-dynamic.diag"
    202     cat "$DUMP_PHDR" >>"$work/A-has-dynamic.diag"
    203     not_ok "A/has-dynamic" "$work/A-has-dynamic.diag"
    204 fi
    205 
    206 # A/soname: DT_SONAME must be present and match libfoo.so
    207 if grep -q "(SONAME)" "$DUMP_DYN" && grep -q "libfoo.so" "$DUMP_DYN"; then
    208     ok "A/soname"
    209 else
    210     printf 'FAIL: DT_SONAME absent or wrong\n' >"$work/A-soname.diag"
    211     grep "SONAME\|soname\|libfoo" "$DUMP_DYN" >>"$work/A-soname.diag"
    212     not_ok "A/soname" "$work/A-soname.diag"
    213 fi
    214 
    215 # A/export-foo-add: foo_add must be in .dynsym as a GLOBAL defined symbol
    216 if grep -q "GLOBAL\|WEAK" "$DUMP_DYNSYM" && grep "foo_add" "$DUMP_DYNSYM" | grep -qv "UND"; then
    217     ok "A/export-foo-add"
    218 else
    219     printf 'FAIL: foo_add not exported in .dynsym\n' >"$work/A-export-foo-add.diag"
    220     grep "foo_add" "$DUMP_DYNSYM" >>"$work/A-export-foo-add.diag" || true
    221     not_ok "A/export-foo-add" "$work/A-export-foo-add.diag"
    222 fi
    223 
    224 # A/export-foo-ctr: foo_counter must be in .dynsym as a GLOBAL defined symbol
    225 if grep "foo_counter" "$DUMP_DYNSYM" | grep -qv "UND"; then
    226     ok "A/export-foo-ctr"
    227 else
    228     printf 'FAIL: foo_counter not exported in .dynsym\n' >"$work/A-export-foo-ctr.diag"
    229     grep "foo_counter" "$DUMP_DYNSYM" >>"$work/A-export-foo-ctr.diag" || true
    230     not_ok "A/export-foo-ctr" "$work/A-export-foo-ctr.diag"
    231 fi
    232 
    233 # A/export-foo-get: foo_get_counter must be in .dynsym as a GLOBAL defined symbol
    234 if grep "foo_get_counter" "$DUMP_DYNSYM" | grep -qv "UND"; then
    235     ok "A/export-foo-get"
    236 else
    237     printf 'FAIL: foo_get_counter not exported in .dynsym\n' >"$work/A-export-foo-get.diag"
    238     grep "foo_get_counter" "$DUMP_DYNSYM" >>"$work/A-export-foo-get.diag" || true
    239     not_ok "A/export-foo-get" "$work/A-export-foo-get.diag"
    240 fi
    241 
    242 # A/hidden-absent: foo_hidden must NOT appear as a GLOBAL/WEAK defined symbol
    243 # in .dynsym. Hidden symbols stay in .symtab only; they must not be preemptible.
    244 # If it appears at all in .dynsym it must be STV_HIDDEN (Vis == HIDDEN) and not
    245 # GLOBAL-or-WEAK DEFAULT, so check that no GLOBAL DEFAULT line mentions it.
    246 if grep "foo_hidden" "$DUMP_DYNSYM" | grep -q "GLOBAL.*DEFAULT.*[0-9]"; then
    247     printf 'FAIL: foo_hidden appears as GLOBAL DEFAULT in .dynsym\n' >"$work/A-hidden-absent.diag"
    248     grep "foo_hidden" "$DUMP_DYNSYM" >>"$work/A-hidden-absent.diag"
    249     not_ok "A/hidden-absent" "$work/A-hidden-absent.diag"
    250 else
    251     ok "A/hidden-absent"
    252 fi
    253 
    254 # A/import-bar: bar_external must be in .dynsym as UND (undefined import)
    255 if grep "bar_external" "$DUMP_DYNSYM" | grep -q "UND"; then
    256     ok "A/import-bar"
    257 else
    258     printf 'FAIL: bar_external not in .dynsym as UND\n' >"$work/A-import-bar.diag"
    259     grep "bar_external" "$DUMP_DYNSYM" >>"$work/A-import-bar.diag" || true
    260     not_ok "A/import-bar" "$work/A-import-bar.diag"
    261 fi
    262 
    263 # ---- A: build consumers for runtime execution --------------------------------
    264 # Two variants, one per libc ABI, so each can run in its matching container.
    265 # Both are freestanding (no libc calls, no sysroot required at compile time).
    266 # --export-dynamic exports bar_external to the executable's .dynsym so that
    267 # libfoo.so's dynamic reference to it is resolved by the loader at startup.
    268 
    269 # Musl interpreter (alpine linux/arm64)
    270 MUSL_INTERP="/lib/ld-musl-aarch64.so.1"
    271 if ! "$KIT" cc $KIT_TARGET \
    272         -O1 -ffreestanding \
    273         -nostdlib -rdynamic \
    274         -e _start \
    275         -Wl,-dynamic-linker,"$MUSL_INTERP" \
    276         -Wl,-rpath,\$ORIGIN \
    277         "$SRC_DIR/consumer.c" \
    278         -L"$work" -lfoo \
    279         -o "$CONSUMER_MUSL" \
    280         >"$work/build-consumer-musl.out" 2>"$work/build-consumer-musl.err"; then
    281     skip_test "A/run-musl" "consumer-musl build failed; see $work/build-consumer-musl.err"
    282     have_consumer_musl=0
    283 else
    284     have_consumer_musl=1
    285 fi
    286 
    287 # Glibc interpreter (debian:bookworm-slim linux/arm64)
    288 GLIBC_INTERP="/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"
    289 if ! "$KIT" cc $KIT_TARGET \
    290         -O1 -ffreestanding \
    291         -nostdlib -rdynamic \
    292         -e _start \
    293         -Wl,-dynamic-linker,"$GLIBC_INTERP" \
    294         -Wl,-rpath,\$ORIGIN \
    295         "$SRC_DIR/consumer.c" \
    296         -L"$work" -lfoo \
    297         -o "$CONSUMER_GLIBC" \
    298         >"$work/build-consumer-glibc.out" 2>"$work/build-consumer-glibc.err"; then
    299     skip_test "A/run-glibc" "consumer-glibc build failed; see $work/build-consumer-glibc.err"
    300     have_consumer_glibc=0
    301 else
    302     have_consumer_glibc=1
    303 fi
    304 
    305 # ---- A: check consumer DT_NEEDED and RPATH (structural, glibc variant) -------
    306 # Only if the glibc consumer built successfully. The musl and glibc consumers
    307 # have identical dynamic metadata (same NEEDED/RPATH) — check once.
    308 if [ $have_consumer_glibc -eq 1 ]; then
    309     DUMP_CON_DYN="$work/readelf-consumer-dyn.txt"
    310     "$READELF_BIN" -d "$CONSUMER_GLIBC" >"$DUMP_CON_DYN" 2>/dev/null
    311 
    312     # DT_NEEDED must reference libfoo.so (matching the soname we embedded)
    313     if grep -q "(NEEDED)" "$DUMP_CON_DYN" && grep "(NEEDED)" "$DUMP_CON_DYN" | grep -q "libfoo.so"; then
    314         ok "A/consumer-needed"
    315     else
    316         printf 'FAIL: consumer missing DT_NEEDED libfoo.so\n' >"$work/A-consumer-needed.diag"
    317         grep "NEEDED\|libfoo" "$DUMP_CON_DYN" >>"$work/A-consumer-needed.diag" || true
    318         not_ok "A/consumer-needed" "$work/A-consumer-needed.diag"
    319     fi
    320 
    321     # RPATH or RUNPATH must contain $ORIGIN
    322     if grep -E "(RPATH|RUNPATH)" "$DUMP_CON_DYN" | grep -q 'ORIGIN'; then
    323         ok "A/consumer-rpath"
    324     else
    325         printf 'FAIL: consumer missing RPATH/RUNPATH with \$ORIGIN\n' >"$work/A-consumer-rpath.diag"
    326         grep -E "RPATH|RUNPATH" "$DUMP_CON_DYN" >>"$work/A-consumer-rpath.diag" || true
    327         not_ok "A/consumer-rpath" "$work/A-consumer-rpath.diag"
    328     fi
    329 fi
    330 
    331 # ---- A/run-musl: runtime execution in alpine (musl) container ----------------
    332 if [ $have_consumer_musl -eq 1 ]; then
    333     if [ "${have_podman:-0}" -ne 1 ]; then
    334         skip_test "A/run-musl" "podman unavailable"
    335     elif ! _exec_target_image_present "aarch64-linux"; then
    336         skip_test "A/run-musl" "aarch64 musl image not provisioned (run: make test-images)"
    337     else
    338         exec_dso_podman "aarch64-linux" "$CONSUMER_MUSL" \
    339             "$work/run-musl.out" "$work/run-musl.err"
    340         if [ "$RUN_RC" -eq 0 ]; then
    341             ok "A/run-musl"
    342         else
    343             printf 'consumer-musl exited %d\n' "$RUN_RC" >"$work/A-run-musl.diag"
    344             [ -s "$work/run-musl.err" ] && sed 's/^/  | /' "$work/run-musl.err" >>"$work/A-run-musl.diag"
    345             not_ok "A/run-musl" "$work/A-run-musl.diag"
    346         fi
    347     fi
    348 fi
    349 
    350 # ---- A/run-glibc: runtime execution in debian (glibc) container --------------
    351 if [ $have_consumer_glibc -eq 1 ]; then
    352     if [ "${have_podman:-0}" -ne 1 ]; then
    353         skip_test "A/run-glibc" "podman unavailable"
    354     elif ! _exec_target_image_present "aarch64-linux-glibc"; then
    355         skip_test "A/run-glibc" "aarch64 glibc image not provisioned (run: make test-images)"
    356     else
    357         exec_dso_podman "aarch64-linux-glibc" "$CONSUMER_GLIBC" \
    358             "$work/run-glibc.out" "$work/run-glibc.err"
    359         if [ "$RUN_RC" -eq 0 ]; then
    360             ok "A/run-glibc"
    361         else
    362             printf 'consumer-glibc exited %d\n' "$RUN_RC" >"$work/A-run-glibc.diag"
    363             [ -s "$work/run-glibc.err" ] && sed 's/^/  | /' "$work/run-glibc.err" >>"$work/A-run-glibc.diag"
    364             not_ok "A/run-glibc" "$work/A-run-glibc.diag"
    365         fi
    366     fi
    367 fi
    368 
    369 # ---- B: produced DSO depends on libc.so --------------------------------------
    370 # This lane links the shared object itself against the extracted aarch64 musl
    371 # libc.so. The consumer only names libfoo_libc.so; libc is pulled transitively
    372 # from libfoo_libc.so's DT_NEEDED entry at runtime.
    373 
    374 have_libc_lane=0
    375 if [ ! -f "$MUSL_SYSROOT/usr/lib/libc.so" ]; then
    376     skip_test "B" "aarch64 musl sysroot unavailable (run: make test-libc-musl, or set KIT_MUSL_SYSROOT)"
    377 else
    378     if ! "$KIT" cc $KIT_TARGET \
    379             -O1 -fPIC \
    380             -c "$SRC_DIR/lib_foo_libc.c" -o "$LIBFOO_LIBC_O" \
    381             >"$work/compile-libc-lib.out" 2>"$work/compile-libc-lib.err"; then
    382         not_ok "B/build-libc-lib" "$work/compile-libc-lib.err"
    383     elif ! "$KIT" ld \
    384             -shared \
    385             -soname libfoo_libc.so \
    386             "$LIBFOO_LIBC_O" "$MUSL_SYSROOT/usr/lib/libc.so" \
    387             -o "$LIBFOO_LIBC_SO" \
    388             >"$work/link-libc-lib.out" 2>"$work/link-libc-lib.err"; then
    389         not_ok "B/build-libc-lib" "$work/link-libc-lib.err"
    390     else
    391         ok "B/build-libc-lib"
    392         have_libc_lane=1
    393     fi
    394 fi
    395 
    396 if [ $have_libc_lane -eq 1 ]; then
    397     DUMP_LIBC_DYN="$work/readelf-libc-dyn.txt"
    398     DUMP_LIBC_DYNSYM="$work/readelf-libc-dynsym.txt"
    399     "$READELF_BIN" -d         "$LIBFOO_LIBC_SO" >"$DUMP_LIBC_DYN"    2>/dev/null
    400     "$READELF_BIN" --dyn-syms "$LIBFOO_LIBC_SO" >"$DUMP_LIBC_DYNSYM" 2>/dev/null
    401 
    402     if grep -q "(NEEDED)" "$DUMP_LIBC_DYN" && grep "(NEEDED)" "$DUMP_LIBC_DYN" | grep -q "libc"; then
    403         ok "B/libc-needed"
    404     else
    405         printf 'FAIL: produced DSO missing a libc DT_NEEDED entry\n' >"$work/B-libc-needed.diag"
    406         grep "NEEDED\|libc" "$DUMP_LIBC_DYN" >>"$work/B-libc-needed.diag" || true
    407         not_ok "B/libc-needed" "$work/B-libc-needed.diag"
    408     fi
    409 
    410     if grep "malloc" "$DUMP_LIBC_DYNSYM" | grep -q "UND"; then
    411         ok "B/import-malloc"
    412     else
    413         printf 'FAIL: malloc not in libfoo_libc.so .dynsym as UND\n' >"$work/B-import-malloc.diag"
    414         grep "malloc" "$DUMP_LIBC_DYNSYM" >>"$work/B-import-malloc.diag" || true
    415         not_ok "B/import-malloc" "$work/B-import-malloc.diag"
    416     fi
    417 
    418     if ! "$KIT" cc $KIT_TARGET \
    419             -O1 -ffreestanding \
    420             -nostdlib -rdynamic \
    421             -e _start \
    422             -Wl,-dynamic-linker,"$MUSL_INTERP" \
    423             -Wl,-rpath,\$ORIGIN \
    424             "$SRC_DIR/consumer.c" \
    425             -L"$work" -lfoo_libc \
    426             -o "$CONSUMER_LIBC_MUSL" \
    427             >"$work/build-consumer-libc-musl.out" 2>"$work/build-consumer-libc-musl.err"; then
    428         skip_test "B/run-musl" "consumer-libc-musl build failed; see $work/build-consumer-libc-musl.err"
    429         have_consumer_libc_musl=0
    430     else
    431         have_consumer_libc_musl=1
    432     fi
    433 
    434     if [ $have_consumer_libc_musl -eq 1 ]; then
    435         if [ "${have_podman:-0}" -ne 1 ]; then
    436             skip_test "B/run-musl" "podman unavailable"
    437         elif ! _exec_target_image_present "aarch64-linux"; then
    438             skip_test "B/run-musl" "aarch64 musl image not provisioned (run: make test-images)"
    439         else
    440             exec_dso_podman "aarch64-linux" "$CONSUMER_LIBC_MUSL" \
    441                 "$work/run-libc-musl.out" "$work/run-libc-musl.err"
    442             if [ "$RUN_RC" -eq 0 ]; then
    443                 ok "B/run-musl"
    444             else
    445                 printf 'consumer-libc-musl exited %d\n' "$RUN_RC" >"$work/B-run-musl.diag"
    446                 [ -s "$work/run-libc-musl.err" ] && sed 's/^/  | /' "$work/run-libc-musl.err" >>"$work/B-run-musl.diag"
    447                 not_ok "B/run-musl" "$work/B-run-musl.diag"
    448             fi
    449         fi
    450     fi
    451 fi
    452 
    453 # ---- summary -----------------------------------------------------------------
    454 kit_summary test-link-dso-aa64
    455 kit_exit