Fix Windows ARM64 runtime regressions

This commit is contained in:
Benjamin Oldenburg 2026-03-15 16:58:23 +07:00
parent 4f4b3dda6b
commit cf4441c415
6 changed files with 67 additions and 21 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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
}

9
tcc.c
View File

@ -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);

View File

@ -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

11
win32/test_rstdin.c Normal file
View File

@ -0,0 +1,11 @@
#include <stdio.h>
int main(void)
{
char buf[64];
if (!fgets(buf, sizeof buf, stdin))
return 1;
printf("%s", buf);
return 0;
}