kit

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

windows-ucrt-hosted-smoke.sh (16826B)


      1 #!/usr/bin/env bash
      2 # test/coff/windows-ucrt-hosted-smoke.sh — Type-K (mode P) hosted Windows UCRT
      3 # smoke, on the shared scripted-shell kit (test/lib/kit_sh_kit.sh).
      4 #
      5 # One program per UCRT surface (Sleep, windows.h coverage, runtime, UCRT stdio,
      6 # imported-data, TLS, GUI WinMain) is built with `kit cc` for both
      7 # x86_64-windows and aarch64-windows; the link-level checks inspect the PE
      8 # import directory via `kit objdump -p` (run_ok + contains), and a negative
      9 # check asserts no legacy CRT DLL is imported directly. The Wine runtime check
     10 # is run conditionally and self-skips when podman/Wine are absent.
     11 #
     12 # Serial by design (mode P): all programs share one $work sandbox.
     13 #
     14 # Self-skip: prints SKIP and exits 0 when no llvm-mingw UCRT sysroot is found.
     15 set -u
     16 
     17 ROOT=${KIT_TEST_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}
     18 KIT=${KIT:-"$ROOT/build/kit"}
     19 SDK=${KIT_SYSROOT:-}
     20 
     21 KIT_KIT_DIR="$ROOT/test/lib"
     22 . "$ROOT/test/lib/kit_sh_kit.sh"
     23 kit_report_init
     24 
     25 LABEL_SUITE=windows-ucrt-hosted-smoke
     26 
     27 find_sdk() {
     28   local arch=$1
     29   local d
     30   for d in \
     31     "$ROOT"/build/llvm-mingw/*/ucrt/"$arch"-w64-mingw32 \
     32     /tmp/llvm-mingw*/llvm-mingw-*-ucrt-*/"$arch"-w64-mingw32 \
     33     /tmp/llvm-mingw*/"$arch"-w64-mingw32 \
     34     /private/tmp/llvm-mingw*/llvm-mingw-*-ucrt-*/"$arch"-w64-mingw32 \
     35     /private/tmp/llvm-mingw*/"$arch"-w64-mingw32; do
     36     if [ -d "$d/lib" ] && [ -r "$d/include/windows.h" ]; then
     37       printf '%s\n' "$d"
     38       return 0
     39     fi
     40   done
     41   return 1
     42 }
     43 
     44 sdk_for_arch() {
     45   local arch=$1
     46   local base
     47   if [ -n "$SDK" ]; then
     48     if [ "$(basename "$SDK")" = "$arch-w64-mingw32" ]; then
     49       printf '%s\n' "$SDK"
     50       return 0
     51     fi
     52     base=$(dirname "$SDK")
     53     if [ -d "$base/$arch-w64-mingw32/lib" ] &&
     54        [ -r "$base/$arch-w64-mingw32/include/windows.h" ]; then
     55       printf '%s\n' "$base/$arch-w64-mingw32"
     56       return 0
     57     fi
     58   fi
     59   find_sdk "$arch"
     60 }
     61 
     62 # kit presence: was a hard FAIL+exit 1 in the original. Preserve that verdict.
     63 if [ ! -x "$KIT" ]; then
     64   kit_fail "$LABEL_SUITE/kit-present" "kit binary not found: $KIT"
     65   kit_summary "$LABEL_SUITE"
     66   kit_exit
     67 fi
     68 
     69 TMP=${TMPDIR:-/tmp}
     70 work=$(mktemp -d "$TMP/kit-windows-ucrt-smoke.XXXXXX")
     71 WORK_REAL=$(cd "$work" && pwd -P)
     72 trap 'rm -rf "$work"' EXIT
     73 
     74 CONSOLE_C=$work/windows-h.c
     75 HEADER_C=$work/windows-h-coverage.c
     76 RUNTIME_C=$work/runtime.c
     77 STDIO_C=$work/stdio.c
     78 IMPORTDATA_C=$work/import-data.c
     79 GUI_C=$work/gui.c
     80 TLS_C=$work/tls.c
     81 
     82 cat >"$CONSOLE_C" <<'SRC'
     83 #include <windows.h>
     84 int main(void) { Sleep(1); return 0; }
     85 SRC
     86 
     87 cat >"$HEADER_C" <<'SRC'
     88 #include <windows.h>
     89 #include <fileapi.h>
     90 #include <processthreadsapi.h>
     91 #include <synchapi.h>
     92 #include <errhandlingapi.h>
     93 #include <winuser.h>
     94 
     95 _Static_assert(sizeof(long) == 4, "windows long is LLP64");
     96 _Static_assert(sizeof(WCHAR) == 2, "WCHAR is UTF-16");
     97 _Static_assert(sizeof(void*) == 8, "PE32+ pointer size");
     98 
     99 static DWORD WINAPI thread_proc(LPVOID ctx) {
    100   return (DWORD)(ULONG_PTR)ctx;
    101 }
    102 
    103 static BOOL CALLBACK enum_windows_proc(HWND hwnd, LPARAM lparam) {
    104   RECT r;
    105   POINT p;
    106   WINDOWPLACEMENT wp;
    107   ZeroMemory(&wp, sizeof(wp));
    108   wp.length = sizeof(wp);
    109   GetClientRect(hwnd, &r);
    110   p.x = r.left;
    111   p.y = r.top;
    112   ClientToScreen(hwnd, &p);
    113   SetLastError((DWORD)lparam);
    114   return TRUE;
    115 }
    116 
    117 int main(void) {
    118   HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
    119   DWORD wrote = 0;
    120   const char msg[] = "windows coverage\n";
    121   WriteFile(out, msg, sizeof(msg) - 1, &wrote, NULL);
    122 
    123   SECURITY_ATTRIBUTES sa;
    124   ZeroMemory(&sa, sizeof(sa));
    125   sa.nLength = sizeof(sa);
    126   sa.bInheritHandle = FALSE;
    127 
    128   WCHAR tmp_path[MAX_PATH];
    129   WCHAR file_path[MAX_PATH];
    130   GetTempPathW(MAX_PATH, tmp_path);
    131   GetTempFileNameW(tmp_path, L"cfr", 0, file_path);
    132   HANDLE h = CreateFileW(file_path, GENERIC_READ | GENERIC_WRITE, 0, &sa,
    133                          CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
    134   if (h != INVALID_HANDLE_VALUE) {
    135     LARGE_INTEGER pos;
    136     pos.QuadPart = 0;
    137     SetFilePointerEx(h, pos, NULL, FILE_BEGIN);
    138     CloseHandle(h);
    139     DeleteFileW(file_path);
    140   }
    141 
    142   CRITICAL_SECTION cs;
    143   InitializeCriticalSection(&cs);
    144   EnterCriticalSection(&cs);
    145   LeaveCriticalSection(&cs);
    146   DeleteCriticalSection(&cs);
    147 
    148   DWORD tid = 0;
    149   HANDLE th = CreateThread(NULL, 0, thread_proc, (LPVOID)(ULONG_PTR)3, 0, &tid);
    150   if (th) {
    151     WaitForSingleObject(th, INFINITE);
    152     CloseHandle(th);
    153   }
    154 
    155   EnumWindows(enum_windows_proc, 0);
    156   MessageBoxW(NULL, L"", L"", MB_OK | MB_SETFOREGROUND);
    157   return 0;
    158 }
    159 SRC
    160 
    161 cat >"$RUNTIME_C" <<'SRC'
    162 #include <windows.h>
    163 #include <stdlib.h>
    164 #include <string.h>
    165 
    166 static int cmp_ints(const void *a, const void *b) {
    167   int ia = *(const int *)a;
    168   int ib = *(const int *)b;
    169   return (ia > ib) - (ia < ib);
    170 }
    171 
    172 static int has_env(char **envp, const char *prefix) {
    173   size_t n = strlen(prefix);
    174   if (!envp) return 0;
    175   for (; *envp; ++envp) {
    176     if (strncmp(*envp, prefix, n) == 0) return 1;
    177   }
    178   return 0;
    179 }
    180 
    181 int main(int argc, char **argv, char **envp) {
    182   if (argc < 3) return 10;
    183   if (strcmp(argv[1], "alpha") != 0 || strcmp(argv[2], "beta") != 0) return 11;
    184   if (!has_env(envp, "KIT_WIN_PROBE=present")) return 12;
    185 
    186   HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
    187   HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
    188   DWORD wrote = 0;
    189   WriteFile(out, "stdout-ok\n", 10, &wrote, 0);
    190   WriteFile(err, "stderr-ok\n", 10, &wrote, 0);
    191 
    192   HANDLE heap = GetProcessHeap();
    193   char *mem = (char *)HeapAlloc(heap, 0, 32);
    194   if (!mem) return 13;
    195   strcpy(mem, "heap-ok");
    196   if (strcmp(mem, "heap-ok") != 0) return 14;
    197   HeapFree(heap, 0, mem);
    198 
    199   int vals[4] = {4, 1, 3, 2};
    200   qsort(vals, 4, sizeof(vals[0]), cmp_ints);
    201   if (vals[0] != 1 || vals[3] != 4) return 15;
    202 
    203   SetLastError(1234);
    204   if (GetLastError() != 1234) return 16;
    205 
    206   char dir[MAX_PATH];
    207   char path[MAX_PATH];
    208   if (!GetTempPathA(MAX_PATH, dir)) return 17;
    209   wsprintfA(path, "%skit-runtime-%lu.tmp", dir,
    210             (unsigned long)GetCurrentProcessId());
    211   HANDLE f = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, 0, 0,
    212                          CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0);
    213   if (f == INVALID_HANDLE_VALUE) return 18;
    214   if (!WriteFile(f, "file-ok", 7, &wrote, 0) || wrote != 7) return 19;
    215   SetFilePointer(f, 0, 0, FILE_BEGIN);
    216   char buf[8];
    217   DWORD got = 0;
    218   memset(buf, 0, sizeof(buf));
    219   if (!ReadFile(f, buf, 7, &got, 0)) return 20;
    220   CloseHandle(f);
    221   DeleteFileA(path);
    222   if (got != 7 || strcmp(buf, "file-ok") != 0) return 21;
    223   return 0;
    224 }
    225 SRC
    226 
    227 cat >"$STDIO_C" <<'SRC'
    228 #define _INC_STDIO_S
    229 #include <stdio.h>
    230 
    231 int main(void) {
    232   puts("puts-ok");
    233   fputs("fputs-ok\n", stdout);
    234   printf("printf-ok\n");
    235   fflush(stdout);
    236   return 0;
    237 }
    238 SRC
    239 
    240 cat >"$IMPORTDATA_C" <<'SRC'
    241 #include <windows.h>
    242 
    243 extern char **__dcrt_initial_narrow_environment;
    244 
    245 int main(void) {
    246   HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
    247   DWORD wrote = 0;
    248   WriteFile(out, "importdata\n", 11, &wrote, 0);
    249   if (&__dcrt_initial_narrow_environment == 0) return 10;
    250   if (__dcrt_initial_narrow_environment == 0) return 11;
    251   return 0;
    252 }
    253 SRC
    254 
    255 cat >"$GUI_C" <<'SRC'
    256 #include <windows.h>
    257 int WINAPI WinMain(HINSTANCE hinst, HINSTANCE prev, LPSTR cmd, int show) {
    258   (void)hinst;
    259   (void)prev;
    260   (void)cmd;
    261   (void)show;
    262   return 0;
    263 }
    264 SRC
    265 
    266 cat >"$TLS_C" <<'SRC'
    267 struct tlsdir {
    268   unsigned long long start;
    269   unsigned long long end;
    270   unsigned long long index;
    271   unsigned long long callbacks;
    272   unsigned int zero_fill;
    273   unsigned int characteristics;
    274 };
    275 
    276 extern unsigned char __ImageBase;
    277 extern const struct tlsdir _tls_used;
    278 
    279 _Thread_local int tls_init = 7;
    280 _Thread_local int tls_zero;
    281 
    282 static unsigned int rd32(const unsigned char *p) {
    283   return (unsigned int)p[0] |
    284          ((unsigned int)p[1] << 8) |
    285          ((unsigned int)p[2] << 16) |
    286          ((unsigned int)p[3] << 24);
    287 }
    288 
    289 static int check_tls_directory(void) {
    290   const unsigned char *image = &__ImageBase;
    291   unsigned int pe = rd32(image + 0x3c);
    292   const unsigned char *opt = image + pe + 4 + 20;
    293   const unsigned char *dir = opt + 112 + 9 * 8;
    294   unsigned int tls_rva = rd32(dir);
    295   unsigned int tls_size = rd32(dir + 4);
    296   if (tls_size != 40) return 34;
    297   if ((const unsigned char *)&_tls_used != image + tls_rva) return 35;
    298   if (_tls_used.start == 0 || _tls_used.end <= _tls_used.start) return 36;
    299   if (_tls_used.index == 0) return 37;
    300   if (_tls_used.zero_fill != 0 || _tls_used.characteristics != 0) return 38;
    301   return 0;
    302 }
    303 
    304 static int bump(void) {
    305   tls_zero += 3;
    306   tls_init += tls_zero;
    307   return tls_init;
    308 }
    309 
    310 int main(void) {
    311   int dir = check_tls_directory();
    312   if (dir) return dir;
    313   int a = bump();
    314   int b = bump();
    315   if (a != 10) return 31;
    316   if (b != 16) return 32;
    317   if (tls_zero != 6) return 33;
    318   return 0;
    319 }
    320 SRC
    321 
    322 # ---- assert helpers (mode-P verbs, $work-confined) -------------------------
    323 
    324 # no_legacy_crt_imports NAME DUMP : pass iff DUMP imports no msvcrt/ucrt DLL.
    325 no_legacy_crt_imports() {
    326   local name=$1 dump=$2
    327   if grep -Eiq 'DLL Name: (msvcrt|ucrt)\.dll' "$dump"; then
    328     grep -Ei 'DLL Name: (msvcrt|ucrt)\.dll' "$dump" > "$work/$name.diag"
    329     not_ok "$name" "$work/$name.diag"
    330   else
    331     ok "$name"
    332   fi
    333 }
    334 
    335 # not_contains NAME FILE NEEDLE : pass iff NEEDLE is absent from FILE.
    336 not_contains() {
    337   local name=$1 file=$2 needle=$3
    338   if grep -Fq "$needle" "$file"; then
    339     { printf 'unexpected text: %s\n' "$needle"; } > "$work/$name.diag"
    340     not_ok "$name" "$work/$name.diag"
    341   else
    342     ok "$name"
    343   fi
    344 }
    345 
    346 # matches NAME FILE EREGEX : pass iff FILE has a line matching EREGEX.
    347 matches() {
    348   local name=$1 file=$2 re=$3
    349   if grep -Eq "$re" "$file"; then ok "$name"
    350   else { printf 'no line matched: %s\n' "$re"; } > "$work/$name.diag"; not_ok "$name" "$work/$name.diag"; fi
    351 }
    352 
    353 # run_wine_if_available LABEL IMAGE POD_ARCH EXE [ARGS...] : conditional Wine
    354 # run. Self-skips (kit_skip) when podman or the container image is absent;
    355 # otherwise pass iff the program exits 0 under Wine.
    356 run_wine_if_available() {
    357   local label=$1 image=$2 pod_arch=$3 exe=$4
    358   shift 4
    359   case "$pod_arch" in
    360     amd64)
    361       if [ -n "${KIT_WINDOWS_VM_X64:-${KIT_WINDOWS_VM_AMD64:-}}" ]; then
    362         if KIT_WIN_PROBE=present "$ROOT/scripts/windows_vm.sh" run x64 "$exe" "$@" \
    363             > "$work/$label-vm.out" 2> "$work/$label-vm.err"; then
    364           ok "$label-vm"
    365         else
    366           not_ok "$label-vm" "$work/$label-vm.err"
    367         fi
    368         return 0
    369       fi
    370       ;;
    371     arm64)
    372       if [ -n "${KIT_WINDOWS_VM_AARCH64:-${KIT_WINDOWS_VM_ARM64:-}}" ]; then
    373         if KIT_WIN_PROBE=present "$ROOT/scripts/windows_vm.sh" run aarch64 "$exe" "$@" \
    374             > "$work/$label-vm.out" 2> "$work/$label-vm.err"; then
    375           ok "$label-vm"
    376         else
    377           not_ok "$label-vm" "$work/$label-vm.err"
    378         fi
    379         return 0
    380       fi
    381       ;;
    382   esac
    383   if ! command -v podman >/dev/null 2>&1; then
    384     skip_test "$label-wine" "podman unavailable"
    385     return 0
    386   fi
    387   if ! podman image exists "$image" >/dev/null 2>&1; then
    388     skip_test "$label-wine" "$image unavailable"
    389     return 0
    390   fi
    391   if podman run --rm --arch "$pod_arch" -v "$WORK_REAL:/probe:ro" "$image" \
    392       bash -lc "
    393         export WINEDEBUG=-all WINEPREFIX=/tmp/wineprefix KIT_WIN_PROBE=present
    394         timeout 120s /usr/lib/wine/wine64 /probe/$(basename "$exe") $*
    395         rc=\$?
    396         echo \"$label exit=\$rc\"
    397         test \"\$rc\" -eq 0
    398       " > "$work/$label-wine.out" 2> "$work/$label-wine.err"; then
    399     ok "$label-wine"
    400   else
    401     not_ok "$label-wine" "$work/$label-wine.err"
    402   fi
    403 }
    404 
    405 ran=0
    406 for arch in x86_64 aarch64; do
    407   case "$arch" in
    408     x86_64)
    409       target=x86_64-windows
    410       label=x64
    411       image=localhost/kit-wine-amd64
    412       pod_arch=amd64
    413       ;;
    414     aarch64)
    415       target=aarch64-windows
    416       label=aarch64
    417       image=localhost/kit-wine-arm64
    418       pod_arch=arm64
    419       ;;
    420   esac
    421 
    422   if ! ARCH_SDK=$(sdk_for_arch "$arch"); then
    423     skip_test "$LABEL_SUITE/$label-sysroot" "no $arch llvm-mingw UCRT sysroot"
    424     continue
    425   fi
    426   # Discovered-but-invalid sysroot was a hard FAIL+exit 1 originally.
    427   if [ ! -r "$ARCH_SDK/include/windows.h" ] ||
    428      [ ! -r "$ARCH_SDK/lib/libucrt.a" ]; then
    429     echo "invalid UCRT llvm-mingw sysroot: $ARCH_SDK" > "$work/$label-sysroot.diag"
    430     not_ok "$LABEL_SUITE/$label-sysroot" "$work/$label-sysroot.diag"
    431     kit_summary "$LABEL_SUITE"
    432     kit_exit
    433   fi
    434 
    435   ran=1
    436   CONSOLE_EXE=$work/windows-h-$arch.exe
    437   CONSOLE_DUMP=$work/windows-h-$arch.dump
    438   HEADER_EXE=$work/windows-h-coverage-$arch.exe
    439   HEADER_DUMP=$work/windows-h-coverage-$arch.dump
    440   RUNTIME_EXE=$work/runtime-$arch.exe
    441   RUNTIME_DUMP=$work/runtime-$arch.dump
    442   STDIO_EXE=$work/stdio-$arch.exe
    443   STDIO_DUMP=$work/stdio-$arch.dump
    444   IMPORTDATA_EXE=$work/import-data-$arch.exe
    445   IMPORTDATA_DUMP=$work/import-data-$arch.dump
    446   TLS_EXE=$work/tls-$arch.exe
    447   TLS_DUMP=$work/tls-$arch.dump
    448   GUI_EXE=$work/gui-$arch.exe
    449   GUI_DUMP=$work/gui-$arch.dump
    450 
    451   # build_dump NAME EXE DUMP -- CC_ARGS... : build EXE, then `objdump -p` it
    452   # into DUMP. Returns 0 only if both the EXE and the DUMP were produced, so
    453   # the per-program import asserts below run iff the link round-tripped.
    454   build_dump() {
    455     local bn=$1 exe=$2 dump=$3; shift 3
    456     [ "$1" = "--" ] && shift
    457     run_ok "$bn-build" "$KIT" cc -target "$target" --sysroot "$ARCH_SDK" "$@" -o "$exe"
    458     [ -f "$exe" ] || return 1
    459     run_ok "$bn-objdump" "$KIT" objdump -p "$exe"
    460     [ -s "$work/$bn-objdump.out" ] || return 1
    461     cp "$work/$bn-objdump.out" "$dump"
    462   }
    463 
    464   # ---- console Sleep ----
    465   if build_dump "$label-console" "$CONSOLE_EXE" "$CONSOLE_DUMP" -- -mconsole "$CONSOLE_C"; then
    466     no_legacy_crt_imports "$label-console-no-legacy-crt" "$CONSOLE_DUMP"
    467     not_contains "$label-console-no-weak-set-app-type" "$CONSOLE_DUMP" "Name:     __set_app_type"
    468     contains "$label-console-kernel32" "$CONSOLE_DUMP" "DLL Name: KERNEL32.dll"
    469     contains "$label-console-sleep" "$CONSOLE_DUMP" "Name:     Sleep"
    470     contains "$label-console-crt-runtime-dll" "$CONSOLE_DUMP" "DLL Name: api-ms-win-crt-runtime-l1-1-0.dll"
    471     contains "$label-console-set-app-type" "$CONSOLE_DUMP" "Name:     _set_app_type"
    472     run_wine_if_available "$label-console-Sleep" "$image" "$pod_arch" "$CONSOLE_EXE"
    473   fi
    474 
    475   # ---- windows.h coverage ----
    476   if build_dump "$label-header" "$HEADER_EXE" "$HEADER_DUMP" -- -mconsole "$HEADER_C"; then
    477     no_legacy_crt_imports "$label-header-no-legacy-crt" "$HEADER_DUMP"
    478     contains "$label-header-CreateFileW" "$HEADER_DUMP" "Name:     CreateFileW"
    479     contains "$label-header-CreateThread" "$HEADER_DUMP" "Name:     CreateThread"
    480     contains "$label-header-WaitForSingleObject" "$HEADER_DUMP" "Name:     WaitForSingleObject"
    481     contains "$label-header-MessageBoxW" "$HEADER_DUMP" "Name:     MessageBoxW"
    482   fi
    483 
    484   # ---- runtime ----
    485   if build_dump "$label-runtime" "$RUNTIME_EXE" "$RUNTIME_DUMP" -- "$RUNTIME_C"; then
    486     no_legacy_crt_imports "$label-runtime-no-legacy-crt" "$RUNTIME_DUMP"
    487     contains "$label-runtime-HeapAlloc" "$RUNTIME_DUMP" "Name:     HeapAlloc"
    488     contains "$label-runtime-CreateFileA" "$RUNTIME_DUMP" "Name:     CreateFileA"
    489     contains "$label-runtime-qsort" "$RUNTIME_DUMP" "Name:     qsort"
    490     run_wine_if_available "$label-runtime" "$image" "$pod_arch" "$RUNTIME_EXE" alpha beta
    491   fi
    492 
    493   # ---- UCRT stdio ----
    494   if build_dump "$label-stdio" "$STDIO_EXE" "$STDIO_DUMP" -- "$STDIO_C"; then
    495     no_legacy_crt_imports "$label-stdio-no-legacy-crt" "$STDIO_DUMP"
    496     contains "$label-stdio-crt-stdio-dll" "$STDIO_DUMP" "DLL Name: api-ms-win-crt-stdio-l1-1-0.dll"
    497     contains "$label-stdio-fflush" "$STDIO_DUMP" "Name:     fflush"
    498     run_wine_if_available "$label-UCRT-stdio" "$image" "$pod_arch" "$STDIO_EXE"
    499   fi
    500 
    501   # ---- imported-data ----
    502   if build_dump "$label-importdata" "$IMPORTDATA_EXE" "$IMPORTDATA_DUMP" -- "$IMPORTDATA_C"; then
    503     no_legacy_crt_imports "$label-importdata-no-legacy-crt" "$IMPORTDATA_DUMP"
    504     contains "$label-importdata-crt-private-dll" "$IMPORTDATA_DUMP" "DLL Name: api-ms-win-crt-private-l1-1-0.dll"
    505     contains "$label-importdata-dcrt-env" "$IMPORTDATA_DUMP" "Name:     __dcrt_initial_narrow_environment"
    506     run_wine_if_available "$label-imported-data" "$image" "$pod_arch" "$IMPORTDATA_EXE"
    507   fi
    508 
    509   # ---- TLS ----
    510   if build_dump "$label-tls" "$TLS_EXE" "$TLS_DUMP" -- "$TLS_C"; then
    511     no_legacy_crt_imports "$label-tls-no-legacy-crt" "$TLS_DUMP"
    512     matches "$label-tls-directory" "$TLS_DUMP" \
    513       '^[[:space:]]*9[[:space:]]+TLS[[:space:]]+0x[0-9a-fA-F]+[[:space:]]+0x00000028'
    514   fi
    515 
    516   # ---- GUI WinMain ----
    517   if build_dump "$label-gui" "$GUI_EXE" "$GUI_DUMP" -- -mwindows "$GUI_C"; then
    518     contains "$label-gui-subsystem" "$GUI_DUMP" "Subsystem:           2  (WINDOWS_GUI)"
    519     no_legacy_crt_imports "$label-gui-no-legacy-crt" "$GUI_DUMP"
    520   fi
    521 
    522   run_wine_if_available "$label-TLS" "$image" "$pod_arch" "$TLS_EXE"
    523 done
    524 
    525 if [ "$ran" -eq 0 ]; then
    526   skip_test "$LABEL_SUITE" "set KIT_SYSROOT or install llvm-mingw UCRT under /tmp/llvm-mingw*"
    527 fi
    528 
    529 kit_summary "$LABEL_SUITE"
    530 kit_exit