From 396675f74f3189000e4afaf38bae6a8bfb0662e9 Mon Sep 17 00:00:00 2001 From: Benjamin Oldenburg Date: Sun, 15 Mar 2026 20:26:18 +0700 Subject: [PATCH] Fix Windows ARM64 runtime regressions and coverage --- .github/workflows/build.yml | 21 ++++- tcc-doc.texi | 4 + tcc.c | 37 ++++++++- tcc.h | 2 +- tccgen.c | 1 + tccpe.c | 43 +++++++++- tccrun.c | 46 ++++++++--- win32/build-tcc.bat | 1 - win32/include/winapi/winnt.h | 95 +++++++++++++++++----- win32/test_arm64_libtcc_context.S | 34 ++++++++ win32/test_arm64_libtcc_context.c | 126 ++++++++++++++++++++++++++++++ win32/test_pe_field_alignment.c | 16 ++++ win32/test_pe_field_alignment.ref | 1 + win32/test_run_argv.c | 11 +++ win32/test_run_argv.ref | 4 + win32/test_run_exit.c | 6 ++ win32/test_run_stdin.c | 11 +++ win32/test_run_stdin.ref | 1 + 18 files changed, 422 insertions(+), 38 deletions(-) create mode 100644 win32/test_arm64_libtcc_context.S create mode 100644 win32/test_arm64_libtcc_context.c create mode 100644 win32/test_pe_field_alignment.c create mode 100644 win32/test_pe_field_alignment.ref create mode 100644 win32/test_run_argv.c create mode 100644 win32/test_run_argv.ref create mode 100644 win32/test_run_exit.c create mode 100644 win32/test_run_stdin.c create mode 100644 win32/test_run_stdin.ref diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a9568a1..6ff50bf0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,11 @@ jobs: steps: - uses: actions/checkout@v4 - name: make & test tcc (x86_64-linux) - run: ./configure && make && make test -k + run: | + ./configure + make + make test -k + make -C tests/tests2 tests2.112 tests2.128 test-x86_64-osx: runs-on: macos-15-intel @@ -54,6 +58,8 @@ jobs: cd win32 call build-tcc.bat -t 64 -c cl echo ::endgroup:: + .\tcc -B. ..\win32\test_pe_field_alignment.c -o test_pe_field_alignment.exe && .\test_pe_field_alignment.exe > test_pe_field_alignment.out + fc /n test_pe_field_alignment.out ..\win32\test_pe_field_alignment.ref .\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe .\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c @@ -100,9 +106,17 @@ jobs: cd win32 call build-tcc.bat -t arm64 -c clang echo ::endgroup:: + if not exist libtcc.dll exit /b 1 .\tcc -B. -v + .\tcc -B. -run ..\win32\test_run_argv.c alpha "two words" beta > test_run_argv.out + fc /n test_run_argv.out ..\win32\test_run_argv.ref + type ..\win32\test_run_stdin.ref | .\tcc -B. -run ..\win32\test_run_stdin.c > test_run_stdin.out + fc /n test_run_stdin.out ..\win32\test_run_stdin.ref + powershell -NoProfile -Command "$before = @(Get-ChildItem -Path $env:TEMP -Filter 'tcc*.tmp' -Name -ErrorAction SilentlyContinue); & .\tcc -B. -run ..\win32\test_run_exit.c; if ($LASTEXITCODE -ne 27) { exit 1 }; $after = @(Get-ChildItem -Path $env:TEMP -Filter 'tcc*.tmp' -Name -ErrorAction SilentlyContinue); if (Compare-Object $before $after) { Write-Host 'Temporary -run file cleanup mismatch'; Compare-Object $before $after; exit 1 }" .\tcc -B. ..\win32\test_arm64.c -o test_arm64.exe && .\test_arm64.exe .\tcc -B. -run ..\examples\ex1.c + clang -O0 -I.. ..\win32\test_arm64_libtcc_context.c ..\win32\test_arm64_libtcc_context.S -o test_libtcc_context.exe + .\test_libtcc_context.exe .\tcc -B. ..\win32\test_arm64_inline_asm.c -o test_inline_asm.exe && .\test_inline_asm.exe > test_inline_asm.out > test_inline_asm.expect echo inline asm ok fc /n test_inline_asm.out test_inline_asm.expect @@ -173,7 +187,10 @@ jobs: apt-get install -q -y gcc make run: | echo "::endgroup::" # flatten 'run container' - ./configure && make && make test -k + ./configure + make + make test -k + make -C tests/tests2 tests2.73 tests2.109 tests2.121 tests2.133 test-riscv64-linux: runs-on: ubuntu-22.04 diff --git a/tcc-doc.texi b/tcc-doc.texi index 9a9695f7..ae39462d 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -175,6 +175,10 @@ In a script, it gives the following header: @example #!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 @end example +On native Windows ARM64 builds, CLI @option{-run} currently uses a +temporary executable for ordinary runs as a compatibility workaround. +@code{libtcc} @code{tcc_run()} remains in-process, and CLI keeps the +in-process path for @option{-dt} and @option{-rstdin}. @item -v Display TCC version. diff --git a/tcc.c b/tcc.c index ac76976a..22d38319 100644 --- a/tcc.c +++ b/tcc.c @@ -234,6 +234,36 @@ static void print_search_dirs(TCCState *s) static void set_environment(TCCState *s) { +#ifdef _WIN32 + static const char * const names[] = { + "C_INCLUDE_PATH", + "CPATH", + "LIBRARY_PATH", + }; + int i; + + for (i = 0; i < sizeof(names) / sizeof(names[0]); ++i) { + DWORD len = GetEnvironmentVariableA(names[i], NULL, 0); + char *path; + + if (!len) + continue; + path = tcc_malloc(len); + if (!path) + continue; + if (!GetEnvironmentVariableA(names[i], path, len)) { + tcc_free(path); + continue; + } + if (i == 0) + tcc_add_sysinclude_path(s, path); + else if (i == 1) + tcc_add_include_path(s, path); + else + tcc_add_library_path(s, path); + tcc_free(path); + } +#else char * path; path = getenv("C_INCLUDE_PATH"); @@ -248,6 +278,7 @@ static void set_environment(TCCState *s) if(path != NULL) { tcc_add_library_path(s, path); } +#endif } static char *default_outputfile(TCCState *s, const char *first_file) @@ -337,9 +368,6 @@ static int tcc_run_via_temp_exe(TCCState *s, int argc, char **argv) return tcc_error_noabort("could not get temp directory"), -1; if (!GetTempFileNameA(tmpdir, "tcc", 0, tmppath)) return tcc_error_noabort("could not create temp file name"), -1; - DeleteFileA(tmppath); - strcpy(tcc_fileextension(tmppath), ".exe"); - DeleteFileA(tmppath); saved_outfile = s->outfile; saved_output_type = s->output_type; @@ -403,6 +431,9 @@ static int tcc_run_via_temp_exe(TCCState *s, int argc, char **argv) static int tcc_run_requires_inprocess(const TCCState *s) { + /* Temporary Windows ARM64 workaround: keep the generic in-process path + where CLI features rely on it, but run ordinary `tcc -run` through a + child process until the native runtime path is fully equivalent. */ return (s->dflag & 16) || s->run_stdin != NULL; } #endif diff --git a/tcc.h b/tcc.h index e7c65b70..307fc6c5 100644 --- a/tcc.h +++ b/tcc.h @@ -592,7 +592,7 @@ typedef struct Section { typedef struct DLLReference { int level; void *handle; - unsigned char found, index; + unsigned char found, index, process_scoped; char name[1]; } DLLReference; diff --git a/tccgen.c b/tccgen.c index 18d1bdc9..941e4ed3 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4226,6 +4226,7 @@ static void struct_layout(CType *type, AttributeDef *ad) } /* some individual align was specified */ #ifdef TCC_TARGET_PE + /* GNU aligned(n) on a field is a minimum, not a way to lower alignment. */ if (a > align) align = a; #else diff --git a/tccpe.c b/tccpe.c index 58481f9b..f78f7cd4 100644 --- a/tccpe.c +++ b/tccpe.c @@ -29,6 +29,41 @@ #include /* chmod() */ #endif +#if defined(_WIN32) && defined(TCC_IS_NATIVE) && defined(TCC_TARGET_ARM64) +static TCCSem pe_msvcrt_sem; + +static HMODULE pe_get_process_msvcrt_handle(void) +{ + static HMODULE handle; + HMODULE dll; + + wait_sem(&pe_msvcrt_sem); + dll = handle; + if (!dll) { + dll = LoadLibraryA("msvcrt.dll"); + if (dll) + handle = dll; + } + post_sem(&pe_msvcrt_sem); + return dll; +} + +static HMODULE pe_load_runtime_dll(const char *name, unsigned char *process_scoped) +{ + HMODULE dll = NULL; + + *process_scoped = 0; + if (0 == PATHCMP(tcc_basename(name), "msvcrt.dll")) { + dll = pe_get_process_msvcrt_handle(); + if (dll) + *process_scoped = 1; + } + if (!dll) + dll = LoadLibraryA(name); + return dll; +} +#endif + #ifdef TCC_TARGET_X86_64 # define ADDR3264 ULONGLONG # define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 @@ -995,8 +1030,14 @@ static void pe_build_imports(struct pe_info *pe) #ifdef TCC_IS_NATIVE if (pe->type == PE_RUN) { if (dllref) { - if ( !dllref->handle ) + if (!dllref->handle) { +#if defined(_WIN32) && defined(TCC_TARGET_ARM64) + dllref->handle = pe_load_runtime_dll(dllref->name, + &dllref->process_scoped); +#else dllref->handle = LoadLibraryA(dllref->name); +#endif + } v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name); } if (!v) diff --git a/tccrun.c b/tccrun.c index 8d3be65a..57c1c26b 100644 --- a/tccrun.c +++ b/tccrun.c @@ -181,10 +181,7 @@ ST_FUNC void tcc_run_free(TCCState *s1) if ( ref->handle ) #ifdef _WIN32 # if defined(__aarch64__) - /* Native ARM64 builds currently host libtcc with the UCRT while - generated PE code still imports msvcrt. Unloading msvcrt from - nested -run states corrupts teardown, so leave it process-wide. */ - if (0 == PATHCMP(tcc_basename(ref->name), "msvcrt.dll")) + if (ref->process_scoped) continue; # endif FreeLibrary((HMODULE)ref->handle); @@ -215,20 +212,28 @@ ST_FUNC void tcc_run_free(TCCState *s1) #ifdef _WIN32 static char **rt_get_environ(void) { -#ifdef __TINYC__ - return NULL; + char **env = NULL; +#ifdef _UCRT + char ***penv = __p__environ(); + if (penv) + env = *penv; #else - return environ; + _get_environ(&env); #endif + return env; } static wchar_t **rt_get_wenviron(void) { -#ifdef __TINYC__ - return NULL; + wchar_t **env = NULL; +#ifdef _UCRT + wchar_t ***penv = __p__wenviron(); + if (penv) + env = *penv; #else - return _wenviron; + _get_wenviron(&env); #endif + return env; } #endif @@ -260,6 +265,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) #if defined(__APPLE__) extern char ***_NSGetEnviron(void); char **envp = *_NSGetEnviron(); +#elif defined(_WIN32) + char **envp = rt_get_environ(); #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) extern char **environ; char **envp = environ; @@ -1442,6 +1449,23 @@ static PVOID rt_exception_handler; #if defined(_WIN64) && defined(__aarch64__) && !defined(CONFIG_TCC_BACKTRACE_ONLY) typedef VOID (__cdecl *rt_restore_context_func_t)(PCONTEXT, struct _EXCEPTION_RECORD *); +#define RT_ARM64_CONTEXT_ASSERT(name, expr) \ + typedef char rt_arm64_context_assert_##name[(expr) ? 1 : -1] +RT_ARM64_CONTEXT_ASSERT(size, sizeof(CONTEXT) == 0x390); +RT_ARM64_CONTEXT_ASSERT(flags_offset, offsetof(CONTEXT, ContextFlags) == 0x000); +RT_ARM64_CONTEXT_ASSERT(x_offset, offsetof(CONTEXT, X) == 0x008); +RT_ARM64_CONTEXT_ASSERT(fp_offset, offsetof(CONTEXT, Fp) == 0x0f0); +RT_ARM64_CONTEXT_ASSERT(lr_offset, offsetof(CONTEXT, Lr) == 0x0f8); +RT_ARM64_CONTEXT_ASSERT(sp_offset, offsetof(CONTEXT, Sp) == 0x100); +RT_ARM64_CONTEXT_ASSERT(pc_offset, offsetof(CONTEXT, Pc) == 0x108); +RT_ARM64_CONTEXT_ASSERT(v_offset, offsetof(CONTEXT, V) == 0x110); +RT_ARM64_CONTEXT_ASSERT(v_slot_size, sizeof(((CONTEXT *)0)->V[0]) == 16); +RT_ARM64_CONTEXT_ASSERT(fpcr_offset, offsetof(CONTEXT, Fpcr) == 0x310); +RT_ARM64_CONTEXT_ASSERT(fpsr_offset, offsetof(CONTEXT, Fpsr) == 0x314); +RT_ARM64_CONTEXT_ASSERT(bvr_offset, offsetof(CONTEXT, Bvr) == 0x338); +RT_ARM64_CONTEXT_ASSERT(wvr_offset, offsetof(CONTEXT, Wvr) == 0x380); +#undef RT_ARM64_CONTEXT_ASSERT + static rt_restore_context_func_t rt_get_restore_context_func(void) { static rt_restore_context_func_t fn; @@ -1479,7 +1503,7 @@ static void rt_restore_context_from_jmpbuf(void *p_jmp_buf, int code) ctx.Sp = jb->Sp; ctx.Pc = jb->Lr; for (i = 0; i < 8; ++i) - memcpy(&ctx.V[8 + i], &jb->D[i], sizeof(jb->D[i])); + memcpy(&ctx.V[8 + i].D[0], &jb->D[i], sizeof(jb->D[i])); ctx.Fpcr = jb->Fpcr; ctx.Fpsr = jb->Fpsr; fn = rt_get_restore_context_func(); diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index 4c3cb1a2..7a449ee6 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -119,7 +119,6 @@ goto :p3 :tarm64 set D=%DARM64% set P=%PARM64% -set TCC_C=..\tcc.c goto :p3 :p3 diff --git a/win32/include/winapi/winnt.h b/win32/include/winapi/winnt.h index 746e6973..0897e2af 100644 --- a/win32/include/winapi/winnt.h +++ b/win32/include/winapi/winnt.h @@ -1423,7 +1423,7 @@ typedef DWORD LCID; typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context); -#ifdef _ARM64_ +#if defined(_ARM64_) || defined(__aarch64__) /* ARM64 Context Definition */ #define CONTEXT_ARM64 0x00400000 @@ -1448,26 +1448,83 @@ typedef DWORD LCID; #define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG) #endif -#ifndef _ARM64_CONTEXT_DECLARED -#define _ARM64_CONTEXT_DECLARED - typedef struct _CONTEXT { - DWORD64 ContextFlags; - DWORD64 X[29]; - DWORD64 Fp; - DWORD64 Lr; - DWORD64 Sp; - DWORD64 Pc; - DWORD64 V[32]; - DWORD Fpcr; - DWORD Fpsr; - DWORD Bcr[8]; - DWORD Bvr[8]; - DWORD Wcr[2]; - DWORD Wvr[2]; - } CONTEXT,*PCONTEXT; +#ifndef ARM64_MAX_BREAKPOINTS +#define ARM64_MAX_BREAKPOINTS 8 +#endif +#ifndef ARM64_MAX_WATCHPOINTS +#define ARM64_MAX_WATCHPOINTS 2 #endif -#endif /* _ARM64_ */ +#ifndef _ARM64_NT_NEON128_DECLARED +#define _ARM64_NT_NEON128_DECLARED + typedef union _ARM64_NT_NEON128 { + struct { + ULONGLONG Low; + LONGLONG High; + } DUMMYSTRUCTNAME; + double D[2]; + float S[4]; + WORD H[8]; + BYTE B[16]; + } ARM64_NT_NEON128,*PARM64_NT_NEON128; +#endif + +#ifndef _ARM64_CONTEXT_DECLARED +#define _ARM64_CONTEXT_DECLARED + typedef struct DECLSPEC_ALIGN(16) _ARM64_NT_CONTEXT { + ULONG ContextFlags; + ULONG Cpsr; + union { + struct { + DWORD64 X0; + DWORD64 X1; + DWORD64 X2; + DWORD64 X3; + DWORD64 X4; + DWORD64 X5; + DWORD64 X6; + DWORD64 X7; + DWORD64 X8; + DWORD64 X9; + DWORD64 X10; + DWORD64 X11; + DWORD64 X12; + DWORD64 X13; + DWORD64 X14; + DWORD64 X15; + DWORD64 X16; + DWORD64 X17; + DWORD64 X18; + DWORD64 X19; + DWORD64 X20; + DWORD64 X21; + DWORD64 X22; + DWORD64 X23; + DWORD64 X24; + DWORD64 X25; + DWORD64 X26; + DWORD64 X27; + DWORD64 X28; + DWORD64 Fp; + DWORD64 Lr; + } DUMMYSTRUCTNAME; + DWORD64 X[31]; + } DUMMYUNIONNAME; + DWORD64 Sp; + DWORD64 Pc; + ARM64_NT_NEON128 V[32]; + DWORD Fpcr; + DWORD Fpsr; + DWORD Bcr[ARM64_MAX_BREAKPOINTS]; + DWORD64 Bvr[ARM64_MAX_BREAKPOINTS]; + DWORD Wcr[ARM64_MAX_WATCHPOINTS]; + DWORD64 Wvr[ARM64_MAX_WATCHPOINTS]; + } ARM64_NT_CONTEXT,*PARM64_NT_CONTEXT; +#endif + + typedef ARM64_NT_CONTEXT CONTEXT,*PCONTEXT; + +#endif /* _ARM64_ || __aarch64__ */ typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions); #define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback" diff --git a/win32/test_arm64_libtcc_context.S b/win32/test_arm64_libtcc_context.S new file mode 100644 index 00000000..eff145d8 --- /dev/null +++ b/win32/test_arm64_libtcc_context.S @@ -0,0 +1,34 @@ + .text + .p2align 2 + .global arm64_call_with_dregs + +arm64_call_with_dregs: + stp x29, x30, [sp, #-32]! + stp x19, x20, [sp, #16] + mov x29, sp + mov x19, x1 + + ldr d8, [x0, #0] + ldr d9, [x0, #8] + ldr d10, [x0, #16] + ldr d11, [x0, #24] + ldr d12, [x0, #32] + ldr d13, [x0, #40] + ldr d14, [x0, #48] + ldr d15, [x0, #56] + + mov x0, x3 + blr x2 + + str d8, [x19, #0] + str d9, [x19, #8] + str d10, [x19, #16] + str d11, [x19, #24] + str d12, [x19, #32] + str d13, [x19, #40] + str d14, [x19, #48] + str d15, [x19, #56] + + ldp x19, x20, [sp, #16] + ldp x29, x30, [sp], #32 + ret diff --git a/win32/test_arm64_libtcc_context.c b/win32/test_arm64_libtcc_context.c new file mode 100644 index 00000000..6e69db23 --- /dev/null +++ b/win32/test_arm64_libtcc_context.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#include "libtcc.h" + +typedef struct libtcc_api { + TCCState *(*tcc_new)(void); + void (*tcc_delete)(TCCState *s); + void (*tcc_set_lib_path)(TCCState *s, const char *path); + void (*tcc_set_error_func)(TCCState *s, void *opaque, TCCErrorFunc *error_func); + int (*tcc_set_output_type)(TCCState *s, int output_type); + int (*tcc_add_include_path)(TCCState *s, const char *pathname); + int (*tcc_add_library_path)(TCCState *s, const char *pathname); + int (*tcc_compile_string)(TCCState *s, const char *buf); + int (*tcc_run)(TCCState *s, int argc, char **argv); +} libtcc_api; + +typedef struct test_context { + libtcc_api api; +} test_context; + +extern int arm64_call_with_dregs(const double *expected, double *actual, + int (*fn)(void *opaque), void *opaque); + +static const char run_program[] = + "void exit(int);\n" + "int main(int argc, char **argv)\n" + "{\n" + " if (argc != 2)\n" + " return 11;\n" + " if (argv[1][0] != 'x' || argv[1][1] != '\\0')\n" + " return 12;\n" + " exit(42);\n" + "}\n"; + +static void handle_error(void *opaque, const char *msg) +{ + fprintf((FILE *)opaque, "%s\n", msg); +} + +static FARPROC load_symbol(HMODULE dll, const char *name) +{ + FARPROC proc = GetProcAddress(dll, name); + if (!proc) { + fprintf(stderr, "missing libtcc symbol: %s\n", name); + exit(1); + } + return proc; +} + +static int run_once(void *opaque) +{ + test_context *ctx = (test_context *)opaque; + TCCState *s; + char *argv[] = { "arm64_libtcc_context", "x" }; + int ret; + + s = ctx->api.tcc_new(); + if (!s) { + fprintf(stderr, "tcc_new failed\n"); + return 1; + } + + ctx->api.tcc_set_error_func(s, stderr, handle_error); + ctx->api.tcc_set_lib_path(s, "."); + ctx->api.tcc_add_include_path(s, ".\\include"); + ctx->api.tcc_add_library_path(s, ".\\lib"); + + ret = ctx->api.tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + if (!ret) + ret = ctx->api.tcc_compile_string(s, run_program); + if (!ret) + ret = ctx->api.tcc_run(s, 2, argv); + + ctx->api.tcc_delete(s); + return ret; +} + +int main(void) +{ + static const double expected[8] = { + 1.25, -2.5, 3.75, -4.875, + 5.5, -6.625, 7.75, -8.875 + }; + double actual[8]; + HMODULE dll; + test_context ctx; + int i; + + memset(&ctx, 0, sizeof(ctx)); + dll = LoadLibraryA("libtcc.dll"); + if (!dll) { + fprintf(stderr, "failed to load libtcc.dll\n"); + return 1; + } + + ctx.api.tcc_new = (void *)load_symbol(dll, "tcc_new"); + ctx.api.tcc_delete = (void *)load_symbol(dll, "tcc_delete"); + ctx.api.tcc_set_lib_path = (void *)load_symbol(dll, "tcc_set_lib_path"); + ctx.api.tcc_set_error_func = (void *)load_symbol(dll, "tcc_set_error_func"); + ctx.api.tcc_set_output_type = (void *)load_symbol(dll, "tcc_set_output_type"); + ctx.api.tcc_add_include_path = (void *)load_symbol(dll, "tcc_add_include_path"); + ctx.api.tcc_add_library_path = (void *)load_symbol(dll, "tcc_add_library_path"); + ctx.api.tcc_compile_string = (void *)load_symbol(dll, "tcc_compile_string"); + ctx.api.tcc_run = (void *)load_symbol(dll, "tcc_run"); + + for (i = 0; i < 32; ++i) { + memset(actual, 0, sizeof(actual)); + if (arm64_call_with_dregs(expected, actual, run_once, &ctx) != 42) { + fprintf(stderr, "tcc_run did not return 42 on iteration %d\n", i); + FreeLibrary(dll); + return 1; + } + if (memcmp(expected, actual, sizeof(expected)) != 0) { + fprintf(stderr, "nonvolatile FP registers were not restored on iteration %d\n", i); + FreeLibrary(dll); + return 1; + } + } + + puts("arm64 libtcc context ok"); + FreeLibrary(dll); + return 0; +} diff --git a/win32/test_pe_field_alignment.c b/win32/test_pe_field_alignment.c new file mode 100644 index 00000000..8d1be8a8 --- /dev/null +++ b/win32/test_pe_field_alignment.c @@ -0,0 +1,16 @@ +#include +#include + +struct pe_field_align_min { + char c; + double d __attribute__((aligned(1))); +}; + +int main(void) +{ + printf("size=%u align=%u off=%u\n", + (unsigned)sizeof(struct pe_field_align_min), + (unsigned)__alignof__(struct pe_field_align_min), + (unsigned)offsetof(struct pe_field_align_min, d)); + return 0; +} diff --git a/win32/test_pe_field_alignment.ref b/win32/test_pe_field_alignment.ref new file mode 100644 index 00000000..88a88ef2 --- /dev/null +++ b/win32/test_pe_field_alignment.ref @@ -0,0 +1 @@ +size=16 align=8 off=8 diff --git a/win32/test_run_argv.c b/win32/test_run_argv.c new file mode 100644 index 00000000..0d47295f --- /dev/null +++ b/win32/test_run_argv.c @@ -0,0 +1,11 @@ +#include + +int main(int argc, char **argv) +{ + int i; + + printf("argc=%d\n", argc); + for (i = 1; i < argc; ++i) + printf("arg%d=<%s>\n", i, argv[i]); + return 0; +} diff --git a/win32/test_run_argv.ref b/win32/test_run_argv.ref new file mode 100644 index 00000000..6092f200 --- /dev/null +++ b/win32/test_run_argv.ref @@ -0,0 +1,4 @@ +argc=4 +arg1= +arg2= +arg3= diff --git a/win32/test_run_exit.c b/win32/test_run_exit.c new file mode 100644 index 00000000..e7c58f84 --- /dev/null +++ b/win32/test_run_exit.c @@ -0,0 +1,6 @@ +#include + +int main(void) +{ + return 27; +} diff --git a/win32/test_run_stdin.c b/win32/test_run_stdin.c new file mode 100644 index 00000000..69e550fd --- /dev/null +++ b/win32/test_run_stdin.c @@ -0,0 +1,11 @@ +#include + +int main(void) +{ + char buf[128]; + + if (!fgets(buf, sizeof(buf), stdin)) + return 1; + fputs(buf, stdout); + return 0; +} diff --git a/win32/test_run_stdin.ref b/win32/test_run_stdin.ref new file mode 100644 index 00000000..364885a2 --- /dev/null +++ b/win32/test_run_stdin.ref @@ -0,0 +1 @@ +temp exe stdin