Emit fence + fence.i (Zifencei extension) for I/D cache
synchronization, needed for tcc -run mode on RISC-V.
Zifencei is required by the RISC-V Linux ABI and present
on all Linux-capable cores, though technically not part
of the RV64G base ISA.
Replaces the empty stub that relied on 'RV64 registers are always
sign-extended' assumption. Now emits addiw rd, rs, 0 for proper
32-to-64 bit sign extension, matching arm64's sxtw behavior.
Verified on Spacemit X100: tests2 pass (125_atomic_misc has a
pre-existing intermittent segfault, not caused by this change).
Add sign/zero extension for char/short to int casts using
slli+srai (signed) or slli+srli/andi (unsigned) sequences.
Also adds RISCV64 to the gen_cvt_csti fast-path conditional
in tccgen.c:3466, matching arm64/i386/x86_64.
Verified on Spacemit X100: all tests2 pass, no regressions.
Other mature backends (i386, x86_64, arm64) all define PROMOTE_RET,
which forces explicit sign/zero extension of narrow return types at the
caller side. Without it, riscv64 relied on the assumption that RV64
registers are always sign-extended, which may not hold when interfacing
with non-TCC compilers.
Verified on Spacemit X100 (riscv64): self-compilation is self-consistent
across 3 layers. test3 reference mismatch is expected — the test
intentionally invokes UB via type-punned function pointers (csf macro).
workflow:
- revert 'pinact for security' for readability
from 831c3fa184
tccpp.c:
- remove code that allows tcc to parse numbers incorrectly (*)
from 829c848520
tccgen.c:
- Revert "Relaxed the 'incompatible pointer type' warning a bit" (*)
from d9ec17d334.
tccrun.c:
- remove support for -nostdlib -run
for simplicity, we require "main" with tcc -run always
tccpp.c:
- Revert "Free all preprocessor memmory in case of error."
from c96f0cad61
Remove TinyAlloc->limit instead. Thus it can do also bigger
allocs. Big TokenStrings (like 200kb+ when compiling tcc)
may come from inline functions or from large initializers.
Makefile/configure:
- use --config-pie for configuring tcc output only
- use -fPIC with clang-x86_64 to avoid 32-bit relocs
libtcc.c:
- fix "tcc file.c -run" i.e. -run as last argument
i386-gen.c:
- PIC refactor
(*) sorry, but code in tcc should have a minimum of generic relevance
When calculating the difference between two pointers (TOK_PDIV), the
AArch64 and RISC-V64 backends used unsigned division
instructions (udiv/divu).
This patch moves TOK_PDIV to use signed division instructions (sdiv/div)
for both backends, ensuring correct behavior as per the C standard.
The -run option did not support -nostdlib correctly.
The argc/argc/envp are now passed on stack according to sysv.
This implementation does not work for TCC_TARGET_PE.
Also arm64 does not work when running tcc compiled with itself.
This is because arm64 assembly is not implemented yet.
The following test code is used to check the code:
#include <unistd.h>
#include <sys/syscall.h>
void _start() {
syscall(SYS_write, 1, "hello world\n", 12);
syscall(SYS_exit, 0);
}
Run this with:
./tcc -nostdlib -lc -run a.c
make tcc_c
./tcc_c -nostdlib -lc -run a.c
int foo(struct xxx {int x[3];} *p) { ...
We want 'xxx' be visible only inside the function. To get that,
the patch removes the 'sym_push(param)' in xxx-gen.c, and instead
(in tccgen.c:gen_function()) pushes all symbols that were newly
defined during parsing of the parameter list in post_type().
Also,
- decl_initializer_alloc():
patch existing globals earlier, which updates flex arrays too
- let patch_type() do the 'redefinition' check and FUNC_OLD update
arm-link.c: remove some casts
tccelf.c: code style and remove code
tccpp.c: use correct pointer size so cross compiling works
riscv64-gen.c: make code more readable
I tried to fix all remaining warnings/errors reported by -fsanitize.
The riscv64-gen.c is a bit large because it contained a lot of warnings.
I forgot some arm-link.c changes in last commit.
The other changes are all small fixes to avoid warnings/errors.
While adding some testcases for attribute cleanup I found a
bug in the riscv code. It modifies the sv->c.i in load_symofs.
If a structure contains more then one element only the
first is stored correctly. This only happens on a large
stack frame.
Fixed by saving/restoring sv->c.i.
This makes attribute cleanup code work the same as gcc and also
makes bound checking a very little bit faster.
tcc.h:
Add save_return_reg(CType *) and restore_return_reg(CType *)
Change gfunc_epilog() to gfunc_epilog(Sym *)
arm-gen.c:
arm64-gen.c:
c67-gen.c:
i386-gen.c:
il-gen.c:
riscv64-gen.c:
x86_64-gen.c:
Move save and restore register around bound_local_delete call
to save_return_reg and restore_return_reg.
Pass func_type from gfunc_epilog to gen_bounds_epilog.
tccgen.c:
Call save_return_reg/restore_return_reg in try_call_scope_cleanup
when RETURN is found.
tccrun.c:
Fix warning when bound checking not used.
tests/tests2/101_cleanup.c
tests/tests2/101_cleanup.expect
Extra checks attribute cleanup save/restore registers.
tests/tests2/Makefile:
Fix when bound checking not used.
libtcc.c:
- free 'elfint' string
- acceot -O and -Os
- accept -gstabs (to override dwarf when default)
- better -Wp,...
tccpp.c:
- #line cleanup
also warn with "extra tokens after directive"
tccgen.c & xxx_gen.c:
- force CPU flags to register earlier
tccelf.c:
- tcc_load_object: align size only for code sections
data/bss objects are always put with their specfic type align
(in decl_initializer_alloc())
x86/64 doesn't need aligned code
from c6afdff7ab
tccpe.c:
- enable dllimport for "_imp__<sym>" also from assembler
x86_64-gen.c & lib/libtcc1.c:
- simpler fneg without libtcc1 reference
tests2/134_double_to_signed.c:
- a tcc compiled by msvc won't pass this test
Use `t1` instead of `t0` for the cases when `rr` is not set so `t0` is
used by default and this happens:
lui t0, XXX
add t0, t0, t0
Instead, now we do:
lui t1, XXX
add t0, t0, t1
NOTE: In order to be able to deal with general-purpose vs floating-point
registers, this commit adds a flag in the 6th bit of the register. If
set, it means the register is a floating-point one. This affects all the
assembler.
In `load` and `store` RISC-V gen used `type_size` to retrieve the size
of the types being moved around, the problem with that function is it
tries to obtain internal information of the type. When using `type_size`
with a `char *` it returns 1, and emits a `lb` instruction when using a
conditional expression like so (but probably also in other cases):
char *a, *b;
b = "hello";
a = x ? b : "" ; // this emits an `lb`
That `lb` clobbers the pointer, only loading the latest byte of it:
// if `b` was, say: 0x1f822e
a = b;
// now `a` is 0x00002e
NOTE: We spotted this when building make-3.82, in `init_switches`
function in the `main.c` file. This error made `make` unable to
run long options like `make --help` (segfault when doing the
`strlen` later)
This happens because a `char *` is internally stored as a `char[1]` or
something similar, it's result is the size of a `char` (1) times the
size of the array `1`. This is not what we want, we are copying the
pointer, not the array itself. Using `type_size` for this is not
appropriate even if it works for some cases.
If the conditional expression is rewritten to imperative style using an
`if` it works properly, so it might be related with the fact the pointer
is `load`ed to a register.
`load` and `store` should only work with integral types, so reading the
size of the array is not useful. This commit creates a simpler version
of this function that only reads the integral type of what's working
with: char * is considered just a pointer. So it makes an `ld` instead,
and the code above works.
The new gcc12 release does not support stabs any more.
This was a good reason to add support for dwarf.
The stabs code still works and is used if configure option --dwarf
is not used.
Tested on x86_64, i386, arm, arm64, riscv64 with dwarf-5.
Some debuggers may not support dwarf-5. Try using older dwarf versions
i that case.
The tccmacho.c code probably need some support for dwarf.
arm-gen.c, arm64-gen.c, i386-gen.c, riscv64-gen.c, x86_64-gen.
- fix get_sym_ref symbol size
arm-link.c, arm64-link.c, i386-link.c, riscv64-link.c, x86_64-link.c
- add R_DATA_32U
libtcc.c:
- parse -gdwarf option
tcc.c:
- add dwarf option
tcc.h:
- add dwarf option and sections
tccelf.c:
- init dwarf sections
- avoid adding sh_addr for dwarf sections
- remove dwarf relocs for output dll
- add dwarf sections for tccrun
tccgen.c:
- add dwarf defines + global data
- add dwarf_* functions
- mix dwarf code with stabs code
- a trick is used to emit function name in .debug_line section so
only this section has to be parsed instead of .debug_info and
.debug_abbrev.
- fix init debug_modes
tccrun.c:
- add dwarf sections in rt_context
- init them in tcc_run
- add new dwarf code rt_printline_dwarf to find file/function
dwarf.h:
- New file
tcc-doc.texi:
- document dwarf
configure:
- add dwarf option
lib/Makefile
- change -gstabs into -gdwarf
lib/bt-exe.c, tests/tests2/Makefile, tests/tests2/126_bound_global:
- Add __bound_init call
- Add new testcase to test it
libtcc.c: add -Wwrite-strings to -Wall
tccgen.c: ro float-consts, string-consts, ro arrays if base type is
tccpe.c: merge IAT with rodata
tccrun.c: mprotect rodata accordingly. free section data after copy
x86_64.c: do not use got for static data.
tcc -bench: show data.rw/ro
Probably STB_LOCAL should never get to put_got_entry(), and currently
it doesn't seem to happen (See "Hack Alarm" there)
Other files: use more ro-data in tinycc
tccgen.c: debug_modes
- don't waste debug function calls during normal execution.
libtcc.c:
- mem_debug: no C99 features in tcc please, for example
({compound expressions}): do not use.
tccgen.c: struct_layout:
- unaligned access is completely ok for most targets.
- Moreover the patch was triggering single byte mode even
for normal aligned access (as with tcc's SymAttr)
static Sym label: don't do this
arm-gen.c:
- use some #ifdefs to explain some code
tccpp.c:
- cleanup UCN chars
libtcc.c:
- replace openbsd library search
configure:
- cleanup strip fallouts
tccgen.c:
- expr_cond(): remove an exotic optimization that eventually
got fixed to do the contrary by a gv(RC_InT)
- pop_local_syms(): remove some args
- init_putv() : use write##le functions to avoid cross-compiler
unaligned access
- __bt_init(): remove unused param 'mode'
I have implemented the -ftest-coverage option. It works a bit different
from the gcc version. It output .tcov text file which looks almost the
same as a gcov file after a executable/so file is run.
Add lib/tcov.c file
Modify Makefiles to compile/install it
Add -ftest-coverage option in tcc.c/tcc.h/tcc-doc.texi
Add code to tccelf.c/tccgen.c/tccpe.c
Add gen_increment_tcov to tcc.h/*gen.c
unrelated changes:
Add sigemptyset in tccrun.c
Fix riscv64-gen.c tok_alloc label size
implement load/store to constant address
use VT_LLONG instead of VT_PTR in register passing
fix bound checking problem with small structs
enable riscv tests in tests/tcctest.c and tests/tests2/119_random_stuff.c
moved target_machine defines to the <target>-gen.c files.
Also:
- c2str.c moved into conftest.c
- tccdefs.h ; defined(__TINYC__) && !defined(_LOCORE) removed
(in tinycc __TINYC__ is always defined and _LO... is never.)
- stddef.h : too many #ifdefs, removed
- tccgen.c:stabs: support win32 long doubles aka doubles.
- win32: math.h/tcc_libm.h: fix pointer mismatch in modfl
- tccpp.c: increment include_stack_ptr after the file was
actually found otherwise it would print
"in file included from <itself>: file not found..."
- tccpe.c: commit "tidy support for helper function" created
STT_NOTYPE symbols and hence relied on ad-hoc detection which
didn't work for x86_64 (as reported by Christian Jullien)
- tccgen.c: However to be more safe the helper symbols are
now made STT_FUNC anyway (via new VT_ASM_FUNC).
Also:
- tcc.h: minor reorder
- riscv64-*, arm64-*, tccmacho.c: avoid some gcc format-warnings
(mingw-gcc complains about "%llx" being "unknown conversion",
although it does work since Vista or so)
tcc.h, tccgen.c: Introduce Sym *external_helper_sym(int v);
to create an external reference with no specific type. This
avoids type conflicts if the symbol is used from C too.
the other files: use it.
tccgen.c:
- Fix 'tcc -b conftest.s'
- Add offset during bound checking for struct return
lib/bcheck.c:
- Check overlap when reusing vla/alloca
arm-gen.c:
arm64-gen.c:
riscv64-gen.c:
lib/alloca86-bt.S:
- add space for vla/alloca during bound checking
tests/tests2/Makefile:
tests/tests2/121_struct_return:
tests/tests2/122_vla_reuse:
- New test cases with bound checking enabled to test vla and struct return
lib/va_list.c:
- Handle struct {double, double} correctly
arm64-gen.c:
riscv64-gen.c:
x86_64-gen.c:
- Allow zero sized structs to work with va_arg
tcctest.c:
- Add new va_arg test code
test/bug.c:
- Remove tst2 va_arg test
found in mpfr. Expressions like "(longlong)i <= MAX_ULONGLONG" are
always true (not yet short-circuited in tcc), but still need to be
handled correctly in the backends.
tccgen.c:
- cleanup __builtin_... stuff
- merge __attribute((alias("sym"))) with __asm__("sym")
Now one cannot have both, however for alias underscores are
added if enabled. For __asm__ they aren't.
tccpp.c:
- extend tcc_predefs accordingly. Was generated with
'cd tests/misc && tcc -run c2str.c tcc_predef.h tcc_predefs'
xxx-gen.c:
- move bcheck setjmp test to tccgen.c:gbound_args()
i386-gen.c:
- create win32 compatible stack space for big structures
tcctest.c:
- some cleanup + nicer output