To ensure that qualifiers within an array-style
parameter declaration (e.g. int [const 2] are handled
correctly, post_type() is modified to collect qualifiers
and OR them into the t member of CType.
The new test for restrict also passes, but only
because the restrict keyword is ignored.
Previously, TCC wrongly discarded the const and
volatile qualifiers from parameter types when
adjusting them.
- convert_parameter_type() will no longer remove
the const and volatile qualifiers from a CType.
- a new function, convert_expression_type(), will
remove the const and volatile qualifiers before
tail-calling convert_parameter_type().
- unary() and gexpr() will call
convert_expression_type() instead of
convert_parameter_type() to ensure that
expression semantics are unchanged.
The new tests for restrict also pass, but only
because the restrict keyword is ignored.
Clang doesn't combine qualifiers through array types
so put a workaround into tcctest.c to avoid spurious
failures of the recently-added tests for that
operation, when using Clang instead of GCC to
generate the reference output.
Conditional expressions combine the qualifiers
of their pointer target types. TCC only examines
the outer array node, although array qualifiers
are stored on the element type. This makes the
result depend on operand order.
Collect and apply qualifiers through array layers.
__builtin_types_compatible_p ignores qualifiers
exposed through array type derivations in GCC
and Clang, whereas it does not in TCC.
This fix uses the existing unqualified
comparison recursively for array types, while
continuing to preserve qualifiers on referenced
types.
With this commit bound checking will be about 20% .. 25% faster.
(Tested with running testsuites with bound checking.
About 1000 files.)
The speedup is made possible because of TLS implementation.
TLS is not possible with -run so create a new bcheck_run.o
Makefile:lib/Makefile:win32/build-tcc.bat
- Compile new bcheck_run.o
tccelf.c:tccpe.c
- Use bcheck_run.o
lib/bcheck.c
- Use TLS code
tccelf.c:
- set_elf_sym()
check NOBITS instead of just .bss
- sort_sections()
must have common alignment for tls sections
fix BSD relro
tccpe.c:
- sort .tbss after .tdata
tccrun.c:
- TLS not supported with -run
- arm64: FlushInstructionCache on win32 too
lib/bt-exe.c:
- use less unused bss memory (from global vars in tcc.h)
arm64-gen.c:
- arm64_sym():
direct access (no GOT) for 'static' vars
relocate with 'addend' unless GOT
- reserve X16/x17 for internal usage (specifically to avoid
their usage as value register passed to store())
Most of the manual predates the x86-64, ARM64, RISC-V 64 and Mach-O
targets, and parts of it describe things TCC never did or no longer
does. Go through it against the sources: the target table, the C11 and
GNU C extensions, the attributes, built-ins and pragmas, the command
line options and their defaults, the assembler and linker chapters, the
bound checks and the libtcc call sequence.
The developer's guide had drifted the most, from CType and Sym.type down
to gfunc_call() and next_c(), and is resynced as well.
The option groups become @subheading instead of plain text. texi2pod.pl
has no handler for it and would copy them verbatim into tcc.1, so add
one beside the @subsection handler, and move '@c man begin OPTIONS'
above the first heading so that all of them reach the man page.
- tcc_add_linker_symbols():
don't add for dlls
- bind_exe_dynsym():
update _end symbol when done
allow data definition in the .so override a bss symbol
in the exe. For example
exe: int x;
.so: int x = 123;
- set_elf_sym():
cannot compare section numbers with symbols from dlls
tcc_load_obj():
return -1 from symbol conflict errors
tests/tests2/148_linker_symbols:
- use only one file
- make it print useful output rather than just "2 errors."
In general, the tests2 setup with .expect files is meant
to compare text output. For example:
printf("val = %d\n", val);
.expect file can be generated or refreshed using
make tests2.nnn+
or in order to force generation with tcc itself
make tests2.nnn+ GEN-CC='$(GEN-TCC)'
tccgen.c:
- __attribute__((section(...))) : set section type/flags
according to first usage
- fix bcheck bounds for -fcommon
The host-sized symbol addend parameter was introduced by commit b14ef0e2 and truncates 64-bit addends on LLP64 hosts.
Use addr_t and cover the negative-addend case.
Also:
- arm64-gen.c: cleanup load/store
fixes a problem with bound-check test1b with
./configure --cc=tcc
Also, do not use 'long' or 'ul' suffix in tcc because
for example on win32-arm64
(uint64_t) ~0xffful == 0x00000000fffff000
but on linux-arm64
(uint64_t) ~0xffful == 0xfffffffffffff000
Also:
- tccpe.c: cleanup "quoted dll nanes in def" parse
- tests2: enable some threaded tests on windows
An input shared object can be the only place where a conventional boundary name is referenced or defined. In that case the regular symbol table has no entry, but native ELF linkers still synthesize the executable definition so that it participates in dynamic symbol resolution.
Consult the input dynamic symbol table before treating a plain boundary name as unreferenced. Exercise the case with a DSO-defined end symbol whose address must be interposed by the executable's final boundary.
The traditional boundary symbols were recorded against the canonical .text, .data and .bss sections before dynamic binding and final layout. Separately named allocatable sections and copy-relocated data could therefore fall outside the advertised ranges.
Track definitions synthesized by the linker and finalize them from the ordered loadable sections. Refresh both regular and dynamic symbol tables, and give the plain etext, edata and end names PROVIDE semantics on every ELF target while preserving user definitions.
Cover archive references, overrides, copy relocations and independently named text/data/bss sections.
Reported-by: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com>
Parse quoted LIBRARY names as a single token and add the default .dll
extension when needed. Allocate the stored name dynamically.
Add a Windows regression test using a quoted name with spaces.
tcc 0.9.27 does have a usable ldexp - but not ldexpl. however,
on windows these functions are identical, so map ldexpl to ldexp
and remove the MUSL-implementation which was copied from tcc_libm.h.
Commit cb39bc4 ("Calculate hex floating point with 128 bits instead of
64 bits.", 2025-05-27) started using ldexpl in tccpp.c, however, older
tcc like 0.9.27 (2017) don't have it on windows - ldexpl was added to
win32/include/math.h (in tcc_libm.h) in commit b11144d (2020).
So copy the current ldexpl definition from current tcc_libm.h into
tccpp.c - but under a different name.
Commit 03d58b0 ("arm64-win32 support : runtime", 2026-04-04) added
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE to winnt.h, and it was later
used in tccpe.c, but older tcc like 0.9.27 don't have it.
So define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE is missing.
Commit 44977b0 ("tcctest: restore & combine", 2026-05-06) effectively
changed the run-if macro to "true" - i.e. don't run the command and
don't report that it's skippped. As a result, all the doc targets
were skippped quietly and unconditionally.
Presumably it was a temporary in-development change - the commit
message doesn't mention docs changes, and the doc targets still exist
at Makefile, but this change was not reverted before the commit.
Revert this specific change, which restores the automatic doc targets
(build them only if the command to generate them exists).
Preserve symbolic offsets when materializing i386 TLS addresses, generate ARM64 TLS addresses from the thread pointer, and carry RISC-V addends on both halves of the TPREL relocation pair.
Keep undefined ELF TLS symbols typed as STT_TLS so objects produced by TCC can be linked by the system linker. Extend the TLS regression coverage for narrow signed and unsigned accesses, address-taking, runtime indexing, thread isolation, large RISC-V offsets, unsupported runtimes, and external TLS definitions.
tccgen.c:
remove VT_TLS in gen_cast
libtcc.c:
remove warning for gcc 16
i386-gen.c:
fix gen_modrm for VT_LDOUBLE
riscv64-gen.c:
add fc to TLS address
x86_64-gen.c:
add TLS prefix in gen_opf
tests2/144_tls.c/tests2/144_tls.expect:
updated test case
tests/tests2/Makefile
skip TLS test for BSD
tccrun.c:
- simplify usage of VirtualAlloc on win32/64
from 6728a64f1b
tccpe.c:
- revert changes to pe_create_pdb()
(doesn't work and/or too much complication)
from 37b7247796
- reduce #ifdef amount
tccgen.c:
- fix fix for cast to void
from fad812360b
tccelf.c:
- put create_riscv_attribute_section() into right place
from c77339ab41
tcc.h/libtcc.c:
- simplify link-option parser for pe dll_characteristics
from 1a54e47dda
i386-gen.c:
- fix tls
from 8502540b4a
workflow/build.yml:
- add i386-linux
- disable riscv64-linux-native (seems not supported currently)
Use the existing array-aware qualifier helper when propagating qualifiers from a const or volatile aggregate to a selected field. This keeps address-of array members from spuriously warning while preserving warnings for discarded qualifiers and read-only writes.
Add regression coverage for pointer-to-array returns, array decay, and writes through const array members.
Replace hardcoded VsDevCmd.bat Enterprise path with vswhere.exe +
vcvarsall.bat for dynamic VS discovery across editions and runner
image versions. Architecture args: amd64, x86, amd64_arm64.
Split x86_64/i386 win32 jobs into separate build and test steps.
For arm64: keep build+test in one step (needs vcvarsall for lib.exe).
Prepend standalone LLVM bin to PATH so clang targets ARM64 natively
instead of VS's clang-cl inheriting the x64-hosted cross-compile env.
Wire gen_clear_cache to __riscv64_clear_cache builtin, emitting
fence.i for instruction cache synchronization.
Add lib/riscvflush.c to provide __clear_cache for JIT bootstrap.
Extend tccrun.c I-cache flush guard to include RISC-V targets.
Add gen_clear_cache declaration to tcc.h riscv64 section.
Move the TinyCC/Windows ARM64 Interlocked workaround from the semlock call site into the bundled WinAPI header. This keeps tcc.h using the normal Interlocked API while avoiding unresolved Interlocked imports when tcc -run self-compiles on Windows ARM64.
Update lib/bt-exe.c as well so its ARM64 runtime object does not define a second InterlockedExchange fallback now provided by winnt.h.
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.
Report VirtualProtect failures with a Windows-specific -run diagnostic.
On Win64, also treat RtlAddFunctionTable failure as an error so unwind
registration problems are visible.
Add PE linker switches to set and clear DYNAMIC_BASE, NX_COMPAT,
HIGH_ENTROPY_VA and TERMINAL_SERVER_AWARE without changing x86/x64
defaults. HIGH_ENTROPY_VA is limited to 64-bit PE targets and implies
DYNAMIC_BASE; clearing DYNAMIC_BASE also clears HIGH_ENTROPY_VA.
When DYNAMIC_BASE is requested for an executable, emit base relocations
and clear RELOCS_STRIPPED so Windows ASLR can relocate the image. Keep
the existing ARM64 default hardening flags.
Invoke cv2pdb with _spawnvp on Windows so output paths are passed
as argv entries instead of through cmd.exe.
For non-Windows PE cross builds, keep the system() fallback but
shell-quote the executable name and size the PDB path dynamically.
Use interlocked state transitions around the lazily initialized Windows
CRITICAL_SECTION so concurrent first-time callers cannot race into a
double initialization.
- tccmacho.c: add STT_TLS to convert_symbol() for Mach-O output
- tests/tests2/Makefile: skip 144_tls on Win32 (no pthread.h) and
remove arm from TLS arch list (QEMU user-mode cannot emulate
MRC p15 TLS register access)