From cf4441c41519780f971a4c8b9cd6681f1bbeea0f Mon Sep 17 00:00:00 2001 From: Benjamin Oldenburg Date: Sun, 15 Mar 2026 16:58:23 +0700 Subject: [PATCH] Fix Windows ARM64 runtime regressions --- .github/workflows/build.yml | 12 +++++++++++- arm64-asm.c | 35 ++++++++++++++++++++++++----------- arm64-gen.c | 19 ++++++++++++++----- tcc.c | 9 ++++++--- win32/build-tcc.bat | 2 +- win32/test_rstdin.c | 11 +++++++++++ 6 files changed, 67 insertions(+), 21 deletions(-) create mode 100644 win32/test_rstdin.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 506b6b7c..a59d37cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,17 @@ jobs: cd win32 call build-tcc.bat -t arm64 -c clang echo ::endgroup:: - .\tcc -v + .\tcc -B. -v + .\tcc -B. ..\win32\test_arm64.c -o test_arm64.exe && .\test_arm64.exe + .\tcc -B. -run ..\examples\ex1.c + > test_rstdin.txt echo arm64 stdin + .\tcc -B. -rstdin test_rstdin.txt -run ..\win32\test_rstdin.c > test_rstdin.out + type test_rstdin.out + fc /n test_rstdin.out test_rstdin.txt + .\tcc -B. ..\tests\tests2\49_bracket_evaluation.c -o test49.exe && .\test49.exe > test49.out + fc /n test49.out ..\tests\tests2\49_bracket_evaluation.expect + .\tcc -B. ..\tests\tests2\133_old_func.c -o test133.exe && .\test133.exe > test133.out + fc /n test133.out ..\tests\tests2\133_old_func.expect test-armv7-linux: runs-on: ubuntu-22.04 diff --git a/arm64-asm.c b/arm64-asm.c index a85377a2..ef9d5d7b 100644 --- a/arm64-asm.c +++ b/arm64-asm.c @@ -3,7 +3,7 @@ * ARM64 (AArch64) assembler for TCC * * Based on ARM64 Architecture Reference Manual - * Supports AArch64 instruction set for inline assembly + * Supports AArch64 assembler parsing plus basic inline asm strings */ #ifdef TARGET_DEFS_ONLY @@ -1169,29 +1169,42 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier) } } -/* Generate code for inline asm - ARM64 inline asm with constraints not yet fully implemented */ +static int asm_has_clobbers(const uint8_t *clobber_regs) +{ + int i; + for (i = 0; i < NB_ASM_REGS; ++i) + if (clobber_regs[i]) + return 1; + return 0; +} + +/* Basic inline asm strings are assembled directly by tccasm.c. + Operand allocation and clobber handling are still unsupported here. */ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg) { - /* For now, just handle clobber registers by marking them as volatile */ - /* TODO: Implement full ARM64 inline asm support with register allocation */ - if (nb_operands > 0 || out_reg > 0) { - tcc_error("ARM64 inline asm with operands is not implemented"); - } - gen_nop(); + (void)operands; + (void)nb_outputs; + (void)is_output; + + if (nb_operands > 0 || asm_has_clobbers(clobber_regs) || out_reg >= 0) + tcc_error("ARM64 extended inline asm is not implemented"); } -/* Compute constraints - ARM64 not yet fully implemented */ ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg) { - /* TODO: Implement ARM64 constraint computation */ + (void)operands; + (void)nb_outputs; + if (pout_reg) - *pout_reg = 0; + *pout_reg = -1; + if (nb_operands > 0 || asm_has_clobbers(clobber_regs)) + tcc_error("ARM64 extended inline asm is not implemented"); } /* Handle clobber list */ diff --git a/arm64-gen.c b/arm64-gen.c index d73e9a1a..37eddbdf 100644 --- a/arm64-gen.c +++ b/arm64-gen.c @@ -874,12 +874,13 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l size = type_size(type[i], &align); #if defined(TCC_TARGET_MACHO) - if (variadic && i == variadic) { + if (variadic > 0 && i == variadic) { nx = 8; nv = 8; } #elif defined(TCC_TARGET_PE) - if (variadic && i >= variadic && (hfa || is_float(type[i]->t))) { + if ((variadic < 0 || (variadic > 0 && i >= variadic)) + && (hfa || is_float(type[i]->t))) { hfa = 0; if (is_float(type[i]->t)) { win_vararg_float = 1; @@ -992,6 +993,8 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l return ns - 32; } +#define ARM64_PCS_ALL_VARARGS (-1) + static unsigned long arm64_pcs(int variadic, int n, CType **type, unsigned long *a) { unsigned long stack; @@ -1074,6 +1077,7 @@ ST_FUNC void gfunc_call(int nb_args) unsigned long *a, *a1; unsigned long stack; int i; + int pcs_variadic = 0; int func_type = vtop[-nb_args].type.ref->f.func_type; int variadic = (func_type == FUNC_ELLIPSIS); int old_style = (func_type == FUNC_OLD); @@ -1098,7 +1102,11 @@ ST_FUNC void gfunc_call(int nb_args) for (i = 0; i < nb_args; i++) t[nb_args - i] = &vtop[-i].type; - stack = arm64_pcs((variadic || old_style) ? var_nb_arg : 0, nb_args, t, a); + if (variadic) + pcs_variadic = var_nb_arg; + else if (old_style) + pcs_variadic = ARM64_PCS_ALL_VARARGS; + stack = arm64_pcs(pcs_variadic, nb_args, t, a); // Allocate space for structs replaced by pointer: for (i = nb_args; i; i--) @@ -1263,6 +1271,7 @@ ST_FUNC void gfunc_call(int nb_args) static unsigned long arm64_func_va_list_stack; static int arm64_func_va_list_gr_offs; static int arm64_func_va_list_vr_offs; +static unsigned arm64_func_start_offset; static int arm64_func_sub_sp_offset; #define ARM64_FUNC_STACK_SETUP_SLOTS 6 @@ -1341,6 +1350,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) last_int = last_int > 4 ? 4 : last_int; last_float = last_float > 4 ? 4 : last_float; + arm64_func_start_offset = ind; o(0xa9b27bfd); // stp x29,x30,[sp,#-224]! for (i = 0; i < last_float; i++) // stp q0,q1,[sp,#16], stp q2,q3,[sp,#48] @@ -1664,8 +1674,7 @@ ST_FUNC void gfunc_epilog(void) #ifdef TCC_TARGET_PE { - unsigned start = arm64_func_sub_sp_offset - 8; - pe_add_unwind_data(start, ind, -loc); + pe_add_unwind_data(arm64_func_start_offset, ind, -loc); } #endif } diff --git a/tcc.c b/tcc.c index ec148d91..1194d6b9 100644 --- a/tcc.c +++ b/tcc.c @@ -400,6 +400,11 @@ static int tcc_run_via_temp_exe(TCCState *s, int argc, char **argv) DeleteFileA(tmppath); return ret; } + +static int tcc_run_requires_inprocess(const TCCState *s) +{ + return (s->dflag & 16) || s->run_stdin != NULL; +} #endif int main(int argc, char **argv) @@ -513,9 +518,7 @@ redo: if (s->output_type == TCC_OUTPUT_MEMORY) { #ifdef TCC_IS_NATIVE #if defined(_WIN32) && defined(__aarch64__) - if (s->dflag & 16) - ret = tcc_run(s, argc, argv); - else if (first_file && 0 == strcmp(tcc_basename(first_file), "tcc.c")) + if (tcc_run_requires_inprocess(s)) ret = tcc_run(s, argc, argv); else ret = tcc_run_via_temp_exe(s, argc, argv); diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index 6e8e58e4..4c3cb1a2 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -179,7 +179,7 @@ if exist libtcc.dll .\tcc -impdef libtcc.dll -o libtcc\libtcc.def @if errorlevel 1 goto :the_end :lib -@rem ARM64 now supported with implemented assembler +@rem ARM64 assembler files and basic inline asm strings are supported here. call :make_lib %T% || goto :the_end @if exist %PX%-tcc.exe call :make_lib %TX% %PX%- || goto :the_end diff --git a/win32/test_rstdin.c b/win32/test_rstdin.c new file mode 100644 index 00000000..5e84c185 --- /dev/null +++ b/win32/test_rstdin.c @@ -0,0 +1,11 @@ +#include + +int main(void) +{ + char buf[64]; + + if (!fgets(buf, sizeof buf, stdin)) + return 1; + printf("%s", buf); + return 0; +}