The orignal code does:
push eax/edx/size
call alloca
pop eax/edx/size
The pop does not work because the stack pointer has changed.
To make this also work with bound checking the code is now
using the stack probing from alloca.
i386-gen.c:
- Fix large stack size alloca code.
The returned value of alloca was not used corectly.
libtcc.c:
- Use __SIZE_TYPE__ for __builtin_offsetof
tccpp.c:
- Fix __MAYBE_REDIR and abort builtins.
tests/tests2/Makefile
- Run 117_gcc_test also with bound checking enabled
This found the above problems.
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
Checked on:
- i386/x86_64 (linux/windows)
- arm/arm64 (rapberry pi)
- riscv64 (simulator)
Not tested for arm softfloat because raspberry pi does not support it.
Modifications:
Makefile:
add arm-asm.c to arm64_FILES
add riscv64-asm.c (new file) to riscv64_FILES
lib/Makefile:
add fetch_and_add_arm.o(new file) to ARM_O
add fetch_and_add_arm64.o(new file) to ARM64_O
add fetch_and_add_riscv64.o(new file) to RISCV64_O
add $(BCHECK_O) to OBJ-arm/OBJ-arm64/OBJ-riscv64
tcc.h:
Enable CONFIG_TCC_BCHECK for arm32/arm64/riscv64
Add arm-asm.c, riscv64-asm.c
tcctok.h:
for arm use memmove4 instead of memcpy4
for arm use memmove8 instead of memcpy8
tccgen.c:
put_extern_sym2: for arm check memcpy/memmove/memset/memmove4/memmove8
only use alloca for i386/x86_64
for arm use memmove4 instead of memcpy4
for arm use memmove8 instead of memcpy8
fix builtin_frame_address/builtin_return_address for arm/riscv64
tccrun.c:
Add riscv64 support
fix rt_getcontext/rt_get_caller_pc for arm
tccelf.c:
tcc_load_dll: Print filename for bad architecture
libtcc.c:
add arm-asm.c/riscv64-asm.c
tcc-doc.texi:
Add arm, arm64, riscv64 support for bound checking
lib/bcheck.c:
add __bound___aeabi_memcpy/__bound___aeabi_memmove
__bound___aeabi_memmove4/__bound___aeabi_memmove8
__bound___aeabi_memset for arm
call fetch_and_add_arm/fetch_and_add_arm64/fetch_and_add_riscv64
__bound_init: Fix type for start/end/ad
__bound_malloc/__bound_memalign/__bound_realloc/__bound_calloc: Use size + 1
arm-gen.c:
add bound checking code like i386/x86_64
assign_regs: only malloc if nb_args != 0
gen_opi/gen_opf: Fix reload problems
arm-link.c:
relocate_plt: Fix address calculating
arm64-gen.c:
add bound checking code like i386/x86_64
load/store: remove VT_BOUNDED from sv->r
arm64_hfa_aux/arm64_hfa_aux: Fix array code
gfunc_prolog: only malloc if n != 0
arm64-link.c:
code_reloc/gotplt_entry_type/relocate: add R_AARCH64_LDST64_ABS_LO12_NC
relocate: Use addXXle instead of writeXXle
riscv64-gen.c:
add bound checking code like i386/x86_64
add NB_ASM_REGS/CONFIG_TCC_ASM
riscv64-link.c:
relocate: Use addXXle instead of writeXXle
i386-gen.c/x86_64-gen.c
gen_bounds_epilog: Fix code (unrelated)
tests/Makefile:
add $(BTESTS) for arm/arm64/riscv64
tests/tests2/Makefile:
Use 85 only on i386/x86_64 because of asm code
Use 113 only on i386/x86_64 because of DLL code
Add 112/114/115/116 for arm/arm64/riscv64
Fix FILTER (failed on riscv64)
tests/boundtest.c:
Only use alloca for i386/x86_64
i386-gen.c:
- load/gen_opf: set v1.sym to NULL
lib/Makefile:
- Add -gstabs -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable
lib/bt-log.c:
- tcc_backtrace: Prevent __builtin_frame_address warning
tccgen.c:
- struct_layout: Set t.t to VT_BYTE
- default_debug: Use octal instead of -1 to make size_t work
tccpp.c:
- tal_realloc_impl: Only memcpy when p set
x86_64-gen.c:
- gen_bounds_epilog: Do not save/restore rcx (not caller/callee saved)
This also made stack not aligned to 16 bytes.
tcctok.h:
- Add __bound_setjmp/setjmp/_setjmp/longjmp
tccgen.c:
- redirect setjmp/longjmp to bcheck.c code
i386-gen.c/x86_64-gen.c
- Change func_bound_alloca_used into func_bound_add_epilog
- Set func_bound_add_epilog also when setjmp is called
bcheck.c:
- Add __bound_setjmp/__bound_longjmp
- __bound_local_delete: remove setjmp if used in function
- __bound_exit: clear setjmp list and print statistic
- make malloc_redir more readable (unrelated)
New testcases:
- 115_bound_setjmp
- 116_bound_setjmp2
from 3e731e3a78
tccgen.c:
- make 'struct default_debug' const
- pass TCCState* as parameter to tcc_debug_xxx functions
- always check tcc_state->do_debug before calling functions
- factor out tcc_debug_extern_sym()
- remove formats "%lld"/"%llu" (not reliable on windows)
xxx-gen files:
- set func_vt/var from caller
- tests2/113_btdll.c: test handling multiple stabs infos
Also:
- libtcc.c: remove _ISOC99_SOURCE pre-defines. It is causing
strange warnings such as 'strdup not declared'
- i386/x86_64-gen.c cleanup bounds_pro/epilog. This discards
the extra code for main's argv. If needed, __argv might be
processed instead.
- tccgen.c:block(): reduce stackspace usage. For example with
code like "if (..) ... else if (..) ... else if (..)... "
considerable numbers of nested block() calls may occur.
Before that most stack space used when compiling itself was
for libtcc.c:tcc_set_linker().
Now it's rather this construct at tccpp.c:2765: in next_nomacro1():
if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
|| c == '.'
|| ((c == '+' || c == '-')
...
remove quadratic loops by not using side tables; address-taken
can simply be a flag per local sym, and the lbounds section can
be filled after symbols go out of scope at which point we know
if the address was taken, so that there's no need to compress it
again after the funcion is done.
Add __attribute__((constructor)) to __bounds_init.
- remove tcc_add_bcheck from i386-link.c and x86_64-link.c
- add simplified tcc_add_bcheck to tccelf.c
- Update tccrun.c to call constructor/destructor.
Set dynsym sh_info to number of local symbols in tccelf.c
Reduce stack size when bounds checking is enabled.
Added variable TCC_LIBBCHECK for windows support.
Add signal stack to detect stack overflow.
Add all & parameters in lbound_section and remove them if not used.
Close fd in tcc_relocate in tccrun.c
Fix section type constructor/destructor in tccelf.c
Add check code in tests/boundtest.c for mem/str functions.
Remove -ba from documentation.
Add bounds check signal info in documentation.
bcheck.c:
- Fix initial_pool alignment.
. Fix printf statements.
. Add prototypes for all external interface functions.
- Add TCC_BOUNDS_WARN_POINTER_ADD environment variable.
. Add ctype and errno data.
- Fix alloca when multithreading is used.
- Add lock for __bound_checking and __bound_never_fatal.
- Catch pthread_create and use locks when called.
- Detect in loaded in shared lib and use locks when found
- Use spin locks instead of semaphore locks.
- Make spin locked code as small as possible.
- Fix mem/str functions checking.
- Fix overlap checking mem/str functions.
this is a bit complicated: for i386 and x86-64 we really need to
extend return values ourself, as the common code now does. For arm64
this at least preserves old behaviour. For riscv64 we don't have to
extend ourself but can expect things to be extended up to int (this
matters for var-args tests, when the sign-extension to int64 needs to
happen explicitely). As the extensions are useless, don't do them.
And for arm32 we actually can't express GCC behaviour: the callee side
expects the return value to be correctly extended to int32, but
remembers the original type. In case the ultimate target type for the
call result is only int, no further extension is done. But in case
the target type is e.g. int64 an extension happens, but not from int32
but from the original type. We don't know the ultimate target type,
so we have to choose a type to put into vtop:
* original type (plus VT_MUSTCAST) - this looses when the ultimate
target is int (GCC: no cast, TCC: a cast)
* int (without MUSTCAST) - this looses when the ultimate target is
int64 (GCC: cast from original type, TCC: cast from int)
This difference can only be seen with undefined sources, like the
testcases, so it doesn't seem worthwhile to try an make it work, just
disable the test on arm and choose the second variant as that generates
less code.
- revert Makefiles to state before last bcheck additions
Instead, just load bcheck.o explicitly if that is
what is wanted.
- move tcc_add_bcheck() to the <target>-link.c files and
remove revently added arguments. This function is to
support tccelf.c with linking, not for tccgen.c to
support compilation.
- remove -ba option: It said:
"-ba Enable better address checking with bounds checker"
Okay, if it is better then to have it is not an option.
- remove va_copy. It is C99 and we try to stay C89 in tinycc
when possible. For example, MS compilers do not have va_copy.
- win64: revert any 'fixes' to alloca
It was correct as it was before, except for bound_checking
where it was not implemented. This should now work too.
- remove parasitic filename:linenum features
Such feature is already present with rt_printline in
tccrun.c. If it doesn't work it can be fixed.
- revert changes to gen_bounded_ptr_add()
gen_bounded_ptr_add() was working as it should before
(mostly). For the sake of simplicity I switched it to
CDECL. Anyway, FASTCALL means SLOWCALL with tinycc.
In exchange you get one addition which is required for
bounds_cnecking function arguments. The important thing
is to check them *BEFORE* they are loaded into registers.
New function gbound_args() does that.
In any case, code instrumentation with the bounds-check
functions as such now seems to work flawlessly again,
which means when they are inserted as NOPs, any code that
tcc can compile, seems to behave just the same as without
them.
What these functions then do when fully enabled, is a
differnt story. I did not touch this.
The bounds checking code has now enabled gen_bounded_ptr_add tests.
This makes the code slower but finds more errors.
I had to correct some things in tcc to make it work.
- Fixed off by one in lib/bcheck.c
- Corrected tccelf.c sym_versions.
- Disabled USE_TAL when using bounds checking.
- Fixed cstr_printf va_start.
- Fixed tests/tests2/46_grep.c off by one error.
- Updated gen_bounded_ptr_add in x86_64-gen.c
- Fixed x86_64-link.c pointer diff.
For gen_vla_alloc now always use alloca call when bounds checking.
Added line/filename in %rax before bound calls to find location of error.
This allows creation of TCCStates and operation with API
calls independently from each other, even from threads.
Frontend (option parsing/libtcc.c) and backend (linker/tccelf.c)
now depend only on the TCCState (s1) argument.
Compilation per se (tccpp.c, tccgen.c) is still using
globals for convenience. There is only one entry point
to this section which is tcc_compile() which is protected
by a semaphore.
There are some hacks involved to avoid too many changes,
as well as some changes in order to avoid too many hacks ;)
The test libtcc_test_mt.c shows the feature. Except this
new file the patch adds 87 lines overall.
A more automatic approach to code suppression (aka. nocode_wanted)
The simple rules are:
- Clear 'nocode_wanted' at (im/explicit) label IF it was used
- Set 'nocode_wanted' after unconditional jumps
Also in order to test this then I did add the "function might
return no value" warning, and then to make that work again I
did add the __attribute__((noreturn)).
Also moved the look ahead label check into the type parser
to gain a little speed.
the real difference is in decl0 where we can use external_sym
just fine also for function definitions, we don't have to use
external_global_sym. Setting VT_EXTERN in external_sym isn't
necessary either (the type will have it set if necessary).
The rest is tidying: removing unused arguments and moving
some code around.
the ABIs (and other compilers) extend sub-int return values in the
caller. TCC extends them in the callee. For compatibility with
those other compilers we have extend them in the caller as well.
That introduces a useless double extension in pure TCC-compiled code,
but fixing that generally requires that the code generator of TCC would
understand sub-int types. For the time being bite the bullet.
In gfunc_call, regisger will be saved before gcall_or_jmp. The register
stored the function will be saved too, though in some generator the SValue
of this function will be immediately poped after gcall_or_jmp, and no need to be saved. So I modify some generator to avoid save redundant SValue before gcall_or_jmp.
which requires being able to emit an arbitrary number of NOP
instructions, which is also implemented here. For x86 we
could emit other sequences but these are the easiest.
The code generated for "((void (*)(void))0x12345678)()" will be a single "CALL 0x12345678" in previous code.
However, this will not work for DLLs, because "CALL imm" is PC related, DLL relocation will break the code.
This commit fixed the problem by forcing TCC generates indirect CALLs in this situation.
AL/AX should be extended to EAX when calling functions. However, the previous code did this only for direct calls, indirect calls were ignored.
New code also avoid redundant code when generating JMP instruction. (i.e. expanding code should be generated with CALL instruction only)
tcc.h:
* cleanup struct 'Sym'
* include some 'Attributes' into 'Sym'
* in turn get rid of VT_IM/EXPORT, VT_WEAK
* re-number VT_XXX flags
* replace some 'long' function args by 'int'
tccgen.c:
* refactor parse_btype()
- configure
* use aarch64 instead of arm64
- Makefile
* rename the custom include file to "config-extra.mak"
* Also avoid "rm -r /*" if $(tccdir) is empty
- pp/Makefile
* fix .expect generation with gcc
- tcc.h
* cleanup #defines for _MSC_VER
- tccgen.c:
* fix const-propagation for &,|
* fix anonymous named struct (ms-extension) and enable
-fms-extension by default
- i386-gen.c
* clear VT_DEFSIGN
- x86_64-gen.c/win64:
* fix passing structs in registers
* fix alloca (need to keep "func_scratch" below each alloca area on stack)
(This allows to compile a working gnu-make on win64)
- tccpp.c
* alternative approach to 37999a4fbf
This is to avoid some slowdown with ## token pasting.
* get_tok_str() : return <eof> for TOK_EOF
* -funsigned-char: apply to "string" literals as well
- tccpe/tools.c: -impdef: support both 32 and 64 bit dlls anyway
- configure:
- add --config-uClibc,-musl switch and suggest to use
it if uClibc/musl is detected
- make warning options magic clang compatible
- simplify (use $confvars instead of individual options)
- Revert "Remove some unused-parameter lint"
7443db0d5f
rather use -Wno-unused-parameter (or just not -Wextra)
- #ifdef functions that are unused on some targets
- tccgen.c: use PTR_SIZE==8 instead of (X86_64 || ARM64)
- tccpe.c: fix some warnings
- integrate dummy arm-asm better
- tccgen.c/tcc.h: allow function declaration after use:
int f() { return g(); }
int g() { return 1; }
may be a warning but not an error
see also 76cb1144ef
- tccgen.c: redundant code related to inline functions removed
(functions used anywhere have sym->c set automatically)
- tccgen.c: make 32bit llop non-equal test portable
(probably not on C67)
- dynarray_add: change prototype to possibly avoid aliasing
problems or at least warnings
- lib/alloca*.S: ".section .note.GNU-stack,"",%progbits" removed
(has no effect)
- tccpe: set SizeOfCode field (for correct upx decompression)
- libtcc.c: fixed alternative -run invocation
tcc "-run -lxxx ..." file.c
(meant to load the library after file).
Also supported now:
tcc files ... options ... -run @ arguments ...
Also:
- on windows i386 and x86-64, structures of size <= 8 are
NOT returned in registers if size is not one of 1,2,4,8.
- cleanup: put all tv-push/pop/swap/rot into one place
There seems nothing wrong. With
int t1 = 176401255;
float f = 0.25;
int t2 = t1 * f; // 176401255 * 0.25 = 44100313.75
according to the arithmetic conversion rules, the number
176401255 needs to be converted to float, and the compiler
can choose either the nearest higher or nearest lower
representable number "in an implementation-defined manner".
Which may be 176401248 or 176401264. So as result both
44100312 and 44100313 are correct.
This reverts commit 664c19ad5e.
Restore ebx from *ebp because alloca might change esp.
Also disable USE_EBX for upcoming release.
Actually the benefit is less than one would expect, it
appears that tcc can't do much with more than 3 registers
except with extensive use of long longs where the disassembly
looks much prettier (and shorter also).
Also: tccgen/expr_cond() : fix wrong gv/save_regs order
tccgen.c: remove any 'nocode_wanted' checks, except in
- greloca(), disables output elf symbols and relocs
- get_reg(), will return just the first suitable reg)
- save_regs(), will do nothing
Some minor adjustments were made where nocode_wanted is set.
xxx-gen.c: disable code output directly where it happens
in functions:
- g(), output disabled
- gjmp(), will do nothing
- gtst(), dto.
on 32bit long long support was sometimes broken. This fixes
code-gen for long long values in switches, disables a x86-64 specific
testcase and avoid an undefined shift amount. It comments out
a bitfield test involving long long bitfields > 32 bit; with GCC layout
they can straddle multiple words and code generation isn't prepared
for this.
Some routines were using the wrong type (int) in passing addends,
truncating it. This matters when bit 31 isn't set and the high
32 bits are set: the truncation would make it unsigned where in
reality it's signed (happen e.g. on the x86-64 with it's load
address at top-2GB).
C standard specifies that array should be declared with a non null size
or with * for standard array. Declaration of relocs_info in tcc.h was
not respecting this rule. This commit add a R_NUM macro that maps to the
R_<ARCH>_NUM macros and declare relocs_info using it. This commit also
moves all linker-related macros from <arch>-gen.c files to <arch>-link.c
ones.
With -b, this produces garbage. Code to call __bound_local_new
is put at wrong place, overwriting the regparam setup code.
Fix copied from x86_64-gen.c.
void __attribute__((regparm(3)))
fun(int unused)
{
char local[1];
}