aboutsummaryrefslogtreecommitdiff
path: root/tinycc/lib
diff options
context:
space:
mode:
authorUneven Prankster <unevenprankster@protonmail.com>2023-07-12 13:22:29 -0300
committerUneven Prankster <unevenprankster@protonmail.com>2023-07-12 13:22:29 -0300
commitfa2bdd711212ba6b7a94a20971e8bfa281e73296 (patch)
tree6713b3c0379507d49558287b71dd360ce188a2f0 /tinycc/lib
lol
Diffstat (limited to 'tinycc/lib')
-rw-r--r--tinycc/lib/Makefile94
-rw-r--r--tinycc/lib/alloca-bt.S96
-rw-r--r--tinycc/lib/alloca.S85
-rw-r--r--tinycc/lib/armeabi.c544
-rw-r--r--tinycc/lib/armflush.c51
-rw-r--r--tinycc/lib/atomic.S858
-rw-r--r--tinycc/lib/bcheck.c2270
-rw-r--r--tinycc/lib/bt-dll.c74
-rw-r--r--tinycc/lib/bt-exe.c74
-rw-r--r--tinycc/lib/bt-log.c47
-rw-r--r--tinycc/lib/builtin.c164
-rw-r--r--tinycc/lib/dsohandle.c1
-rw-r--r--tinycc/lib/lib-arm64.c677
-rw-r--r--tinycc/lib/libtcc1.c641
-rw-r--r--tinycc/lib/stdatomic.c166
-rw-r--r--tinycc/lib/tcov.c428
-rw-r--r--tinycc/lib/va_list.c67
17 files changed, 6337 insertions, 0 deletions
diff --git a/tinycc/lib/Makefile b/tinycc/lib/Makefile
new file mode 100644
index 0000000..81e390b
--- /dev/null
+++ b/tinycc/lib/Makefile
@@ -0,0 +1,94 @@
+#
+# Tiny C Compiler Makefile for libtcc1.a
+#
+
+TOP = ..
+include $(TOP)/Makefile
+VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
+T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
+X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
+
+XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
+XCC = $(XTCC)
+XAR = $(XTCC) -ar
+XFLAGS-unx = -B$(TOPSRC)
+XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
+XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
+XCFG = $(or $(findstring -win,$T),-unx)
+S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
+
+# in order to use gcc, type: make <target>-libtcc1-usegcc=yes
+arm-libtcc1-usegcc ?= no
+
+# This makes bounds checking 40%..60% faster.
+#x86_64-libtcc1-usegcc=yes
+#i386-libtcc1-usegcc=yes
+
+ifeq "$($(T)-libtcc1-usegcc)" "yes"
+ XCC = $(CC)
+ XAR = $(AR)
+ XFLAGS = $(CFLAGS) -fPIC -gdwarf -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable
+endif
+
+ifneq ($(CONFIG_backtrace),no)
+# only for native compiler
+ifneq ($(CONFIG_bcheck),no)
+$(X)BCHECK_O = bcheck.o
+endif
+$(X)BT_O = bt-exe.o bt-log.o
+$(X)B_O = $(BCHECK_O) bt-exe.o bt-log.o bt-dll.o
+endif
+$(X)BT_O += tcov.o
+
+DSO_O = dsohandle.o
+
+I386_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o $(BT_O)
+X86_64_O = libtcc1.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o $(BT_O)
+ARM_O = libtcc1.o armeabi.o alloca.o armflush.o stdatomic.o atomic.o builtin.o $(BT_O)
+ARM64_O = lib-arm64.o stdatomic.o atomic.o builtin.o $(BT_O)
+RISCV64_O = lib-arm64.o stdatomic.o atomic.o builtin.o $(BT_O)
+WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
+
+OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
+OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
+OBJ-x86_64-osx = $(X86_64_O) va_list.o $(BCHECK_O)
+OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
+OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
+OBJ-arm64 = $(ARM64_O) $(BCHECK_O) $(DSO_O)
+OBJ-arm64-osx = $(ARM64_O) $(BCHECK_O)
+OBJ-arm = $(ARM_O) $(BCHECK_O) $(DSO_O)
+OBJ-arm-fpa = $(ARM_O) $(DSO_O)
+OBJ-arm-fpa-ld = $(ARM_O) $(DSO_O)
+OBJ-arm-vfp = $(ARM_O) $(DSO_O)
+OBJ-arm-eabi = $(ARM_O) $(DSO_O)
+OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
+OBJ-arm-wince = $(ARM_O) $(WIN_O)
+OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
+
+OBJ-extra = $(filter $(B_O),$(OBJ-$T))
+OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
+
+ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
+
+all: $(ALL)
+
+$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1)
+ $S$(XAR) rcs $@ $^
+
+$(X)%.o : %.c
+ $S$(XCC) -c $< -o $@ $(XFLAGS)
+
+$(X)%.o : %.S
+ $S$(XCC) -c $< -o $@ $(XFLAGS)
+
+$(TOP)/%.o : %.c
+ $S$(XCC) -c $< -o $@ $(XFLAGS)
+
+$(TOP)/bcheck.o : XFLAGS += -g $(if $(CONFIG_musl),-DTCC_MUSL)
+$(TOP)/bt-exe.o : $(TOP)/tccrun.c
+
+$(X)crt1w.o : crt1.c
+$(X)wincrt1w.o : wincrt1.c
+
+clean :
+ rm -f *.a *.o $(ALL)
diff --git a/tinycc/lib/alloca-bt.S b/tinycc/lib/alloca-bt.S
new file mode 100644
index 0000000..c161488
--- /dev/null
+++ b/tinycc/lib/alloca-bt.S
@@ -0,0 +1,96 @@
+/* ---------------------------------------------- */
+/* alloca-bt.S */
+
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
+
+/* ---------------------------------------------- */
+#if defined __i386__
+
+.globl _(__bound_alloca)
+_(__bound_alloca):
+ pop %edx
+ pop %eax
+ mov %eax, %ecx
+ add $3+1,%eax
+ and $-4,%eax
+ jz p6
+
+#ifdef _WIN32
+p4:
+ cmp $4096,%eax
+ jbe p5
+ test %eax,-4096(%esp)
+ sub $4096,%esp
+ sub $4096,%eax
+ jmp p4
+
+p5:
+#endif
+
+ sub %eax,%esp
+ mov %esp,%eax
+
+ push %edx
+ push %eax
+ push %ecx
+ push %eax
+ call _(__bound_new_region)
+ add $8, %esp
+ pop %eax
+ pop %edx
+
+p6:
+ push %edx
+ push %edx
+ ret
+
+/* ---------------------------------------------- */
+#elif defined __x86_64__
+
+.globl _(__bound_alloca)
+_(__bound_alloca):
+#ifdef _WIN32
+ inc %rcx # add one extra to separate regions
+ jmp _(alloca)
+.globl _(__bound_alloca_nr)
+_(__bound_alloca_nr):
+ dec %rcx
+ push %rax
+ mov %rcx,%rdx
+ mov %rax,%rcx
+ sub $32,%rsp
+ call _(__bound_new_region)
+ add $32,%rsp
+ pop %rax
+ ret
+#else
+ pop %rdx
+ mov %rdi,%rax
+ mov %rax,%rsi # size, a second parm to the __bound_new_region
+
+ add $15 + 1,%rax # add one extra to separate regions
+ and $-16,%rax
+ jz p3
+
+
+ sub %rax,%rsp
+ mov %rsp,%rdi # pointer, a first parm to the __bound_new_region
+ mov %rsp,%rax
+
+ push %rdx
+ push %rax
+ call _(__bound_new_region)
+ pop %rax
+ pop %rdx
+
+p3:
+ push %rdx
+ ret
+#endif
+
+/* ---------------------------------------------- */
+#endif
diff --git a/tinycc/lib/alloca.S b/tinycc/lib/alloca.S
new file mode 100644
index 0000000..6ebafd7
--- /dev/null
+++ b/tinycc/lib/alloca.S
@@ -0,0 +1,85 @@
+/* ---------------------------------------------- */
+/* alloca.S */
+
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
+
+/* ---------------------------------------------- */
+#if defined __i386__
+
+.globl _(alloca), _(__alloca)
+_(alloca):
+_(__alloca):
+ push %ebp
+ mov %esp,%ebp
+ mov 8(%ebp),%eax
+ add $3,%eax
+ and $-4,%eax
+#ifdef _WIN32
+ jmp .+16 #p2
+p1:
+ sub $4096,%esp
+ sub $4096,%eax
+ test %eax,(%esp)
+p2:
+ cmp $4096,%eax
+ jae p1
+#endif
+ sub %eax,%esp
+ mov 4(%ebp),%eax
+ mov 0(%ebp),%ebp
+ add $8,%esp
+ push %eax
+ lea 8(%esp),%eax
+ ret
+
+/* ---------------------------------------------- */
+#elif defined __x86_64__
+
+.globl _(alloca)
+_(alloca):
+ pop %rdx
+#ifdef _WIN32
+ mov %rcx,%rax
+#else
+ mov %rdi,%rax
+#endif
+ add $15,%rax
+ and $-16,%rax
+ jz p3
+
+#ifdef _WIN32
+p1:
+ cmp $4096,%rax
+ jbe p2
+ test %rax,-4096(%rsp)
+ sub $4096,%rsp
+ sub $4096,%rax
+ jmp p1
+p2:
+#endif
+ sub %rax,%rsp
+ mov %rsp,%rax
+p3:
+ push %rdx
+ ret
+
+/* ---------------------------------------------- */
+#elif defined __arm__
+
+ .text
+ .align 2
+ .global alloca
+ .type alloca, %function
+alloca:
+ rsb sp, r0, sp
+ bic sp, sp, #7
+ mov r0, sp
+ mov pc, lr
+ .size alloca, .-alloca
+
+/* ---------------------------------------------- */
+#endif
diff --git a/tinycc/lib/armeabi.c b/tinycc/lib/armeabi.c
new file mode 100644
index 0000000..6ade65e
--- /dev/null
+++ b/tinycc/lib/armeabi.c
@@ -0,0 +1,544 @@
+/* TCC ARM runtime EABI
+ Copyright (C) 2013 Thomas Preud'homme
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.*/
+
+#ifdef __TINYC__
+#define INT_MIN (-2147483647 - 1)
+#define INT_MAX 2147483647
+#define UINT_MAX 0xffffffff
+#define LONG_MIN (-2147483647L - 1)
+#define LONG_MAX 2147483647L
+#define ULONG_MAX 0xffffffffUL
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-9223372036854775807LL - 1)
+#define ULLONG_MAX 0xffffffffffffffffULL
+#else
+#include <limits.h>
+#endif
+
+/* We rely on the little endianness and EABI calling convention for this to
+ work */
+
+typedef struct double_unsigned_struct {
+ unsigned low;
+ unsigned high;
+} double_unsigned_struct;
+
+typedef struct unsigned_int_struct {
+ unsigned low;
+ int high;
+} unsigned_int_struct;
+
+#define REGS_RETURN(name, type) \
+ void name ## _return(type ret) {}
+
+
+/* Float helper functions */
+
+#define FLOAT_EXP_BITS 8
+#define FLOAT_FRAC_BITS 23
+
+#define DOUBLE_EXP_BITS 11
+#define DOUBLE_FRAC_BITS 52
+
+#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1)
+
+REGS_RETURN(unsigned_int_struct, unsigned_int_struct)
+REGS_RETURN(double_unsigned_struct, double_unsigned_struct)
+
+/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */
+
+
+/* float to [unsigned] long long conversion */
+#define DEFINE__AEABI_F2XLZ(name, with_sign) \
+void __aeabi_ ## name(unsigned val) \
+{ \
+ int exp, high_shift, sign; \
+ double_unsigned_struct ret; \
+ \
+ /* compute sign */ \
+ sign = val >> 31; \
+ \
+ /* compute real exponent */ \
+ exp = val >> FLOAT_FRAC_BITS; \
+ exp &= (1 << FLOAT_EXP_BITS) - 1; \
+ exp -= ONE_EXP(FLOAT); \
+ \
+ /* undefined behavior if truncated value cannot be represented */ \
+ if (with_sign) { \
+ if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
+ return; \
+ } else { \
+ if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
+ return; \
+ } \
+ \
+ val &= (1 << FLOAT_FRAC_BITS) - 1; \
+ if (exp >= 32) { \
+ ret.high = 1 << (exp - 32); \
+ if (exp - 32 >= FLOAT_FRAC_BITS) { \
+ ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \
+ ret.low = 0; \
+ } else { \
+ high_shift = FLOAT_FRAC_BITS - (exp - 32); \
+ ret.high |= val >> high_shift; \
+ ret.low = val << (32 - high_shift); \
+ } \
+ } else { \
+ ret.high = 0; \
+ ret.low = 1 << exp; \
+ if (exp > FLOAT_FRAC_BITS) \
+ ret.low |= val << (exp - FLOAT_FRAC_BITS); \
+ else \
+ ret.low |= val >> (FLOAT_FRAC_BITS - exp); \
+ } \
+ \
+ /* encode negative integer using 2's complement */ \
+ if (with_sign && sign) { \
+ ret.low = ~ret.low; \
+ ret.high = ~ret.high; \
+ if (ret.low == UINT_MAX) { \
+ ret.low = 0; \
+ ret.high++; \
+ } else \
+ ret.low++; \
+ } \
+ \
+ double_unsigned_struct_return(ret); \
+}
+
+/* float to unsigned long long conversion */
+DEFINE__AEABI_F2XLZ(f2ulz, 0)
+
+/* float to long long conversion */
+DEFINE__AEABI_F2XLZ(f2lz, 1)
+
+/* double to [unsigned] long long conversion */
+#define DEFINE__AEABI_D2XLZ(name, with_sign) \
+void __aeabi_ ## name(double_unsigned_struct val) \
+{ \
+ int exp, high_shift, sign; \
+ double_unsigned_struct ret; \
+ \
+ if ((val.high & ~0x80000000) == 0 && val.low == 0) { \
+ ret.low = ret.high = 0; \
+ goto _ret_; \
+ } \
+ \
+ /* compute sign */ \
+ sign = val.high >> 31; \
+ \
+ /* compute real exponent */ \
+ exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \
+ exp &= (1 << DOUBLE_EXP_BITS) - 1; \
+ exp -= ONE_EXP(DOUBLE); \
+ \
+ /* undefined behavior if truncated value cannot be represented */ \
+ if (with_sign) { \
+ if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
+ return; \
+ } else { \
+ if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
+ return; \
+ } \
+ \
+ val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \
+ if (exp >= 32) { \
+ ret.high = 1 << (exp - 32); \
+ if (exp >= DOUBLE_FRAC_BITS) { \
+ high_shift = exp - DOUBLE_FRAC_BITS; \
+ ret.high |= val.high << high_shift; \
+ ret.high |= val.low >> (32 - high_shift); \
+ ret.low = val.low << high_shift; \
+ } else { \
+ high_shift = DOUBLE_FRAC_BITS - exp; \
+ ret.high |= val.high >> high_shift; \
+ ret.low = val.high << (32 - high_shift); \
+ ret.low |= val.low >> high_shift; \
+ } \
+ } else { \
+ ret.high = 0; \
+ ret.low = 1 << exp; \
+ if (exp > DOUBLE_FRAC_BITS - 32) { \
+ high_shift = exp - DOUBLE_FRAC_BITS - 32; \
+ ret.low |= val.high << high_shift; \
+ ret.low |= val.low >> (32 - high_shift); \
+ } else \
+ ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \
+ } \
+ \
+ /* encode negative integer using 2's complement */ \
+ if (with_sign && sign) { \
+ ret.low = ~ret.low; \
+ ret.high = ~ret.high; \
+ if (ret.low == UINT_MAX) { \
+ ret.low = 0; \
+ ret.high++; \
+ } else \
+ ret.low++; \
+ } \
+ \
+_ret_: \
+ double_unsigned_struct_return(ret); \
+}
+
+/* double to unsigned long long conversion */
+DEFINE__AEABI_D2XLZ(d2ulz, 0)
+
+/* double to long long conversion */
+DEFINE__AEABI_D2XLZ(d2lz, 1)
+
+/* long long to float conversion */
+#define DEFINE__AEABI_XL2F(name, with_sign) \
+unsigned __aeabi_ ## name(unsigned long long v) \
+{ \
+ int s /* shift */, flb /* first lost bit */, sign = 0; \
+ unsigned p = 0 /* power */, ret; \
+ double_unsigned_struct val; \
+ \
+ /* fraction in negative float is encoded in 1's complement */ \
+ if (with_sign && (v & (1ULL << 63))) { \
+ sign = 1; \
+ v = ~v + 1; \
+ } \
+ val.low = v; \
+ val.high = v >> 32; \
+ /* fill fraction bits */ \
+ for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
+ if (p) { \
+ ret = val.high & (p - 1); \
+ if (s < FLOAT_FRAC_BITS) { \
+ ret <<= FLOAT_FRAC_BITS - s; \
+ ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \
+ flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \
+ } else { \
+ flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
+ ret >>= s - FLOAT_FRAC_BITS; \
+ } \
+ s += 32; \
+ } else { \
+ for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
+ if (p) { \
+ ret = val.low & (p - 1); \
+ if (s <= FLOAT_FRAC_BITS) { \
+ ret <<= FLOAT_FRAC_BITS - s; \
+ flb = 0; \
+ } else { \
+ flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
+ ret >>= s - FLOAT_FRAC_BITS; \
+ } \
+ } else \
+ return 0; \
+ } \
+ if (flb) \
+ ret++; \
+ \
+ /* fill exponent bits */ \
+ ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \
+ \
+ /* fill sign bit */ \
+ ret |= sign << 31; \
+ \
+ return ret; \
+}
+
+/* unsigned long long to float conversion */
+DEFINE__AEABI_XL2F(ul2f, 0)
+
+/* long long to float conversion */
+DEFINE__AEABI_XL2F(l2f, 1)
+
+/* long long to double conversion */
+#define __AEABI_XL2D(name, with_sign) \
+void __aeabi_ ## name(unsigned long long v) \
+{ \
+ int s /* shift */, high_shift, sign = 0; \
+ unsigned tmp, p = 0; \
+ double_unsigned_struct val, ret; \
+ \
+ /* fraction in negative float is encoded in 1's complement */ \
+ if (with_sign && (v & (1ULL << 63))) { \
+ sign = 1; \
+ v = ~v + 1; \
+ } \
+ val.low = v; \
+ val.high = v >> 32; \
+ \
+ /* fill fraction bits */ \
+ for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
+ if (p) { \
+ tmp = val.high & (p - 1); \
+ if (s < DOUBLE_FRAC_BITS - 32) { \
+ high_shift = DOUBLE_FRAC_BITS - 32 - s; \
+ ret.high = tmp << high_shift; \
+ ret.high |= val.low >> (32 - high_shift); \
+ ret.low = val.low << high_shift; \
+ } else { \
+ high_shift = s - (DOUBLE_FRAC_BITS - 32); \
+ ret.high = tmp >> high_shift; \
+ ret.low = tmp << (32 - high_shift); \
+ ret.low |= val.low >> high_shift; \
+ if ((val.low >> (high_shift - 1)) & 1) { \
+ if (ret.low == UINT_MAX) { \
+ ret.high++; \
+ ret.low = 0; \
+ } else \
+ ret.low++; \
+ } \
+ } \
+ s += 32; \
+ } else { \
+ for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
+ if (p) { \
+ tmp = val.low & (p - 1); \
+ if (s <= DOUBLE_FRAC_BITS - 32) { \
+ high_shift = DOUBLE_FRAC_BITS - 32 - s; \
+ ret.high = tmp << high_shift; \
+ ret.low = 0; \
+ } else { \
+ high_shift = s - (DOUBLE_FRAC_BITS - 32); \
+ ret.high = tmp >> high_shift; \
+ ret.low = tmp << (32 - high_shift); \
+ } \
+ } else { \
+ ret.high = ret.low = 0; \
+ goto _ret_; \
+ } \
+ } \
+ \
+ /* fill exponent bits */ \
+ ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \
+ \
+ /* fill sign bit */ \
+ ret.high |= sign << 31; \
+ \
+_ret_: \
+ double_unsigned_struct_return(ret); \
+}
+
+/* unsigned long long to double conversion */
+__AEABI_XL2D(ul2d, 0)
+
+/* long long to double conversion */
+__AEABI_XL2D(l2d, 1)
+
+
+/* Long long helper functions */
+
+/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */
+
+#define define_aeabi_xdivmod_signed_type(basetype, type) \
+typedef struct type { \
+ basetype quot; \
+ unsigned basetype rem; \
+} type
+
+#define define_aeabi_xdivmod_unsigned_type(basetype, type) \
+typedef struct type { \
+ basetype quot; \
+ basetype rem; \
+} type
+
+#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \
+static inline rettype aeabi_ ## name (type num, type den) \
+{ \
+ rettype ret; \
+ type quot = 0; \
+ \
+ /* Increase quotient while it is less than numerator */ \
+ while (num >= den) { \
+ type q = 1; \
+ \
+ /* Find closest power of two */ \
+ while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \
+ q <<= 1; \
+ \
+ /* Compute difference between current quotient and numerator */ \
+ num -= q * den; \
+ quot += q; \
+ } \
+ ret.quot = quot; \
+ ret.rem = num; \
+ return ret; \
+}
+
+#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \
+void __aeabi_ ## name(type numerator, type denominator) \
+{ \
+ unsigned type num, den; \
+ urettype uxdiv_ret; \
+ rettype ret; \
+ \
+ if (numerator >= 0) \
+ num = numerator; \
+ else \
+ num = 0 - numerator; \
+ if (denominator >= 0) \
+ den = denominator; \
+ else \
+ den = 0 - denominator; \
+ uxdiv_ret = aeabi_ ## uiname(num, den); \
+ /* signs differ */ \
+ if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \
+ ret.quot = 0 - uxdiv_ret.quot; \
+ else \
+ ret.quot = uxdiv_ret.quot; \
+ if (numerator < 0) \
+ ret.rem = 0 - uxdiv_ret.rem; \
+ else \
+ ret.rem = uxdiv_ret.rem; \
+ \
+ rettype ## _return(ret); \
+}
+
+define_aeabi_xdivmod_signed_type(long long, lldiv_t);
+define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t);
+define_aeabi_xdivmod_signed_type(int, idiv_t);
+define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t);
+
+REGS_RETURN(lldiv_t, lldiv_t)
+REGS_RETURN(ulldiv_t, ulldiv_t)
+REGS_RETURN(idiv_t, idiv_t)
+REGS_RETURN(uidiv_t, uidiv_t)
+
+AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULLONG)
+
+__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG)
+
+void __aeabi_uldivmod(unsigned long long num, unsigned long long den)
+{
+ ulldiv_t_return(aeabi_uldivmod(num, den));
+}
+
+void __aeabi_llsl(double_unsigned_struct val, int shift)
+{
+ double_unsigned_struct ret;
+
+ if (shift >= 32) {
+ val.high = val.low;
+ val.low = 0;
+ shift -= 32;
+ }
+ if (shift > 0) {
+ ret.low = val.low << shift;
+ ret.high = (val.high << shift) | (val.low >> (32 - shift));
+ double_unsigned_struct_return(ret);
+ return;
+ }
+ double_unsigned_struct_return(val);
+}
+
+#define aeabi_lsr(val, shift, fill, type) \
+ type ## _struct ret; \
+ \
+ if (shift >= 32) { \
+ val.low = val.high; \
+ val.high = fill; \
+ shift -= 32; \
+ } \
+ if (shift > 0) { \
+ ret.high = val.high >> shift; \
+ ret.low = (val.high << (32 - shift)) | (val.low >> shift); \
+ type ## _struct_return(ret); \
+ return; \
+ } \
+ type ## _struct_return(val);
+
+void __aeabi_llsr(double_unsigned_struct val, int shift)
+{
+ aeabi_lsr(val, shift, 0, double_unsigned);
+}
+
+void __aeabi_lasr(unsigned_int_struct val, int shift)
+{
+ aeabi_lsr(val, shift, val.high >> 31, unsigned_int);
+}
+
+
+/* Integer division functions */
+
+AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT)
+
+int __aeabi_idiv(int numerator, int denominator)
+{
+ unsigned num, den;
+ uidiv_t ret;
+
+ if (numerator >= 0)
+ num = numerator;
+ else
+ num = 0 - numerator;
+ if (denominator >= 0)
+ den = denominator;
+ else
+ den = 0 - denominator;
+ ret = aeabi_uidivmod(num, den);
+ if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */
+ ret.quot *= -1;
+ return ret.quot;
+}
+
+unsigned __aeabi_uidiv(unsigned num, unsigned den)
+{
+ return aeabi_uidivmod(num, den).quot;
+}
+
+__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT)
+
+void __aeabi_uidivmod(unsigned num, unsigned den)
+{
+ uidiv_t_return(aeabi_uidivmod(num, den));
+}
+
+/* Some targets do not have all eabi calls (OpenBSD) */
+typedef __SIZE_TYPE__ size_t;
+extern void *memcpy(void *dest, const void *src, size_t n);
+extern void *memmove(void *dest, const void *src, size_t n);
+extern void *memset(void *s, int c, size_t n);
+
+void *
+__aeabi_memcpy (void *dest, const void *src, size_t n)
+{
+ return memcpy (dest, src, n);
+}
+
+void *
+__aeabi_memmove (void *dest, const void *src, size_t n)
+{
+ return memmove (dest, src, n);
+}
+
+void *
+__aeabi_memmove4 (void *dest, const void *src, size_t n)
+{
+ return memmove (dest, src, n);
+}
+
+void *
+__aeabi_memmove8 (void *dest, const void *src, size_t n)
+{
+ return memmove (dest, src, n);
+}
+
+void *
+__aeabi_memset (void *s, size_t n, int c)
+{
+ return memset (s, c, n);
+}
diff --git a/tinycc/lib/armflush.c b/tinycc/lib/armflush.c
new file mode 100644
index 0000000..c379e43
--- /dev/null
+++ b/tinycc/lib/armflush.c
@@ -0,0 +1,51 @@
+/* armflush.c - flush the instruction cache
+
+ __clear_cache is used in tccrun.c, It is a built-in
+ intrinsic with gcc. However tcc in order to compile
+ itself needs this function */
+
+#ifdef __TINYC__
+
+/* syscall wrapper */
+unsigned _tccsyscall(unsigned syscall_nr, ...);
+
+/* arm-tcc supports only fake asm currently */
+__asm__(
+ ".global _tccsyscall\n"
+ "_tccsyscall:\n"
+ "push {r7, lr}\n\t"
+ "mov r7, r0\n\t"
+ "mov r0, r1\n\t"
+ "mov r1, r2\n\t"
+ "mov r2, r3\n\t"
+ "svc #0\n\t"
+ "pop {r7, pc}"
+ );
+
+/* from unistd.h: */
+#if defined(__thumb__) || defined(__ARM_EABI__)
+# define __NR_SYSCALL_BASE 0x0
+#else
+# define __NR_SYSCALL_BASE 0x900000
+#endif
+#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
+#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+
+#define syscall _tccsyscall
+
+#else
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+
+#endif
+
+/* Flushing for tccrun */
+void __clear_cache(void *beginning, void *end)
+{
+/* __ARM_NR_cacheflush is kernel private and should not be used in user space.
+ * However, there is no ARM asm parser in tcc so we use it for now */
+ syscall(__ARM_NR_cacheflush, beginning, end, 0);
+}
diff --git a/tinycc/lib/atomic.S b/tinycc/lib/atomic.S
new file mode 100644
index 0000000..29fdbee
--- /dev/null
+++ b/tinycc/lib/atomic.S
@@ -0,0 +1,858 @@
+/* ---------------------------------------------- */
+/* This file implements for arm/arm64/riscv:
+ * __atomic_compare_exchange_1
+ * __atomic_compare_exchange_2
+ * __atomic_compare_exchange_4
+ * __atomic_compare_exchange_8
+ */
+
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
+
+#if defined __i386__
+ .text
+ .align 2
+
+ .global _(__atomic_test_and_set)
+ .type _(__atomic_test_and_set), %function
+_(__atomic_test_and_set):
+ movl 4(%esp), %edx
+ movl $1, %eax
+ xchgb (%edx), %al
+ ret
+ .size _(__atomic_test_and_set), .-_(__atomic_test_and_set)
+
+ .global _(__atomic_clear)
+ .type _(__atomic_clear), %function
+_(__atomic_clear):
+ movl 4(%esp), %edx
+ xorl %eax, %eax
+ xchgb (%edx), %al
+ ret
+ .size _(__atomic_clear), .-_(__atomic_clear)
+
+#elif defined __x86_64__
+ .text
+ .align 2
+
+ .global _(__atomic_test_and_set)
+ .type _(__atomic_test_and_set), %function
+_(__atomic_test_and_set):
+ movl $1, %eax
+ xchgb (%rdi), %al
+ ret
+ .size _(__atomic_test_and_set), .-_(__atomic_test_and_set)
+
+ .global _(__atomic_clear)
+ .type _(__atomic_clear), %function
+_(__atomic_clear):
+ xorl %eax, %eax
+ xchgb (%rdi), %al
+ ret
+ .size _(__atomic_clear), .-_(__atomic_clear)
+
+#elif defined __arm__
+
+#ifndef __TINYC__
+ .arch armv6k
+ .syntax unified
+#endif
+ .text
+ .align 2
+
+ .global _(fetch_and_add_arm)
+ .type _(fetch_and_add_arm), %function
+_(fetch_and_add_arm):
+ mcr p15, #0, r0, c7, c10, #5
+.L0:
+ ldrex r3, [r0]
+ add r3, r3, r1
+ strex r2, r3, [r0]
+ cmp r2, #0
+ bne .L0
+ mcr p15, #0, r0, c7, c10, #5
+ bx lr
+ .size _(fetch_and_add_arm), .-_(fetch_and_add_arm)
+
+ .global _(__atomic_test_and_set)
+ .type _(__atomic_test_and_set), %function
+_(__atomic_test_and_set):
+#ifdef __TINYC__
+ .int 0xe92d4030
+ .int 0xee070fba
+ .int 0xe5d03000
+ .int 0xe24dd014
+ .int 0xe1a05000
+ .int 0xe2533000
+ .int 0xe1a04001
+ .int 0x13a03001
+ .int 0xee070fba
+ .int 0xe5cd300f
+ .int 0xe3a03001
+ .int 0xe1a02003
+ .int 0xe28d100f
+ .int 0xe1a00005
+ .int 0xe58d4004
+ .int 0xe58d4000
+ .int 0xeb000009
+ .int 0xe3500000
+ .int 0x0afffff6
+ .int 0xe5dd000f
+ .int 0xe28dd014
+ .int 0xe8bd8030
+#else
+ push {r4, r5, lr}
+ mcr p15, 0, r0, c7, c10, 5
+ ldrb r3, [r0]
+ sub sp, sp, #20
+ mov r5, r0
+ subs r3, r3, #0
+ mov r4, r1
+ movne r3, #1
+ mcr p15, 0, r0, c7, c10, 5
+ strb r3, [sp, #15]
+.L20:
+ mov r3, #1
+ mov r2, r3
+ add r1, sp, #15
+ mov r0, r5
+ str r4, [sp, #4]
+ str r4, [sp]
+ bl __atomic_compare_exchange_1
+ cmp r0, #0
+ beq .L20
+ ldrb r0, [sp, #15]
+ add sp, sp, #20
+ pop {r4, r5, pc}
+#endif
+ .size _(__atomic_test_and_set), .-_(__atomic_test_and_set)
+
+ .global _(__atomic_clear)
+ .type _(__atomic_clear), %function
+_(__atomic_clear):
+#ifdef __TINYC__
+ .int 0xe3a03000
+ .int 0xee070fba
+ .int 0xe5c03000
+ .int 0xee070fba
+ .int 0xe12fff1e
+#else
+ mov r3, #0
+ mcr p15, 0, r0, c7, c10, 5
+ strb r3, [r0]
+ mcr p15, 0, r0, c7, c10, 5
+ bx lr
+#endif
+ .size _(__atomic_clear), .-_(__atomic_clear)
+
+ .global _(__atomic_compare_exchange_1)
+ .type _(__atomic_compare_exchange_1), %function
+_(__atomic_compare_exchange_1):
+#ifdef __TINYC__
+ .int 0xe52de004
+ .int 0xe5d13000
+ .int 0xf57ff05b
+ .int 0xe1d0cf9f
+ .int 0xe15c0003
+ .int 0x1a000002
+ .int 0xe1c0ef92
+ .int 0xe35e0000
+ .int 0x1afffff9
+ .int 0x03a00001
+ .int 0x13a00000
+ .int 0xf57ff05b
+ .int 0x15c1c000
+ .int 0xe49df004
+#else
+ str lr, [sp, #-4]!
+ ldrb r3, [r1]
+ mcr p15, 0, r0, c7, c10, 5
+.L1:
+ ldrexb ip, [r0]
+ cmp ip, r3
+ bne .L2
+ strexb lr, r2, [r0]
+ cmp lr, #0
+ bne .L1
+.L2:
+ mcr p15, 0, r0, c7, c10, 5
+ moveq r0, #1
+ movne r0, #0
+ strbne ip, [r1]
+ ldr pc, [sp], #4
+#endif
+ .size _(__atomic_compare_exchange_1), .-_(__atomic_compare_exchange_1)
+
+ .global _(__atomic_compare_exchange_2)
+ .type _(__atomic_compare_exchange_2), %function
+_(__atomic_compare_exchange_2):
+#ifdef __TINYC__
+ .int 0xe52de004
+ .int 0xe1d130b0
+ .int 0xf57ff05b
+ .int 0xe1f0cf9f
+ .int 0xe15c0003
+ .int 0x1a000002
+ .int 0xe1e0ef92
+ .int 0xe35e0000
+ .int 0x1afffff9
+ .int 0x03a00001
+ .int 0x13a00000
+ .int 0xf57ff05b
+ .int 0x11c1c0b0
+ .int 0xe49df004
+#else
+ str lr, [sp, #-4]!
+ ldrh r3, [r1]
+ mcr p15, 0, r0, c7, c10, 5
+.L3:
+ ldrexh ip, [r0]
+ cmp ip, r3
+ bne .L4
+ strexh lr, r2, [r0]
+ cmp lr, #0
+ bne .L3
+.L4:
+ mcr p15, 0, r0, c7, c10, 5
+ moveq r0, #1
+ movne r0, #0
+ strhne ip, [r1]
+ ldr pc, [sp], #4
+#endif
+ .size _(__atomic_compare_exchange_2), .-_(__atomic_compare_exchange_2)
+
+ .global _(__atomic_compare_exchange_4)
+ .type _(__atomic_compare_exchange_4), %function
+_(__atomic_compare_exchange_4):
+#ifdef __TINYC__
+ .int 0xe52de004
+ .int 0xe5913000
+ .int 0xf57ff05b
+ .int 0xe190cf9f
+ .int 0xe15c0003
+ .int 0x1a000002
+ .int 0xe180ef92
+ .int 0xe35e0000
+ .int 0x1afffff9
+ .int 0x03a00001
+ .int 0x13a00000
+ .int 0xf57ff05b
+ .int 0x1581c000
+ .int 0xe49df004
+#else
+ str lr, [sp, #-4]!
+ ldr r3, [r1]
+ mcr p15, 0, r0, c7, c10, 5
+.L5:
+ ldrex ip, [r0]
+ cmp ip, r3
+ bne .L6
+ strex lr, r2, [r0]
+ cmp lr, #0
+ bne .L5
+.L6:
+ mcr p15, 0, r0, c7, c10, 5
+ moveq r0, #1
+ movne r0, #0
+ strne ip, [r1]
+ ldr pc, [sp], #4
+#endif
+ .size _(__atomic_compare_exchange_4), .-_(__atomic_compare_exchange_4)
+
+/* ---------------------------------------------- */
+#elif defined __aarch64__
+
+ .text
+ .align 2
+
+ .global _(fetch_and_add_arm64)
+ .type _(fetch_and_add_arm64), %function
+_(fetch_and_add_arm64):
+#ifdef __TINYC__
+ .int 0x885f7c02
+ .int 0x0b010042
+ .int 0x8803fc02
+ .int 0x35ffffa3
+ .int 0xd5033bbf
+ .int 0xd65f03c0
+#else
+ ldxr w2, [x0]
+ add w2, w2, w1
+ stlxr w3, w2, [x0]
+ cbnz w3, _(fetch_and_add_arm64)
+ dmb ish
+ ret
+#endif
+ .size _(fetch_and_add_arm64), .-_(fetch_and_add_arm64)
+
+ .global _(__atomic_test_and_set)
+ .type _(__atomic_test_and_set), %function
+_(__atomic_test_and_set):
+#ifdef __TINYC__
+ .int 0xa9bf7bfd
+ .int 0xaa0003e1
+ .int 0x52800020
+ .int 0x910003fd
+ .int 0x2a0003f0
+ .int 0x085ffc20
+ .int 0x0811fc30
+ .int 0x35ffffd1
+ .int 0xa8c17bfd
+ .int 0xd65f03c0
+#else
+ stp x29, x30, [sp, -16]!
+ mov x1, x0
+ mov w0, 1
+ mov x29, sp
+ mov w16, w0
+.L20:
+ ldaxrb w0, [x1]
+ stlxrb w17, w16, [x1]
+ cbnz w17, .L20
+ ldp x29, x30, [sp], 16
+ ret
+#endif
+ .size _(__atomic_test_and_set), .-_(__atomic_test_and_set)
+
+ .global _(__atomic_clear)
+ .type _(__atomic_clear), %function
+_(__atomic_clear):
+#ifdef __TINYC__
+ .int 0x089ffc1f
+ .int 0xd65f03c0
+#else
+ stlrb wzr, [x0]
+ ret
+#endif
+ .size _(__atomic_clear), .-_(__atomic_clear)
+
+ .global _(__atomic_compare_exchange_1)
+ .type _(__atomic_compare_exchange_1), %function
+_(__atomic_compare_exchange_1):
+#ifdef __TINYC__
+ .int 0xa9be7bfd
+ .int 0x910003fd
+ .int 0xa90153f3
+ .int 0xaa0103f3
+ .int 0x12001c41
+ .int 0xaa0003e2
+ .int 0x39400274
+ .int 0x2a1403e0
+ .int 0x53001c10
+ .int 0x085ffc40
+ .int 0x6b10001f
+ .int 0x54000061
+ .int 0x0811fc41
+ .int 0x35ffff91
+ .int 0x6b34001f
+ .int 0x1a9f17e1
+ .int 0x54000040
+ .int 0x39000260
+ .int 0x2a0103e0
+ .int 0xa94153f3
+ .int 0xa8c27bfd
+ .int 0xd65f03c0
+#else
+ stp x29, x30, [sp, -32]!
+ mov x29, sp
+ stp x19, x20, [sp, 16]
+ mov x19, x1
+ and w1, w2, 255
+ mov x2, x0
+ ldrb w20, [x19]
+ mov w0, w20
+ uxtb w16, w0
+.L1:
+ ldaxrb w0, [x2]
+ cmp w0, w16
+ b.ne .L2
+ stlxrb w17, w1, [x2]
+ cbnz w17, .L1
+.L2:
+ cmp w0, w20, uxtb
+ cset w1, eq
+ beq .L3
+ strb w0, [x19]
+.L3:
+ mov w0, w1
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 32
+ ret
+#endif
+ .size _(__atomic_compare_exchange_1), .-_(__atomic_compare_exchange_1)
+
+ .global _(__atomic_compare_exchange_2)
+ .type _(__atomic_compare_exchange_2), %function
+_(__atomic_compare_exchange_2):
+#ifdef __TINYC__
+ .int 0xa9be7bfd
+ .int 0x910003fd
+ .int 0xa90153f3
+ .int 0xaa0103f3
+ .int 0x12003c41
+ .int 0xaa0003e2
+ .int 0x79400274
+ .int 0x2a1403e0
+ .int 0x53003c10
+ .int 0x485ffc40
+ .int 0x6b10001f
+ .int 0x54000061
+ .int 0x4811fc41
+ .int 0x35ffff91
+ .int 0x6b34201f
+ .int 0x1a9f17e1
+ .int 0x54000040
+ .int 0x79000260
+ .int 0x2a0103e0
+ .int 0xa94153f3
+ .int 0xa8c27bfd
+ .int 0xd65f03c0
+#else
+ stp x29, x30, [sp, -32]!
+ mov x29, sp
+ stp x19, x20, [sp, 16]
+ mov x19, x1
+ and w1, w2, 65535
+ mov x2, x0
+ ldrh w20, [x19]
+ mov w0, w20
+ uxth w16, w0
+.L4:
+ ldaxrh w0, [x2]
+ cmp w0, w16
+ b.ne .L5
+ stlxrh w17, w1, [x2]
+ cbnz w17, .L4
+.L5:
+ cmp w0, w20, uxth
+ cset w1, eq
+ beq .L6
+ strh w0, [x19]
+.L6:
+ mov w0, w1
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 32
+ ret
+#endif
+ .size _(__atomic_compare_exchange_2), .-_(__atomic_compare_exchange_2)
+
+ .global _(__atomic_compare_exchange_4)
+ .type _(__atomic_compare_exchange_4), %function
+_(__atomic_compare_exchange_4):
+#ifdef __TINYC__
+ .int 0xa9be7bfd
+ .int 0x910003fd
+ .int 0xa90153f3
+ .int 0xaa0103f3
+ .int 0x2a0203e1
+ .int 0xaa0003e2
+ .int 0xb9400274
+ .int 0x2a1403e0
+ .int 0x2a0003f0
+ .int 0x885ffc40
+ .int 0x6b10001f
+ .int 0x54000061
+ .int 0x8811fc41
+ .int 0x35ffff91
+ .int 0x6b14001f
+ .int 0x1a9f17e1
+ .int 0x54000040
+ .int 0xb9000260
+ .int 0x2a0103e0
+ .int 0xa94153f3
+ .int 0xa8c27bfd
+ .int 0xd65f03c0
+#else
+ stp x29, x30, [sp, -32]!
+ mov x29, sp
+ stp x19, x20, [sp, 16]
+ mov x19, x1
+ mov w1, w2
+ mov x2, x0
+ ldr w20, [x19]
+ mov w0, w20
+ mov w16, w0
+.L7:
+ ldaxr w0, [x2]
+ cmp w0, w16
+ b.ne .L8
+ stlxr w17, w1, [x2]
+ cbnz w17, .L7
+.L8:
+ cmp w0, w20
+ cset w1, eq
+ beq .L9
+ str w0, [x19]
+.L9:
+ mov w0, w1
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 32
+ ret
+#endif
+ .size _(__atomic_compare_exchange_4), .-_(__atomic_compare_exchange_4)
+
+ .global _(__atomic_compare_exchange_8)
+ .type _(__atomic_compare_exchange_8), %function
+_(__atomic_compare_exchange_8):
+#ifdef __TINYC__
+ .int 0xa9be7bfd
+ .int 0x910003fd
+ .int 0xa90153f3
+ .int 0xaa0103f3
+ .int 0xaa0203e1
+ .int 0xaa0003e2
+ .int 0xf9400274
+ .int 0xaa1403e0
+ .int 0xaa0003f0
+ .int 0xc85ffc40
+ .int 0xeb10001f
+ .int 0x54000061
+ .int 0xc811fc41
+ .int 0x35ffff91
+ .int 0xeb14001f
+ .int 0x1a9f17e1
+ .int 0x54000040
+ .int 0xf9000260
+ .int 0x2a0103e0
+ .int 0xa94153f3
+ .int 0xa8c27bfd
+ .int 0xd65f03c0
+#else
+ stp x29, x30, [sp, -32]!
+ mov x29, sp
+ stp x19, x20, [sp, 16]
+ mov x19, x1
+ mov x1, x2
+ mov x2, x0
+ ldr x20, [x19]
+ mov x0, x20
+ mov x16, x0
+.L10:
+ ldaxr x0, [x2]
+ cmp x0, x16
+ b.ne .L11
+ stlxr w17, x1, [x2]
+ cbnz w17, .L10
+.L11:
+ cmp x0, x20
+ cset w1, eq
+ beq .L12
+ str x0, [x19]
+.L12:
+ mov w0, w1
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 32
+ ret
+#endif
+ .size _(__atomic_compare_exchange_8), .-_(__atomic_compare_exchange_8)
+
+/* ---------------------------------------------- */
+#elif defined __riscv
+
+ .text
+ .align 2
+
+ .global _(fetch_and_add_riscv64)
+ .type _(fetch_and_add_riscv64), %function
+_(fetch_and_add_riscv64):
+#ifdef __TINYC__
+ .int 0x0f50000f
+ .int 0x004b5202f
+ .short 0x8082
+#else
+ fence iorw,ow
+ amoadd.w.aq zero,a1,0(a0)
+ ret
+#endif
+ .size _(fetch_and_add_riscv64), .-_(fetch_and_add_riscv64)
+
+ .global _(__atomic_test_and_set)
+ .type _(__atomic_test_and_set), %function
+_(__atomic_test_and_set):
+#ifdef __TINYC__
+ .int 0x00357793
+ .int 0x0037979b
+ .short 0x4685
+ .short 0x9971
+ .int 0x00f696bb
+ .int 0x0f50000f
+ .int 0x44d5272f
+ .int 0x00f7553b
+ .int 0x0ff57513
+ .short 0x8082
+#else
+ andi a5,a0,3
+ slliw a5,a5,3
+ li a3,1
+ andi a0,a0,-4
+ sllw a3,a3,a5
+ fence iorw,ow; amoor.w.aq a4,a3,0(a0)
+ srlw a0,a4,a5
+ andi a0,a0,0xff
+ ret
+#endif
+ .size _(__atomic_test_and_set), .-_(__atomic_test_and_set)
+
+ .global _(__atomic_clear)
+ .type _(__atomic_clear), %function
+_(__atomic_clear):
+#ifdef __TINYC__
+ .int 0x0ff0000f
+ .int 0x00050023
+ .int 0x0ff0000f
+ .short 0x8082
+#else
+ fence iorw,iorw
+ sb zero,0(a0)
+ fence iorw,iorw
+ ret
+#endif
+ .size _(__atomic_clear), .-_(__atomic_clear)
+
+ .global _(__atomic_compare_exchange_1)
+ .type _(__atomic_compare_exchange_1), %function
+_(__atomic_compare_exchange_1):
+#ifdef __TINYC__
+ .short 0x1141
+ .short 0x86ba
+ .short 0x873e
+ .short 0xe406
+ .int 0x0ff0000f
+ .int 0x0005c803
+ .int 0xff857893
+ .int 0x0008b783
+ .short 0x891d
+ .short 0x050e
+ .int 0x0ff00693
+ .int 0x00a696b3
+ .int 0x00a81833
+ .int 0x00a61633
+ .int 0xfff6c713
+ .short 0x8f7d
+ .int 0x00f6f333
+ .short 0x8f51
+ .int 0x03031263
+ .int 0x1008b32f
+ .int 0x00f31663
+ .int 0x18e8be2f
+ .int 0xfe0e1ae3
+ .int 0x40f30733
+ .short 0x879a
+ .short 0xff69
+ .int 0x0ff0000f
+ .short 0x4505
+ .short 0xa801
+ .int 0x00a7d7b3
+ .int 0x00f58023
+ .int 0x0ff0000f
+ .short 0x4501
+ .short 0x60a2
+ .short 0x0141
+ .short 0x8082
+#else
+ addi sp,sp,-16
+ mv a3,a4
+ mv a4,a5
+ sd ra,8(sp)
+ fence
+ lbu a6,0(a1)
+ andi a7,a0,-8
+ ld a5,0(a7)
+ andi a0,a0,7
+ slli a0,a0,0x3
+ li a3,255
+ sll a3,a3,a0
+ sll a6,a6,a0
+ sll a2,a2,a0
+.L1:
+ not a4,a3
+ and a4,a4,a5
+ and t1,a3,a5
+ or a4,a4,a2
+ bne t1,a6,.L4
+.L2:
+ lr.d t1,(a7)
+ bne t1,a5,.L3
+ sc.d t3,a4,(a7)
+ bnez t3,.L2
+.L3:
+ sub a4,t1,a5
+ mv a5,t1
+ bnez a4,.L1
+ fence
+ li a0,1
+ j .L5
+.L4:
+ srl a5,a5,a0
+ sb a5,0(a1)
+ fence
+ li a0,0
+.L5:
+ ld ra,8(sp)
+ addi sp,sp,16
+ jr ra
+#endif
+ .size _(__atomic_compare_exchange_1), .-_(__atomic_compare_exchange_1)
+
+ .global _(__atomic_compare_exchange_2)
+ .type _(__atomic_compare_exchange_2), %function
+_(__atomic_compare_exchange_2):
+#ifdef __TINYC__
+ .short 0x1141
+ .short 0x86ba
+ .short 0x873e
+ .short 0xe406
+ .int 0x0ff0000f
+ .int 0x0005d803
+ .int 0xff857893
+ .short 0x67c1
+ .short 0x891d
+ .int 0x0008b703
+ .short 0x050e
+ .short 0x17fd
+ .int 0x00a797b3
+ .int 0x00a81833
+ .int 0x00a61633
+ .int 0xfff7c693
+ .short 0x8ef9
+ .int 0x00e7f333
+ .short 0x8ed1
+ .int 0x03031263
+ .int 0x1008b32f
+ .int 0x00e31663
+ .int 0x18d8be2f
+ .int 0xfe0e1ae3
+ .int 0x40e306b3
+ .short 0x871a
+ .short 0xfee9
+ .int 0x0ff0000f
+ .short 0x4505
+ .short 0xa801
+ .int 0x00a75733
+ .int 0x00e59023
+ .int 0x0ff0000f
+ .short 0x4501
+ .short 0x60a2
+ .short 0x0141
+ .short 0x8082
+#else
+ addi sp,sp,-16
+ mv a3,a4
+ mv a4,a5
+ sd ra,8(sp)
+ fence
+ lhu a6,0(a1)
+ andi a7,a0,-8
+ lui a5,0x10
+ andi a0,a0,7
+ ld a4,0(a7)
+ slli a0,a0,0x3
+ addi a5,a5,-1
+ sll a5,a5,a0
+ sll a6,a6,a0
+ sll a2,a2,a0
+.L6:
+ not a3,a5
+ and a3,a3,a4
+ and t1,a5,a4
+ or a3,a3,a2
+ bne t1,a6,.L9
+.L7:
+ lr.d t1,(a7)
+ bne t1,a4,.L8
+ sc.d t3,a3,(a7)
+ bnez t3,.L7
+.L8:
+ sub a3,t1,a4
+ mv a4,t1
+ bnez a3,.L6
+ fence
+ li a0,1
+ j .L10
+.L9:
+ srl a4,a4,a0
+ sh a4,0(a1)
+ fence
+ li a0,0
+.L10:
+ ld ra,8(sp)
+ addi sp,sp,16
+ jr ra
+#endif
+ .size _(__atomic_compare_exchange_2), .-_(__atomic_compare_exchange_2)
+
+ .global _(__atomic_compare_exchange_4)
+ .type _(__atomic_compare_exchange_4), %function
+_(__atomic_compare_exchange_4):
+#ifdef __TINYC__
+ .short 0x419c
+ .int 0x0f50000f
+ .int 0x1405272f
+ .int 0x00f71663
+ .int 0x1cc5282f
+ .int 0xfe081ae3
+ .int 0x40f707bb
+ .int 0x0017b513
+ .short 0xc391
+ .short 0xc198
+ .short 0x8905
+ .short 0x8082
+#else
+ lw a5,0(a1)
+ fence iorw,ow;
+.L11:
+ lr.w.aq a4,0(a0)
+ bne a4,a5,.L12
+ sc.w.aq a6,a2,0(a0)
+ bnez a6,.L11
+.L12:
+ subw a5,a4,a5
+ seqz a0,a5
+ beq a5,zero,.L13
+ sw a4,0(a1)
+.L13:
+ andi a0,a0,1
+ ret
+#endif
+ .size _(__atomic_compare_exchange_4), .-_(__atomic_compare_exchange_4)
+
+ .global _(__atomic_compare_exchange_8)
+ .type _(__atomic_compare_exchange_8), %function
+_(__atomic_compare_exchange_8):
+#ifdef __TINYC__
+ .short 0x619c
+ .int 0x0f50000f
+ .int 0x1405372f
+ .int 0x00f71563
+ .int 0x1cc536af
+ .short 0xfaf5
+ .int 0x40f707b3
+ .int 0x0017b513
+ .short 0xc391
+ .short 0xe198
+ .short 0x8905
+ .short 0x8082
+#else
+ ld a5,0(a1)
+ fence iorw,ow;
+.L14:
+ lr.d.aq a4,0(a0)
+ bne a4,a5,.L15
+ sc.d.aq a3,a2,0(a0)
+ bnez a3,.L14
+.L15:
+ sub a5,a4,a5
+ seqz a0,a5
+ beq a5,zero,.L16
+ sd a4,0(a1)
+.L16:
+ andi a0,a0,1
+ ret
+#endif
+ .size _(__atomic_compare_exchange_8), .-_(__atomic_compare_exchange_8)
+
+/* ---------------------------------------------- */
+#endif
diff --git a/tinycc/lib/bcheck.c b/tinycc/lib/bcheck.c
new file mode 100644
index 0000000..b8dd1c5
--- /dev/null
+++ b/tinycc/lib/bcheck.c
@@ -0,0 +1,2270 @@
+/*
+ * Tiny C Memory and bounds checker
+ *
+ * Copyright (c) 2002 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <setjmp.h>
+
+#if !defined(__FreeBSD__) \
+ && !defined(__FreeBSD_kernel__) \
+ && !defined(__DragonFly__) \
+ && !defined(__OpenBSD__) \
+ && !defined(__APPLE__) \
+ && !defined(__NetBSD__)
+#include <malloc.h>
+#endif
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+
+#define BOUND_DEBUG (1)
+#define BOUND_STATISTIC (1)
+
+#if BOUND_DEBUG
+ #define dprintf(a...) if (print_calls) fprintf(a)
+#else
+ #define dprintf(a...)
+#endif
+
+#ifdef __attribute__
+ /* an __attribute__ macro is defined in the system headers */
+ #undef __attribute__
+#endif
+#define FASTCALL __attribute__((regparm(3)))
+
+#ifdef _WIN32
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT
+#endif
+
+#if defined(__FreeBSD__) \
+ || defined(__FreeBSD_kernel__) \
+ || defined(__DragonFly__) \
+ || defined(__OpenBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__dietlibc__)
+
+#include <sys/mman.h>
+#define INIT_SEM()
+#define EXIT_SEM()
+#define WAIT_SEM()
+#define POST_SEM()
+#define TRY_SEM()
+#define HAVE_MEMALIGN (0)
+#define MALLOC_REDIR (0)
+#define HAVE_PTHREAD_CREATE (0)
+#define HAVE_CTYPE (0)
+#define HAVE_ERRNO (0)
+#define HAVE_SIGNAL (0)
+#define HAVE_SIGACTION (0)
+#define HAVE_FORK (0)
+#define HAVE_TLS_FUNC (0)
+#define HAVE_TLS_VAR (0)
+
+#elif defined(_WIN32)
+
+#include <windows.h>
+#include <signal.h>
+static CRITICAL_SECTION bounds_sem;
+#define INIT_SEM() InitializeCriticalSection(&bounds_sem)
+#define EXIT_SEM() DeleteCriticalSection(&bounds_sem)
+#define WAIT_SEM() EnterCriticalSection(&bounds_sem)
+#define POST_SEM() LeaveCriticalSection(&bounds_sem)
+#define TRY_SEM() TryEnterCriticalSection(&bounds_sem)
+#define HAVE_MEMALIGN (0)
+#define MALLOC_REDIR (0)
+#define HAVE_PTHREAD_CREATE (0)
+#define HAVE_CTYPE (0)
+#define HAVE_ERRNO (0)
+#define HAVE_SIGNAL (1)
+#define HAVE_SIGACTION (0)
+#define HAVE_FORK (0)
+#define HAVE_TLS_FUNC (1)
+#define HAVE_TLS_VAR (0)
+
+#else
+
+#define __USE_GNU /* get RTLD_NEXT */
+#include <sys/mman.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <signal.h>
+#ifdef __APPLE__
+#include <dispatch/dispatch.h>
+static dispatch_semaphore_t bounds_sem;
+#define INIT_SEM() bounds_sem = dispatch_semaphore_create(1)
+#define EXIT_SEM() dispatch_release(*(dispatch_object_t*)&bounds_sem)
+#define WAIT_SEM() if (use_sem) dispatch_semaphore_wait(bounds_sem, DISPATCH_TIME_FOREVER)
+#define POST_SEM() if (use_sem) dispatch_semaphore_signal(bounds_sem)
+#define TRY_SEM() if (use_sem) dispatch_semaphore_wait(bounds_sem, DISPATCH_TIME_NOW)
+#elif 0
+#include <semaphore.h>
+static sem_t bounds_sem;
+#define INIT_SEM() sem_init (&bounds_sem, 0, 1)
+#define EXIT_SEM() sem_destroy (&bounds_sem)
+#define WAIT_SEM() if (use_sem) while (sem_wait (&bounds_sem) < 0 \
+ && errno == EINTR)
+#define POST_SEM() if (use_sem) sem_post (&bounds_sem)
+#define TRY_SEM() if (use_sem) while (sem_trywait (&bounds_sem) < 0 \
+ && errno == EINTR)
+#elif 0
+static pthread_mutex_t bounds_mtx;
+#define INIT_SEM() pthread_mutex_init (&bounds_mtx, NULL)
+#define EXIT_SEM() pthread_mutex_destroy (&bounds_mtx)
+#define WAIT_SEM() if (use_sem) pthread_mutex_lock (&bounds_mtx)
+#define POST_SEM() if (use_sem) pthread_mutex_unlock (&bounds_mtx)
+#define TRY_SEM() if (use_sem) pthread_mutex_trylock (&bounds_mtx)
+#else
+static pthread_spinlock_t bounds_spin;
+/* about 25% faster then semaphore. */
+#define INIT_SEM() pthread_spin_init (&bounds_spin, 0)
+#define EXIT_SEM() pthread_spin_destroy (&bounds_spin)
+#define WAIT_SEM() if (use_sem) pthread_spin_lock (&bounds_spin)
+#define POST_SEM() if (use_sem) pthread_spin_unlock (&bounds_spin)
+#define TRY_SEM() if (use_sem) pthread_spin_trylock (&bounds_spin)
+#endif
+#define HAVE_MEMALIGN (1)
+#define MALLOC_REDIR (1)
+#define HAVE_PTHREAD_CREATE (1)
+#define HAVE_CTYPE (1)
+#define HAVE_ERRNO (1)
+#define HAVE_SIGNAL (1)
+#define HAVE_SIGACTION (1)
+#define HAVE_FORK (1)
+#if !defined(__APPLE__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define HAVE_TLS_FUNC (0)
+#define HAVE_TLS_VAR (1)
+#else
+#define HAVE_TLS_FUNC (1)
+#define HAVE_TLS_VAR (0)
+#endif
+#if defined TCC_MUSL || defined __ANDROID__
+# undef HAVE_CTYPE
+#endif
+#endif
+
+#if MALLOC_REDIR
+static void *(*malloc_redir) (size_t);
+static void *(*calloc_redir) (size_t, size_t);
+static void (*free_redir) (void *);
+static void *(*realloc_redir) (void *, size_t);
+static unsigned int pool_index;
+static unsigned char __attribute__((aligned(16))) initial_pool[256];
+#endif
+#if HAVE_MEMALIGN
+static void *(*memalign_redir) (size_t, size_t);
+#endif
+#if HAVE_PTHREAD_CREATE
+static int (*pthread_create_redir) (pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg);
+#endif
+#if HAVE_SIGNAL
+typedef void (*bound_sig)(int);
+static bound_sig (*signal_redir) (int signum, bound_sig handler);
+#endif
+#if HAVE_SIGACTION
+static int (*sigaction_redir) (int signum, const struct sigaction *act,
+ struct sigaction *oldact);
+#endif
+#if HAVE_FORK
+static int (*fork_redir) (void);
+#endif
+
+#define TCC_TYPE_NONE (0)
+#define TCC_TYPE_MALLOC (1)
+#define TCC_TYPE_CALLOC (2)
+#define TCC_TYPE_REALLOC (3)
+#define TCC_TYPE_MEMALIGN (4)
+#define TCC_TYPE_STRDUP (5)
+
+/* this pointer is generated when bound check is incorrect */
+#define INVALID_POINTER ((void *)(-2))
+
+typedef struct tree_node Tree;
+struct tree_node {
+ Tree * left, * right;
+ size_t start;
+ size_t size;
+ unsigned char type;
+ unsigned char is_invalid; /* true if pointers outside region are invalid */
+};
+
+typedef struct alloca_list_struct {
+ size_t fp;
+ void *p;
+ size_t size;
+ struct alloca_list_struct *next;
+} alloca_list_type;
+
+#if defined(_WIN32)
+#define BOUND_TID_TYPE DWORD
+#define BOUND_GET_TID(id) id = GetCurrentThreadId()
+#elif defined(__OpenBSD__)
+#define BOUND_TID_TYPE pid_t
+#define BOUND_GET_TID(id) id = getthrid()
+#elif defined(__FreeBSD__)
+#define BOUND_TID_TYPE pid_t
+#define BOUND_GET_TID(id) syscall (SYS_thr_self, &id)
+#elif defined(__NetBSD__)
+#define BOUND_TID_TYPE pid_t
+#define BOUND_GET_TID(id) id = syscall (SYS__lwp_self)
+#elif defined(__linux__)
+#define BOUND_TID_TYPE pid_t
+#define BOUND_GET_TID(id) id = syscall (SYS_gettid)
+#else
+#define BOUND_TID_TYPE int
+#define BOUND_GET_TID(id) id = 0
+#endif
+
+typedef struct jmp_list_struct {
+ void *penv;
+ size_t fp;
+ size_t end_fp;
+ BOUND_TID_TYPE tid;
+ struct jmp_list_struct *next;
+} jmp_list_type;
+
+#define BOUND_STATISTIC_SPLAY (0)
+static Tree * splay (size_t addr, Tree *t);
+static Tree * splay_end (size_t addr, Tree *t);
+static Tree * splay_insert(size_t addr, size_t size, Tree * t);
+static Tree * splay_delete(size_t addr, Tree *t);
+void splay_printtree(Tree * t, int d);
+
+/* external interface */
+void __bounds_checking (int no_check);
+void __bound_checking_lock (void);
+void __bound_checking_unlock (void);
+void __bound_never_fatal (int no_check);
+DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
+DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
+DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset);
+DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset);
+DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset);
+DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset);
+DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset);
+DLL_EXPORT void FASTCALL __bound_local_new(void *p1);
+DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
+void __bound_init(size_t *, int);
+void __bound_main_arg(int argc, char **argv, char **envp);
+void __bound_exit(void);
+void __bound_exit_dll(size_t *);
+#if !defined(_WIN32)
+void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
+ off_t offset);
+int __bound_munmap (void *start, size_t size);
+DLL_EXPORT void __bound_siglongjmp(jmp_buf env, int val);
+#endif
+DLL_EXPORT void __bound_new_region(void *p, size_t size);
+DLL_EXPORT void __bound_setjmp(jmp_buf env);
+DLL_EXPORT void __bound_longjmp(jmp_buf env, int val);
+DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
+DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
+DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size);
+DLL_EXPORT int __bound_strlen(const char *s);
+DLL_EXPORT char *__bound_strcpy(char *dst, const char *src);
+DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n);
+DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2);
+DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n);
+DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
+DLL_EXPORT char *__bound_strncat(char *dest, const char *src, size_t n);
+DLL_EXPORT char *__bound_strchr(const char *string, int ch);
+DLL_EXPORT char *__bound_strrchr(const char *string, int ch);
+DLL_EXPORT char *__bound_strdup(const char *s);
+
+#if defined(__arm__) && defined(__ARM_EABI__)
+DLL_EXPORT void *__bound___aeabi_memcpy(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__bound___aeabi_memmove(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__bound___aeabi_memmove4(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__bound___aeabi_memmove8(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__bound___aeabi_memset(void *dst, int c, size_t size);
+DLL_EXPORT void *__aeabi_memcpy(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__aeabi_memmove(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__aeabi_memmove4(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__aeabi_memmove8(void *dst, const void *src, size_t size);
+DLL_EXPORT void *__aeabi_memset(void *dst, int c, size_t size);
+#endif
+
+#if MALLOC_REDIR
+#define BOUND_MALLOC(a) malloc_redir(a)
+#define BOUND_MEMALIGN(a,b) memalign_redir(a,b)
+#define BOUND_FREE(a) free_redir(a)
+#define BOUND_REALLOC(a,b) realloc_redir(a,b)
+#define BOUND_CALLOC(a,b) calloc_redir(a,b)
+#else
+#define BOUND_MALLOC(a) malloc(a)
+#define BOUND_MEMALIGN(a,b) memalign(a,b)
+#define BOUND_FREE(a) free(a)
+#define BOUND_REALLOC(a,b) realloc(a,b)
+#define BOUND_CALLOC(a,b) calloc(a,b)
+DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
+DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller);
+DLL_EXPORT void __bound_free(void *ptr, const void *caller);
+DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller);
+DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size);
+#endif
+
+#define FREE_REUSE_SIZE (100)
+static unsigned int free_reuse_index;
+static void *free_reuse_list[FREE_REUSE_SIZE];
+
+static Tree *tree = NULL;
+#define TREE_REUSE (1)
+#if TREE_REUSE
+static Tree *tree_free_list;
+#endif
+static alloca_list_type *alloca_list;
+static jmp_list_type *jmp_list;
+
+static unsigned char inited;
+static unsigned char print_warn_ptr_add;
+static unsigned char print_calls;
+static unsigned char print_heap;
+static unsigned char print_statistic;
+static unsigned char no_strdup;
+static unsigned char use_sem;
+static int never_fatal;
+#if HAVE_TLS_FUNC
+#if defined(_WIN32)
+static int no_checking = 0;
+static DWORD no_checking_key;
+#define NO_CHECKING_CHECK() if (!p) { \
+ p = (int *) LocalAlloc(LPTR, sizeof(int)); \
+ if (!p) bound_alloc_error("tls malloc"); \
+ *p = 0; \
+ TlsSetValue(no_checking_key, p); \
+ }
+#define NO_CHECKING_GET() ({ int *p = TlsGetValue(no_checking_key); \
+ NO_CHECKING_CHECK(); \
+ *p; \
+ })
+#define NO_CHECKING_SET(v) { int *p = TlsGetValue(no_checking_key); \
+ NO_CHECKING_CHECK(); \
+ *p = v; \
+ }
+#else
+static int no_checking = 0;
+static pthread_key_t no_checking_key;
+#define NO_CHECKING_CHECK() if (!p) { \
+ p = (int *) BOUND_MALLOC(sizeof(int)); \
+ if (!p) bound_alloc_error("tls malloc"); \
+ *p = 0; \
+ pthread_setspecific(no_checking_key, p); \
+ }
+#define NO_CHECKING_GET() ({ int *p = pthread_getspecific(no_checking_key); \
+ NO_CHECKING_CHECK(); \
+ *p; \
+ })
+#define NO_CHECKING_SET(v) { int *p = pthread_getspecific(no_checking_key); \
+ NO_CHECKING_CHECK(); \
+ *p = v; \
+ }
+#endif
+#elif HAVE_TLS_VAR
+static __thread int no_checking = 0;
+#define NO_CHECKING_GET() no_checking
+#define NO_CHECKING_SET(v) no_checking = v
+#else
+static int no_checking = 0;
+#define NO_CHECKING_GET() no_checking
+#define NO_CHECKING_SET(v) no_checking = v
+#endif
+static char exec[100];
+
+#if BOUND_STATISTIC
+static unsigned long long bound_ptr_add_count;
+static unsigned long long bound_ptr_indir1_count;
+static unsigned long long bound_ptr_indir2_count;
+static unsigned long long bound_ptr_indir4_count;
+static unsigned long long bound_ptr_indir8_count;
+static unsigned long long bound_ptr_indir12_count;
+static unsigned long long bound_ptr_indir16_count;
+static unsigned long long bound_local_new_count;
+static unsigned long long bound_local_delete_count;
+static unsigned long long bound_malloc_count;
+static unsigned long long bound_calloc_count;
+static unsigned long long bound_realloc_count;
+static unsigned long long bound_free_count;
+static unsigned long long bound_memalign_count;
+static unsigned long long bound_mmap_count;
+static unsigned long long bound_munmap_count;
+static unsigned long long bound_alloca_count;
+static unsigned long long bound_setjmp_count;
+static unsigned long long bound_longjmp_count;
+static unsigned long long bound_mempcy_count;
+static unsigned long long bound_memcmp_count;
+static unsigned long long bound_memmove_count;
+static unsigned long long bound_memset_count;
+static unsigned long long bound_strlen_count;
+static unsigned long long bound_strcpy_count;
+static unsigned long long bound_strncpy_count;
+static unsigned long long bound_strcmp_count;
+static unsigned long long bound_strncmp_count;
+static unsigned long long bound_strcat_count;
+static unsigned long long bound_strncat_count;
+static unsigned long long bound_strchr_count;
+static unsigned long long bound_strrchr_count;
+static unsigned long long bound_strdup_count;
+static unsigned long long bound_not_found;
+#define INCR_COUNT(x) ++x
+#else
+#define INCR_COUNT(x)
+#endif
+#if BOUND_STATISTIC_SPLAY
+static unsigned long long bound_splay;
+static unsigned long long bound_splay_end;
+static unsigned long long bound_splay_insert;
+static unsigned long long bound_splay_delete;
+#define INCR_COUNT_SPLAY(x) ++x
+#else
+#define INCR_COUNT_SPLAY(x)
+#endif
+
+int tcc_backtrace(const char *fmt, ...);
+
+/* print a bound error message */
+#define bound_warning(...) \
+ do { \
+ WAIT_SEM (); \
+ tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__); \
+ POST_SEM (); \
+ } while (0)
+
+#define bound_error(...) \
+ do { \
+ bound_warning(__VA_ARGS__); \
+ if (never_fatal == 0) \
+ exit(255); \
+ } while (0)
+
+static void bound_alloc_error(const char *s)
+{
+ fprintf(stderr,"FATAL: %s\n",s);
+ exit (1);
+}
+
+static void bound_not_found_warning(const char *file, const char *function,
+ void *ptr)
+{
+ dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
+}
+
+static void fetch_and_add(int* variable, int value)
+{
+#if defined __i386__ || defined __x86_64__
+ __asm__ volatile("lock; addl %0, %1"
+ : "+r" (value), "+m" (*variable) // input+output
+ : // No input-only
+ : "memory"
+ );
+#elif defined __arm__
+ extern void fetch_and_add_arm(int* variable, int value);
+ fetch_and_add_arm(variable, value);
+#elif defined __aarch64__
+ extern void fetch_and_add_arm64(int* variable, int value);
+ fetch_and_add_arm64(variable, value);
+#elif defined __riscv
+ extern void fetch_and_add_riscv64(int* variable, int value);
+ fetch_and_add_riscv64(variable, value);
+#else
+ *variable += value;
+#endif
+}
+
+/* enable/disable checking. This can be used in signal handlers. */
+void __bounds_checking (int no_check)
+{
+#if HAVE_TLS_FUNC || HAVE_TLS_VAR
+ NO_CHECKING_SET(NO_CHECKING_GET() + no_check);
+#else
+ fetch_and_add (&no_checking, no_check);
+#endif
+}
+
+void __bound_checking_lock(void)
+{
+ WAIT_SEM ();
+}
+
+void __bound_checking_unlock(void)
+{
+ POST_SEM ();
+}
+
+/* enable/disable checking. This can be used in signal handlers. */
+void __bound_never_fatal (int neverfatal)
+{
+ fetch_and_add (&never_fatal, neverfatal);
+}
+
+/* return '(p + offset)' for pointer arithmetic (a pointer can reach
+ the end of a region in this case */
+void * __bound_ptr_add(void *p, size_t offset)
+{
+ size_t addr = (size_t)p;
+
+ if (NO_CHECKING_GET())
+ return p + offset;
+
+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
+ __FILE__, __FUNCTION__, p, (unsigned long)offset);
+
+ WAIT_SEM ();
+ INCR_COUNT(bound_ptr_add_count);
+ if (tree) {
+ addr -= tree->start;
+ if (addr >= tree->size) {
+ addr = (size_t)p;
+ tree = splay (addr, tree);
+ addr -= tree->start;
+ }
+ if (addr >= tree->size) {
+ addr = (size_t)p;
+ tree = splay_end (addr, tree);
+ addr -= tree->start;
+ }
+ if (addr <= tree->size) {
+ if (tree->is_invalid || addr + offset > tree->size) {
+ POST_SEM ();
+ if (print_warn_ptr_add)
+ bound_warning("%p is outside of the region", p + offset);
+ if (never_fatal <= 0)
+ return INVALID_POINTER; /* return an invalid pointer */
+ return p + offset;
+ }
+ }
+ else if (p) { /* Allow NULL + offset. offsetoff is using it. */
+ INCR_COUNT(bound_not_found);
+ POST_SEM ();
+ bound_not_found_warning (__FILE__, __FUNCTION__, p);
+ return p + offset;
+ }
+ }
+ POST_SEM ();
+ return p + offset;
+}
+
+/* return '(p + offset)' for pointer indirection (the resulting must
+ be strictly inside the region */
+#define BOUND_PTR_INDIR(dsize) \
+void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
+{ \
+ size_t addr = (size_t)p; \
+ \
+ if (NO_CHECKING_GET()) \
+ return p + offset; \
+ \
+ dprintf(stderr, "%s, %s(): %p 0x%lx\n", \
+ __FILE__, __FUNCTION__, p, (unsigned long)offset); \
+ WAIT_SEM (); \
+ INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
+ if (tree) { \
+ addr -= tree->start; \
+ if (addr >= tree->size) { \
+ addr = (size_t)p; \
+ tree = splay (addr, tree); \
+ addr -= tree->start; \
+ } \
+ if (addr >= tree->size) { \
+ addr = (size_t)p; \
+ tree = splay_end (addr, tree); \
+ addr -= tree->start; \
+ } \
+ if (addr <= tree->size) { \
+ if (tree->is_invalid || addr + offset + dsize > tree->size) { \
+ POST_SEM (); \
+ bound_warning("%p is outside of the region", p + offset); \
+ if (never_fatal <= 0) \
+ return INVALID_POINTER; /* return an invalid pointer */ \
+ return p + offset; \
+ } \
+ } \
+ else { \
+ INCR_COUNT(bound_not_found); \
+ POST_SEM (); \
+ bound_not_found_warning (__FILE__, __FUNCTION__, p); \
+ return p + offset; \
+ } \
+ } \
+ POST_SEM (); \
+ return p + offset; \
+}
+
+BOUND_PTR_INDIR(1)
+BOUND_PTR_INDIR(2)
+BOUND_PTR_INDIR(4)
+BOUND_PTR_INDIR(8)
+BOUND_PTR_INDIR(12)
+BOUND_PTR_INDIR(16)
+
+/* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */
+#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
+/*
+ * At least gcc 6.2 complains when __builtin_frame_address is used with
+ * nonzero argument.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-address"
+#endif
+
+/* return the frame pointer of the caller */
+#define GET_CALLER_FP(fp)\
+{\
+ fp = (size_t)__builtin_frame_address(1);\
+}
+
+/* called when entering a function to add all the local regions */
+void FASTCALL __bound_local_new(void *p1)
+{
+ size_t addr, fp, *p = p1;
+
+ if (NO_CHECKING_GET())
+ return;
+ GET_CALLER_FP(fp);
+ dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
+ __FILE__, __FUNCTION__, p, (void *)fp);
+ WAIT_SEM ();
+ while ((addr = p[0])) {
+ INCR_COUNT(bound_local_new_count);
+ tree = splay_insert(addr + fp, p[1], tree);
+ p += 2;
+ }
+ POST_SEM ();
+#if BOUND_DEBUG
+ if (print_calls) {
+ p = p1;
+ while ((addr = p[0])) {
+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
+ __FILE__, __FUNCTION__,
+ (void *) (addr + fp), (unsigned long) p[1]);
+ p += 2;
+ }
+ }
+#endif
+}
+
+/* called when leaving a function to delete all the local regions */
+void FASTCALL __bound_local_delete(void *p1)
+{
+ size_t addr, fp, *p = p1;
+
+ if (NO_CHECKING_GET())
+ return;
+ GET_CALLER_FP(fp);
+ dprintf(stderr, "%s, %s(): p1=%p fp=%p\n",
+ __FILE__, __FUNCTION__, p, (void *)fp);
+ WAIT_SEM ();
+ while ((addr = p[0])) {
+ INCR_COUNT(bound_local_delete_count);
+ tree = splay_delete(addr + fp, tree);
+ p += 2;
+ }
+ if (alloca_list) {
+ alloca_list_type *last = NULL;
+ alloca_list_type *cur = alloca_list;
+
+ do {
+ if (cur->fp == fp) {
+ if (last)
+ last->next = cur->next;
+ else
+ alloca_list = cur->next;
+ tree = splay_delete ((size_t) cur->p, tree);
+ dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
+ __FILE__, __FUNCTION__, cur->p);
+ BOUND_FREE (cur);
+ cur = last ? last->next : alloca_list;
+ }
+ else {
+ last = cur;
+ cur = cur->next;
+ }
+ } while (cur);
+ }
+ if (jmp_list) {
+ jmp_list_type *last = NULL;
+ jmp_list_type *cur = jmp_list;
+
+ do {
+ if (cur->fp == fp) {
+ if (last)
+ last->next = cur->next;
+ else
+ jmp_list = cur->next;
+ dprintf(stderr, "%s, %s(): remove setjmp %p\n",
+ __FILE__, __FUNCTION__, cur->penv);
+ BOUND_FREE (cur);
+ cur = last ? last->next : jmp_list;
+ }
+ else {
+ last = cur;
+ cur = cur->next;
+ }
+ } while (cur);
+ }
+
+ POST_SEM ();
+#if BOUND_DEBUG
+ if (print_calls) {
+ p = p1;
+ while ((addr = p[0])) {
+ if (addr != 1) {
+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
+ __FILE__, __FUNCTION__,
+ (void *) (addr + fp), (unsigned long) p[1]);
+ }
+ p+= 2;
+ }
+ }
+#endif
+}
+
+/* used by alloca */
+void __bound_new_region(void *p, size_t size)
+{
+ size_t fp;
+ alloca_list_type *last;
+ alloca_list_type *cur;
+ alloca_list_type *new;
+
+ if (NO_CHECKING_GET())
+ return;
+
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, p, (unsigned long)size);
+ GET_CALLER_FP (fp);
+ new = BOUND_MALLOC (sizeof (alloca_list_type));
+ WAIT_SEM ();
+ INCR_COUNT(bound_alloca_count);
+ last = NULL;
+ cur = alloca_list;
+ while (cur) {
+#if defined(__i386__) || (defined(__arm__) && !defined(__ARM_EABI__))
+ int align = 4;
+#elif defined(__arm__)
+ int align = 8;
+#else
+ int align = 16;
+#endif
+ void *cure = (void *)((char *)cur->p + ((cur->size + align) & -align));
+ void *pe = (void *)((char *)p + ((size + align) & -align));
+ if (cur->fp == fp && ((cur->p <= p && cure > p) ||
+ (p <= cur->p && pe > cur->p))) {
+ if (last)
+ last->next = cur->next;
+ else
+ alloca_list = cur->next;
+ tree = splay_delete((size_t)cur->p, tree);
+ break;
+ }
+ last = cur;
+ cur = cur->next;
+ }
+ tree = splay_insert((size_t)p, size, tree);
+ if (new) {
+ new->fp = fp;
+ new->p = p;
+ new->size = size;
+ new->next = alloca_list;
+ alloca_list = new;
+ }
+ POST_SEM ();
+ if (cur) {
+ dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
+ __FILE__, __FUNCTION__, cur->p);
+ BOUND_FREE (cur);
+ }
+}
+
+void __bound_setjmp(jmp_buf env)
+{
+ jmp_list_type *jl;
+ void *e = (void *) env;
+
+ if (NO_CHECKING_GET() == 0) {
+ dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e);
+ WAIT_SEM ();
+ INCR_COUNT(bound_setjmp_count);
+ jl = jmp_list;
+ while (jl) {
+ if (jl->penv == e)
+ break;
+ jl = jl->next;
+ }
+ if (jl == NULL) {
+ jl = BOUND_MALLOC (sizeof (jmp_list_type));
+ if (jl) {
+ jl->penv = e;
+ jl->next = jmp_list;
+ jmp_list = jl;
+ }
+ }
+ if (jl) {
+ size_t fp;
+
+ GET_CALLER_FP (fp);
+ jl->fp = fp;
+ jl->end_fp = (size_t)__builtin_frame_address(0);
+ BOUND_GET_TID(jl->tid);
+ }
+ POST_SEM ();
+ }
+}
+
+static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func)
+{
+ jmp_list_type *jl;
+ void *e;
+ BOUND_TID_TYPE tid;
+
+ if (NO_CHECKING_GET() == 0) {
+ e = (void *)env;
+ BOUND_GET_TID(tid);
+ dprintf(stderr, "%s, %s(): %p\n", __FILE__, func, e);
+ WAIT_SEM();
+ INCR_COUNT(bound_longjmp_count);
+ jl = jmp_list;
+ while (jl) {
+ if (jl->penv == e && jl->tid == tid) {
+ size_t start_fp = (size_t)__builtin_frame_address(0);
+ size_t end_fp = jl->end_fp;
+ jmp_list_type *cur = jmp_list;
+ jmp_list_type *last = NULL;
+
+ while (cur->penv != e || cur->tid != tid) {
+ if (cur->tid == tid) {
+ dprintf(stderr, "%s, %s(): remove setjmp %p\n",
+ __FILE__, func, cur->penv);
+ if (last)
+ last->next = cur->next;
+ else
+ jmp_list = cur->next;
+ BOUND_FREE (cur);
+ cur = last ? last->next : jmp_list;
+ }
+ else {
+ last = cur;
+ cur = cur->next;
+ }
+ }
+ for (;;) {
+ Tree *t = tree;
+ alloca_list_type *last;
+ alloca_list_type *cur;
+
+ while (t && (t->start < start_fp || t->start > end_fp))
+ if (t->start < start_fp)
+ t = t->right;
+ else
+ t = t->left;
+ if (t == NULL)
+ break;
+ last = NULL;
+ cur = alloca_list;
+ while (cur) {
+ if ((size_t) cur->p == t->start) {
+ dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
+ __FILE__, func, cur->p);
+ if (last)
+ last->next = cur->next;
+ else
+ alloca_list = cur->next;
+ BOUND_FREE (cur);
+ break;
+ }
+ last = cur;
+ cur = cur->next;
+ }
+ dprintf(stderr, "%s, %s(): delete %p\n",
+ __FILE__, func, (void *) t->start);
+ tree = splay_delete(t->start, tree);
+ }
+ break;
+ }
+ jl = jl->next;
+ }
+ POST_SEM();
+ }
+#if !defined(_WIN32)
+ sig ? siglongjmp(env, val) :
+#endif
+ longjmp (env, val);
+}
+
+void __bound_longjmp(jmp_buf env, int val)
+{
+ __bound_long_jump(env,val, 0, __FUNCTION__);
+}
+
+#if !defined(_WIN32)
+void __bound_siglongjmp(jmp_buf env, int val)
+{
+ __bound_long_jump(env,val, 1, __FUNCTION__);
+}
+#endif
+
+#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+void __bound_init(size_t *p, int mode)
+{
+ dprintf(stderr, "%s, %s(): start %s\n", __FILE__, __FUNCTION__,
+ mode < 0 ? "lazy" : mode == 0 ? "normal use" : "for -run");
+
+ if (inited) {
+ WAIT_SEM();
+ goto add_bounds;
+ }
+ inited = 1;
+
+#if HAVE_TLS_FUNC
+#if defined(_WIN32)
+ no_checking_key = TlsAlloc();
+ TlsSetValue(no_checking_key, &no_checking);
+#else
+ pthread_key_create(&no_checking_key, NULL);
+ pthread_setspecific(no_checking_key, &no_checking);
+#endif
+#endif
+ NO_CHECKING_SET(1);
+
+ print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
+ print_calls = getenv ("TCC_BOUNDS_PRINT_CALLS") != NULL;
+ print_heap = getenv ("TCC_BOUNDS_PRINT_HEAP") != NULL;
+ print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
+ never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
+
+ INIT_SEM ();
+
+#if MALLOC_REDIR
+ {
+ void *addr = mode > 0 ? RTLD_DEFAULT : RTLD_NEXT;
+
+ /* tcc -run required RTLD_DEFAULT. Normal usage requires RTLD_NEXT,
+ but using RTLD_NEXT with -run segfaults on MacOS in dyld as the
+ generated code segment isn't registered with dyld and hence the
+ caller image of dlsym isn't known to it */
+ *(void **) (&malloc_redir) = dlsym (addr, "malloc");
+ if (malloc_redir == NULL) {
+ dprintf(stderr, "%s, %s(): use RTLD_DEFAULT\n",
+ __FILE__, __FUNCTION__);
+ addr = RTLD_DEFAULT;
+ *(void **) (&malloc_redir) = dlsym (addr, "malloc");
+ }
+ *(void **) (&calloc_redir) = dlsym (addr, "calloc");
+ *(void **) (&free_redir) = dlsym (addr, "free");
+ *(void **) (&realloc_redir) = dlsym (addr, "realloc");
+ *(void **) (&memalign_redir) = dlsym (addr, "memalign");
+ dprintf(stderr, "%s, %s(): malloc_redir %p\n",
+ __FILE__, __FUNCTION__, malloc_redir);
+ dprintf(stderr, "%s, %s(): free_redir %p\n",
+ __FILE__, __FUNCTION__, free_redir);
+ dprintf(stderr, "%s, %s(): realloc_redir %p\n",
+ __FILE__, __FUNCTION__, realloc_redir);
+ dprintf(stderr, "%s, %s(): memalign_redir %p\n",
+ __FILE__, __FUNCTION__, memalign_redir);
+ if (malloc_redir == NULL || free_redir == NULL)
+ bound_alloc_error ("Cannot redirect malloc/free");
+#if HAVE_PTHREAD_CREATE
+ *(void **) (&pthread_create_redir) = dlsym (addr, "pthread_create");
+ dprintf(stderr, "%s, %s(): pthread_create_redir %p\n",
+ __FILE__, __FUNCTION__, pthread_create_redir);
+ if (pthread_create_redir == NULL)
+ bound_alloc_error ("Cannot redirect pthread_create");
+#endif
+#if HAVE_SIGNAL
+ *(void **) (&signal_redir) = dlsym (addr, "signal");
+ dprintf(stderr, "%s, %s(): signal_redir %p\n",
+ __FILE__, __FUNCTION__, signal_redir);
+ if (signal_redir == NULL)
+ bound_alloc_error ("Cannot redirect signal");
+#endif
+#if HAVE_SIGACTION
+ *(void **) (&sigaction_redir) = dlsym (addr, "sigaction");
+ dprintf(stderr, "%s, %s(): sigaction_redir %p\n",
+ __FILE__, __FUNCTION__, sigaction_redir);
+ if (sigaction_redir == NULL)
+ bound_alloc_error ("Cannot redirect sigaction");
+#endif
+#if HAVE_FORK
+ *(void **) (&fork_redir) = dlsym (addr, "fork");
+ dprintf(stderr, "%s, %s(): fork_redir %p\n",
+ __FILE__, __FUNCTION__, fork_redir);
+ if (fork_redir == NULL)
+ bound_alloc_error ("Cannot redirect fork");
+#endif
+ }
+#endif
+
+#ifdef __linux__
+ {
+ FILE *fp;
+ unsigned char found;
+ unsigned long start;
+ unsigned long end;
+ unsigned long ad =
+ (unsigned long) __builtin_return_address(0);
+ char line[1000];
+
+ /* Display exec name. Usefull when a lot of code is compiled with tcc */
+ fp = fopen ("/proc/self/comm", "r");
+ if (fp) {
+ memset (exec, 0, sizeof(exec));
+ fread (exec, 1, sizeof(exec) - 2, fp);
+ if (strchr(exec,'\n'))
+ *strchr(exec,'\n') = '\0';
+ strcat (exec, ":");
+ fclose (fp);
+ }
+ /* check if dlopen is used (is threre a better way?) */
+ found = 0;
+ fp = fopen ("/proc/self/maps", "r");
+ if (fp) {
+ while (fgets (line, sizeof(line), fp)) {
+ if (sscanf (line, "%lx-%lx", &start, &end) == 2 &&
+ ad >= start && ad < end) {
+ found = 1;
+ break;
+ }
+ if (strstr (line,"[heap]"))
+ break;
+ }
+ fclose (fp);
+ }
+ if (found == 0) {
+ use_sem = 1;
+ no_strdup = 1;
+ }
+ }
+#endif
+
+ WAIT_SEM ();
+
+#if HAVE_CTYPE
+#ifdef __APPLE__
+ tree = splay_insert((size_t) &_DefaultRuneLocale,
+ sizeof (_DefaultRuneLocale), tree);
+#else
+ /* XXX: Does not work if locale is changed */
+ tree = splay_insert((size_t) __ctype_b_loc(),
+ sizeof (unsigned short *), tree);
+ tree = splay_insert((size_t) (*__ctype_b_loc() - 128),
+ 384 * sizeof (unsigned short), tree);
+ tree = splay_insert((size_t) __ctype_tolower_loc(),
+ sizeof (__int32_t *), tree);
+ tree = splay_insert((size_t) (*__ctype_tolower_loc() - 128),
+ 384 * sizeof (__int32_t), tree);
+ tree = splay_insert((size_t) __ctype_toupper_loc(),
+ sizeof (__int32_t *), tree);
+ tree = splay_insert((size_t) (*__ctype_toupper_loc() - 128),
+ 384 * sizeof (__int32_t), tree);
+#endif
+#endif
+#if HAVE_ERRNO
+ tree = splay_insert((size_t) (&errno), sizeof (int), tree);
+#endif
+
+add_bounds:
+ if (!p)
+ goto no_bounds;
+
+ /* add all static bound check values */
+ while (p[0] != 0) {
+ tree = splay_insert(p[0], p[1], tree);
+#if BOUND_DEBUG
+ if (print_calls) {
+ dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
+ __FILE__, __FUNCTION__,
+ (void *) p[0], (unsigned long) p[1]);
+ }
+#endif
+ p += 2;
+ }
+no_bounds:
+
+ POST_SEM ();
+ NO_CHECKING_SET(0);
+ dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
+}
+
+void
+#if (defined(__GLIBC__) && (__GLIBC_MINOR__ >= 4)) || defined(_WIN32)
+__attribute__((constructor))
+#endif
+__bound_main_arg(int argc, char **argv, char **envp)
+{
+ __bound_init (0, -1);
+ if (argc && argv) {
+ int i;
+
+ WAIT_SEM ();
+ for (i = 0; i < argc; i++)
+ tree = splay_insert((size_t) argv[i], strlen (argv[i]) + 1, tree);
+ tree = splay_insert((size_t) argv, (argc + 1) * sizeof(char *), tree);
+ POST_SEM ();
+#if BOUND_DEBUG
+ if (print_calls) {
+ for (i = 0; i < argc; i++)
+ dprintf(stderr, "%s, %s(): arg %p 0x%lx\n",
+ __FILE__, __FUNCTION__,
+ argv[i], (unsigned long)(strlen (argv[i]) + 1));
+ dprintf(stderr, "%s, %s(): argv %p %d\n",
+ __FILE__, __FUNCTION__, argv,
+ (int)((argc + 1) * sizeof(char *)));
+ }
+#endif
+ }
+
+ if (envp && *envp) {
+ char **p = envp;
+
+ WAIT_SEM ();
+ while (*p) {
+ tree = splay_insert((size_t) *p, strlen (*p) + 1, tree);
+ ++p;
+ }
+ tree = splay_insert((size_t) envp, (++p - envp) * sizeof(char *), tree);
+ POST_SEM ();
+#if BOUND_DEBUG
+ if (print_calls) {
+ p = envp;
+ while (*p) {
+ dprintf(stderr, "%s, %s(): env %p 0x%lx\n",
+ __FILE__, __FUNCTION__,
+ *p, (unsigned long)(strlen (*p) + 1));
+ ++p;
+ }
+ dprintf(stderr, "%s, %s(): environ %p %d\n",
+ __FILE__, __FUNCTION__, envp,
+ (int)((++p - envp) * sizeof(char *)));
+ }
+#endif
+ }
+}
+
+void __attribute__((destructor)) __bound_exit(void)
+{
+ int i;
+ static const char * const alloc_type[] = {
+ "", "malloc", "calloc", "realloc", "memalign", "strdup"
+ };
+
+ dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__);
+
+ if (inited) {
+#if !defined(_WIN32) && !defined(__APPLE__) && !defined TCC_MUSL && \
+ !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
+ !defined(__ANDROID__)
+ if (print_heap) {
+ extern void __libc_freeres (void);
+ __libc_freeres ();
+ }
+#endif
+
+ NO_CHECKING_SET(1);
+
+ TRY_SEM ();
+ while (alloca_list) {
+ alloca_list_type *next = alloca_list->next;
+
+ tree = splay_delete ((size_t) alloca_list->p, tree);
+ BOUND_FREE (alloca_list);
+ alloca_list = next;
+ }
+ while (jmp_list) {
+ jmp_list_type *next = jmp_list->next;
+
+ BOUND_FREE (jmp_list);
+ jmp_list = next;
+ }
+ for (i = 0; i < FREE_REUSE_SIZE; i++) {
+ if (free_reuse_list[i]) {
+ tree = splay_delete ((size_t) free_reuse_list[i], tree);
+ BOUND_FREE (free_reuse_list[i]);
+ }
+ }
+ while (tree) {
+ if (print_heap && tree->type != 0)
+ fprintf (stderr, "%s, %s(): %s found size %lu\n",
+ __FILE__, __FUNCTION__, alloc_type[tree->type],
+ (unsigned long) tree->size);
+ tree = splay_delete (tree->start, tree);
+ }
+#if TREE_REUSE
+ while (tree_free_list) {
+ Tree *next = tree_free_list->left;
+ BOUND_FREE (tree_free_list);
+ tree_free_list = next;
+ }
+#endif
+ POST_SEM ();
+ EXIT_SEM ();
+#if HAVE_TLS_FUNC
+#if defined(_WIN32)
+ TlsFree(no_checking_key);
+#else
+ pthread_key_delete(no_checking_key);
+#endif
+#endif
+ inited = 0;
+ if (print_statistic) {
+#if BOUND_STATISTIC
+ fprintf (stderr, "bound_ptr_add_count %llu\n", bound_ptr_add_count);
+ fprintf (stderr, "bound_ptr_indir1_count %llu\n", bound_ptr_indir1_count);
+ fprintf (stderr, "bound_ptr_indir2_count %llu\n", bound_ptr_indir2_count);
+ fprintf (stderr, "bound_ptr_indir4_count %llu\n", bound_ptr_indir4_count);
+ fprintf (stderr, "bound_ptr_indir8_count %llu\n", bound_ptr_indir8_count);
+ fprintf (stderr, "bound_ptr_indir12_count %llu\n", bound_ptr_indir12_count);
+ fprintf (stderr, "bound_ptr_indir16_count %llu\n", bound_ptr_indir16_count);
+ fprintf (stderr, "bound_local_new_count %llu\n", bound_local_new_count);
+ fprintf (stderr, "bound_local_delete_count %llu\n", bound_local_delete_count);
+ fprintf (stderr, "bound_malloc_count %llu\n", bound_malloc_count);
+ fprintf (stderr, "bound_calloc_count %llu\n", bound_calloc_count);
+ fprintf (stderr, "bound_realloc_count %llu\n", bound_realloc_count);
+ fprintf (stderr, "bound_free_count %llu\n", bound_free_count);
+ fprintf (stderr, "bound_memalign_count %llu\n", bound_memalign_count);
+ fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count);
+ fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count);
+ fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count);
+ fprintf (stderr, "bound_setjmp_count %llu\n", bound_setjmp_count);
+ fprintf (stderr, "bound_longjmp_count %llu\n", bound_longjmp_count);
+ fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count);
+ fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count);
+ fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count);
+ fprintf (stderr, "bound_memset_count %llu\n", bound_memset_count);
+ fprintf (stderr, "bound_strlen_count %llu\n", bound_strlen_count);
+ fprintf (stderr, "bound_strcpy_count %llu\n", bound_strcpy_count);
+ fprintf (stderr, "bound_strncpy_count %llu\n", bound_strncpy_count);
+ fprintf (stderr, "bound_strcmp_count %llu\n", bound_strcmp_count);
+ fprintf (stderr, "bound_strncmp_count %llu\n", bound_strncmp_count);
+ fprintf (stderr, "bound_strcat_count %llu\n", bound_strcat_count);
+ fprintf (stderr, "bound_strncat_count %llu\n", bound_strncat_count);
+ fprintf (stderr, "bound_strchr_count %llu\n", bound_strchr_count);
+ fprintf (stderr, "bound_strrchr_count %llu\n", bound_strrchr_count);
+ fprintf (stderr, "bound_strdup_count %llu\n", bound_strdup_count);
+ fprintf (stderr, "bound_not_found %llu\n", bound_not_found);
+#endif
+#if BOUND_STATISTIC_SPLAY
+ fprintf (stderr, "bound_splay %llu\n", bound_splay);
+ fprintf (stderr, "bound_splay_end %llu\n", bound_splay_end);
+ fprintf (stderr, "bound_splay_insert %llu\n", bound_splay_insert);
+ fprintf (stderr, "bound_splay_delete %llu\n", bound_splay_delete);
+#endif
+ }
+ }
+}
+
+void __bound_exit_dll(size_t *p)
+{
+ dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
+
+ if (p) {
+ WAIT_SEM ();
+ while (p[0] != 0) {
+ tree = splay_delete(p[0], tree);
+#if BOUND_DEBUG
+ if (print_calls) {
+ dprintf(stderr, "%s, %s(): remove static var %p 0x%lx\n",
+ __FILE__, __FUNCTION__,
+ (void *) p[0], (unsigned long) p[1]);
+ }
+#endif
+ p += 2;
+ }
+ POST_SEM ();
+ }
+}
+
+#if HAVE_PTHREAD_CREATE
+typedef struct {
+ void *(*start_routine) (void *);
+ void *arg;
+ sigset_t old_mask;
+} bound_thread_create_type;
+
+static void *bound_thread_create(void *bdata)
+{
+ bound_thread_create_type *data = (bound_thread_create_type *) bdata;
+ void *retval;
+#if HAVE_TLS_FUNC
+ int *p = (int *) BOUND_MALLOC(sizeof(int));
+
+ if (!p) bound_alloc_error("bound_thread_create malloc");
+ *p = 0;
+ pthread_setspecific(no_checking_key, p);
+#endif
+ pthread_sigmask(SIG_SETMASK, &data->old_mask, NULL);
+ retval = data->start_routine(data->arg);
+#if HAVE_TLS_FUNC
+ pthread_setspecific(no_checking_key, NULL);
+ BOUND_FREE (p);
+#endif
+ BOUND_FREE (data);
+ return retval;
+}
+
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg)
+{
+ int retval;
+ bound_thread_create_type *data;
+ sigset_t mask;
+ sigset_t old_mask;
+
+ use_sem = 1;
+ dprintf (stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
+ sigfillset(&mask);
+ pthread_sigmask(SIG_SETMASK, &mask, &old_mask);
+ data = (bound_thread_create_type *) BOUND_MALLOC(sizeof(bound_thread_create_type));
+ if (!data) bound_alloc_error("bound_thread_create malloc");
+ data->start_routine = start_routine;
+ data->arg = arg;
+ data->old_mask = old_mask;
+ retval = pthread_create_redir(thread, attr, bound_thread_create, data);
+ pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+ return retval;
+}
+#endif
+
+#if HAVE_SIGNAL || HAVE_SIGACTION
+typedef union {
+#if HAVE_SIGNAL
+ bound_sig signal_handler;
+#endif
+#if HAVE_SIGACTION
+ void (*sig_handler)(int);
+ void (*sig_sigaction)(int, siginfo_t *, void *);
+#endif
+} bound_sig_type;
+
+static unsigned char bound_sig_used[NSIG];
+static bound_sig_type bound_sig_data[NSIG];
+#endif
+
+#if HAVE_SIGNAL
+static void signal_handler(int sig)
+{
+ __bounds_checking(1);
+ bound_sig_data[sig].signal_handler(sig);
+ __bounds_checking(-1);
+}
+
+bound_sig signal(int signum, bound_sig handler)
+{
+ bound_sig retval;
+
+ dprintf (stderr, "%s, %s() %d %p\n", __FILE__, __FUNCTION__,
+ signum, handler);
+ retval = signal_redir(signum, handler ? signal_handler : handler);
+ if (retval != SIG_ERR) {
+ if (bound_sig_used[signum])
+ retval = bound_sig_data[signum].signal_handler;
+ if (handler) {
+ bound_sig_used[signum] = 1;
+ bound_sig_data[signum].signal_handler = handler;
+ }
+ }
+ return retval;
+}
+#endif
+
+#if HAVE_SIGACTION
+static void sig_handler(int sig)
+{
+ __bounds_checking(1);
+ bound_sig_data[sig].sig_handler(sig);
+ __bounds_checking(-1);
+}
+
+static void sig_sigaction(int sig, siginfo_t *info, void *ucontext)
+{
+ __bounds_checking(1);
+ bound_sig_data[sig].sig_sigaction(sig, info, ucontext);
+ __bounds_checking(-1);
+}
+
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+ int retval;
+ struct sigaction nact, oact;
+
+ dprintf (stderr, "%s, %s() %d %p %p\n", __FILE__, __FUNCTION__,
+ signum, act, oldact);
+
+ if (sigaction_redir == NULL)
+ __bound_init(0,-1);
+
+ if (act) {
+ nact = *act;
+ if (nact.sa_flags & SA_SIGINFO)
+ nact.sa_sigaction = sig_sigaction;
+ else
+ nact.sa_handler = sig_handler;
+ retval = sigaction_redir(signum, &nact, &oact);
+ }
+ else
+ retval = sigaction_redir(signum, act, &oact);
+ if (retval >= 0) {
+ if (bound_sig_used[signum]) {
+ if (oact.sa_flags & SA_SIGINFO)
+ oact.sa_sigaction = bound_sig_data[signum].sig_sigaction;
+ else
+ oact.sa_handler = bound_sig_data[signum].sig_handler;
+ }
+ if (oldact) {
+ *oldact = oact;
+ }
+ if (act) {
+ bound_sig_used[signum] = 1;
+ if (act->sa_flags & SA_SIGINFO)
+ bound_sig_data[signum].sig_sigaction = act->sa_sigaction;
+ else
+ bound_sig_data[signum].sig_handler = act->sa_handler;
+ }
+ }
+ return retval;
+}
+#endif
+
+#if HAVE_FORK
+pid_t fork(void)
+{
+ pid_t retval;
+
+ WAIT_SEM();
+ retval = (*fork_redir)();
+ if (retval == 0)
+ INIT_SEM();
+ else
+ POST_SEM();
+ return retval;
+}
+#endif
+
+#if MALLOC_REDIR
+void *malloc(size_t size)
+#else
+void *__bound_malloc(size_t size, const void *caller)
+#endif
+{
+ void *ptr;
+
+#if MALLOC_REDIR
+ /* This will catch the first dlsym call from __bound_init */
+ if (malloc_redir == NULL) {
+ __bound_init (0, -1);
+ if (malloc_redir == NULL) {
+ ptr = &initial_pool[pool_index];
+ pool_index = (pool_index + size + 15) & ~15;
+ if (pool_index >= sizeof (initial_pool))
+ bound_alloc_error ("initial memory pool too small");
+ dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
+ return ptr;
+ }
+ }
+#endif
+ /* we allocate one more byte to ensure the regions will be
+ separated by at least one byte. With the glibc malloc, it may
+ be in fact not necessary */
+ ptr = BOUND_MALLOC (size + 1);
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
+
+ if (inited && NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_malloc_count);
+
+ if (ptr) {
+ tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
+ if (tree && tree->start == (size_t) ptr)
+ tree->type = TCC_TYPE_MALLOC;
+ }
+ POST_SEM ();
+ }
+ return ptr;
+}
+
+#if MALLOC_REDIR
+void *memalign(size_t size, size_t align)
+#else
+void *__bound_memalign(size_t size, size_t align, const void *caller)
+#endif
+{
+ void *ptr;
+
+#if HAVE_MEMALIGN
+ /* we allocate one more byte to ensure the regions will be
+ separated by at least one byte. With the glibc malloc, it may
+ be in fact not necessary */
+ ptr = BOUND_MEMALIGN(size + 1, align);
+#else
+ if (align > 4) {
+ /* XXX: handle it ? */
+ ptr = NULL;
+ } else {
+ /* we suppose that malloc aligns to at least four bytes */
+ ptr = BOUND_MALLOC(size + 1);
+ }
+#endif
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
+
+ if (NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_memalign_count);
+
+ if (ptr) {
+ tree = splay_insert((size_t) ptr, size ? size : size + 1, tree);
+ if (tree && tree->start == (size_t) ptr)
+ tree->type = TCC_TYPE_MEMALIGN;
+ }
+ POST_SEM ();
+ }
+ return ptr;
+}
+
+#if MALLOC_REDIR
+void free(void *ptr)
+#else
+void __bound_free(void *ptr, const void *caller)
+#endif
+{
+ size_t addr = (size_t) ptr;
+ void *p;
+
+ if (ptr == NULL || tree == NULL
+#if MALLOC_REDIR
+ || ((unsigned char *) ptr >= &initial_pool[0] &&
+ (unsigned char *) ptr < &initial_pool[sizeof(initial_pool)])
+#endif
+ )
+ return;
+
+ dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr);
+
+ if (inited && NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_free_count);
+ tree = splay (addr, tree);
+ if (tree->start == addr) {
+ if (tree->is_invalid) {
+ POST_SEM ();
+ bound_error("freeing invalid region");
+ return;
+ }
+ tree->is_invalid = 1;
+ memset (ptr, 0x5a, tree->size);
+ p = free_reuse_list[free_reuse_index];
+ free_reuse_list[free_reuse_index] = ptr;
+ free_reuse_index = (free_reuse_index + 1) % FREE_REUSE_SIZE;
+ if (p)
+ tree = splay_delete((size_t)p, tree);
+ ptr = p;
+ }
+ POST_SEM ();
+ }
+ BOUND_FREE (ptr);
+}
+
+#if MALLOC_REDIR
+void *realloc(void *ptr, size_t size)
+#else
+void *__bound_realloc(void *ptr, size_t size, const void *caller)
+#endif
+{
+ void *new_ptr;
+
+ if (size == 0) {
+#if MALLOC_REDIR
+ free(ptr);
+#else
+ __bound_free(ptr, caller);
+#endif
+ return NULL;
+ }
+
+ new_ptr = BOUND_REALLOC (ptr, size + 1);
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
+
+ if (NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_realloc_count);
+
+ if (ptr)
+ tree = splay_delete ((size_t) ptr, tree);
+ if (new_ptr) {
+ tree = splay_insert ((size_t) new_ptr, size ? size : size + 1, tree);
+ if (tree && tree->start == (size_t) new_ptr)
+ tree->type = TCC_TYPE_REALLOC;
+ }
+ POST_SEM ();
+ }
+ return new_ptr;
+}
+
+#if MALLOC_REDIR
+void *calloc(size_t nmemb, size_t size)
+#else
+void *__bound_calloc(size_t nmemb, size_t size)
+#endif
+{
+ void *ptr;
+
+ size *= nmemb;
+#if MALLOC_REDIR
+ /* This will catch the first dlsym call from __bound_init */
+ if (malloc_redir == NULL) {
+ __bound_init (0, -1);
+ if (malloc_redir == NULL) {
+ ptr = &initial_pool[pool_index];
+ pool_index = (pool_index + size + 15) & ~15;
+ if (pool_index >= sizeof (initial_pool))
+ bound_alloc_error ("initial memory pool too small");
+ dprintf (stderr, "%s, %s(): initial %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
+ memset (ptr, 0, size);
+ return ptr;
+ }
+ }
+#endif
+ ptr = BOUND_MALLOC(size + 1);
+ dprintf (stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
+
+ if (ptr) {
+ memset (ptr, 0, size);
+ if (NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_calloc_count);
+ tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
+ if (tree && tree->start == (size_t) ptr)
+ tree->type = TCC_TYPE_CALLOC;
+ POST_SEM ();
+ }
+ }
+ return ptr;
+}
+
+#if !defined(_WIN32)
+void *__bound_mmap (void *start, size_t size, int prot,
+ int flags, int fd, off_t offset)
+{
+ void *result;
+
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, start, (unsigned long)size);
+ result = mmap (start, size, prot, flags, fd, offset);
+ if (result && NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_mmap_count);
+ tree = splay_insert((size_t)result, size, tree);
+ POST_SEM ();
+ }
+ return result;
+}
+
+int __bound_munmap (void *start, size_t size)
+{
+ int result;
+
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, start, (unsigned long)size);
+ if (start && NO_CHECKING_GET() == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_munmap_count);
+ tree = splay_delete ((size_t) start, tree);
+ POST_SEM ();
+ }
+ result = munmap (start, size);
+ return result;
+}
+#endif
+
+/* some useful checked functions */
+
+/* check that (p ... p + size - 1) lies inside 'p' region, if any */
+static void __bound_check(const void *p, size_t size, const char *function)
+{
+ if (size != 0 && __bound_ptr_add((void *)p, size) == INVALID_POINTER) {
+ bound_error("invalid pointer %p, size 0x%lx in %s",
+ p, (unsigned long)size, function);
+ }
+}
+
+static int check_overlap (const void *p1, size_t n1,
+ const void *p2, size_t n2,
+ const char *function)
+{
+ const void *p1e = (const void *) ((const char *) p1 + n1);
+ const void *p2e = (const void *) ((const char *) p2 + n2);
+
+ if (NO_CHECKING_GET() == 0 && n1 != 0 && n2 !=0 &&
+ ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
+ (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
+ bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
+ p1, (unsigned long)n1, p2, (unsigned long)n2, function);
+ return never_fatal < 0;
+ }
+ return 0;
+}
+
+void *__bound_memcpy(void *dest, const void *src, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_mempcy_count);
+ __bound_check(dest, n, "memcpy dest");
+ __bound_check(src, n, "memcpy src");
+ if (check_overlap(dest, n, src, n, "memcpy"))
+ return dest;
+ return memcpy(dest, src, n);
+}
+
+int __bound_memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *u1 = (const unsigned char *) s1;
+ const unsigned char *u2 = (const unsigned char *) s2;
+ int retval = 0;
+
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
+ INCR_COUNT(bound_memcmp_count);
+ for (;;) {
+ if ((ssize_t) --n == -1)
+ break;
+ else if (*u1 != *u2) {
+ retval = *u1++ - *u2++;
+ break;
+ }
+ ++u1;
+ ++u2;
+ }
+ __bound_check(s1, (const void *)u1 - s1, "memcmp s1");
+ __bound_check(s2, (const void *)u2 - s2, "memcmp s2");
+ return retval;
+}
+
+void *__bound_memmove(void *dest, const void *src, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_memmove_count);
+ __bound_check(dest, n, "memmove dest");
+ __bound_check(src, n, "memmove src");
+ return memmove(dest, src, n);
+}
+
+void *__bound_memset(void *s, int c, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
+ __FILE__, __FUNCTION__, s, c, (unsigned long)n);
+ INCR_COUNT(bound_memset_count);
+ __bound_check(s, n, "memset");
+ return memset(s, c, n);
+}
+
+#if defined(__arm__) && defined(__ARM_EABI__)
+void *__bound___aeabi_memcpy(void *dest, const void *src, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_mempcy_count);
+ __bound_check(dest, n, "memcpy dest");
+ __bound_check(src, n, "memcpy src");
+ if (check_overlap(dest, n, src, n, "memcpy"))
+ return dest;
+ return __aeabi_memcpy(dest, src, n);
+}
+
+void *__bound___aeabi_memmove(void *dest, const void *src, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_memmove_count);
+ __bound_check(dest, n, "memmove dest");
+ __bound_check(src, n, "memmove src");
+ return __aeabi_memmove(dest, src, n);
+}
+
+void *__bound___aeabi_memmove4(void *dest, const void *src, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_memmove_count);
+ __bound_check(dest, n, "memmove dest");
+ __bound_check(src, n, "memmove src");
+ return __aeabi_memmove4(dest, src, n);
+}
+
+void *__bound___aeabi_memmove8(void *dest, const void *src, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_memmove_count);
+ __bound_check(dest, n, "memmove dest");
+ __bound_check(src, n, "memmove src");
+ return __aeabi_memmove8(dest, src, n);
+}
+
+void *__bound___aeabi_memset(void *s, int c, size_t n)
+{
+ dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
+ __FILE__, __FUNCTION__, s, c, (unsigned long)n);
+ INCR_COUNT(bound_memset_count);
+ __bound_check(s, n, "memset");
+ return __aeabi_memset(s, c, n);
+}
+#endif
+
+int __bound_strlen(const char *s)
+{
+ const char *p = s;
+
+ dprintf(stderr, "%s, %s(): %p\n",
+ __FILE__, __FUNCTION__, s);
+ INCR_COUNT(bound_strlen_count);
+ while (*p++);
+ __bound_check(s, p - s, "strlen");
+ return (p - s) - 1;
+}
+
+char *__bound_strcpy(char *dest, const char *src)
+{
+ size_t len;
+ const char *p = src;
+
+ dprintf(stderr, "%s, %s(): %p, %p\n",
+ __FILE__, __FUNCTION__, dest, src);
+ INCR_COUNT(bound_strcpy_count);
+ while (*p++);
+ len = p - src;
+ __bound_check(dest, len, "strcpy dest");
+ __bound_check(src, len, "strcpy src");
+ if (check_overlap(dest, len, src, len, "strcpy"))
+ return dest;
+ return strcpy (dest, src);
+}
+
+char *__bound_strncpy(char *dest, const char *src, size_t n)
+{
+ size_t len = n;
+ const char *p = src;
+
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_strncpy_count);
+ while (len-- && *p++);
+ len = p - src;
+ __bound_check(dest, len, "strncpy dest");
+ __bound_check(src, len, "strncpy src");
+ if (check_overlap(dest, len, src, len, "strncpy"))
+ return dest;
+ return strncpy(dest, src, n);
+}
+
+int __bound_strcmp(const char *s1, const char *s2)
+{
+ const unsigned char *u1 = (const unsigned char *) s1;
+ const unsigned char *u2 = (const unsigned char *) s2;
+
+ dprintf(stderr, "%s, %s(): %p, %p\n",
+ __FILE__, __FUNCTION__, s1, s2);
+ INCR_COUNT(bound_strcmp_count);
+ while (*u1 && *u1 == *u2) {
+ ++u1;
+ ++u2;
+ }
+ __bound_check(s1, ((const char *)u1 - s1) + 1, "strcmp s1");
+ __bound_check(s2, ((const char *)u2 - s2) + 1, "strcmp s2");
+ return *u1 - *u2;
+}
+
+int __bound_strncmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *u1 = (const unsigned char *) s1;
+ const unsigned char *u2 = (const unsigned char *) s2;
+ int retval = 0;
+
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, s1, s2, (unsigned long)n);
+ INCR_COUNT(bound_strncmp_count);
+ do {
+ if ((ssize_t) --n == -1)
+ break;
+ else if (*u1 != *u2) {
+ retval = *u1++ - *u2++;
+ break;
+ }
+ ++u2;
+ } while (*u1++);
+ __bound_check(s1, (const char *)u1 - s1, "strncmp s1");
+ __bound_check(s2, (const char *)u2 - s2, "strncmp s2");
+ return retval;
+}
+
+char *__bound_strcat(char *dest, const char *src)
+{
+ char *r = dest;
+ const char *s = src;
+
+ dprintf(stderr, "%s, %s(): %p, %p\n",
+ __FILE__, __FUNCTION__, dest, src);
+ INCR_COUNT(bound_strcat_count);
+ while (*dest++);
+ while (*src++);
+ __bound_check(r, (dest - r) + (src - s) - 1, "strcat dest");
+ __bound_check(s, src - s, "strcat src");
+ if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strcat"))
+ return dest;
+ return strcat(r, s);
+}
+
+char *__bound_strncat(char *dest, const char *src, size_t n)
+{
+ char *r = dest;
+ const char *s = src;
+ size_t len = n;
+
+ dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, dest, src, (unsigned long)n);
+ INCR_COUNT(bound_strncat_count);
+ while (*dest++);
+ while (len-- && *src++);
+ __bound_check(r, (dest - r) + (src - s) - 1, "strncat dest");
+ __bound_check(s, src - s, "strncat src");
+ if (check_overlap(r, (dest - r) + (src - s) - 1, s, src - s, "strncat"))
+ return dest;
+ return strncat(r, s, n);
+}
+
+char *__bound_strchr(const char *s, int c)
+{
+ const unsigned char *str = (const unsigned char *) s;
+ unsigned char ch = c;
+
+ dprintf(stderr, "%s, %s(): %p, %d\n",
+ __FILE__, __FUNCTION__, s, ch);
+ INCR_COUNT(bound_strchr_count);
+ while (*str) {
+ if (*str == ch)
+ break;
+ ++str;
+ }
+ __bound_check(s, ((const char *)str - s) + 1, "strchr");
+ return *str == ch ? (char *) str : NULL;
+}
+
+char *__bound_strrchr(const char *s, int c)
+{
+ const unsigned char *str = (const unsigned char *) s;
+ unsigned char ch = c;
+
+ dprintf(stderr, "%s, %s(): %p, %d\n",
+ __FILE__, __FUNCTION__, s, ch);
+ INCR_COUNT(bound_strrchr_count);
+ while (*str++);
+ __bound_check(s, (const char *)str - s, "strrchr");
+ while (str != (const unsigned char *)s) {
+ if (*--str == ch)
+ break;
+ }
+ __bound_check(s, (const char *)str - s, "strrchr");
+ return *str == ch ? (char *) str : NULL;
+}
+
+char *__bound_strdup(const char *s)
+{
+ const char *p = s;
+ char *new;
+
+ INCR_COUNT(bound_strdup_count);
+ while (*p++);
+ __bound_check(s, p - s, "strdup");
+ new = BOUND_MALLOC ((p - s) + 1);
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, new, (unsigned long)(p -s));
+ if (new) {
+ if (NO_CHECKING_GET() == 0 && no_strdup == 0) {
+ WAIT_SEM ();
+ tree = splay_insert((size_t)new, p - s, tree);
+ if (tree && tree->start == (size_t) new)
+ tree->type = TCC_TYPE_STRDUP;
+ POST_SEM ();
+ }
+ memcpy (new, s, p - s);
+ }
+ return new;
+}
+
+/*
+ An implementation of top-down splaying with sizes
+ D. Sleator <sleator@cs.cmu.edu>, January 1994.
+
+ This extends top-down-splay.c to maintain a size field in each node.
+ This is the number of nodes in the subtree rooted there. This makes
+ it possible to efficiently compute the rank of a key. (The rank is
+ the number of nodes to the left of the given key.) It it also
+ possible to quickly find the node of a given rank. Both of these
+ operations are illustrated in the code below. The remainder of this
+ introduction is taken from top-down-splay.c.
+
+ "Splay trees", or "self-adjusting search trees" are a simple and
+ efficient data structure for storing an ordered set. The data
+ structure consists of a binary tree, with no additional fields. It
+ allows searching, insertion, deletion, deletemin, deletemax,
+ splitting, joining, and many other operations, all with amortized
+ logarithmic performance. Since the trees adapt to the sequence of
+ requests, their performance on real access patterns is typically even
+ better. Splay trees are described in a number of texts and papers
+ [1,2,3,4].
+
+ The code here is adapted from simple top-down splay, at the bottom of
+ page 669 of [2]. It can be obtained via anonymous ftp from
+ spade.pc.cs.cmu.edu in directory /usr/sleator/public.
+
+ The chief modification here is that the splay operation works even if the
+ item being splayed is not in the tree, and even if the tree root of the
+ tree is NULL. So the line:
+
+ t = splay(i, t);
+
+ causes it to search for item with key i in the tree rooted at t. If it's
+ there, it is splayed to the root. If it isn't there, then the node put
+ at the root is the last one before NULL that would have been reached in a
+ normal binary search for i. (It's a neighbor of i in the tree.) This
+ allows many other operations to be easily implemented, as shown below.
+
+ [1] "Data Structures and Their Algorithms", Lewis and Denenberg,
+ Harper Collins, 1991, pp 243-251.
+ [2] "Self-adjusting Binary Search Trees" Sleator and Tarjan,
+ JACM Volume 32, No 3, July 1985, pp 652-686.
+ [3] "Data Structure and Algorithm Analysis", Mark Weiss,
+ Benjamin Cummins, 1992, pp 119-130.
+ [4] "Data Structures, Algorithms, and Performance", Derick Wood,
+ Addison-Wesley, 1993, pp 367-375
+*/
+
+/* Code adapted for tcc */
+
+#define compare(start,tstart,tsize) (start < tstart ? -1 : \
+ start >= tstart+tsize ? 1 : 0)
+
+static Tree * splay (size_t addr, Tree *t)
+/* Splay using the key start (which may or may not be in the tree.) */
+/* The starting root is t, and the tree used is defined by rat */
+{
+ Tree N, *l, *r, *y;
+ int comp;
+
+ INCR_COUNT_SPLAY(bound_splay);
+ if (t == NULL) return t;
+ N.left = N.right = NULL;
+ l = r = &N;
+
+ for (;;) {
+ comp = compare(addr, t->start, t->size);
+ if (comp < 0) {
+ y = t->left;
+ if (y == NULL) break;
+ if (compare(addr, y->start, y->size) < 0) {
+ t->left = y->right; /* rotate right */
+ y->right = t;
+ t = y;
+ if (t->left == NULL) break;
+ }
+ r->left = t; /* link right */
+ r = t;
+ t = t->left;
+ } else if (comp > 0) {
+ y = t->right;
+ if (y == NULL) break;
+ if (compare(addr, y->start, y->size) > 0) {
+ t->right = y->left; /* rotate left */
+ y->left = t;
+ t = y;
+ if (t->right == NULL) break;
+ }
+ l->right = t; /* link left */
+ l = t;
+ t = t->right;
+ } else {
+ break;
+ }
+ }
+ l->right = t->left; /* assemble */
+ r->left = t->right;
+ t->left = N.right;
+ t->right = N.left;
+
+ return t;
+}
+
+#define compare_end(start,tend) (start < tend ? -1 : \
+ start > tend ? 1 : 0)
+
+static Tree * splay_end (size_t addr, Tree *t)
+/* Splay using the key start (which may or may not be in the tree.) */
+/* The starting root is t, and the tree used is defined by rat */
+{
+ Tree N, *l, *r, *y;
+ int comp;
+
+ INCR_COUNT_SPLAY(bound_splay_end);
+ if (t == NULL) return t;
+ N.left = N.right = NULL;
+ l = r = &N;
+
+ for (;;) {
+ comp = compare_end(addr, t->start + t->size);
+ if (comp < 0) {
+ y = t->left;
+ if (y == NULL) break;
+ if (compare_end(addr, y->start + y->size) < 0) {
+ t->left = y->right; /* rotate right */
+ y->right = t;
+ t = y;
+ if (t->left == NULL) break;
+ }
+ r->left = t; /* link right */
+ r = t;
+ t = t->left;
+ } else if (comp > 0) {
+ y = t->right;
+ if (y == NULL) break;
+ if (compare_end(addr, y->start + y->size) > 0) {
+ t->right = y->left; /* rotate left */
+ y->left = t;
+ t = y;
+ if (t->right == NULL) break;
+ }
+ l->right = t; /* link left */
+ l = t;
+ t = t->right;
+ } else {
+ break;
+ }
+ }
+ l->right = t->left; /* assemble */
+ r->left = t->right;
+ t->left = N.right;
+ t->right = N.left;
+
+ return t;
+}
+
+static Tree * splay_insert(size_t addr, size_t size, Tree * t)
+/* Insert key start into the tree t, if it is not already there. */
+/* Return a pointer to the resulting tree. */
+{
+ Tree * new;
+
+ INCR_COUNT_SPLAY(bound_splay_insert);
+ if (t != NULL) {
+ t = splay(addr,t);
+ if (compare(addr, t->start, t->size)==0) {
+ return t; /* it's already there */
+ }
+ }
+#if TREE_REUSE
+ if (tree_free_list) {
+ new = tree_free_list;
+ tree_free_list = new->left;
+ }
+ else
+#endif
+ {
+ new = (Tree *) BOUND_MALLOC (sizeof (Tree));
+ }
+ if (new == NULL) {
+ bound_alloc_error("not enough memory for bound checking code");
+ }
+ else {
+ if (t == NULL) {
+ new->left = new->right = NULL;
+ } else if (compare(addr, t->start, t->size) < 0) {
+ new->left = t->left;
+ new->right = t;
+ t->left = NULL;
+ } else {
+ new->right = t->right;
+ new->left = t;
+ t->right = NULL;
+ }
+ new->start = addr;
+ new->size = size;
+ new->type = TCC_TYPE_NONE;
+ new->is_invalid = 0;
+ }
+ return new;
+}
+
+#define compare_destroy(start,tstart) (start < tstart ? -1 : \
+ start > tstart ? 1 : 0)
+
+static Tree * splay_delete(size_t addr, Tree *t)
+/* Deletes addr from the tree if it's there. */
+/* Return a pointer to the resulting tree. */
+{
+ Tree * x;
+
+ INCR_COUNT_SPLAY(bound_splay_delete);
+ if (t==NULL) return NULL;
+ t = splay(addr,t);
+ if (compare_destroy(addr, t->start) == 0) { /* found it */
+ if (t->left == NULL) {
+ x = t->right;
+ } else {
+ x = splay(addr, t->left);
+ x->right = t->right;
+ }
+#if TREE_REUSE
+ t->left = tree_free_list;
+ tree_free_list = t;
+#else
+ BOUND_FREE(t);
+#endif
+ return x;
+ } else {
+ return t; /* It wasn't there */
+ }
+}
+
+void splay_printtree(Tree * t, int d)
+{
+ int i;
+ if (t == NULL) return;
+ splay_printtree(t->right, d+1);
+ for (i=0; i<d; i++) fprintf(stderr," ");
+ fprintf(stderr,"%p(0x%lx:%u:%u)\n",
+ (void *) t->start, (unsigned long) t->size,
+ (unsigned)t->type, (unsigned)t->is_invalid);
+ splay_printtree(t->left, d+1);
+}
diff --git a/tinycc/lib/bt-dll.c b/tinycc/lib/bt-dll.c
new file mode 100644
index 0000000..7c62cef
--- /dev/null
+++ b/tinycc/lib/bt-dll.c
@@ -0,0 +1,74 @@
+/* ------------------------------------------------------------- */
+/* stubs for calling bcheck functions from a dll. */
+
+#include <windows.h>
+#include <stdio.h>
+
+#define REDIR_ALL \
+ REDIR(__bt_init) \
+ REDIR(__bt_exit) \
+ REDIR(tcc_backtrace) \
+ \
+ REDIR(__bound_ptr_add) \
+ REDIR(__bound_ptr_indir1) \
+ REDIR(__bound_ptr_indir2) \
+ REDIR(__bound_ptr_indir4) \
+ REDIR(__bound_ptr_indir8) \
+ REDIR(__bound_ptr_indir12) \
+ REDIR(__bound_ptr_indir16) \
+ REDIR(__bound_local_new) \
+ REDIR(__bound_local_delete) \
+ REDIR(__bound_new_region) \
+ \
+ REDIR(__bound_free) \
+ REDIR(__bound_malloc) \
+ REDIR(__bound_realloc) \
+ REDIR(__bound_memcpy) \
+ REDIR(__bound_memcmp) \
+ REDIR(__bound_memmove) \
+ REDIR(__bound_memset) \
+ REDIR(__bound_strlen) \
+ REDIR(__bound_strcpy) \
+ REDIR(__bound_strncpy) \
+ REDIR(__bound_strcmp) \
+ REDIR(__bound_strncmp) \
+ REDIR(__bound_strcat) \
+ REDIR(__bound_strchr) \
+ REDIR(__bound_strdup)
+
+#ifdef __leading_underscore
+#define _(s) "_"#s
+#else
+#define _(s) #s
+#endif
+
+#define REDIR(s) void *s;
+static struct { REDIR_ALL } all_ptrs;
+#undef REDIR
+#define REDIR(s) #s"\0"
+static const char all_names[] = REDIR_ALL;
+#undef REDIR
+#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) );
+static void all_jmps() { REDIR_ALL }
+#undef REDIR
+
+void __bt_init_dll(int bcheck)
+{
+ const char *s = all_names;
+ void **p = (void**)&all_ptrs;
+ do {
+ *p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
+ if (NULL == *p) {
+ char buf[100];
+ sprintf(buf,
+ "Error: function '%s()' not found in executable. "
+ "(Need -bt or -b for linking the exe.)", s);
+ if (GetStdHandle(STD_ERROR_HANDLE))
+ fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
+ else
+ MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
+ ExitProcess(1);
+ }
+ s = strchr(s,'\0') + 1, ++p;
+ } while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
+}
diff --git a/tinycc/lib/bt-exe.c b/tinycc/lib/bt-exe.c
new file mode 100644
index 0000000..3a2d02e
--- /dev/null
+++ b/tinycc/lib/bt-exe.c
@@ -0,0 +1,74 @@
+/* ------------------------------------------------------------- */
+/* for linking rt_printline and the signal/exception handler
+ from tccrun.c into executables. */
+
+#define CONFIG_TCC_BACKTRACE_ONLY
+#define ONE_SOURCE 1
+#define pstrcpy tcc_pstrcpy
+#include "../tccrun.c"
+
+int (*__rt_error)(void*, void*, const char *, va_list);
+__attribute__((weak)) void __bound_checking_lock(void);
+__attribute__((weak)) void __bound_checking_unlock(void);
+
+#ifndef _WIN32
+# define __declspec(n)
+#endif
+
+__declspec(dllexport)
+void __bt_init(rt_context *p, int num_callers)
+{
+ __attribute__((weak)) int main();
+ __attribute__((weak)) void __bound_init(void*, int);
+ struct rt_context *rc = &g_rtctxt;
+ //fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
+ /* call __bound_init here due to redirection of sigaction */
+ /* needed to add global symbols */
+ if (p->bounds_start) {
+ __bound_init(p->bounds_start, -1);
+ __bound_checking_lock();
+ }
+ if (num_callers) {
+ memcpy(rc, p, offsetof(rt_context, next));
+ rc->num_callers = num_callers - 1;
+ rc->top_func = main;
+ __rt_error = _rt_error;
+ set_exception_handler();
+ } else {
+ p->next = rc->next, rc->next = p;
+ }
+ if (p->bounds_start)
+ __bound_checking_unlock();
+}
+
+__declspec(dllexport)
+void __bt_exit(rt_context *p)
+{
+ __attribute__((weak)) void __bound_exit_dll(void*);
+ struct rt_context *rc = &g_rtctxt;
+
+ if (p->bounds_start) {
+ __bound_exit_dll(p->bounds_start);
+ __bound_checking_lock();
+ }
+ while (rc) {
+ if (rc->next == p) {
+ rc->next = rc->next->next;
+ break;
+ }
+ rc = rc->next;
+ }
+ if (p->bounds_start)
+ __bound_checking_unlock();
+}
+
+/* copy a string and truncate it. */
+ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s)
+{
+ int l = strlen(s);
+ if (l >= buf_size)
+ l = buf_size - 1;
+ memcpy(buf, s, l);
+ buf[l] = 0;
+ return buf;
+}
diff --git a/tinycc/lib/bt-log.c b/tinycc/lib/bt-log.c
new file mode 100644
index 0000000..8f7a4db
--- /dev/null
+++ b/tinycc/lib/bt-log.c
@@ -0,0 +1,47 @@
+/* ------------------------------------------------------------- */
+/* function to get a stack backtrace on demand with a message */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+int (*__rt_error)(void*, void*, const char *, va_list);
+
+#ifdef _WIN32
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT
+#endif
+
+/* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */
+#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wframe-address"
+#endif
+
+DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (__rt_error) {
+ void *fp = __builtin_frame_address(1);
+ void *ip = __builtin_return_address(0);
+ va_start(ap, fmt);
+ ret = __rt_error(fp, ip, fmt, ap);
+ va_end(ap);
+ } else {
+ const char *p;
+ if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
+ fmt = p + 1;
+ va_start(ap, fmt);
+ ret = vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n"), fflush(stderr);
+ }
+ return ret;
+}
+
+#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
diff --git a/tinycc/lib/builtin.c b/tinycc/lib/builtin.c
new file mode 100644
index 0000000..e40a003
--- /dev/null
+++ b/tinycc/lib/builtin.c
@@ -0,0 +1,164 @@
+/* uses alias to allow building with gcc/clang */
+#ifdef __TINYC__
+#define BUILTIN(x) __builtin_##x
+#define BUILTINN(x) "__builtin_" # x
+#else
+#define BUILTIN(x) __tcc_builtin_##x
+#define BUILTINN(x) "__tcc_builtin_" # x
+#endif
+
+/* ---------------------------------------------- */
+/* This file implements:
+ * __builtin_ffs
+ * __builtin_clz
+ * __builtin_ctz
+ * __builtin_clrsb
+ * __builtin_popcount
+ * __builtin_parity
+ * for int, long and long long
+ */
+
+static const unsigned char table_1_32[] = {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+};
+static const unsigned char table_2_32[32] = {
+ 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
+ 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
+};
+static const unsigned char table_1_64[] = {
+ 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
+ 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
+ 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
+ 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
+};
+static const unsigned char table_2_64[] = {
+ 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
+ 9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
+ 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
+ 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
+};
+
+#define FFSI(x) \
+ return table_1_32[((x & -x) * 0x077cb531u) >> 27] + (x != 0);
+#define FFSL(x) \
+ return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58] + (x != 0);
+#define CTZI(x) \
+ return table_1_32[((x & -x) * 0x077cb531u) >> 27];
+#define CTZL(x) \
+ return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58];
+#define CLZI(x) \
+ x |= x >> 1; \
+ x |= x >> 2; \
+ x |= x >> 4; \
+ x |= x >> 8; \
+ x |= x >> 16; \
+ return table_2_32[(x * 0x07c4acddu) >> 27];
+#define CLZL(x) \
+ x |= x >> 1; \
+ x |= x >> 2; \
+ x |= x >> 4; \
+ x |= x >> 8; \
+ x |= x >> 16; \
+ x |= x >> 32; \
+ return table_2_64[x * 0x03f79d71b4cb0a89ull >> 58];
+#define POPCOUNTI(x, m) \
+ x = x - ((x >> 1) & 0x55555555); \
+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333); \
+ x = (x + (x >> 4)) & 0xf0f0f0f; \
+ return ((x * 0x01010101) >> 24) & m;
+#define POPCOUNTL(x, m) \
+ x = x - ((x >> 1) & 0x5555555555555555ull); \
+ x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); \
+ x = (x + (x >> 4)) & 0xf0f0f0f0f0f0f0full; \
+ return ((x * 0x0101010101010101ull) >> 56) & m;
+
+/* Returns one plus the index of the least significant 1-bit of x,
+ or if x is zero, returns zero. */
+int BUILTIN(ffs) (int x) { FFSI(x) }
+int BUILTIN(ffsll) (long long x) { FFSL(x) }
+#if __SIZEOF_LONG__ == 4
+int BUILTIN(ffsl) (long x) __attribute__((alias(BUILTINN(ffs))));
+#else
+int BUILTIN(ffsl) (long x) __attribute__((alias(BUILTINN(ffsll))));
+#endif
+
+/* Returns the number of leading 0-bits in x, starting at the most significant
+ bit position. If x is 0, the result is undefined. */
+int BUILTIN(clz) (unsigned int x) { CLZI(x) }
+int BUILTIN(clzll) (unsigned long long x) { CLZL(x) }
+#if __SIZEOF_LONG__ == 4
+int BUILTIN(clzl) (unsigned long x) __attribute__((alias(BUILTINN(clz))));
+#else
+int BUILTIN(clzl) (unsigned long x) __attribute__((alias(BUILTINN(clzll))));
+#endif
+
+/* Returns the number of trailing 0-bits in x, starting at the least
+ significant bit position. If x is 0, the result is undefined. */
+int BUILTIN(ctz) (unsigned int x) { CTZI(x) }
+int BUILTIN(ctzll) (unsigned long long x) { CTZL(x) }
+#if __SIZEOF_LONG__ == 4
+int BUILTIN(ctzl) (unsigned long x) __attribute__((alias(BUILTINN(ctz))));
+#else
+int BUILTIN(ctzl) (unsigned long x) __attribute__((alias(BUILTINN(ctzll))));
+#endif
+
+/* Returns the number of leading redundant sign bits in x, i.e. the number
+ of bits following the most significant bit that are identical to it.
+ There are no special cases for 0 or other values. */
+int BUILTIN(clrsb) (int x) { if (x < 0) x = ~x; x <<= 1; CLZI(x) }
+int BUILTIN(clrsbll) (long long x) { if (x < 0) x = ~x; x <<= 1; CLZL(x) }
+#if __SIZEOF_LONG__ == 4
+int BUILTIN(clrsbl) (long x) __attribute__((alias(BUILTINN(clrsb))));
+#else
+int BUILTIN(clrsbl) (long x) __attribute__((alias(BUILTINN(clrsbll))));
+#endif
+
+/* Returns the number of 1-bits in x.*/
+int BUILTIN(popcount) (unsigned int x) { POPCOUNTI(x, 0x3f) }
+int BUILTIN(popcountll) (unsigned long long x) { POPCOUNTL(x, 0x7f) }
+#if __SIZEOF_LONG__ == 4
+int BUILTIN(popcountl) (unsigned long x) __attribute__((alias(BUILTINN(popcount))));
+#else
+int BUILTIN(popcountl ) (unsigned long x) __attribute__((alias(BUILTINN(popcountll))));
+#endif
+
+/* Returns the parity of x, i.e. the number of 1-bits in x modulo 2. */
+int BUILTIN(parity) (unsigned int x) { POPCOUNTI(x, 0x01) }
+int BUILTIN(parityll) (unsigned long long x) { POPCOUNTL(x, 0x01) }
+#if __SIZEOF_LONG__ == 4
+int BUILTIN(parityl) (unsigned long x) __attribute__((alias(BUILTINN(parity))));
+#else
+int BUILTIN(parityl) (unsigned long x) __attribute__((alias(BUILTINN(parityll))));
+#endif
+
+#ifndef __TINYC__
+#if defined(__GNUC__) && (__GNUC__ >= 6)
+/* gcc overrides alias from __builtin_ffs... to ffs.. so use assembly code */
+__asm__(".globl __builtin_ffs");
+__asm__(".set __builtin_ffs,__tcc_builtin_ffs");
+__asm__(".globl __builtin_ffsl");
+__asm__(".set __builtin_ffsl,__tcc_builtin_ffsl");
+__asm__(".globl __builtin_ffsll");
+__asm__(".set __builtin_ffsll,__tcc_builtin_ffsll");
+#else
+int __builtin_ffs(int x) __attribute__((alias("__tcc_builtin_ffs")));
+int __builtin_ffsl(long x) __attribute__((alias("__tcc_builtin_ffsl")));
+int __builtin_ffsll(long long x) __attribute__((alias("__tcc_builtin_ffsll")));
+#endif
+int __builtin_clz(unsigned int x) __attribute__((alias("__tcc_builtin_clz")));
+int __builtin_clzl(unsigned long x) __attribute__((alias("__tcc_builtin_clzl")));
+int __builtin_clzll(unsigned long long x) __attribute__((alias("__tcc_builtin_clzll")));
+int __builtin_ctz(unsigned int x) __attribute__((alias("__tcc_builtin_ctz")));
+int __builtin_ctzl(unsigned long x) __attribute__((alias("__tcc_builtin_ctzl")));
+int __builtin_ctzll(unsigned long long x) __attribute__((alias("__tcc_builtin_ctzll")));
+int __builtin_clrsb(int x) __attribute__((alias("__tcc_builtin_clrsb")));
+int __builtin_clrsbl(long x) __attribute__((alias("__tcc_builtin_clrsbl")));
+int __builtin_clrsbll(long long x) __attribute__((alias("__tcc_builtin_clrsbll")));
+int __builtin_popcount(unsigned int x) __attribute__((alias("__tcc_builtin_popcount")));
+int __builtin_popcountl(unsigned long x) __attribute__((alias("__tcc_builtin_popcountl")));
+int __builtin_popcountll(unsigned long long x) __attribute__((alias("__tcc_builtin_popcountll")));
+int __builtin_parity(unsigned int x) __attribute__((alias("__tcc_builtin_parity")));
+int __builtin_parityl(unsigned long x) __attribute__((alias("__tcc_builtin_parityl")));
+int __builtin_parityll(unsigned long long x) __attribute__((alias("__tcc_builtin_parityll")));
+#endif
diff --git a/tinycc/lib/dsohandle.c b/tinycc/lib/dsohandle.c
new file mode 100644
index 0000000..0993dbc
--- /dev/null
+++ b/tinycc/lib/dsohandle.c
@@ -0,0 +1 @@
+void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle;
diff --git a/tinycc/lib/lib-arm64.c b/tinycc/lib/lib-arm64.c
new file mode 100644
index 0000000..226827e
--- /dev/null
+++ b/tinycc/lib/lib-arm64.c
@@ -0,0 +1,677 @@
+/*
+ * TCC runtime library for arm64.
+ *
+ * Copyright (c) 2015 Edmund Grimley Evans
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved. This file is offered as-is,
+ * without any warranty.
+ */
+
+#ifdef __TINYC__
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned uint32_t;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+void *memcpy(void*,void*,__SIZE_TYPE__);
+#else
+#include <stdint.h>
+#include <string.h>
+#endif
+
+#if !defined __riscv && !defined __APPLE__
+void __clear_cache(void *beg, void *end)
+{
+ __arm64_clear_cache(beg, end);
+}
+#endif
+
+typedef struct {
+ uint64_t x0, x1;
+} u128_t;
+
+static long double f3_zero(int sgn)
+{
+ long double f;
+ u128_t x = { 0, (uint64_t)sgn << 63 };
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+static long double f3_infinity(int sgn)
+{
+ long double f;
+ u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+static long double f3_NaN(void)
+{
+ long double f;
+#if 0
+ // ARM's default NaN usually has just the top fraction bit set:
+ u128_t x = { 0, 0x7fff800000000000 };
+#else
+ // GCC's library sets all fraction bits:
+ u128_t x = { -1, 0x7fffffffffffffff };
+#endif
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
+{
+ u128_t x = { mnt.x0,
+ mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
+ memcpy(f, &x, 16);
+ return 1;
+}
+
+static int fp3_detect_NaNs(long double *f,
+ int a_sgn, int a_exp, u128_t a,
+ int b_sgn, int b_exp, u128_t b)
+{
+ // Detect signalling NaNs:
+ if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
+ return fp3_convert_NaN(f, a_sgn, a);
+ if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
+ return fp3_convert_NaN(f, b_sgn, b);
+
+ // Detect quiet NaNs:
+ if (a_exp == 32767 && (a.x0 | a.x1 << 16))
+ return fp3_convert_NaN(f, a_sgn, a);
+ if (b_exp == 32767 && (b.x0 | b.x1 << 16))
+ return fp3_convert_NaN(f, b_sgn, b);
+
+ return 0;
+}
+
+static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
+{
+ u128_t x;
+ memcpy(&x, &f, 16);
+ *sgn = x.x1 >> 63;
+ *exp = x.x1 >> 48 & 32767;
+ x.x1 = x.x1 << 16 >> 16;
+ if (*exp)
+ x.x1 |= (uint64_t)1 << 48;
+ else
+ *exp = 1;
+ *mnt = x;
+}
+
+static u128_t f3_normalise(int32_t *exp, u128_t mnt)
+{
+ int sh;
+ if (!(mnt.x0 | mnt.x1))
+ return mnt;
+ if (!mnt.x1) {
+ mnt.x1 = mnt.x0;
+ mnt.x0 = 0;
+ *exp -= 64;
+ }
+ for (sh = 32; sh; sh >>= 1) {
+ if (!(mnt.x1 >> (64 - sh))) {
+ mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh);
+ mnt.x0 = mnt.x0 << sh;
+ *exp -= sh;
+ }
+ }
+ return mnt;
+}
+
+static u128_t f3_sticky_shift(int32_t sh, u128_t x)
+{
+ if (sh >= 128) {
+ x.x0 = !!(x.x0 | x.x1);
+ x.x1 = 0;
+ return x;
+ }
+ if (sh >= 64) {
+ x.x0 = x.x1 | !!x.x0;
+ x.x1 = 0;
+ sh -= 64;
+ }
+ if (sh > 0) {
+ x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh));
+ x.x1 = x.x1 >> sh;
+ }
+ return x;
+}
+
+static long double f3_round(int sgn, int32_t exp, u128_t x)
+{
+ long double f;
+ int error;
+
+ if (exp > 0) {
+ x = f3_sticky_shift(13, x);
+ }
+ else {
+ x = f3_sticky_shift(14 - exp, x);
+ exp = 0;
+ }
+
+ error = x.x0 & 3;
+ x.x0 = x.x0 >> 2 | x.x1 << 62;
+ x.x1 = x.x1 >> 2;
+
+ if (error == 3 || ((error == 2) & (x.x0 & 1))) {
+ if (!++x.x0) {
+ ++x.x1;
+ if (x.x1 == (uint64_t)1 << 48)
+ exp = 1;
+ else if (x.x1 == (uint64_t)1 << 49) {
+ ++exp;
+ x.x0 = x.x0 >> 1 | x.x1 << 63;
+ x.x1 = x.x1 >> 1;
+ }
+ }
+ }
+
+ if (exp >= 32767)
+ return f3_infinity(sgn);
+
+ x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+static long double f3_add(long double fa, long double fb, int neg)
+{
+ u128_t a, b, x;
+ int32_t a_exp, b_exp, x_exp;
+ int a_sgn, b_sgn, x_sgn;
+ long double fx;
+
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ f3_unpack(&b_sgn, &b_exp, &b, fb);
+
+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
+ return fx;
+
+ b_sgn ^= neg;
+
+ // Handle infinities and zeroes:
+ if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn)
+ return f3_NaN();
+ if (a_exp == 32767)
+ return f3_infinity(a_sgn);
+ if (b_exp == 32767)
+ return f3_infinity(b_sgn);
+ if (!(a.x0 | a.x1 | b.x0 | b.x1))
+ return f3_zero(a_sgn & b_sgn);
+
+ a.x1 = a.x1 << 3 | a.x0 >> 61;
+ a.x0 = a.x0 << 3;
+ b.x1 = b.x1 << 3 | b.x0 >> 61;
+ b.x0 = b.x0 << 3;
+
+ if (a_exp <= b_exp) {
+ a = f3_sticky_shift(b_exp - a_exp, a);
+ a_exp = b_exp;
+ }
+ else {
+ b = f3_sticky_shift(a_exp - b_exp, b);
+ b_exp = a_exp;
+ }
+
+ x_sgn = a_sgn;
+ x_exp = a_exp;
+ if (a_sgn == b_sgn) {
+ x.x0 = a.x0 + b.x0;
+ x.x1 = a.x1 + b.x1 + (x.x0 < a.x0);
+ }
+ else {
+ x.x0 = a.x0 - b.x0;
+ x.x1 = a.x1 - b.x1 - (x.x0 > a.x0);
+ if (x.x1 >> 63) {
+ x_sgn ^= 1;
+ x.x0 = -x.x0;
+ x.x1 = -x.x1 - !!x.x0;
+ }
+ }
+
+ if (!(x.x0 | x.x1))
+ return f3_zero(0);
+
+ x = f3_normalise(&x_exp, x);
+
+ return f3_round(x_sgn, x_exp + 12, x);
+}
+
+long double __addtf3(long double a, long double b)
+{
+ return f3_add(a, b, 0);
+}
+
+long double __subtf3(long double a, long double b)
+{
+ return f3_add(a, b, 1);
+}
+
+long double __multf3(long double fa, long double fb)
+{
+ u128_t a, b, x;
+ int32_t a_exp, b_exp, x_exp;
+ int a_sgn, b_sgn, x_sgn;
+ long double fx;
+
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ f3_unpack(&b_sgn, &b_exp, &b, fb);
+
+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
+ return fx;
+
+ // Handle infinities and zeroes:
+ if ((a_exp == 32767 && !(b.x0 | b.x1)) ||
+ (b_exp == 32767 && !(a.x0 | a.x1)))
+ return f3_NaN();
+ if (a_exp == 32767 || b_exp == 32767)
+ return f3_infinity(a_sgn ^ b_sgn);
+ if (!(a.x0 | a.x1) || !(b.x0 | b.x1))
+ return f3_zero(a_sgn ^ b_sgn);
+
+ a = f3_normalise(&a_exp, a);
+ b = f3_normalise(&b_exp, b);
+
+ x_sgn = a_sgn ^ b_sgn;
+ x_exp = a_exp + b_exp - 16352;
+
+ {
+ // Convert to base (1 << 30), discarding bottom 6 bits, which are zero,
+ // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0):
+ uint64_t a0 = a.x0 << 28 >> 34;
+ uint64_t b0 = b.x0 << 28 >> 34;
+ uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34;
+ uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34;
+ uint64_t a2 = a.x1 << 32 >> 34;
+ uint64_t b2 = b.x1 << 32 >> 34;
+ uint64_t a3 = a.x1 >> 32;
+ uint64_t b3 = b.x1 >> 32;
+ // Use 16 small multiplications and additions that do not overflow:
+ uint64_t x0 = a0 * b0;
+ uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0;
+ uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0;
+ uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
+ uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1;
+ uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2;
+ uint64_t x6 = (x5 >> 30) + a3 * b3;
+ // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...).
+ // Take the top 128 bits, setting bottom bit if any lower bits were set:
+ uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 |
+ !!(x3 << 38 | (x2 | x1 | x0) << 34));
+ uint64_t y1 = x6;
+ // Top bit may be zero. Renormalise:
+ if (!(y1 >> 63)) {
+ y1 = y1 << 1 | y0 >> 63;
+ y0 = y0 << 1;
+ --x_exp;
+ }
+ x.x0 = y0;
+ x.x1 = y1;
+ }
+
+ return f3_round(x_sgn, x_exp, x);
+}
+
+long double __divtf3(long double fa, long double fb)
+{
+ u128_t a, b, x;
+ int32_t a_exp, b_exp, x_exp;
+ int a_sgn, b_sgn, x_sgn, i;
+ long double fx;
+
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ f3_unpack(&b_sgn, &b_exp, &b, fb);
+
+ if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
+ return fx;
+
+ // Handle infinities and zeroes:
+ if ((a_exp == 32767 && b_exp == 32767) ||
+ (!(a.x0 | a.x1) && !(b.x0 | b.x1)))
+ return f3_NaN();
+ if (a_exp == 32767 || !(b.x0 | b.x1))
+ return f3_infinity(a_sgn ^ b_sgn);
+ if (!(a.x0 | a.x1) || b_exp == 32767)
+ return f3_zero(a_sgn ^ b_sgn);
+
+ a = f3_normalise(&a_exp, a);
+ b = f3_normalise(&b_exp, b);
+
+ x_sgn = a_sgn ^ b_sgn;
+ x_exp = a_exp - b_exp + 16395;
+
+ a.x0 = a.x0 >> 1 | a.x1 << 63;
+ a.x1 = a.x1 >> 1;
+ b.x0 = b.x0 >> 1 | b.x1 << 63;
+ b.x1 = b.x1 >> 1;
+ x.x0 = 0;
+ x.x1 = 0;
+ for (i = 0; i < 116; i++) {
+ x.x1 = x.x1 << 1 | x.x0 >> 63;
+ x.x0 = x.x0 << 1;
+ if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) {
+ a.x1 = a.x1 - b.x1 - (a.x0 < b.x0);
+ a.x0 = a.x0 - b.x0;
+ x.x0 |= 1;
+ }
+ a.x1 = a.x1 << 1 | a.x0 >> 63;
+ a.x0 = a.x0 << 1;
+ }
+ x.x0 |= !!(a.x0 | a.x1);
+
+ x = f3_normalise(&x_exp, x);
+
+ return f3_round(x_sgn, x_exp, x);
+}
+
+long double __extendsftf2(float f)
+{
+ long double fx;
+ u128_t x;
+ uint32_t a;
+ uint64_t aa;
+ memcpy(&a, &f, 4);
+ aa = a;
+ x.x0 = 0;
+ if (!(a << 1))
+ x.x1 = aa << 32;
+ else if (a << 1 >> 24 == 255)
+ x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
+ (uint64_t)!!(a << 9) << 47);
+ else if (a << 1 >> 24 == 0) {
+ uint64_t adj = 0;
+ while (!(a << 1 >> 1 >> (23 - adj)))
+ adj++;
+ x.x1 = aa >> 31 << 63 | (16256 - adj + 1) << 48 | aa << adj << 41 >> 16;
+ } else
+ x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
+ aa << 41 >> 16);
+ memcpy(&fx, &x, 16);
+ return fx;
+}
+
+long double __extenddftf2(double f)
+{
+ long double fx;
+ u128_t x;
+ uint64_t a;
+ memcpy(&a, &f, 8);
+ x.x0 = a << 60;
+ if (!(a << 1))
+ x.x1 = a;
+ else if (a << 1 >> 53 == 2047)
+ x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
+ (uint64_t)!!(a << 12) << 47);
+ else if (a << 1 >> 53 == 0) {
+ uint64_t adj = 0;
+ while (!(a << 1 >> 1 >> (52 - adj)))
+ adj++;
+ x.x0 <<= adj;
+ x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
+ } else
+ x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
+ memcpy(&fx, &x, 16);
+ return fx;
+}
+
+float __trunctfsf2(long double f)
+{
+ u128_t mnt;
+ int32_t exp;
+ int sgn;
+ uint32_t x;
+ float fx;
+
+ f3_unpack(&sgn, &exp, &mnt, f);
+
+ if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
+ x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
+ else if (exp > 16510)
+ x = 0x7f800000 | (uint32_t)sgn << 31;
+ else if (exp < 16233)
+ x = (uint32_t)sgn << 31;
+ else {
+ exp -= 16257;
+ x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41);
+ if (exp < 0) {
+ x = x >> -exp | !!(x << (32 + exp));
+ exp = 0;
+ }
+ if ((x & 3) == 3 || (x & 7) == 6)
+ x += 4;
+ x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
+ }
+ memcpy(&fx, &x, 4);
+ return fx;
+}
+
+double __trunctfdf2(long double f)
+{
+ u128_t mnt;
+ int32_t exp;
+ int sgn;
+ uint64_t x;
+ double fx;
+
+ f3_unpack(&sgn, &exp, &mnt, f);
+
+ if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
+ x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
+ mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
+ else if (exp > 17406)
+ x = 0x7ff0000000000000 | (uint64_t)sgn << 63;
+ else if (exp < 15308)
+ x = (uint64_t)sgn << 63;
+ else {
+ exp -= 15361;
+ x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6);
+ if (exp < 0) {
+ x = x >> -exp | !!(x << (64 + exp));
+ exp = 0;
+ }
+ if ((x & 3) == 3 || (x & 7) == 6)
+ x += 4;
+ x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
+ }
+ memcpy(&fx, &x, 8);
+ return fx;
+}
+
+int32_t __fixtfsi(long double fa)
+{
+ u128_t a;
+ int32_t a_exp;
+ int a_sgn;
+ int32_t x;
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ if (a_exp < 16369)
+ return 0;
+ if (a_exp > 16413)
+ return a_sgn ? -0x80000000 : 0x7fffffff;
+ x = a.x1 >> (16431 - a_exp);
+ return a_sgn ? -x : x;
+}
+
+int64_t __fixtfdi(long double fa)
+{
+ u128_t a;
+ int32_t a_exp;
+ int a_sgn;
+ int64_t x;
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ if (a_exp < 16383)
+ return 0;
+ if (a_exp > 16445)
+ return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff;
+ x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
+ return a_sgn ? -x : x;
+}
+
+uint32_t __fixunstfsi(long double fa)
+{
+ u128_t a;
+ int32_t a_exp;
+ int a_sgn;
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ if (a_sgn || a_exp < 16369)
+ return 0;
+ if (a_exp > 16414)
+ return -1;
+ return a.x1 >> (16431 - a_exp);
+}
+
+uint64_t __fixunstfdi(long double fa)
+{
+ u128_t a;
+ int32_t a_exp;
+ int a_sgn;
+ f3_unpack(&a_sgn, &a_exp, &a, fa);
+ if (a_sgn || a_exp < 16383)
+ return 0;
+ if (a_exp > 16446)
+ return -1;
+ return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
+}
+
+long double __floatsitf(int32_t a)
+{
+ int sgn = 0;
+ int exp = 16414;
+ uint32_t mnt = a;
+ u128_t x = { 0, 0 };
+ long double f;
+ int i;
+ if (a) {
+ if (a < 0) {
+ sgn = 1;
+ mnt = -mnt;
+ }
+ for (i = 16; i; i >>= 1)
+ if (!(mnt >> (32 - i))) {
+ mnt <<= i;
+ exp -= i;
+ }
+ x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
+ (uint64_t)(mnt << 1) << 16);
+ }
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+long double __floatditf(int64_t a)
+{
+ int sgn = 0;
+ int exp = 16446;
+ uint64_t mnt = a;
+ u128_t x = { 0, 0 };
+ long double f;
+ int i;
+ if (a) {
+ if (a < 0) {
+ sgn = 1;
+ mnt = -mnt;
+ }
+ for (i = 32; i; i >>= 1)
+ if (!(mnt >> (64 - i))) {
+ mnt <<= i;
+ exp -= i;
+ }
+ x.x0 = mnt << 49;
+ x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
+ }
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+long double __floatunsitf(uint32_t a)
+{
+ int exp = 16414;
+ uint32_t mnt = a;
+ u128_t x = { 0, 0 };
+ long double f;
+ int i;
+ if (a) {
+ for (i = 16; i; i >>= 1)
+ if (!(mnt >> (32 - i))) {
+ mnt <<= i;
+ exp -= i;
+ }
+ x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
+ }
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+long double __floatunditf(uint64_t a)
+{
+ int exp = 16446;
+ uint64_t mnt = a;
+ u128_t x = { 0, 0 };
+ long double f;
+ int i;
+ if (a) {
+ for (i = 32; i; i >>= 1)
+ if (!(mnt >> (64 - i))) {
+ mnt <<= i;
+ exp -= i;
+ }
+ x.x0 = mnt << 49;
+ x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
+ }
+ memcpy(&f, &x, 16);
+ return f;
+}
+
+static int f3_cmp(long double fa, long double fb)
+{
+ u128_t a, b;
+ memcpy(&a, &fa, 16);
+ memcpy(&b, &fb, 16);
+ return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
+ ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
+ (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
+ a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) :
+ a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 :
+ a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) :
+ a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 :
+ b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0);
+}
+
+int __eqtf2(long double a, long double b)
+{
+ return !!f3_cmp(a, b);
+}
+
+int __netf2(long double a, long double b)
+{
+ return !!f3_cmp(a, b);
+}
+
+int __lttf2(long double a, long double b)
+{
+ return f3_cmp(a, b);
+}
+
+int __letf2(long double a, long double b)
+{
+ return f3_cmp(a, b);
+}
+
+int __gttf2(long double a, long double b)
+{
+ return -f3_cmp(b, a);
+}
+
+int __getf2(long double a, long double b)
+{
+ return -f3_cmp(b, a);
+}
diff --git a/tinycc/lib/libtcc1.c b/tinycc/lib/libtcc1.c
new file mode 100644
index 0000000..ae94af1
--- /dev/null
+++ b/tinycc/lib/libtcc1.c
@@ -0,0 +1,641 @@
+/* TCC runtime library.
+ Parts of this code are (c) 2002 Fabrice Bellard
+
+ Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file. (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#define W_TYPE_SIZE 32
+#define BITS_PER_UNIT 8
+
+typedef int Wtype;
+typedef unsigned int UWtype;
+typedef unsigned int USItype;
+typedef long long DWtype;
+typedef unsigned long long UDWtype;
+
+struct DWstruct {
+ Wtype low, high;
+};
+
+typedef union
+{
+ struct DWstruct s;
+ DWtype ll;
+} DWunion;
+
+typedef long double XFtype;
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+
+/* the following deal with IEEE single-precision numbers */
+#define EXCESS 126
+#define SIGNBIT 0x80000000
+#define HIDDEN (1 << 23)
+#define SIGN(fp) ((fp) & SIGNBIT)
+#define EXP(fp) (((fp) >> 23) & 0xFF)
+#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN)
+#define PACK(s,e,m) ((s) | ((e) << 23) | (m))
+
+/* the following deal with IEEE double-precision numbers */
+#define EXCESSD 1022
+#define HIDDEND (1 << 20)
+#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
+#define SIGND(fp) ((fp.l.upper) & SIGNBIT)
+#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
+ (fp.l.lower >> 22))
+#define HIDDEND_LL ((long long)1 << 52)
+#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
+#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m))
+
+/* the following deal with x86 long double-precision numbers */
+#define EXCESSLD 16382
+#define EXPLD(fp) (fp.l.upper & 0x7fff)
+#define SIGNLD(fp) ((fp.l.upper) & 0x8000)
+
+/* only for x86 */
+union ldouble_long {
+ long double ld;
+ struct {
+ unsigned long long lower;
+ unsigned short upper;
+ } l;
+};
+
+union double_long {
+ double d;
+#if 1
+ struct {
+ unsigned int lower;
+ int upper;
+ } l;
+#else
+ struct {
+ int upper;
+ unsigned int lower;
+ } l;
+#endif
+ long long ll;
+};
+
+union float_long {
+ float f;
+ unsigned int l;
+};
+
+/* XXX: we don't support several builtin supports for now */
+#if !defined __x86_64__ && !defined __arm__
+
+/* XXX: use gcc/tcc intrinsic ? */
+#if defined __i386__
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("subl %5,%1\n\tsbbl %3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("mull %3" \
+ : "=a" ((USItype) (w0)), \
+ "=d" ((USItype) (w1)) \
+ : "%0" ((USItype) (u)), \
+ "rm" ((USItype) (v)))
+#define udiv_qrnnd(q, r, n1, n0, dv) \
+ __asm__ ("divl %4" \
+ : "=a" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "rm" ((USItype) (dv)))
+#define count_leading_zeros(count, x) \
+ do { \
+ USItype __cbtmp; \
+ __asm__ ("bsrl %1,%0" \
+ : "=r" (__cbtmp) : "rm" ((USItype) (x))); \
+ (count) = __cbtmp ^ 31; \
+ } while (0)
+#else
+#error unsupported CPU type
+#endif
+
+/* most of this code is taken from libgcc2.c from gcc */
+
+static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
+{
+ DWunion ww;
+ DWunion nn, dd;
+ DWunion rr;
+ UWtype d0, d1, n0, n1, n2;
+ UWtype q0, q1;
+ UWtype b, bm;
+
+ nn.ll = n;
+ dd.ll = d;
+
+ d0 = dd.s.low;
+ d1 = dd.s.high;
+ n0 = nn.s.low;
+ n1 = nn.s.high;
+
+#if !defined(UDIV_NEEDS_NORMALIZATION)
+ if (d1 == 0)
+ {
+ if (d0 > n1)
+ {
+ /* 0q = nn / 0D */
+
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+ q1 = 0;
+
+ /* Remainder in n0. */
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (d0 == 0)
+ d0 = 1 / d0; /* Divide intentionally by zero. */
+
+ udiv_qrnnd (q1, n1, 0, n1, d0);
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+
+ /* Remainder in n0. */
+ }
+
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = 0;
+ *rp = rr.ll;
+ }
+ }
+
+#else /* UDIV_NEEDS_NORMALIZATION */
+
+ if (d1 == 0)
+ {
+ if (d0 > n1)
+ {
+ /* 0q = nn / 0D */
+
+ count_leading_zeros (bm, d0);
+
+ if (bm != 0)
+ {
+ /* Normalize, i.e. make the most significant bit of the
+ denominator set. */
+
+ d0 = d0 << bm;
+ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
+ n0 = n0 << bm;
+ }
+
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+ q1 = 0;
+
+ /* Remainder in n0 >> bm. */
+ }
+ else
+ {
+ /* qq = NN / 0d */
+
+ if (d0 == 0)
+ d0 = 1 / d0; /* Divide intentionally by zero. */
+
+ count_leading_zeros (bm, d0);
+
+ if (bm == 0)
+ {
+ /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
+ conclude (the most significant bit of n1 is set) /\ (the
+ leading quotient digit q1 = 1).
+
+ This special case is necessary, not an optimization.
+ (Shifts counts of W_TYPE_SIZE are undefined.) */
+
+ n1 -= d0;
+ q1 = 1;
+ }
+ else
+ {
+ /* Normalize. */
+
+ b = W_TYPE_SIZE - bm;
+
+ d0 = d0 << bm;
+ n2 = n1 >> b;
+ n1 = (n1 << bm) | (n0 >> b);
+ n0 = n0 << bm;
+
+ udiv_qrnnd (q1, n1, n2, n1, d0);
+ }
+
+ /* n1 != d0... */
+
+ udiv_qrnnd (q0, n0, n1, n0, d0);
+
+ /* Remainder in n0 >> bm. */
+ }
+
+ if (rp != 0)
+ {
+ rr.s.low = n0 >> bm;
+ rr.s.high = 0;
+ *rp = rr.ll;
+ }
+ }
+#endif /* UDIV_NEEDS_NORMALIZATION */
+
+ else
+ {
+ if (d1 > n1)
+ {
+ /* 00 = nn / DD */
+
+ q0 = 0;
+ q1 = 0;
+
+ /* Remainder in n1n0. */
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = n1;
+ *rp = rr.ll;
+ }
+ }
+ else
+ {
+ /* 0q = NN / dd */
+
+ count_leading_zeros (bm, d1);
+ if (bm == 0)
+ {
+ /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
+ conclude (the most significant bit of n1 is set) /\ (the
+ quotient digit q0 = 0 or 1).
+
+ This special case is necessary, not an optimization. */
+
+ /* The condition on the next line takes advantage of that
+ n1 >= d1 (true due to program flow). */
+ if (n1 > d1 || n0 >= d0)
+ {
+ q0 = 1;
+ sub_ddmmss (n1, n0, n1, n0, d1, d0);
+ }
+ else
+ q0 = 0;
+
+ q1 = 0;
+
+ if (rp != 0)
+ {
+ rr.s.low = n0;
+ rr.s.high = n1;
+ *rp = rr.ll;
+ }
+ }
+ else
+ {
+ UWtype m1, m0;
+ /* Normalize. */
+
+ b = W_TYPE_SIZE - bm;
+
+ d1 = (d1 << bm) | (d0 >> b);
+ d0 = d0 << bm;
+ n2 = n1 >> b;
+ n1 = (n1 << bm) | (n0 >> b);
+ n0 = n0 << bm;
+
+ udiv_qrnnd (q0, n1, n2, n1, d1);
+ umul_ppmm (m1, m0, q0, d0);
+
+ if (m1 > n1 || (m1 == n1 && m0 > n0))
+ {
+ q0--;
+ sub_ddmmss (m1, m0, m1, m0, d1, d0);
+ }
+
+ q1 = 0;
+
+ /* Remainder in (n1n0 - m1m0) >> bm. */
+ if (rp != 0)
+ {
+ sub_ddmmss (n1, n0, n1, n0, m1, m0);
+ rr.s.low = (n1 << b) | (n0 >> bm);
+ rr.s.high = n1 >> bm;
+ *rp = rr.ll;
+ }
+ }
+ }
+ }
+
+ ww.s.low = q0;
+ ww.s.high = q1;
+ return ww.ll;
+}
+
+#define __negdi2(a) (-(a))
+
+long long __divdi3(long long u, long long v)
+{
+ int c = 0;
+ DWunion uu, vv;
+ DWtype w;
+
+ uu.ll = u;
+ vv.ll = v;
+
+ if (uu.s.high < 0) {
+ c = ~c;
+ uu.ll = __negdi2 (uu.ll);
+ }
+ if (vv.s.high < 0) {
+ c = ~c;
+ vv.ll = __negdi2 (vv.ll);
+ }
+ w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
+ if (c)
+ w = __negdi2 (w);
+ return w;
+}
+
+long long __moddi3(long long u, long long v)
+{
+ int c = 0;
+ DWunion uu, vv;
+ DWtype w;
+
+ uu.ll = u;
+ vv.ll = v;
+
+ if (uu.s.high < 0) {
+ c = ~c;
+ uu.ll = __negdi2 (uu.ll);
+ }
+ if (vv.s.high < 0)
+ vv.ll = __negdi2 (vv.ll);
+
+ __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
+ if (c)
+ w = __negdi2 (w);
+ return w;
+}
+
+unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
+{
+ return __udivmoddi4 (u, v, (UDWtype *) 0);
+}
+
+unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
+{
+ UDWtype w;
+
+ __udivmoddi4 (u, v, &w);
+ return w;
+}
+
+/* XXX: fix tcc's code generator to do this instead */
+long long __ashrdi3(long long a, int b)
+{
+#ifdef __TINYC__
+ DWunion u;
+ u.ll = a;
+ if (b >= 32) {
+ u.s.low = u.s.high >> (b - 32);
+ u.s.high = u.s.high >> 31;
+ } else if (b != 0) {
+ u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
+ u.s.high = u.s.high >> b;
+ }
+ return u.ll;
+#else
+ return a >> b;
+#endif
+}
+
+/* XXX: fix tcc's code generator to do this instead */
+unsigned long long __lshrdi3(unsigned long long a, int b)
+{
+#ifdef __TINYC__
+ DWunion u;
+ u.ll = a;
+ if (b >= 32) {
+ u.s.low = (unsigned)u.s.high >> (b - 32);
+ u.s.high = 0;
+ } else if (b != 0) {
+ u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
+ u.s.high = (unsigned)u.s.high >> b;
+ }
+ return u.ll;
+#else
+ return a >> b;
+#endif
+}
+
+/* XXX: fix tcc's code generator to do this instead */
+long long __ashldi3(long long a, int b)
+{
+#ifdef __TINYC__
+ DWunion u;
+ u.ll = a;
+ if (b >= 32) {
+ u.s.high = (unsigned)u.s.low << (b - 32);
+ u.s.low = 0;
+ } else if (b != 0) {
+ u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
+ u.s.low = (unsigned)u.s.low << b;
+ }
+ return u.ll;
+#else
+ return a << b;
+#endif
+}
+
+#endif /* !__x86_64__ */
+
+/* XXX: fix tcc's code generator to do this instead */
+float __floatundisf(unsigned long long a)
+{
+ DWunion uu;
+ XFtype r;
+
+ uu.ll = a;
+ if (uu.s.high >= 0) {
+ return (float)uu.ll;
+ } else {
+ r = (XFtype)uu.ll;
+ r += 18446744073709551616.0;
+ return (float)r;
+ }
+}
+
+double __floatundidf(unsigned long long a)
+{
+ DWunion uu;
+ XFtype r;
+
+ uu.ll = a;
+ if (uu.s.high >= 0) {
+ return (double)uu.ll;
+ } else {
+ r = (XFtype)uu.ll;
+ r += 18446744073709551616.0;
+ return (double)r;
+ }
+}
+
+long double __floatundixf(unsigned long long a)
+{
+ DWunion uu;
+ XFtype r;
+
+ uu.ll = a;
+ if (uu.s.high >= 0) {
+ return (long double)uu.ll;
+ } else {
+ r = (XFtype)uu.ll;
+ r += 18446744073709551616.0;
+ return (long double)r;
+ }
+}
+
+unsigned long long __fixunssfdi (float a1)
+{
+ register union float_long fl1;
+ register int exp;
+ register unsigned long long l;
+
+ fl1.f = a1;
+
+ if (fl1.l == 0)
+ return (0);
+
+ exp = EXP (fl1.l) - EXCESS - 24;
+ l = MANT(fl1.l);
+
+ if (exp >= 41)
+ return 1ULL << 63;
+ else if (exp >= 0)
+ l <<= exp;
+ else if (exp >= -23)
+ l >>= -exp;
+ else
+ return 0;
+ if (SIGN(fl1.l))
+ l = (unsigned long long)-l;
+ return l;
+}
+
+long long __fixsfdi (float a1)
+{
+ long long ret; int s;
+ ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
+ return s ? ret : -ret;
+}
+
+unsigned long long __fixunsdfdi (double a1)
+{
+ register union double_long dl1;
+ register int exp;
+ register unsigned long long l;
+
+ dl1.d = a1;
+
+ if (dl1.ll == 0)
+ return (0);
+
+ exp = EXPD (dl1) - EXCESSD - 53;
+ l = MANTD_LL(dl1);
+
+ if (exp >= 12)
+ return 1ULL << 63; /* overflow result (like gcc, somewhat) */
+ else if (exp >= 0)
+ l <<= exp;
+ else if (exp >= -52)
+ l >>= -exp;
+ else
+ return 0;
+ if (SIGND(dl1))
+ l = (unsigned long long)-l;
+ return l;
+}
+
+long long __fixdfdi (double a1)
+{
+ long long ret; int s;
+ ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
+ return s ? ret : -ret;
+}
+
+#ifndef __arm__
+unsigned long long __fixunsxfdi (long double a1)
+{
+ register union ldouble_long dl1;
+ register int exp;
+ register unsigned long long l;
+
+ dl1.ld = a1;
+
+ if (dl1.l.lower == 0 && dl1.l.upper == 0)
+ return (0);
+
+ exp = EXPLD (dl1) - EXCESSLD - 64;
+ l = dl1.l.lower;
+ if (exp > 0)
+ return 1ULL << 63;
+ if (exp < -63)
+ return 0;
+ l >>= -exp;
+ if (SIGNLD(dl1))
+ l = (unsigned long long)-l;
+ return l;
+}
+
+long long __fixxfdi (long double a1)
+{
+ long long ret; int s;
+ ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1);
+ return s ? ret : -ret;
+}
+#endif /* !ARM */
+
+#if defined __x86_64__
+/* float constants used for unary minus operation */
+const float __mzerosf = -0.0;
+const double __mzerodf = -0.0;
+#endif
+
+#if defined _WIN64
+/* MSVC x64 intrinsic */
+void __faststorefence(void)
+{
+ __asm__("lock; orl $0,(%rsp)");
+}
+#endif
diff --git a/tinycc/lib/stdatomic.c b/tinycc/lib/stdatomic.c
new file mode 100644
index 0000000..bd8c0ce
--- /dev/null
+++ b/tinycc/lib/stdatomic.c
@@ -0,0 +1,166 @@
+// for libtcc1, avoid including files that are not part of tcc
+// #include <stdint.h>
+#define uint8_t unsigned char
+#define uint16_t unsigned short
+#define uint32_t unsigned int
+#define uint64_t unsigned long long
+#define bool _Bool
+#define false 0
+#define true 1
+#define __ATOMIC_RELAXED 0
+#define __ATOMIC_CONSUME 1
+#define __ATOMIC_ACQUIRE 2
+#define __ATOMIC_RELEASE 3
+#define __ATOMIC_ACQ_REL 4
+#define __ATOMIC_SEQ_CST 5
+typedef __SIZE_TYPE__ size_t;
+
+#if defined __i386__ || defined __x86_64__
+#define ATOMIC_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \
+ bool __atomic_compare_exchange_##MODE \
+ (volatile void *atom, void *ref, TYPE xchg, \
+ bool weak, int success_memorder, int failure_memorder) \
+ { \
+ TYPE rv; \
+ TYPE cmp = *(TYPE *)ref; \
+ __asm__ volatile( \
+ "lock cmpxchg" SUFFIX " %2,%1\n" \
+ : "=a" (rv), "+m" (*(TYPE *)atom) \
+ : "q" (xchg), "0" (cmp) \
+ : "memory" \
+ ); \
+ *(TYPE *)ref = rv; \
+ return (rv == cmp); \
+ }
+#else
+#define ATOMIC_COMPARE_EXCHANGE(TYPE, MODE, SUFFIX) \
+ extern bool __atomic_compare_exchange_##MODE \
+ (volatile void *atom, void *ref, TYPE xchg, \
+ bool weak, int success_memorder, int failure_memorder);
+#endif
+
+#define ATOMIC_LOAD(TYPE, MODE) \
+ TYPE __atomic_load_##MODE(const volatile void *atom, int memorder) \
+ { \
+ return *(volatile TYPE *)atom; \
+ }
+
+#define ATOMIC_STORE(TYPE, MODE) \
+ void __atomic_store_##MODE(volatile void *atom, TYPE value, int memorder) \
+ { \
+ *(volatile TYPE *)atom = value; \
+ }
+
+#define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP, RET) \
+ TYPE __atomic_##NAME##_##MODE(volatile void *atom, TYPE value, int memorder) \
+ { \
+ TYPE xchg, cmp; \
+ __atomic_load((TYPE *)atom, (TYPE *)&cmp, __ATOMIC_RELAXED); \
+ do { \
+ xchg = (OP); \
+ } while (!__atomic_compare_exchange((TYPE *)atom, &cmp, &xchg, true, \
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); \
+ return RET; \
+ }
+
+#define ATOMIC_EXCHANGE(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, exchange, value, cmp)
+#define ATOMIC_ADD_FETCH(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, add_fetch, (cmp + value), xchg)
+#define ATOMIC_SUB_FETCH(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, sub_fetch, (cmp - value), xchg)
+#define ATOMIC_AND_FETCH(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, and_fetch, (cmp & value), xchg)
+#define ATOMIC_OR_FETCH(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, or_fetch, (cmp | value), xchg)
+#define ATOMIC_XOR_FETCH(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, xor_fetch, (cmp ^ value), xchg)
+#define ATOMIC_NAND_FETCH(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, nand_fetch, ~(cmp & value), xchg)
+#define ATOMIC_FETCH_ADD(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, fetch_add, (cmp + value), cmp)
+#define ATOMIC_FETCH_SUB(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, fetch_sub, (cmp - value), cmp)
+#define ATOMIC_FETCH_AND(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, fetch_and, (cmp & value), cmp)
+#define ATOMIC_FETCH_OR(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, fetch_or, (cmp | value), cmp)
+#define ATOMIC_FETCH_XOR(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, fetch_xor, (cmp ^ value), cmp)
+#define ATOMIC_FETCH_NAND(TYPE, MODE) \
+ ATOMIC_GEN_OP(TYPE, MODE, fetch_nand, ~(cmp & value), cmp)
+
+#define ATOMIC_GEN(TYPE, SIZE, SUFFIX) \
+ ATOMIC_STORE(TYPE, SIZE) \
+ ATOMIC_LOAD(TYPE, SIZE) \
+ ATOMIC_COMPARE_EXCHANGE(TYPE, SIZE, SUFFIX) \
+ ATOMIC_EXCHANGE(TYPE, SIZE) \
+ ATOMIC_ADD_FETCH(TYPE, SIZE) \
+ ATOMIC_SUB_FETCH(TYPE, SIZE) \
+ ATOMIC_AND_FETCH(TYPE, SIZE) \
+ ATOMIC_OR_FETCH(TYPE, SIZE) \
+ ATOMIC_XOR_FETCH(TYPE, SIZE) \
+ ATOMIC_NAND_FETCH(TYPE, SIZE) \
+ ATOMIC_FETCH_ADD(TYPE, SIZE) \
+ ATOMIC_FETCH_SUB(TYPE, SIZE) \
+ ATOMIC_FETCH_AND(TYPE, SIZE) \
+ ATOMIC_FETCH_OR(TYPE, SIZE) \
+ ATOMIC_FETCH_XOR(TYPE, SIZE) \
+ ATOMIC_FETCH_NAND(TYPE, SIZE)
+
+ATOMIC_GEN(uint8_t, 1, "b")
+ATOMIC_GEN(uint16_t, 2, "w")
+ATOMIC_GEN(uint32_t, 4, "l")
+#if defined __x86_64__ || defined __aarch64__ || defined __riscv
+ATOMIC_GEN(uint64_t, 8, "q")
+#endif
+
+/* uses alias to allow building with gcc/clang */
+#ifdef __TINYC__
+#define ATOMIC(x) __atomic_##x
+#else
+#define ATOMIC(x) __tcc_atomic_##x
+#endif
+
+void ATOMIC(signal_fence) (int memorder)
+{
+}
+
+void ATOMIC(thread_fence) (int memorder)
+{
+#if defined __i386__
+ __asm__ volatile("lock orl $0, (%esp)");
+#elif defined __x86_64__
+ __asm__ volatile("lock orq $0, (%rsp)");
+#elif defined __arm__
+ __asm__ volatile(".int 0xee070fba"); // mcr p15, 0, r0, c7, c10, 5
+#elif defined __aarch64__
+ __asm__ volatile(".int 0xd5033bbf"); // dmb ish
+#elif defined __riscv
+ __asm__ volatile(".int 0x0ff0000f"); // fence iorw,iorw
+#endif
+}
+
+bool ATOMIC(is_lock_free) (unsigned long size, const volatile void *ptr)
+{
+ bool ret;
+
+ switch (size) {
+ case 1: ret = true; break;
+ case 2: ret = true; break;
+ case 4: ret = true; break;
+#if defined __x86_64__ || defined __aarch64__ || defined __riscv
+ case 8: ret = true; break;
+#else
+ case 8: ret = false; break;
+#endif
+ default: ret = false; break;
+ }
+ return ret;
+}
+
+#ifndef __TINYC__
+void __atomic_signal_fence(int memorder) __attribute__((alias("__tcc_atomic_signal_fence")));
+void __atomic_thread_fence(int memorder) __attribute__((alias("__tcc_atomic_thread_fence")));
+bool __atomic_is_lock_free(unsigned long size, const volatile void *ptr) __attribute__((alias("__tcc_atomic_is_lock_free")));
+#endif
diff --git a/tinycc/lib/tcov.c b/tinycc/lib/tcov.c
new file mode 100644
index 0000000..32b7d18
--- /dev/null
+++ b/tinycc/lib/tcov.c
@@ -0,0 +1,428 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <errno.h>
+#else
+#include <windows.h>
+#include <io.h>
+#endif
+
+/* section layout (all little endian):
+ 32bit offset to executable/so file name
+ filename \0
+ function name \0
+ align to 64 bits
+ 64bit function start line
+ 64bits end_line(28bits) / start_line(28bits) / flag=0xff(8bits)
+ 64bits counter
+ \0
+ \0
+ \0
+ executable/so file name \0
+ */
+
+typedef struct tcov_line {
+ unsigned int fline;
+ unsigned int lline;
+ unsigned long long count;
+} tcov_line;
+
+typedef struct tcov_function {
+ char *function;
+ unsigned int first_line;
+ unsigned int n_line;
+ unsigned int m_line;
+ tcov_line *line;
+} tcov_function;
+
+typedef struct tcov_file {
+ char *filename;
+ unsigned int n_func;
+ unsigned int m_func;
+ tcov_function *func;
+ struct tcov_file *next;
+} tcov_file;
+
+static FILE *open_tcov_file (char *cov_filename)
+{
+ int fd;
+#ifndef _WIN32
+ struct flock lock;
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0; /* Until EOF. */
+ lock.l_pid = getpid ();
+#endif
+ fd = open (cov_filename, O_RDWR | O_CREAT, 0666);
+ if (fd < 0)
+ return NULL;
+
+#ifndef _WIN32
+ while (fcntl (fd, F_SETLKW, &lock) && errno == EINTR)
+ continue;
+#else
+ {
+ OVERLAPPED overlapped = { 0 };
+ LockFileEx((HANDLE)_get_osfhandle(fd), LOCKFILE_EXCLUSIVE_LOCK,
+ 0, 1, 0, &overlapped);
+ }
+#endif
+
+ return fdopen (fd, "r+");
+}
+
+static unsigned long long get_value(unsigned char *p, int size)
+{
+ unsigned long long value = 0;
+
+ p += size;
+ while (size--)
+ value = (value << 8) | *--p;
+ return value;
+}
+
+static int sort_func (const void *p, const void *q)
+{
+ const tcov_function *pp = (const tcov_function *) p;
+ const tcov_function *pq = (const tcov_function *) q;
+
+ return pp->first_line > pq->first_line ? 1 :
+ pp->first_line < pq->first_line ? -1 : 0;
+}
+
+static int sort_line (const void *p, const void *q)
+{
+ const tcov_line *pp = (const tcov_line *) p;
+ const tcov_line *pq = (const tcov_line *) q;
+
+ return pp->fline > pq->fline ? 1 :
+ pp->fline < pq->fline ? -1 :
+ pp->count < pq->count ? 1 :
+ pp->count > pq->count ? -1 : 0;
+}
+
+/* sort to let inline functions work */
+static tcov_file *sort_test_coverage (unsigned char *p)
+{
+ int i, j, k;
+ unsigned char *start = p;
+ tcov_file *file = NULL;
+ tcov_file *nfile;
+
+ p += 4;
+ while (*p) {
+ char *filename = (char *)p;
+ size_t len = strlen (filename);
+
+ nfile = file;
+ while (nfile) {
+ if (strcmp (nfile->filename, filename) == 0)
+ break;
+ nfile = nfile->next;
+ }
+ if (nfile == NULL) {
+ nfile = malloc (sizeof(tcov_file));
+ if (nfile == NULL) {
+ fprintf (stderr, "Malloc error test_coverage\n");
+ return file;
+ }
+ nfile->filename = filename;
+ nfile->n_func = 0;
+ nfile->m_func = 0;
+ nfile->func = NULL;
+ nfile->next = NULL;
+ if (file == NULL)
+ file = nfile;
+ else {
+ tcov_file *lfile = file;
+
+ while (lfile->next)
+ lfile = lfile->next;
+ lfile->next = nfile;
+ }
+ }
+ p += len + 1;
+ while (*p) {
+ int i;
+ char *function = (char *)p;
+ tcov_function *func;
+
+ p += strlen (function) + 1;
+ p += -(p - start) & 7;
+ for (i = 0; i < nfile->n_func; i++) {
+ func = &nfile->func[i];
+ if (strcmp (func->function, function) == 0)
+ break;
+ }
+ if (i == nfile->n_func) {
+ if (nfile->n_func >= nfile->m_func) {
+ nfile->m_func = nfile->m_func == 0 ? 4 : nfile->m_func * 2;
+ nfile->func = realloc (nfile->func,
+ nfile->m_func *
+ sizeof (tcov_function));
+ if (nfile->func == NULL) {
+ fprintf (stderr, "Realloc error test_coverage\n");
+ return file;
+ }
+ }
+ func = &nfile->func[nfile->n_func++];
+ func->function = function;
+ func->first_line = get_value (p, 8);
+ func->n_line = 0;
+ func->m_line = 0;
+ func->line = NULL;
+ }
+ p += 8;
+ while (*p) {
+ tcov_line *line;
+ unsigned long long val;
+
+ if (func->n_line >= func->m_line) {
+ func->m_line = func->m_line == 0 ? 4 : func->m_line * 2;
+ func->line = realloc (func->line,
+ func->m_line * sizeof (tcov_line));
+ if (func->line == NULL) {
+ fprintf (stderr, "Realloc error test_coverage\n");
+ return file;
+ }
+ }
+ line = &func->line[func->n_line++];
+ val = get_value (p, 8);
+ line->fline = (val >> 8) & 0xfffffffULL;
+ line->lline = val >> 36;
+ line->count = get_value (p + 8, 8);
+ p += 16;
+ }
+ p++;
+ }
+ p++;
+ }
+ nfile = file;
+ while (nfile) {
+ qsort (nfile->func, nfile->n_func, sizeof (tcov_function), sort_func);
+ for (i = 0; i < nfile->n_func; i++) {
+ tcov_function *func = &nfile->func[i];
+ qsort (func->line, func->n_line, sizeof (tcov_line), sort_line);
+ }
+ nfile = nfile->next;
+ }
+ return file;
+}
+
+/* merge with previous tcov file */
+static void merge_test_coverage (tcov_file *file, FILE *fp,
+ unsigned int *pruns)
+{
+ unsigned int runs;
+ char *p;
+ char str[10000];
+
+ *pruns = 1;
+ if (fp == NULL)
+ return;
+ if (fgets(str, sizeof(str), fp) &&
+ (p = strrchr (str, ':')) &&
+ (sscanf (p + 1, "%u", &runs) == 1))
+ *pruns = runs + 1;
+ while (file) {
+ int i;
+ size_t len = strlen (file->filename);
+
+ while (fgets(str, sizeof(str), fp) &&
+ (p = strstr(str, "0:File:")) == NULL) {}
+ if ((p = strstr(str, "0:File:")) == NULL ||
+ strncmp (p + strlen("0:File:"), file->filename, len) != 0 ||
+ p[strlen("0:File:") + len] != ' ')
+ break;
+ for (i = 0; i < file->n_func; i++) {
+ int j;
+ tcov_function *func = &file->func[i];
+ unsigned int next_zero = 0;
+ unsigned int curline = 0;
+
+ for (j = 0; j < func->n_line; j++) {
+ tcov_line *line = &func->line[j];
+ unsigned int fline = line->fline;
+ unsigned long long count;
+ unsigned int tmp;
+ char c;
+
+ while (curline < fline &&
+ fgets(str, sizeof(str), fp))
+ if ((p = strchr(str, ':')) &&
+ sscanf (p + 1, "%u", &tmp) == 1)
+ curline = tmp;
+ if (sscanf (str, "%llu%c\n", &count, &c) == 2) {
+ if (next_zero == 0)
+ line->count += count;
+ next_zero = c == '*';
+ }
+ }
+ }
+ file = file->next;
+ }
+}
+
+/* store tcov data in file */
+void __store_test_coverage (unsigned char * p)
+{
+ int i, j;
+ unsigned int files;
+ unsigned int funcs;
+ unsigned int blocks;
+ unsigned int blocks_run;
+ unsigned int runs;
+ char *cov_filename = (char *)p + get_value (p, 4);
+ FILE *fp;
+ char *q;
+ tcov_file *file;
+ tcov_file *nfile;
+ tcov_function *func;
+
+ fp = open_tcov_file (cov_filename);
+ if (fp == NULL) {
+ fprintf (stderr, "Cannot create coverage file: %s\n", cov_filename);
+ return;
+ }
+ file = sort_test_coverage (p);
+ merge_test_coverage (file, fp, &runs);
+ fseek (fp, 0, SEEK_SET);
+ fprintf (fp, " -: 0:Runs:%u\n", runs);
+ files = 0;
+ funcs = 0;
+ blocks = 0;
+ blocks_run = 0;
+ nfile = file;
+ while (nfile) {
+ files++;
+ for (i = 0; i < nfile->n_func; i++) {
+ func = &nfile->func[i];
+ funcs++;
+ for (j = 0; j < func->n_line; j++) {
+ blocks++;
+ blocks_run += func->line[j].count != 0;
+ }
+ }
+ nfile = nfile->next;
+ }
+ if (blocks == 0)
+ blocks = 1;
+ fprintf (fp, " -: 0:All:%s Files:%u Functions:%u %.02f%%\n",
+ cov_filename, files, funcs, 100.0 * (double) blocks_run / blocks);
+ nfile = file;
+ while (nfile) {
+ FILE *src = fopen (nfile->filename, "r");
+ unsigned int curline = 1;
+ char str[10000];
+
+ if (src == NULL)
+ goto next;
+ funcs = 0;
+ blocks = 0;
+ blocks_run = 0;
+ for (i = 0; i < nfile->n_func; i++) {
+ func = &nfile->func[i];
+ funcs++;
+ for (j = 0; j < func->n_line; j++) {
+ blocks++;
+ blocks_run += func->line[j].count != 0;
+ }
+ }
+ if (blocks == 0)
+ blocks = 1;
+ fprintf (fp, " -: 0:File:%s Functions:%u %.02f%%\n",
+ nfile->filename, funcs, 100.0 * (double) blocks_run / blocks);
+ for (i = 0; i < nfile->n_func; i++) {
+ func = &nfile->func[i];
+
+ while (curline < func->first_line)
+ if (fgets(str, sizeof(str), src))
+ fprintf (fp, " -:%5u:%s", curline++, str);
+ blocks = 0;
+ blocks_run = 0;
+ for (j = 0; j < func->n_line; j++) {
+ blocks++;
+ blocks_run += func->line[j].count != 0;
+ }
+ if (blocks == 0)
+ blocks = 1;
+ fprintf (fp, " -: 0:Function:%s %.02f%%\n",
+ func->function, 100.0 * (double) blocks_run / blocks);
+#if 0
+ for (j = 0; j < func->n_line; j++) {
+ unsigned int fline = func->line[j].fline;
+ unsigned int lline = func->line[j].lline;
+ unsigned long long count = func->line[j].count;
+
+ fprintf (fp, "%u %u %llu\n", fline, lline, count);
+ }
+#endif
+ for (j = 0; j < func->n_line;) {
+ unsigned int fline = func->line[j].fline;
+ unsigned int lline = func->line[j].lline;
+ unsigned long long count = func->line[j].count;
+ unsigned int has_zero = 0;
+ unsigned int same_line = fline == lline;
+
+ j++;
+ while (j < func->n_line) {
+ unsigned int nfline = func->line[j].fline;
+ unsigned int nlline = func->line[j].lline;
+ unsigned long long ncount = func->line[j].count;
+
+ if (fline == nfline) {
+ if (ncount == 0)
+ has_zero = 1;
+ else if (ncount > count)
+ count = ncount;
+ same_line = nfline == nlline;
+ lline = nlline;
+ j++;
+ }
+ else
+ break;
+ }
+ if (same_line)
+ lline++;
+
+ while (curline < fline)
+ if (fgets(str, sizeof(str), src))
+ fprintf (fp, " -:%5u:%s", curline++, str);
+ while (curline < lline &&
+ fgets(str, sizeof(str), src)) {
+ if (count == 0)
+ fprintf (fp, " #####:%5u:%s",
+ curline, str);
+ else if (has_zero)
+ fprintf (fp, "%8llu*:%5u:%s",
+ count, curline, str);
+ else
+ fprintf (fp, "%9llu:%5u:%s",
+ count, curline, str);
+ curline++;
+ }
+ }
+ }
+ while (fgets(str, sizeof(str), src))
+ fprintf (fp, " -:%5u:%s", curline++, str);
+ fclose (src);
+next:
+ nfile = nfile->next;
+ }
+ while (file) {
+ for (i = 0; i < file->n_func; i++) {
+ func = &file->func[i];
+ free (func->line);
+ }
+ free (file->func);
+ nfile = file;
+ file = file->next;
+ free (nfile);
+ }
+ fclose (fp);
+}
diff --git a/tinycc/lib/va_list.c b/tinycc/lib/va_list.c
new file mode 100644
index 0000000..1fb5512
--- /dev/null
+++ b/tinycc/lib/va_list.c
@@ -0,0 +1,67 @@
+/* va_list.c - tinycc support for va_list on X86_64 */
+
+#if defined __x86_64__
+
+/* Avoid include files, they may not be available when cross compiling */
+extern void abort(void);
+
+/* This should be in sync with our include/stdarg.h */
+enum __va_arg_type {
+ __va_gen_reg, __va_float_reg, __va_stack
+};
+
+/* GCC compatible definition of va_list. */
+/*predefined by TCC (tcc_predefs.h):
+typedef struct {
+ unsigned int gp_offset;
+ unsigned int fp_offset;
+ union {
+ unsigned int overflow_offset;
+ char *overflow_arg_area;
+ };
+ char *reg_save_area;
+} __builtin_va_list[1];
+*/
+
+extern void *memcpy(void *dest, const void *src, unsigned long n);
+
+void *__va_arg(__builtin_va_list ap,
+ int arg_type,
+ int size, int align)
+{
+ size = (size + 7) & ~7;
+ align = (align + 7) & ~7;
+ switch ((enum __va_arg_type)arg_type) {
+ case __va_gen_reg:
+ if (ap->gp_offset + size <= 48) {
+ ap->gp_offset += size;
+ return ap->reg_save_area + ap->gp_offset - size;
+ }
+ goto use_overflow_area;
+
+ case __va_float_reg:
+ if (ap->fp_offset < 128 + 48) {
+ ap->fp_offset += 16;
+ if (size == 8)
+ return ap->reg_save_area + ap->fp_offset - 16;
+ if (ap->fp_offset < 128 + 48) {
+ memcpy(ap->reg_save_area + ap->fp_offset - 8,
+ ap->reg_save_area + ap->fp_offset, 8);
+ ap->fp_offset += 16;
+ return ap->reg_save_area + ap->fp_offset - 32;
+ }
+ }
+ goto use_overflow_area;
+
+ case __va_stack:
+ use_overflow_area:
+ ap->overflow_arg_area += size;
+ ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
+ return ap->overflow_arg_area - size;
+
+ default: /* should never happen */
+ abort();
+ return 0;
+ }
+}
+#endif