From 904e95cbdf0248a57e5f8675ff10d17c59f5adbe Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Thu, 21 May 2026 08:13:41 +0900 Subject: [PATCH] win32: avoid Interlocked imports for tcc arm64 Windows/arm64 exposes Interlocked* operations as compiler intrinsics rather than kernel32 exports. When tcc -run self-compiles tcc.c, calls to InterlockedCompareExchange or InterlockedExchange can therefore remain as unresolved imports in the in-memory linker. Route the TinyCC arm64 path through the existing __atomic helpers while keeping Interlocked* for other Windows compilers. The compile-lock initialization state machine remains unchanged. --- tcc.h | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/tcc.h b/tcc.h index c74fae47..083e9d30 100644 --- a/tcc.h +++ b/tcc.h @@ -1930,12 +1930,46 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) #if CONFIG_TCC_SEMLOCK #if defined _WIN32 typedef struct { volatile LONG init; CRITICAL_SECTION cs; } TCCSem; +#if defined __TINYC__ && (defined __aarch64__ || defined __arm64__) +/* Windows/arm64 Interlocked* names are compiler intrinsics, not + kernel32 exports, so tcc -run must not emit calls to them. */ +# define TCC_SEM_USE_ATOMICS 1 +enum { TCC_SEM_ATOMIC_SEQ_CST = 5 }; +#endif +static inline LONG tcc_sem_cmpxchg(volatile LONG *ptr, LONG val, LONG cmp) { +#ifdef TCC_SEM_USE_ATOMICS + LONG old = cmp; + __atomic_compare_exchange((LONG *)ptr, &old, &val, 0, + TCC_SEM_ATOMIC_SEQ_CST, + TCC_SEM_ATOMIC_SEQ_CST); + return old; +#else + return InterlockedCompareExchange(ptr, val, cmp); +#endif +} +static inline void tcc_sem_store(volatile LONG *ptr, LONG val) { +#ifdef TCC_SEM_USE_ATOMICS + __atomic_store((LONG *)ptr, &val, TCC_SEM_ATOMIC_SEQ_CST); +#else + InterlockedExchange(ptr, val); +#endif +} +static inline LONG tcc_sem_load(volatile LONG *ptr) { +#ifdef TCC_SEM_USE_ATOMICS + LONG val; + __atomic_load((LONG *)ptr, &val, TCC_SEM_ATOMIC_SEQ_CST); + return val; +#else + return InterlockedCompareExchange(ptr, 0, 0); +#endif +} static inline void wait_sem(TCCSem *p) { - if (InterlockedCompareExchange(&p->init, 1, 0) == 0) { + if (tcc_sem_cmpxchg(&p->init, 1, 0) == 0) { InitializeCriticalSection(&p->cs); - InterlockedExchange(&p->init, 2); + tcc_sem_store(&p->init, 2); } else { - while (InterlockedCompareExchange(&p->init, 2, 2) != 2) + /* On tcc/arm64, __atomic_load maps to the acquire helper path. */ + while (tcc_sem_load(&p->init) != 2) Sleep(0); } EnterCriticalSection(&p->cs);