summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2020-08-14 23:04:13 +0100
committerThomas Preud'homme <robotux@celest.fr>2020-08-14 23:04:13 +0100
commitafd09586d7ead4f146ad7a7a471be34196b3c6bc (patch)
tree87854be29fb4264b979b700fa45445f58faa4c26
parente2ccf3981d78dfeb390d22c74625b60310100abb (diff)
New upstream version 0.9.27+git20200814.62c30a4a
-rw-r--r--.gitignore2
-rw-r--r--Makefile203
-rw-r--r--README4
-rw-r--r--USES20
-rw-r--r--arm-asm.c2
-rw-r--r--arm-gen.c402
-rw-r--r--arm-link.c59
-rw-r--r--arm64-gen.c383
-rw-r--r--arm64-link.c62
-rw-r--r--c67-gen.c69
-rw-r--r--c67-link.c6
-rwxr-xr-xconfigure67
-rw-r--r--conftest.c66
-rw-r--r--elf.h71
-rw-r--r--i386-asm.c5
-rw-r--r--i386-gen.c356
-rw-r--r--i386-link.c19
-rw-r--r--include/float.h21
-rw-r--r--include/stdalign.h16
-rw-r--r--include/stdarg.h75
-rw-r--r--include/stddef.h9
-rw-r--r--include/stdnoreturn.h7
-rw-r--r--lib/Makefile77
-rw-r--r--lib/alloca86-bt.S13
-rw-r--r--lib/alloca86.S9
-rw-r--r--lib/alloca86_64-bt.S47
-rw-r--r--lib/alloca86_64.S10
-rw-r--r--lib/armflush.c8
-rw-r--r--lib/bcheck.c2294
-rw-r--r--lib/bt-dll.c73
-rw-r--r--lib/bt-exe.c43
-rw-r--r--lib/bt-log.c37
-rw-r--r--lib/dsohandle.c1
-rw-r--r--lib/fetch_and_add_arm.S28
-rw-r--r--lib/fetch_and_add_arm64.S22
-rw-r--r--lib/fetch_and_add_riscv64.S16
-rw-r--r--lib/lib-arm64.c17
-rw-r--r--lib/va_list.c20
-rw-r--r--libtcc.c658
-rw-r--r--libtcc.h17
-rw-r--r--riscv64-asm.c94
-rw-r--r--riscv64-gen.c1342
-rw-r--r--riscv64-link.c349
-rw-r--r--tcc-doc.html2489
-rw-r--r--tcc-doc.texi95
-rw-r--r--tcc.c139
-rw-r--r--tcc.h603
-rw-r--r--tccasm.c61
-rw-r--r--tcccoff.c14
-rw-r--r--tccelf.c1171
-rw-r--r--tccgen.c4772
-rw-r--r--tccmacho.c982
-rw-r--r--tccpe.c386
-rw-r--r--tccpp.c469
-rw-r--r--tccrun.c861
-rw-r--r--tcctok.h48
-rw-r--r--tcctools.c22
-rw-r--r--tests/Makefile171
-rw-r--r--tests/asm-c-connect-1.c13
-rw-r--r--tests/asm-c-connect-2.c11
-rw-r--r--tests/boundtest.c61
-rw-r--r--tests/bug.c75
-rw-r--r--[-rwxr-xr-x]tests/gcctestsuite.sh39
-rw-r--r--tests/libtcc_test.c14
-rw-r--r--tests/libtcc_test_mt.c300
-rw-r--r--tests/misc/c2str.c112
-rw-r--r--tests/misc/tcc_predefs.h111
-rw-r--r--tests/pp/Makefile4
-rw-r--r--tests/tcctest.c874
-rw-r--r--tests/tests2/03_struct.c13
-rw-r--r--tests/tests2/03_struct.expect2
-rw-r--r--tests/tests2/07_function.c5
-rw-r--r--tests/tests2/100_c99array-decls.c34
-rw-r--r--tests/tests2/100_c99array-decls.expect0
-rw-r--r--tests/tests2/101_cleanup.c227
-rw-r--r--tests/tests2/101_cleanup.expect59
-rw-r--r--tests/tests2/102_alignas.c29
-rw-r--r--tests/tests2/102_alignas.expect1
-rw-r--r--tests/tests2/103_implicit_memmove.c20
-rw-r--r--tests/tests2/103_implicit_memmove.expect0
-rw-r--r--tests/tests2/104+_inline.c54
-rw-r--r--tests/tests2/104_inline.c132
-rw-r--r--tests/tests2/104_inline.expect39
-rw-r--r--tests/tests2/105_local_extern.c12
-rw-r--r--tests/tests2/105_local_extern.expect2
-rw-r--r--tests/tests2/106_pthread.c17
-rw-r--r--tests/tests2/106_pthread.expect1
-rw-r--r--tests/tests2/107_stack_safe.c13
-rw-r--r--tests/tests2/107_stack_safe.expect1
-rw-r--r--tests/tests2/108_constructor.c20
-rw-r--r--tests/tests2/108_constructor.expect3
-rw-r--r--tests/tests2/109_float_struct_calling.c24
-rw-r--r--tests/tests2/109_float_struct_calling.expect1
-rw-r--r--tests/tests2/110_average.c27
-rw-r--r--tests/tests2/110_average.expect1
-rw-r--r--tests/tests2/111_conversion.c22
-rw-r--r--tests/tests2/111_conversion.expect1
-rw-r--r--tests/tests2/112_backtrace.c165
-rw-r--r--tests/tests2/112_backtrace.expect142
-rw-r--r--tests/tests2/113_btdll.c43
-rw-r--r--tests/tests2/113_btdll.expect6
-rw-r--r--tests/tests2/114_bound_signal.c110
-rw-r--r--tests/tests2/114_bound_signal.expect2
-rw-r--r--tests/tests2/115_bound_setjmp.c169
-rw-r--r--tests/tests2/115_bound_setjmp.expect0
-rw-r--r--tests/tests2/116_bound_setjmp2.c84
-rw-r--r--tests/tests2/116_bound_setjmp2.expect0
-rw-r--r--tests/tests2/117_gcc_test.c158
-rw-r--r--tests/tests2/117_gcc_test.expect0
-rw-r--r--tests/tests2/11_precedence.c3
-rw-r--r--tests/tests2/22_floating_point.c13
-rw-r--r--tests/tests2/33_ternary_op.c67
-rw-r--r--tests/tests2/33_ternary_op.expect2
-rw-r--r--tests/tests2/46_grep.c4
-rw-r--r--tests/tests2/60_errors_and_warnings.c298
-rw-r--r--tests/tests2/60_errors_and_warnings.expect136
-rw-r--r--tests/tests2/61_integers.c70
-rw-r--r--tests/tests2/61_integers.expect56
-rw-r--r--tests/tests2/73_arm64.c11
-rw-r--r--tests/tests2/81_types.c12
-rw-r--r--tests/tests2/82_attribs_position.c48
-rw-r--r--tests/tests2/82_attribs_position.expect2
-rw-r--r--tests/tests2/85_asm-outside-function.c8
-rw-r--r--tests/tests2/87_dead_code.c33
-rw-r--r--tests/tests2/87_dead_code.expect5
-rw-r--r--tests/tests2/88_codeopt.c3
-rw-r--r--tests/tests2/90_struct-init.c20
-rw-r--r--tests/tests2/90_struct-init.expect5
-rw-r--r--tests/tests2/92_enum_bitfield.c1
-rw-r--r--tests/tests2/94_generic.c51
-rw-r--r--tests/tests2/94_generic.expect3
-rw-r--r--tests/tests2/95_bitfields.c23
-rw-r--r--tests/tests2/95_bitfields.expect24
-rw-r--r--tests/tests2/95_bitfields_ms.expect24
-rw-r--r--tests/tests2/96_nodata_wanted.c24
-rw-r--r--tests/tests2/96_nodata_wanted.expect5
-rw-r--r--tests/tests2/98_al_ax_extend.c2
-rw-r--r--tests/tests2/99_fastcall.c2
-rw-r--r--tests/tests2/Makefile76
-rw-r--r--[-rwxr-xr-x]win32/build-tcc.bat380
-rw-r--r--win32/include/_mingw.h12
-rw-r--r--win32/include/assert.h5
-rw-r--r--win32/include/iso646.h36
-rw-r--r--win32/include/math.h52
-rw-r--r--win32/include/sys/stat.h4
-rwxr-xr-xwin32/include/uchar.h33
-rw-r--r--win32/include/winapi/qos.h72
-rw-r--r--win32/include/winapi/windows.h2
-rw-r--r--win32/include/winapi/winnls.h778
-rw-r--r--win32/include/winapi/winnt.h14
-rw-r--r--win32/include/winapi/winsock2.h1474
-rw-r--r--win32/include/winapi/ws2ipdef.h21
-rw-r--r--win32/include/winapi/ws2tcpip.h391
-rw-r--r--win32/lib/chkstk.S142
-rw-r--r--win32/lib/crt1.c22
-rw-r--r--win32/lib/crtinit.c26
-rw-r--r--win32/lib/dllcrt1.c13
-rw-r--r--win32/lib/msvcrt.def259
-rw-r--r--win32/lib/wincrt1.c15
-rw-r--r--win32/lib/ws2_32.def198
-rw-r--r--win32/tcc-win32.txt336
-rw-r--r--win32/tccwin32.sh8
-rw-r--r--win32/tccwin64.sh8
-rw-r--r--win32/tccwin_build.sh39
-rw-r--r--x86_64-gen.c531
-rw-r--r--x86_64-link.c29
166 files changed, 19708 insertions, 8858 deletions
diff --git a/.gitignore b/.gitignore
index c989b6b..c473264 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,8 +50,10 @@ tests/*.gcc
tests/*-cc*
tests/*-tcc*
tests/libtcc_test
+tests/libtcc_test_mt
tests/asm-c-connect
tests/asm-c-connect-sep
tests/vla_test
tests/hello
tests/tests2/fred.txt
+libtcc.dylib
diff --git a/Makefile b/Makefile
index 3ae466f..ca5fae4 100644
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,11 @@ ifndef TOP
INCLUDED = no
endif
-include $(TOP)/config.mak
+ifeq ($(findstring $(MAKECMDGOALS),clean distclean),)
+ include $(TOP)/config.mak
+endif
-ifeq (-$(CC)-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-gcc-4--)
+ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
CFLAGS += -D_FORTIFY_SOURCE=0
endif
@@ -23,14 +25,15 @@ CFLAGS += $(CPPFLAGS)
VPATH = $(TOPSRC)
ifdef CONFIG_WIN32
+ CFG = -win
ifneq ($(CONFIG_static),yes)
LIBTCC = libtcc$(DLLSUF)
LIBTCCDEF = libtcc.def
endif
- CFGWIN = -win
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
else
- LIBS=-lm
+ CFG = -unx
+ LIBS=-lm -lpthread
ifneq ($(CONFIG_ldl),no)
LIBS+=-ldl
endif
@@ -39,26 +42,38 @@ else
LIBTCC=libtcc$(DLLSUF)
export LD_LIBRARY_PATH := $(CURDIR)/$(TOP)
ifneq ($(CONFIG_rpath),no)
- LINK_LIBTCC += -Wl,-rpath,"$(libdir)"
+ ifndef CONFIG_OSX
+ LINK_LIBTCC += -Wl,-rpath,"$(libdir)"
+ else
+ # macOS doesn't support env-vars libdir out of the box - which we need for
+ # `make test' when libtcc.dylib is used (configure --disable-static), so
+ # we bake a relative path into the binary. $libdir is used after install.
+ LINK_LIBTCC += -Wl,-rpath,"@executable_path/$(TOP)" -Wl,-rpath,"$(libdir)"
+ DYLIBVER += -current_version $(VERSION)
+ DYLIBVER += -compatibility_version $(VERSION)
+ endif
endif
endif
- CFGWIN =-unx
NATIVE_TARGET = $(ARCH)
ifdef CONFIG_OSX
NATIVE_TARGET = $(ARCH)-osx
- LDFLAGS += -flat_namespace -undefined warning
- export MACOSX_DEPLOYMENT_TARGET := 10.2
+ ifneq ($(CC_NAME),tcc)
+ LDFLAGS += -flat_namespace -undefined warning
+ endif
+ export MACOSX_DEPLOYMENT_TARGET := 10.6
endif
endif
# run local version of tcc with local libraries and includes
TCCFLAGS-unx = -B$(TOP) -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP)
TCCFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP) -L$(TOP)
-TCCFLAGS = $(TCCFLAGS$(CFGWIN))
+TCCFLAGS = $(TCCFLAGS$(CFG))
TCC = $(TOP)/tcc$(EXESUF) $(TCCFLAGS)
-ifdef CONFIG_OSX
- TCCFLAGS += -D_ANSI_SOURCE
-endif
+
+# cross compiler targets to build
+TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
+TCC_X += riscv64
+# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
LIBS_P = $(LIBS)
@@ -78,6 +93,7 @@ NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
+NATIVE_DEFINES_$(CONFIG_riscv64) += -DTCC_TARGET_RISCV64
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
ifeq ($(INCLUDED),no)
@@ -85,17 +101,14 @@ ifeq ($(INCLUDED),no)
# running top Makefile
PROGS = tcc$(EXESUF)
-TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
+TCCLIBS = $(LIBTCCDEF) $(LIBTCC) $(LIBTCC1)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
-# cross compiler targets to build
-TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
-# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
-
# cross libtcc1.a targets to build
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
+LIBTCC1_X += riscv64
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
@@ -106,9 +119,9 @@ cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
# build specific cross compiler & lib
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
-install: ; @$(MAKE) --no-print-directory install$(CFGWIN)
-install-strip: ; @$(MAKE) --no-print-directory install$(CFGWIN) CONFIG_strip=yes
-uninstall: ; @$(MAKE) --no-print-directory uninstall$(CFGWIN)
+install: ; @$(MAKE) --no-print-directory install$(CFG)
+install-strip: ; @$(MAKE) --no-print-directory install$(CFG) CONFIG_strip=yes
+uninstall: ; @$(MAKE) --no-print-directory uninstall$(CFG)
ifdef CONFIG_cross
all : cross
@@ -125,7 +138,7 @@ DEF-i386-win32 = -DTCC_TARGET_PE -DTCC_TARGET_I386
DEF-x86_64-win32= -DTCC_TARGET_PE -DTCC_TARGET_X86_64
DEF-x86_64-osx = -DTCC_TARGET_MACHO -DTCC_TARGET_X86_64
DEF-arm-wince = -DTCC_TARGET_PE -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DTCC_ARM_HARDFLOAT
-DEF-arm64 = -DTCC_TARGET_ARM64
+DEF-arm64 = -DTCC_TARGET_ARM64 -Wno-format
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
DEF-arm-fpa = -DTCC_TARGET_ARM
DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
@@ -133,6 +146,7 @@ DEF-arm-vfp = -DTCC_TARGET_ARM -DTCC_ARM_VFP
DEF-arm-eabi = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI
DEF-arm-eabihf = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
DEF-arm = $(DEF-arm-eabihf)
+DEF-riscv64 = -DTCC_TARGET_RISCV64
DEF-$(NATIVE_TARGET) = $(NATIVE_DEFINES)
DEFINES += $(DEF-$T) $(DEF-all)
@@ -161,11 +175,18 @@ i386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok
i386-win32_FILES = $(i386_FILES) tccpe.c
x86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h
x86_64-win32_FILES = $(x86_64_FILES) tccpe.c
-x86_64-osx_FILES = $(x86_64_FILES)
+x86_64-osx_FILES = $(x86_64_FILES) tccmacho.c
arm_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c
arm-wince_FILES = $(arm_FILES) tccpe.c
-arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
+arm-eabihf_FILES = $(arm_FILES)
+arm-fpa_FILES = $(arm_FILES)
+arm-fpa-ld_FILES = $(arm_FILES)
+arm-vfp_FILES = $(arm_FILES)
+arm-eabi_FILES = $(arm_FILES)
+arm-eabihf_FILES = $(arm_FILES)
+arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm-asm.c
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
+riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c riscv64-asm.c
# libtcc sources
LIBTCC_SRC = $(filter-out tcc.c tcctools.c,$(filter %.c,$($T_FILES)))
@@ -182,72 +203,94 @@ TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
$(TCC_FILES) : DEFINES += -DONE_SOURCE=0
endif
+ifeq ($(CONFIG_strip),no)
+CFLAGS += -g
+LDFLAGS += -g
+else
+CONFIG_strip = yes
+ifndef CONFIG_OSX
+LDFLAGS += -s
+endif
+endif
+
# target specific object rule
$(X)%.o : %.c $(LIBTCC_INC)
- $(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
+ $S$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
# additional dependencies
$(X)tcc.o : tcctools.c
# Host Tiny C Compiler
tcc$(EXESUF): tcc.o $(LIBTCC)
- $(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
+ $S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
# Cross Tiny C Compilers
%-tcc$(EXESUF): FORCE
@$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
- $(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
+ $S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
# profiling version
tcc_p$(EXESUF): $($T_FILES)
- $(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
+ $S$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
# static libtcc library
libtcc.a: $(LIBTCC_OBJ)
- $(AR) rcs $@ $^
+ $S$(AR) rcs $@ $^
# dynamic libtcc library
libtcc.so: $(LIBTCC_OBJ)
- $(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
+ $S$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
libtcc.so: CFLAGS+=-fPIC
libtcc.so: LDFLAGS+=-fPIC
+# OSX dynamic libtcc library
+libtcc.dylib: $(LIBTCC_OBJ)
+ $S$(CC) -dynamiclib $(DYLIBVER) -install_name @rpath/$@ -o $@ $^ $(LDFLAGS)
+
+# OSX libtcc.dylib (without rpath/ prefix)
+libtcc.osx: $(LIBTCC_OBJ)
+ $S$(CC) -shared -install_name libtcc.dylib -o libtcc.dylib $^ $(LDFLAGS)
+
# windows dynamic libtcc library
libtcc.dll : $(LIBTCC_OBJ)
- $(CC) -shared -o $@ $^ $(LDFLAGS)
+ $S$(CC) -shared -o $@ $^ $(LDFLAGS)
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
# import file for windows libtcc.dll
libtcc.def : libtcc.dll tcc$(EXESUF)
- $(XTCC) -impdef $< -o $@
+ $S$(XTCC) -impdef $< -o $@
XTCC ?= ./tcc$(EXESUF)
# TinyCC runtime libraries
libtcc1.a : tcc$(EXESUF) FORCE
- @$(MAKE) -C lib DEFINES='$(DEF-$T)'
+ @$(MAKE) -C lib
# Cross libtcc1.a
%-libtcc1.a : %-tcc$(EXESUF) FORCE
- @$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
+ @$(MAKE) -C lib CROSS_TARGET=$*
.PRECIOUS: %-libtcc1.a
FORCE:
+run-if = $(if $(shell which $1),$S $1 $2)
+S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
+
# --------------------------------------------------------------------------
# documentation and man page
tcc-doc.html: tcc-doc.texi
- makeinfo --no-split --html --number-sections -o $@ $< || true
-
-tcc.1: tcc-doc.texi
- $(TOPSRC)/texi2pod.pl $< tcc.pod \
- && pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod >tmp.1 \
- && mv tmp.1 $@ || rm -f tmp.1
+ $(call run-if,makeinfo,--no-split --html --number-sections -o $@ $<)
tcc-doc.info: tcc-doc.texi
- makeinfo $< || true
+ $(call run-if,makeinfo,$< || true)
+
+tcc.1 : tcc-doc.pod
+ $(call run-if,pod2man,--section=1 --center="Tiny C Compiler" \
+ --release="$(VERSION)" $< >$@ && rm -f $<)
+%.pod : %.texi
+ $(call run-if,perl,$(TOPSRC)/texi2pod.pl $< $@)
# --------------------------------------------------------------------------
# install
@@ -258,16 +301,19 @@ STRIP_yes = -s
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS))
-IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2)
+IB = $(if $1,$(IM) mkdir -p $2 && $(INSTALLBIN) $1 $2)
IBw = $(call IB,$(wildcard $1),$2)
-IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
+IF = $(if $1,$(IM) mkdir -p $2 && $(INSTALL) $1 $2)
IFw = $(call IF,$(wildcard $1),$2)
-IR = mkdir -p $2 && cp -r $1/. $2
+IR = $(IM) mkdir -p $2 && cp -r $1/. $2
+IM = $(info -> $2 : $1)@
+
+B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
# install progs & libs
install-unx:
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
- $(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
+ $(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
@@ -283,16 +329,16 @@ endif
# uninstall
uninstall-unx:
@rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS),"$(bindir)/$P")
- @rm -fv "$(libdir)/libtcc.a" "$(libdir)/libtcc.so" "$(includedir)/libtcc.h"
+ @rm -fv "$(libdir)/libtcc.a" "$(libdir)/libtcc.so" "$(libdir)/libtcc.dylib" "$(includedir)/libtcc.h"
@rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
@rm -fv "$(docdir)/tcc-doc.html"
- rm -r "$(tccdir)"
+ @rm -frv "$(tccdir)"
# install progs & libs on windows
install-win:
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
- $(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib")
+ $(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
@@ -305,17 +351,16 @@ ifneq "$(wildcard $(LIBTCC1_U))" ""
endif
# the msys-git shell works to configure && make except it does not have install
-ifeq "$(and $(CONFIG_WIN32),$(shell which install >/dev/null 2>&1 || echo no))" "no"
+ifeq ($(CONFIG_WIN32)-$(shell which install || echo no),yes-no)
install-win : INSTALL = cp
install-win : INSTALLBIN = cp
endif
# uninstall on windows
uninstall-win:
- @rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS) libtcc.dll,"$(bindir)/$P")
- @rm -fv $(foreach F,tcc-doc.html tcc-win32.txt,"$(docdir)/$F")
- @rm -fv $(foreach F,libtcc.h libtcc.def libtcc.a,"$(libdir)/$F")
- rm -r "$(tccdir)"
+ @rm -fv $(foreach P,libtcc.dll $(PROGS) *-tcc.exe,"$(bindir)"/$P)
+ @rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P"/*)
+ @rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P")
# --------------------------------------------------------------------------
# other stuff
@@ -328,8 +373,9 @@ ETAGS : ; etags $(TAGFILES)
# create release tarball from *current* git branch (including tcc-doc.html
# and converting two files to CRLF)
TCC-VERSION = tcc-$(VERSION)
+TCC-VERSION = tinycc-mob-$(shell git rev-parse --short=7 HEAD)
tar: tcc-doc.html
- mkdir $(TCC-VERSION)
+ mkdir -p $(TCC-VERSION)
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
cp tcc-doc.html $(TCC-VERSION)
for f in tcc-win32.txt build-tcc.bat ; do \
@@ -344,19 +390,22 @@ config.mak:
# run all tests
test:
- $(MAKE) -C tests
+ @$(MAKE) -C tests
# run test(s) from tests2 subdir (see make help)
tests2.%:
- $(MAKE) -C tests/tests2 $@
+ @$(MAKE) -C tests/tests2 $@
+
+testspp.%:
+ @$(MAKE) -C tests/pp $@
clean:
- rm -f tcc$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) tcc.pod
- rm -f *~ *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out tags TAGS
- @$(MAKE) -C lib $@
- @$(MAKE) -C tests $@
+ @rm -f tcc$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) tcc.pod
+ @rm -f *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out tags TAGS *.dylib
+ @$(MAKE) -s -C lib $@
+ @$(MAKE) -s -C tests $@
distclean: clean
- rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
+ @rm -fv config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
.PHONY: all clean test tar tags ETAGS distclean install uninstall FORCE
@@ -367,37 +416,37 @@ help:
@echo "make cross"
@echo " build cross compilers (from one source)"
@echo ""
- @echo "make ONE_SOURCE=yes / no"
- @echo " force building from one source / separate objects"
+ @echo "make ONE_SOURCE=no/yes SILENT=no/yes"
+ @echo " force building from separate/one object(s), less/more silently"
@echo ""
@echo "make cross-TARGET"
- @echo " build one specific cross compiler for 'TARGET', as in"
- @echo " $(TCC_X)"
+ @echo " build one specific cross compiler for 'TARGET'. Currently supported:"
+ @echo " $(wordlist 1,6,$(TCC_X))"
+ @echo " $(wordlist 7,99,$(TCC_X))"
+ @echo ""
+ @echo "make test"
+ @echo " run all tests"
+ @echo ""
+ @echo "make tests2.all / make tests2.37 / make tests2.37+"
+ @echo " run all/single test(s) from tests2, optionally update .expect"
+ @echo ""
+ @echo "make testspp.all / make testspp.17"
+ @echo " run all/single test(s) from tests/pp"
+ @echo ""
+ @echo "Other supported make targets:"
+ @echo " install install-strip doc clean tags ETAGS tar distclean help"
@echo ""
@echo "Custom configuration:"
@echo " The makefile includes a file 'config-extra.mak' if it is present."
@echo " This file may contain some custom configuration. For example:"
- @echo ""
@echo " NATIVE_DEFINES += -D..."
- @echo ""
@echo " Or for example to configure the search paths for a cross-compiler"
@echo " that expects the linux files in <tccdir>/i386-linux:"
- @echo ""
@echo " ROOT-i386 = {B}/i386-linux"
@echo " CRT-i386 = {B}/i386-linux/usr/lib"
@echo " LIB-i386 = {B}/i386-linux/lib:{B}/i386-linux/usr/lib"
@echo " INC-i386 = {B}/lib/include:{B}/i386-linux/usr/include"
@echo " DEF-i386 += -D__linux__"
- @echo ""
- @echo "make test"
- @echo " run all tests"
- @echo ""
- @echo "make tests2.all / make tests2.37 / make tests2.37+"
- @echo " run all/single test(s) from tests2, optionally update .expect"
- @echo ""
- @echo "Other supported make targets:"
- @echo " install install-strip tags ETAGS tar clean distclean help"
- @echo ""
# --------------------------------------------------------------------------
endif # ($(INCLUDED),no)
diff --git a/README b/README
index 3a3f90b..d1d34d2 100644
--- a/README
+++ b/README
@@ -12,14 +12,14 @@ Features:
-O0'.
- UNLIMITED! Any C dynamic library can be used directly. TCC is
- heading torward full ISOC99 compliance. TCC can of course compile
+ heading toward full ISOC99 compliance. TCC can of course compile
itself.
- SAFE! tcc includes an optional memory and bound checker. Bound
checked code can be mixed freely with standard code.
- Compile and execute C source directly. No linking or assembly
- necessary. Full C preprocessor included.
+ necessary. Full C preprocessor included.
- C script supported : just add '#!/usr/local/bin/tcc -run' at the first
line of your C source, and execute it directly from the command
diff --git a/USES b/USES
new file mode 100644
index 0000000..6d7a2d1
--- /dev/null
+++ b/USES
@@ -0,0 +1,20 @@
+The following software are known to use or support tcc builds.
+Feel free to complete this list (*).
+
+Name Short Description
+---- -----------------
+bigz An infinite precision Z & Q library.
+gawk GNU awk.
+gmp Library for arbitrary precision arithmetic.
+gnumake GNU makefile.
+mpfr Multiple-precision floating-point library.
+mpc Complex floating-point library with exact rounding.
+mpv A free, open source, and cross-platform media player.
+openlisp ISLISP ISO/IEC 13816 Lisp interpreter and compiler.
+s-nail BSD Mail/POSIX mailx: send and receive Internet mail.
+sqlite Embbedable SQL engine.
+st Simple Terminal.
+tcc Tiny CC which compiles itself.
+zlib Lossless data-compression library.
+
+(*) This list is ordered by name.
diff --git a/arm-asm.c b/arm-asm.c
index 3b5ae66..f09f003 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -16,7 +16,7 @@ ST_FUNC void gen_le32(int c);
/*************************************************************/
#else
/*************************************************************/
-
+#define USING_GLOBALS
#include "tcc.h"
static void asm_error(void)
diff --git a/arm-gen.c b/arm-gen.c
index f535a09..784b236 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -59,7 +59,7 @@
#define RC_F7 0x4000
#endif
#define RC_IRET RC_R0 /* function return: integer register */
-#define RC_LRET RC_R1 /* function return: second integer register */
+#define RC_IRE2 RC_R1 /* function return: second integer register */
#define RC_FRET RC_F0 /* function return: float register */
/* pretty names for the registers */
@@ -89,7 +89,7 @@ enum {
/* return registers for function */
#define REG_IRET TREG_R0 /* single word int return register */
-#define REG_LRET TREG_R1 /* second word return register (for long long) */
+#define REG_IRE2 TREG_R1 /* second word return register (for long long) */
#define REG_FRET TREG_F0 /* float return register */
#ifdef TCC_ARM_EABI
@@ -132,6 +132,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
+#define USING_GLOBALS
#include "tcc.h"
enum float_abi float_abi;
@@ -157,6 +158,12 @@ ST_DATA const int reg_classes[NB_REGS] = {
static int func_sub_sp_offset, last_itod_magic;
static int leaffunc;
+#if defined(CONFIG_TCC_BCHECK)
+static addr_t func_bound_offset;
+static unsigned long func_bound_ind;
+ST_DATA int func_bound_add_epilog;
+#endif
+
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
static CType float_type, double_type, func_float_type, func_double_type;
ST_FUNC void arm_init(struct TCCState *s)
@@ -170,7 +177,7 @@ ST_FUNC void arm_init(struct TCCState *s)
float_abi = s->float_abi;
#ifndef TCC_ARM_HARDFLOAT
- tcc_warning("soft float ABI currently not supported: default to softfp");
+# warning "soft float ABI currently not supported: default to softfp"
#endif
}
#else
@@ -192,11 +199,17 @@ ST_FUNC void arm_init(struct TCCState *s)
}
#endif
+#define CHECK_R(r) ((r) >= TREG_R0 && (r) <= TREG_LR)
+
static int two2mask(int a,int b) {
+ if (!CHECK_R(a) || !CHECK_R(b))
+ tcc_error("compiler error! registers %i,%i is not valid",a,b);
return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
}
static int regmask(int r) {
+ if (!CHECK_R(r))
+ tcc_error("compiler error! register %i is not valid",r);
return reg_classes[r]&~(RC_INT|RC_FLOAT);
}
@@ -382,11 +395,6 @@ void gsym_addr(int t, int a)
}
}
-void gsym(int t)
-{
- gsym_addr(t, ind);
-}
-
#ifdef TCC_ARM_VFP
static uint32_t vfpr(int r)
{
@@ -409,9 +417,9 @@ static uint32_t intr(int r)
return 12;
if(r >= TREG_R0 && r <= TREG_R3)
return r - TREG_R0;
- if (r >= TREG_SP && r <= TREG_LR)
- return r + (13 - TREG_SP);
- tcc_error("compiler error! register %i is no int register",r);
+ if (!(r >= TREG_SP && r <= TREG_LR))
+ tcc_error("compiler error! register %i is no int register",r);
+ return r + (13 - TREG_SP);
}
static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift)
@@ -739,27 +747,33 @@ static void gadd_sp(int val)
static void gcall_or_jmp(int is_jmp)
{
int r;
+ uint32_t x;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
- uint32_t x;
/* constant case */
- x=encbranch(ind,ind+vtop->c.i,0);
- if(x) {
- if (vtop->r & VT_SYM) {
- /* relocation case */
- greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
- } else
- put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
- o(x|(is_jmp?0xE0000000:0xE1000000));
- } else {
- if(!is_jmp)
- o(0xE28FE004); // add lr,pc,#4
- o(0xE51FF004); // ldr pc,[pc,#-4]
- if (vtop->r & VT_SYM)
- greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
- o(vtop->c.i);
- }
+ if(vtop->r & VT_SYM){
+ x=encbranch(ind,ind+vtop->c.i,0);
+ if(x) {
+ /* relocation case */
+ greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
+ o(x|(is_jmp?0xE0000000:0xE1000000));
+ } else {
+ if(!is_jmp)
+ o(0xE28FE004); // add lr,pc,#4
+ o(0xE51FF004); // ldr pc,[pc,#-4]
+ greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
+ o(vtop->c.i);
+ }
+ }else{
+ if(!is_jmp)
+ o(0xE28FE004); // add lr,pc,#4
+ o(0xE51FF004); // ldr pc,[pc,#-4]
+ o(vtop->c.i);
+ }
} else {
/* otherwise, indirect call */
+#ifdef CONFIG_TCC_BCHECK
+ vtop->r &= ~VT_MUSTBOUND;
+#endif
r = gv(RC_INT);
if(!is_jmp)
o(0xE1A0E00F); // mov lr,pc
@@ -767,6 +781,70 @@ static void gcall_or_jmp(int is_jmp)
}
}
+#if defined(CONFIG_TCC_BCHECK)
+
+static void gen_bounds_call(int v)
+{
+ Sym *sym = external_global_sym(v, &func_old_type);
+
+ greloc(cur_text_section, sym, ind, R_ARM_PC24);
+ o(0xebfffffe);
+}
+
+static void gen_bounds_prolog(void)
+{
+ /* leave some room for bound checking code */
+ func_bound_offset = lbounds_section->data_offset;
+ func_bound_ind = ind;
+ func_bound_add_epilog = 0;
+ o(0xe1a00000); /* ld r0,lbounds_section->data_offset */
+ o(0xe1a00000);
+ o(0xe1a00000);
+ o(0xe1a00000); /* call __bound_local_new */
+}
+
+static void gen_bounds_epilog(void)
+{
+ addr_t saved_ind;
+ addr_t *bounds_ptr;
+ Sym *sym_data;
+ int offset_modified = func_bound_offset != lbounds_section->data_offset;
+
+ if (!offset_modified && !func_bound_add_epilog)
+ return;
+
+ /* add end of table info */
+ bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
+ *bounds_ptr = 0;
+
+ sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
+ func_bound_offset, lbounds_section->data_offset);
+
+ /* generate bound local allocation */
+ if (offset_modified) {
+ saved_ind = ind;
+ ind = func_bound_ind;
+ o(0xe59f0000); /* ldr r0, [pc] */
+ o(0xea000000); /* b $+4 */
+ greloc(cur_text_section, sym_data, ind, R_ARM_ABS32);
+ o(0x00000000); /* lbounds_section->data_offset */
+ gen_bounds_call(TOK___bound_local_new);
+ ind = saved_ind;
+ }
+
+ /* generate bound check local freeing */
+ o(0xe92d0003); /* push {r0,r1} */
+ o(0xed2d0b02); /* vpush {d0} */
+ o(0xe59f0000); /* ldr r0, [pc] */
+ o(0xea000000); /* b $+4 */
+ greloc(cur_text_section, sym_data, ind, R_ARM_ABS32);
+ o(0x00000000); /* lbounds_section->data_offset */
+ gen_bounds_call(TOK___bound_local_delete);
+ o(0xecbd0b02); /* vpop {d0} */
+ o(0xe8bd0003); /* pop {r0,r1} */
+}
+#endif
+
static int unalias_ldbl(int btype)
{
#if LDOUBLE_SIZE == 8
@@ -788,10 +866,12 @@ static int is_hgen_float_aggr(CType *type)
int btype, nb_fields = 0;
ref = type->ref->next;
- btype = unalias_ldbl(ref->type.t & VT_BTYPE);
- if (btype == VT_FLOAT || btype == VT_DOUBLE) {
- for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
- return !ref && nb_fields <= 4;
+ if (ref) {
+ btype = unalias_ldbl(ref->type.t & VT_BTYPE);
+ if (btype == VT_FLOAT || btype == VT_DOUBLE) {
+ for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
+ return !ref && nb_fields <= 4;
+ }
}
}
return 0;
@@ -804,8 +884,6 @@ struct avail_regs {
int first_free_reg; /* next free register in the sequence, hole excluded */
};
-#define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
-
/* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
param) according to the rules described in the procedure call standard for
the ARM architecture (AAPCS). If found, the registers are assigned to this
@@ -880,7 +958,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int
ret->ref = NULL;
ret->t = VT_DOUBLE;
return (size + 7) >> 3;
- } else if (size <= 4) {
+ } else if (size > 0 && size <= 4) {
*ret_align = 4;
*regsize = 4;
ret->ref = NULL;
@@ -921,14 +999,16 @@ struct param_plan {
struct plan {
struct param_plan *pplans; /* array of all the param plans */
struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */
+ int nb_plans;
};
-#define add_param_plan(plan,pplan,class) \
- do { \
- pplan.prev = plan->clsplans[class]; \
- plan->pplans[plan ## _nb] = pplan; \
- plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \
- } while(0)
+static void add_param_plan(struct plan* plan, int cls, int start, int end, SValue *v)
+{
+ struct param_plan *p = &plan->pplans[plan->nb_plans++];
+ p->prev = plan->clsplans[cls];
+ plan->clsplans[cls] = p;
+ p->start = start, p->end = end, p->sval = v;
+}
/* Assign parameters to registers and stack with alignment according to the
rules in the procedure call standard for the ARM architecture (AAPCS).
@@ -951,14 +1031,11 @@ static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
{
int i, size, align;
int ncrn /* next core register number */, nsaa /* next stacked argument address*/;
- int plan_nb = 0;
- struct param_plan pplan;
- struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
+ struct avail_regs avregs = {{0}};
ncrn = nsaa = 0;
*todo = 0;
- plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans));
- memset(plan->clsplans, 0, sizeof(plan->clsplans));
+
for(i = nb_args; i-- ;) {
int j, start_vfpreg = 0;
CType type = vtop[-i].type;
@@ -981,11 +1058,8 @@ static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
start_vfpreg = assign_vfpreg(&avregs, align, size);
end_vfpreg = start_vfpreg + ((size - 1) >> 2);
if (start_vfpreg >= 0) {
- pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]};
- if (is_hfa)
- add_param_plan(plan, pplan, VFP_STRUCT_CLASS);
- else
- add_param_plan(plan, pplan, VFP_CLASS);
+ add_param_plan(plan, is_hfa ? VFP_STRUCT_CLASS : VFP_CLASS,
+ start_vfpreg, end_vfpreg, &vtop[-i]);
continue;
} else
break;
@@ -998,8 +1072,7 @@ static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
* CORE_STRUCT_CLASS or the first of STACK_CLASS. */
for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
*todo|=(1<<j);
- pplan = (struct param_plan) {ncrn, j, &vtop[-i]};
- add_param_plan(plan, pplan, CORE_STRUCT_CLASS);
+ add_param_plan(plan, CORE_STRUCT_CLASS, ncrn, j, &vtop[-i]);
ncrn += size/4;
if (ncrn > 4)
nsaa = (ncrn - 4) * 4;
@@ -1017,24 +1090,18 @@ static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
if (ncrn == 4)
break;
}
- pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]};
- ncrn++;
- if (is_long)
- pplan.end = ncrn++;
- add_param_plan(plan, pplan, CORE_CLASS);
+ add_param_plan(plan, CORE_CLASS, ncrn, ncrn + is_long, &vtop[-i]);
+ ncrn += 1 + is_long;
continue;
}
}
nsaa = (nsaa + (align - 1)) & ~(align - 1);
- pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]};
- add_param_plan(plan, pplan, STACK_CLASS);
+ add_param_plan(plan, STACK_CLASS, nsaa, nsaa + size, &vtop[-i]);
nsaa += size; /* size already rounded up before */
}
return nsaa;
}
-#undef add_param_plan
-
/* Copy parameters to their final destination (core reg, VFP reg or stack) for
function call.
@@ -1138,7 +1205,7 @@ again:
/* XXX: implicit cast ? */
size=4;
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
- lexpand_nr();
+ lexpand();
size = 8;
r = gv(RC_INT);
o(0xE52D0004|(intr(r)<<12)); /* push r */
@@ -1162,7 +1229,7 @@ again:
case CORE_CLASS:
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
- lexpand_nr();
+ lexpand();
gv(regmask(pplan->end));
pplan->sval->r2 = vtop->r;
vtop--;
@@ -1216,10 +1283,16 @@ void gfunc_call(int nb_args)
int def_float_abi = float_abi;
int todo;
struct plan plan;
-
#ifdef TCC_ARM_EABI
int variadic;
+#endif
+
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gbound_args(nb_args);
+#endif
+#ifdef TCC_ARM_EABI
if (float_abi == ARM_HARD_FLOAT) {
variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS);
if (variadic || floats_in_core_regs(&vtop[-nb_args]))
@@ -1233,6 +1306,10 @@ void gfunc_call(int nb_args)
if (r == VT_CMP || (r & ~1) == VT_JMP)
gv(RC_INT);
+ memset(&plan, 0, sizeof plan);
+ if (nb_args)
+ plan.pplans = tcc_malloc(nb_args * sizeof(*plan.pplans));
+
args_size = assign_regs(nb_args, float_abi, &plan, &todo);
#ifdef TCC_ARM_EABI
@@ -1266,20 +1343,19 @@ void gfunc_call(int nb_args)
}
/* generate function prolog of type 't' */
-void gfunc_prolog(CType *func_type)
+void gfunc_prolog(Sym *func_sym)
{
+ CType *func_type = &func_sym->type;
Sym *sym,*sym2;
int n, nf, size, align, rs, struct_ret = 0;
int addr, pn, sn; /* pn=core, sn=stack */
CType ret_type;
#ifdef TCC_ARM_EABI
- struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
+ struct avail_regs avregs = {{0}};
#endif
sym = func_type->ref;
- func_vt = sym->type;
- func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS);
n = nf = 0;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
@@ -1327,7 +1403,7 @@ void gfunc_prolog(CType *func_type)
#ifdef TCC_ARM_EABI
if (float_abi == ARM_HARD_FLOAT) {
func_vc += nf * 4;
- avregs = AVAIL_REGS_INITIALIZER;
+ memset(&avregs, 0, sizeof avregs);
}
#endif
pn = struct_ret, sn = 0;
@@ -1363,12 +1439,16 @@ from_stack:
addr = (n + nf + sn) * 4;
sn += size;
}
- sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t),
+ sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL,
addr + 12);
}
last_itod_magic=0;
leaffunc = 1;
loc = 0;
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_prolog();
+#endif
}
/* generate function epilog */
@@ -1376,6 +1456,11 @@ void gfunc_epilog(void)
{
uint32_t x;
int diff;
+
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_epilog();
+#endif
/* Copy float return value to core register if base standard is used and
float computation is made with VFP */
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
@@ -1410,8 +1495,18 @@ void gfunc_epilog(void)
}
}
+ST_FUNC void gen_fill_nops(int bytes)
+{
+ if ((bytes & 3))
+ tcc_error("alignment of code section not multiple of 4");
+ while (bytes > 0) {
+ o(0xE1A00000);
+ bytes -= 4;
+ }
+}
+
/* generate a jump to a label */
-int gjmp(int t)
+ST_FUNC int gjmp(int t)
{
int r;
if (nocode_wanted)
@@ -1422,51 +1517,37 @@ int gjmp(int t)
}
/* generate a jump to a fixed address */
-void gjmp_addr(int a)
+ST_FUNC void gjmp_addr(int a)
{
gjmp(a);
}
-/* generate a test. set 'inv' to invert test. Stack entry is popped */
-int gtst(int inv, int t)
+ST_FUNC int gjmp_cond(int op, int t)
{
- int v, r;
- uint32_t op;
-
- v = vtop->r & VT_VALMASK;
+ int r;
+ if (nocode_wanted)
+ return t;
r=ind;
+ op=mapcc(op);
+ op|=encbranch(r,t,1);
+ o(op);
+ return r;
+}
- if (nocode_wanted) {
- ;
- } else if (v == VT_CMP) {
- op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
- op|=encbranch(r,t,1);
- o(op);
- t=r;
- } else if (v == VT_JMP || v == VT_JMPI) {
- if ((v & 1) == inv) {
- if(!vtop->c.i)
- vtop->c.i=t;
- else {
- uint32_t *x;
- int p,lp;
- if(t) {
- p = vtop->c.i;
- do {
- p = decbranch(lp=p);
- } while(p);
- x = (uint32_t *)(cur_text_section->data + lp);
- *x &= 0xff000000;
- *x |= encbranch(lp,t,1);
- }
- t = vtop->c.i;
- }
- } else {
- t = gjmp(t);
- gsym(vtop->c.i);
- }
+ST_FUNC int gjmp_append(int n, int t)
+{
+ uint32_t *x;
+ int p,lp;
+ if(n) {
+ p = n;
+ do {
+ p = decbranch(lp=p);
+ } while(p);
+ x = (uint32_t *)(cur_text_section->data + lp);
+ *x &= 0xff000000;
+ *x |= encbranch(lp,t,1);
+ t = n;
}
- vtop--;
return t;
}
@@ -1546,7 +1627,7 @@ void gen_opi(int op)
case '%':
#ifdef TCC_ARM_EABI
func=TOK___aeabi_idivmod;
- retreg=REG_LRET;
+ retreg=REG_IRE2;
#else
func=TOK___modsi3;
#endif
@@ -1555,7 +1636,7 @@ void gen_opi(int op)
case TOK_UMOD:
#ifdef TCC_ARM_EABI
func=TOK___aeabi_uidivmod;
- retreg=REG_LRET;
+ retreg=REG_IRE2;
#else
func=TOK___umodsi3;
#endif
@@ -1588,10 +1669,10 @@ void gen_opi(int op)
vswap();
c=intr(gv(RC_INT));
vswap();
- opc=0xE0000000|(opc<<20)|(c<<16);
+ opc=0xE0000000|(opc<<20);
if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
uint32_t x;
- x=stuff_const(opc|0x2000000,vtop->c.i);
+ x=stuff_const(opc|0x2000000|(c<<16),vtop->c.i);
if(x) {
r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
o(x|(r<<12));
@@ -1599,14 +1680,17 @@ void gen_opi(int op)
}
}
fr=intr(gv(RC_INT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ c=intr(gv(RC_INT));
+ vswap();
+ }
r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
- o(opc|(r<<12)|fr);
+ o(opc|(c<<16)|(r<<12)|fr);
done:
vtop--;
- if (op >= TOK_ULT && op <= TOK_GT) {
- vtop->r = VT_CMP;
- vtop->c.i = op;
- }
+ if (op >= TOK_ULT && op <= TOK_GT)
+ vset_VT_CMP(op);
break;
case 2:
opc=0xE1A00000|(opc<<5);
@@ -1616,15 +1700,19 @@ done:
vswap();
r=intr(gv(RC_INT));
vswap();
- opc|=r;
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
c = vtop->c.i & 0x1f;
- o(opc|(c<<7)|(fr<<12));
+ o(opc|r|(c<<7)|(fr<<12));
} else {
fr=intr(gv(RC_INT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=intr(gv(RC_INT));
+ vswap();
+ }
c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
- o(opc|(c<<12)|(fr<<8)|0x10);
+ o(opc|r|(c<<12)|(fr<<8)|0x10);
}
vtop--;
break;
@@ -1709,9 +1797,9 @@ void gen_opf(int op)
vtop--;
o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
} else {
- x|=vfpr(gv(RC_FLOAT));
- vswap();
- o(x|(vfpr(gv(RC_FLOAT))<<12));
+ gv2(RC_FLOAT,RC_FLOAT);
+ x|=vfpr(vtop[0].r);
+ o(x|(vfpr(vtop[-1].r) << 12));
vtop--;
}
o(0xEEF1FA10); /* fmstat */
@@ -1722,9 +1810,7 @@ void gen_opf(int op)
case TOK_UGE: op=TOK_GE; break;
case TOK_UGT: op=TOK_GT; break;
}
-
- vtop->r = VT_CMP;
- vtop->c.i = op;
+ vset_VT_CMP(op);
return;
}
r=gv(RC_FLOAT);
@@ -1736,6 +1822,12 @@ void gen_opf(int op)
r2=gv(RC_FLOAT);
x|=vfpr(r2)<<16;
r|=regmask(r2);
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=gv(RC_FLOAT);
+ vswap();
+ x=(x&~0xf)|vfpr(r);
+ }
}
vtop->r=get_reg_ex(RC_FLOAT,r);
if(!fneg)
@@ -1818,6 +1910,11 @@ void gen_opf(int op)
r2=c2&0xf;
} else {
r2=fpr(gv(RC_FLOAT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=fpr(gv(RC_FLOAT));
+ vswap();
+ }
}
break;
case '-':
@@ -1839,6 +1936,11 @@ void gen_opf(int op)
r=fpr(gv(RC_FLOAT));
vswap();
r2=fpr(gv(RC_FLOAT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=fpr(gv(RC_FLOAT));
+ vswap();
+ }
}
break;
case '*':
@@ -1851,8 +1953,14 @@ void gen_opf(int op)
vswap();
if(c2 && c2<=0xf)
r2=c2;
- else
+ else {
r2=fpr(gv(RC_FLOAT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=fpr(gv(RC_FLOAT));
+ vswap();
+ }
+ }
x|=0x100000; // muf
break;
case '/':
@@ -1873,6 +1981,11 @@ void gen_opf(int op)
r=fpr(gv(RC_FLOAT));
vswap();
r2=fpr(gv(RC_FLOAT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=fpr(gv(RC_FLOAT));
+ vswap();
+ }
}
break;
default:
@@ -1925,9 +2038,15 @@ void gen_opf(int op)
r2=c2&0xf;
} else {
r2=fpr(gv(RC_FLOAT));
+ if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+ vswap();
+ r=fpr(gv(RC_FLOAT));
+ vswap();
+ }
}
- vtop[-1].r = VT_CMP;
- vtop[-1].c.i = op;
+ --vtop;
+ vset_VT_CMP(op);
+ ++vtop;
} else {
tcc_error("unknown fp op %x!",op);
return;
@@ -1949,7 +2068,7 @@ void gen_opf(int op)
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
and 'long long' cases. */
-ST_FUNC void gen_cvt_itof1(int t)
+ST_FUNC void gen_cvt_itof(int t)
{
uint32_t r, r2;
int bt;
@@ -2082,7 +2201,7 @@ void gen_cvt_ftoi(int t)
gfunc_call(1);
vpushi(0);
if(t == VT_LLONG)
- vtop->r2 = REG_LRET;
+ vtop->r2 = REG_IRE2;
vtop->r = REG_IRET;
return;
}
@@ -2130,7 +2249,12 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
- int r = intr(gv(RC_INT));
+ int r;
+#if defined(CONFIG_TCC_BCHECK)
+ if (tcc_state->do_bounds_check)
+ vpushv(vtop);
+#endif
+ r = intr(gv(RC_INT));
o(0xE04D0000|(r<<12)|r); /* sub r, sp, r */
#ifdef TCC_ARM_EABI
if (align < 8)
@@ -2143,6 +2267,18 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) {
tcc_error("alignment is not a power of 2: %i", align);
o(stuff_const(0xE3C0D000|(r<<16), align - 1)); /* bic sp, r, #align-1 */
vpop();
+#if defined(CONFIG_TCC_BCHECK)
+ if (tcc_state->do_bounds_check) {
+ vpushi(0);
+ vtop->r = TREG_R0;
+ o(0xe1a0000d | (vtop->r << 12)); // mov r0,sp
+ vswap();
+ vpush_global_sym(&func_old_type, TOK___bound_new_region);
+ vrott(3);
+ gfunc_call(2);
+ func_bound_add_epilog = 1;
+ }
+#endif
}
/* end of ARM code generator */
diff --git a/arm-link.c b/arm-link.c
index 92a24eb..c75eeb7 100644
--- a/arm-link.c
+++ b/arm-link.c
@@ -16,7 +16,7 @@
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 1
-#define RELOCATE_DLLPLT 0
+#define RELOCATE_DLLPLT 1
enum float_abi {
ARM_SOFTFP_FLOAT,
@@ -57,8 +57,6 @@ int code_reloc (int reloc_type)
case R_ARM_JUMP_SLOT:
return 1;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -97,11 +95,10 @@ int gotplt_entry_type (int reloc_type)
case R_ARM_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
+#ifndef TCC_TARGET_PE
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
@@ -110,8 +107,6 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
/* when building a DLL, GOT entry accesses must be done relative to
start of GOT (see x86_64 example above) */
- if (s1->output_type == TCC_OUTPUT_DLL)
- tcc_error("DLLs unimplemented!");
/* empty PLT: create PLT0 entry that push address of call site and
jump to ld.so resolution routine (GOT + 8) */
@@ -130,13 +125,9 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
}
- p = section_ptr_add(plt, 16);
- /* Jump to GOT entry where ld.so initially put address of PLT0 */
- write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */
- write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */
- write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */
- /* p + 12 contains offset to GOT entry once patched by relocate_plt */
- write32le(p+12, got_offset);
+ p = section_ptr_add(plt, 12);
+ /* save GOT offset for relocate_plt */
+ write32le(p + 4, got_offset);
return plt_offset;
}
@@ -157,20 +148,22 @@ ST_FUNC void relocate_plt(TCCState *s1)
write32le(s1->plt->data + 16, x - 16);
p += 20;
while (p < p_end) {
+ unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4;
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
p += 4;
- add32le(p + 12, x + s1->plt->data - p);
- p += 16;
+ write32le(p, 0xe28fc600 | ((off >> 20) & 0xff)); // add ip, pc, #0xNN00000
+ write32le(p + 4, 0xe28cca00 | ((off >> 12) & 0xff)); // add ip, ip, #0xNN000
+ write32le(p + 8, 0xe5bcf000 | (off & 0xfff)); // ldr pc, [ip, #0xNNN]!
+ p += 12;
}
}
}
-
-void relocate_init(Section *sr) {}
+#endif
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
ElfW(Sym) *sym;
- int sym_index;
+ int sym_index, esym_index;
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@@ -254,24 +247,24 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
int index;
uint8_t *p;
char *name, buf[1024];
- Section *text_section;
+ Section *text;
name = (char *) symtab_section->link->data + sym->st_name;
- text_section = s1->sections[sym->st_shndx];
+ text = s1->sections[sym->st_shndx];
/* Modify reloc to target a thumb stub to switch to ARM */
snprintf(buf, sizeof(buf), "%s_from_thumb", name);
index = put_elf_sym(symtab_section,
- text_section->data_offset + 1,
+ text->data_offset + 1,
sym->st_size, sym->st_info, 0,
sym->st_shndx, buf);
to_thumb = 1;
- val = text_section->data_offset + 1;
+ val = text->data_offset + 1;
rel->r_info = ELFW(R_INFO)(index, type);
/* Create a thumb stub function to switch to ARM mode */
- put_elf_reloc(symtab_section, text_section,
- text_section->data_offset + 4, R_ARM_JUMP24,
+ put_elf_reloc(symtab_section, text,
+ text->data_offset + 4, R_ARM_JUMP24,
sym_index);
- p = section_ptr_add(text_section, 8);
+ p = section_ptr_add(text, 8);
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
write32le(p+4, 0xeafffffe); /* b $sym */
@@ -352,6 +345,18 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
(*(int *)ptr) |= x & 0x7fffffff;
}
case R_ARM_ABS32:
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
+ qrel->r_offset = rel->r_offset;
+ if (esym_index) {
+ qrel->r_info = ELFW(R_INFO)(esym_index, R_ARM_ABS32);
+ qrel++;
+ return;
+ } else {
+ qrel->r_info = ELFW(R_INFO)(0, R_ARM_RELATIVE);
+ qrel++;
+ }
+ }
*(int *)ptr += val;
return;
case R_ARM_REL32:
@@ -365,7 +370,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
return;
case R_ARM_GOT32:
/* we load the got offset */
- *(int *)ptr += s1->sym_attrs[sym_index].got_offset;
+ *(int *)ptr += get_sym_attr(s1, sym_index, 0)->got_offset;
return;
case R_ARM_COPY:
return;
diff --git a/arm64-gen.c b/arm64-gen.c
index 86b3af7..bb352ad 100644
--- a/arm64-gen.c
+++ b/arm64-gen.c
@@ -40,9 +40,13 @@
#define CHAR_IS_UNSIGNED
+/* define if return values need to be extended explicitely
+ at caller side (for interfacing with non-TCC compilers) */
+#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
+#define USING_GLOBALS
#include "tcc.h"
#include <assert.h>
@@ -77,6 +81,12 @@ ST_DATA const int reg_classes[NB_REGS] = {
RC_FLOAT | RC_F(7)
};
+#if defined(CONFIG_TCC_BCHECK)
+static addr_t func_bound_offset;
+static unsigned long func_bound_ind;
+ST_DATA int func_bound_add_epilog;
+#endif
+
#define IS_FREG(x) ((x) >= TREG_F(0))
static uint32_t intr(int r)
@@ -236,25 +246,24 @@ ST_FUNC void gsym_addr(int t_, int a_)
}
}
-// Patch all branches in list pointed to by t to branch to current location:
-ST_FUNC void gsym(int t)
-{
- gsym_addr(t, ind);
-}
-
static int arm64_type_size(int t)
{
+ /*
+ * case values are in increasing order (from 1 to 11).
+ * which 'may' help compiler optimizers. See tcc.h
+ */
switch (t & VT_BTYPE) {
- case VT_INT: return 2;
case VT_BYTE: return 0;
case VT_SHORT: return 1;
+ case VT_INT: return 2;
+ case VT_LLONG: return 3;
case VT_PTR: return 3;
case VT_FUNC: return 3;
+ case VT_STRUCT: return 3;
case VT_FLOAT: return 2;
case VT_DOUBLE: return 3;
case VT_LDOUBLE: return 4;
case VT_BOOL: return 0;
- case VT_LLONG: return 3;
}
assert(0);
return 0;
@@ -274,6 +283,23 @@ static void arm64_spoff(int reg, uint64_t off)
}
}
+/* invert 0: return value to use for store/load */
+/* invert 1: return value to use for arm64_sym */
+static uint64_t arm64_check_offset(int invert, int sz_, uint64_t off)
+{
+ uint32_t sz = sz_;
+ if (!(off & ~((uint32_t)0xfff << sz)) ||
+ (off < 256 || -off <= 256))
+ return invert ? off : 0ul;
+ else if ((off & ((uint32_t)0xfff << sz)))
+ return invert ? off & ((uint32_t)0xfff << sz)
+ : off & ~((uint32_t)0xfff << sz);
+ else if (off & 0x1ff)
+ return invert ? off & 0x1ff : off & ~0x1ff;
+ else
+ return invert ? 0ul : off;
+}
+
static void arm64_ldrx(int sg, int sz_, int dst, int bas, uint64_t off)
{
uint32_t sz = sz_;
@@ -314,6 +340,9 @@ static void arm64_ldrs(int reg_, int size)
// Use x30 for intermediate value in some cases.
switch (size) {
default: assert(0); break;
+ case 0:
+ /* Can happen with zero size structs */
+ break;
case 1:
arm64_ldrx(0, 0, reg, reg, 0);
break;
@@ -420,36 +449,36 @@ static void arm64_strv(int sz_, int dst, int bas, uint64_t off)
static void arm64_sym(int r, Sym *sym, unsigned long addend)
{
- // Currently TCC's linker does not generate COPY relocations for
- // STT_OBJECTs when tcc is invoked with "-run". This typically
- // results in "R_AARCH64_ADR_PREL_PG_HI21 relocation failed" when
- // a program refers to stdin. A workaround is to avoid that
- // relocation and use only relocations with unlimited range.
- int avoid_adrp = 1;
-
- if (avoid_adrp || sym->a.weak) {
- // (GCC uses a R_AARCH64_ABS64 in this case.)
- greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend);
- o(0xd2800000 | r); // mov x(rt),#0,lsl #0
- greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G1_NC, addend);
- o(0xf2a00000 | r); // movk x(rt),#0,lsl #16
- greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G2_NC, addend);
- o(0xf2c00000 | r); // movk x(rt),#0,lsl #32
- greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend);
- o(0xf2e00000 | r); // movk x(rt),#0,lsl #48
- }
- else {
- greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, addend);
- o(0x90000000 | r);
- greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend);
- o(0x91000000 | r | r << 5);
+ greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
+ o(0x90000000 | r); // adrp xr, #sym
+ greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
+ o(0xf9400000 | r | (r << 5)); // ld xr,[xr, #sym]
+ if (addend) {
+ // add xr, xr, #addend
+ if (addend & 0xffful)
+ o(0x91000000 | r | r << 5 | (addend & 0xfff) << 10);
+ if (addend > 0xffful) {
+ // add xr, xr, #addend, lsl #12
+ if (addend & 0xfff000ul)
+ o(0x91400000 | r | r << 5 | ((addend >> 12) & 0xfff) << 10);
+ if (addend > 0xfffffful) {
+ /* very unlikely */
+ int t = r ? 0 : 1;
+ o(0xf81f0fe0 | t); /* str xt, [sp, #-16]! */
+ arm64_movimm(t, addend & ~0xfffffful); // use xt for addent
+ o(0x91000000 | r | (t << 5)); /* add xr, xt, #0 */
+ o(0xf84107e0 | t); /* ldr xt, [sp], #16 */
+ }
+ }
}
}
+static void arm64_load_cmp(int r, SValue *sv);
+
ST_FUNC void load(int r, SValue *sv)
{
int svtt = sv->type.t;
- int svr = sv->r & ~VT_LVAL_TYPE;
+ int svr = sv->r & ~VT_BOUNDED;
int svrv = svr & VT_VALMASK;
uint64_t svcul = (uint32_t)sv->c.i;
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
@@ -463,22 +492,38 @@ ST_FUNC void load(int r, SValue *sv)
return;
}
- if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
+ if (svr == (VT_CONST | VT_LVAL)) {
+ arm64_sym(30, sv->sym, // use x30 for address
+ arm64_check_offset(0, arm64_type_size(svtt), sv->c.i));
if (IS_FREG(r))
- arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
+ arm64_ldrv(arm64_type_size(svtt), fltr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), sv->c.i));
else
- arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
- intr(r), intr(svrv), 0);
+ arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), intr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), sv->c.i));
+ return;
+ }
+
+ if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
+ if ((svtt & VT_BTYPE) != VT_VOID) {
+ if (IS_FREG(r))
+ arm64_ldrv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
+ else
+ arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
+ intr(r), intr(svrv), 0);
+ }
return;
}
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
- arm64_sym(30, sv->sym, svcul); // use x30 for address
+ arm64_sym(30, sv->sym, // use x30 for address
+ arm64_check_offset(0, arm64_type_size(svtt), svcul));
if (IS_FREG(r))
- arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, 0);
+ arm64_ldrv(arm64_type_size(svtt), fltr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), svcul));
else
- arm64_ldrx(!(svtt & VT_UNSIGNED), arm64_type_size(svtt),
- intr(r), 30, 0);
+ arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt), intr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), svcul));
return;
}
@@ -537,6 +582,11 @@ ST_FUNC void load(int r, SValue *sv)
return;
}
+ if (svr == VT_CMP) {
+ arm64_load_cmp(r, sv);
+ return;
+ }
+
printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul);
assert(0);
}
@@ -544,7 +594,7 @@ ST_FUNC void load(int r, SValue *sv)
ST_FUNC void store(int r, SValue *sv)
{
int svtt = sv->type.t;
- int svr = sv->r & ~VT_LVAL_TYPE;
+ int svr = sv->r & ~VT_BOUNDED;
int svrv = svr & VT_VALMASK;
uint64_t svcul = (uint32_t)sv->c.i;
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
@@ -557,6 +607,18 @@ ST_FUNC void store(int r, SValue *sv)
return;
}
+ if (svr == (VT_CONST | VT_LVAL)) {
+ arm64_sym(30, sv->sym, // use x30 for address
+ arm64_check_offset(0, arm64_type_size(svtt), sv->c.i));
+ if (IS_FREG(r))
+ arm64_strv(arm64_type_size(svtt), fltr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), sv->c.i));
+ else
+ arm64_strx(arm64_type_size(svtt), intr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), sv->c.i));
+ return;
+ }
+
if ((svr & ~VT_VALMASK) == VT_LVAL && svrv < VT_CONST) {
if (IS_FREG(r))
arm64_strv(arm64_type_size(svtt), fltr(r), intr(svrv), 0);
@@ -566,11 +628,14 @@ ST_FUNC void store(int r, SValue *sv)
}
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
- arm64_sym(30, sv->sym, svcul); // use x30 for address
+ arm64_sym(30, sv->sym, // use x30 for address
+ arm64_check_offset(0, arm64_type_size(svtt), svcul));
if (IS_FREG(r))
- arm64_strv(arm64_type_size(svtt), fltr(r), 30, 0);
+ arm64_strv(arm64_type_size(svtt), fltr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), svcul));
else
- arm64_strx(arm64_type_size(svtt), intr(r), 30, 0);
+ arm64_strx(arm64_type_size(svtt), intr(r), 30,
+ arm64_check_offset(1, arm64_type_size(svtt), svcul));
return;
}
@@ -580,15 +645,83 @@ ST_FUNC void store(int r, SValue *sv)
static void arm64_gen_bl_or_b(int b)
{
- if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
- assert(!b && (vtop->r & VT_SYM));
- greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0);
- o(0x94000000); // bl .
+ if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
+ greloca(cur_text_section, vtop->sym, ind,
+ b ? R_AARCH64_JUMP26 : R_AARCH64_CALL26, 0);
+ o(0x14000000 | (uint32_t)!b << 31); // b/bl .
}
- else
+ else {
+#ifdef CONFIG_TCC_BCHECK
+ vtop->r &= ~VT_MUSTBOUND;
+#endif
o(0xd61f0000 | (uint32_t)!b << 21 | intr(gv(RC_R30)) << 5); // br/blr
+ }
+}
+
+#if defined(CONFIG_TCC_BCHECK)
+
+static void gen_bounds_call(int v)
+{
+ Sym *sym = external_global_sym(v, &func_old_type);
+
+ greloca(cur_text_section, sym, ind, R_AARCH64_CALL26, 0);
+ o(0x94000000); // bl
}
+static void gen_bounds_prolog(void)
+{
+ /* leave some room for bound checking code */
+ func_bound_offset = lbounds_section->data_offset;
+ func_bound_ind = ind;
+ func_bound_add_epilog = 0;
+ o(0xd503201f); /* nop -> mov x0, lbound section pointer */
+ o(0xd503201f);
+ o(0xd503201f);
+ o(0xd503201f); /* nop -> call __bound_local_new */
+}
+
+static void gen_bounds_epilog(void)
+{
+ addr_t saved_ind;
+ addr_t *bounds_ptr;
+ Sym *sym_data;
+ int offset_modified = func_bound_offset != lbounds_section->data_offset;
+
+ if (!offset_modified && !func_bound_add_epilog)
+ return;
+
+ /* add end of table info */
+ bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
+ *bounds_ptr = 0;
+
+ sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
+ func_bound_offset, lbounds_section->data_offset);
+
+ /* generate bound local allocation */
+ if (offset_modified) {
+ saved_ind = ind;
+ ind = func_bound_ind;
+ greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0);
+ o(0x90000000 | 0); // adrp x0, #sym_data
+ greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
+ o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data]
+ gen_bounds_call(TOK___bound_local_new);
+ ind = saved_ind;
+ }
+
+ /* generate bound check local freeing */
+ o(0xf81f0fe0); /* str x0, [sp, #-16]! */
+ o(0x3c9f0fe0); /* str q0, [sp, #-16]! */
+ greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0);
+ o(0x90000000 | 0); // adrp x0, #sym_data
+ greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
+ o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data]
+ gen_bounds_call(TOK___bound_local_delete);
+ o(0x3cc107e0); /* ldr q0, [sp], #16 */
+ o(0xf84107e0); /* ldr x0, [sp], #16 */
+}
+#endif
+
static int arm64_hfa_aux(CType *type, int *fsize, int num)
{
if (is_float(type->t)) {
@@ -632,7 +765,7 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
return num;
}
}
- else if (type->t & VT_ARRAY) {
+ else if ((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR)) {
int num1;
if (!type->ref->c)
return num;
@@ -647,9 +780,10 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
return -1;
}
-static int arm64_hfa(CType *type, int *fsize)
+static int arm64_hfa(CType *type, unsigned *fsize)
{
- if ((type->t & VT_BTYPE) == VT_STRUCT || (type->t & VT_ARRAY)) {
+ if ((type->t & VT_BTYPE) == VT_STRUCT ||
+ ((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR))) {
int sz = 0;
int n = arm64_hfa_aux(type, &sz, 0);
if (0 < n && n <= 4) {
@@ -829,6 +963,11 @@ ST_FUNC void gfunc_call(int nb_args)
unsigned long stack;
int i;
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gbound_args(nb_args);
+#endif
+
return_type = &vtop[-nb_args].type.ref->type;
if ((return_type->t & VT_BTYPE) == VT_STRUCT)
--nb_args;
@@ -856,9 +995,12 @@ ST_FUNC void gfunc_call(int nb_args)
stack = (stack + 15) >> 4 << 4;
- assert(stack < 0x1000);
- if (stack)
- o(0xd10003ff | stack << 10); // sub sp,sp,#(n)
+ if (stack >= 0x1000000) // 16Mb
+ tcc_error("stack size too big %lu", stack);
+ if (stack & 0xfff)
+ o(0xd10003ff | (stack & 0xfff) << 10); // sub sp,sp,#(n)
+ if (stack >> 12)
+ o(0xd14003ff | (stack >> 12) << 10);
// First pass: set all values on stack
for (i = nb_args; i; i--) {
@@ -951,17 +1093,15 @@ ST_FUNC void gfunc_call(int nb_args)
save_regs(0);
arm64_gen_bl_or_b(0);
--vtop;
- if (stack)
- o(0x910003ff | stack << 10); // add sp,sp,#(n)
+ if (stack & 0xfff)
+ o(0x910003ff | (stack & 0xfff) << 10); // add sp,sp,#(n)
+ if (stack >> 12)
+ o(0x914003ff | (stack >> 12) << 10);
{
int rt = return_type->t;
int bt = rt & VT_BTYPE;
- if (bt == VT_BYTE || bt == VT_SHORT)
- // Promote small integers:
- o(0x13001c00 | (bt == VT_SHORT) << 13 |
- (uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0
- else if (bt == VT_STRUCT && !(a[0] & 1)) {
+ if (bt == VT_STRUCT && !(a[0] & 1)) {
// A struct was returned in registers, so write it out:
gv(RC_R(8));
--vtop;
@@ -995,22 +1135,21 @@ static int arm64_func_va_list_gr_offs;
static int arm64_func_va_list_vr_offs;
static int arm64_func_sub_sp_offset;
-ST_FUNC void gfunc_prolog(CType *func_type)
+ST_FUNC void gfunc_prolog(Sym *func_sym)
{
+ CType *func_type = &func_sym->type;
int n = 0;
int i = 0;
Sym *sym;
CType **t;
unsigned long *a;
- // Why doesn't the caller (gen_function) set func_vt?
- func_vt = func_type->ref->type;
func_vc = 144; // offset of where x8 is stored
for (sym = func_type->ref; sym; sym = sym->next)
++n;
- t = tcc_malloc(n * sizeof(*t));
- a = tcc_malloc(n * sizeof(*a));
+ t = n ? tcc_malloc(n * sizeof(*t)) : NULL;
+ a = n ? tcc_malloc(n * sizeof(*a)) : NULL;
for (sym = func_type->ref; sym; sym = sym->next)
t[i++] = &sym->type;
@@ -1036,7 +1175,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
224 + ((a[i] - 32) >> 1 << 1));
sym_push(sym->v & ~SYM_FIELD, &sym->type,
- (a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t),
+ (a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
off);
if (a[i] < 16) {
@@ -1071,6 +1210,10 @@ ST_FUNC void gfunc_prolog(CType *func_type)
o(0xd503201f); // nop
o(0xd503201f); // nop
loc = 0;
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_prolog();
+#endif
}
ST_FUNC void gen_va_start(void)
@@ -1112,7 +1255,7 @@ ST_FUNC void gen_va_start(void)
ST_FUNC void gen_va_arg(CType *t)
{
int align, size = type_size(t, &align);
- int fsize, hfa = arm64_hfa(t, &fsize);
+ unsigned fsize, hfa = arm64_hfa(t, &fsize);
uint32_t r0, r1;
if (is_float(t->t)) {
@@ -1123,7 +1266,7 @@ ST_FUNC void gen_va_arg(CType *t)
gaddrof();
r0 = intr(gv(RC_INT));
r1 = get_reg(RC_INT);
- vtop[0].r = r1 | lvalue_type(t->t);
+ vtop[0].r = r1 | VT_LVAL;
r1 = intr(r1);
if (!hfa) {
@@ -1241,6 +1384,11 @@ ST_FUNC void gfunc_return(CType *func_type)
ST_FUNC void gfunc_epilog(void)
{
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_epilog();
+#endif
+
if (loc) {
// Insert instructions to subtract size of stack frame from SP.
unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset;
@@ -1276,6 +1424,16 @@ ST_FUNC void gfunc_epilog(void)
o(0xd65f03c0); // ret
}
+ST_FUNC void gen_fill_nops(int bytes)
+{
+ if ((bytes & 3))
+ tcc_error("alignment of code section not multiple of 4");
+ while (bytes > 0) {
+ o(0xd503201f); // nop
+ bytes -= 4;
+ }
+}
+
// Generate forward branch to label:
ST_FUNC int gjmp(int t)
{
@@ -1293,9 +1451,50 @@ ST_FUNC void gjmp_addr(int a)
o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
}
-ST_FUNC int gtst(int inv, int t)
+ST_FUNC int gjmp_append(int n, int t)
+{
+ void *p;
+ /* insert vtop->c jump list in t */
+ if (n) {
+ uint32_t n1 = n, n2;
+ while ((n2 = read32le(p = cur_text_section->data + n1)))
+ n1 = n2;
+ write32le(p, t);
+ t = n;
+ }
+ return t;
+}
+
+void arm64_vset_VT_CMP(int op)
+{
+ if (op >= TOK_ULT && op <= TOK_GT) {
+ vtop->cmp_r = vtop->r;
+ vset_VT_CMP(0x80);
+ }
+}
+
+static void arm64_gen_opil(int op, uint32_t l);
+
+static void arm64_load_cmp(int r, SValue *sv)
+{
+ sv->r = sv->cmp_r;
+ if (sv->c.i & 1) {
+ vpushi(1);
+ arm64_gen_opil('^', 0);
+ }
+ if (r != sv->r) {
+ load(r, sv);
+ sv->r = r;
+ }
+}
+
+ST_FUNC int gjmp_cond(int op, int t)
{
int bt = vtop->type.t & VT_BTYPE;
+
+ int inv = op & 1;
+ vtop->r = vtop->cmp_r;
+
if (bt == VT_LDOUBLE) {
uint32_t a, b, f = fltr(gv(RC_FLOAT));
a = get_reg(RC_INT);
@@ -1320,7 +1519,6 @@ ST_FUNC int gtst(int inv, int t)
uint32_t a = intr(gv(RC_INT));
o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8
}
- --vtop;
return gjmp(t);
}
@@ -1399,8 +1597,11 @@ static int arm64_gen_opic(int op, uint32_t l, int rev, uint64_t val,
val = val & (n - 1);
if (rev)
return 0;
- if (!val)
- assert(0);
+ if (!val) {
+ // tcc_warning("shift count >= width of type");
+ o(0x2a0003e0 | l << 31 | a << 16);
+ return 1;
+ }
else if (op == TOK_SHL)
o(0x53000000 | l << 31 | l << 22 | x | a << 5 |
(n - val) << 16 | (n - 1 - val) << 10); // lsl
@@ -1549,11 +1750,13 @@ static void arm64_gen_opil(int op, uint32_t l)
ST_FUNC void gen_opi(int op)
{
arm64_gen_opil(op, 0);
+ arm64_vset_VT_CMP(op);
}
ST_FUNC void gen_opl(int op)
{
arm64_gen_opil(op, 1);
+ arm64_vset_VT_CMP(op);
}
ST_FUNC void gen_opf(int op)
@@ -1653,6 +1856,7 @@ ST_FUNC void gen_opf(int op)
default:
assert(0);
}
+ arm64_vset_VT_CMP(op);
}
// Generate sign extension from 32 to 64 bits:
@@ -1662,6 +1866,16 @@ ST_FUNC void gen_cvt_sxtw(void)
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
}
+/* char/short to int conversion */
+ST_FUNC void gen_cvt_csti(int t)
+{
+ int r = intr(gv(RC_INT));
+ o(0x13001c00
+ | ((t & VT_BTYPE) == VT_SHORT) << 13
+ | (uint32_t)!!(t & VT_UNSIGNED) << 30
+ | r | r << 5); // [su]xt[bh] w(r),w(r)
+}
+
ST_FUNC void gen_cvt_itof(int t)
{
if (t == VT_LDOUBLE) {
@@ -1721,7 +1935,7 @@ ST_FUNC void gen_cvt_ftoi(int t)
ST_FUNC void gen_cvt_ftof(int t)
{
- int f = vtop[0].type.t;
+ int f = vtop[0].type.t & VT_BTYPE;
assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE);
assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE);
if (t == f)
@@ -1824,11 +2038,28 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
}
ST_FUNC void gen_vla_alloc(CType *type, int align) {
- uint32_t r = intr(gv(RC_INT));
+ uint32_t r;
+#if defined(CONFIG_TCC_BCHECK)
+ if (tcc_state->do_bounds_check)
+ vpushv(vtop);
+#endif
+ r = intr(gv(RC_INT));
o(0x91003c00 | r | r << 5); // add x(r),x(r),#15
o(0x927cec00 | r | r << 5); // bic x(r),x(r),#15
o(0xcb2063ff | r << 16); // sub sp,sp,x(r)
vpop();
+#if defined(CONFIG_TCC_BCHECK)
+ if (tcc_state->do_bounds_check) {
+ vpushi(0);
+ vtop->r = TREG_R(0);
+ o(0x910003e0 | vtop->r); // mov r0,sp
+ vswap();
+ vpush_global_sym(&func_old_type, TOK___bound_new_region);
+ vrott(3);
+ gfunc_call(2);
+ func_bound_add_epilog = 1;
+ }
+#endif
}
/* end of A64 code generator */
diff --git a/arm64-link.c b/arm64-link.c
index 59322c5..740993c 100644
--- a/arm64-link.c
+++ b/arm64-link.c
@@ -12,7 +12,7 @@
#define R_NUM R_AARCH64_NUM
#define ELF_START_ADDR 0x00400000
-#define ELF_PAGE_SIZE 0x1000
+#define ELF_PAGE_SIZE 0x10000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
@@ -37,6 +37,7 @@ int code_reloc (int reloc_type)
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_COPY:
return 0;
@@ -46,8 +47,6 @@ int code_reloc (int reloc_type)
case R_AARCH64_JUMP_SLOT:
return 1;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -64,6 +63,7 @@ int gotplt_entry_type (int reloc_type)
case R_AARCH64_MOVW_UABS_G3:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
case R_AARCH64_COPY:
@@ -79,8 +79,6 @@ int gotplt_entry_type (int reloc_type)
case R_AARCH64_LD64_GOT_LO12_NC:
return ALWAYS_GOTPLT_ENTRY;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -90,9 +88,6 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
uint8_t *p;
unsigned plt_offset;
- if (s1->output_type == TCC_OUTPUT_DLL)
- tcc_error("DLLs unimplemented!");
-
if (plt->data_offset == 0) {
section_ptr_add(plt, 32);
}
@@ -152,23 +147,56 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
-void relocate_init(Section *sr) {}
-
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
- int sym_index = ELFW(R_SYM)(rel->r_info);
+ int sym_index = ELFW(R_SYM)(rel->r_info), esym_index;
#ifdef DEBUG_RELOC
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
#endif
switch(type) {
case R_AARCH64_ABS64:
- write64le(ptr, val);
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
+ qrel->r_offset = rel->r_offset;
+ if (esym_index) {
+ qrel->r_info = ELFW(R_INFO)(esym_index, R_AARCH64_ABS64);
+ qrel->r_addend = rel->r_addend;
+ qrel++;
+ break;
+ } else {
+ qrel->r_info = ELFW(R_INFO)(0, R_AARCH64_RELATIVE);
+ qrel->r_addend = read64le(ptr) + val;
+ qrel++;
+ }
+ }
+ add64le(ptr, val);
return;
case R_AARCH64_ABS32:
- write32le(ptr, val);
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ /* XXX: this logic may depend on TCC's codegen
+ now TCC uses R_AARCH64_RELATIVE even for a 64bit pointer */
+ qrel->r_offset = rel->r_offset;
+ qrel->r_info = ELFW(R_INFO)(0, R_AARCH64_RELATIVE);
+ /* Use sign extension! */
+ qrel->r_addend = (int)read32le(ptr) + val;
+ qrel++;
+ }
+ add32le(ptr, val);
return;
case R_AARCH64_PREL32:
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ /* DLL relocation */
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
+ if (esym_index) {
+ qrel->r_offset = rel->r_offset;
+ qrel->r_info = ELFW(R_INFO)(esym_index, R_AARCH64_PREL32);
+ /* Use sign extension! */
+ qrel->r_addend = (int)read32le(ptr) + rel->r_addend;
+ qrel++;
+ break;
+ }
+ }
write32le(ptr, val - addr);
return;
case R_AARCH64_MOVW_UABS_G0_NC:
@@ -199,6 +227,10 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
(val & 0xfff) << 10));
return;
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
+ (val & 0xff8) << 7));
+ return;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
#ifdef DEBUG_RELOC
@@ -215,7 +247,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_AARCH64_ADR_GOT_PAGE: {
uint64_t off =
(((s1->got->sh_addr +
- s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
+ get_sym_attr(s1, sym_index, 0)->got_offset) >> 12) - (addr >> 12));
if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
@@ -226,7 +258,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
write32le(ptr,
((read32le(ptr) & 0xfff803ff) |
((s1->got->sh_addr +
- s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
+ get_sym_attr(s1, sym_index, 0)->got_offset) & 0xff8) << 7));
return;
case R_AARCH64_COPY:
return;
diff --git a/c67-gen.c b/c67-gen.c
index bcb4b0e..2498aed 100644
--- a/c67-gen.c
+++ b/c67-gen.c
@@ -56,7 +56,7 @@
#define RC_C67_B12 0x04000000
#define RC_C67_B13 0x08000000
#define RC_IRET RC_C67_A4 /* function return: integer register */
-#define RC_LRET RC_C67_A5 /* function return: second integer register */
+#define RC_IRE2 RC_C67_A5 /* function return: second integer register */
#define RC_FRET RC_C67_A4 /* function return: float register */
/* pretty names for the registers */
@@ -89,7 +89,7 @@ enum {
/* return registers for function */
#define REG_IRET TREG_C67_A4 /* single word int return register */
-#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */
+#define REG_IRE2 TREG_C67_A5 /* second word return register (for long long) */
#define REG_FRET TREG_C67_A4 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
@@ -111,6 +111,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
+#define USING_GLOBALS
#include "tcc.h"
ST_DATA const int reg_classes[NB_REGS] = {
@@ -226,11 +227,6 @@ void gsym_addr(int t, int a)
}
}
-void gsym(int t)
-{
- gsym_addr(t, ind);
-}
-
// these are regs that tcc doesn't really know about,
// but assign them unique values so the mapping routines
// can distinguish them
@@ -1944,8 +1940,9 @@ void gfunc_call(int nb_args)
// parameters are loaded and restored upon return (or if/when needed).
/* generate function prolog of type 't' */
-void gfunc_prolog(CType * func_type)
+void gfunc_prolog(Sym *func_sym)
{
+ CType *func_type = &func_sym->type;
int addr, align, size, func_call, i;
Sym *sym;
CType *type;
@@ -1955,8 +1952,6 @@ void gfunc_prolog(CType * func_type)
addr = 8;
/* if the function returns a structure, then add an
implicit pointer parameter */
- func_vt = sym->type;
- func_var = (sym->f.func_type == FUNC_ELLIPSIS);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
@@ -1967,7 +1962,7 @@ void gfunc_prolog(CType * func_type)
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
- sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
+ sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
size = type_size(type, &align);
size = (size + 3) & ~3;
@@ -2035,6 +2030,16 @@ void gfunc_epilog(void)
}
}
+ST_FUNC void gen_fill_nops(int bytes)
+{
+ if ((bytes & 3))
+ tcc_error("alignment of code section not multiple of 4");
+ while (bytes > 0) {
+ C67_NOP(4);
+ bytes -= 4;
+ }
+}
+
/* generate a jump to a label */
int gjmp(int t)
{
@@ -2067,15 +2072,13 @@ void gjmp_addr(int a)
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
-int gtst(int inv, int t)
+ST_FUNC int gjmp_cond(int op, int t)
{
- int ind1, n;
- int v, *p;
+ int ind1;
+ int inv = op & 1;
+ if (nocode_wanted)
+ return t;
- v = vtop->r & VT_VALMASK;
- if (nocode_wanted) {
- ;
- } else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
// C67 uses B2 sort of as flags register
ind1 = ind;
@@ -2093,16 +2096,18 @@ int gtst(int inv, int t)
C67_NOP(5);
t = ind1; //return where we need to patch
- } else if (v == VT_JMP || v == VT_JMPI) {
- /* && or || optimization */
- if ((v & 1) == inv) {
+ return t;
+}
+
+ST_FUNC int gjmp_append(int n0, int t)
+{
+ if (n0) {
+ int n = n0, *p;
/* insert vtop->c jump list in t */
// I guess the idea is to traverse to the
// null at the end of the list and store t
// there
-
- n = vtop->c.i;
while (n != 0) {
p = (int *) (cur_text_section->data + n);
@@ -2112,14 +2117,8 @@ int gtst(int inv, int t)
}
*p |= (t & 0xffff) << 7;
*(p + 1) |= ((t >> 16) & 0xffff) << 7;
- t = vtop->c.i;
-
- } else {
- t = gjmp(t);
- gsym(vtop->c.i);
- }
+ t = n0;
}
- vtop--;
return t;
}
@@ -2195,10 +2194,8 @@ void gen_opi(int op)
ALWAYS_ASSERT(FALSE);
vtop--;
- if (op >= TOK_ULT && op <= TOK_GT) {
- vtop->r = VT_CMP;
- vtop->c.i = op;
- }
+ if (op >= TOK_ULT && op <= TOK_GT)
+ vset_VT_CMP(0x80);
break;
case '-':
case TOK_SUBC1: /* sub with carry generation */
@@ -2354,7 +2351,7 @@ void gen_opf(int op)
} else {
ALWAYS_ASSERT(FALSE);
}
- vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2
+ vset_VT_CMP(0x80);
} else {
if (op == '+') {
if ((ft & VT_BTYPE) == VT_DOUBLE) {
@@ -2393,7 +2390,7 @@ void gen_opf(int op)
gfunc_call(2);
vpushi(0);
vtop->r = REG_FRET;
- vtop->r2 = REG_LRET;
+ vtop->r2 = REG_IRE2;
} else {
// must call intrinsic SP floating point divide
diff --git a/c67-link.c b/c67-link.c
index de72e44..514689c 100644
--- a/c67-link.c
+++ b/c67-link.c
@@ -39,8 +39,6 @@ int code_reloc (int reloc_type)
case R_C60_PLT32:
return 1;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -64,8 +62,6 @@ int gotplt_entry_type (int reloc_type)
case R_C60_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -95,8 +91,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
-void relocate_init(Section *sr) {}
-
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
switch(type) {
diff --git a/configure b/configure
index 1ee3acb..5673d17 100755
--- a/configure
+++ b/configure
@@ -35,6 +35,7 @@ mingw32="no"
LIBSUF=".a"
EXESUF=""
DLLSUF=".so"
+tcc_usrinclude=""
tcc_sysincludepaths=""
tcc_libpaths=""
tcc_crtprefix=""
@@ -47,15 +48,20 @@ cpu=
cpuver=
gcc_major=0
gcc_minor=0
+cc_name="gcc"
+ar_set=
# OS specific
targetos=`uname`
case $targetos in
Darwin)
confvars="$confvars OSX"
+ cc=`which cc`
+ cc=`readlink $cc`
+ tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
DLLSUF=".dylib"
;;
- MINGW*|MSYS*|CYGWIN*)
+ Windows_NT|MINGW*|MSYS*|CYGWIN*)
mingw32=yes
;;
DragonFly|OpenBSD|FreeBSD|NetBSD)
@@ -105,7 +111,7 @@ for opt do
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
- --ar=*) ar=`echo $opt | cut -d '=' -f 2`
+ --ar=*) ar=`echo $opt | cut -d '=' -f 2` ; ar_set="yes"
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
@@ -135,6 +141,8 @@ for opt do
;;
--strip-binaries) confvars="$confvars strip"
;;
+ --debug) confvars="$confvars strip=no"
+ ;;
--with-libgcc) confvars="$confvars libgcc"
;;
--with-selinux) confvars="$confvars selinux"
@@ -150,11 +158,15 @@ for opt do
esac
done
+cc="${cross_prefix}${cc}"
+ar="${cross_prefix}${ar}"
+strip="${cross_prefix}${strip}"
+
if test -z "$cpu" ; then
if test -n "$ARCH" ; then
- cpu="$ARCH"
+ cpu="$ARCH"
else
- cpu=`uname -m`
+ cpu=`uname -m`
fi
fi
@@ -197,6 +209,9 @@ case "$cpu" in
s390)
cpu="s390"
;;
+ riscv64)
+ cpu="riscv64"
+ ;;
*)
echo "Unsupported CPU"
exit 1
@@ -205,16 +220,13 @@ esac
# Checking for CFLAGS
if test -z "$CFLAGS"; then
- CFLAGS="-Wall -g -O2"
+ CFLAGS="-Wall -O2"
fi
if test "$mingw32" = "yes" ; then
if test "$source_path_used" = "no"; then
source_path="."
fi
- if test "$cc" = gcc; then
- test -z "$LDFLAGS" && LDFLAGS="-static"
- fi
test -z "$prefix" && prefix="C:/Program Files/tcc"
test -z "$tccdir" && tccdir="${prefix}"
test -z "$bindir" && bindir="${tccdir}"
@@ -286,6 +298,7 @@ Advanced options (experts only):
--extra-ldflags= specify linker options []
--cpu=CPU CPU [$cpu]
--strip-binaries strip symbol tables from resulting binaries
+ --debug include debug info with resulting binaries
--disable-static make libtcc.so instead of libtcc.a
--enable-static make libtcc.a instead of libtcc.dll (win32)
--disable-rpath disable use of -rpath with the above
@@ -303,30 +316,27 @@ EOF
exit 1
fi
-cc="${cross_prefix}${cc}"
-ar="${cross_prefix}${ar}"
-strip="${cross_prefix}${strip}"
-
if test -z "$cross_prefix" ; then
CONFTEST=./conftest$EXESUF
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
echo "configure: error: '$cc' failed to compile conftest.c."
else
+ cc_name="$($CONFTEST compiler)"
gcc_major="$($CONFTEST version)"
gcc_minor="$($CONFTEST minor)"
+ bigendian="$($CONFTEST bigendian)"
+ _triplet="$($CONFTEST triplet)"
fi
- bigendian="$($CONFTEST bigendian)"
if test "$mingw32" = "no" ; then
if test -z "$triplet"; then
- tt="$($CONFTEST triplet)"
- if test -n "$tt" -a -f "/usr/lib/$tt/crti.o" ; then
- triplet="$tt"
+ if test -n "$_triplet" -a -f "/usr/lib/$_triplet/crti.o" ; then
+ triplet="$_triplet"
fi
fi
if test -z "$triplet"; then
- if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
+ if test $cpu = "x86_64" -o $cpu = "aarch64" -o $cpu = "riscv64" ; then
if test -f "/usr/lib64/crti.o" ; then
tcc_lddir="lib64"
fi
@@ -335,7 +345,7 @@ if test -z "$cross_prefix" ; then
if test "$cpu" = "arm" ; then
if test "${triplet%eabihf}" != "$triplet" ; then
- confvars="$confvars arm_eabihf"
+ confvars="$confvars arm_eabihf arm_vfp"
elif test "${triplet%eabi}" != "$triplet" ; then
confvars="$confvars arm_eabi"
fi
@@ -352,6 +362,11 @@ if test -z "$cross_prefix" ; then
echo "Perhaps you want ./configure --config-musl"
fi
fi
+ else # mingw32 = yes
+ if test "$cc_name" = "gcc"; then
+ # avoid mingw dependencies such as 'libgcc_s_dw2-1.dll'
+ test -z "$LDFLAGS" && LDFLAGS="-static"
+ fi
fi
else
# if cross compiling, cannot launch a program, so make a static guess
@@ -365,11 +380,11 @@ if test "$bigendian" = "yes" ; then
fi
# a final configuration tuning
-if ! echo "$cc" | grep -q "tcc"; then
+if test "$cc_name" != "tcc"; then
OPT1="-Wdeclaration-after-statement -fno-strict-aliasing"
# we want -Wno- but gcc does not always reject unknown -Wno- options
- OPT2="-Wpointer-sign -Wsign-compare -Wunused-result"
- if echo "$cc" | grep -q "clang"; then
+ OPT2="-Wpointer-sign -Wsign-compare -Wunused-result -Wformat-truncation"
+ if test "$cc_name" = "clang"; then
OPT1="$OPT1 -fheinous-gnu-extensions"
OPT2="$OPT2 -Wstring-plus-int"
fi
@@ -383,6 +398,8 @@ if ! echo "$cc" | grep -q "tcc"; then
# cat cc_msg.txt
# echo $CFLAGS
rm -f cc_msg.txt a.out
+else # cc is tcc
+ test "$ar_set" || ar="$cc -ar"
fi
fcho() { if test -n "$2"; then echo "$1$2"; fi }
@@ -395,6 +412,7 @@ fcho "Manual directory " "$mandir"
fcho "Info directory " "$infodir"
fcho "Doc directory " "$docdir"
fcho "Target root prefix " "$sysroot"
+fcho "/usr/include dir " "$tcc_usrinclude"
echo "Source path $source_path"
echo "C compiler $cc ($gcc_major.$gcc_minor)"
echo "Target OS $targetos"
@@ -414,6 +432,7 @@ mandir=\$(DESTDIR)$mandir
infodir=\$(DESTDIR)$infodir
docdir=\$(DESTDIR)$docdir
CC=$cc
+CC_NAME=$cc_name
GCC_MAJOR=$gcc_major
GCC_MINOR=$gcc_minor
AR=$ar
@@ -449,6 +468,7 @@ echo "/* Automatically generated by configure - do not modify */" > $TMPH
print_inc CONFIG_SYSROOT "$sysroot"
print_inc CONFIG_TCCDIR "$tccdir"
+print_mak CONFIG_USR_INCLUDE "$tcc_usrinclude"
print_mak CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths"
print_mak CONFIG_TCC_LIBPATHS "$tcc_libpaths"
print_mak CONFIG_TCC_CRTPREFIX "$tcc_crtprefix"
@@ -485,6 +505,11 @@ if test "$source_path_used" = "yes" ; then
else
echo 'TOPSRC=$(TOP)' >>config.mak
fi
+cat >>$TMPH <<EOF
+#define GCC_MAJOR $gcc_major
+#define GCC_MINOR $gcc_minor
+#define CC_NAME CC_${cc_name}
+EOF
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then
diff --git a/conftest.c b/conftest.c
index 2824cc8..f3b6ea6 100644
--- a/conftest.c
+++ b/conftest.c
@@ -1,5 +1,9 @@
#include <stdio.h>
+#if defined(_WIN32)
+#include <fcntl.h>
+#endif
+
/* Define architecture */
#if defined(__i386__) || defined _M_IX86
# define TRIPLET_ARCH "i386"
@@ -9,6 +13,8 @@
# define TRIPLET_ARCH "arm"
#elif defined(__aarch64__)
# define TRIPLET_ARCH "aarch64"
+#elif defined(__riscv) && defined(__LP64__)
+# define TRIPLET_ARCH "riscv64"
#else
# define TRIPLET_ARCH "unknown"
#endif
@@ -18,8 +24,10 @@
# define TRIPLET_OS "linux"
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
# define TRIPLET_OS "kfreebsd"
-#elif defined _WIN32
+#elif defined(_WIN32)
# define TRIPLET_OS "win32"
+#elif defined(__APPLE__)
+# define TRIPLET_OS "darwin"
#elif !defined (__GNU__)
# define TRIPLET_OS "unknown"
#endif
@@ -49,37 +57,67 @@ int _CRT_glob = 0;
int main(int argc, char *argv[])
{
+#if defined(_WIN32)
+ _setmode(_fileno(stdout), _O_BINARY); /* don't translate \n to \r\n */
+#endif
switch(argc == 2 ? argv[1][0] : 0) {
- case 'b':
+ case 'b'://igendian
{
volatile unsigned foo = 0x01234567;
puts(*(unsigned char*)&foo == 0x67 ? "no" : "yes");
break;
}
-#ifdef __GNUC__
- case 'm':
- printf("%d\n", __GNUC_MINOR__);
+#if defined(__clang__)
+ case 'm'://inor
+ printf("%d\n", __clang_minor__);
break;
- case 'v':
- printf("%d\n", __GNUC__);
+ case 'v'://ersion
+ printf("%d\n", __clang_major__);
break;
-#elif defined __TINYC__
- case 'v':
+#elif defined(__TINYC__)
+ case 'v'://ersion
puts("0");
break;
- case 'm':
+ case 'm'://inor
printf("%d\n", __TINYC__);
break;
+#elif defined(_MSC_VER)
+ case 'v'://ersion
+ puts("0");
+ break;
+ case 'm'://inor
+ printf("%d\n", _MSC_VER);
+ break;
+#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+ /* GNU comes last as other compilers may add 'GNU' compatibility */
+ case 'm'://inor
+ printf("%d\n", __GNUC_MINOR__);
+ break;
+ case 'v'://ersion
+ printf("%d\n", __GNUC__);
+ break;
#else
- case 'm':
- case 'v':
+ case 'm'://inor
+ case 'v'://ersion
puts("0");
break;
#endif
- case 't':
+ case 't'://riplet
puts(TRIPLET);
break;
-
+ case 'c'://ompiler
+#if defined(__clang__)
+ puts("clang");
+#elif defined(__TINYC__)
+ puts("tcc");
+#elif defined(_MSC_VER)
+ puts("msvc");
+#elif defined(__GNUC__)
+ puts("gcc");
+#else
+ puts("unknown");
+#endif
+ break;
default:
break;
}
diff --git a/elf.h b/elf.h
index 9fed6eb..a78db18 100644
--- a/elf.h
+++ b/elf.h
@@ -262,7 +262,8 @@ typedef struct
#define EM_AARCH64 183 /* ARM AARCH64 */
#define EM_TILEPRO 188 /* Tilera TILEPro */
#define EM_TILEGX 191 /* Tilera TILE-Gx */
-#define EM_NUM 192
+#define EM_RISCV 243 /* RISC-V */
+#define EM_NUM 253
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
@@ -381,7 +382,7 @@ typedef struct
#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
#define SHF_ORDERED (1 << 30) /* Special ordering requirement
(Solaris). */
-#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless
+#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless
referenced or allocated (Solaris).*/
/* Section group handling. */
@@ -3233,5 +3234,71 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_TILEGX_NUM 130
+/* RISC-V ELF Flags */
+#define EF_RISCV_RVC 0x0001
+#define EF_RISCV_FLOAT_ABI 0x0006
+#define EF_RISCV_FLOAT_ABI_SOFT 0x0000
+#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002
+#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
+#define EF_RISCV_FLOAT_ABI_QUAD 0x0006
+
+/* RISC-V relocations. */
+#define R_RISCV_NONE 0
+#define R_RISCV_32 1
+#define R_RISCV_64 2
+#define R_RISCV_RELATIVE 3
+#define R_RISCV_COPY 4
+#define R_RISCV_JUMP_SLOT 5
+#define R_RISCV_TLS_DTPMOD32 6
+#define R_RISCV_TLS_DTPMOD64 7
+#define R_RISCV_TLS_DTPREL32 8
+#define R_RISCV_TLS_DTPREL64 9
+#define R_RISCV_TLS_TPREL32 10
+#define R_RISCV_TLS_TPREL64 11
+#define R_RISCV_BRANCH 16
+#define R_RISCV_JAL 17
+#define R_RISCV_CALL 18
+#define R_RISCV_CALL_PLT 19
+#define R_RISCV_GOT_HI20 20
+#define R_RISCV_TLS_GOT_HI20 21
+#define R_RISCV_TLS_GD_HI20 22
+#define R_RISCV_PCREL_HI20 23
+#define R_RISCV_PCREL_LO12_I 24
+#define R_RISCV_PCREL_LO12_S 25
+#define R_RISCV_HI20 26
+#define R_RISCV_LO12_I 27
+#define R_RISCV_LO12_S 28
+#define R_RISCV_TPREL_HI20 29
+#define R_RISCV_TPREL_LO12_I 30
+#define R_RISCV_TPREL_LO12_S 31
+#define R_RISCV_TPREL_ADD 32
+#define R_RISCV_ADD8 33
+#define R_RISCV_ADD16 34
+#define R_RISCV_ADD32 35
+#define R_RISCV_ADD64 36
+#define R_RISCV_SUB8 37
+#define R_RISCV_SUB16 38
+#define R_RISCV_SUB32 39
+#define R_RISCV_SUB64 40
+#define R_RISCV_GNU_VTINHERIT 41
+#define R_RISCV_GNU_VTENTRY 42
+#define R_RISCV_ALIGN 43
+#define R_RISCV_RVC_BRANCH 44
+#define R_RISCV_RVC_JUMP 45
+#define R_RISCV_RVC_LUI 46
+#define R_RISCV_GPREL_I 47
+#define R_RISCV_GPREL_S 48
+#define R_RISCV_TPREL_I 49
+#define R_RISCV_TPREL_S 50
+#define R_RISCV_RELAX 51
+#define R_RISCV_SUB6 52
+#define R_RISCV_SET6 53
+#define R_RISCV_SET8 54
+#define R_RISCV_SET16 55
+#define R_RISCV_SET32 56
+#define R_RISCV_32_PCREL 57
+
+#define R_RISCV_NUM 58
+
#endif /* elf.h */
diff --git a/i386-asm.c b/i386-asm.c
index 55c95af..3f7c1df 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define USING_GLOBALS
#include "tcc.h"
#define MAX_OPERANDS 3
@@ -1201,7 +1202,7 @@ ST_FUNC int asm_parse_regvar (int t)
{
const char *s;
Operand op;
- if (t < TOK_IDENT)
+ if (t < TOK_IDENT || (t & SYM_FIELD))
return -1;
s = table_ident[t - TOK_IDENT]->str;
if (s[0] != '%')
@@ -1489,6 +1490,8 @@ ST_FUNC void subst_asm_operand(CString *add_str,
list when we still know the symbol. */
get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
}
+ if (tcc_state->leading_underscore)
+ cstr_ccat(add_str, '_');
cstr_cat(add_str, name, -1);
if ((uint32_t)sv->c.i == 0)
goto no_offset;
diff --git a/i386-gen.c b/i386-gen.c
index b9c3599..8a0fb35 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -37,7 +37,7 @@
#define RC_EBX 0x0040
#define RC_IRET RC_EAX /* function return: integer register */
-#define RC_LRET RC_EDX /* function return: second integer register */
+#define RC_IRE2 RC_EDX /* function return: second integer register */
#define RC_FRET RC_ST0 /* function return: float register */
/* pretty names for the registers */
@@ -52,7 +52,7 @@ enum {
/* return registers for function */
#define REG_IRET TREG_EAX /* single word int return register */
-#define REG_LRET TREG_EDX /* second word return register (for long long) */
+#define REG_IRE2 TREG_EDX /* second word return register (for long long) */
#define REG_FRET TREG_ST0 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
@@ -71,9 +71,14 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
+/* define if return values need to be extended explicitely
+ at caller side (for interfacing with non-TCC compilers) */
+#define PROMOTE_RET
+
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
+#define USING_GLOBALS
#include "tcc.h"
/* define to 1/0 to [not] have EBX as 4th register */
@@ -92,6 +97,9 @@ static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK
static addr_t func_bound_offset;
static unsigned long func_bound_ind;
+ST_DATA int func_bound_add_epilog;
+static void gen_bounds_prolog(void);
+static void gen_bounds_epilog(void);
#endif
/* XXX: make it faster ? */
@@ -140,11 +148,6 @@ ST_FUNC void gsym_addr(int t, int a)
}
}
-ST_FUNC void gsym(int t)
-{
- gsym_addr(t, ind);
-}
-
/* instruction + 4 bytes data. Return the address of the data */
static int oad(int c, int s)
{
@@ -157,6 +160,12 @@ static int oad(int c, int s)
return t;
}
+ST_FUNC void gen_fill_nops(int bytes)
+{
+ while (bytes--)
+ g(0x90);
+}
+
/* generate jmp to a label */
#define gjmp2(instr,lbl) oad(instr,lbl)
@@ -221,6 +230,7 @@ ST_FUNC void load(int r, SValue *sv)
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
+ v1.sym = NULL;
fr = r;
if (!(reg_classes[fr] & RC_INT))
fr = get_reg(RC_INT);
@@ -260,10 +270,10 @@ ST_FUNC void load(int r, SValue *sv)
o(0xe8 + r); /* mov %ebp, r */
}
} else if (v == VT_CMP) {
- oad(0xb8 + r, 0); /* mov $0, r */
o(0x0f); /* setxx %br */
o(fc);
o(0xc0 + r);
+ o(0xc0b60f + r * 0x90000); /* movzbl %al, %eax */
} else if (v == VT_JMP || v == VT_JMPI) {
t = v & 1;
oad(0xb8 + r, t); /* mov $1, r */
@@ -335,7 +345,7 @@ static void gen_static_call(int v)
{
Sym *sym;
- sym = external_global_sym(v, &func_old_type, 0);
+ sym = external_global_sym(v, &func_old_type);
oad(0xe8, -4);
greloc(cur_text_section, sym, ind-4, R_386_PC32);
}
@@ -355,33 +365,6 @@ static void gcall_or_jmp(int is_jmp)
o(0xff); /* call/jmp *r */
o(0xd0 + r + (is_jmp << 4));
}
- if (!is_jmp) {
- int rt;
- /* extend the return value to the whole register if necessary
- visual studio and gcc do not always set the whole eax register
- when assigning the return value of a function */
- rt = vtop->type.ref->type.t;
- switch (rt & VT_BTYPE) {
- case VT_BYTE:
- if (rt & VT_UNSIGNED) {
- o(0xc0b60f); /* movzx %al, %eax */
- }
- else {
- o(0xc0be0f); /* movsx %al, %eax */
- }
- break;
- case VT_SHORT:
- if (rt & VT_UNSIGNED) {
- o(0xc0b70f); /* movzx %ax, %eax */
- }
- else {
- o(0xc0bf0f); /* movsx %ax, %eax */
- }
- break;
- default:
- break;
- }
- }
}
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
@@ -422,6 +405,11 @@ ST_FUNC void gfunc_call(int nb_args)
int size, align, r, args_size, i, func_call;
Sym *func_sym;
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gbound_args(nb_args);
+#endif
+
args_size = 0;
for(i = 0;i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
@@ -429,6 +417,22 @@ ST_FUNC void gfunc_call(int nb_args)
/* align to stack align size */
size = (size + 3) & ~3;
/* allocate the necessary size on stack */
+#ifdef TCC_TARGET_PE
+ if (size >= 0x4096) {
+ /* cannot call alloca with bound checking. Do stack probing. */
+ o(0x50); // push %eax
+ oad(0xb8, size - 4); // mov size-4,%eax
+ oad(0x3d, 4096); // p1: cmp $4096,%eax
+ o(0x1476); // jbe <p2>
+ oad(0x248485,-4096); // test %eax,-4096(%esp)
+ oad(0xec81, 4096); // sub $4096,%esp
+ oad(0x2d, 4096); // sub $4096,%eax
+ o(0xe5eb); // jmp <p1>
+ o(0xc429); // p2: sub %eax,%esp
+ oad(0xc481, size - 4); // add size-4,%esp
+ o(0x58); // pop %eax
+ }
+#endif
oad(0xec81, size); /* sub $xxx, %esp */
/* generate structure store */
r = get_reg(RC_INT);
@@ -496,6 +500,7 @@ ST_FUNC void gfunc_call(int nb_args)
else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
args_size -= 4;
#endif
+
gcall_or_jmp(0);
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
@@ -510,8 +515,9 @@ ST_FUNC void gfunc_call(int nb_args)
#endif
/* generate function prolog of type 't' */
-ST_FUNC void gfunc_prolog(CType *func_type)
+ST_FUNC void gfunc_prolog(Sym *func_sym)
{
+ CType *func_type = &func_sym->type;
int addr, align, size, func_call, fastcall_nb_regs;
int param_index, param_addr;
uint8_t *fastcall_regs_ptr;
@@ -540,8 +546,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
func_sub_sp_offset = ind;
/* if the function returns a structure, then add an
implicit pointer parameter */
- func_vt = sym->type;
- func_var = (sym->f.func_type == FUNC_ELLIPSIS);
#ifdef TCC_TARGET_PE
size = type_size(&func_vt,&align);
if (((func_vt.t & VT_BTYPE) == VT_STRUCT)
@@ -576,7 +580,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
addr += size;
}
sym_push(sym->v & ~SYM_FIELD, type,
- VT_LOCAL | lvalue_type(type->t), param_addr);
+ VT_LOCAL | VT_LVAL, param_addr);
param_index++;
}
func_ret_sub = 0;
@@ -589,13 +593,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
#endif
#ifdef CONFIG_TCC_BCHECK
- /* leave some room for bound checking code */
- if (tcc_state->do_bounds_check) {
- func_bound_offset = lbounds_section->data_offset;
- func_bound_ind = ind;
- oad(0xb8, 0); /* lbound section pointer */
- oad(0xb8, 0); /* call to function */
- }
+ if (tcc_state->do_bounds_check)
+ gen_bounds_prolog();
#endif
}
@@ -605,34 +604,8 @@ ST_FUNC void gfunc_epilog(void)
addr_t v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
- if (tcc_state->do_bounds_check
- && func_bound_offset != lbounds_section->data_offset) {
- addr_t saved_ind;
- addr_t *bounds_ptr;
- Sym *sym_data;
-
- /* add end of table info */
- bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
- *bounds_ptr = 0;
-
- /* generate bound local allocation */
- saved_ind = ind;
- ind = func_bound_ind;
- sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
- func_bound_offset, lbounds_section->data_offset);
- greloc(cur_text_section, sym_data,
- ind + 1, R_386_32);
- oad(0xb8, 0); /* mov %eax, xxx */
- gen_static_call(TOK___bound_local_new);
- ind = saved_ind;
-
- /* generate bound check local freeing */
- o(0x5250); /* save returned value, if any */
- greloc(cur_text_section, sym_data, ind + 1, R_386_32);
- oad(0xb8, 0); /* mov %eax, xxx */
- gen_static_call(TOK___bound_local_delete);
- o(0x585a); /* restore returned value, if any */
- }
+ if (tcc_state->do_bounds_check)
+ gen_bounds_epilog();
#endif
/* align local size to word & save local variables */
@@ -690,63 +663,39 @@ ST_FUNC void gjmp_addr(int a)
}
}
-ST_FUNC void gtst_addr(int inv, int a)
+#if 0
+/* generate a jump to a fixed address */
+ST_FUNC void gjmp_cond_addr(int a, int op)
{
- int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP) {
- inv ^= (vtop--)->c.i;
- a -= ind + 2;
- if (a == (char)a) {
- g(inv - 32);
- g(a);
- } else {
- g(0x0f);
- oad(inv - 16, a - 4);
- }
- } else if ((v & ~1) == VT_JMP) {
- if ((v & 1) != inv) {
- gjmp_addr(a);
- gsym(vtop->c.i);
- } else {
- gsym(vtop->c.i);
- o(0x05eb);
- gjmp_addr(a);
- }
- vtop--;
- }
+ int r = a - ind - 2;
+ if (r == (char)r)
+ g(op - 32), g(r);
+ else
+ g(0x0f), gjmp2(op - 16, r - 4);
}
+#endif
-/* generate a test. set 'inv' to invert test. Stack entry is popped */
-ST_FUNC int gtst(int inv, int t)
+ST_FUNC int gjmp_append(int n, int t)
{
- int v = vtop->r & VT_VALMASK;
- if (nocode_wanted) {
- ;
- } else if (v == VT_CMP) {
- /* fast case : can jump directly since flags are set */
- g(0x0f);
- t = gjmp2((vtop->c.i - 16) ^ inv, t);
- } else if (v == VT_JMP || v == VT_JMPI) {
- /* && or || optimization */
- if ((v & 1) == inv) {
- /* insert vtop->c jump list in t */
- uint32_t n1, n = vtop->c.i;
- if (n) {
- while ((n1 = read32le(cur_text_section->data + n)))
- n = n1;
- write32le(cur_text_section->data + n, t);
- t = vtop->c.i;
- }
- } else {
- t = gjmp(t);
- gsym(vtop->c.i);
- }
+ void *p;
+ /* insert vtop->c jump list in t */
+ if (n) {
+ uint32_t n1 = n, n2;
+ while ((n2 = read32le(p = cur_text_section->data + n1)))
+ n1 = n2;
+ write32le(p, t);
+ t = n;
}
- vtop--;
return t;
}
-/* generate an integer binary operation */
+ST_FUNC int gjmp_cond(int op, int t)
+{
+ g(0x0f);
+ t = gjmp2(op - 16, t);
+ return t;
+}
+
ST_FUNC void gen_opi(int op)
{
int r, fr, opc, c;
@@ -764,10 +713,9 @@ ST_FUNC void gen_opi(int op)
c = vtop->c.i;
if (c == (char)c) {
/* generate inc and dec for smaller code */
- if (c==1 && opc==0 && op != TOK_ADDC1) {
- o (0x40 | r); // inc
- } else if (c==1 && opc==5 && op != TOK_SUBC1) {
- o (0x48 | r); // dec
+ if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
+ opc = (c == 1) ^ (op == '+');
+ o (0x40 | (opc << 3) | r); // inc,dec
} else {
o(0x83);
o(0xc0 | (opc << 3) | r);
@@ -785,10 +733,8 @@ ST_FUNC void gen_opi(int op)
o(0xc0 + r + fr * 8);
}
vtop--;
- if (op >= TOK_ULT && op <= TOK_GT) {
- vtop->r = VT_CMP;
- vtop->c.i = op;
- }
+ if (op >= TOK_ULT && op <= TOK_GT)
+ vset_VT_CMP(op);
break;
case '-':
case TOK_SUBC1: /* sub with carry generation */
@@ -946,8 +892,7 @@ ST_FUNC void gen_opf(int op)
op = TOK_EQ;
}
vtop--;
- vtop->r = VT_CMP;
- vtop->c.i = op;
+ vset_VT_CMP(op);
} else {
/* no memory reference possible for long double operations */
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
@@ -988,6 +933,7 @@ ST_FUNC void gen_opf(int op)
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
+ v1.sym = NULL;
load(r, &v1);
fc = 0;
}
@@ -1015,6 +961,7 @@ ST_FUNC void gen_cvt_itof(int t)
o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
o(0x242cdf); /* fildll (%esp) */
o(0x08c483); /* add $8, %esp */
+ vtop->r2 = VT_CONST;
} else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
(VT_INT | VT_UNSIGNED)) {
/* unsigned int to float/double/long double */
@@ -1029,6 +976,7 @@ ST_FUNC void gen_cvt_itof(int t)
o(0x2404db); /* fildl (%esp) */
o(0x04c483); /* add $4, %esp */
}
+ vtop->r2 = VT_CONST;
vtop->r = TREG_ST0;
}
@@ -1046,7 +994,8 @@ ST_FUNC void gen_cvt_ftoi(int t)
gfunc_call(1);
vpushi(0);
vtop->r = REG_IRET;
- vtop->r2 = REG_LRET;
+ if ((t & VT_BTYPE) == VT_LLONG)
+ vtop->r2 = REG_IRE2;
}
/* convert from one floating point type to another */
@@ -1056,6 +1005,19 @@ ST_FUNC void gen_cvt_ftof(int t)
gv(RC_FLOAT);
}
+/* char/short to int conversion */
+ST_FUNC void gen_cvt_csti(int t)
+{
+ int r, sz, xl;
+ r = gv(RC_INT);
+ sz = !(t & VT_UNSIGNED);
+ xl = (t & VT_BTYPE) == VT_SHORT;
+ o(0xc0b60f /* mov[sz] %a[xl], %eax */
+ | (sz << 3 | xl) << 8
+ | (r << 3 | r) << 16
+ );
+}
+
/* computed goto support */
ST_FUNC void ggoto(void)
{
@@ -1066,62 +1028,49 @@ ST_FUNC void ggoto(void)
/* bound check support functions */
#ifdef CONFIG_TCC_BCHECK
-/* generate a bounded pointer addition */
-ST_FUNC void gen_bounded_ptr_add(void)
+static void gen_bounds_prolog(void)
{
- /* prepare fast i386 function call (args in eax and edx) */
- gv2(RC_EAX, RC_EDX);
- /* save all temporary registers */
- vtop -= 2;
- save_regs(0);
- /* do a fast function call */
- gen_static_call(TOK___bound_ptr_add);
- /* returned pointer is in eax */
- vtop++;
- vtop->r = TREG_EAX | VT_BOUNDED;
- /* address of bounding function call point */
- vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
+ /* leave some room for bound checking code */
+ func_bound_offset = lbounds_section->data_offset;
+ func_bound_ind = ind;
+ func_bound_add_epilog = 0;
+ oad(0xb8, 0); /* lbound section pointer */
+ oad(0xb8, 0); /* call to function */
}
-/* patch pointer addition in vtop so that pointer dereferencing is
- also tested */
-ST_FUNC void gen_bounded_ptr_deref(void)
+static void gen_bounds_epilog(void)
{
- addr_t func;
- int size, align;
- Elf32_Rel *rel;
- Sym *sym;
+ addr_t saved_ind;
+ addr_t *bounds_ptr;
+ Sym *sym_data;
+ int offset_modified = func_bound_offset != lbounds_section->data_offset;
- size = 0;
- /* XXX: put that code in generic part of tcc */
- if (!is_float(vtop->type.t)) {
- if (vtop->r & VT_LVAL_BYTE)
- size = 1;
- else if (vtop->r & VT_LVAL_SHORT)
- size = 2;
- }
- if (!size)
- size = type_size(&vtop->type, &align);
- switch(size) {
- case 1: func = TOK___bound_ptr_indir1; break;
- case 2: func = TOK___bound_ptr_indir2; break;
- case 4: func = TOK___bound_ptr_indir4; break;
- case 8: func = TOK___bound_ptr_indir8; break;
- case 12: func = TOK___bound_ptr_indir12; break;
- case 16: func = TOK___bound_ptr_indir16; break;
- default:
- tcc_error("unhandled size when dereferencing bounded pointer");
- func = 0;
- break;
+ if (!offset_modified && !func_bound_add_epilog)
+ return;
+
+ /* add end of table info */
+ bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
+ *bounds_ptr = 0;
+
+ sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
+ func_bound_offset, lbounds_section->data_offset);
+
+ /* generate bound local allocation */
+ if (offset_modified) {
+ saved_ind = ind;
+ ind = func_bound_ind;
+ greloc(cur_text_section, sym_data, ind + 1, R_386_32);
+ ind = ind + 5;
+ gen_static_call(TOK___bound_local_new);
+ ind = saved_ind;
}
- /* patch relocation */
- /* XXX: find a better solution ? */
- rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
- sym = external_global_sym(func, &func_old_type, 0);
- if (!sym->c)
- put_extern_sym(sym, NULL, 0, 0);
- rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
+ /* generate bound check local freeing */
+ o(0x5250); /* save returned value, if any */
+ greloc(cur_text_section, sym_data, ind + 1, R_386_32);
+ oad(0xb8, 0); /* mov %eax, xxx */
+ gen_static_call(TOK___bound_local_delete);
+ o(0x585a); /* restore returned value, if any */
}
#endif
@@ -1140,22 +1089,31 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
-#ifdef TCC_TARGET_PE
- /* alloca does more than just adjust %rsp on Windows */
- vpush_global_sym(&func_old_type, TOK_alloca);
- vswap(); /* Move alloca ref past allocation size */
- gfunc_call(1);
-#else
- int r;
- r = gv(RC_INT); /* allocation size */
- /* sub r,%rsp */
- o(0x2b);
- o(0xe0 | r);
- /* We align to 16 bytes rather than align */
- /* and ~15, %esp */
- o(0xf0e483);
- vpop();
+ int use_call = 0;
+
+#if defined(CONFIG_TCC_BCHECK)
+ use_call = tcc_state->do_bounds_check;
#endif
+#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */
+ use_call = 1;
+#endif
+ if (use_call)
+ {
+ vpush_global_sym(&func_old_type, TOK_alloca);
+ vswap(); /* Move alloca ref past allocation size */
+ gfunc_call(1);
+ }
+ else {
+ int r;
+ r = gv(RC_INT); /* allocation size */
+ /* sub r,%rsp */
+ o(0x2b);
+ o(0xe0 | r);
+ /* We align to 16 bytes rather than align */
+ /* and ~15, %esp */
+ o(0xf0e483);
+ vpop();
+ }
}
/* end of X86 code generator */
diff --git a/i386-link.c b/i386-link.c
index aea3c21..e4929b4 100644
--- a/i386-link.c
+++ b/i386-link.c
@@ -22,6 +22,7 @@
#include "tcc.h"
+#ifndef ELF_OBJ_ONLY
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
@@ -44,8 +45,6 @@ int code_reloc (int reloc_type)
case R_386_JMP_SLOT:
return 1;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -81,8 +80,6 @@ int gotplt_entry_type (int reloc_type)
case R_386_PLT32:
return ALWAYS_GOTPLT_ENTRY;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -152,13 +149,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
}
-
-static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
-
-void relocate_init(Section *sr)
-{
- qrel = (ElfW_Rel *) sr->data;
-}
+#endif
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
@@ -169,7 +160,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
switch (type) {
case R_386_32:
if (s1->output_type == TCC_OUTPUT_DLL) {
- esym_index = s1->sym_attrs[sym_index].dyn_index;
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
@@ -185,7 +176,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_386_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
- esym_index = s1->sym_attrs[sym_index].dyn_index;
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
@@ -211,7 +202,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_386_GOT32:
case R_386_GOT32X:
/* we load the got offset */
- add32le(ptr, s1->sym_attrs[sym_index].got_offset);
+ add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
return;
case R_386_16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
diff --git a/include/float.h b/include/float.h
index f16f1f0..35b28f2 100644
--- a/include/float.h
+++ b/include/float.h
@@ -39,17 +39,32 @@
#define LDBL_MAX 1.18973149535723176502e+4932L
#define LDBL_MAX_10_EXP 4932
+#elif defined __aarch64__ || defined __riscv
+/*
+ * Use values from:
+ * gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g"
+ */
+#define LDBL_MANT_DIG 113
+#define LDBL_DIG 33
+#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L
+#define LDBL_MIN_EXP (-16381)
+#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L
+#define LDBL_MIN_10_EXP (-4931)
+#define LDBL_MAX_EXP 16384
+#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L
+#define LDBL_MAX_EXP 16384
+
#else
/* same as IEEE double */
#define LDBL_MANT_DIG 53
#define LDBL_DIG 15
-#define LDBL_EPSILON 2.2204460492503131e-16
+#define LDBL_EPSILON 2.2204460492503131e-16L
#define LDBL_MIN_EXP (-1021)
-#define LDBL_MIN 2.2250738585072014e-308
+#define LDBL_MIN 2.2250738585072014e-308L
#define LDBL_MIN_10_EXP (-307)
#define LDBL_MAX_EXP 1024
-#define LDBL_MAX 1.7976931348623157e+308
+#define LDBL_MAX 1.7976931348623157e+308L
#define LDBL_MAX_10_EXP 308
#endif
diff --git a/include/stdalign.h b/include/stdalign.h
new file mode 100644
index 0000000..ae46c34
--- /dev/null
+++ b/include/stdalign.h
@@ -0,0 +1,16 @@
+#ifndef _STDALIGN_H
+#define _STDALIGN_H
+
+#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__))
+# define _Alignas(t) __attribute__((__aligned__(t)))
+# define _Alignof(t) __alignof__(t)
+#endif
+
+#define alignas _Alignas
+#define alignof _Alignof
+
+#define __alignas_is_defined 1
+#define __alignof_is_defined 1
+
+#endif /* _STDALIGN_H */
+
diff --git a/include/stdarg.h b/include/stdarg.h
index 10ce733..aa784da 100644
--- a/include/stdarg.h
+++ b/include/stdarg.h
@@ -1,76 +1,11 @@
#ifndef _STDARG_H
#define _STDARG_H
-#ifdef __x86_64__
-#ifndef _WIN64
-
-//This should be in sync with the declaration on our lib/libtcc1.c
-/* GCC compatible definition of va_list. */
-typedef struct {
- unsigned int gp_offset;
- unsigned int fp_offset;
- union {
- unsigned int overflow_offset;
- char *overflow_arg_area;
- };
- char *reg_save_area;
-} __va_list_struct;
-
-typedef __va_list_struct va_list[1];
-
-void __va_start(__va_list_struct *ap, void *fp);
-void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);
-
-#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0))
-#define va_arg(ap, type) \
- (*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type))))
-#define va_copy(dest, src) (*(dest) = *(src))
-#define va_end(ap)
-
-/* avoid conflicting definition for va_list on Macs. */
-#define _VA_LIST_T
-
-#else /* _WIN64 */
-typedef char *va_list;
-#define va_start(ap,last) __builtin_va_start(ap,last)
-#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
- ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
-#define va_copy(dest, src) ((dest) = (src))
-#define va_end(ap)
-#endif
-
-#elif __arm__
-typedef char *va_list;
-#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
-#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
- & ~(_tcc_alignof(type) - 1))
-#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
-#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
- &~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
-#define va_copy(dest, src) (dest) = (src)
-#define va_end(ap)
-
-#elif defined(__aarch64__)
-typedef struct {
- void *__stack;
- void *__gr_top;
- void *__vr_top;
- int __gr_offs;
- int __vr_offs;
-} va_list;
-#define va_start(ap, last) __va_start(ap, last)
-#define va_arg(ap, type) __va_arg(ap, type)
-#define va_end(ap)
-#define va_copy(dest, src) ((dest) = (src))
-
-#else /* __i386__ */
-typedef char *va_list;
-/* only correct for i386 */
-#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
-#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
-#define va_copy(dest, src) (dest) = (src)
-#define va_end(ap)
-#endif
+typedef __builtin_va_list va_list;
+#define va_start __builtin_va_start
+#define va_arg __builtin_va_arg
+#define va_copy __builtin_va_copy
+#define va_end __builtin_va_end
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;
diff --git a/include/stddef.h b/include/stddef.h
index 694d503..773006f 100644
--- a/include/stddef.h
+++ b/include/stddef.h
@@ -8,12 +8,16 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __PTRDIFF_TYPE__ intptr_t;
typedef __SIZE_TYPE__ uintptr_t;
+#if __STDC_VERSION__ >= 201112L
+typedef union { long long __ll; long double __ld; } max_align_t;
+#endif
+
#ifndef __int8_t_defined
#define __int8_t_defined
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
-#ifdef __LP64__
+#if defined(__LP64__) && !defined(__APPLE__)
typedef signed long int int64_t;
#else
typedef signed long long int int64_t;
@@ -21,7 +25,7 @@ typedef signed long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
-#ifdef __LP64__
+#if defined(__LP64__) && !defined(__APPLE__)
typedef unsigned long int uint64_t;
#else
typedef unsigned long long int uint64_t;
@@ -32,6 +36,7 @@ typedef unsigned long long int uint64_t;
#define NULL ((void*)0)
#endif
+#undef offsetof
#define offsetof(type, field) ((size_t)&((type *)0)->field)
void *alloca(size_t size);
diff --git a/include/stdnoreturn.h b/include/stdnoreturn.h
new file mode 100644
index 0000000..4d580ea
--- /dev/null
+++ b/include/stdnoreturn.h
@@ -0,0 +1,7 @@
+#ifndef _STDNORETURN_H
+#define _STDNORETURN_H
+
+/* ISOC11 noreturn */
+#define noreturn _Noreturn
+
+#endif /* _STDNORETURN_H */
diff --git a/lib/Makefile b/lib/Makefile
index 0c1ec54..bc57be7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -7,67 +7,86 @@ include $(TOP)/Makefile
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
-BIN = $(TOP)/$(X)libtcc1.a
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))
+XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
XCFG = $(or $(findstring -win,$T),-unx)
+S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
-# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
+# 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
+ XFLAGS = $(CFLAGS) -fPIC -gstabs -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable
endif
# only for native compiler
$(X)BCHECK_O = bcheck.o
+$(X)BT_O = bt-exe.o bt-log.o
+$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
BCHECK_O =
+else
+ DSO_O = dsohandle.o
endif
-ifdef CONFIG_OSX
- XFLAGS += -D_ANSI_SOURCE
-endif
-
-I386_O = libtcc1.o alloca86.o alloca86-bt.o
-X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
-ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
-ARM64_O = lib-arm64.o
+I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
+X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
+ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o fetch_and_add_arm.o $(BT_O)
+ARM64_O = lib-arm64.o fetch_and_add_arm64.o $(BT_O)
+RISCV64_O = lib-arm64.o fetch_and_add_riscv64.o $(BT_O)
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
-OBJ-i386 = $(I386_O) $(BCHECK_O)
-OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O)
-OBJ-x86_64-osx = $(X86_64_O) va_list.o
-OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
-OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
-OBJ-arm64 = $(ARM64_O)
-OBJ-arm = $(ARM_O)
-OBJ-arm-fpa = $(ARM_O)
-OBJ-arm-fpa-ld = $(ARM_O)
-OBJ-arm-vfp = $(ARM_O)
-OBJ-arm-eabi = $(ARM_O)
-OBJ-arm-eabihf = $(ARM_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-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)))
-$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
- $(XAR) rcs $@ $^
+ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
+
+all: $(ALL)
+
+$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1)
+ $S$(XAR) rcs $@ $^
$(X)%.o : %.c
- $(XCC) -c $< -o $@ $(XFLAGS)
+ $S$(XCC) -c $< -o $@ $(XFLAGS)
$(X)%.o : %.S
- $(XCC) -c $< -o $@ $(XFLAGS)
+ $S$(XCC) -c $< -o $@ $(XFLAGS)
+
+$(TOP)/%.o : %.c
+ $S$(XCC) -c $< -o $@ $(XFLAGS)
+
+$(TOP)/bcheck.o : XFLAGS += -g
+$(TOP)/bt-exe.o : $(TOP)/tccrun.c
$(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c
clean :
- rm -f *.a *.o $(BIN)
+ rm -f *.a *.o $(ALL)
diff --git a/lib/alloca86-bt.S b/lib/alloca86-bt.S
index 4f95cf1..177838a 100644
--- a/lib/alloca86-bt.S
+++ b/lib/alloca86-bt.S
@@ -1,9 +1,14 @@
/* ---------------------------------------------- */
/* alloca86-bt.S */
-.globl __bound_alloca
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
-__bound_alloca:
+.globl _(__bound_alloca)
+_(__bound_alloca):
pop %edx
pop %eax
mov %eax, %ecx
@@ -30,8 +35,8 @@ p5:
push %eax
push %ecx
push %eax
- call __bound_new_region
- add $8, %esp
+ call _(__bound_new_region)
+ add $8, %esp
pop %eax
pop %edx
diff --git a/lib/alloca86.S b/lib/alloca86.S
index bb7a2c2..bdc7391 100644
--- a/lib/alloca86.S
+++ b/lib/alloca86.S
@@ -1,9 +1,14 @@
/* ---------------------------------------------- */
/* alloca86.S */
-.globl alloca
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
-alloca:
+.globl _(alloca)
+_(alloca):
pop %edx
pop %eax
add $3,%eax
diff --git a/lib/alloca86_64-bt.S b/lib/alloca86_64-bt.S
index 4cbad90..d1df3a9 100644
--- a/lib/alloca86_64-bt.S
+++ b/lib/alloca86_64-bt.S
@@ -1,39 +1,34 @@
/* ---------------------------------------------- */
/* alloca86_64.S */
-.globl __bound_alloca
-__bound_alloca:
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
+.globl _(__bound_alloca)
+_(__bound_alloca):
#ifdef _WIN32
- # bound checking is not implemented
- pop %rdx
- mov %rcx,%rax
- add $15,%rax
- and $-16,%rax
- jz p3
-
-p1:
- cmp $4096,%rax
- jbe p2
- test %rax,-4096(%rsp)
- sub $4096,%rsp
- sub $4096,%rax
- jmp p1
-p2:
-
- sub %rax,%rsp
- mov %rsp,%rax
- add $32,%rax
-
-p3:
- push %rdx
+ 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,%rax
+ add $15 + 1,%rax # add one extra to separate regions
and $-16,%rax
jz p3
@@ -44,7 +39,7 @@ p3:
push %rdx
push %rax
- call __bound_new_region
+ call _(__bound_new_region)
pop %rax
pop %rdx
diff --git a/lib/alloca86_64.S b/lib/alloca86_64.S
index ae3c97d..5195eca 100644
--- a/lib/alloca86_64.S
+++ b/lib/alloca86_64.S
@@ -1,9 +1,14 @@
/* ---------------------------------------------- */
/* alloca86_64.S */
-.globl alloca
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
-alloca:
+.globl _(alloca)
+_(alloca):
pop %rdx
#ifdef _WIN32
mov %rcx,%rax
@@ -24,7 +29,6 @@ p1:
jmp p1
p2:
#endif
-
sub %rax,%rsp
mov %rsp,%rax
p3:
diff --git a/lib/armflush.c b/lib/armflush.c
index eae3260..13955e1 100644
--- a/lib/armflush.c
+++ b/lib/armflush.c
@@ -7,12 +7,12 @@
#ifdef __TINYC__
/* syscall wrapper */
-unsigned syscall(unsigned syscall_nr, ...);
+unsigned _tccsyscall(unsigned syscall_nr, ...);
/* arm-tcc supports only fake asm currently */
__asm__(
- ".global syscall\n"
- "syscall:\n"
+ ".global _tccsyscall\n"
+ "_tccsyscall:\n"
".int 0xe92d4080\n" // push {r7, lr}
".int 0xe1a07000\n" // mov r7, r0
".int 0xe1a00001\n" // mov r0, r1
@@ -31,6 +31,8 @@ __asm__(
#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+#define syscall _tccsyscall
+
#else
#define _GNU_SOURCE
diff --git a/lib/bcheck.c b/lib/bcheck.c
index 90f0ad2..9c0a40b 100644
--- a/lib/bcheck.c
+++ b/lib/bcheck.c
@@ -21,218 +21,471 @@
#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 */
+#define BOUND_DEBUG (1)
+#define BOUND_STATISTIC (1)
-#ifdef BOUND_DEBUG
- #define dprintf(a...) fprintf(a)
+#if BOUND_DEBUG
+ #define dprintf(a...) if (print_calls) fprintf(a)
#else
#define dprintf(a...)
#endif
-/* define so that bound array is static (faster, but use memory if
- bound checking not used) */
-/* #define BOUND_STATIC */
+#ifdef __attribute__
+ /* an __attribute__ macro is defined in the system headers */
+ #undef __attribute__
+#endif
+#define FASTCALL __attribute__((regparm(3)))
-/* use malloc hooks. Currently the code cannot be reliable if no hooks */
-#define CONFIG_TCC_MALLOC_HOOKS
-#define HAVE_MEMALIGN
+#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__) \
- || defined(_WIN32)
-//#warning Bound checking does not support malloc (etc.) in this environment.
-#undef CONFIG_TCC_MALLOC_HOOKS
-#undef HAVE_MEMALIGN
-#endif
+ || defined(__dietlibc__)
+
+#define INIT_SEM()
+#define EXIT_SEM()
+#define WAIT_SEM()
+#define POST_SEM()
+#define HAVE_MEMALIGN (0)
+#define MALLOC_REDIR (0)
+#define HAVE_PTHREAD_CREATE (0)
+#define HAVE_CTYPE (0)
+#define HAVE_ERRNO (0)
+
+#elif defined(_WIN32)
+
+#include <windows.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 HAVE_MEMALIGN (0)
+#define MALLOC_REDIR (0)
+#define HAVE_PTHREAD_CREATE (0)
+#define HAVE_CTYPE (0)
+#define HAVE_ERRNO (0)
-#define BOUND_T1_BITS 13
-#define BOUND_T2_BITS 11
-#define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS)
-#define BOUND_E_BITS (sizeof(size_t))
+#else
-#define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS)
-#define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS)
-#define BOUND_T3_SIZE ((size_t)1 << BOUND_T3_BITS)
+#define __USE_GNU /* get RTLD_NEXT */
+#include <sys/mman.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include <errno.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)
+#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)
+#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)
+#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)
+#endif
+#define HAVE_MEMALIGN (1)
+#define MALLOC_REDIR (1)
+#define HAVE_PTHREAD_CREATE (1)
+#define HAVE_CTYPE (1)
+#define HAVE_ERRNO (1)
+
+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 void *(*memalign_redir) (size_t, size_t);
+static int (*pthread_create_redir) (pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg);
+static unsigned int pool_index;
+static unsigned char __attribute__((aligned(16))) initial_pool[256];
+static unsigned char use_sem;
-#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
-#define BOUND_T23_SIZE ((size_t)1 << BOUND_T23_BITS)
+#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))
-/* size of an empty region */
-#define EMPTY_SIZE ((size_t)(-1))
-/* size of an invalid region */
-#define INVALID_SIZE 0
-typedef struct BoundEntry {
+typedef struct tree_node Tree;
+struct tree_node {
+ Tree * left, * right;
size_t start;
size_t size;
- struct BoundEntry *next;
- size_t is_invalid; /* true if pointers outside region are invalid */
-} BoundEntry;
+ unsigned char type;
+ unsigned char is_invalid; /* true if pointers outside region are invalid */
+};
+
+typedef struct alloca_list_struct {
+ size_t fp;
+ void *p;
+ struct alloca_list_struct *next;
+} alloca_list_type;
+
+#if defined(_WIN32)
+#define BOUND_TID_TYPE DWORD
+#define BOUND_GET_TID GetCurrentThreadId()
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__riscv)
+#define BOUND_TID_TYPE pid_t
+#define BOUND_GET_TID syscall (SYS_gettid)
+#else
+#define BOUND_TID_TYPE int
+#define BOUND_GET_TID 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 __bound_init(void);
-void __bound_new_region(void *p, size_t size);
-int __bound_delete_region(void *p);
+void __bound_checking (int no_check);
+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);
+#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_strchr(const char *string, int ch);
+DLL_EXPORT char *__bound_strdup(const char *s);
+
+#if defined(__arm__)
+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
-#ifdef __attribute__
- /* an __attribute__ macro is defined in the system headers */
- #undef __attribute__
+#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 FASTCALL __attribute__((regparm(3)))
-void *__bound_malloc(size_t size, const void *caller);
-void *__bound_memalign(size_t size, size_t align, const void *caller);
-void __bound_free(void *ptr, const void *caller);
-void *__bound_realloc(void *ptr, size_t size, const void *caller);
-static void *libc_malloc(size_t size);
-static void libc_free(void *ptr);
-static void install_malloc_hooks(void);
-static void restore_malloc_hooks(void);
+#define FREE_REUSE_SIZE (100)
+static unsigned int free_reuse_index;
+static void *free_reuse_list[FREE_REUSE_SIZE];
-#ifdef CONFIG_TCC_MALLOC_HOOKS
-static void *saved_malloc_hook;
-static void *saved_free_hook;
-static void *saved_realloc_hook;
-static void *saved_memalign_hook;
+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 int never_fatal;
+static int no_checking = 1;
+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_strchr_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
-/* TCC definitions */
-extern char __bounds_start; /* start of static bounds table */
-/* error message, just for TCC */
-const char *__bound_error_msg;
+/* currently only i386/x86_64 supported. Change for other platforms */
+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
+}
-/* runtime error output */
-extern void rt_error(size_t pc, const char *fmt, ...);
+/* enable/disable checking. This can be used in signal handlers. */
+void __bound_checking (int no_check)
+{
+ fetch_and_add (&no_checking, no_check);
+}
-#ifdef BOUND_STATIC
-static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
-#else
-static BoundEntry **__bound_t1; /* page table */
-#endif
-static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
-static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
-
-static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
-{
- size_t addr, tmp;
- BoundEntry *e;
-
- e = e1;
- while (e != NULL) {
- addr = (size_t)p;
- addr -= e->start;
- if (addr <= e->size) {
- /* put region at the head */
- tmp = e1->start;
- e1->start = e->start;
- e->start = tmp;
- tmp = e1->size;
- e1->size = e->size;
- e->size = tmp;
- return e1;
- }
- e = e->next;
- }
- /* no entry found: return empty entry or invalid entry */
- if (e1->is_invalid)
- return __bound_invalid_t2;
- else
- return __bound_empty_t2;
+/* enable/disable checking. This can be used in signal handlers. */
+void __bound_never_fatal (int neverfatal)
+{
+ fetch_and_add (&never_fatal, neverfatal);
}
+int tcc_backtrace(const char *fmt, ...);
+
/* print a bound error message */
-static void bound_error(const char *fmt, ...)
+#define bound_warning(...) \
+ tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__)
+
+#define bound_error(...) \
+ do { \
+ bound_warning(__VA_ARGS__); \
+ if (never_fatal == 0) \
+ exit(255); \
+ } while (0)
+
+static void bound_alloc_error(const char *s)
{
- __bound_error_msg = fmt;
- fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt);
- *(void **)0 = 0; /* force a runtime error */
+ fprintf(stderr,"FATAL: %s\n",s);
+ exit (1);
}
-static void bound_alloc_error(void)
+static void bound_not_found_warning(const char *file, const char *function,
+ void *ptr)
{
- bound_error("not enough memory for bound checking code");
+ dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
}
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */
-void * FASTCALL __bound_ptr_add(void *p, size_t offset)
+void * __bound_ptr_add(void *p, size_t offset)
{
size_t addr = (size_t)p;
- BoundEntry *e;
- dprintf(stderr, "%s %s: %p %x\n",
- __FILE__, __FUNCTION__, p, (unsigned)offset);
+ if (no_checking)
+ return p + offset;
- __bound_init();
+ dprintf(stderr, "%s, %s(): %p 0x%lx\n",
+ __FILE__, __FUNCTION__, p, (unsigned long)offset);
- e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
- e = (BoundEntry *)((char *)e +
- ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
- addr -= e->start;
- if (addr > e->size) {
- e = __bound_find_region(e, p);
- addr = (size_t)p - e->start;
- }
- addr += offset;
- if (addr >= e->size) {
- fprintf(stderr,"%s %s: %p is outside of the region\n",
- __FILE__, __FUNCTION__, p + offset);
- return INVALID_POINTER; /* return an invalid pointer */
+ 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 * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
-{ \
- size_t addr = (size_t)p; \
- BoundEntry *e; \
- \
- dprintf(stderr, "%s %s: %p %x start\n", \
- __FILE__, __FUNCTION__, p, (unsigned)offset); \
- \
- __bound_init(); \
- e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
- e = (BoundEntry *)((char *)e + \
- ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
- addr -= e->start; \
- if (addr > e->size) { \
- e = __bound_find_region(e, p); \
- addr = (size_t)p - e->start; \
- } \
- addr += offset + dsize; \
- if (addr > e->size) { \
- fprintf(stderr,"%s %s: %p is outside of the region\n", \
- __FILE__, __FUNCTION__, p + offset); \
- return INVALID_POINTER; /* return an invalid pointer */ \
- } \
- dprintf(stderr, "%s %s: return p+offset = %p\n", \
- __FILE__, __FUNCTION__, p + offset); \
- return p + offset; \
+#define BOUND_PTR_INDIR(dsize) \
+void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
+{ \
+ size_t addr = (size_t)p; \
+ \
+ if (no_checking) \
+ 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)
@@ -260,720 +513,1359 @@ BOUND_PTR_INDIR(16)
/* called when entering a function to add all the local regions */
void FASTCALL __bound_local_new(void *p1)
{
- size_t addr, size, fp, *p = p1;
+ size_t addr, fp, *p = p1;
- dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p);
+ if (no_checking)
+ return;
GET_CALLER_FP(fp);
- for(;;) {
- addr = p[0];
- if (addr == 0)
- break;
- addr += fp;
- size = p[1];
+ 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;
- __bound_new_region((void *)addr, size);
}
- dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
+ 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)
+ return;
GET_CALLER_FP(fp);
- for(;;) {
- addr = p[0];
- if (addr == 0)
- break;
- addr += 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;
- __bound_delete_region((void *)addr);
}
-}
-
-#if defined(__GNUC__) && (__GNUC__ >= 6)
-#pragma GCC diagnostic pop
-#endif
-
-static BoundEntry *__bound_new_page(void)
-{
- BoundEntry *page;
- size_t i;
+ 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);
+ }
- page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
- if (!page)
- bound_alloc_error();
- for(i=0;i<BOUND_T2_SIZE;i++) {
- /* put empty entries */
- page[i].start = 0;
- page[i].size = EMPTY_SIZE;
- page[i].next = NULL;
- page[i].is_invalid = 0;
+ 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;
+ }
}
- return page;
+#endif
}
-/* currently we use malloc(). Should use bound_new_page() */
-static BoundEntry *bound_new_entry(void)
+/* used by alloca */
+void __bound_new_region(void *p, size_t size)
{
- BoundEntry *e;
- e = libc_malloc(sizeof(BoundEntry));
- return e;
-}
+ size_t fp;
+ alloca_list_type *last;
+ alloca_list_type *cur;
+ alloca_list_type *new;
-static void bound_free_entry(BoundEntry *e)
-{
- libc_free(e);
-}
+ if (no_checking)
+ return;
-static BoundEntry *get_page(size_t index)
-{
- BoundEntry *page;
- page = __bound_t1[index];
- if (!page || page == __bound_empty_t2 || page == __bound_invalid_t2) {
- /* create a new page if necessary */
- page = __bound_new_page();
- __bound_t1[index] = page;
+ 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 (cur->fp == fp && cur->p == p) {
+ if (last)
+ last->next = cur->next;
+ else
+ alloca_list = cur->next;
+ tree = splay_delete((size_t)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->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);
}
- return page;
}
-/* mark a region as being invalid (can only be used during init) */
-static void mark_invalid(size_t addr, size_t size)
+void __bound_setjmp(jmp_buf env)
{
- size_t start, end;
- BoundEntry *page;
- size_t t1_start, t1_end, i, j, t2_start, t2_end;
-
- start = addr;
- end = addr + size;
-
- t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
- if (end != 0)
- t2_end = end >> BOUND_T3_BITS;
- else
- t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
-
-#if 0
- dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end);
-#endif
-
- /* first we handle full pages */
- t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
- t1_end = t2_end >> BOUND_T2_BITS;
-
- i = t2_start & (BOUND_T2_SIZE - 1);
- j = t2_end & (BOUND_T2_SIZE - 1);
-
- if (t1_start == t1_end) {
- page = get_page(t2_start >> BOUND_T2_BITS);
- for(; i < j; i++) {
- page[i].size = INVALID_SIZE;
- page[i].is_invalid = 1;
+ jmp_list_type *jl;
+ void *e = (void *) env;
+
+ if (no_checking == 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;
}
- } else {
- if (i > 0) {
- page = get_page(t2_start >> BOUND_T2_BITS);
- for(; i < BOUND_T2_SIZE; i++) {
- page[i].size = INVALID_SIZE;
- page[i].is_invalid = 1;
+ if (jl == NULL) {
+ jl = BOUND_MALLOC (sizeof (jmp_list_type));
+ if (jl) {
+ jl->penv = e;
+ jl->next = jmp_list;
+ jmp_list = jl;
}
}
- for(i = t1_start; i < t1_end; i++) {
- __bound_t1[i] = __bound_invalid_t2;
- }
- if (j != 0) {
- page = get_page(t1_end);
- for(i = 0; i < j; i++) {
- page[i].size = INVALID_SIZE;
- page[i].is_invalid = 1;
- }
+ if (jl) {
+ size_t fp;
+
+ GET_CALLER_FP (fp);
+ jl->fp = fp;
+ jl->end_fp = (size_t)__builtin_frame_address(0);
+ jl->tid = BOUND_GET_TID;
}
+ POST_SEM ();
}
}
-void __bound_init(void)
+static void __bound_long_jump(jmp_buf env, int val, int sig, const char *func)
{
- size_t i;
- BoundEntry *page;
- size_t start, size;
- size_t *p;
-
- static int inited;
- if (inited)
- return;
-
- inited = 1;
-
- dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
-
- /* save malloc hooks and install bound check hooks */
- install_malloc_hooks();
-
-#ifndef BOUND_STATIC
- __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
- if (!__bound_t1)
- bound_alloc_error();
-#endif
- __bound_empty_t2 = __bound_new_page();
- for(i=0;i<BOUND_T1_SIZE;i++) {
- __bound_t1[i] = __bound_empty_t2;
- }
-
- page = __bound_new_page();
- for(i=0;i<BOUND_T2_SIZE;i++) {
- /* put invalid entries */
- page[i].start = 0;
- page[i].size = INVALID_SIZE;
- page[i].next = NULL;
- page[i].is_invalid = 1;
- }
- __bound_invalid_t2 = page;
-
- /* invalid pointer zone */
- start = (size_t)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
- size = BOUND_T23_SIZE;
- mark_invalid(start, size);
-
-#if defined(CONFIG_TCC_MALLOC_HOOKS)
- /* malloc zone is also marked invalid. can only use that with
- * hooks because all libs should use the same malloc. The solution
- * would be to build a new malloc for tcc.
- *
- * usually heap (= malloc zone) comes right after bss, i.e. after _end, but
- * not always - either if we are running from under `tcc -b -run`, or if
- * address space randomization is turned on(a), heap start will be separated
- * from bss end.
- *
- * So sbrk(0) will be a good approximation for start_brk:
- *
- * - if we are a separately compiled program, __bound_init() runs early,
- * and sbrk(0) should be equal or very near to start_brk(b) (in case other
- * constructors malloc something), or
- *
- * - if we are running from under `tcc -b -run`, sbrk(0) will return
- * start of heap portion which is under this program control, and not
- * mark as invalid earlier allocated memory.
- *
- *
- * (a) /proc/sys/kernel/randomize_va_space = 2, on Linux;
- * usually turned on by default.
- *
- * (b) on Linux >= v3.3, the alternative is to read
- * start_brk from /proc/self/stat
- */
- start = (size_t)sbrk(0);
- size = 128 * 0x100000;
- mark_invalid(start, size);
-#endif
-
- /* add all static bound check values */
- p = (size_t *)&__bounds_start;
- while (p[0] != 0) {
- __bound_new_region((void *)p[0], p[1]);
- p += 2;
+ jmp_list_type *jl;
+ void *e;
+ BOUND_TID_TYPE tid;
+
+ if (no_checking == 0) {
+ e = (void *)env;
+ tid = BOUND_GET_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();
}
-
- dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
+#if !defined(_WIN32)
+ sig ? siglongjmp(env, val) :
+#endif
+ longjmp (env, val);
}
-void __bound_main_arg(void **p)
+void __bound_longjmp(jmp_buf env, int val)
{
- void *start = p;
- while (*p++);
-
- dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n",
- __FILE__, __FUNCTION__, start, (unsigned)((void *)p - start));
-
- __bound_new_region(start, (void *) p - start);
+ __bound_long_jump(env,val, 0, __FUNCTION__);
}
-void __bound_exit(void)
+#if !defined(_WIN32)
+void __bound_siglongjmp(jmp_buf env, int val)
{
- dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
- restore_malloc_hooks();
+ __bound_long_jump(env,val, 1, __FUNCTION__);
}
+#endif
-static inline void add_region(BoundEntry *e,
- size_t start, size_t size)
-{
- BoundEntry *e1;
- if (e->start == 0) {
- /* no region : add it */
- e->start = start;
- e->size = size;
- } else {
- /* already regions in the list: add it at the head */
- e1 = bound_new_entry();
- e1->start = e->start;
- e1->size = e->size;
- e1->next = e->next;
- e->start = start;
- e->size = size;
- e->next = e1;
- }
-}
+#if defined(__GNUC__) && (__GNUC__ >= 6)
+#pragma GCC diagnostic pop
+#endif
-/* create a new region. It should not already exist in the region list */
-void __bound_new_region(void *p, size_t size)
+void __bound_init(size_t *p, int mode)
{
- size_t start, end;
- BoundEntry *page, *e, *e2;
- size_t t1_start, t1_end, i, t2_start, t2_end;
-
- dprintf(stderr, "%s, %s(%p, %x) start\n",
- __FILE__, __FUNCTION__, p, (unsigned)size);
-
- __bound_init();
-
- start = (size_t)p;
- end = start + size;
- t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
- t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
-
- /* start */
- page = get_page(t1_start);
- t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
- t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
+ 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;
- e = (BoundEntry *)((char *)page + t2_start);
- add_region(e, start, size);
+ 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);
+#endif
+ }
+#endif
- if (t1_end == t1_start) {
- /* same ending page */
- e2 = (BoundEntry *)((char *)page + t2_end);
- if (e2 > e) {
- e++;
- for(;e<e2;e++) {
- e->start = start;
- e->size = size;
- }
- add_region(e, start, size);
+#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);
}
- } else {
- /* mark until end of page */
- e2 = page + BOUND_T2_SIZE;
- e++;
- for(;e<e2;e++) {
- e->start = start;
- e->size = size;
- }
- /* mark intermediate pages, if any */
- for(i=t1_start+1;i<t1_end;i++) {
- page = get_page(i);
- e2 = page + BOUND_T2_SIZE;
- for(e=page;e<e2;e++) {
- e->start = start;
- e->size = size;
+ /* 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);
}
- /* last page */
- page = get_page(t1_end);
- e2 = (BoundEntry *)((char *)page + t2_end);
- for(e=page;e<e2;e++) {
- e->start = start;
- e->size = size;
+ if (found == 0) {
+ use_sem = 1;
+ no_strdup = 1;
}
- add_region(e, start, size);
}
+#endif
- dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
-}
+ WAIT_SEM ();
-/* delete a region */
-static inline void delete_region(BoundEntry *e, void *p, size_t empty_size)
-{
- size_t addr;
- BoundEntry *e1;
+#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
- addr = (size_t)p;
- addr -= e->start;
- if (addr <= e->size) {
- /* region found is first one */
- e1 = e->next;
- if (e1 == NULL) {
- /* no more region: mark it empty */
- e->start = 0;
- e->size = empty_size;
- } else {
- /* copy next region in head */
- e->start = e1->start;
- e->size = e1->size;
- e->next = e1->next;
- bound_free_entry(e1);
- }
- } else {
- /* find the matching region */
- for(;;) {
- e1 = e;
- e = e->next;
- /* region not found: do nothing */
- if (e == NULL)
- break;
- addr = (size_t)p - e->start;
- if (addr <= e->size) {
- /* found: remove entry */
- e1->next = e->next;
- bound_free_entry(e);
- break;
- }
+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 = 0;
+ dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
}
-/* WARNING: 'p' must be the starting point of the region. */
-/* return non zero if error */
-int __bound_delete_region(void *p)
+void
+#if (defined(__GLIBC__) && (__GLIBC_MINOR__ >= 4)) || defined(_WIN32)
+__attribute__((constructor))
+#endif
+__bound_main_arg(int argc, char **argv, char **envp)
{
- size_t start, end, addr, size, empty_size;
- BoundEntry *page, *e, *e2;
- size_t t1_start, t1_end, t2_start, t2_end, i;
-
- dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__);
+ __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 0x%lx\n",
+ __FILE__, __FUNCTION__, argv, (argc + 1) * sizeof(char *));
+ }
+#endif
+ }
- __bound_init();
+ if (envp && *envp) {
+ char **p = envp;
- start = (size_t)p;
- t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
- t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
-
- /* find region size */
- page = __bound_t1[t1_start];
- e = (BoundEntry *)((char *)page + t2_start);
- addr = start - e->start;
- if (addr > e->size)
- e = __bound_find_region(e, p);
- /* test if invalid region */
- if (e->size == EMPTY_SIZE || (size_t)p != e->start)
- return -1;
- /* compute the size we put in invalid regions */
- if (e->is_invalid)
- empty_size = INVALID_SIZE;
- else
- empty_size = EMPTY_SIZE;
- size = e->size;
- end = start + size;
-
- /* now we can free each entry */
- t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
- t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
-
- delete_region(e, p, empty_size);
- if (t1_end == t1_start) {
- /* same ending page */
- e2 = (BoundEntry *)((char *)page + t2_end);
- if (e2 > e) {
- e++;
- for(;e<e2;e++) {
- e->start = 0;
- e->size = empty_size;
- }
- delete_region(e, p, empty_size);
+ WAIT_SEM ();
+ while (*p) {
+ tree = splay_insert((size_t) *p, strlen (*p) + 1, tree);
+ ++p;
}
- } else {
- /* mark until end of page */
- e2 = page + BOUND_T2_SIZE;
- e++;
- for(;e<e2;e++) {
- e->start = 0;
- e->size = empty_size;
- }
- /* mark intermediate pages, if any */
- /* XXX: should free them */
- for(i=t1_start+1;i<t1_end;i++) {
- page = get_page(i);
- e2 = page + BOUND_T2_SIZE;
- for(e=page;e<e2;e++) {
- e->start = 0;
- e->size = empty_size;
+ 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 0x%lx\n",
+ __FILE__, __FUNCTION__, envp, (++p - envp) * sizeof(char *));
}
- /* last page */
- page = get_page(t1_end);
- e2 = (BoundEntry *)((char *)page + t2_end);
- for(e=page;e<e2;e++) {
- e->start = 0;
- e->size = empty_size;
- }
- delete_region(e, p, empty_size);
+#endif
}
-
- dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__);
-
- return 0;
}
-/* return the size of the region starting at p, or EMPTY_SIZE if non
- existent region. */
-static size_t get_region_size(void *p)
+void __attribute__((destructor)) __bound_exit(void)
{
- size_t addr = (size_t)p;
- BoundEntry *e;
-
- e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
- e = (BoundEntry *)((char *)e +
- ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
- ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
- addr -= e->start;
- if (addr > e->size)
- e = __bound_find_region(e, p);
- if (e->start != (size_t)p)
- return EMPTY_SIZE;
- return e->size;
-}
+ 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__)
+ if (print_heap) {
+ extern void __libc_freeres (void);
+ __libc_freeres ();
+ }
+#endif
-/* patched memory functions */
+ no_checking = 1;
-/* force compiler to perform stores coded up to this point */
-#define barrier() __asm__ __volatile__ ("": : : "memory")
+ WAIT_SEM ();
+ while (alloca_list) {
+ alloca_list_type *next = alloca_list->next;
-static void install_malloc_hooks(void)
-{
-#ifdef CONFIG_TCC_MALLOC_HOOKS
- saved_malloc_hook = __malloc_hook;
- saved_free_hook = __free_hook;
- saved_realloc_hook = __realloc_hook;
- saved_memalign_hook = __memalign_hook;
- __malloc_hook = __bound_malloc;
- __free_hook = __bound_free;
- __realloc_hook = __bound_realloc;
- __memalign_hook = __bound_memalign;
+ 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;
- barrier();
+ 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
-}
-
-static void restore_malloc_hooks(void)
-{
-#ifdef CONFIG_TCC_MALLOC_HOOKS
- __malloc_hook = saved_malloc_hook;
- __free_hook = saved_free_hook;
- __realloc_hook = saved_realloc_hook;
- __memalign_hook = saved_memalign_hook;
-
- barrier();
+ POST_SEM ();
+ EXIT_SEM ();
+ 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_strchr_count %llu\n", bound_strchr_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
+ }
+ }
}
-static void *libc_malloc(size_t size)
-{
- void *ptr;
- restore_malloc_hooks();
- ptr = malloc(size);
- install_malloc_hooks();
- return ptr;
-}
-
-static void libc_free(void *ptr)
+#if HAVE_PTHREAD_CREATE
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start_routine) (void *), void *arg)
{
- restore_malloc_hooks();
- free(ptr);
- install_malloc_hooks();
+ use_sem = 1;
+ dprintf (stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
+ return pthread_create_redir(thread, attr, start_routine, arg);
}
+#endif
-/* XXX: we should use a malloc which ensure that it is unlikely that
- two malloc'ed data have the same address if 'free' are made in
- between. */
+#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 = libc_malloc(size + 1);
+ ptr = BOUND_MALLOC (size + 1);
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
- if (!ptr)
- return NULL;
-
- dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
- __FILE__, __FUNCTION__, ptr, (unsigned)size);
-
- __bound_new_region(ptr, size);
+ if (no_checking == 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;
- restore_malloc_hooks();
-
-#ifndef HAVE_MEMALIGN
+#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 = malloc(size + 1);
+ ptr = BOUND_MALLOC(size + 1);
}
-#else
- /* 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 = memalign(size + 1, align);
#endif
-
- install_malloc_hooks();
-
- if (!ptr)
- return NULL;
+ dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
+ __FILE__, __FUNCTION__, ptr, (unsigned long)size);
- dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
- __FILE__, __FUNCTION__, ptr, (unsigned)size);
+ if (no_checking == 0) {
+ WAIT_SEM ();
+ INCR_COUNT(bound_memalign_count);
- __bound_new_region(ptr, size);
+ 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
{
- if (ptr == NULL)
+ 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;
- if (__bound_delete_region(ptr) != 0)
- bound_error("freeing invalid region");
- libc_free(ptr);
+ dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, ptr);
+
+ if (no_checking == 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 *ptr1;
- size_t old_size;
+ void *new_ptr;
if (size == 0) {
+#if MALLOC_REDIR
+ free(ptr);
+#else
__bound_free(ptr, caller);
+#endif
return NULL;
- } else {
- ptr1 = __bound_malloc(size, caller);
- if (ptr == NULL || ptr1 == NULL)
- return ptr1;
- old_size = get_region_size(ptr);
- if (old_size == EMPTY_SIZE)
- bound_error("realloc'ing invalid pointer");
- memcpy(ptr1, ptr, old_size);
- __bound_free(ptr, caller);
- return ptr1;
}
+
+ 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 == 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;
}
-#ifndef CONFIG_TCC_MALLOC_HOOKS
+#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 = size * nmemb;
- ptr = __bound_malloc(size, NULL);
- if (!ptr)
- return NULL;
- memset(ptr, 0, size);
+
+ 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 == 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;
}
-#endif
-#if 0
-static void bound_dump(void)
-{
- BoundEntry *page, *e;
- size_t i, j;
-
- fprintf(stderr, "region dump:\n");
- for(i=0;i<BOUND_T1_SIZE;i++) {
- page = __bound_t1[i];
- for(j=0;j<BOUND_T2_SIZE;j++) {
- e = page + j;
- /* do not print invalid or empty entries */
- if (e->size != EMPTY_SIZE && e->start != 0) {
- fprintf(stderr, "%08x:",
- (i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
- (j << BOUND_T3_BITS));
- do {
- fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size);
- e = e->next;
- } while (e != NULL);
- fprintf(stderr, "\n");
- }
- }
+#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 == 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 == 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)
+static void __bound_check(const void *p, size_t size, const char *function)
{
- if (size == 0)
- return;
- p = __bound_ptr_add((void *)p, size - 1);
- if (p == INVALID_POINTER)
- bound_error("invalid pointer");
+ 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);
+ }
}
-void *__bound_memcpy(void *dst, const void *src, size_t size)
+static int check_overlap (const void *p1, size_t n1,
+ const void *p2, size_t n2,
+ const char *function)
{
- void* p;
+ const void *p1e = (const void *) ((const char *) p1 + n1);
+ const void *p2e = (const void *) ((const char *) p2 + n2);
+
+ if (no_checking == 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;
+}
- dprintf(stderr, "%s %s: start, dst=%p src=%p size=%x\n",
- __FILE__, __FUNCTION__, dst, src, (unsigned)size);
+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);
+}
- __bound_check(dst, size);
- __bound_check(src, size);
- /* check also region overlap */
- if (src >= dst && src < dst + size)
- bound_error("overlapping regions in memcpy()");
+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;
+}
- p = memcpy(dst, src, size);
+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);
+}
- dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p);
- return p;
+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);
}
-void *__bound_memmove(void *dst, const void *src, size_t size)
+#if defined(__arm__)
+void *__bound___aeabi_memcpy(void *dest, const void *src, size_t n)
{
- __bound_check(dst, size);
- __bound_check(src, size);
- return memmove(dst, src, size);
+ 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_memset(void *dst, int c, size_t size)
+void *__bound___aeabi_memmove(void *dest, const void *src, size_t n)
{
- __bound_check(dst, size);
- return memset(dst, c, size);
+ 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);
}
-/* XXX: could be optimized */
+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;
+ 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;
+}
- len = 0;
- for(;;) {
- p = __bound_ptr_indir1((char *)s, len);
- if (p == INVALID_POINTER)
- bound_error("bad pointer in strlen()");
- if (*p == '\0')
+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;
- len++;
+ }
+ ++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_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;
}
- return len;
+ __bound_check(s, ((const char *)str - s) + 1, "strchr");
+ return *str == ch ? (char *) str : NULL;
}
-char *__bound_strcpy(char *dst, const char *src)
+char *__bound_strdup(const char *s)
{
- size_t len;
- void *p;
+ 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 == 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;
+}
- dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n",
- __FILE__, __FUNCTION__, dst, src);
- len = __bound_strlen(src);
- p = __bound_memcpy(dst, src, len + 1);
- dprintf(stderr, "%s %s: strcpy end, p = %p\n",
- __FILE__, __FUNCTION__, p);
- return p;
+/*
+ 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/lib/bt-dll.c b/lib/bt-dll.c
new file mode 100644
index 0000000..3389bd7
--- /dev/null
+++ b/lib/bt-dll.c
@@ -0,0 +1,73 @@
+/* ------------------------------------------------------------- */
+/* stubs for calling bcheck functions from a dll. */
+
+#include <windows.h>
+#include <stdio.h>
+
+#define REDIR_ALL \
+ REDIR(__bt_init) \
+ 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/lib/bt-exe.c b/lib/bt-exe.c
new file mode 100644
index 0000000..a0e8fad
--- /dev/null
+++ b/lib/bt-exe.c
@@ -0,0 +1,43 @@
+/* ------------------------------------------------------------- */
+/* for linking rt_printline and the signal/exception handler
+ from tccrun.c into executables. */
+
+#define CONFIG_TCC_BACKTRACE_ONLY
+#include "../tccrun.c"
+
+int (*__rt_error)(void*, void*, const char *, va_list);
+
+#ifndef _WIN32
+# define __declspec(n)
+#endif
+
+__declspec(dllexport)
+void __bt_init(rt_context *p, int num_callers, int mode)
+{
+ __attribute__((weak)) int main();
+ __attribute__((weak)) void __bound_init(void*, int);
+ struct rt_context *rc = &g_rtctxt;
+ //fprintf(stderr, "__bt_init %d %p %p %d\n", num_callers, p->stab_sym, p->bounds_start, mode), fflush(stderr);
+ 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 (__bound_init && p->bounds_start)
+ __bound_init(p->bounds_start, mode);
+}
+
+/* copy a string and truncate it. */
+static 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/lib/bt-log.c b/lib/bt-log.c
new file mode 100644
index 0000000..d767f08
--- /dev/null
+++ b/lib/bt-log.c
@@ -0,0 +1,37 @@
+/* ------------------------------------------------------------- */
+/* 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
+
+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;
+}
diff --git a/lib/dsohandle.c b/lib/dsohandle.c
new file mode 100644
index 0000000..0993dbc
--- /dev/null
+++ b/lib/dsohandle.c
@@ -0,0 +1 @@
+void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle;
diff --git a/lib/fetch_and_add_arm.S b/lib/fetch_and_add_arm.S
new file mode 100644
index 0000000..773128b
--- /dev/null
+++ b/lib/fetch_and_add_arm.S
@@ -0,0 +1,28 @@
+ .text
+ .align 2
+ .global fetch_and_add_arm
+ .type fetch_and_add_arm, %function
+fetch_and_add_arm:
+#ifdef __TINYC__
+ .int 0xee070fba
+ .int 0xe1903f9f
+ .int 0xe0833001
+ .int 0xe1802f93
+ .int 0xe3520000
+ .int 0x1afffffa
+ .int 0xee070fba
+ .int 0xe12fff1e
+#else
+ .arch armv6
+
+ 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
+#endif
+ .size fetch_and_add_arm, .-fetch_and_add_arm
diff --git a/lib/fetch_and_add_arm64.S b/lib/fetch_and_add_arm64.S
new file mode 100644
index 0000000..5795db5
--- /dev/null
+++ b/lib/fetch_and_add_arm64.S
@@ -0,0 +1,22 @@
+ .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
diff --git a/lib/fetch_and_add_riscv64.S b/lib/fetch_and_add_riscv64.S
new file mode 100644
index 0000000..b4cd575
--- /dev/null
+++ b/lib/fetch_and_add_riscv64.S
@@ -0,0 +1,16 @@
+ .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
diff --git a/lib/lib-arm64.c b/lib/lib-arm64.c
index b8fd9e8..33df509 100644
--- a/lib/lib-arm64.c
+++ b/lib/lib-arm64.c
@@ -24,10 +24,12 @@ void *memcpy(void*,void*,__SIZE_TYPE__);
#include <string.h>
#endif
+#ifndef __riscv
void __clear_cache(void *beg, void *end)
{
__arm64_clear_cache(beg, end);
}
+#endif
typedef struct {
uint64_t x0, x1;
@@ -385,7 +387,12 @@ long double __extendsftf2(float f)
else if (a << 1 >> 24 == 255)
x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
(uint64_t)!!(a << 9) << 47);
- else
+ 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);
@@ -404,7 +411,13 @@ long double __extenddftf2(double f)
else if (a << 1 >> 53 == 2047)
x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
(uint64_t)!!(a << 12) << 47);
- else
+ 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;
diff --git a/lib/va_list.c b/lib/va_list.c
index 8749f46..fab6675 100644
--- a/lib/va_list.c
+++ b/lib/va_list.c
@@ -3,7 +3,6 @@
#if defined __x86_64__
/* Avoid include files, they may not be available when cross compiling */
-extern void *memset(void *s, int c, __SIZE_TYPE__ n);
extern void abort(void);
/* This should be in sync with our include/stdarg.h */
@@ -12,6 +11,7 @@ enum __va_arg_type {
};
/* GCC compatible definition of va_list. */
+/*predefined by TCC (tcc_predefs.h):
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
@@ -20,23 +20,16 @@ typedef struct {
char *overflow_arg_area;
};
char *reg_save_area;
-} __va_list_struct;
+} __builtin_va_list[1];
+*/
-void __va_start(__va_list_struct *ap, void *fp)
-{
- memset(ap, 0, sizeof(__va_list_struct));
- *ap = *(__va_list_struct *)((char *)fp - 16);
- ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
- ap->reg_save_area = (char *)fp - 176 - 16;
-}
-
-void *__va_arg(__va_list_struct *ap,
- enum __va_arg_type arg_type,
+void *__va_arg(__builtin_va_list ap,
+ int arg_type,
int size, int align)
{
size = (size + 7) & ~7;
align = (align + 7) & ~7;
- switch (arg_type) {
+ switch ((enum __va_arg_type)arg_type) {
case __va_gen_reg:
if (ap->gp_offset + size <= 48) {
ap->gp_offset += size;
@@ -60,6 +53,7 @@ void *__va_arg(__va_list_struct *ap,
default: /* should never happen */
abort();
+ return 0;
}
}
#endif
diff --git a/libtcc.c b/libtcc.c
index 1e9dd97..c3d96d4 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -18,25 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "tcc.h"
-
-/********************************************************/
-/* global variables */
-
-/* use GNU C extensions */
-ST_DATA int gnu_ext = 1;
-
-/* use TinyCC extensions */
-ST_DATA int tcc_ext = 1;
-
-/* XXX: get rid of this ASAP */
-ST_DATA struct TCCState *tcc_state;
-
-static int nb_states;
-
-/********************************************************/
-
-#if ONE_SOURCE
+#if !defined ONE_SOURCE || ONE_SOURCE
#include "tccpp.c"
#include "tccgen.c"
#include "tccelf.c"
@@ -45,25 +27,28 @@ static int nb_states;
#include "i386-gen.c"
#include "i386-link.c"
#include "i386-asm.c"
-#endif
-#ifdef TCC_TARGET_ARM
+#elif defined(TCC_TARGET_ARM)
#include "arm-gen.c"
#include "arm-link.c"
#include "arm-asm.c"
-#endif
-#ifdef TCC_TARGET_ARM64
+#elif defined(TCC_TARGET_ARM64)
#include "arm64-gen.c"
#include "arm64-link.c"
-#endif
-#ifdef TCC_TARGET_C67
+#include "arm-asm.c"
+#elif defined(TCC_TARGET_C67)
#include "c67-gen.c"
#include "c67-link.c"
#include "tcccoff.c"
-#endif
-#ifdef TCC_TARGET_X86_64
+#elif defined(TCC_TARGET_X86_64)
#include "x86_64-gen.c"
#include "x86_64-link.c"
#include "i386-asm.c"
+#elif defined(TCC_TARGET_RISCV64)
+#include "riscv64-gen.c"
+#include "riscv64-link.c"
+#include "riscv64-asm.c"
+#else
+#error unknown target
#endif
#ifdef CONFIG_TCC_ASM
#include "tccasm.c"
@@ -71,18 +56,21 @@ static int nb_states;
#ifdef TCC_TARGET_PE
#include "tccpe.c"
#endif
+#ifdef TCC_TARGET_MACHO
+#include "tccmacho.c"
+#endif
#endif /* ONE_SOURCE */
+#include "tcc.h"
+
/********************************************************/
-#ifndef CONFIG_TCC_ASM
-ST_FUNC void asm_instr(void)
-{
- tcc_error("inline asm() not supported");
-}
-ST_FUNC void asm_global_instr(void)
-{
- tcc_error("inline asm() not supported");
-}
+/* global variables */
+
+/* XXX: get rid of this ASAP (or maybe not) */
+ST_DATA struct TCCState *tcc_state;
+
+#ifdef MEM_DEBUG
+static int nb_states;
#endif
/********************************************************/
@@ -130,8 +118,51 @@ BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
#endif
/********************************************************/
+#ifndef CONFIG_TCC_SEMLOCK
+#define WAIT_SEM()
+#define POST_SEM()
+#elif defined _WIN32
+static int tcc_sem_init;
+static CRITICAL_SECTION tcc_cr;
+static void wait_sem(void)
+{
+ if (!tcc_sem_init)
+ InitializeCriticalSection(&tcc_cr), tcc_sem_init = 1;
+ EnterCriticalSection(&tcc_cr);
+}
+#define WAIT_SEM() wait_sem()
+#define POST_SEM() LeaveCriticalSection(&tcc_cr);
+#elif defined __APPLE__
+/* Half-compatible MacOS doesn't have non-shared (process local)
+ semaphores. Use the dispatch framework for lightweight locks. */
+#include <dispatch/dispatch.h>
+static int tcc_sem_init;
+static dispatch_semaphore_t tcc_sem;
+static void wait_sem(void)
+{
+ if (!tcc_sem_init)
+ tcc_sem = dispatch_semaphore_create(1), tcc_sem_init = 1;
+ dispatch_semaphore_wait(tcc_sem, DISPATCH_TIME_FOREVER);
+}
+#define WAIT_SEM() wait_sem()
+#define POST_SEM() dispatch_semaphore_signal(tcc_sem)
+#else
+#include <semaphore.h>
+static int tcc_sem_init;
+static sem_t tcc_sem;
+static void wait_sem(void)
+{
+ if (!tcc_sem_init)
+ sem_init(&tcc_sem, 0, 1), tcc_sem_init = 1;
+ while (sem_wait (&tcc_sem) < 0 && errno == EINTR);
+}
+#define WAIT_SEM() wait_sem()
+#define POST_SEM() sem_post(&tcc_sem)
+#endif
+
+/********************************************************/
/* copy a string and truncate it. */
-ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
+ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s)
{
char *q, *q_end;
int c;
@@ -151,9 +182,9 @@ ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
}
/* strcat and truncate. */
-ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
+ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s)
{
- int len;
+ size_t len;
len = strlen(buf);
if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
@@ -206,7 +237,7 @@ PUB_FUNC void *tcc_malloc(unsigned long size)
void *ptr;
ptr = malloc(size);
if (!ptr && size)
- tcc_error("memory full (malloc)");
+ _tcc_error("memory full (malloc)");
return ptr;
}
@@ -223,7 +254,7 @@ PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size)
void *ptr1;
ptr1 = realloc(ptr, size);
if (!ptr1 && size)
- tcc_error("memory full (realloc)");
+ _tcc_error("memory full (realloc)");
return ptr1;
}
@@ -235,10 +266,6 @@ PUB_FUNC char *tcc_strdup(const char *str)
return ptr;
}
-PUB_FUNC void tcc_memcheck(void)
-{
-}
-
#else
#define MEM_DEBUG_MAGIC1 0xFEEDDEB1
@@ -292,7 +319,7 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
header = malloc(sizeof(mem_debug_header_t) + size);
if (!header)
- tcc_error("memory full (malloc)");
+ _tcc_error("memory full (malloc)");
header->magic1 = MEM_DEBUG_MAGIC1;
header->magic2 = MEM_DEBUG_MAGIC2;
@@ -352,7 +379,7 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
mem_debug_chain_update = (header == mem_debug_chain);
header = realloc(header, sizeof(mem_debug_header_t) + size);
if (!header)
- tcc_error("memory full (realloc)");
+ _tcc_error("memory full (realloc)");
header->size = size;
MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
if (header->next)
@@ -443,6 +470,15 @@ static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *
c = p[1], p += 2;
if (c == 'B')
cstr_cat(&str, s->tcc_lib_path, -1);
+ if (c == 'f' && file) {
+ /* substitute current file's dir */
+ const char *f = file->true_filename;
+ const char *b = tcc_basename(f);
+ if (b > f)
+ cstr_cat(&str, f, b - f - 1);
+ else
+ cstr_cat(&str, ".", 1);
+ }
} else {
cstr_ccat(&str, c);
}
@@ -473,38 +509,71 @@ static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
va_end(ap);
}
-static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
+#define ERROR_WARN 0
+#define ERROR_NOABORT 1
+#define ERROR_ERROR 2
+
+PUB_FUNC void tcc_enter_state(TCCState *s1)
+{
+ WAIT_SEM();
+ tcc_state = s1;
+}
+
+PUB_FUNC void tcc_exit_state(void)
+{
+ tcc_state = NULL;
+ POST_SEM();
+}
+
+static void error1(int mode, const char *fmt, va_list ap)
{
char buf[2048];
BufferedFile **pf, *f;
+ TCCState *s1 = tcc_state;
buf[0] = '\0';
- /* use upper file if inline ":asm:" or token ":paste:" */
- for (f = file; f && f->filename[0] == ':'; f = f->prev)
- ;
+ if (s1 == NULL)
+ /* can happen only if called from tcc_malloc(): 'out of memory' */
+ goto no_file;
+
+ if (s1 && !s1->error_set_jmp_enabled)
+ /* tcc_state just was set by tcc_enter_state() */
+ tcc_exit_state();
+
+ if (mode == ERROR_WARN) {
+ if (s1->warn_none)
+ return;
+ if (s1->warn_error)
+ mode = ERROR_ERROR;
+ }
+
+ f = NULL;
+ if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */
+ /* use upper file if inline ":asm:" or token ":paste:" */
+ for (f = file; f && f->filename[0] == ':'; f = f->prev)
+ ;
+ }
if (f) {
for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
(*pf)->filename, (*pf)->line_num);
- if (s1->error_set_jmp_enabled) {
- strcat_printf(buf, sizeof(buf), "%s:%d: ",
- f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
- } else {
- strcat_printf(buf, sizeof(buf), "%s: ",
- f->filename);
- }
- } else {
- strcat_printf(buf, sizeof(buf), "tcc: ");
+ strcat_printf(buf, sizeof(buf), "%s:%d: ",
+ f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
+ } else if (s1->current_filename) {
+ strcat_printf(buf, sizeof(buf), "%s: ", s1->current_filename);
}
- if (is_warning)
+
+no_file:
+ if (0 == buf[0])
+ strcat_printf(buf, sizeof(buf), "tcc: ");
+ if (mode == ERROR_WARN)
strcat_printf(buf, sizeof(buf), "warning: ");
else
strcat_printf(buf, sizeof(buf), "error: ");
strcat_vprintf(buf, sizeof(buf), fmt, ap);
-
- if (!s1->error_func) {
+ if (!s1 || !s1->error_func) {
/* default case: stderr */
- if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
+ if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
/* print a newline during tcc -E */
printf("\n"), fflush(stdout);
fflush(stdout); /* flush -v output */
@@ -513,55 +582,54 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
} else {
s1->error_func(s1->error_opaque, buf);
}
- if (!is_warning || s1->warn_error)
- s1->nb_errors++;
+ if (s1) {
+ if (mode != ERROR_WARN)
+ s1->nb_errors++;
+ if (mode != ERROR_ERROR)
+ return;
+ if (s1->error_set_jmp_enabled)
+ longjmp(s1->error_jmp_buf, 1);
+ }
+ exit(1);
}
-LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
- void (*error_func)(void *opaque, const char *msg))
+LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func)
{
s->error_opaque = error_opaque;
s->error_func = error_func;
}
+LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s)
+{
+ return s->error_func;
+}
+
+LIBTCCAPI void *tcc_get_error_opaque(TCCState *s)
+{
+ return s->error_opaque;
+}
+
/* error without aborting current compilation */
-PUB_FUNC void tcc_error_noabort(const char *fmt, ...)
+PUB_FUNC void _tcc_error_noabort(const char *fmt, ...)
{
- TCCState *s1 = tcc_state;
va_list ap;
-
va_start(ap, fmt);
- error1(s1, 0, fmt, ap);
+ error1(ERROR_NOABORT, fmt, ap);
va_end(ap);
}
-PUB_FUNC void tcc_error(const char *fmt, ...)
+PUB_FUNC void _tcc_error(const char *fmt, ...)
{
- TCCState *s1 = tcc_state;
va_list ap;
-
va_start(ap, fmt);
- error1(s1, 0, fmt, ap);
- va_end(ap);
- /* better than nothing: in some cases, we accept to handle errors */
- if (s1->error_set_jmp_enabled) {
- longjmp(s1->error_jmp_buf, 1);
- } else {
- /* XXX: eliminate this someday */
- exit(1);
- }
+ for (;;) error1(ERROR_ERROR, fmt, ap);
}
-PUB_FUNC void tcc_warning(const char *fmt, ...)
+PUB_FUNC void _tcc_warning(const char *fmt, ...)
{
- TCCState *s1 = tcc_state;
va_list ap;
-
- if (s1->warn_none)
- return;
-
va_start(ap, fmt);
- error1(s1, 1, fmt, ap);
+ error1(ERROR_WARN, fmt, ap);
va_end(ap);
}
@@ -578,6 +646,9 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
bf->buf_end = bf->buffer + initlen;
bf->buf_end[0] = CH_EOB; /* put eob symbol */
pstrcpy(bf->filename, sizeof(bf->filename), filename);
+#ifdef _WIN32
+ normalize_slashes(bf->filename);
+#endif
bf->true_filename = bf->filename;
bf->line_num = 1;
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
@@ -589,6 +660,7 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
ST_FUNC void tcc_close(void)
{
+ TCCState *s1 = tcc_state;
BufferedFile *bf = file;
if (bf->fd > 0) {
close(bf->fd);
@@ -600,7 +672,7 @@ ST_FUNC void tcc_close(void)
tcc_free(bf);
}
-ST_FUNC int tcc_open(TCCState *s1, const char *filename)
+static int _tcc_open(TCCState *s1, const char *filename)
{
int fd;
if (strcmp(filename, "-") == 0)
@@ -610,37 +682,52 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
printf("%s %*s%s\n", fd < 0 ? "nf":"->",
(int)(s1->include_stack_ptr - s1->include_stack), "", filename);
+ return fd;
+}
+
+ST_FUNC int tcc_open(TCCState *s1, const char *filename)
+{
+ int fd = _tcc_open(s1, filename);
if (fd < 0)
return -1;
tcc_open_bf(s1, filename, 0);
-#ifdef _WIN32
- normalize_slashes(file->filename);
-#endif
file->fd = fd;
- return fd;
+ return 0;
}
/* compile the file opened in 'file'. Return non zero if errors. */
-static int tcc_compile(TCCState *s1)
+static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
{
- Sym *define_start;
- int filetype, is_asm;
+ /* Here we enter the code section where we use the global variables for
+ parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c).
+ Other threads need to wait until we're done.
- define_start = define_stack;
- filetype = s1->filetype;
- is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP;
- tccelf_begin_file(s1);
+ Alternatively we could use thread local storage for those global
+ variables, which may or may not have advantages */
+
+ tcc_enter_state(s1);
if (setjmp(s1->error_jmp_buf) == 0) {
- s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1;
+ s1->nb_errors = 0;
+
+ if (fd == -1) {
+ int len = strlen(str);
+ tcc_open_bf(s1, "<string>", len);
+ memcpy(file->buffer, str, len);
+ } else {
+ tcc_open_bf(s1, str, 0);
+ file->fd = fd;
+ }
- preprocess_start(s1, is_asm);
+ tccelf_begin_file(s1);
+ preprocess_start(s1, filetype);
+ tccgen_init(s1);
if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
tcc_preprocess(s1);
- } else if (is_asm) {
+ } else if (filetype & (AFF_TYPE_ASM | AFF_TYPE_ASMPP)) {
#ifdef CONFIG_TCC_ASM
- tcc_assemble(s1, filetype == AFF_TYPE_ASMPP);
+ tcc_assemble(s1, !!(filetype & AFF_TYPE_ASMPP));
#else
tcc_error_noabort("asm not supported");
#endif
@@ -649,92 +736,55 @@ static int tcc_compile(TCCState *s1)
}
}
s1->error_set_jmp_enabled = 0;
-
+ tccgen_finish(s1);
preprocess_end(s1);
- free_inline_functions(s1);
- /* reset define stack, but keep -D and built-ins */
- free_defines(define_start);
- sym_pop(&global_stack, NULL, 0);
- sym_pop(&local_stack, NULL, 0);
+ tcc_exit_state();
+
tccelf_end_file(s1);
return s1->nb_errors != 0 ? -1 : 0;
}
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
{
- int len, ret;
-
- len = strlen(str);
- tcc_open_bf(s, "<string>", len);
- memcpy(file->buffer, str, len);
- ret = tcc_compile(s);
- tcc_close();
- return ret;
+ return tcc_compile(s, s->filetype, str, -1);
}
-/* define a preprocessor symbol. A value can also be provided with the '=' operator */
+/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */
LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
{
- int len1, len2;
- /* default value */
- if (!value)
- value = "1";
- len1 = strlen(sym);
- len2 = strlen(value);
-
- /* init file structure */
- tcc_open_bf(s1, "<define>", len1 + len2 + 1);
- memcpy(file->buffer, sym, len1);
- file->buffer[len1] = ' ';
- memcpy(file->buffer + len1 + 1, value, len2);
-
- /* parse with define parser */
- next_nomacro();
- parse_define();
- tcc_close();
+ const char *eq;
+ if (NULL == (eq = strchr(sym, '=')))
+ eq = strchr(sym, 0);
+ if (NULL == value)
+ value = *eq ? eq + 1 : "1";
+ cstr_printf(&s1->cmdline_defs, "#define %.*s %s\n", (int)(eq-sym), sym, value);
}
/* undefine a preprocessor symbol */
LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
{
- TokenSym *ts;
- Sym *s;
- ts = tok_alloc(sym, strlen(sym));
- s = define_find(ts->tok);
- /* undefine symbol by putting an invalid name */
- if (s)
- define_undef(s);
+ cstr_printf(&s1->cmdline_defs, "#undef %s\n", sym);
}
-/* cleanup all static data used during compilation */
-static void tcc_cleanup(void)
-{
- if (NULL == tcc_state)
- return;
- while (file)
- tcc_close();
- tccpp_delete(tcc_state);
- tcc_state = NULL;
- /* free sym_pools */
- dynarray_reset(&sym_pools, &nb_sym_pools);
- /* reset symbol stack */
- sym_free_first = NULL;
-}
LIBTCCAPI TCCState *tcc_new(void)
{
TCCState *s;
- tcc_cleanup();
-
s = tcc_mallocz(sizeof(TCCState));
if (!s)
return NULL;
- tcc_state = s;
+#ifdef MEM_DEBUG
++nb_states;
+#endif
+
+#undef gnu_ext
- s->alacarte_link = 1;
+ s->gnu_ext = 1;
+ s->tcc_ext = 1;
s->nocommon = 1;
+ s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/
+ s->cversion = 199901; /* default unless -std=c11 is supplied */
s->warn_implicit_function_declaration = 1;
s->ms_extensions = 1;
@@ -745,24 +795,21 @@ LIBTCCAPI TCCState *tcc_new(void)
s->seg_size = 32;
#endif
/* enable this if you want symbols with leading underscore on windows: */
-#if 0 /* def TCC_TARGET_PE */
+#if defined TCC_TARGET_MACHO /* || defined TCC_TARGET_PE */
s->leading_underscore = 1;
#endif
+ s->ppfp = stdout;
+ /* might be used in error() before preprocess_start() */
+ s->include_stack_ptr = s->include_stack;
+
+ tccelf_new(s);
+
#ifdef _WIN32
tcc_set_lib_path_w32(s);
#else
tcc_set_lib_path(s, CONFIG_TCCDIR);
#endif
- tccelf_new(s);
- tccpp_new(s);
-
- /* we add dummy defines for some special macros to speed up tests
- and to have working defined() */
- define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
- define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
- define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
- define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
- define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
+
{
/* define __TINYC__ 92X */
char buffer[32]; int a,b,c;
@@ -806,10 +853,21 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__aarch64__", NULL);
#elif defined TCC_TARGET_C67
tcc_define_symbol(s, "__C67__", NULL);
+#elif defined TCC_TARGET_RISCV64
+ tcc_define_symbol(s, "__riscv", NULL);
+ tcc_define_symbol(s, "__riscv_xlen", "64");
+ tcc_define_symbol(s, "__riscv_flen", "64");
+ tcc_define_symbol(s, "__riscv_div", NULL);
+ tcc_define_symbol(s, "__riscv_mul", NULL);
+ tcc_define_symbol(s, "__riscv_fdiv", NULL);
+ tcc_define_symbol(s, "__riscv_fsqrt", NULL);
+ tcc_define_symbol(s, "__riscv_float_abi_double", NULL);
#endif
#ifdef TCC_TARGET_PE
tcc_define_symbol(s, "_WIN32", NULL);
+ tcc_define_symbol(s, "__declspec(x)", "__attribute__((x))");
+ tcc_define_symbol(s, "__cdecl", "");
# ifdef TCC_TARGET_X86_64
tcc_define_symbol(s, "_WIN64", NULL);
# endif
@@ -854,6 +912,7 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
tcc_define_symbol(s, "__LP64__", NULL);
#endif
+ tcc_define_symbol(s, "__SIZEOF_POINTER__", PTR_SIZE == 4 ? "4" : "8");
#ifdef TCC_TARGET_PE
tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
@@ -881,21 +940,52 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
"name proto __asm__ (#alias) __THROW");
# endif
-# if defined(TCC_MUSL)
- tcc_define_symbol(s, "__DEFINED_va_list", "");
- tcc_define_symbol(s, "__DEFINED___isoc_va_list", "");
- tcc_define_symbol(s, "__isoc_va_list", "void *");
-# endif /* TCC_MUSL */
/* Some GCC builtins that are simple to express as macros. */
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
#endif /* ndef TCC_TARGET_PE */
+#ifdef TCC_TARGET_MACHO
+ /* emulate APPLE-GCC to make libc's headerfiles compile: */
+ tcc_define_symbol(s, "__APPLE__", "1");
+ tcc_define_symbol(s, "__GNUC__", "4"); /* darwin emits warning on GCC<4 */
+ tcc_define_symbol(s, "__APPLE_CC__", "1"); /* for <TargetConditionals.h> */
+ tcc_define_symbol(s, "_DONT_USE_CTYPE_INLINE_", "1");
+ tcc_define_symbol(s, "__builtin_alloca", "alloca"); /* as we claim GNUC */
+ /* used by math.h */
+ tcc_define_symbol(s, "__builtin_huge_val()", "1e500");
+ tcc_define_symbol(s, "__builtin_huge_valf()", "1e50f");
+ tcc_define_symbol(s, "__builtin_huge_vall()", "1e5000L");
+ tcc_define_symbol(s, "__builtin_nanf(ignored_string)", "__nan()");
+ /* used by _fd_def.h */
+ tcc_define_symbol(s, "__builtin_bzero(p, ignored_size)", "bzero(p, sizeof(*(p)))");
+ /* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */
+ tcc_define_symbol(s, "__builtin_flt_rounds()", "1");
+
+ /* avoids usage of GCC/clang specific builtins in libc-headerfiles: */
+ tcc_define_symbol(s, "__FINITE_MATH_ONLY__", "1");
+ tcc_define_symbol(s, "_FORTIFY_SOURCE", "0");
+#endif /* ndef TCC_TARGET_MACHO */
+
+#if LONG_SIZE == 4
+ tcc_define_symbol(s, "__SIZEOF_LONG__", "4");
+ tcc_define_symbol(s, "__LONG_MAX__", "0x7fffffffL");
+#else
+ tcc_define_symbol(s, "__SIZEOF_LONG__", "8");
+ tcc_define_symbol(s, "__LONG_MAX__", "0x7fffffffffffffffL");
+#endif
+ tcc_define_symbol(s, "__SIZEOF_INT__", "4");
+ tcc_define_symbol(s, "__SIZEOF_LONG_LONG__", "8");
+ tcc_define_symbol(s, "__CHAR_BIT__", "8");
+ tcc_define_symbol(s, "__ORDER_LITTLE_ENDIAN__", "1234");
+ tcc_define_symbol(s, "__ORDER_BIG_ENDIAN__", "4321");
+ tcc_define_symbol(s, "__BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__");
+ tcc_define_symbol(s, "__INT_MAX__", "0x7fffffff");
+ tcc_define_symbol(s, "__LONG_LONG_MAX__", "0x7fffffffffffffffLL");
+ tcc_define_symbol(s, "__builtin_offsetof(type,field)", "((__SIZE_TYPE__) &((type *)0)->field)");
return s;
}
LIBTCCAPI void tcc_delete(TCCState *s1)
{
- tcc_cleanup();
-
/* free sections */
tccelf_delete(s1);
@@ -904,10 +994,8 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths);
/* free include paths */
- dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
- dynarray_reset(&s1->cmd_include_files, &s1->nb_cmd_include_files);
tcc_free(s1->tcc_lib_path);
tcc_free(s1->soname);
@@ -921,14 +1009,18 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
dynarray_reset(&s1->argv, &s1->argc);
+ cstr_free(&s1->cmdline_defs);
+ cstr_free(&s1->cmdline_incl);
#ifdef TCC_IS_NATIVE
/* free runtime memory */
tcc_run_free(s1);
#endif
tcc_free(s1);
+#ifdef MEM_DEBUG
if (0 == --nb_states)
tcc_memcheck();
+#endif
}
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
@@ -942,6 +1034,30 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
if (s->char_is_unsigned)
tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
+ if (s->cversion == 201112) {
+ tcc_undefine_symbol(s, "__STDC_VERSION__");
+ tcc_define_symbol(s, "__STDC_VERSION__", "201112L");
+ tcc_define_symbol(s, "__STDC_NO_ATOMICS__", NULL);
+ tcc_define_symbol(s, "__STDC_NO_COMPLEX__", NULL);
+ tcc_define_symbol(s, "__STDC_NO_THREADS__", NULL);
+#ifndef TCC_TARGET_PE
+ /* on Linux, this conflicts with a define introduced by
+ /usr/include/stdc-predef.h included by glibc libs
+ tcc_define_symbol(s, "__STDC_ISO_10646__", "201605L"); */
+ tcc_define_symbol(s, "__STDC_UTF_16__", NULL);
+ tcc_define_symbol(s, "__STDC_UTF_32__", NULL);
+#endif
+ }
+
+ if (s->optimize > 0)
+ tcc_define_symbol(s, "__OPTIMIZE__", NULL);
+
+ if (s->option_pthread)
+ tcc_define_symbol(s, "_REENTRANT", NULL);
+
+ if (s->leading_underscore)
+ tcc_define_symbol(s, "__leading_underscore", NULL);
+
if (!s->nostdinc) {
/* default include paths */
/* -isystem paths have already been handled */
@@ -974,9 +1090,12 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
/* add libc crt1/crti objects */
if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
!s->nostdlib) {
+#ifndef TCC_TARGET_MACHO
+ /* Mach-O with LC_MAIN doesn't need any crt startup code. */
if (output_type != TCC_OUTPUT_DLL)
tcc_add_crt(s, "crt1.o");
tcc_add_crt(s, "crti.o");
+#endif
}
#endif
return 0;
@@ -996,25 +1115,21 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
{
- int ret;
+ int fd, ret;
/* open the file */
- ret = tcc_open(s1, filename);
- if (ret < 0) {
+ fd = _tcc_open(s1, filename);
+ if (fd < 0) {
if (flags & AFF_PRINT_ERROR)
tcc_error_noabort("file '%s' not found", filename);
- return ret;
+ return -1;
}
- /* update target deps */
- dynarray_add(&s1->target_deps, &s1->nb_target_deps,
- tcc_strdup(filename));
-
+ s1->current_filename = filename;
if (flags & AFF_TYPE_BIN) {
ElfW(Ehdr) ehdr;
- int fd, obj_type;
+ int obj_type;
- fd = file->fd;
obj_type = tcc_object_type(fd, &ehdr);
lseek(fd, 0, SEEK_SET);
@@ -1036,13 +1151,18 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
ret = -1;
#endif
} else {
+#ifndef TCC_TARGET_MACHO
ret = tcc_load_dll(s1, fd, filename,
(flags & AFF_REFERENCED_DLL) != 0);
+#else
+ ret = macho_load_dll(s1, fd, filename,
+ (flags & AFF_REFERENCED_DLL) != 0);
+#endif
}
break;
#endif
case AFF_BINTYPE_AR:
- ret = tcc_load_archive(s1, fd);
+ ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE));
break;
#ifdef TCC_TARGET_COFF
case AFF_BINTYPE_C67:
@@ -1052,26 +1172,31 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
default:
#ifdef TCC_TARGET_PE
ret = pe_load_file(s1, filename, fd);
+#elif defined(TCC_TARGET_MACHO)
+ ret = -1;
#else
/* as GNU ld, consider it is an ld script if not recognized */
- ret = tcc_load_ldscript(s1);
+ ret = tcc_load_ldscript(s1, fd);
#endif
if (ret < 0)
- tcc_error_noabort("unrecognized file type");
+ tcc_error_noabort("%s: unrecognized file type %d", filename,
+ obj_type);
break;
}
+ close(fd);
} else {
- ret = tcc_compile(s1);
+ /* update target deps */
+ dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
+ ret = tcc_compile(s1, flags, filename, fd);
}
- tcc_close();
+ s1->current_filename = NULL;
return ret;
}
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
{
int filetype = s->filetype;
- int flags = AFF_PRINT_ERROR;
- if (filetype == 0) {
+ if (0 == (filetype & AFF_TYPE_MASK)) {
/* use a file extension to detect a filetype */
const char *ext = tcc_fileextension(filename);
if (ext[0]) {
@@ -1083,13 +1208,12 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
filetype = AFF_TYPE_C;
else
- flags |= AFF_TYPE_BIN;
+ filetype |= AFF_TYPE_BIN;
} else {
filetype = AFF_TYPE_C;
}
- s->filetype = filetype;
}
- return tcc_add_file_internal(s, filename, flags);
+ return tcc_add_file_internal(s, filename, filetype | AFF_PRINT_ERROR);
}
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
@@ -1112,6 +1236,7 @@ static int tcc_add_library_internal(TCCState *s, const char *fmt,
return -1;
}
+#ifndef TCC_TARGET_MACHO
/* find and load a dll. Return non zero if not found */
/* XXX: add '-rpath' option support ? */
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
@@ -1119,14 +1244,17 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
return tcc_add_library_internal(s, "%s/%s", filename, flags,
s->library_paths, s->nb_library_paths);
}
+#endif
-ST_FUNC int tcc_add_crt(TCCState *s, const char *filename)
+#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO
+ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename)
{
- if (-1 == tcc_add_library_internal(s, "%s/%s",
- filename, 0, s->crt_paths, s->nb_crt_paths))
+ if (-1 == tcc_add_library_internal(s1, "%s/%s",
+ filename, 0, s1->crt_paths, s1->nb_crt_paths))
tcc_error_noabort("file '%s' not found", filename);
return 0;
}
+#endif
/* the library name is the same as the argument of the '-l' option */
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
@@ -1141,18 +1269,19 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
const char **pp = s->static_link ? libs + 1 : libs;
#endif
+ int flags = s->filetype & AFF_WHOLE_ARCHIVE;
while (*pp) {
if (0 == tcc_add_library_internal(s, *pp,
- libraryname, 0, s->library_paths, s->nb_library_paths))
+ libraryname, flags, s->library_paths, s->nb_library_paths))
return 0;
++pp;
}
return -1;
}
-PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname)
+PUB_FUNC int tcc_add_library_err(TCCState *s1, const char *libname)
{
- int ret = tcc_add_library(s, libname);
+ int ret = tcc_add_library(s1, libname);
if (ret < 0)
tcc_error_noabort("library '%s' not found", libname);
return ret;
@@ -1166,16 +1295,20 @@ ST_FUNC void tcc_add_pragma_libs(TCCState *s1)
tcc_add_library_err(s1, s1->pragma_libs[i]);
}
-LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
+LIBTCCAPI int tcc_add_symbol(TCCState *s1, const char *name, const void *val)
{
#ifdef TCC_TARGET_PE
/* On x86_64 'val' might not be reachable with a 32bit offset.
So it is handled here as if it were in a DLL. */
- pe_putimport(s, 0, name, (uintptr_t)val);
+ pe_putimport(s1, 0, name, (uintptr_t)val);
#else
- set_elf_sym(symtab_section, (uintptr_t)val, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- SHN_ABS, name);
+ char buf[256];
+ if (s1->leading_underscore) {
+ buf[0] = '_';
+ pstrcpy(buf + 1, sizeof(buf) - 1, name);
+ name = buf;
+ }
+ set_global_sym(s1, name, NULL, (addr_t)(uintptr_t)val); /* NULL: SHN_ABS */
#endif
return 0;
}
@@ -1224,7 +1357,7 @@ ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name)
continue;
}
if (p->offset) {
- *(int*)((char *)s + p->offset) =
+ *((unsigned char *)s + p->offset) =
p->flags & FD_INVERT ? !value : value;
if (ret)
return 0;
@@ -1323,6 +1456,7 @@ static void copy_linker_arg(char **pp, const char *s, int sep)
/* set linker options */
static int tcc_set_linker(TCCState *s, const char *option)
{
+ TCCState *s1 = s;
while (*option) {
const char *p = NULL;
@@ -1368,6 +1502,8 @@ static int tcc_set_linker(TCCState *s, const char *option)
ignoring = 1;
} else if (link_option(option, "export-all-symbols", &p)) {
s->rdynamic = 1;
+ } else if (link_option(option, "export-dynamic", &p)) {
+ s->rdynamic = 1;
} else if (link_option(option, "rpath=", &p)) {
copy_linker_arg(&s->rpath, p, ':');
} else if (link_option(option, "enable-new-dtags", &p)) {
@@ -1409,7 +1545,10 @@ static int tcc_set_linker(TCCState *s, const char *option)
goto err;
#endif
} else if (ret = link_option(option, "?whole-archive", &p), ret) {
- s->alacarte_link = ret < 0;
+ if (ret > 0)
+ s->filetype |= AFF_WHOLE_ARCHIVE;
+ else
+ s->filetype &= ~AFF_WHOLE_ARCHIVE;
} else if (p) {
return 0;
} else {
@@ -1445,6 +1584,7 @@ enum {
TCC_OPTION_bench,
TCC_OPTION_bt,
TCC_OPTION_b,
+ TCC_OPTION_ba,
TCC_OPTION_g,
TCC_OPTION_c,
TCC_OPTION_dumpversion,
@@ -1482,7 +1622,8 @@ enum {
TCC_OPTION_MF,
TCC_OPTION_x,
TCC_OPTION_ar,
- TCC_OPTION_impdef
+ TCC_OPTION_impdef,
+ TCC_OPTION_C
};
#define TCC_OPTION_HAS_ARG 0x0001
@@ -1494,16 +1635,17 @@ static const TCCOption tcc_options[] = {
{ "?", TCC_OPTION_HELP, 0 },
{ "hh", TCC_OPTION_HELP2, 0 },
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+ { "-version", TCC_OPTION_v, 0 }, /* handle as verbose, also prints version*/
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
{ "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
- { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+ { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
{ "bench", TCC_OPTION_bench, 0 },
#ifdef CONFIG_TCC_BACKTRACE
- { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
+ { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
#endif
#ifdef CONFIG_TCC_BCHECK
{ "b", TCC_OPTION_b, 0 },
@@ -1549,6 +1691,7 @@ static const TCCOption tcc_options[] = {
#ifdef TCC_TARGET_PE
{ "impdef", TCC_OPTION_impdef, 0},
#endif
+ { "C", TCC_OPTION_C, 0},
{ NULL, 0, 0 },
};
@@ -1581,21 +1724,10 @@ static const FlagDef options_m[] = {
{ 0, 0, NULL }
};
-static void parse_option_D(TCCState *s1, const char *optarg)
-{
- char *sym = tcc_strdup(optarg);
- char *value = strchr(sym, '=');
- if (value)
- *value++ = '\0';
- tcc_define_symbol(s1, sym, value);
- tcc_free(sym);
-}
-
static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
{
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
f->type = filetype;
- f->alacarte = s->alacarte_link;
strcpy(f->name, filename);
dynarray_add(&s->files, &s->nb_files, f);
}
@@ -1606,7 +1738,7 @@ static int args_parser_make_argv(const char *r, int *argc, char ***argv)
CString str;
for(;;) {
while (c = (unsigned char)*r, c && c <= ' ')
- ++r;
+ ++r;
if (c == 0)
break;
q = 0;
@@ -1636,6 +1768,7 @@ static int args_parser_make_argv(const char *r, int *argc, char ***argv)
static void args_parser_listfile(TCCState *s,
const char *filename, int optind, int *pargc, char ***pargv)
{
+ TCCState *s1 = s;
int fd, i;
size_t len;
char *p;
@@ -1663,10 +1796,10 @@ static void args_parser_listfile(TCCState *s,
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
{
+ TCCState *s1 = s;
const TCCOption *popt;
const char *optarg, *r;
const char *run = NULL;
- int last_o = -1;
int x;
CString linker_arg; /* collect -Wl options */
int tool = 0, arg_start = 0, noaction = optind;
@@ -1679,7 +1812,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
r = argv[optind];
if (r[0] == '@' && r[1] != '\0') {
args_parser_listfile(s, r + 1, optind, &argc, &argv);
- continue;
+ continue;
}
optind++;
if (tool) {
@@ -1722,14 +1855,16 @@ reparse:
switch(popt->index) {
case TCC_OPTION_HELP:
- return OPT_HELP;
+ x = OPT_HELP;
+ goto extra_action;
case TCC_OPTION_HELP2:
- return OPT_HELP2;
+ x = OPT_HELP2;
+ goto extra_action;
case TCC_OPTION_I:
tcc_add_include_path(s, optarg);
break;
case TCC_OPTION_D:
- parse_option_D(s, optarg);
+ tcc_define_symbol(s, optarg, NULL);
break;
case TCC_OPTION_U:
tcc_undefine_symbol(s, optarg);
@@ -1742,11 +1877,10 @@ reparse:
tcc_set_lib_path(s, optarg);
break;
case TCC_OPTION_l:
- args_parser_add_file(s, optarg, AFF_TYPE_LIB);
+ args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
s->nb_libraries++;
break;
case TCC_OPTION_pthread:
- parse_option_D(s, "_REENTRANT");
s->option_pthread = 1;
break;
case TCC_OPTION_bench:
@@ -1754,12 +1888,15 @@ reparse:
break;
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
- tcc_set_num_callers(atoi(optarg));
+ s->rt_num_callers = atoi(optarg);
+ s->do_backtrace = 1;
+ s->do_debug = 1;
break;
#endif
#ifdef CONFIG_TCC_BCHECK
case TCC_OPTION_b:
s->do_bounds_check = 1;
+ s->do_backtrace = 1;
s->do_debug = 1;
break;
#endif
@@ -1781,7 +1918,7 @@ reparse:
else if (*optarg == 't')
s->dflag = 16;
else if (isnum(*optarg))
- g_debug = atoi(optarg);
+ s->g_debug |= atoi(optarg);
else
goto unsupported_option;
break;
@@ -1789,8 +1926,8 @@ reparse:
s->static_link = 1;
break;
case TCC_OPTION_std:
- /* silently ignore, a current purpose:
- allow to use a tcc as a reference compiler for "make test" */
+ if (strcmp(optarg, "=c11") == 0)
+ s->cversion = 201112;
break;
case TCC_OPTION_shared:
x = TCC_OUTPUT_DLL;
@@ -1813,10 +1950,9 @@ reparse:
case TCC_OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
- case TCC_OPTION_include:
- dynarray_add(&s->cmd_include_files,
- &s->nb_cmd_include_files, tcc_strdup(optarg));
- break;
+ case TCC_OPTION_include:
+ cstr_printf(&s->cmdline_incl, "#include \"%s\"\n", optarg);
+ break;
case TCC_OPTION_nostdinc:
s->nostdinc = 1;
break;
@@ -1860,7 +1996,8 @@ reparse:
}
break;
case TCC_OPTION_W:
- if (set_flag(s, options_W, optarg) < 0)
+ s->warn_none = 0;
+ if (optarg[0] && set_flag(s, options_W, optarg) < 0)
goto unsupported_option;
break;
case TCC_OPTION_w:
@@ -1876,9 +2013,9 @@ reparse:
if (tcc_set_linker(s, linker_arg.data))
cstr_free(&linker_arg);
break;
- case TCC_OPTION_Wp:
- r = optarg;
- goto reparse;
+ case TCC_OPTION_Wp:
+ r = optarg;
+ goto reparse;
case TCC_OPTION_E:
x = TCC_OUTPUT_PREPROCESS;
goto set_output_type;
@@ -1896,17 +2033,21 @@ reparse:
exit(0);
break;
case TCC_OPTION_x:
+ x = 0;
if (*optarg == 'c')
- s->filetype = AFF_TYPE_C;
+ x = AFF_TYPE_C;
else if (*optarg == 'a')
- s->filetype = AFF_TYPE_ASMPP;
+ x = AFF_TYPE_ASMPP;
+ else if (*optarg == 'b')
+ x = AFF_TYPE_BIN;
else if (*optarg == 'n')
- s->filetype = AFF_TYPE_NONE;
+ x = AFF_TYPE_NONE;
else
tcc_warning("unsupported language '%s'", optarg);
+ s->filetype = x | (s->filetype & ~AFF_TYPE_MASK);
break;
case TCC_OPTION_O:
- last_o = atoi(optarg);
+ s->optimize = atoi(optarg);
break;
case TCC_OPTION_print_search_dirs:
x = OPT_PRINT_DIRS;
@@ -1926,6 +2067,7 @@ reparse:
case TCC_OPTION_pedantic:
case TCC_OPTION_pipe:
case TCC_OPTION_s:
+ case TCC_OPTION_C:
/* ignored */
break;
default:
@@ -1935,8 +2077,6 @@ unsupported_option:
break;
}
}
- if (last_o > 0)
- tcc_define_symbol(s, "__OPTIMIZE__", NULL);
if (linker_arg.size) {
r = linker_arg.data;
goto arg_err;
@@ -1963,7 +2103,7 @@ LIBTCCAPI void tcc_set_options(TCCState *s, const char *r)
dynarray_reset(&argv, &argc);
}
-PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
+PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time)
{
if (total_time < 1)
total_time = 1;
@@ -1971,7 +2111,7 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
total_bytes = 1;
fprintf(stderr, "* %d idents, %d lines, %d bytes\n"
"* %0.3f s, %u lines/s, %0.1f MB/s\n",
- tok_ident - TOK_IDENT, total_lines, total_bytes,
+ total_idents, total_lines, total_bytes,
(double)total_time/1000,
(unsigned)total_lines*1000/total_time,
(double)total_bytes/1000/total_time);
diff --git a/libtcc.h b/libtcc.h
index a1b31e3..25d247a 100644
--- a/libtcc.h
+++ b/libtcc.h
@@ -13,6 +13,8 @@ struct TCCState;
typedef struct TCCState TCCState;
+typedef void (*TCCErrorFunc)(void *opaque, const char *msg);
+
/* create a new TCC compilation context */
LIBTCCAPI TCCState *tcc_new(void);
@@ -23,8 +25,13 @@ LIBTCCAPI void tcc_delete(TCCState *s);
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
/* set error/warning display callback */
-LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
- void (*error_func)(void *opaque, const char *msg));
+LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func);
+
+/* return error/warning callback */
+LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s);
+
+/* return error/warning callback opaque pointer */
+LIBTCCAPI void *tcc_get_error_opaque(TCCState *s);
/* set options as from command line (multiple supported) */
LIBTCCAPI void tcc_set_options(TCCState *s, const char *str);
@@ -38,7 +45,7 @@ LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
/* add in system include path */
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
-/* define preprocessor symbol 'sym'. Can put optional value */
+/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
/* undefine preprocess symbol 'sym' */
@@ -93,6 +100,10 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
+/* return symbol value or NULL if not found */
+LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
+ void (*symbol_cb)(void *ctx, const char *name, const void *val));
+
#ifdef __cplusplus
}
#endif
diff --git a/riscv64-asm.c b/riscv64-asm.c
new file mode 100644
index 0000000..6b82e77
--- /dev/null
+++ b/riscv64-asm.c
@@ -0,0 +1,94 @@
+/*************************************************************/
+/*
+ * RISCV64 dummy assembler for TCC
+ *
+ */
+
+#ifdef TARGET_DEFS_ONLY
+
+#define CONFIG_TCC_ASM
+#define NB_ASM_REGS 32
+
+ST_FUNC void g(int c);
+ST_FUNC void gen_le16(int c);
+ST_FUNC void gen_le32(int c);
+
+/*************************************************************/
+#else
+/*************************************************************/
+#define USING_GLOBALS
+#include "tcc.h"
+
+static void asm_error(void)
+{
+ tcc_error("RISCV64 asm not implemented.");
+}
+
+/* XXX: make it faster ? */
+ST_FUNC void g(int c)
+{
+ int ind1;
+ if (nocode_wanted)
+ return;
+ ind1 = ind + 1;
+ if (ind1 > cur_text_section->data_allocated)
+ section_realloc(cur_text_section, ind1);
+ cur_text_section->data[ind] = c;
+ ind = ind1;
+}
+
+ST_FUNC void gen_le16 (int i)
+{
+ g(i);
+ g(i>>8);
+}
+
+ST_FUNC void gen_le32 (int i)
+{
+ gen_le16(i);
+ gen_le16(i>>16);
+}
+
+ST_FUNC void gen_expr32(ExprValue *pe)
+{
+ gen_le32(pe->v);
+}
+
+ST_FUNC void asm_opcode(TCCState *s1, int opcode)
+{
+ asm_error();
+}
+
+ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
+{
+ asm_error();
+}
+
+/* generate prolog and epilog code for asm statement */
+ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
+ int nb_outputs, int is_output,
+ uint8_t *clobber_regs,
+ int out_reg)
+{
+}
+
+ST_FUNC void asm_compute_constraints(ASMOperand *operands,
+ int nb_operands, int nb_outputs,
+ const uint8_t *clobber_regs,
+ int *pout_reg)
+{
+}
+
+ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
+{
+ asm_error();
+}
+
+ST_FUNC int asm_parse_regvar (int t)
+{
+ asm_error();
+ return -1;
+}
+
+/*************************************************************/
+#endif /* ndef TARGET_DEFS_ONLY */
diff --git a/riscv64-gen.c b/riscv64-gen.c
new file mode 100644
index 0000000..baf7f5e
--- /dev/null
+++ b/riscv64-gen.c
@@ -0,0 +1,1342 @@
+#ifdef TARGET_DEFS_ONLY
+
+// Number of registers available to allocator:
+#define NB_REGS 19 // x10-x17 aka a0-a7, f10-f17 aka fa0-fa7, xxx, ra, sp
+#define NB_ASM_REGS 32
+#define CONFIG_TCC_ASM
+
+#define TREG_R(x) (x) // x = 0..7
+#define TREG_F(x) (x + 8) // x = 0..7
+
+// Register classes sorted from more general to more precise:
+#define RC_INT (1 << 0)
+#define RC_FLOAT (1 << 1)
+#define RC_R(x) (1 << (2 + (x))) // x = 0..7
+#define RC_F(x) (1 << (10 + (x))) // x = 0..7
+
+#define RC_IRET (RC_R(0)) // int return register class
+#define RC_IRE2 (RC_R(1)) // int 2nd return register class
+#define RC_FRET (RC_F(0)) // float return register class
+
+#define REG_IRET (TREG_R(0)) // int return register number
+#define REG_IRE2 (TREG_R(1)) // int 2nd return register number
+#define REG_FRET (TREG_F(0)) // float return register number
+
+#define PTR_SIZE 8
+
+#define LDOUBLE_SIZE 16
+#define LDOUBLE_ALIGN 16
+
+#define MAX_ALIGN 16
+
+#define CHAR_IS_UNSIGNED
+
+#else
+#define USING_GLOBALS
+#include "tcc.h"
+#include <assert.h>
+
+#define XLEN 8
+
+#define TREG_RA 17
+#define TREG_SP 18
+
+ST_DATA const int reg_classes[NB_REGS] = {
+ RC_INT | RC_R(0),
+ RC_INT | RC_R(1),
+ RC_INT | RC_R(2),
+ RC_INT | RC_R(3),
+ RC_INT | RC_R(4),
+ RC_INT | RC_R(5),
+ RC_INT | RC_R(6),
+ RC_INT | RC_R(7),
+ RC_FLOAT | RC_F(0),
+ RC_FLOAT | RC_F(1),
+ RC_FLOAT | RC_F(2),
+ RC_FLOAT | RC_F(3),
+ RC_FLOAT | RC_F(4),
+ RC_FLOAT | RC_F(5),
+ RC_FLOAT | RC_F(6),
+ RC_FLOAT | RC_F(7),
+ 0,
+ 1 << TREG_RA,
+ 1 << TREG_SP
+};
+
+#if defined(CONFIG_TCC_BCHECK)
+static addr_t func_bound_offset;
+static unsigned long func_bound_ind;
+ST_DATA int func_bound_add_epilog;
+#endif
+
+static int ireg(int r)
+{
+ if (r == TREG_RA)
+ return 1; // ra
+ if (r == TREG_SP)
+ return 2; // sp
+ assert(r >= 0 && r < 8);
+ return r + 10; // tccrX --> aX == x(10+X)
+}
+
+static int is_ireg(int r)
+{
+ return (unsigned)r < 8 || r == TREG_RA || r == TREG_SP;
+}
+
+static int freg(int r)
+{
+ assert(r >= 8 && r < 16);
+ return r - 8 + 10; // tccfX --> faX == f(10+X)
+}
+
+static int is_freg(int r)
+{
+ return r >= 8 && r < 16;
+}
+
+ST_FUNC void o(unsigned int c)
+{
+ int ind1 = ind + 4;
+ if (nocode_wanted)
+ return;
+ if (ind1 > cur_text_section->data_allocated)
+ section_realloc(cur_text_section, ind1);
+ write32le(cur_text_section->data + ind, c);
+ ind = ind1;
+}
+
+static void EIu(uint32_t opcode, uint32_t func3,
+ uint32_t rd, uint32_t rs1, uint32_t imm)
+{
+ o(opcode | (func3 << 12) | (rd << 7) | (rs1 << 15) | (imm << 20));
+}
+
+static void ER(uint32_t opcode, uint32_t func3,
+ uint32_t rd, uint32_t rs1, uint32_t rs2, uint32_t func7)
+{
+ o(opcode | func3 << 12 | rd << 7 | rs1 << 15 | rs2 << 20 | func7 << 25);
+}
+
+static void EI(uint32_t opcode, uint32_t func3,
+ uint32_t rd, uint32_t rs1, uint32_t imm)
+{
+ assert(! ((imm + (1 << 11)) >> 12));
+ EIu(opcode, func3, rd, rs1, imm);
+}
+
+static void ES(uint32_t opcode, uint32_t func3,
+ uint32_t rs1, uint32_t rs2, uint32_t imm)
+{
+ assert(! ((imm + (1 << 11)) >> 12));
+ o(opcode | (func3 << 12) | ((imm & 0x1f) << 7) | (rs1 << 15)
+ | (rs2 << 20) | ((imm >> 5) << 25));
+}
+
+// Patch all branches in list pointed to by t to branch to a:
+ST_FUNC void gsym_addr(int t_, int a_)
+{
+ uint32_t t = t_;
+ uint32_t a = a_;
+ while (t) {
+ unsigned char *ptr = cur_text_section->data + t;
+ uint32_t next = read32le(ptr);
+ uint32_t r = a - t, imm;
+ if ((r + (1 << 21)) & ~((1U << 22) - 2))
+ tcc_error("out-of-range branch chain");
+ imm = (((r >> 12) & 0xff) << 12)
+ | (((r >> 11) & 1) << 20)
+ | (((r >> 1) & 0x3ff) << 21)
+ | (((r >> 20) & 1) << 31);
+ write32le(ptr, r == 4 ? 0x33 : 0x6f | imm); // nop || j imm
+ t = next;
+ }
+}
+
+static int load_symofs(int r, SValue *sv, int forstore)
+{
+ static Sym label;
+ int rr, doload = 0;
+ int fc = sv->c.i, v = sv->r & VT_VALMASK;
+ if (sv->r & VT_SYM) {
+ assert(v == VT_CONST);
+ if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax
+ greloca(cur_text_section, sv->sym, ind,
+ R_RISCV_PCREL_HI20, sv->c.i);
+ sv->c.i = 0;
+ } else {
+ if (((unsigned)fc + (1 << 11)) >> 12)
+ tcc_error("unimp: large addend for global address (0x%llx)", (long long)sv->c.i);
+ greloca(cur_text_section, sv->sym, ind,
+ R_RISCV_GOT_HI20, 0);
+ doload = 1;
+ }
+ if (!label.v) {
+ label.v = tok_alloc(".L0 ", 4)->tok;
+ label.type.t = VT_VOID | VT_STATIC;
+ }
+ label.c = 0; /* force new local ELF symbol */
+ put_extern_sym(&label, cur_text_section, ind, 0);
+ rr = is_ireg(r) ? ireg(r) : 5;
+ o(0x17 | (rr << 7)); // auipc RR, 0 %pcrel_hi(sym)+addend
+ greloca(cur_text_section, &label, ind,
+ doload || !forstore
+ ? R_RISCV_PCREL_LO12_I : R_RISCV_PCREL_LO12_S, 0);
+ if (doload) {
+ EI(0x03, 3, rr, rr, 0); // ld RR, 0(RR)
+ }
+ } else if (v == VT_LOCAL || v == VT_LLOCAL) {
+ rr = 8; // s0
+ if (fc != sv->c.i)
+ tcc_error("unimp: store(giant local off) (0x%llx)", (long long)sv->c.i);
+ if (((unsigned)fc + (1 << 11)) >> 12) {
+ rr = is_ireg(r) ? ireg(r) : 5; // t0
+ o(0x37 | (rr << 7) | ((0x800 + fc) & 0xfffff000)); //lui RR, upper(fc)
+ ER(0x33, 0, rr, rr, 8, 0); // add RR, RR, s0
+ sv->c.i = fc << 20 >> 20;
+ }
+ } else
+ tcc_error("uhh");
+ return rr;
+}
+
+ST_FUNC void load(int r, SValue *sv)
+{
+ int fr = sv->r;
+ int v = fr & VT_VALMASK;
+ int rr = is_ireg(r) ? ireg(r) : freg(r);
+ int fc = sv->c.i;
+ int bt = sv->type.t & VT_BTYPE;
+ int align, size;
+ if (fr & VT_LVAL) {
+ int func3, opcode = is_freg(r) ? 0x07 : 0x03, br;
+ size = type_size(&sv->type, &align);
+ assert (!is_freg(r) || bt == VT_FLOAT || bt == VT_DOUBLE);
+ if (bt == VT_FUNC) /* XXX should be done in generic code */
+ size = PTR_SIZE;
+ func3 = size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3;
+ if (size < 4 && !is_float(sv->type.t) && (sv->type.t & VT_UNSIGNED))
+ func3 |= 4;
+ if (v == VT_LOCAL || (fr & VT_SYM)) {
+ br = load_symofs(r, sv, 0);
+ fc = sv->c.i;
+ } else if (v < VT_CONST) {
+ br = ireg(v);
+ /*if (((unsigned)fc + (1 << 11)) >> 12)
+ tcc_error("unimp: load(large addend) (0x%x)", fc);*/
+ fc = 0; // XXX store ofs in LVAL(reg)
+ } else if (v == VT_LLOCAL) {
+ br = load_symofs(r, sv, 0);
+ fc = sv->c.i;
+ EI(0x03, 3, rr, br, fc); // ld RR, fc(BR)
+ br = rr;
+ fc = 0;
+ } else {
+ tcc_error("unimp: load(non-local lval)");
+ }
+ EI(opcode, func3, rr, br, fc); // l[bhwd][u] / fl[wd] RR, fc(BR)
+ } else if (v == VT_CONST) {
+ int rb = 0, do32bit = 8, zext = 0;
+ assert((!is_float(sv->type.t) && is_ireg(r)) || bt == VT_LDOUBLE);
+ if (fr & VT_SYM) {
+ rb = load_symofs(r, sv, 0);
+ fc = sv->c.i;
+ do32bit = 0;
+ }
+ if (is_float(sv->type.t) && bt != VT_LDOUBLE)
+ tcc_error("unimp: load(float)");
+ if (fc != sv->c.i) {
+ int64_t si = sv->c.i;
+ uint32_t pi;
+ si >>= 32;
+ if (si != 0) {
+ pi = si;
+ if (fc < 0)
+ pi++;
+ o(0x37 | (rr << 7) | (((pi + 0x800) & 0xfffff000))); // lui RR, up(up(fc))
+ EI(0x13, 0, rr, rr, (int)pi << 20 >> 20); // addi RR, RR, lo(up(fc))
+ EI(0x13, 1, rr, rr, 12); // slli RR, RR, 12
+ EI(0x13, 0, rr, rr, (fc + (1 << 19)) >> 20); // addi RR, RR, up(lo(fc))
+ EI(0x13, 1, rr, rr, 12); // slli RR, RR, 12
+ fc = fc << 12 >> 12;
+ EI(0x13, 0, rr, rr, fc >> 8); // addi RR, RR, lo1(lo(fc))
+ EI(0x13, 1, rr, rr, 8); // slli RR, RR, 8
+ fc &= 0xff;
+ rb = rr;
+ do32bit = 0;
+ } else if (bt == VT_LLONG) {
+ /* A 32bit unsigned constant for a 64bit type.
+ lui always sign extends, so we need to do an explicit zext.*/
+ zext = 1;
+ }
+ }
+ if (((unsigned)fc + (1 << 11)) >> 12)
+ o(0x37 | (rr << 7) | ((0x800 + fc) & 0xfffff000)), rb = rr; //lui RR, upper(fc)
+ if (fc || (rr != rb) || do32bit || (fr & VT_SYM))
+ EI(0x13 | do32bit, 0, rr, rb, fc << 20 >> 20); // addi[w] R, x0|R, FC
+ if (zext) {
+ EI(0x13, 1, rr, rr, 32); // slli RR, RR, 32
+ EI(0x13, 5, rr, rr, 32); // srli RR, RR, 32
+ }
+ } else if (v == VT_LOCAL) {
+ int br = load_symofs(r, sv, 0);
+ assert(is_ireg(r));
+ fc = sv->c.i;
+ EI(0x13, 0, rr, br, fc); // addi R, s0, FC
+ } else if (v < VT_CONST) { /* reg-reg */
+ //assert(!fc); XXX support offseted regs
+ if (is_freg(r) && is_freg(v))
+ ER(0x53, 0, rr, freg(v), freg(v), bt == VT_DOUBLE ? 0x11 : 0x10); //fsgnj.[sd] RR, V, V == fmv.[sd] RR, V
+ else if (is_ireg(r) && is_ireg(v))
+ EI(0x13, 0, rr, ireg(v), 0); // addi RR, V, 0 == mv RR, V
+ else {
+ int func7 = is_ireg(r) ? 0x70 : 0x78;
+ size = type_size(&sv->type, &align);
+ if (size == 8)
+ func7 |= 1;
+ assert(size == 4 || size == 8);
+ o(0x53 | (rr << 7) | ((is_freg(v) ? freg(v) : ireg(v)) << 15)
+ | (func7 << 25)); // fmv.{w.x, x.w, d.x, x.d} RR, VR
+ }
+ } else if (v == VT_CMP) {
+ int op = vtop->cmp_op;
+ int a = vtop->cmp_r & 0xff;
+ int b = (vtop->cmp_r >> 8) & 0xff;
+ int inv = 0;
+ switch (op) {
+ case TOK_ULT:
+ case TOK_UGE:
+ case TOK_ULE:
+ case TOK_UGT:
+ case TOK_LT:
+ case TOK_GE:
+ case TOK_LE:
+ case TOK_GT:
+ if (op & 1) { // remove [U]GE,GT
+ inv = 1;
+ op--;
+ }
+ if ((op & 7) == 6) { // [U]LE
+ int t = a; a = b; b = t;
+ inv ^= 1;
+ }
+ ER(0x33, (op > TOK_UGT) ? 2 : 3, rr, a, b, 0); // slt[u] d, a, b
+ if (inv)
+ EI(0x13, 4, rr, rr, 1); // xori d, d, 1
+ break;
+ case TOK_NE:
+ case TOK_EQ:
+ if (rr != a || b)
+ ER(0x33, 0, rr, a, b, 0x20); // sub d, a, b
+ if (op == TOK_NE)
+ ER(0x33, 3, rr, 0, rr, 0); // sltu d, x0, d == snez d,d
+ else
+ EI(0x13, 3, rr, rr, 1); // sltiu d, d, 1 == seqz d,d
+ break;
+ }
+ } else if ((v & ~1) == VT_JMP) {
+ int t = v & 1;
+ assert(is_ireg(r));
+ EI(0x13, 0, rr, 0, t); // addi RR, x0, t
+ gjmp_addr(ind + 8);
+ gsym(fc);
+ EI(0x13, 0, rr, 0, t ^ 1); // addi RR, x0, !t
+ } else
+ tcc_error("unimp: load(non-const)");
+}
+
+ST_FUNC void store(int r, SValue *sv)
+{
+ int fr = sv->r & VT_VALMASK;
+ int rr = is_ireg(r) ? ireg(r) : freg(r), ptrreg;
+ int fc = sv->c.i;
+ int bt = sv->type.t & VT_BTYPE;
+ int align, size = type_size(&sv->type, &align);
+ assert(!is_float(bt) || is_freg(r) || bt == VT_LDOUBLE);
+ /* long doubles are in two integer registers, but the load/store
+ primitives only deal with one, so do as if it's one reg. */
+ if (bt == VT_LDOUBLE)
+ size = align = 8;
+ if (bt == VT_STRUCT)
+ tcc_error("unimp: store(struct)");
+ if (size > 8)
+ tcc_error("unimp: large sized store");
+ assert(sv->r & VT_LVAL);
+ if (fr == VT_LOCAL || (sv->r & VT_SYM)) {
+ ptrreg = load_symofs(-1, sv, 1);
+ fc = sv->c.i;
+ } else if (fr < VT_CONST) {
+ ptrreg = ireg(fr);
+ /*if (((unsigned)fc + (1 << 11)) >> 12)
+ tcc_error("unimp: store(large addend) (0x%x)", fc);*/
+ fc = 0; // XXX support offsets regs
+ } else
+ tcc_error("implement me: %s(!local)", __FUNCTION__);
+ ES(is_freg(r) ? 0x27 : 0x23, // fs... | s...
+ size == 1 ? 0 : size == 2 ? 1 : size == 4 ? 2 : 3, // ... [wd] | [bhwd]
+ ptrreg, rr, fc); // RR, fc(base)
+}
+
+static void gcall_or_jmp(int docall)
+{
+ int tr = docall ? 1 : 5; // ra or t0
+ if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
+ ((vtop->r & VT_SYM) && vtop->c.i == (int)vtop->c.i)) {
+ /* constant symbolic case -> simple relocation */
+ greloca(cur_text_section, vtop->sym, ind,
+ R_RISCV_CALL_PLT, (int)vtop->c.i);
+ o(0x17 | (tr << 7)); // auipc TR, 0 %call(func)
+ EI(0x67, 0, tr, tr, 0);// jalr TR, r(TR)
+ } else if (vtop->r < VT_CONST) {
+ int r = ireg(vtop->r);
+ EI(0x67, 0, tr, r, 0); // jalr TR, 0(R)
+ } else {
+ int r = TREG_RA;
+ load(r, vtop);
+ r = ireg(r);
+ EI(0x67, 0, tr, r, 0); // jalr TR, 0(R)
+ }
+}
+
+#if defined(CONFIG_TCC_BCHECK)
+
+static void gen_bounds_call(int v)
+{
+ Sym *sym = external_global_sym(v, &func_old_type);
+
+ greloca(cur_text_section, sym, ind, R_RISCV_CALL_PLT, 0);
+ o(0x17 | (1 << 7)); // auipc TR, 0 %call(func)
+ EI(0x67, 0, 1, 1, 0); // jalr TR, r(TR)
+}
+
+static void gen_bounds_prolog(void)
+{
+ /* leave some room for bound checking code */
+ func_bound_offset = lbounds_section->data_offset;
+ func_bound_ind = ind;
+ func_bound_add_epilog = 0;
+ o(0x00000013); /* ld a0,#lbound section pointer */
+ o(0x00000013);
+ o(0x00000013); /* nop -> call __bound_local_new */
+ o(0x00000013);
+}
+
+static void gen_bounds_epilog(void)
+{
+ static Sym label;
+ addr_t saved_ind;
+ addr_t *bounds_ptr;
+ Sym *sym_data;
+ int offset_modified = func_bound_offset != lbounds_section->data_offset;
+
+ if (!offset_modified && !func_bound_add_epilog)
+ return;
+
+ /* add end of table info */
+ bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
+ *bounds_ptr = 0;
+
+ sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
+ func_bound_offset, lbounds_section->data_offset);
+
+ if (!label.v) {
+ label.v = tok_alloc(".LB0 ", 4)->tok;
+ label.type.t = VT_VOID | VT_STATIC;
+ }
+ /* generate bound local allocation */
+ if (offset_modified) {
+ saved_ind = ind;
+ ind = func_bound_ind;
+ label.c = 0; /* force new local ELF symbol */
+ put_extern_sym(&label, cur_text_section, ind, 0);
+ greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0);
+ o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend
+ greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0);
+ EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0)
+ gen_bounds_call(TOK___bound_local_new);
+ ind = saved_ind;
+ }
+
+ /* generate bound check local freeing */
+ o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */
+ o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */
+ label.c = 0; /* force new local ELF symbol */
+ put_extern_sym(&label, cur_text_section, ind, 0);
+ greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0);
+ o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend
+ greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0);
+ EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0)
+ gen_bounds_call(TOK___bound_local_delete);
+ o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */
+ o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */
+}
+#endif
+
+static void reg_pass_rec(CType *type, int *rc, int *fieldofs, int ofs)
+{
+ if ((type->t & VT_BTYPE) == VT_STRUCT) {
+ Sym *f;
+ if (type->ref->type.t == VT_UNION)
+ rc[0] = -1;
+ else for (f = type->ref->next; f; f = f->next)
+ reg_pass_rec(&f->type, rc, fieldofs, ofs + f->c);
+ } else if (type->t & VT_ARRAY) {
+ if (type->ref->c < 0 || type->ref->c > 2)
+ rc[0] = -1;
+ else {
+ int a, sz = type_size(&type->ref->type, &a);
+ reg_pass_rec(&type->ref->type, rc, fieldofs, ofs);
+ if (rc[0] > 2 || (rc[0] == 2 && type->ref->c > 1))
+ rc[0] = -1;
+ else if (type->ref->c == 2 && rc[0] && rc[1] == RC_FLOAT) {
+ rc[++rc[0]] = RC_FLOAT;
+ fieldofs[rc[0]] = ((ofs + sz) << 4)
+ | (type->ref->type.t & VT_BTYPE);
+ } else if (type->ref->c == 2)
+ rc[0] = -1;
+ }
+ } else if (rc[0] == 2 || rc[0] < 0 || (type->t & VT_BTYPE) == VT_LDOUBLE)
+ rc[0] = -1;
+ else if (!rc[0] || rc[1] == RC_FLOAT || is_float(type->t)) {
+ rc[++rc[0]] = is_float(type->t) ? RC_FLOAT : RC_INT;
+ fieldofs[rc[0]] = (ofs << 4) | (type->t & VT_BTYPE);
+ } else
+ rc[0] = -1;
+}
+
+static void reg_pass(CType *type, int *prc, int *fieldofs, int named)
+{
+ prc[0] = 0;
+ reg_pass_rec(type, prc, fieldofs, 0);
+ if (prc[0] <= 0 || !named) {
+ int align, size = type_size(type, &align);
+ prc[0] = (size + 7) >> 3;
+ prc[1] = prc[2] = RC_INT;
+ fieldofs[1] = (0 << 4) | (size <= 1 ? VT_BYTE : size <= 2 ? VT_SHORT : size <= 4 ? VT_INT : VT_LLONG);
+ fieldofs[2] = (8 << 4) | (size <= 9 ? VT_BYTE : size <= 10 ? VT_SHORT : size <= 12 ? VT_INT : VT_LLONG);
+ }
+}
+
+ST_FUNC void gfunc_call(int nb_args)
+{
+ int i, align, size, areg[2];
+ int *info = tcc_malloc((nb_args + 1) * sizeof (int));
+ int stack_adj = 0, tempspace = 0, stack_add, ofs, splitofs = 0;
+ SValue *sv;
+ Sym *sa;
+
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gbound_args(nb_args);
+#endif
+
+ areg[0] = 0; /* int arg regs */
+ areg[1] = 8; /* float arg regs */
+ sa = vtop[-nb_args].type.ref->next;
+ for (i = 0; i < nb_args; i++) {
+ int nregs, byref = 0, tempofs;
+ int prc[3], fieldofs[3];
+ sv = &vtop[1 + i - nb_args];
+ sv->type.t &= ~VT_ARRAY; // XXX this should be done in tccgen.c
+ size = type_size(&sv->type, &align);
+ if (size > 16) {
+ if (align < XLEN)
+ align = XLEN;
+ tempspace = (tempspace + align - 1) & -align;
+ tempofs = tempspace;
+ tempspace += size;
+ size = align = 8;
+ byref = 64 | (tempofs << 7);
+ }
+ reg_pass(&sv->type, prc, fieldofs, sa != 0);
+ if (!sa && align == 2*XLEN && size <= 2*XLEN)
+ areg[0] = (areg[0] + 1) & ~1;
+ nregs = prc[0];
+ if ((prc[1] == RC_INT && areg[0] >= 8)
+ || (prc[1] == RC_FLOAT && areg[1] >= 16)
+ || (nregs == 2 && prc[1] == RC_FLOAT && prc[2] == RC_FLOAT
+ && areg[1] >= 15)
+ || (nregs == 2 && prc[1] != prc[2]
+ && (areg[1] >= 16 || areg[0] >= 8))) {
+ info[i] = 32;
+ if (align < XLEN)
+ align = XLEN;
+ stack_adj += (size + align - 1) & -align;
+ if (!sa) /* one vararg on stack forces the rest on stack */
+ areg[0] = 8, areg[1] = 16;
+ } else {
+ info[i] = areg[prc[1] - 1]++;
+ if (!byref)
+ info[i] |= (fieldofs[1] & VT_BTYPE) << 12;
+ assert(!(fieldofs[1] >> 4));
+ if (nregs == 2) {
+ if (prc[2] == RC_FLOAT || areg[0] < 8)
+ info[i] |= (1 + areg[prc[2] - 1]++) << 7;
+ else {
+ info[i] |= 16;
+ stack_adj += 8;
+ }
+ if (!byref) {
+ assert((fieldofs[2] >> 4) < 2048);
+ info[i] |= fieldofs[2] << (12 + 4); // includes offset
+ }
+ }
+ }
+ info[i] |= byref;
+ if (sa)
+ sa = sa->next;
+ }
+ stack_adj = (stack_adj + 15) & -16;
+ tempspace = (tempspace + 15) & -16;
+ stack_add = stack_adj + tempspace;
+ if (stack_add) {
+ if (stack_add >= 0x1000) {
+ o(0x37 | (5 << 7) | (-stack_add & 0xfffff000)); //lui t0, upper(v)
+ EI(0x13, 0, 5, 5, -stack_add << 20 >> 20); // addi t0, t0, lo(v)
+ ER(0x33, 0, 2, 2, 5, 0); // add sp, sp, t0
+ }
+ else
+ EI(0x13, 0, 2, 2, -stack_add); // addi sp, sp, -adj
+ for (i = ofs = 0; i < nb_args; i++) {
+ if (info[i] & (64 | 32)) {
+ vrotb(nb_args - i);
+ size = type_size(&vtop->type, &align);
+ if (info[i] & 64) {
+ vset(&char_pointer_type, TREG_SP, 0);
+ vpushi(stack_adj + (info[i] >> 7));
+ gen_op('+');
+ vpushv(vtop); // this replaces the old argument
+ vrott(3);
+ indir();
+ vtop->type = vtop[-1].type;
+ vswap();
+ vstore();
+ vpop();
+ size = align = 8;
+ }
+ if (info[i] & 32) {
+ if (align < XLEN)
+ align = XLEN;
+ /* Once we support offseted regs we can do this:
+ vset(&vtop->type, TREG_SP | VT_LVAL, ofs);
+ to construct the lvalue for the outgoing stack slot,
+ until then we have to jump through hoops. */
+ vset(&char_pointer_type, TREG_SP, 0);
+ ofs = (ofs + align - 1) & -align;
+ vpushi(ofs);
+ gen_op('+');
+ indir();
+ vtop->type = vtop[-1].type;
+ vswap();
+ vstore();
+ vtop->r = vtop->r2 = VT_CONST; // this arg is done
+ ofs += size;
+ }
+ vrott(nb_args - i);
+ } else if (info[i] & 16) {
+ assert(!splitofs);
+ splitofs = ofs;
+ ofs += 8;
+ }
+ }
+ }
+ for (i = 0; i < nb_args; i++) {
+ int ii = info[nb_args - 1 - i], r = ii, r2 = r;
+ if (!(r & 32)) {
+ CType origtype;
+ int loadt;
+ r &= 15;
+ r2 = r2 & 64 ? 0 : (r2 >> 7) & 31;
+ assert(r2 <= 16);
+ vrotb(i+1);
+ origtype = vtop->type;
+ size = type_size(&vtop->type, &align);
+ loadt = vtop->type.t & VT_BTYPE;
+ if (loadt == VT_STRUCT) {
+ loadt = (ii >> 12) & VT_BTYPE;
+ }
+ if (info[nb_args - 1 - i] & 16) {
+ assert(!r2);
+ r2 = 1 + TREG_RA;
+ }
+ if (loadt == VT_LDOUBLE) {
+ assert(r2);
+ r2--;
+ } else if (r2) {
+ test_lvalue();
+ vpushv(vtop);
+ }
+ vtop->type.t = loadt | (vtop->type.t & VT_UNSIGNED);
+ gv(r < 8 ? RC_R(r) : RC_F(r - 8));
+ vtop->type = origtype;
+
+ if (r2 && loadt != VT_LDOUBLE) {
+ r2--;
+ assert(r2 < 16 || r2 == TREG_RA);
+ vswap();
+ gaddrof();
+ vtop->type = char_pointer_type;
+ vpushi(ii >> 20);
+ gen_op('+');
+ indir();
+ vtop->type = origtype;
+ loadt = vtop->type.t & VT_BTYPE;
+ if (loadt == VT_STRUCT) {
+ loadt = (ii >> 16) & VT_BTYPE;
+ }
+ save_reg_upstack(r2, 1);
+ vtop->type.t = loadt | (vtop->type.t & VT_UNSIGNED);
+ load(r2, vtop);
+ assert(r2 < VT_CONST);
+ vtop--;
+ vtop->r2 = r2;
+ }
+ if (info[nb_args - 1 - i] & 16) {
+ ES(0x23, 3, 2, ireg(vtop->r2), splitofs); // sd t0, ofs(sp)
+ vtop->r2 = VT_CONST;
+ } else if (loadt == VT_LDOUBLE && vtop->r2 != r2) {
+ assert(vtop->r2 <= 7 && r2 <= 7);
+ /* XXX we'd like to have 'gv' move directly into
+ the right class instead of us fixing it up. */
+ EI(0x13, 0, ireg(r2), ireg(vtop->r2), 0); // mv Ra+1, RR2
+ vtop->r2 = r2;
+ }
+ vrott(i+1);
+ }
+ }
+ vrotb(nb_args + 1);
+ save_regs(nb_args + 1);
+ gcall_or_jmp(1);
+ vtop -= nb_args + 1;
+ if (stack_add) {
+ if (stack_add >= 0x1000) {
+ o(0x37 | (5 << 7) | (stack_add & 0xfffff000)); //lui t0, upper(v)
+ EI(0x13, 0, 5, 5, stack_add << 20 >> 20); // addi t0, t0, lo(v)
+ ER(0x33, 0, 2, 2, 5, 0); // add sp, sp, t0
+ }
+ else
+ EI(0x13, 0, 2, 2, stack_add); // addi sp, sp, adj
+ }
+ tcc_free(info);
+}
+
+static int func_sub_sp_offset, num_va_regs, func_va_list_ofs;
+
+ST_FUNC void gfunc_prolog(Sym *func_sym)
+{
+ CType *func_type = &func_sym->type;
+ int i, addr, align, size;
+ int param_addr = 0;
+ int areg[2];
+ Sym *sym;
+ CType *type;
+
+ sym = func_type->ref;
+ loc = -16; // for ra and s0
+ func_sub_sp_offset = ind;
+ ind += 5 * 4;
+
+ areg[0] = 0, areg[1] = 0;
+ addr = 0;
+ /* if the function returns by reference, then add an
+ implicit pointer parameter */
+ size = type_size(&func_vt, &align);
+ if (size > 2 * XLEN) {
+ loc -= 8;
+ func_vc = loc;
+ ES(0x23, 3, 8, 10 + areg[0]++, loc); // sd a0, loc(s0)
+ }
+ /* define parameters */
+ while ((sym = sym->next) != NULL) {
+ int byref = 0;
+ int regcount;
+ int prc[3], fieldofs[3];
+ type = &sym->type;
+ size = type_size(type, &align);
+ if (size > 2 * XLEN) {
+ type = &char_pointer_type;
+ size = align = byref = 8;
+ }
+ reg_pass(type, prc, fieldofs, 1);
+ regcount = prc[0];
+ if (areg[prc[1] - 1] >= 8
+ || (regcount == 2
+ && ((prc[1] == RC_FLOAT && prc[2] == RC_FLOAT && areg[1] >= 7)
+ || (prc[1] != prc[2] && (areg[1] >= 8 || areg[0] >= 8))))) {
+ if (align < XLEN)
+ align = XLEN;
+ addr = (addr + align - 1) & -align;
+ param_addr = addr;
+ addr += size;
+ } else {
+ loc -= regcount * 8; // XXX could reserve only 'size' bytes
+ param_addr = loc;
+ for (i = 0; i < regcount; i++) {
+ if (areg[prc[1+i] - 1] >= 8) {
+ assert(i == 1 && regcount == 2 && !(addr & 7));
+ EI(0x03, 3, 5, 8, addr); // ld t0, addr(s0)
+ addr += 8;
+ ES(0x23, 3, 8, 5, loc + i*8); // sd t0, loc(s0)
+ } else if (prc[1+i] == RC_FLOAT) {
+ ES(0x27, (size / regcount) == 4 ? 2 : 3, 8, 10 + areg[1]++, loc + (fieldofs[i+1] >> 4)); // fs[wd] FAi, loc(s0)
+ } else {
+ ES(0x23, 3, 8, 10 + areg[0]++, loc + i*8); // sd aX, loc(s0) // XXX
+ }
+ }
+ }
+ sym_push(sym->v & ~SYM_FIELD, &sym->type,
+ (byref ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
+ param_addr);
+ }
+ func_va_list_ofs = addr;
+ num_va_regs = 0;
+ if (func_var) {
+ for (; areg[0] < 8; areg[0]++) {
+ num_va_regs++;
+ ES(0x23, 3, 8, 10 + areg[0], -8 + num_va_regs * 8); // sd aX, loc(s0)
+ }
+ }
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_prolog();
+#endif
+}
+
+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
+ int *ret_align, int *regsize)
+{
+ int align, size = type_size(vt, &align), nregs;
+ int prc[3], fieldofs[3];
+ *ret_align = 1;
+ *regsize = 8;
+ if (size > 16)
+ return 0;
+ reg_pass(vt, prc, fieldofs, 1);
+ nregs = prc[0];
+ if (nregs == 2 && prc[1] != prc[2])
+ return -1; /* generic code can't deal with this case */
+ if (prc[1] == RC_FLOAT) {
+ *regsize = size / nregs;
+ }
+ ret->t = fieldofs[1] & VT_BTYPE;
+ return nregs;
+}
+
+ST_FUNC void arch_transfer_ret_regs(int aftercall)
+{
+ int prc[3], fieldofs[3];
+ reg_pass(&vtop->type, prc, fieldofs, 1);
+ assert(prc[0] == 2 && prc[1] != prc[2] && !(fieldofs[1] >> 4));
+ assert(vtop->r == (VT_LOCAL | VT_LVAL));
+ vpushv(vtop);
+ vtop->type.t = fieldofs[1] & VT_BTYPE;
+ (aftercall ? store : load)(prc[1] == RC_INT ? REG_IRET : REG_FRET, vtop);
+ vtop->c.i += fieldofs[2] >> 4;
+ vtop->type.t = fieldofs[2] & VT_BTYPE;
+ (aftercall ? store : load)(prc[2] == RC_INT ? REG_IRET : REG_FRET, vtop);
+ vtop--;
+}
+
+ST_FUNC void gfunc_epilog(void)
+{
+ int v, saved_ind, d, large_ofs_ind;
+
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_epilog();
+#endif
+
+ loc = (loc - num_va_regs * 8);
+ d = v = (-loc + 15) & -16;
+
+ if (v >= (1 << 11)) {
+ d = 16;
+ o(0x37 | (5 << 7) | ((0x800 + (v-16)) & 0xfffff000)); //lui t0, upper(v)
+ EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
+ ER(0x33, 0, 2, 2, 5, 0); // add sp, sp, t0
+ }
+ EI(0x03, 3, 1, 2, d - 8 - num_va_regs * 8); // ld ra, v-8(sp)
+ EI(0x03, 3, 8, 2, d - 16 - num_va_regs * 8); // ld s0, v-16(sp)
+ EI(0x13, 0, 2, 2, d); // addi sp, sp, v
+ EI(0x67, 0, 0, 1, 0); // jalr x0, 0(x1), aka ret
+ large_ofs_ind = ind;
+ if (v >= (1 << 11)) {
+ EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
+ o(0x37 | (5 << 7) | ((0x800 + (v-16)) & 0xfffff000)); //lui t0, upper(v)
+ EI(0x13, 0, 5, 5, (v-16) << 20 >> 20); // addi t0, t0, lo(v)
+ ER(0x33, 0, 2, 2, 5, 0x20); // sub sp, sp, t0
+ gjmp_addr(func_sub_sp_offset + 5*4);
+ }
+ saved_ind = ind;
+
+ ind = func_sub_sp_offset;
+ EI(0x13, 0, 2, 2, -d); // addi sp, sp, -d
+ ES(0x23, 3, 2, 1, d - 8 - num_va_regs * 8); // sd ra, d-8(sp)
+ ES(0x23, 3, 2, 8, d - 16 - num_va_regs * 8); // sd s0, d-16(sp)
+ if (v < (1 << 11))
+ EI(0x13, 0, 8, 2, d - num_va_regs * 8); // addi s0, sp, d
+ else
+ gjmp_addr(large_ofs_ind);
+ if ((ind - func_sub_sp_offset) != 5*4)
+ EI(0x13, 0, 0, 0, 0); // addi x0, x0, 0 == nop
+ ind = saved_ind;
+}
+
+ST_FUNC void gen_va_start(void)
+{
+ vtop--;
+ vset(&char_pointer_type, VT_LOCAL, func_va_list_ofs);
+}
+
+ST_FUNC void gen_fill_nops(int bytes)
+{
+ if ((bytes & 3))
+ tcc_error("alignment of code section not multiple of 4");
+ while (bytes > 0) {
+ EI(0x13, 0, 0, 0, 0); // addi x0, x0, 0 == nop
+ bytes -= 4;
+ }
+}
+
+// Generate forward branch to label:
+ST_FUNC int gjmp(int t)
+{
+ if (nocode_wanted)
+ return t;
+ o(t);
+ return ind - 4;
+}
+
+// Generate branch to known address:
+ST_FUNC void gjmp_addr(int a)
+{
+ uint32_t r = a - ind, imm;
+ if ((r + (1 << 21)) & ~((1U << 22) - 2)) {
+ o(0x17 | (5 << 7) | (((r + 0x800) & 0xfffff000))); // lui RR, up(r)
+ r = (int)r << 20 >> 20;
+ EI(0x67, 0, 0, 5, r); // jalr x0, r(t0)
+ } else {
+ imm = (((r >> 12) & 0xff) << 12)
+ | (((r >> 11) & 1) << 20)
+ | (((r >> 1) & 0x3ff) << 21)
+ | (((r >> 20) & 1) << 31);
+ o(0x6f | imm); // jal x0, imm == j imm
+ }
+}
+
+ST_FUNC int gjmp_cond(int op, int t)
+{
+ int tmp;
+ int a = vtop->cmp_r & 0xff;
+ int b = (vtop->cmp_r >> 8) & 0xff;
+ switch (op) {
+ case TOK_ULT: op = 6; break;
+ case TOK_UGE: op = 7; break;
+ case TOK_ULE: op = 7; tmp = a; a = b; b = tmp; break;
+ case TOK_UGT: op = 6; tmp = a; a = b; b = tmp; break;
+ case TOK_LT: op = 4; break;
+ case TOK_GE: op = 5; break;
+ case TOK_LE: op = 5; tmp = a; a = b; b = tmp; break;
+ case TOK_GT: op = 4; tmp = a; a = b; b = tmp; break;
+ case TOK_NE: op = 1; break;
+ case TOK_EQ: op = 0; break;
+ }
+ o(0x63 | (op ^ 1) << 12 | a << 15 | b << 20 | 8 << 7); // bOP a,b,+4
+ return gjmp(t);
+}
+
+ST_FUNC int gjmp_append(int n, int t)
+{
+ void *p;
+ /* insert jump list n into t */
+ if (n) {
+ uint32_t n1 = n, n2;
+ while ((n2 = read32le(p = cur_text_section->data + n1)))
+ n1 = n2;
+ write32le(p, t);
+ t = n;
+ }
+ return t;
+}
+
+static void gen_opil(int op, int ll)
+{
+ int a, b, d;
+ int func3 = 0;
+ ll = ll ? 0 : 8;
+ if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+ int fc = vtop->c.i;
+ if (fc == vtop->c.i && !(((unsigned)fc + (1 << 11)) >> 12)) {
+ int cll = 0;
+ int m = ll ? 31 : 63;
+ vswap();
+ gv(RC_INT);
+ a = ireg(vtop[0].r);
+ --vtop;
+ d = get_reg(RC_INT);
+ ++vtop;
+ vswap();
+ switch (op) {
+ case '-':
+ if (fc <= -(1 << 11))
+ break;
+ fc = -fc;
+ case '+':
+ func3 = 0; // addi d, a, fc
+ cll = ll;
+ do_cop:
+ EI(0x13 | cll, func3, ireg(d), a, fc);
+ --vtop;
+ if (op >= TOK_ULT && op <= TOK_GT) {
+ vset_VT_CMP(TOK_NE);
+ vtop->cmp_r = ireg(d) | 0 << 8;
+ } else
+ vtop[0].r = d;
+ return;
+ case TOK_LE:
+ if (fc >= (1 << 11) - 1)
+ break;
+ ++fc;
+ case TOK_LT: func3 = 2; goto do_cop; // slti d, a, fc
+ case TOK_ULE:
+ if (fc >= (1 << 11) - 1 || fc == -1)
+ break;
+ ++fc;
+ case TOK_ULT: func3 = 3; goto do_cop; // sltiu d, a, fc
+ case '^': func3 = 4; goto do_cop; // xori d, a, fc
+ case '|': func3 = 6; goto do_cop; // ori d, a, fc
+ case '&': func3 = 7; goto do_cop; // andi d, a, fc
+ case TOK_SHL: func3 = 1; cll = ll; fc &= m; goto do_cop; // slli d, a, fc
+ case TOK_SHR: func3 = 5; cll = ll; fc &= m; goto do_cop; // srli d, a, fc
+ case TOK_SAR: func3 = 5; cll = ll; fc = 1024 | (fc & m); goto do_cop;
+
+ case TOK_UGE: /* -> TOK_ULT */
+ case TOK_UGT: /* -> TOK_ULE */
+ case TOK_GE: /* -> TOK_LT */
+ case TOK_GT: /* -> TOK_LE */
+ gen_opil(op - 1, !ll);
+ vtop->cmp_op ^= 1;
+ return;
+
+ case TOK_NE:
+ case TOK_EQ:
+ if (fc)
+ gen_opil('-', !ll), a = ireg(vtop++->r);
+ --vtop;
+ vset_VT_CMP(op);
+ vtop->cmp_r = a | 0 << 8;
+ return;
+ }
+ }
+ }
+ gv2(RC_INT, RC_INT);
+ a = ireg(vtop[-1].r);
+ b = ireg(vtop[0].r);
+ vtop -= 2;
+ d = get_reg(RC_INT);
+ vtop++;
+ vtop[0].r = d;
+ d = ireg(d);
+ switch (op) {
+ default:
+ if (op >= TOK_ULT && op <= TOK_GT) {
+ vset_VT_CMP(op);
+ vtop->cmp_r = a | b << 8;
+ break;
+ }
+ tcc_error("implement me: %s(%s)", __FUNCTION__, get_tok_str(op, NULL));
+ break;
+
+ case '+':
+ ER(0x33 | ll, 0, d, a, b, 0); // add d, a, b
+ break;
+ case '-':
+ ER(0x33 | ll, 0, d, a, b, 0x20); // sub d, a, b
+ break;
+ case TOK_SAR:
+ ER(0x33 | ll | ll, 5, d, a, b, 0x20); // sra d, a, b
+ break;
+ case TOK_SHR:
+ ER(0x33 | ll | ll, 5, d, a, b, 0); // srl d, a, b
+ break;
+ case TOK_SHL:
+ ER(0x33 | ll, 1, d, a, b, 0); // sll d, a, b
+ break;
+ case '*':
+ ER(0x33 | ll, 0, d, a, b, 1); // mul d, a, b
+ break;
+ case '/':
+ ER(0x33 | ll, 4, d, a, b, 1); // div d, a, b
+ break;
+ case '&':
+ ER(0x33, 7, d, a, b, 0); // and d, a, b
+ break;
+ case '^':
+ ER(0x33, 4, d, a, b, 0); // xor d, a, b
+ break;
+ case '|':
+ ER(0x33, 6, d, a, b, 0); // or d, a, b
+ break;
+ case '%':
+ ER(ll ? 0x3b: 0x33, 6, d, a, b, 1); // rem d, a, b
+ break;
+ case TOK_UMOD:
+ ER(0x33 | ll, 7, d, a, b, 1); // remu d, a, b
+ break;
+ case TOK_PDIV:
+ case TOK_UDIV:
+ ER(0x33 | ll, 5, d, a, b, 1); // divu d, a, b
+ break;
+ }
+}
+
+ST_FUNC void gen_opi(int op)
+{
+ gen_opil(op, 0);
+}
+
+ST_FUNC void gen_opl(int op)
+{
+ gen_opil(op, 1);
+}
+
+ST_FUNC void gen_opf(int op)
+{
+ int rs1, rs2, rd, dbl, invert;
+ if (vtop[0].type.t == VT_LDOUBLE) {
+ CType type = vtop[0].type;
+ int func = 0;
+ int cond = -1;
+ switch (op) {
+ case '*': func = TOK___multf3; break;
+ case '+': func = TOK___addtf3; break;
+ case '-': func = TOK___subtf3; break;
+ case '/': func = TOK___divtf3; break;
+ case TOK_EQ: func = TOK___eqtf2; cond = 1; break;
+ case TOK_NE: func = TOK___netf2; cond = 0; break;
+ case TOK_LT: func = TOK___lttf2; cond = 10; break;
+ case TOK_GE: func = TOK___getf2; cond = 11; break;
+ case TOK_LE: func = TOK___letf2; cond = 12; break;
+ case TOK_GT: func = TOK___gttf2; cond = 13; break;
+ default: assert(0); break;
+ }
+ vpush_global_sym(&func_old_type, func);
+ vrott(3);
+ gfunc_call(2);
+ vpushi(0);
+ vtop->r = REG_IRET;
+ vtop->r2 = cond < 0 ? TREG_R(1) : VT_CONST;
+ if (cond < 0)
+ vtop->type = type;
+ else {
+ vpushi(0);
+ gen_opil(op, 1);
+ }
+ return;
+ }
+
+ gv2(RC_FLOAT, RC_FLOAT);
+ assert(vtop->type.t == VT_DOUBLE || vtop->type.t == VT_FLOAT);
+ dbl = vtop->type.t == VT_DOUBLE;
+ rs1 = freg(vtop[-1].r);
+ rs2 = freg(vtop->r);
+ vtop--;
+ invert = 0;
+ switch(op) {
+ default:
+ assert(0);
+ case '+':
+ op = 0; // fadd
+ arithop:
+ rd = get_reg(RC_FLOAT);
+ vtop->r = rd;
+ rd = freg(rd);
+ ER(0x53, 7, rd, rs1, rs2, dbl | (op << 2)); // fop.[sd] RD, RS1, RS2 (dyn rm)
+ break;
+ case '-':
+ op = 1; // fsub
+ goto arithop;
+ case '*':
+ op = 2; // fmul
+ goto arithop;
+ case '/':
+ op = 3; // fdiv
+ goto arithop;
+ case TOK_EQ:
+ op = 2; // EQ
+ cmpop:
+ rd = get_reg(RC_INT);
+ vtop->r = rd;
+ rd = ireg(rd);
+ ER(0x53, op, rd, rs1, rs2, dbl | 0x50); // fcmp.[sd] RD, RS1, RS2 (op == eq/lt/le)
+ if (invert)
+ EI(0x13, 4, rd, rd, 1); // xori RD, 1
+ break;
+ case TOK_NE:
+ invert = 1;
+ op = 2; // EQ
+ goto cmpop;
+ case TOK_LT:
+ op = 1; // LT
+ goto cmpop;
+ case TOK_LE:
+ op = 0; // LE
+ goto cmpop;
+ case TOK_GT:
+ op = 1; // LT
+ rd = rs1, rs1 = rs2, rs2 = rd;
+ goto cmpop;
+ case TOK_GE:
+ op = 0; // LE
+ rd = rs1, rs1 = rs2, rs2 = rd;
+ goto cmpop;
+ }
+}
+
+ST_FUNC void gen_cvt_sxtw(void)
+{
+ /* XXX on risc-v the registers are usually sign-extended already.
+ Let's try to not do anything here. */
+}
+
+ST_FUNC void gen_cvt_itof(int t)
+{
+ int rr = ireg(gv(RC_INT)), dr;
+ int u = vtop->type.t & VT_UNSIGNED;
+ int l = (vtop->type.t & VT_BTYPE) == VT_LLONG;
+ if (t == VT_LDOUBLE) {
+ int func = l ?
+ (u ? TOK___floatunditf : TOK___floatditf) :
+ (u ? TOK___floatunsitf : TOK___floatsitf);
+ vpush_global_sym(&func_old_type, func);
+ vrott(2);
+ gfunc_call(1);
+ vpushi(0);
+ vtop->type.t = t;
+ vtop->r = REG_IRET;
+ vtop->r2 = TREG_R(1);
+ } else {
+ vtop--;
+ dr = get_reg(RC_FLOAT);
+ vtop++;
+ vtop->r = dr;
+ dr = freg(dr);
+ EIu(0x53, 7, dr, rr, ((0x68 | (t == VT_DOUBLE ? 1 : 0)) << 5) | (u ? 1 : 0) | (l ? 2 : 0)); // fcvt.[sd].[wl][u]
+ }
+}
+
+ST_FUNC void gen_cvt_ftoi(int t)
+{
+ int ft = vtop->type.t & VT_BTYPE;
+ int l = (t & VT_BTYPE) == VT_LLONG;
+ int u = t & VT_UNSIGNED;
+ if (ft == VT_LDOUBLE) {
+ int func = l ?
+ (u ? TOK___fixunstfdi : TOK___fixtfdi) :
+ (u ? TOK___fixunstfsi : TOK___fixtfsi);
+ vpush_global_sym(&func_old_type, func);
+ vrott(2);
+ gfunc_call(1);
+ vpushi(0);
+ vtop->type.t = t;
+ vtop->r = REG_IRET;
+ } else {
+ int rr = freg(gv(RC_FLOAT)), dr;
+ vtop--;
+ dr = get_reg(RC_INT);
+ vtop++;
+ vtop->r = dr;
+ dr = ireg(dr);
+ EIu(0x53, 1, dr, rr, ((0x60 | (ft == VT_DOUBLE ? 1 : 0)) << 5) | (u ? 1 : 0) | (l ? 2 : 0)); // fcvt.[wl][u].[sd] rtz
+ }
+}
+
+ST_FUNC void gen_cvt_ftof(int dt)
+{
+ int st = vtop->type.t & VT_BTYPE, rs, rd;
+ dt &= VT_BTYPE;
+ if (st == dt)
+ return;
+ if (dt == VT_LDOUBLE || st == VT_LDOUBLE) {
+ int func = (dt == VT_LDOUBLE) ?
+ (st == VT_FLOAT ? TOK___extendsftf2 : TOK___extenddftf2) :
+ (dt == VT_FLOAT ? TOK___trunctfsf2 : TOK___trunctfdf2);
+ /* We can't use gfunc_call, as func_old_type works like vararg
+ functions, and on riscv unnamed float args are passed like
+ integers. But we really need them in the float argument registers
+ for extendsftf2/extenddftf2. So, do it explicitely. */
+ save_regs(1);
+ if (dt == VT_LDOUBLE)
+ gv(RC_F(0));
+ else {
+ gv(RC_R(0));
+ assert(vtop->r2 < 7);
+ if (vtop->r2 != 1 + vtop->r) {
+ EI(0x13, 0, ireg(vtop->r) + 1, ireg(vtop->r2), 0); // mv Ra+1, RR2
+ vtop->r2 = 1 + vtop->r;
+ }
+ }
+ vpush_global_sym(&func_old_type, func);
+ gcall_or_jmp(1);
+ vtop -= 2;
+ vpushi(0);
+ vtop->type.t = dt;
+ if (dt == VT_LDOUBLE)
+ vtop->r = REG_IRET, vtop->r2 = REG_IRET+1;
+ else
+ vtop->r = REG_FRET;
+ } else {
+ assert (dt == VT_FLOAT || dt == VT_DOUBLE);
+ assert (st == VT_FLOAT || st == VT_DOUBLE);
+ rs = gv(RC_FLOAT);
+ rd = get_reg(RC_FLOAT);
+ if (dt == VT_DOUBLE)
+ EI(0x53, 0, freg(rd), freg(rs), 0x21 << 5); // fcvt.d.s RD, RS (no rm)
+ else
+ EI(0x53, 7, freg(rd), freg(rs), (0x20 << 5) | 1); // fcvt.s.d RD, RS (dyn rm)
+ vtop->r = rd;
+ }
+}
+
+ST_FUNC void ggoto(void)
+{
+ gcall_or_jmp(0);
+ vtop--;
+}
+
+ST_FUNC void gen_vla_sp_save(int addr)
+{
+ ES(0x23, 3, 8, 2, addr); // sd sp, fc(s0)
+}
+
+ST_FUNC void gen_vla_sp_restore(int addr)
+{
+ EI(0x03, 3, 2, 8, addr); // ld sp, fc(s0)
+}
+
+ST_FUNC void gen_vla_alloc(CType *type, int align)
+{
+ int rr;
+#if defined(CONFIG_TCC_BCHECK)
+ if (tcc_state->do_bounds_check)
+ vpushv(vtop);
+#endif
+ rr = ireg(gv(RC_INT));
+ EI(0x13, 0, rr, rr, 15); // addi RR, RR, 15
+ EI(0x13, 7, rr, rr, -16); // andi, RR, RR, -16
+ ER(0x33, 0, 2, 2, rr, 0x20); // sub sp, sp, rr
+ vpop();
+#if defined(CONFIG_TCC_BCHECK)
+ if (tcc_state->do_bounds_check) {
+ vpushi(0);
+ vtop->r = TREG_R(0);
+ o(0x00010513); /* mv a0,sp */
+ vswap();
+ vpush_global_sym(&func_old_type, TOK___bound_new_region);
+ vrott(3);
+ gfunc_call(2);
+ func_bound_add_epilog = 1;
+ }
+#endif
+}
+#endif
diff --git a/riscv64-link.c b/riscv64-link.c
new file mode 100644
index 0000000..dc0bb5a
--- /dev/null
+++ b/riscv64-link.c
@@ -0,0 +1,349 @@
+#ifdef TARGET_DEFS_ONLY
+
+#define EM_TCC_TARGET EM_RISCV
+
+#define R_DATA_32 R_RISCV_32
+#define R_DATA_PTR R_RISCV_64
+#define R_JMP_SLOT R_RISCV_JUMP_SLOT
+#define R_GLOB_DAT R_RISCV_64
+#define R_COPY R_RISCV_COPY
+#define R_RELATIVE R_RISCV_RELATIVE
+
+#define R_NUM R_RISCV_NUM
+
+#define ELF_START_ADDR 0x00010000
+#define ELF_PAGE_SIZE 0x1000
+
+#define PCRELATIVE_DLLPLT 1
+#define RELOCATE_DLLPLT 1
+
+#else /* !TARGET_DEFS_ONLY */
+
+//#define DEBUG_RELOC
+#include "tcc.h"
+
+/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
+ relocations, returns -1. */
+int code_reloc (int reloc_type)
+{
+ switch (reloc_type) {
+
+ case R_RISCV_BRANCH:
+ case R_RISCV_CALL:
+ case R_RISCV_JAL:
+ return 1;
+
+ case R_RISCV_GOT_HI20:
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ case R_RISCV_32_PCREL:
+ case R_RISCV_SET6:
+ case R_RISCV_SUB6:
+ case R_RISCV_ADD16:
+ case R_RISCV_ADD32:
+ case R_RISCV_ADD64:
+ case R_RISCV_SUB16:
+ case R_RISCV_SUB32:
+ case R_RISCV_SUB64:
+ case R_RISCV_32:
+ case R_RISCV_64:
+ return 0;
+
+ case R_RISCV_CALL_PLT:
+ return 1;
+ }
+ return -1;
+}
+
+/* Returns an enumerator to describe whether and when the relocation needs a
+ GOT and/or PLT entry to be created. See tcc.h for a description of the
+ different values. */
+int gotplt_entry_type (int reloc_type)
+{
+ switch (reloc_type) {
+ case R_RISCV_ALIGN:
+ case R_RISCV_RELAX:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
+ case R_RISCV_JUMP_SLOT:
+ case R_RISCV_SET6:
+ case R_RISCV_SUB6:
+ case R_RISCV_ADD16:
+ case R_RISCV_SUB16:
+ return NO_GOTPLT_ENTRY;
+
+ case R_RISCV_BRANCH:
+ case R_RISCV_CALL:
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ case R_RISCV_32_PCREL:
+ case R_RISCV_ADD32:
+ case R_RISCV_ADD64:
+ case R_RISCV_SUB32:
+ case R_RISCV_SUB64:
+ case R_RISCV_32:
+ case R_RISCV_64:
+ case R_RISCV_JAL:
+ case R_RISCV_CALL_PLT:
+ return AUTO_GOTPLT_ENTRY;
+
+ case R_RISCV_GOT_HI20:
+ return ALWAYS_GOTPLT_ENTRY;
+ }
+ return -1;
+}
+
+ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
+{
+ Section *plt = s1->plt;
+ uint8_t *p;
+ unsigned plt_offset;
+
+ if (plt->data_offset == 0)
+ section_ptr_add(plt, 32);
+ plt_offset = plt->data_offset;
+
+ p = section_ptr_add(plt, 16);
+ write64le(p, got_offset);
+ return plt_offset;
+}
+
+/* relocate the PLT: compute addresses and offsets in the PLT now that final
+ address for PLT and GOT are known (see fill_program_header) */
+ST_FUNC void relocate_plt(TCCState *s1)
+{
+ uint8_t *p, *p_end;
+
+ if (!s1->plt)
+ return;
+
+ p = s1->plt->data;
+ p_end = p + s1->plt->data_offset;
+
+ if (p < p_end) {
+ uint64_t plt = s1->plt->sh_addr;
+ uint64_t got = s1->got->sh_addr;
+ uint64_t off = (got - plt + 0x800) >> 12;
+ if ((off + ((uint32_t)1 << 20)) >> 21)
+ tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
+ write32le(p, 0x397 | (off << 12)); // auipc t2, %pcrel_hi(got)
+ write32le(p + 4, 0x41c30333); // sub t1, t1, t3
+ write32le(p + 8, 0x0003be03 // ld t3, %pcrel_lo(got)(t2)
+ | (((got - plt) & 0xfff) << 20));
+ write32le(p + 12, 0xfd430313); // addi t1, t1, -(32+12)
+ write32le(p + 16, 0x00038293 // addi t0, t2, %pcrel_lo(got)
+ | (((got - plt) & 0xfff) << 20));
+ write32le(p + 20, 0x00135313); // srli t1, t1, log2(16/PTRSIZE)
+ write32le(p + 24, 0x0082b283); // ld t0, PTRSIZE(t0)
+ write32le(p + 28, 0x000e0067); // jr t3
+ p += 32;
+ while (p < p_end) {
+ uint64_t pc = plt + (p - s1->plt->data);
+ uint64_t addr = got + read64le(p);
+ uint64_t off = (addr - pc + 0x800) >> 12;
+ if ((off + ((uint32_t)1 << 20)) >> 21)
+ tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
+ write32le(p, 0xe17 | (off << 12)); // auipc t3, %pcrel_hi(func@got)
+ write32le(p + 4, 0x000e3e03 // ld t3, %pcrel_lo(func@got)(t3)
+ | (((addr - pc) & 0xfff) << 20));
+ write32le(p + 8, 0x000e0367); // jalr t1, t3
+ write32le(p + 12, 0x00000013); // nop
+ p += 16;
+ }
+ }
+}
+
+struct pcrel_hi {
+ addr_t addr, val;
+};
+static struct pcrel_hi last_hi;
+
+void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
+ addr_t addr, addr_t val)
+{
+ uint64_t off64;
+ uint32_t off32;
+ int sym_index = ELFW(R_SYM)(rel->r_info), esym_index;
+ ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+
+ switch(type) {
+ case R_RISCV_ALIGN:
+ case R_RISCV_RELAX:
+ return;
+
+ case R_RISCV_BRANCH:
+ off64 = val - addr;
+ if ((off64 + (1 << 12)) & ~(uint64_t)0x1ffe)
+ tcc_error("R_RISCV_BRANCH relocation failed"
+ " (val=%lx, addr=%lx)", val, addr);
+ off32 = off64 >> 1;
+ write32le(ptr, (read32le(ptr) & ~0xfe000f80)
+ | ((off32 & 0x800) << 20)
+ | ((off32 & 0x3f0) << 21)
+ | ((off32 & 0x00f) << 8)
+ | ((off32 & 0x400) >> 3));
+ return;
+ case R_RISCV_JAL:
+ off64 = val - addr;
+ if ((off64 + (1 << 21)) & ~(((uint64_t)1 << 22) - 2))
+ tcc_error("R_RISCV_JAL relocation failed"
+ " (val=%lx, addr=%lx)", val, addr);
+ off32 = off64;
+ write32le(ptr, (read32le(ptr) & 0xfff)
+ | (((off32 >> 12) & 0xff) << 12)
+ | (((off32 >> 11) & 1) << 20)
+ | (((off32 >> 1) & 0x3ff) << 21)
+ | (((off32 >> 20) & 1) << 31));
+ return;
+ case R_RISCV_CALL:
+ case R_RISCV_CALL_PLT:
+ write32le(ptr, (read32le(ptr) & 0xfff)
+ | ((val - addr + 0x800) & ~0xfff));
+ write32le(ptr + 4, (read32le(ptr + 4) & 0xfffff)
+ | (((val - addr) & 0xfff) << 20));
+ return;
+ case R_RISCV_PCREL_HI20:
+#ifdef DEBUG_RELOC
+ printf("PCREL_HI20: val=%lx addr=%lx\n", val, addr);
+#endif
+ off64 = (int64_t)(val - addr + 0x800) >> 12;
+ if ((off64 + ((uint64_t)1 << 20)) >> 21)
+ tcc_error("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx sym=%s",
+ off64, ((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21),
+ symtab_section->link->data + sym->st_name);
+ write32le(ptr, (read32le(ptr) & 0xfff)
+ | ((off64 & 0xfffff) << 12));
+ last_hi.addr = addr;
+ last_hi.val = val;
+ return;
+ case R_RISCV_GOT_HI20:
+ val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
+ off64 = (int64_t)(val - addr + 0x800) >> 12;
+ if ((off64 + ((uint64_t)1 << 20)) >> 21)
+ tcc_error("R_RISCV_GOT_HI20 relocation failed");
+ last_hi.addr = addr;
+ last_hi.val = val;
+ write32le(ptr, (read32le(ptr) & 0xfff)
+ | ((off64 & 0xfffff) << 12));
+ return;
+ case R_RISCV_PCREL_LO12_I:
+#ifdef DEBUG_RELOC
+ printf("PCREL_LO12_I: val=%lx addr=%lx\n", val, addr);
+#endif
+ if (val != last_hi.addr)
+ tcc_error("unsupported hi/lo pcrel reloc scheme");
+ val = last_hi.val;
+ addr = last_hi.addr;
+ write32le(ptr, (read32le(ptr) & 0xfffff)
+ | (((val - addr) & 0xfff) << 20));
+ return;
+ case R_RISCV_PCREL_LO12_S:
+ if (val != last_hi.addr)
+ tcc_error("unsupported hi/lo pcrel reloc scheme");
+ val = last_hi.val;
+ addr = last_hi.addr;
+ off32 = val - addr;
+ write32le(ptr, (read32le(ptr) & ~0xfe000f80)
+ | ((off32 & 0xfe0) << 20)
+ | ((off32 & 0x01f) << 7));
+ return;
+
+ case R_RISCV_RVC_BRANCH:
+ off64 = (val - addr);
+ if ((off64 + (1 << 8)) & ~(uint64_t)0x1fe)
+ tcc_error("R_RISCV_RVC_BRANCH relocation failed"
+ " (val=%lx, addr=%lx)", val, addr);
+ off32 = off64;
+ write16le(ptr, (read16le(ptr) & 0xe383)
+ | (((off32 >> 5) & 1) << 2)
+ | (((off32 >> 1) & 3) << 3)
+ | (((off32 >> 6) & 3) << 5)
+ | (((off32 >> 3) & 3) << 10)
+ | (((off32 >> 8) & 1) << 12));
+ return;
+ case R_RISCV_RVC_JUMP:
+ off64 = (val - addr);
+ if ((off64 + (1 << 11)) & ~(uint64_t)0xffe)
+ tcc_error("R_RISCV_RVC_BRANCH relocation failed"
+ " (val=%lx, addr=%lx)", val, addr);
+ off32 = off64;
+ write16le(ptr, (read16le(ptr) & 0xe003)
+ | (((off32 >> 5) & 1) << 2)
+ | (((off32 >> 1) & 7) << 3)
+ | (((off32 >> 7) & 1) << 6)
+ | (((off32 >> 6) & 1) << 7)
+ | (((off32 >> 10) & 1) << 8)
+ | (((off32 >> 8) & 3) << 9)
+ | (((off32 >> 4) & 1) << 11)
+ | (((off32 >> 11) & 1) << 12));
+ return;
+
+ case R_RISCV_32:
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ /* XXX: this logic may depend on TCC's codegen
+ now TCC uses R_RISCV_RELATIVE even for a 64bit pointer */
+ qrel->r_offset = rel->r_offset;
+ qrel->r_info = ELFW(R_INFO)(0, R_RISCV_RELATIVE);
+ /* Use sign extension! */
+ qrel->r_addend = (int)read32le(ptr) + val;
+ qrel++;
+ }
+ add32le(ptr, val);
+ return;
+ case R_RISCV_64:
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
+ qrel->r_offset = rel->r_offset;
+ if (esym_index) {
+ qrel->r_info = ELFW(R_INFO)(esym_index, R_RISCV_64);
+ qrel->r_addend = rel->r_addend;
+ qrel++;
+ break;
+ } else {
+ qrel->r_info = ELFW(R_INFO)(0, R_RISCV_RELATIVE);
+ qrel->r_addend = read64le(ptr) + val;
+ qrel++;
+ }
+ }
+ case R_RISCV_JUMP_SLOT:
+ add64le(ptr, val);
+ return;
+ case R_RISCV_ADD64:
+ write64le(ptr, read64le(ptr) + val);
+ return;
+ case R_RISCV_ADD32:
+ write32le(ptr, read32le(ptr) + val);
+ return;
+ case R_RISCV_SUB64:
+ write64le(ptr, read64le(ptr) - val);
+ return;
+ case R_RISCV_SUB32:
+ write32le(ptr, read32le(ptr) - val);
+ return;
+ case R_RISCV_ADD16:
+ write16le(ptr, read16le(ptr) + val);
+ return;
+ case R_RISCV_SUB16:
+ write16le(ptr, read16le(ptr) - val);
+ return;
+ case R_RISCV_SET6:
+ *ptr = (*ptr & ~0x3f) | (val & 0x3f);
+ return;
+ case R_RISCV_SUB6:
+ *ptr = (*ptr & ~0x3f) | ((*ptr - val) & 0x3f);
+ return;
+
+ case R_RISCV_32_PCREL:
+ case R_RISCV_COPY:
+ /* XXX */
+ return;
+
+ default:
+ fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
+ type, (unsigned)addr, ptr, (unsigned)val);
+ return;
+ }
+}
+#endif
diff --git a/tcc-doc.html b/tcc-doc.html
deleted file mode 100644
index c88d27a..0000000
--- a/tcc-doc.html
+++ /dev/null
@@ -1,2489 +0,0 @@
-<HTML>
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<!-- Created on December, 17 2017 by texi2html 1.64 -->
-<!--
-Written by: Lionel Cons <Lionel.Cons@cern.ch> (original author)
- Karl Berry <karl@freefriends.org>
- Olaf Bachmann <obachman@mathematik.uni-kl.de>
- and many others.
-Maintained by: Olaf Bachmann <obachman@mathematik.uni-kl.de>
-Send bugs and suggestions to <texi2html@mathematik.uni-kl.de>
-
--->
-<HEAD>
-<TITLE>Tiny C Compiler Reference Documentation: </TITLE>
-
-<META NAME="description" CONTENT="Tiny C Compiler Reference Documentation: ">
-<META NAME="keywords" CONTENT="Tiny C Compiler Reference Documentation: ">
-<META NAME="resource-type" CONTENT="document">
-<META NAME="distribution" CONTENT="global">
-<META NAME="Generator" CONTENT="texi2html 1.64">
-
-</HEAD>
-
-<BODY LANG="" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080" ALINK="#FF0000">
-
-<A NAME="SEC_Top"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1>Tiny C Compiler Reference Documentation</H1></P><P>
-
-This manual documents version 0.9.27 of the Tiny C Compiler.
-</P><P>
-
-<BLOCKQUOTE><TABLE BORDER=0 CELLSPACING=0>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC1">1. Introduction</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">Introduction to tcc.</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC2">2. Command line invocation</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">Invocation of tcc (command line, options).</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC5">3. C language support</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">ANSI C and extensions.</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC10">4. TinyCC Assembler</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">Assembler syntax.</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC16">5. TinyCC Linker</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">Output file generation and supported targets.</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">Automatic bounds-checking of C code.</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC22">7. The <CODE>libtcc</CODE> library</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">The libtcc library.</TD></TR>
-<TR><TD ALIGN="left" VALIGN="TOP"><A HREF="tcc-doc.html#SEC23">8. Developer's guide</A></TD><TD>&nbsp;&nbsp;</TD><TD ALIGN="left" VALIGN="TOP">Guide for Developers.</TD></TR>
-</TABLE></BLOCKQUOTE>
-<P>
-
-<HR SIZE=1>
-<A NAME="SEC1"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[ &lt;&lt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<A NAME="Introduction"></A>
-<H1> 1. Introduction </H1>
-<!--docid::SEC1::-->
-<P>
-
-TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C
-compilers, it is meant to be self-relying: you do not need an
-external assembler or linker because TCC does that for you.
-</P><P>
-
-TCC compiles so <EM>fast</EM> that even for big projects <CODE>Makefile</CODE>s may
-not be necessary.
-</P><P>
-
-TCC not only supports ANSI C, but also most of the new ISO C99
-standard and many GNUC extensions including inline assembly.
-</P><P>
-
-TCC can also be used to make <EM>C scripts</EM>, i.e. pieces of C source
-that you run as a Perl or Python script. Compilation is so fast that
-your script will be as fast as if it was an executable.
-</P><P>
-
-TCC can also automatically generate memory and bound checks
-(see section <A HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A>) while allowing all C pointers operations. TCC can do
-these checks even if non patched libraries are used.
-</P><P>
-
-With <CODE>libtcc</CODE>, you can use TCC as a backend for dynamic code
-generation (see section <A HREF="tcc-doc.html#SEC22">7. The <CODE>libtcc</CODE> library</A>).
-</P><P>
-
-TCC mainly supports the i386 target on Linux and Windows. There are alpha
-ports for the ARM (<CODE>arm-tcc</CODE>) and the TMS320C67xx targets
-(<CODE>c67-tcc</CODE>). More information about the ARM port is available at
-<A HREF="http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html">http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html</A>.
-</P><P>
-
-For usage on Windows, see also <A HREF="tcc-win32.txt">tcc-win32.txt</A>.
-</P><P>
-
-<A NAME="Invoke"></A>
-<HR SIZE="6">
-<A NAME="SEC2"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC1"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC3"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 2. Command line invocation </H1>
-<!--docid::SEC2::-->
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC3"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC4"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 2.1 Quick start </H2>
-<!--docid::SEC3::-->
-<P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>usage: tcc [options] [<VAR>infile1</VAR> <VAR>infile2</VAR><small>...</small>] [<SAMP>`-run'</SAMP> <VAR>infile</VAR> <VAR>args</VAR><small>...</small>]
-</pre></td></tr></table></P><P>
-
-TCC options are a very much like gcc options. The main difference is that TCC
-can also execute directly the resulting program and give it runtime
-arguments.
-</P><P>
-
-Here are some examples to understand the logic:
-</P><P>
-
-<DL COMPACT>
-<DT><CODE><SAMP>`tcc -run a.c'</SAMP></CODE>
-<DD>Compile <TT>`a.c'</TT> and execute it directly
-<P>
-
-<DT><CODE><SAMP>`tcc -run a.c arg1'</SAMP></CODE>
-<DD>Compile a.c and execute it directly. arg1 is given as first argument to
-the <CODE>main()</CODE> of a.c.
-<P>
-
-<DT><CODE><SAMP>`tcc a.c -run b.c arg1'</SAMP></CODE>
-<DD>Compile <TT>`a.c'</TT> and <TT>`b.c'</TT>, link them together and execute them. arg1 is given
-as first argument to the <CODE>main()</CODE> of the resulting program.
-<P>
-
-<DT><CODE><SAMP>`tcc -o myprog a.c b.c'</SAMP></CODE>
-<DD>Compile <TT>`a.c'</TT> and <TT>`b.c'</TT>, link them and generate the executable <TT>`myprog'</TT>.
-<P>
-
-<DT><CODE><SAMP>`tcc -o myprog a.o b.o'</SAMP></CODE>
-<DD>link <TT>`a.o'</TT> and <TT>`b.o'</TT> together and generate the executable <TT>`myprog'</TT>.
-<P>
-
-<DT><CODE><SAMP>`tcc -c a.c'</SAMP></CODE>
-<DD>Compile <TT>`a.c'</TT> and generate object file <TT>`a.o'</TT>.
-<P>
-
-<DT><CODE><SAMP>`tcc -c asmfile.S'</SAMP></CODE>
-<DD>Preprocess with C preprocess and assemble <TT>`asmfile.S'</TT> and generate
-object file <TT>`asmfile.o'</TT>.
-<P>
-
-<DT><CODE><SAMP>`tcc -c asmfile.s'</SAMP></CODE>
-<DD>Assemble (but not preprocess) <TT>`asmfile.s'</TT> and generate object file
-<TT>`asmfile.o'</TT>.
-<P>
-
-<DT><CODE><SAMP>`tcc -r -o ab.o a.c b.c'</SAMP></CODE>
-<DD>Compile <TT>`a.c'</TT> and <TT>`b.c'</TT>, link them together and generate the object file <TT>`ab.o'</TT>.
-<P>
-
-</DL>
-<P>
-
-Scripting:
-</P><P>
-
-TCC can be invoked from <EM>scripts</EM>, just as shell scripts. You just
-need to add <CODE>#!/usr/local/bin/tcc -run</CODE> at the start of your C source:
-</P><P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>#!/usr/local/bin/tcc -run
-#include &#60;stdio.h&#62;
-
-int main()
-{
- printf("Hello World\n");
- return 0;
-}
-</pre></td></tr></table></P><P>
-
-TCC can read C source code from <EM>standard input</EM> when <SAMP>`-'</SAMP> is used in
-place of <SAMP>`infile'</SAMP>. Example:
-</P><P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>echo 'main(){puts("hello");}' | tcc -run -
-</pre></td></tr></table></P><P>
-
-<HR SIZE="6">
-<A NAME="SEC4"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC3"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 2.2 Option summary </H2>
-<!--docid::SEC4::-->
-<P>
-
-General Options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-c'</SAMP>
-<DD>Generate an object file.
-<P>
-
-<DT><SAMP>`-o outfile'</SAMP>
-<DD>Put object file, executable, or dll into output file <TT>`outfile'</TT>.
-<P>
-
-<DT><SAMP>`-run source [args...]'</SAMP>
-<DD>Compile file <VAR>source</VAR> and run it with the command line arguments
-<VAR>args</VAR>. In order to be able to give more than one argument to a
-script, several TCC options can be given <EM>after</EM> the
-<SAMP>`-run'</SAMP> option, separated by spaces:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
-</pre></td></tr></table>In a script, it gives the following header:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
-</pre></td></tr></table><P>
-
-<DT><SAMP>`-v'</SAMP>
-<DD>Display TCC version.
-<P>
-
-<DT><SAMP>`-vv'</SAMP>
-<DD>Show included files. As sole argument, print search dirs. -vvv shows tries too.
-<P>
-
-<DT><SAMP>`-bench'</SAMP>
-<DD>Display compilation statistics.
-<P>
-
-</DL>
-<P>
-
-Preprocessor options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-Idir'</SAMP>
-<DD>Specify an additional include path. Include paths are searched in the
-order they are specified.
-<P>
-
-System include paths are always searched after. The default system
-include paths are: <TT>`/usr/local/include'</TT>, <TT>`/usr/include'</TT>
-and <TT>`PREFIX/lib/tcc/include'</TT>. (<TT>`PREFIX'</TT> is usually
-<TT>`/usr'</TT> or <TT>`/usr/local'</TT>).
-</P><P>
-
-<DT><SAMP>`-Dsym[=val]'</SAMP>
-<DD>Define preprocessor symbol <SAMP>`sym'</SAMP> to
-val. If val is not present, its value is <SAMP>`1'</SAMP>. Function-like macros can
-also be defined: <SAMP>`-DF(a)=a+1'</SAMP>
-<P>
-
-<DT><SAMP>`-Usym'</SAMP>
-<DD>Undefine preprocessor symbol <SAMP>`sym'</SAMP>.
-<P>
-
-<DT><SAMP>`-E'</SAMP>
-<DD>Preprocess only, to stdout or file (with -o).
-<P>
-
-</DL>
-<P>
-
-Compilation flags:
-</P><P>
-
-Note: each of the following options has a negative form beginning with
-<SAMP>`-fno-'</SAMP>.
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-funsigned-char'</SAMP>
-<DD>Let the <CODE>char</CODE> type be unsigned.
-<P>
-
-<DT><SAMP>`-fsigned-char'</SAMP>
-<DD>Let the <CODE>char</CODE> type be signed.
-<P>
-
-<DT><SAMP>`-fno-common'</SAMP>
-<DD>Do not generate common symbols for uninitialized data.
-<P>
-
-<DT><SAMP>`-fleading-underscore'</SAMP>
-<DD>Add a leading underscore at the beginning of each C symbol.
-<P>
-
-<DT><SAMP>`-fms-extensions'</SAMP>
-<DD>Allow a MS C compiler extensions to the language. Currently this
-assumes a nested named structure declaration without an identifier
-behaves like an unnamed one.
-<P>
-
-<DT><SAMP>`-fdollars-in-identifiers'</SAMP>
-<DD>Allow dollar signs in identifiers
-<P>
-
-</DL>
-<P>
-
-Warning options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-w'</SAMP>
-<DD>Disable all warnings.
-<P>
-
-</DL>
-<P>
-
-Note: each of the following warning options has a negative form beginning with
-<SAMP>`-Wno-'</SAMP>.
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-Wimplicit-function-declaration'</SAMP>
-<DD>Warn about implicit function declaration.
-<P>
-
-<DT><SAMP>`-Wunsupported'</SAMP>
-<DD>Warn about unsupported GCC features that are ignored by TCC.
-<P>
-
-<DT><SAMP>`-Wwrite-strings'</SAMP>
-<DD>Make string constants be of type <CODE>const char *</CODE> instead of <CODE>char
-*</CODE>.
-<P>
-
-<DT><SAMP>`-Werror'</SAMP>
-<DD>Abort compilation if warnings are issued.
-<P>
-
-<DT><SAMP>`-Wall'</SAMP>
-<DD>Activate all warnings, except <SAMP>`-Werror'</SAMP>, <SAMP>`-Wunusupported'</SAMP> and
-<SAMP>`-Wwrite-strings'</SAMP>.
-<P>
-
-</DL>
-<P>
-
-Linker options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-Ldir'</SAMP>
-<DD>Specify an additional static library path for the <SAMP>`-l'</SAMP> option. The
-default library paths are <TT>`/usr/local/lib'</TT>, <TT>`/usr/lib'</TT> and <TT>`/lib'</TT>.
-<P>
-
-<DT><SAMP>`-lxxx'</SAMP>
-<DD>Link your program with dynamic library libxxx.so or static library
-libxxx.a. The library is searched in the paths specified by the
-<SAMP>`-L'</SAMP> option and <CODE>LIBRARY_PATH</CODE> variable.
-<P>
-
-<DT><SAMP>`-Bdir'</SAMP>
-<DD>Set the path where the tcc internal libraries (and include files) can be
-found (default is <TT>`PREFIX/lib/tcc'</TT>).
-<P>
-
-<DT><SAMP>`-shared'</SAMP>
-<DD>Generate a shared library instead of an executable.
-<P>
-
-<DT><SAMP>`-soname name'</SAMP>
-<DD>set name for shared library to be used at runtime
-<P>
-
-<DT><SAMP>`-static'</SAMP>
-<DD>Generate a statically linked executable (default is a shared linked
-executable).
-<P>
-
-<DT><SAMP>`-rdynamic'</SAMP>
-<DD>Export global symbols to the dynamic linker. It is useful when a library
-opened with <CODE>dlopen()</CODE> needs to access executable symbols.
-<P>
-
-<DT><SAMP>`-r'</SAMP>
-<DD>Generate an object file combining all input files.
-<P>
-
-<DT><SAMP>`-Wl,-rpath=path'</SAMP>
-<DD>Put custom search path for dynamic libraries into executable.
-<P>
-
-<DT><SAMP>`-Wl,--enable-new-dtags'</SAMP>
-<DD>When putting a custom search path for dynamic libraries into the executable,
-create the new ELF dynamic tag DT_RUNPATH instead of the old legacy DT_RPATH.
-<P>
-
-<DT><SAMP>`-Wl,--oformat=fmt'</SAMP>
-<DD>Use <VAR>fmt</VAR> as output format. The supported output formats are:
-<DL COMPACT>
-<DT><CODE>elf32-i386</CODE>
-<DD>ELF output format (default)
-<DT><CODE>binary</CODE>
-<DD>Binary image (only for executable output)
-<DT><CODE>coff</CODE>
-<DD>COFF output format (only for executable output for TMS320C67xx target)
-</DL>
-<P>
-
-<DT><SAMP>`-Wl,-subsystem=console/gui/wince/...'</SAMP>
-<DD>Set type for PE (Windows) executables.
-<P>
-
-<DT><SAMP>`-Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#]'</SAMP>
-<DD>Modify executable layout.
-<P>
-
-<DT><SAMP>`-Wl,-Bsymbolic'</SAMP>
-<DD>Set DT_SYMBOLIC tag.
-<P>
-
-<DT><SAMP>`-Wl,-(no-)whole-archive'</SAMP>
-<DD>Turn on/off linking of all objects in archives.
-<P>
-
-</DL>
-<P>
-
-Debugger options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-g'</SAMP>
-<DD>Generate run time debug information so that you get clear run time
-error messages: <CODE> test.c:68: in function 'test5()': dereferencing
-invalid pointer</CODE> instead of the laconic <CODE>Segmentation
-fault</CODE>.
-<P>
-
-<DT><SAMP>`-b'</SAMP>
-<DD>Generate additional support code to check
-memory allocations and array/pointer bounds. <SAMP>`-g'</SAMP> is implied. Note
-that the generated code is slower and bigger in this case.
-<P>
-
-Note: <SAMP>`-b'</SAMP> is only available on i386 when using libtcc for the moment.
-</P><P>
-
-<DT><SAMP>`-bt N'</SAMP>
-<DD>Display N callers in stack traces. This is useful with <SAMP>`-g'</SAMP> or
-<SAMP>`-b'</SAMP>.
-<P>
-
-</DL>
-<P>
-
-Misc options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-MD'</SAMP>
-<DD>Generate makefile fragment with dependencies.
-<P>
-
-<DT><SAMP>`-MF depfile'</SAMP>
-<DD>Use <TT>`depfile'</TT> as output for -MD.
-<P>
-
-<DT><SAMP>`-print-search-dirs'</SAMP>
-<DD>Print the configured installation directory and a list of library
-and include directories tcc will search.
-<P>
-
-<DT><SAMP>`-dumpversion'</SAMP>
-<DD>Print version.
-<P>
-
-</DL>
-<P>
-
-Target specific options:
-</P><P>
-
-<DL COMPACT>
-<DT><SAMP>`-mms-bitfields'</SAMP>
-<DD>Use an algorithm for bitfield alignment consistent with MSVC. Default is
-gcc's algorithm.
-<P>
-
-<DT><SAMP>`-mfloat-abi (ARM only)'</SAMP>
-<DD>Select the float ABI. Possible values: <CODE>softfp</CODE> and <CODE>hard</CODE>
-<P>
-
-<DT><SAMP>`-mno-sse'</SAMP>
-<DD>Do not use sse registers on x86_64
-<P>
-
-<DT><SAMP>`-m32, -m64'</SAMP>
-<DD>Pass command line to the i386/x86_64 cross compiler.
-<P>
-
-</DL>
-<P>
-
-Note: GCC options <SAMP>`-Ox'</SAMP>, <SAMP>`-fx'</SAMP> and <SAMP>`-mx'</SAMP> are
-ignored.
-</P><P>
-
-Environment variables that affect how tcc operates.
-</P><P>
-
-<DL COMPACT>
-
-<DT><SAMP>`CPATH'</SAMP>
-<DD><DT><SAMP>`C_INCLUDE_PATH'</SAMP>
-<DD>A colon-separated list of directories searched for include files,
-directories given with <SAMP>`-I'</SAMP> are searched first.
-<P>
-
-<DT><SAMP>`LIBRARY_PATH'</SAMP>
-<DD>A colon-separated list of directories searched for libraries for the
-<SAMP>`-l'</SAMP> option, directories given with <SAMP>`-L'</SAMP> are searched first.
-<P>
-
-</DL>
-<P>
-
-<A NAME="Clang"></A>
-<HR SIZE="6">
-<A NAME="SEC5"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC4"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC6"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 3. C language support </H1>
-<!--docid::SEC5::-->
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC6"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC7"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 3.1 ANSI C </H2>
-<!--docid::SEC6::-->
-<P>
-
-TCC implements all the ANSI C standard, including structure bit fields
-and floating point numbers (<CODE>long double</CODE>, <CODE>double</CODE>, and
-<CODE>float</CODE> fully supported).
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC7"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC6"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC8"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC8"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 3.2 ISOC99 extensions </H2>
-<!--docid::SEC7::-->
-<P>
-
-TCC implements many features of the new C standard: ISO C99. Currently
-missing items are: complex and imaginary numbers.
-</P><P>
-
-Currently implemented ISOC99 features:
-</P><P>
-
-<UL>
-
-<LI>variable length arrays.
-<P>
-
-<LI>64 bit <CODE>long long</CODE> types are fully supported.
-<P>
-
-<LI>The boolean type <CODE>_Bool</CODE> is supported.
-<P>
-
-<LI><CODE>__func__</CODE> is a string variable containing the current
-function name.
-<P>
-
-<LI>Variadic macros: <CODE>__VA_ARGS__</CODE> can be used for
- function-like macros:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)
-</pre></td></tr></table><P>
-
-<CODE>dprintf</CODE> can then be used with a variable number of parameters.
-</P><P>
-
-<LI>Declarations can appear anywhere in a block (as in C++).
-<P>
-
-<LI>Array and struct/union elements can be initialized in any order by
- using designators:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 };
-
- int tab[10] = { 1, 2, [5] = 5, [9] = 9};
-</pre></td></tr></table>
-<LI>Compound initializers are supported:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> int *p = (int []){ 1, 2, 3 };
-</pre></td></tr></table>to initialize a pointer pointing to an initialized array. The same
-works for structures and strings.
-<P>
-
-<LI>Hexadecimal floating point constants are supported:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> double d = 0x1234p10;
-</pre></td></tr></table><P>
-
-is the same as writing
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> double d = 4771840.0;
-</pre></td></tr></table></P><P>
-
-<LI><CODE>inline</CODE> keyword is ignored.
-<P>
-
-<LI><CODE>restrict</CODE> keyword is ignored.
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC8"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC7"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC9"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC9"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 3.3 GNU C extensions </H2>
-<!--docid::SEC8::-->
-<P>
-
-TCC implements some GNU C extensions:
-</P><P>
-
-<UL>
-
-<LI>array designators can be used without '=':
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> int a[10] = { [0] 1, [5] 2, 3, 4 };
-</pre></td></tr></table><P>
-
-<LI>Structure field designators can be a label:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> struct { int x, y; } st = { x: 1, y: 1};
-</pre></td></tr></table>instead of
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> struct { int x, y; } st = { .x = 1, .y = 1};
-</pre></td></tr></table><P>
-
-<LI><CODE>\e</CODE> is ASCII character 27.
-<P>
-
-<LI>case ranges : ranges can be used in <CODE>case</CODE>s:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> switch(a) {
- case 1 <small>...</small> 9:
- printf("range 1 to 9\n");
- break;
- default:
- printf("unexpected\n");
- break;
- }
-</pre></td></tr></table><P>
-
-<A NAME="IDX1"></A>
-<A NAME="IDX2"></A>
-<A NAME="IDX3"></A>
-<A NAME="IDX4"></A>
-<A NAME="IDX5"></A>
-<A NAME="IDX6"></A>
-<A NAME="IDX7"></A>
-<A NAME="IDX8"></A>
-</P><P>
-
-<LI>The keyword <CODE>__attribute__</CODE> is handled to specify variable or
-function attributes. The following attributes are supported:
-<UL>
-
-<LI><CODE>aligned(n)</CODE>: align a variable or a structure field to n bytes
-(must be a power of two).
-<P>
-
-<LI><CODE>packed</CODE>: force alignment of a variable or a structure field to
- 1.
-<P>
-
-<LI><CODE>section(name)</CODE>: generate function or data in assembly section
-name (name is a string containing the section name) instead of the default
-section.
-<P>
-
-<LI><CODE>unused</CODE>: specify that the variable or the function is unused.
-<P>
-
-<LI><CODE>cdecl</CODE>: use standard C calling convention (default).
-<P>
-
-<LI><CODE>stdcall</CODE>: use Pascal-like calling convention.
-<P>
-
-<LI><CODE>regparm(n)</CODE>: use fast i386 calling convention. <VAR>n</VAR> must be
-between 1 and 3. The first <VAR>n</VAR> function parameters are respectively put in
-registers <CODE>%eax</CODE>, <CODE>%edx</CODE> and <CODE>%ecx</CODE>.
-<P>
-
-<LI><CODE>dllexport</CODE>: export function from dll/executable (win32 only)
-<P>
-
-</UL>
-<P>
-
-Here are some examples:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> int a __attribute__ ((aligned(8), section(".mysection")));
-</pre></td></tr></table></P><P>
-
-align variable <CODE>a</CODE> to 8 bytes and put it in section <CODE>.mysection</CODE>.
-</P><P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> int my_add(int a, int b) __attribute__ ((section(".mycodesection")))
- {
- return a + b;
- }
-</pre></td></tr></table></P><P>
-
-generate function <CODE>my_add</CODE> in section <CODE>.mycodesection</CODE>.
-</P><P>
-
-<LI>GNU style variadic macros:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> #define dprintf(fmt, args<small>...</small>) printf(fmt, ## args)
-
- dprintf("no arg\n");
- dprintf("one arg %d\n", 1);
-</pre></td></tr></table><P>
-
-<LI><CODE>__FUNCTION__</CODE> is interpreted as C99 <CODE>__func__</CODE>
-(so it has not exactly the same semantics as string literal GNUC
-where it is a string literal).
-<P>
-
-<LI>The <CODE>__alignof__</CODE> keyword can be used as <CODE>sizeof</CODE>
-to get the alignment of a type or an expression.
-<P>
-
-<LI>The <CODE>typeof(x)</CODE> returns the type of <CODE>x</CODE>.
-<CODE>x</CODE> is an expression or a type.
-<P>
-
-<LI>Computed gotos: <CODE>&#38;&#38;label</CODE> returns a pointer of type
-<CODE>void *</CODE> on the goto label <CODE>label</CODE>. <CODE>goto *expr</CODE> can be
-used to jump on the pointer resulting from <CODE>expr</CODE>.
-<P>
-
-<LI>Inline assembly with asm instruction:
-<A NAME="IDX9"></A>
-<A NAME="IDX10"></A>
-<A NAME="IDX11"></A>
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>static inline void * my_memcpy(void * to, const void * from, size_t n)
-{
-int d0, d1, d2;
-__asm__ __volatile__(
- "rep ; movsl\n\t"
- "testb $2,%b4\n\t"
- "je 1f\n\t"
- "movsw\n"
- "1:\ttestb $1,%b4\n\t"
- "je 2f\n\t"
- "movsb\n"
- "2:"
- : "=&c" (d0), "=&#38;D" (d1), "=&#38;S" (d2)
- :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
- : "memory");
-return (to);
-}
-</pre></td></tr></table><P>
-
-<A NAME="IDX12"></A>
-TCC includes its own x86 inline assembler with a <CODE>gas</CODE>-like (GNU
-assembler) syntax. No intermediate files are generated. GCC 3.x named
-operands are supported.
-</P><P>
-
-<LI><CODE>__builtin_types_compatible_p()</CODE> and <CODE>__builtin_constant_p()</CODE>
-are supported.
-<P>
-
-<LI><CODE>#pragma pack</CODE> is supported for win32 compatibility.
-<P>
-
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC9"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC8"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 3.4 TinyCC extensions </H2>
-<!--docid::SEC9::-->
-<P>
-
-<UL>
-
-<LI><CODE>__TINYC__</CODE> is a predefined macro to indicate that you use TCC.
-<P>
-
-<LI><CODE>#!</CODE> at the start of a line is ignored to allow scripting.
-<P>
-
-<LI>Binary digits can be entered (<CODE>0b101</CODE> instead of
-<CODE>5</CODE>).
-<P>
-
-<LI><CODE>__BOUNDS_CHECKING_ON</CODE> is defined if bound checking is activated.
-<P>
-
-</UL>
-<P>
-
-<A NAME="asm"></A>
-<HR SIZE="6">
-<A NAME="SEC10"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC9"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC11"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 4. TinyCC Assembler </H1>
-<!--docid::SEC10::-->
-<P>
-
-Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
-assembler supports a gas-like syntax (GNU assembler). You can
-deactivate assembler support if you want a smaller TinyCC executable
-(the C compiler does not rely on the assembler).
-</P><P>
-
-TinyCC Assembler is used to handle files with <TT>`.S'</TT> (C
-preprocessed assembler) and <TT>`.s'</TT> extensions. It is also used to
-handle the GNU inline assembler with the <CODE>asm</CODE> keyword.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC11"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC12"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 4.1 Syntax </H2>
-<!--docid::SEC11::-->
-<P>
-
-TinyCC Assembler supports most of the gas syntax. The tokens are the
-same as C.
-</P><P>
-
-<UL>
-
-<LI>C and C++ comments are supported.
-<P>
-
-<LI>Identifiers are the same as C, so you cannot use '.' or '$'.
-<P>
-
-<LI>Only 32 bit integer numbers are supported.
-<P>
-
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC12"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC11"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC13"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC13"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 4.2 Expressions </H2>
-<!--docid::SEC12::-->
-<P>
-
-<UL>
-
-<LI>Integers in decimal, octal and hexa are supported.
-<P>
-
-<LI>Unary operators: +, -, ~.
-<P>
-
-<LI>Binary operators in decreasing priority order:
-<P>
-
-<OL>
-<LI>*, /, %
-<LI>&#38;, |, ^
-<LI>+, -
-</OL>
-<P>
-
-<LI>A value is either an absolute number or a label plus an offset.
-All operators accept absolute values except '+' and '-'. '+' or '-' can be
-used to add an offset to a label. '-' supports two labels only if they
-are the same or if they are both defined and in the same section.
-<P>
-
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC13"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC12"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC14"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC14"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 4.3 Labels </H2>
-<!--docid::SEC13::-->
-<P>
-
-<UL>
-
-<LI>All labels are considered as local, except undefined ones.
-<P>
-
-<LI>Numeric labels can be used as local <CODE>gas</CODE>-like labels.
-They can be defined several times in the same source. Use 'b'
-(backward) or 'f' (forward) as suffix to reference them:
-<P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre> 1:
- jmp 1b /* jump to '1' label before */
- jmp 1f /* jump to '1' label after */
- 1:
-</pre></td></tr></table></P><P>
-
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC14"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC13"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC15"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC15"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 4.4 Directives </H2>
-<!--docid::SEC14::-->
-<P>
-
-All directives are preceded by a '.'. The following directives are
-supported:
-</P><P>
-
-<UL>
-<LI>.align n[,value]
-<LI>.skip n[,value]
-<LI>.space n[,value]
-<LI>.byte value1[,...]
-<LI>.word value1[,...]
-<LI>.short value1[,...]
-<LI>.int value1[,...]
-<LI>.long value1[,...]
-<LI>.quad immediate_value1[,...]
-<LI>.globl symbol
-<LI>.global symbol
-<LI>.section section
-<LI>.text
-<LI>.data
-<LI>.bss
-<LI>.fill repeat[,size[,value]]
-<LI>.org n
-<LI>.previous
-<LI>.string string[,...]
-<LI>.asciz string[,...]
-<LI>.ascii string[,...]
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC15"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC14"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 4.5 X86 Assembler </H2>
-<!--docid::SEC15::-->
-<P>
-
-All X86 opcodes are supported. Only ATT syntax is supported (source
-then destination operand order). If no size suffix is given, TinyCC
-tries to guess it from the operand sizes.
-</P><P>
-
-Currently, MMX opcodes are supported but not SSE ones.
-</P><P>
-
-<A NAME="linker"></A>
-<HR SIZE="6">
-<A NAME="SEC16"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC15"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC17"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 5. TinyCC Linker </H1>
-<!--docid::SEC16::-->
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC17"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC18"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 5.1 ELF file generation </H2>
-<!--docid::SEC17::-->
-<P>
-
-TCC can directly output relocatable ELF files (object files),
-executable ELF files and dynamic ELF libraries without relying on an
-external linker.
-</P><P>
-
-Dynamic ELF libraries can be output but the C compiler does not generate
-position independent code (PIC). It means that the dynamic library
-code generated by TCC cannot be factorized among processes yet.
-</P><P>
-
-TCC linker eliminates unreferenced object code in libraries. A single pass is
-done on the object and library list, so the order in which object files and
-libraries are specified is important (same constraint as GNU ld). No grouping
-options (<SAMP>`--start-group'</SAMP> and <SAMP>`--end-group'</SAMP>) are supported.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC18"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC17"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC19"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC19"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 5.2 ELF file loader </H2>
-<!--docid::SEC18::-->
-<P>
-
-TCC can load ELF object files, archives (.a files) and dynamic
-libraries (.so).
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC19"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC18"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC20"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC20"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 5.3 PE-i386 file generation </H2>
-<!--docid::SEC19::-->
-<P>
-
-TCC for Windows supports the native Win32 executable file format (PE-i386). It
-generates EXE files (console and gui) and DLL files.
-</P><P>
-
-For usage on Windows, see also tcc-win32.txt.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC20"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC19"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 5.4 GNU Linker Scripts </H2>
-<!--docid::SEC20::-->
-<P>
-
-Because on many Linux systems some dynamic libraries (such as
-<TT>`/usr/lib/libc.so'</TT>) are in fact GNU ld link scripts (horrible!),
-the TCC linker also supports a subset of GNU ld scripts.
-</P><P>
-
-The <CODE>GROUP</CODE> and <CODE>FILE</CODE> commands are supported. <CODE>OUTPUT_FORMAT</CODE>
-and <CODE>TARGET</CODE> are ignored.
-</P><P>
-
-Example from <TT>`/usr/lib/libc.so'</TT>:
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>/* GNU ld script
- Use the shared library, but some functions are only in
- the static library, so try that secondarily. */
-GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
-</pre></td></tr></table></P><P>
-
-<A NAME="Bounds"></A>
-<HR SIZE="6">
-<A NAME="SEC21"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC20"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC22"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC22"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC22"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 6. TinyCC Memory and Bound checks </H1>
-<!--docid::SEC21::-->
-<P>
-
-This feature is activated with the <SAMP>`-b'</SAMP> (see section <A HREF="tcc-doc.html#SEC2">2. Command line invocation</A>).
-</P><P>
-
-Note that pointer size is <EM>unchanged</EM> and that code generated
-with bound checks is <EM>fully compatible</EM> with unchecked
-code. When a pointer comes from unchecked code, it is assumed to be
-valid. Even very obscure C code with casts should work correctly.
-</P><P>
-
-For more information about the ideas behind this method, see
-<A HREF="http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html">http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html</A>.
-</P><P>
-
-Here are some examples of caught errors:
-</P><P>
-
-<DL COMPACT>
-
-<DT>Invalid range with standard string function:
-<DD><TABLE><tr><td>&nbsp;</td><td class=example><pre>{
- char tab[10];
- memset(tab, 0, 11);
-}
-</pre></td></tr></table><P>
-
-<DT>Out of bounds-error in global or local arrays:
-<DD><TABLE><tr><td>&nbsp;</td><td class=example><pre>{
- int tab[10];
- for(i=0;i&#60;11;i++) {
- sum += tab[i];
- }
-}
-</pre></td></tr></table><P>
-
-<DT>Out of bounds-error in malloc'ed data:
-<DD><TABLE><tr><td>&nbsp;</td><td class=example><pre>{
- int *tab;
- tab = malloc(20 * sizeof(int));
- for(i=0;i&#60;21;i++) {
- sum += tab4[i];
- }
- free(tab);
-}
-</pre></td></tr></table><P>
-
-<DT>Access of freed memory:
-<DD><TABLE><tr><td>&nbsp;</td><td class=example><pre>{
- int *tab;
- tab = malloc(20 * sizeof(int));
- free(tab);
- for(i=0;i&#60;20;i++) {
- sum += tab4[i];
- }
-}
-</pre></td></tr></table><P>
-
-<DT>Double free:
-<DD><TABLE><tr><td>&nbsp;</td><td class=example><pre>{
- int *tab;
- tab = malloc(20 * sizeof(int));
- free(tab);
- free(tab);
-}
-</pre></td></tr></table><P>
-
-</DL>
-<P>
-
-<A NAME="Libtcc"></A>
-<HR SIZE="6">
-<A NAME="SEC22"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 7. The <CODE>libtcc</CODE> library </H1>
-<!--docid::SEC22::-->
-<P>
-
-The <CODE>libtcc</CODE> library enables you to use TCC as a backend for
-dynamic code generation.
-</P><P>
-
-Read the <TT>`libtcc.h'</TT> to have an overview of the API. Read
-<TT>`libtcc_test.c'</TT> to have a very simple example.
-</P><P>
-
-The idea consists in giving a C string containing the program you want
-to compile directly to <CODE>libtcc</CODE>. Then you can access to any global
-symbol (function or variable) defined.
-</P><P>
-
-<A NAME="devel"></A>
-<HR SIZE="6">
-<A NAME="SEC23"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC22"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC24"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[ &lt;&lt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> 8. Developer's guide </H1>
-<!--docid::SEC23::-->
-<P>
-
-This chapter gives some hints to understand how TCC works. You can skip
-it if you do not intend to modify the TCC code.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC24"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC25"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[ &lt;&lt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.1 File reading </H2>
-<!--docid::SEC24::-->
-<P>
-
-The <CODE>BufferedFile</CODE> structure contains the context needed to read a
-file, including the current line number. <CODE>tcc_open()</CODE> opens a new
-file and <CODE>tcc_close()</CODE> closes it. <CODE>inp()</CODE> returns the next
-character.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC25"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC24"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC26"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC26"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.2 Lexer </H2>
-<!--docid::SEC25::-->
-<P>
-
-<CODE>next()</CODE> reads the next token in the current
-file. <CODE>next_nomacro()</CODE> reads the next token without macro
-expansion.
-</P><P>
-
-<CODE>tok</CODE> contains the current token (see <CODE>TOK_xxx</CODE>)
-constants. Identifiers and keywords are also keywords. <CODE>tokc</CODE>
-contains additional infos about the token (for example a constant value
-if number or string token).
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC26"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC25"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC27"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC27"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.3 Parser </H2>
-<!--docid::SEC26::-->
-<P>
-
-The parser is hardcoded (yacc is not necessary). It does only one pass,
-except:
-</P><P>
-
-<UL>
-
-<LI>For initialized arrays with unknown size, a first pass
-is done to count the number of elements.
-<P>
-
-<LI>For architectures where arguments are evaluated in
-reverse order, a first pass is done to reverse the argument order.
-<P>
-
-</UL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC27"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC26"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC28"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC28"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.4 Types </H2>
-<!--docid::SEC27::-->
-<P>
-
-The types are stored in a single 'int' variable. It was chosen in the
-first stages of development when tcc was much simpler. Now, it may not
-be the best solution.
-</P><P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>#define VT_INT 0 /* integer type */
-#define VT_BYTE 1 /* signed byte type */
-#define VT_SHORT 2 /* short type */
-#define VT_VOID 3 /* void type */
-#define VT_PTR 4 /* pointer */
-#define VT_ENUM 5 /* enum definition */
-#define VT_FUNC 6 /* function type */
-#define VT_STRUCT 7 /* struct/union definition */
-#define VT_FLOAT 8 /* IEEE float */
-#define VT_DOUBLE 9 /* IEEE double */
-#define VT_LDOUBLE 10 /* IEEE long double */
-#define VT_BOOL 11 /* ISOC99 boolean type */
-#define VT_LLONG 12 /* 64 bit integer */
-#define VT_LONG 13 /* long integer (NEVER USED as type, only
- during parsing) */
-#define VT_BTYPE 0x000f /* mask for basic type */
-#define VT_UNSIGNED 0x0010 /* unsigned type */
-#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
-#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */
-#define VT_BITFIELD 0x0040 /* bitfield modifier */
-#define VT_CONSTANT 0x0800 /* const modifier */
-#define VT_VOLATILE 0x1000 /* volatile modifier */
-#define VT_DEFSIGN 0x2000 /* signed type */
-
-#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
-</pre></td></tr></table></P><P>
-
-When a reference to another type is needed (for pointers, functions and
-structures), the <CODE>32 - VT_STRUCT_SHIFT</CODE> high order bits are used to
-store an identifier reference.
-</P><P>
-
-The <CODE>VT_UNSIGNED</CODE> flag can be set for chars, shorts, ints and long
-longs.
-</P><P>
-
-Arrays are considered as pointers <CODE>VT_PTR</CODE> with the flag
-<CODE>VT_ARRAY</CODE> set. Variable length arrays are considered as special
-arrays and have flag <CODE>VT_VLA</CODE> set instead of <CODE>VT_ARRAY</CODE>.
-</P><P>
-
-The <CODE>VT_BITFIELD</CODE> flag can be set for chars, shorts, ints and long
-longs. If it is set, then the bitfield position is stored from bits
-VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored
-from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.
-</P><P>
-
-<CODE>VT_LONG</CODE> is never used except during parsing.
-</P><P>
-
-During parsing, the storage of an object is also stored in the type
-integer:
-</P><P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>#define VT_EXTERN 0x00000080 /* extern definition */
-#define VT_STATIC 0x00000100 /* static variable */
-#define VT_TYPEDEF 0x00000200 /* typedef definition */
-#define VT_INLINE 0x00000400 /* inline definition */
-#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */
-#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
-#define VT_WEAK 0x00010000 /* win32: data exported from dll */
-</pre></td></tr></table></P><P>
-
-<HR SIZE="6">
-<A NAME="SEC28"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC27"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC29"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC29"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.5 Symbols </H2>
-<!--docid::SEC28::-->
-<P>
-
-All symbols are stored in hashed symbol stacks. Each symbol stack
-contains <CODE>Sym</CODE> structures.
-</P><P>
-
-<CODE>Sym.v</CODE> contains the symbol name (remember
-an identifier is also a token, so a string is never necessary to store
-it). <CODE>Sym.t</CODE> gives the type of the symbol. <CODE>Sym.r</CODE> is usually
-the register in which the corresponding variable is stored. <CODE>Sym.c</CODE> is
-usually a constant associated to the symbol like its address for normal
-symbols, and the number of entries for symbols representing arrays.
-Variable length array types use <CODE>Sym.c</CODE> as a location on the stack
-which holds the runtime sizeof for the type.
-</P><P>
-
-Four main symbol stacks are defined:
-</P><P>
-
-<DL COMPACT>
-
-<DT><CODE>define_stack</CODE>
-<DD>for the macros (<CODE>#define</CODE>s).
-<P>
-
-<DT><CODE>global_stack</CODE>
-<DD>for the global variables, functions and types.
-<P>
-
-<DT><CODE>local_stack</CODE>
-<DD>for the local variables, functions and types.
-<P>
-
-<DT><CODE>global_label_stack</CODE>
-<DD>for the local labels (for <CODE>goto</CODE>).
-<P>
-
-<DT><CODE>label_stack</CODE>
-<DD>for GCC block local labels (see the <CODE>__label__</CODE> keyword).
-<P>
-
-</DL>
-<P>
-
-<CODE>sym_push()</CODE> is used to add a new symbol in the local symbol
-stack. If no local symbol stack is active, it is added in the global
-symbol stack.
-</P><P>
-
-<CODE>sym_pop(st,b)</CODE> pops symbols from the symbol stack <VAR>st</VAR> until
-the symbol <VAR>b</VAR> is on the top of stack. If <VAR>b</VAR> is NULL, the stack
-is emptied.
-</P><P>
-
-<CODE>sym_find(v)</CODE> return the symbol associated to the identifier
-<VAR>v</VAR>. The local stack is searched first from top to bottom, then the
-global stack.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC29"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC28"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.6 Sections </H2>
-<!--docid::SEC29::-->
-<P>
-
-The generated code and data are written in sections. The structure
-<CODE>Section</CODE> contains all the necessary information for a given
-section. <CODE>new_section()</CODE> creates a new section. ELF file semantics
-is assumed for each section.
-</P><P>
-
-The following sections are predefined:
-</P><P>
-
-<DL COMPACT>
-
-<DT><CODE>text_section</CODE>
-<DD>is the section containing the generated code. <VAR>ind</VAR> contains the
-current position in the code section.
-<P>
-
-<DT><CODE>data_section</CODE>
-<DD>contains initialized data
-<P>
-
-<DT><CODE>bss_section</CODE>
-<DD>contains uninitialized data
-<P>
-
-<DT><CODE>bounds_section</CODE>
-<DD><DT><CODE>lbounds_section</CODE>
-<DD>are used when bound checking is activated
-<P>
-
-<DT><CODE>stab_section</CODE>
-<DD><DT><CODE>stabstr_section</CODE>
-<DD>are used when debugging is active to store debug information
-<P>
-
-<DT><CODE>symtab_section</CODE>
-<DD><DT><CODE>strtab_section</CODE>
-<DD>contain the exported symbols (currently only used for debugging).
-<P>
-
-</DL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC30"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC29"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC31"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.7 Code generation </H2>
-<!--docid::SEC30::-->
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC31"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC32"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H3> 8.7.1 Introduction </H3>
-<!--docid::SEC31::-->
-<P>
-
-The TCC code generator directly generates linked binary code in one
-pass. It is rather unusual these days (see gcc for example which
-generates text assembly), but it can be very fast and surprisingly
-little complicated.
-</P><P>
-
-The TCC code generator is register based. Optimization is only done at
-the expression level. No intermediate representation of expression is
-kept except the current values stored in the <EM>value stack</EM>.
-</P><P>
-
-On x86, three temporary registers are used. When more registers are
-needed, one register is spilled into a new temporary variable on the stack.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC32"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC31"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC33"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC33"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H3> 8.7.2 The value stack </H3>
-<!--docid::SEC32::-->
-<P>
-
-When an expression is parsed, its value is pushed on the value stack
-(<VAR>vstack</VAR>). The top of the value stack is <VAR>vtop</VAR>. Each value
-stack entry is the structure <CODE>SValue</CODE>.
-</P><P>
-
-<CODE>SValue.t</CODE> is the type. <CODE>SValue.r</CODE> indicates how the value is
-currently stored in the generated code. It is usually a CPU register
-index (<CODE>REG_xxx</CODE> constants), but additional values and flags are
-defined:
-</P><P>
-
-<TABLE><tr><td>&nbsp;</td><td class=example><pre>#define VT_CONST 0x00f0
-#define VT_LLOCAL 0x00f1
-#define VT_LOCAL 0x00f2
-#define VT_CMP 0x00f3
-#define VT_JMP 0x00f4
-#define VT_JMPI 0x00f5
-#define VT_LVAL 0x0100
-#define VT_SYM 0x0200
-#define VT_MUSTCAST 0x0400
-#define VT_MUSTBOUND 0x0800
-#define VT_BOUNDED 0x8000
-#define VT_LVAL_BYTE 0x1000
-#define VT_LVAL_SHORT 0x2000
-#define VT_LVAL_UNSIGNED 0x4000
-#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
-</pre></td></tr></table></P><P>
-
-<DL COMPACT>
-
-<DT><CODE>VT_CONST</CODE>
-<DD>indicates that the value is a constant. It is stored in the union
-<CODE>SValue.c</CODE>, depending on its type.
-<P>
-
-<DT><CODE>VT_LOCAL</CODE>
-<DD>indicates a local variable pointer at offset <CODE>SValue.c.i</CODE> in the
-stack.
-<P>
-
-<DT><CODE>VT_CMP</CODE>
-<DD>indicates that the value is actually stored in the CPU flags (i.e. the
-value is the consequence of a test). The value is either 0 or 1. The
-actual CPU flags used is indicated in <CODE>SValue.c.i</CODE>.
-<P>
-
-If any code is generated which destroys the CPU flags, this value MUST be
-put in a normal register.
-</P><P>
-
-<DT><CODE>VT_JMP</CODE>
-<DD><DT><CODE>VT_JMPI</CODE>
-<DD>indicates that the value is the consequence of a conditional jump. For VT_JMP,
-it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted.
-<P>
-
-These values are used to compile the <CODE>||</CODE> and <CODE>&#38;&#38;</CODE> logical
-operators.
-</P><P>
-
-If any code is generated, this value MUST be put in a normal
-register. Otherwise, the generated code won't be executed if the jump is
-taken.
-</P><P>
-
-<DT><CODE>VT_LVAL</CODE>
-<DD>is a flag indicating that the value is actually an lvalue (left value of
-an assignment). It means that the value stored is actually a pointer to
-the wanted value.
-<P>
-
-Understanding the use <CODE>VT_LVAL</CODE> is very important if you want to
-understand how TCC works.
-</P><P>
-
-<DT><CODE>VT_LVAL_BYTE</CODE>
-<DD><DT><CODE>VT_LVAL_SHORT</CODE>
-<DD><DT><CODE>VT_LVAL_UNSIGNED</CODE>
-<DD>if the lvalue has an integer type, then these flags give its real
-type. The type alone is not enough in case of cast optimisations.
-<P>
-
-<DT><CODE>VT_LLOCAL</CODE>
-<DD>is a saved lvalue on the stack. <CODE>VT_LVAL</CODE> must also be set with
-<CODE>VT_LLOCAL</CODE>. <CODE>VT_LLOCAL</CODE> can arise when a <CODE>VT_LVAL</CODE> in
-a register has to be saved to the stack, or it can come from an
-architecture-specific calling convention.
-<P>
-
-<DT><CODE>VT_MUSTCAST</CODE>
-<DD>indicates that a cast to the value type must be performed if the value
-is used (lazy casting).
-<P>
-
-<DT><CODE>VT_SYM</CODE>
-<DD>indicates that the symbol <CODE>SValue.sym</CODE> must be added to the constant.
-<P>
-
-<DT><CODE>VT_MUSTBOUND</CODE>
-<DD><DT><CODE>VT_BOUNDED</CODE>
-<DD>are only used for optional bound checking.
-<P>
-
-</DL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC33"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC32"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC34"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC34"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H3> 8.7.3 Manipulating the value stack </H3>
-<!--docid::SEC33::-->
-<P>
-
-<CODE>vsetc()</CODE> and <CODE>vset()</CODE> pushes a new value on the value
-stack. If the previous <VAR>vtop</VAR> was stored in a very unsafe place(for
-example in the CPU flags), then some code is generated to put the
-previous <VAR>vtop</VAR> in a safe storage.
-</P><P>
-
-<CODE>vpop()</CODE> pops <VAR>vtop</VAR>. In some cases, it also generates cleanup
-code (for example if stacked floating point registers are used as on
-x86).
-</P><P>
-
-The <CODE>gv(rc)</CODE> function generates code to evaluate <VAR>vtop</VAR> (the
-top value of the stack) into registers. <VAR>rc</VAR> selects in which
-register class the value should be put. <CODE>gv()</CODE> is the <EM>most
-important function</EM> of the code generator.
-</P><P>
-
-<CODE>gv2()</CODE> is the same as <CODE>gv()</CODE> but for the top two stack
-entries.
-</P><P>
-
-<HR SIZE="6">
-<A NAME="SEC34"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC33"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &lt;&lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &gt;&gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H3> 8.7.4 CPU dependent code generation </H3>
-<!--docid::SEC34::-->
-See the <TT>`i386-gen.c'</TT> file to have an example.
-<P>
-
-<DL COMPACT>
-
-<DT><CODE>load()</CODE>
-<DD>must generate the code needed to load a stack value into a register.
-<P>
-
-<DT><CODE>store()</CODE>
-<DD>must generate the code needed to store a register into a stack value
-lvalue.
-<P>
-
-<DT><CODE>gfunc_start()</CODE>
-<DD><DT><CODE>gfunc_param()</CODE>
-<DD><DT><CODE>gfunc_call()</CODE>
-<DD>should generate a function call
-<P>
-
-<DT><CODE>gfunc_prolog()</CODE>
-<DD><DT><CODE>gfunc_epilog()</CODE>
-<DD>should generate a function prolog/epilog.
-<P>
-
-<DT><CODE>gen_opi(op)</CODE>
-<DD>must generate the binary integer operation <VAR>op</VAR> on the two top
-entries of the stack which are guaranteed to contain integer types.
-<P>
-
-The result value should be put on the stack.
-</P><P>
-
-<DT><CODE>gen_opf(op)</CODE>
-<DD>same as <CODE>gen_opi()</CODE> for floating point operations. The two top
-entries of the stack are guaranteed to contain floating point values of
-same types.
-<P>
-
-<DT><CODE>gen_cvt_itof()</CODE>
-<DD>integer to floating point conversion.
-<P>
-
-<DT><CODE>gen_cvt_ftoi()</CODE>
-<DD>floating point to integer conversion.
-<P>
-
-<DT><CODE>gen_cvt_ftof()</CODE>
-<DD>floating point to floating point of different size conversion.
-<P>
-
-<DT><CODE>gen_bounded_ptr_add()</CODE>
-<DD><DT><CODE>gen_bounded_ptr_deref()</CODE>
-<DD>are only used for bounds checking.
-<P>
-
-</DL>
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC35"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC34"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36"> &gt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[ &lt;&lt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H2> 8.8 Optimizations done </H2>
-<!--docid::SEC35::-->
-Constant propagation is done for all operations. Multiplications and
-divisions are optimized to shifts when appropriate. Comparison
-operators are optimized by maintaining a special cache for the
-processor flags. &#38;&#38;, || and ! are optimized by maintaining a special
-'jump target' value. No other jump optimization is currently performed
-because it would require to store the code in a more abstract fashion.
-<P>
-
-<HR SIZE="6">
-<A NAME="SEC36"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> &lt; </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[ &lt;&lt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[ &gt;&gt; ]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT"> &nbsp; <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1> Concept Index </H1>
-<!--docid::SEC36::-->
-<table><tr><th valign=top>Jump to: &nbsp; </th><td><A HREF="tcc-doc.html#cp__" style="text-decoration:none"><b>_</b></A>
- &nbsp;
-<BR>
-<A HREF="tcc-doc.html#cp_A" style="text-decoration:none"><b>A</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_B" style="text-decoration:none"><b>B</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_C" style="text-decoration:none"><b>C</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_D" style="text-decoration:none"><b>D</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_E" style="text-decoration:none"><b>E</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_F" style="text-decoration:none"><b>F</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_G" style="text-decoration:none"><b>G</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_I" style="text-decoration:none"><b>I</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_J" style="text-decoration:none"><b>J</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_L" style="text-decoration:none"><b>L</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_M" style="text-decoration:none"><b>M</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_O" style="text-decoration:none"><b>O</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_P" style="text-decoration:none"><b>P</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_Q" style="text-decoration:none"><b>Q</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_R" style="text-decoration:none"><b>R</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_S" style="text-decoration:none"><b>S</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_T" style="text-decoration:none"><b>T</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_U" style="text-decoration:none"><b>U</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_V" style="text-decoration:none"><b>V</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_W" style="text-decoration:none"><b>W</b></A>
- &nbsp;
-</td></tr></table><br><P></P>
-<TABLE border=0>
-<TR><TD></TD><TH ALIGN=LEFT>Index Entry</TH><TH ALIGN=LEFT> Section</TH></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp__"></A>_</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX11">__asm__</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_A"></A>A</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">align directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX1">aligned attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">ascii directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">asciz directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC15">assembler</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC15">4.5 X86 Assembler</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">assembler directives</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX10">assembly, inline</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_B"></A>B</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC21">bound checks</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">bss directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">byte directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_C"></A>C</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">caching processor flags</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX5">cdecl attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC30">code generation</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC30">8.7 Code generation</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">comparison operators</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">constant propagation</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC34">CPU dependent</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC34">8.7.4 CPU dependent code generation</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_D"></A>D</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">data directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">directives, assembler</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX8">dllexport attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_E"></A>E</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC17">ELF</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC17">5.1 ELF file generation</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_F"></A>F</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">FILE, linker command</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">fill directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">flags, caching</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_G"></A>G</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX12">gas</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">global directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">globl directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">GROUP, linker command</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_I"></A>I</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX9">inline assembly</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">int directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_J"></A>J</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">jump optimization</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_L"></A>L</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC16">linker</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC16">5. TinyCC Linker</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">linker scripts</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">long directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_M"></A>M</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC21">memory checks</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_O"></A>O</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">optimizations</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">org directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">OUTPUT_FORMAT, linker command</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_P"></A>P</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX2">packed attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC19">PE-i386</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC19">5.3 PE-i386 file generation</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">previous directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_Q"></A>Q</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">quad directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_R"></A>R</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX7">regparm attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_S"></A>S</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">scripts, linker</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX3">section attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">section directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">short directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">skip directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">space directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX6">stdcall attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">strength reduction</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">string directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_T"></A>T</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">TARGET, linker command</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">text directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_U"></A>U</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#IDX4">unused attribute</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_V"></A>V</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC33">value stack</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC33">8.7.3 Manipulating the value stack</A></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC32">value stack, introduction</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC32">8.7.2 The value stack</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-<TR><TH><A NAME="cp_W"></A>W</TH><TD></TD><TD></TD></TR>
-<TR><TD></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">word directive</A></TD><TD valign=top><A HREF="tcc-doc.html#SEC14">4.4 Directives</A></TD></TR>
-<TR><TD COLSPAN=3> <HR></TD></TR>
-</TABLE><P></P><table><tr><th valign=top>Jump to: &nbsp; </th><td><A HREF="tcc-doc.html#cp__" style="text-decoration:none"><b>_</b></A>
- &nbsp;
-<BR>
-<A HREF="tcc-doc.html#cp_A" style="text-decoration:none"><b>A</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_B" style="text-decoration:none"><b>B</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_C" style="text-decoration:none"><b>C</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_D" style="text-decoration:none"><b>D</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_E" style="text-decoration:none"><b>E</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_F" style="text-decoration:none"><b>F</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_G" style="text-decoration:none"><b>G</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_I" style="text-decoration:none"><b>I</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_J" style="text-decoration:none"><b>J</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_L" style="text-decoration:none"><b>L</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_M" style="text-decoration:none"><b>M</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_O" style="text-decoration:none"><b>O</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_P" style="text-decoration:none"><b>P</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_Q" style="text-decoration:none"><b>Q</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_R" style="text-decoration:none"><b>R</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_S" style="text-decoration:none"><b>S</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_T" style="text-decoration:none"><b>T</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_U" style="text-decoration:none"><b>U</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_V" style="text-decoration:none"><b>V</b></A>
- &nbsp;
-<A HREF="tcc-doc.html#cp_W" style="text-decoration:none"><b>W</b></A>
- &nbsp;
-</td></tr></table><br><P>
-
-<HR SIZE="6">
-<A NAME="SEC_Contents"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1>Table of Contents</H1>
-<UL>
-<A NAME="TOC1" HREF="tcc-doc.html#SEC1">1. Introduction</A>
-<BR>
-<A NAME="TOC2" HREF="tcc-doc.html#SEC2">2. Command line invocation</A>
-<BR>
-<UL>
-<A NAME="TOC3" HREF="tcc-doc.html#SEC3">2.1 Quick start</A>
-<BR>
-<A NAME="TOC4" HREF="tcc-doc.html#SEC4">2.2 Option summary</A>
-<BR>
-</UL>
-<A NAME="TOC5" HREF="tcc-doc.html#SEC5">3. C language support</A>
-<BR>
-<UL>
-<A NAME="TOC6" HREF="tcc-doc.html#SEC6">3.1 ANSI C</A>
-<BR>
-<A NAME="TOC7" HREF="tcc-doc.html#SEC7">3.2 ISOC99 extensions</A>
-<BR>
-<A NAME="TOC8" HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A>
-<BR>
-<A NAME="TOC9" HREF="tcc-doc.html#SEC9">3.4 TinyCC extensions</A>
-<BR>
-</UL>
-<A NAME="TOC10" HREF="tcc-doc.html#SEC10">4. TinyCC Assembler</A>
-<BR>
-<UL>
-<A NAME="TOC11" HREF="tcc-doc.html#SEC11">4.1 Syntax</A>
-<BR>
-<A NAME="TOC12" HREF="tcc-doc.html#SEC12">4.2 Expressions</A>
-<BR>
-<A NAME="TOC13" HREF="tcc-doc.html#SEC13">4.3 Labels</A>
-<BR>
-<A NAME="TOC14" HREF="tcc-doc.html#SEC14">4.4 Directives</A>
-<BR>
-<A NAME="TOC15" HREF="tcc-doc.html#SEC15">4.5 X86 Assembler</A>
-<BR>
-</UL>
-<A NAME="TOC16" HREF="tcc-doc.html#SEC16">5. TinyCC Linker</A>
-<BR>
-<UL>
-<A NAME="TOC17" HREF="tcc-doc.html#SEC17">5.1 ELF file generation</A>
-<BR>
-<A NAME="TOC18" HREF="tcc-doc.html#SEC18">5.2 ELF file loader</A>
-<BR>
-<A NAME="TOC19" HREF="tcc-doc.html#SEC19">5.3 PE-i386 file generation</A>
-<BR>
-<A NAME="TOC20" HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A>
-<BR>
-</UL>
-<A NAME="TOC21" HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A>
-<BR>
-<A NAME="TOC22" HREF="tcc-doc.html#SEC22">7. The <CODE>libtcc</CODE> library</A>
-<BR>
-<A NAME="TOC23" HREF="tcc-doc.html#SEC23">8. Developer's guide</A>
-<BR>
-<UL>
-<A NAME="TOC24" HREF="tcc-doc.html#SEC24">8.1 File reading</A>
-<BR>
-<A NAME="TOC25" HREF="tcc-doc.html#SEC25">8.2 Lexer</A>
-<BR>
-<A NAME="TOC26" HREF="tcc-doc.html#SEC26">8.3 Parser</A>
-<BR>
-<A NAME="TOC27" HREF="tcc-doc.html#SEC27">8.4 Types</A>
-<BR>
-<A NAME="TOC28" HREF="tcc-doc.html#SEC28">8.5 Symbols</A>
-<BR>
-<A NAME="TOC29" HREF="tcc-doc.html#SEC29">8.6 Sections</A>
-<BR>
-<A NAME="TOC30" HREF="tcc-doc.html#SEC30">8.7 Code generation</A>
-<BR>
-<UL>
-<A NAME="TOC31" HREF="tcc-doc.html#SEC31">8.7.1 Introduction</A>
-<BR>
-<A NAME="TOC32" HREF="tcc-doc.html#SEC32">8.7.2 The value stack</A>
-<BR>
-<A NAME="TOC33" HREF="tcc-doc.html#SEC33">8.7.3 Manipulating the value stack</A>
-<BR>
-<A NAME="TOC34" HREF="tcc-doc.html#SEC34">8.7.4 CPU dependent code generation</A>
-<BR>
-</UL>
-<A NAME="TOC35" HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A>
-<BR>
-</UL>
-<A NAME="TOC36" HREF="tcc-doc.html#SEC36">Concept Index</A>
-<BR>
-</UL>
-<HR SIZE=1>
-<A NAME="SEC_OVERVIEW"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1>Short Table of Contents</H1>
-<BLOCKQUOTE>
-<A NAME="TOC1" HREF="tcc-doc.html#SEC1">1. Introduction</A>
-<BR>
-<A NAME="TOC2" HREF="tcc-doc.html#SEC2">2. Command line invocation</A>
-<BR>
-<A NAME="TOC5" HREF="tcc-doc.html#SEC5">3. C language support</A>
-<BR>
-<A NAME="TOC10" HREF="tcc-doc.html#SEC10">4. TinyCC Assembler</A>
-<BR>
-<A NAME="TOC16" HREF="tcc-doc.html#SEC16">5. TinyCC Linker</A>
-<BR>
-<A NAME="TOC21" HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A>
-<BR>
-<A NAME="TOC22" HREF="tcc-doc.html#SEC22">7. The <CODE>libtcc</CODE> library</A>
-<BR>
-<A NAME="TOC23" HREF="tcc-doc.html#SEC23">8. Developer's guide</A>
-<BR>
-<A NAME="TOC36" HREF="tcc-doc.html#SEC36">Concept Index</A>
-<BR>
-
-</BLOCKQUOTE>
-<HR SIZE=1>
-<A NAME="SEC_About"></A>
-<TABLE CELLPADDING=1 CELLSPACING=1 BORDER=0>
-<TR><TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top">Top</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Contents">Contents</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36">Index</A>]</TD>
-<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_About"> ? </A>]</TD>
-</TR></TABLE>
-<H1>About this document</H1>
-This document was generated on <I>December, 17 2017</I>
-using <A HREF="http://www.mathematik.uni-kl.de/~obachman/Texi2html
-"><I>texi2html</I></A>
-<P></P>
-The buttons in the navigation panels have the following meaning:
-<P></P>
-<table border = "1">
-<TR>
-<TH> Button </TH>
-<TH> Name </TH>
-<TH> Go to </TH>
-<TH> From 1.2.3 go to</TH>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [ &lt; ] </TD>
-<TD ALIGN="CENTER">
-Back
-</TD>
-<TD>
-previous section in reading order
-</TD>
-<TD>
-1.2.2
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [ &gt; ] </TD>
-<TD ALIGN="CENTER">
-Forward
-</TD>
-<TD>
-next section in reading order
-</TD>
-<TD>
-1.2.4
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [ &lt;&lt; ] </TD>
-<TD ALIGN="CENTER">
-FastBack
-</TD>
-<TD>
-previous or up-and-previous section
-</TD>
-<TD>
-1.1
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [ Up ] </TD>
-<TD ALIGN="CENTER">
-Up
-</TD>
-<TD>
-up section
-</TD>
-<TD>
-1.2
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [ &gt;&gt; ] </TD>
-<TD ALIGN="CENTER">
-FastForward
-</TD>
-<TD>
-next or up-and-next section
-</TD>
-<TD>
-1.3
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [Top] </TD>
-<TD ALIGN="CENTER">
-Top
-</TD>
-<TD>
-cover (top) of document
-</TD>
-<TD>
- &nbsp;
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [Contents] </TD>
-<TD ALIGN="CENTER">
-Contents
-</TD>
-<TD>
-table of contents
-</TD>
-<TD>
- &nbsp;
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [Index] </TD>
-<TD ALIGN="CENTER">
-Index
-</TD>
-<TD>
-concept index
-</TD>
-<TD>
- &nbsp;
-</TD>
-</TR>
-<TR>
-<TD ALIGN="CENTER">
- [ ? ] </TD>
-<TD ALIGN="CENTER">
-About
-</TD>
-<TD>
-this page
-</TD>
-<TD>
- &nbsp;
-</TD>
-</TR>
-</TABLE>
-<P></P>
-where the <STRONG> Example </STRONG> assumes that the current position
-is at <STRONG> Subsubsection One-Two-Three </STRONG> of a document of
-the following structure:
-<UL>
-<LI> 1. Section One </LI>
-<UL>
-<LI>1.1 Subsection One-One</LI>
-<UL>
-<LI> ... </LI>
-</UL>
-<LI>1.2 Subsection One-Two</LI>
-<UL>
-<LI>1.2.1 Subsubsection One-Two-One
-</LI><LI>1.2.2 Subsubsection One-Two-Two
-</LI><LI>1.2.3 Subsubsection One-Two-Three &nbsp; &nbsp; <STRONG>
-&lt;== Current Position </STRONG>
-</LI><LI>1.2.4 Subsubsection One-Two-Four
-</LI></UL>
-<LI>1.3 Subsection One-Three</LI>
-<UL>
-<LI> ... </LI>
-</UL>
-<LI>1.4 Subsection One-Four</LI>
-</UL>
-</UL>
-
-<HR SIZE=1>
-<BR>
-<FONT SIZE="-1">
-This document was generated
-on <I>December, 17 2017</I>
-using <A HREF="http://www.mathematik.uni-kl.de/~obachman/Texi2html
-"><I>texi2html</I></A>
-
-</BODY>
-</HTML>
diff --git a/tcc-doc.texi b/tcc-doc.texi
index 5e718a2..65aff2d 100644
--- a/tcc-doc.texi
+++ b/tcc-doc.texi
@@ -322,6 +322,11 @@ Binary image (only for executable output)
COFF output format (only for executable output for TMS320C67xx target)
@end table
+@item -Wl,--export-all-symbols
+@item -Wl,--export-dynamic
+Export global symbols to the dynamic linker. It is useful when a library
+opened with @code{dlopen()} needs to access executable symbols.
+
@item -Wl,-subsystem=console/gui/wince/...
Set type for PE (Windows) executables.
@@ -349,12 +354,30 @@ fault}.
Generate additional support code to check
memory allocations and array/pointer bounds. @option{-g} is implied. Note
that the generated code is slower and bigger in this case.
+The bound checking code is not included in shared libraries. The main executable should always be compiled with the @option{-b}.
+
+There are five environment variables that can be used:
+@table @option
+@item TCC_BOUNDS_WARN_POINTER_ADD
+Print warning when pointer add creates an illegal pointer.
+@item TCC_BOUNDS_PRINT_CALLS
+Print bound checking calls. Can be used for debugging.
+@item TCC_BOUNDS_PRINT_HEAP
+Print heap objects that are not freed at exit of program.
+@item TCC_BOUNDS_PRINT_STATISTIC
+Print statistic information at exit of program.
+@item TCC_BOUNDS_NEVER_FATAL
+Try to continue in case of a bound checking error.
+@end table
+
+Note: @option{-b} is only available on i386 (linux and windows), x86_64 (linux and windows), arm, arm64 and riscv64 for the moment.
-Note: @option{-b} is only available on i386 when using libtcc for the moment.
+@item -bt[N]
+Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
+With executables, additional support for stack traces is included.
-@item -bt N
-Display N callers in stack traces. This is useful with @option{-g} or
-@option{-b}.
+A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided
+to trigger a stack trace with a message on demand.
@end table
@@ -543,6 +566,7 @@ instead of
@cindex stdcall attribute
@cindex regparm attribute
@cindex dllexport attribute
+@cindex nodecorate attribute
@item The keyword @code{__attribute__} is handled to specify variable or
function attributes. The following attributes are supported:
@@ -570,6 +594,8 @@ registers @code{%eax}, @code{%edx} and @code{%ecx}.
@item @code{dllexport}: export function from dll/executable (win32 only)
+ @item @code{nodecorate}: do not apply any decorations that would otherwise be applied when exporting function from dll/executable (win32 only)
+
@end itemize
Here are some examples:
@@ -893,7 +919,7 @@ Here are some examples of caught errors:
int *tab;
tab = malloc(20 * sizeof(int));
for(i=0;i<21;i++) @{
- sum += tab4[i];
+ sum += tab[i];
@}
free(tab);
@}
@@ -906,7 +932,7 @@ Here are some examples of caught errors:
tab = malloc(20 * sizeof(int));
free(tab);
for(i=0;i<20;i++) @{
- sum += tab4[i];
+ sum += tab[i];
@}
@}
@end example
@@ -923,6 +949,59 @@ Here are some examples of caught errors:
@end table
+Signal handlers are not compatible with bounds checking. The code
+below can be used to protect signal handlers.
+The @code{__attribute__((bound_no_checking))} will prevent all bound checking
+code generation. If a signal handler calls another function this
+function must also use @code{__attribute__((bound_no_checking))}.
+
+The fork() function call in a multi threaded application is also a problem.
+To solve this all bounds checking can be disabled by calling
+@code{__bound_checking(1)}. The call to @code{__bound_checking(1)} will disable bounds
+checking in the whole application.
+
+The @code{BOUNDS_CHECKING_OFF} and @code{BOUNDS_CHECKING_ON} can also be used to
+disable bounds checking for some code. This is not recommended.
+It is better to fix the code.
+
+@example
+
+#if defined(__TINYC__) && __BOUNDS_CHECKING_ON
+#undef __attribute__
+extern void __bound_checking (int no_check);
+#define BOUNDS_CHECKING_OFF __bound_checking(1)
+#define BOUNDS_CHECKING_ON __bound_checking(-1)
+#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking))
+#else
+#define BOUNDS_CHECKING_OFF
+#define BOUNDS_CHECKING_ON
+#define BOUNDS_NO_CHECKING
+#endif
+
+void signal_handler(int sig, void *info, void *ucontext) BOUNDS_NO_CHECKING
+@{
+ ... signal handler code without generated bounds checking code.
+@}
+
+void run(const char *cmd)
+@{
+ switch (fork()) @{
+ case 0:
+ BOUNDS_CHECKING_OFF;
+ ...
+ exec...
+ exit(1);
+ case -1:
+ ...
+ break;
+ default:
+ ...
+ break;
+ @}
+@}
+
+@end example
+
@node Libtcc
@chapter The @code{libtcc} library
@@ -1294,10 +1373,6 @@ floating point to integer conversion.
@item gen_cvt_ftof()
floating point to floating point of different size conversion.
-@item gen_bounded_ptr_add()
-@item gen_bounded_ptr_deref()
-are only used for bounds checking.
-
@end table
@section Optimizations done
diff --git a/tcc.c b/tcc.c
index cd887d1..4f4eb62 100644
--- a/tcc.c
+++ b/tcc.c
@@ -29,46 +29,52 @@ static const char help[] =
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
" tcc [options...] -run infile [arguments...]\n"
"General options:\n"
- " -c compile only - generate an object file\n"
- " -o outfile set output filename\n"
- " -run run compiled source\n"
- " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
- " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
- " -w disable all warnings\n"
- " -v -vv show version, show search paths or loaded files\n"
- " -h -hh show this, show more help\n"
- " -bench show compilation statistics\n"
- " - use stdin pipe as infile\n"
- " @listfile read arguments from listfile\n"
+ " -c compile only - generate an object file\n"
+ " -o outfile set output filename\n"
+ " -run run compiled source\n"
+ " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
+ " -std=c99 Conform to the ISO 1999 C standard (default).\n"
+ " -std=c11 Conform to the ISO 2011 C standard.\n"
+ " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
+ " -w disable all warnings\n"
+ " --version -v show version\n"
+ " -vv show search paths or loaded files\n"
+ " -h -hh show this, show more help\n"
+ " -bench show compilation statistics\n"
+ " - use stdin pipe as infile\n"
+ " @listfile read arguments from listfile\n"
"Preprocessor options:\n"
- " -Idir add include path 'dir'\n"
- " -Dsym[=val] define 'sym' with value 'val'\n"
- " -Usym undefine 'sym'\n"
- " -E preprocess only\n"
+ " -Idir add include path 'dir'\n"
+ " -Dsym[=val] define 'sym' with value 'val'\n"
+ " -Usym undefine 'sym'\n"
+ " -E preprocess only\n"
+ " -C keep comments (not yet implemented)\n"
"Linker options:\n"
- " -Ldir add library path 'dir'\n"
- " -llib link with dynamic or static library 'lib'\n"
- " -r generate (relocatable) object file\n"
- " -shared generate a shared library/dll\n"
- " -rdynamic export all global symbols to dynamic linker\n"
- " -soname set name for shared library to be used at runtime\n"
+ " -Ldir add library path 'dir'\n"
+ " -llib link with dynamic or static library 'lib'\n"
+ " -r generate (relocatable) object file\n"
+ " -shared generate a shared library/dll\n"
+ " -rdynamic export all global symbols to dynamic linker\n"
+ " -soname set name for shared library to be used at runtime\n"
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
"Debugger options:\n"
- " -g generate runtime debug info\n"
+ " -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK
- " -b compile with built-in memory and bounds checker (implies -g)\n"
+ " -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
#ifdef CONFIG_TCC_BACKTRACE
- " -bt N show N callers in stack traces\n"
+ " -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
#endif
"Misc. options:\n"
- " -x[c|a|n] specify type of the next infile\n"
- " -nostdinc do not use standard system include paths\n"
- " -nostdlib do not link with standard crt and libraries\n"
- " -Bdir set tcc's private include/library dir\n"
- " -MD generate dependency file for make\n"
- " -MF file specify dependency file name\n"
- " -m32/64 defer to i386/x86_64 cross compiler\n"
+ " -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
+ " -nostdinc do not use standard system include paths\n"
+ " -nostdlib do not link with standard crt and libraries\n"
+ " -Bdir set tcc's private include/library dir\n"
+ " -MD generate dependency file for make\n"
+ " -MF file specify dependency file name\n"
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+ " -m32/64 defer to i386/x86_64 cross compiler\n"
+#endif
"Tools:\n"
" create library : tcc -ar [rcsv] lib.a files\n"
#ifdef TCC_TARGET_PE
@@ -91,7 +97,7 @@ static const char help2[] =
" -print-search-dirs print search paths\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n"
- " --param -pedantic -pipe -s -std -traditional\n"
+ " --param -pedantic -pipe -s -traditional\n"
"-W... warnings:\n"
" all turn on some (*) warnings\n"
" error stop after first warning\n"
@@ -117,6 +123,7 @@ static const char help2[] =
" -nostdlib do not link with standard crt/libs\n"
" -[no-]whole-archive load lib(s) fully/only as needed\n"
" -export-all-symbols same as -rdynamic\n"
+ " -export-dynamic same as -rdynamic\n"
" -image-base= -Ttext= set base address of executable\n"
" -section-alignment= set section alignment in executable\n"
#ifdef TCC_TARGET_PE
@@ -152,6 +159,8 @@ static const char version[] =
"ARM"
#elif defined TCC_TARGET_ARM64
"AArch64"
+#elif defined TCC_TARGET_RISCV64
+ "riscv64"
#endif
#ifdef TCC_ARM_HARDFLOAT
" Hard Float"
@@ -182,8 +191,10 @@ static void print_search_dirs(TCCState *s)
/* print_dirs("programs", NULL, 0); */
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
print_dirs("libraries", s->library_paths, s->nb_library_paths);
+#ifdef TCC_TARGET_PE
+ printf("libtcc1:\n %s/lib/"TCC_LIBTCC1"\n", s->tcc_lib_path);
+#else
printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
-#ifndef TCC_TARGET_PE
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
@@ -245,8 +256,8 @@ static unsigned getclock_ms(void)
int main(int argc0, char **argv0)
{
- TCCState *s;
- int ret, opt, n = 0, t = 0;
+ TCCState *s, *s1;
+ int ret, opt, n = 0, t = 0, done;
unsigned start_time = 0;
const char *first_file;
int argc; char **argv;
@@ -254,14 +265,20 @@ int main(int argc0, char **argv0)
redo:
argc = argc0, argv = argv0;
- s = tcc_new();
+ s = s1 = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
- if ((n | t) == 0) {
- if (opt == OPT_HELP)
- return printf(help), 1;
- if (opt == OPT_HELP2)
- return printf(help2), 1;
+ if (n == 0) {
+ if (opt == OPT_HELP) {
+ fputs(help, stdout);
+ if (!s->verbose)
+ return 0;
+ ++opt;
+ }
+ if (opt == OPT_HELP2) {
+ fputs(help2, stdout);
+ return 0;
+ }
if (opt == OPT_M32 || opt == OPT_M64)
tcc_tool_cross(s, argv, opt); /* never returns */
if (s->verbose)
@@ -282,12 +299,11 @@ redo:
return 0;
}
- n = s->nb_files;
- if (n == 0)
+ if (s->nb_files == 0)
tcc_error("no input files\n");
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
- if (s->outfile) {
+ if (s->outfile && 0!=strcmp("-",s->outfile)) {
ppfp = fopen(s->outfile, "w");
if (!ppfp)
tcc_error("could not write '%s'", s->outfile);
@@ -295,11 +311,8 @@ redo:
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
if (s->nb_libraries)
tcc_error("cannot specify libraries with -c");
- if (n > 1 && s->outfile)
+ if (s->nb_files > 1 && s->outfile)
tcc_error("cannot specify output file with -c many files");
- } else {
- if (s->option_pthread)
- tcc_set_options(s, "-lpthread");
}
if (s->do_bench)
@@ -313,15 +326,21 @@ redo:
s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY
- || s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16))
- s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files;
+ || s->output_type == TCC_OUTPUT_PREPROCESS)
+ && (s->dflag & 16)) { /* -dt option */
+ if (t)
+ s->dflag |= 32;
+ s->run_test = ++t;
+ if (n)
+ --n;
+ }
/* compile or add each files or library */
- for (first_file = NULL, ret = 0;;) {
- struct filespec *f = s->files[s->nb_files - n];
+ first_file = NULL, ret = 0;
+ do {
+ struct filespec *f = s->files[n];
s->filetype = f->type;
- s->alacarte_link = f->alacarte;
- if (f->type == AFF_TYPE_LIB) {
+ if (f->type & AFF_TYPE_LIB) {
if (tcc_add_library_err(s, f->name) < 0)
ret = 1;
} else {
@@ -332,12 +351,8 @@ redo:
if (tcc_add_file(s, f->name) < 0)
ret = 1;
}
- s->filetype = 0;
- s->alacarte_link = 1;
- if (--n == 0 || ret
- || (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
- break;
- }
+ done = ret || ++n >= s->nb_files;
+ } while (!done && (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
if (s->run_test) {
t = 0;
@@ -358,10 +373,10 @@ redo:
}
}
- if (s->do_bench && (n | t | ret) == 0)
+ if (s->do_bench && done && !(t | ret))
tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s);
- if (ret == 0 && n)
+ if (!done)
goto redo; /* compile more files with -c */
if (t)
goto redo; /* run more tests with -dt -run */
diff --git a/tcc.h b/tcc.h
index cd67973..f3783d8 100644
--- a/tcc.h
+++ b/tcc.h
@@ -22,11 +22,12 @@
#define _TCC_H
#define _GNU_SOURCE
+#define _DARWIN_C_SOURCE
#include "config.h"
+#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
-#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <math.h>
@@ -35,6 +36,7 @@
#include <time.h>
#ifndef _WIN32
+# define WIN32_LEAN_AND_MEAN 1
# include <unistd.h>
# include <sys/time.h>
# ifndef CONFIG_TCC_STATIC
@@ -46,6 +48,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
#endif
#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <io.h> /* open, close etc. */
# include <direct.h> /* getcwd */
@@ -73,6 +76,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
# pragma warning (disable : 4018) // signed/unsigned mismatch
# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
# define ssize_t intptr_t
+# ifdef _X86_
+# define __i386__ 1
+# endif
+# ifdef _AMD64_
+# define __x86_64__ 1
+# endif
# endif
# undef CONFIG_TCC_STATIC
#endif
@@ -92,9 +101,16 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifdef _MSC_VER
# define NORETURN __declspec(noreturn)
# define ALIGNED(x) __declspec(align(x))
+# define PRINTF_LIKE(x,y)
#else
# define NORETURN __attribute__((noreturn))
# define ALIGNED(x) __attribute__((aligned(x)))
+# define PRINTF_LIKE(x,y) __attribute__ ((format (printf, (x), (y))))
+#endif
+
+/* gnu headers use to #define __attribute__ to empty for non-gcc compilers */
+#ifdef __TINYC__
+# undef __attribute__
#endif
#ifdef _WIN32
@@ -117,7 +133,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* #define PP_DEBUG */
/* include file debug */
/* #define INC_DEBUG */
-/* memory leak debug */
+/* memory leak debug (only for single threaded usage) */
/* #define MEM_DEBUG */
/* assembler debug */
/* #define ASM_DEBUG */
@@ -128,19 +144,23 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* #define TCC_TARGET_ARM *//* ARMv4 code generator */
/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */
/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */
+/* #define TCC_TARGET_RISCV64 *//* risc-v code generator */
/* default target is I386 */
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
- !defined(TCC_TARGET_X86_64)
-# if defined __x86_64__ || defined _AMD64_
+ !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_RISCV64)
+# if defined __x86_64__
# define TCC_TARGET_X86_64
# elif defined __arm__
# define TCC_TARGET_ARM
# define TCC_ARM_EABI
+# define TCC_ARM_VFP
# define TCC_ARM_HARDFLOAT
# elif defined __aarch64__
# define TCC_TARGET_ARM64
+# elif defined __riscv
+# define TCC_TARGET_RISCV64
# else
# define TCC_TARGET_I386
# endif
@@ -151,25 +171,33 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* only native compiler supports -run */
#if defined _WIN32 == defined TCC_TARGET_PE
-# if (defined __i386__ || defined _X86_) && defined TCC_TARGET_I386
+# if defined __i386__ && defined TCC_TARGET_I386
# define TCC_IS_NATIVE
-# elif (defined __x86_64__ || defined _AMD64_) && defined TCC_TARGET_X86_64
+# elif defined __x86_64__ && defined TCC_TARGET_X86_64
# define TCC_IS_NATIVE
# elif defined __arm__ && defined TCC_TARGET_ARM
# define TCC_IS_NATIVE
# elif defined __aarch64__ && defined TCC_TARGET_ARM64
# define TCC_IS_NATIVE
+# elif defined __riscv && defined __LP64__ && defined TCC_TARGET_RISCV64
+# define TCC_IS_NATIVE
# endif
#endif
#if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT
# define CONFIG_TCC_BACKTRACE
-# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) \
+# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || \
+ defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64) || \
+ defined TCC_TARGET_RISCV64 \
&& !defined TCC_UCLIBC && !defined TCC_MUSL
# define CONFIG_TCC_BCHECK /* enable bound checking code */
# endif
#endif
+#if defined TCC_TARGET_PE || defined TCC_TARGET_MACHO
+# define ELF_OBJ_ONLY /* create elf .o but native executables */
+#endif
+
/* ------------ path configuration ------------ */
#ifndef CONFIG_SYSROOT
@@ -194,17 +222,21 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR)
#endif
+#ifndef CONFIG_USR_INCLUDE
+# define CONFIG_USR_INCLUDE "/usr/include"
+#endif
+
/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */
/* system include paths */
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
-# ifdef TCC_TARGET_PE
+# if defined TCC_TARGET_PE || defined _WIN32
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi"
# else
# define CONFIG_TCC_SYSINCLUDEPATHS \
"{B}/include" \
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \
- ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/include")
+ ":" ALSO_TRIPLET(CONFIG_SYSROOT CONFIG_USR_INCLUDE)
# endif
#endif
@@ -252,9 +284,15 @@ extern long double strtold (const char *__nptr, char **__endptr);
# else
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
# endif
+# elif defined(TCC_TARGET_RISCV64)
+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
# elif !defined(TCC_ARM_EABI)
# if defined(TCC_MUSL)
-# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
+# if defined(TCC_TARGET_I386)
+# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-i386.so.1"
+# else
+# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
+# endif
# else
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
# endif
@@ -294,6 +332,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ONE_SOURCE 1
#endif
+/* support using libtcc from threads */
+#define CONFIG_TCC_SEMLOCK
+
#if ONE_SOURCE
#define ST_INLN static inline
#define ST_FUNC static
@@ -315,25 +356,28 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifdef TCC_TARGET_I386
# include "i386-gen.c"
# include "i386-link.c"
-#endif
-#ifdef TCC_TARGET_X86_64
+#elif defined TCC_TARGET_X86_64
# include "x86_64-gen.c"
# include "x86_64-link.c"
-#endif
-#ifdef TCC_TARGET_ARM
+#elif defined TCC_TARGET_ARM
# include "arm-gen.c"
# include "arm-link.c"
# include "arm-asm.c"
-#endif
-#ifdef TCC_TARGET_ARM64
+#elif defined TCC_TARGET_ARM64
# include "arm64-gen.c"
# include "arm64-link.c"
-#endif
-#ifdef TCC_TARGET_C67
+# include "arm-asm.c"
+#elif defined TCC_TARGET_C67
# define TCC_TARGET_COFF
# include "coff.h"
# include "c67-gen.c"
# include "c67-link.c"
+#elif defined(TCC_TARGET_RISCV64)
+# include "riscv64-gen.c"
+# include "riscv64-link.c"
+# include "riscv64-asm.c"
+#else
+#error unknown target
#endif
#undef TARGET_DEFS_ONLY
@@ -414,8 +458,8 @@ typedef union CValue {
float f;
uint64_t i;
struct {
- int size;
const void *data;
+ int size;
} str;
int tab[LDOUBLE_SIZE/4];
} CValue;
@@ -426,9 +470,15 @@ typedef struct SValue {
unsigned short r; /* register + flags */
unsigned short r2; /* second register, used for 'long long'
type. If not used, set to VT_CONST */
- CValue c; /* constant, if VT_CONST */
- struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if
- result of unary() for an identifier. */
+ union {
+ struct { int jtrue, jfalse; }; /* forward jmps */
+ CValue c; /* constant, if VT_CONST */
+ };
+ union {
+ struct { unsigned short cmp_op, cmp_r; }; /* VT_CMP operation */
+ struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if */
+ }; /* result of unary() for an identifier. */
+
} SValue;
/* symbol attributes */
@@ -439,8 +489,10 @@ struct SymAttr {
weak : 1,
visibility : 2,
dllexport : 1,
+ nodecorate : 1,
dllimport : 1,
- unused : 5;
+ addrtaken : 1,
+ xxxx : 3; /* not used */
};
/* function attributes or temporary attributes for parsing */
@@ -448,19 +500,15 @@ struct FuncAttr {
unsigned
func_call : 3, /* calling convention (0..5), see below */
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
- func_args : 8; /* PE __stdcall args */
+ func_noreturn : 1, /* attribute((noreturn)) */
+ func_ctor : 1, /* attribute((constructor)) */
+ func_dtor : 1, /* attribute((destructor)) */
+ func_args : 8, /* PE __stdcall args */
+ func_alwinl : 1, /* always_inline */
+ no_bcheck : 1, /* no bound checking */
+ xxxx :14;
};
-/* GNUC attribute definition */
-typedef struct AttributeDef {
- struct SymAttr a;
- struct FuncAttr f;
- struct Section *section;
- int alias_target; /* token */
- int asm_label; /* associated asm label */
- char attr_mode; /* __attribute__((__mode__(...))) */
-} AttributeDef;
-
/* symbol management */
typedef struct Sym {
int v; /* symbol token */
@@ -478,10 +526,12 @@ typedef struct Sym {
};
long long enum_val; /* enum constant if IS_ENUM_VAL */
int *d; /* define token stream */
+ struct Sym *ncl; /* next cleanup */
};
CType type; /* associated type */
union {
struct Sym *next; /* next related symbol (for fields and anoms) */
+ struct Sym *cleanupstate; /* in defined labels */
int asm_label; /* associated asm label */
};
struct Sym *prev; /* prev symbol in stack */
@@ -493,6 +543,7 @@ typedef struct Section {
unsigned long data_offset; /* current data offset */
unsigned char *data; /* section data */
unsigned long data_allocated; /* used for realloc() handling */
+ TCCState *s1;
int sh_name; /* elf section name (only used during output) */
int sh_num; /* elf section number */
int sh_type; /* elf section type */
@@ -544,6 +595,8 @@ typedef struct DLLReference {
#define LABEL_DEFINED 0 /* label is defined */
#define LABEL_FORWARD 1 /* label is forward defined */
#define LABEL_DECLARED 2 /* label is declared but never used */
+#define LABEL_GONE 3 /* label isn't in scope, but not yet popped
+ from local_label_stack (stmt exprs) */
/* type_decl() types */
#define TYPE_ABSTRACT 1 /* type without variable */
@@ -585,6 +638,16 @@ typedef struct TokenString {
char alloc;
} TokenString;
+/* GNUC attribute definition */
+typedef struct AttributeDef {
+ struct SymAttr a;
+ struct FuncAttr f;
+ struct Section *section;
+ Sym *cleanup_func;
+ int asm_label; /* associated asm label */
+ char attr_mode; /* __attribute__((__mode__(...))) */
+} AttributeDef;
+
/* inline functions */
typedef struct InlineFunc {
TokenString *func_str;
@@ -638,20 +701,22 @@ struct sym_attr {
};
struct TCCState {
-
- int verbose; /* if true, display some information during compilation */
- int nostdinc; /* if true, no standard headers are added */
- int nostdlib; /* if true, no standard libraries are added */
- int nocommon; /* if true, do not use common symbols for .bss data */
- int static_link; /* if true, static linking is performed */
- int rdynamic; /* if true, all symbols are exported */
- int symbolic; /* if true, resolve symbols in the current module first */
- int alacarte_link; /* if true, only link in referenced objects from archive */
+ unsigned char verbose; /* if true, display some information during compilation */
+ unsigned char nostdinc; /* if true, no standard headers are added */
+ unsigned char nostdlib; /* if true, no standard libraries are added */
+ unsigned char nocommon; /* if true, do not use common symbols for .bss data */
+ unsigned char static_link; /* if true, static linking is performed */
+ unsigned char rdynamic; /* if true, all symbols are exported */
+ unsigned char symbolic; /* if true, resolve symbols in the current module first */
+ unsigned char filetype; /* file type for compilation (NONE,C,ASM) */
+ unsigned char optimize; /* only to #define __OPTIMIZE__ */
+ unsigned char option_pthread; /* -pthread option */
+ unsigned char enable_new_dtags; /* -Wl,--enable-new-dtags */
+ unsigned int cversion; /* supported C ISO version, 199901 (the default), 201112, ... */
char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
char *soname; /* as specified on the command line (-soname) */
char *rpath; /* as specified on the command line (-Wl,-rpath=) */
- int enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */
/* output type, see TCC_OUTPUT_XXX */
int output_type;
@@ -659,25 +724,26 @@ struct TCCState {
int output_format;
/* C language options */
- int char_is_unsigned;
- int leading_underscore;
- int ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
- int dollars_in_identifiers; /* allows '$' char in identifiers */
- int ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
+ unsigned char char_is_unsigned;
+ unsigned char leading_underscore;
+ unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
+ unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */
+ unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
/* warning switches */
- int warn_write_strings;
- int warn_unsupported;
- int warn_error;
- int warn_none;
- int warn_implicit_function_declaration;
- int warn_gcc_compat;
+ unsigned char warn_write_strings;
+ unsigned char warn_unsupported;
+ unsigned char warn_error;
+ unsigned char warn_none;
+ unsigned char warn_implicit_function_declaration;
+ unsigned char warn_gcc_compat;
/* compile with debug symbol (and use them if error during execution) */
- int do_debug;
+ unsigned char do_debug;
+ unsigned char do_backtrace;
#ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */
- int do_bounds_check;
+ unsigned char do_bounds_check;
#endif
#ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/
@@ -685,10 +751,15 @@ struct TCCState {
int run_test; /* nth test to run with -dt -run */
addr_t text_addr; /* address of text section */
- int has_text_addr;
+ unsigned char has_text_addr;
unsigned section_align; /* section alignment */
+ /* use GNU C extensions */
+ unsigned char gnu_ext;
+ /* use TinyCC extensions */
+ unsigned char tcc_ext;
+
char *init_symbol; /* symbols to call at load-time (not used currently) */
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
@@ -696,7 +767,7 @@ struct TCCState {
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
#endif
#ifdef TCC_TARGET_X86_64
- int nosse; /* For -mno-sse support. */
+ unsigned char nosse; /* For -mno-sse support. */
#endif
/* array of all loaded dlls (including those referenced by loaded dlls) */
@@ -718,9 +789,10 @@ struct TCCState {
char **crt_paths;
int nb_crt_paths;
- /* -include files */
- char **cmd_include_files;
- int nb_cmd_include_files;
+ /* -D / -U options */
+ CString cmdline_defs;
+ /* -include options */
+ CString cmdline_incl;
/* error handling */
void *error_opaque;
@@ -777,6 +849,22 @@ struct TCCState {
Section *got;
Section *plt;
+ /* predefined sections */
+ Section *text_section, *data_section, *bss_section;
+ Section *common_section;
+ Section *cur_text_section; /* current section where function code is generated */
+#ifdef CONFIG_TCC_BCHECK
+ /* bound check related sections */
+ Section *bounds_section; /* contains global data bound description */
+ Section *lbounds_section; /* contains local data bound description */
+#endif
+ /* symbol sections */
+ Section *symtab_section;
+ /* debug sections */
+ Section *stab_section;
+ /* Is there a new undefined sym since last new_undef_sym() */
+ int new_undef_sym;
+
/* temporary dynamic symbol sections (for dll loading) */
Section *dynsymtab_section;
/* exported dynamic symbol section */
@@ -786,6 +874,9 @@ struct TCCState {
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
struct sym_attr *sym_attrs;
int nb_sym_attrs;
+ /* ptr to next reloc entry reused */
+ ElfW_Rel *qrel;
+# define qrel s1->qrel
#ifdef TCC_TARGET_PE
/* PE info */
@@ -801,30 +892,54 @@ struct TCCState {
# endif
#endif
+#ifndef ELF_OBJ_ONLY
+ int nb_sym_versions;
+ struct sym_version *sym_versions;
+ int nb_sym_to_version;
+ int *sym_to_version;
+ int dt_verneednum;
+ Section *versym_section;
+ Section *verneed_section;
+#endif
+
#ifdef TCC_IS_NATIVE
const char *runtime_main;
void **runtime_mem;
int nb_runtime_mem;
#endif
+#ifdef CONFIG_TCC_BACKTRACE
+ int rt_num_callers;
+#endif
+
+ int fd, cc; /* used by tcc_load_ldscript */
+
+ /* benchmark info */
+ int total_idents;
+ int total_lines;
+ int total_bytes;
+
+ /* option -dnum (for general development purposes) */
+ int g_debug;
+
+ /* for warnings/errors for object files*/
+ const char *current_filename;
+
/* used by main and tcc_parse_args only */
struct filespec **files; /* files seen on command line */
int nb_files; /* number thereof */
int nb_libraries; /* number of libs thereof */
- int filetype;
char *outfile; /* output filename */
- int option_r; /* option -r */
- int do_bench; /* option -bench */
+ unsigned char option_r; /* option -r */
+ unsigned char do_bench; /* option -bench */
int gen_deps; /* option -MD */
char *deps_outfile; /* option -MF */
- int option_pthread; /* -pthread option */
int argc;
char **argv;
};
struct filespec {
char type;
- char alacarte;
char name[1];
};
@@ -838,17 +953,12 @@ struct filespec {
#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */
#define VT_LVAL 0x0100 /* var is an lvalue */
#define VT_SYM 0x0200 /* a symbol value is added */
-#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
+#define VT_MUSTCAST 0x0C00 /* value must be casted to be correct (used for
char/short stored in integer registers) */
-#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
+#define VT_MUSTBOUND 0x4000 /* bound checking must be done before
dereferencing value */
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
bounding function call point is in vc */
-#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
-#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
-#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
-#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
-
/* types */
#define VT_BTYPE 0x000f /* mask for basic type */
#define VT_VOID 0 /* void type */
@@ -883,7 +993,7 @@ struct filespec {
/* currently unused: 0x000[1248]0000 */
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
-#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
+#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
@@ -903,8 +1013,16 @@ struct filespec {
#define VT_ASM (VT_VOID | VT_UNSIGNED)
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
+/* general: set/get the pseudo-bitfield value for bit-mask M */
+#define BFVAL(M,N) ((unsigned)((M) & ~((M) << 1)) * (N))
+#define BFGET(X,M) (((X) & (M)) / BFVAL(M,1))
+#define BFSET(X,M,N) ((X) = ((X) & ~(M)) | BFVAL(M,N))
+
/* token values */
+/* conditional ops */
+#define TOK_LAND 0x90
+#define TOK_LOR 0x91
/* warning: the following compare tokens depend on i386 asm code */
#define TOK_ULT 0x92
#define TOK_UGE 0x93
@@ -919,62 +1037,65 @@ struct filespec {
#define TOK_LE 0x9e
#define TOK_GT 0x9f
-#define TOK_LAND 0xa0
-#define TOK_LOR 0xa1
-#define TOK_DEC 0xa2
-#define TOK_MID 0xa3 /* inc/dec, to void constant */
-#define TOK_INC 0xa4
-#define TOK_UDIV 0xb0 /* unsigned division */
-#define TOK_UMOD 0xb1 /* unsigned modulo */
-#define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
+#define TOK_ISCOND(t) (t >= TOK_LAND && t <= TOK_GT)
+
+#define TOK_DEC 0x80 /* -- */
+#define TOK_MID 0x81 /* inc/dec, to void constant */
+#define TOK_INC 0x82 /* ++ */
+#define TOK_UDIV 0x83 /* unsigned division */
+#define TOK_UMOD 0x84 /* unsigned modulo */
+#define TOK_PDIV 0x85 /* fast division with undefined rounding for pointers */
+#define TOK_UMULL 0x86 /* unsigned 32x32 -> 64 mul */
+#define TOK_ADDC1 0x87 /* add with carry generation */
+#define TOK_ADDC2 0x88 /* add with carry use */
+#define TOK_SUBC1 0x89 /* add with carry generation */
+#define TOK_SUBC2 0x8a /* add with carry use */
+#define TOK_SHL '<' /* shift left */
+#define TOK_SAR '>' /* signed shift right */
+#define TOK_SHR 0x8b /* unsigned shift right */
+
+#define TOK_ARROW 0xa0 /* -> */
+#define TOK_DOTS 0xa1 /* three dots */
+#define TOK_TWODOTS 0xa2 /* C++ token ? */
+#define TOK_TWOSHARPS 0xa3 /* ## preprocessing token */
+#define TOK_PLCHLDR 0xa4 /* placeholder token as defined in C99 */
+#define TOK_NOSUBST 0xa5 /* means following token has already been pp'd */
+#define TOK_PPJOIN 0xa6 /* A '##' in the right position to mean pasting */
+
+/* assignment operators */
+#define TOK_A_ADD 0xb0
+#define TOK_A_SUB 0xb1
+#define TOK_A_MUL 0xb2
+#define TOK_A_DIV 0xb3
+#define TOK_A_MOD 0xb4
+#define TOK_A_AND 0xb5
+#define TOK_A_OR 0xb6
+#define TOK_A_XOR 0xb7
+#define TOK_A_SHL 0xb8
+#define TOK_A_SAR 0xb9
+
+#define TOK_ASSIGN(t) (t >= TOK_A_ADD && t <= TOK_A_SAR)
+#define TOK_ASSIGN_OP(t) ("+-*/%&|^<>"[t - TOK_A_ADD])
/* tokens that carry values (in additional token string space / tokc) --> */
-#define TOK_CCHAR 0xb3 /* char constant in tokc */
-#define TOK_LCHAR 0xb4
-#define TOK_CINT 0xb5 /* number in tokc */
-#define TOK_CUINT 0xb6 /* unsigned int constant */
-#define TOK_CLLONG 0xb7 /* long long constant */
-#define TOK_CULLONG 0xb8 /* unsigned long long constant */
-#define TOK_STR 0xb9 /* pointer to string in tokc */
-#define TOK_LSTR 0xba
-#define TOK_CFLOAT 0xbb /* float constant */
-#define TOK_CDOUBLE 0xbc /* double constant */
-#define TOK_CLDOUBLE 0xbd /* long double constant */
-#define TOK_PPNUM 0xbe /* preprocessor number */
-#define TOK_PPSTR 0xbf /* preprocessor string */
-#define TOK_LINENUM 0xc0 /* line number info */
-#define TOK_TWODOTS 0xa8 /* C++ token ? */
-/* <-- */
-
-#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
-#define TOK_ADDC1 0xc3 /* add with carry generation */
-#define TOK_ADDC2 0xc4 /* add with carry use */
-#define TOK_SUBC1 0xc5 /* add with carry generation */
-#define TOK_SUBC2 0xc6 /* add with carry use */
-#define TOK_ARROW 0xc7
-#define TOK_DOTS 0xc8 /* three dots */
-#define TOK_SHR 0xc9 /* unsigned shift right */
-#define TOK_TWOSHARPS 0xca /* ## preprocessing token */
-#define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */
-#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */
-#define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */
-#define TOK_CLONG 0xce /* long constant */
-#define TOK_CULONG 0xcf /* unsigned long constant */
-
-#define TOK_SHL 0x01 /* shift left */
-#define TOK_SAR 0x02 /* signed shift right */
-
-/* assignment operators : normal operator or 0x80 */
-#define TOK_A_MOD 0xa5
-#define TOK_A_AND 0xa6
-#define TOK_A_MUL 0xaa
-#define TOK_A_ADD 0xab
-#define TOK_A_SUB 0xad
-#define TOK_A_DIV 0xaf
-#define TOK_A_XOR 0xde
-#define TOK_A_OR 0xfc
-#define TOK_A_SHL 0x81
-#define TOK_A_SAR 0x82
+#define TOK_CCHAR 0xc0 /* char constant in tokc */
+#define TOK_LCHAR 0xc1
+#define TOK_CINT 0xc2 /* number in tokc */
+#define TOK_CUINT 0xc3 /* unsigned int constant */
+#define TOK_CLLONG 0xc4 /* long long constant */
+#define TOK_CULLONG 0xc5 /* unsigned long long constant */
+#define TOK_CLONG 0xc6 /* long constant */
+#define TOK_CULONG 0xc7 /* unsigned long constant */
+#define TOK_STR 0xc8 /* pointer to string in tokc */
+#define TOK_LSTR 0xc9
+#define TOK_CFLOAT 0xca /* float constant */
+#define TOK_CDOUBLE 0xcb /* double constant */
+#define TOK_CLDOUBLE 0xcc /* long double constant */
+#define TOK_PPNUM 0xcd /* preprocessor number */
+#define TOK_PPSTR 0xce /* preprocessor string */
+#define TOK_LINENUM 0xcf /* line number info */
+
+#define TOK_HAS_VALUE(t) (t >= TOK_CCHAR && t <= TOK_LINENUM)
#define TOK_EOF (-1) /* end of file */
#define TOK_LINEFEED 10 /* line feed */
@@ -1079,16 +1200,11 @@ enum tcc_token {
/* ------------ libtcc.c ------------ */
-/* use GNU C extensions */
-ST_DATA int gnu_ext;
-/* use Tiny C extensions */
-ST_DATA int tcc_ext;
-/* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state;
/* public functions currently used by the tcc main function */
-ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s);
-ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s);
+ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s);
+ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s);
ST_FUNC char *pstrncpy(char *out, const char *in, size_t num);
PUB_FUNC char *tcc_basename(const char *name);
PUB_FUNC char *tcc_fileextension (const char *name);
@@ -1117,10 +1233,9 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
#define realloc(p, s) use_tcc_realloc(p, s)
#undef strdup
#define strdup(s) use_tcc_strdup(s)
-PUB_FUNC void tcc_memcheck(void);
-PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
-PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);
-PUB_FUNC void tcc_warning(const char *fmt, ...);
+PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2);
+PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2);
+PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2);
/* other utilities */
ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
@@ -1130,6 +1245,7 @@ ST_FUNC void cstr_cat(CString *cstr, const char *str, int len);
ST_FUNC void cstr_wccat(CString *cstr, int ch);
ST_FUNC void cstr_new(CString *cstr);
ST_FUNC void cstr_free(CString *cstr);
+ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...) PRINTF_LIKE(2,3);
ST_FUNC void cstr_reset(CString *cstr);
ST_INLN void sym_free(Sym *sym);
@@ -1150,21 +1266,32 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */
#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */
#define AFF_TYPE_BIN 0x40 /* file to add is binary */
+#define AFF_WHOLE_ARCHIVE 0x80 /* load all objects from archive */
/* s->filetype: */
#define AFF_TYPE_NONE 0
#define AFF_TYPE_C 1
#define AFF_TYPE_ASM 2
-#define AFF_TYPE_ASMPP 3
-#define AFF_TYPE_LIB 4
+#define AFF_TYPE_ASMPP 4
+#define AFF_TYPE_LIB 8
+#define AFF_TYPE_MASK (15 | AFF_TYPE_BIN)
/* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1
#define AFF_BINTYPE_DYN 2
#define AFF_BINTYPE_AR 3
#define AFF_BINTYPE_C67 4
-
+#ifndef ELF_OBJ_ONLY
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
+#endif
+#ifndef TCC_TARGET_MACHO
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
+#endif
+#ifdef CONFIG_TCC_BCHECK
+ST_FUNC void tcc_add_bcheck(TCCState *s1);
+#endif
+#ifdef CONFIG_TCC_BACKTRACE
+ST_FUNC void tcc_add_btstub(TCCState *s1);
+#endif
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
@@ -1194,8 +1321,6 @@ ST_DATA int tok_flags;
ST_DATA CString tokcstr; /* current parsed string, if any */
/* display benchmark infos */
-ST_DATA int total_lines;
-ST_DATA int total_bytes;
ST_DATA int tok_ident;
ST_DATA TokenSym **table_ident;
@@ -1239,10 +1364,9 @@ ST_FUNC Sym *label_push(Sym **ptop, int v, int flags);
ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep);
ST_FUNC void parse_define(void);
ST_FUNC void preprocess(int is_bof);
-ST_FUNC void next_nomacro(void);
ST_FUNC void next(void);
ST_INLN void unget_tok(int last_tok);
-ST_FUNC void preprocess_start(TCCState *s1, int is_asm);
+ST_FUNC void preprocess_start(TCCState *s1, int filetype);
ST_FUNC void preprocess_end(TCCState *s1);
ST_FUNC void tccpp_new(TCCState *s);
ST_FUNC void tccpp_delete(TCCState *s);
@@ -1270,18 +1394,14 @@ static inline int toup(int c) {
/* ------------ tccgen.c ------------ */
#define SYM_POOL_NB (8192 / sizeof(Sym))
-ST_DATA Sym *sym_free_first;
-ST_DATA void **sym_pools;
-ST_DATA int nb_sym_pools;
ST_DATA Sym *global_stack;
ST_DATA Sym *local_stack;
ST_DATA Sym *local_label_stack;
ST_DATA Sym *global_label_stack;
ST_DATA Sym *define_stack;
-ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
-ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop, *pvtop;
-#define vstack (__vstack + 1)
+ST_DATA CType int_type, func_old_type, char_pointer_type;
+ST_DATA SValue *vtop;
ST_DATA int rsym, anon_sym, ind, loc;
ST_DATA int const_wanted; /* true if constant wanted */
@@ -1290,36 +1410,42 @@ ST_DATA int global_expr; /* true if compound literals must be allocated globall
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
-ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA const char *funcname;
-ST_DATA int g_debug;
ST_FUNC void tcc_debug_start(TCCState *s1);
ST_FUNC void tcc_debug_end(TCCState *s1);
+ST_FUNC void tcc_debug_bincl(TCCState *s1);
+ST_FUNC void tcc_debug_eincl(TCCState *s1);
+ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename);
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
ST_FUNC void tcc_debug_line(TCCState *s1);
+ST_FUNC void tccgen_init(TCCState *s1);
ST_FUNC int tccgen_compile(TCCState *s1);
-ST_FUNC void free_inline_functions(TCCState *s);
+ST_FUNC void tccgen_finish(TCCState *s1);
ST_FUNC void check_vstack(void);
ST_INLN int is_float(int t);
ST_FUNC int ieee_finite(double d);
+ST_FUNC int exact_log2p1(int i);
ST_FUNC void test_lvalue(void);
ST_FUNC void vpushi(int v);
ST_FUNC ElfSym *elfsym(Sym *);
ST_FUNC void update_storage(Sym *sym);
-ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
+ST_FUNC Sym *external_global_sym(int v, CType *type);
ST_FUNC void vset(CType *type, int r, int v);
+ST_FUNC void vset_VT_CMP(int op);
ST_FUNC void vswap(void);
ST_FUNC void vpush_global_sym(CType *type, int v);
ST_FUNC void vrote(SValue *e, int n);
ST_FUNC void vrott(int n);
ST_FUNC void vrotb(int n);
+#if PTR_SIZE == 4
+ST_FUNC void lexpand(void);
+#endif
#ifdef TCC_TARGET_ARM
ST_FUNC int get_reg_ex(int rc, int rc2);
-ST_FUNC void lexpand_nr(void);
#endif
ST_FUNC void vpushv(SValue *v);
ST_FUNC void save_reg(int r);
@@ -1337,11 +1463,8 @@ ST_FUNC void vstore(void);
ST_FUNC void inc(int post, int c);
ST_FUNC void parse_mult_str (CString *astr, const char *msg);
ST_FUNC void parse_asm_str(CString *astr);
-ST_FUNC int lvalue_type(int t);
ST_FUNC void indir(void);
ST_FUNC void unary(void);
-ST_FUNC void expr_prod(void);
-ST_FUNC void expr_sum(void);
ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
@@ -1350,6 +1473,10 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
ST_FUNC int classify_x86_64_va_arg(CType *ty);
#endif
+#ifdef CONFIG_TCC_BCHECK
+ST_FUNC void gbound_args(int nb_args);
+ST_DATA int func_bound_add_epilog;
+#endif
/* ------------ tccelf.c ------------ */
@@ -1367,29 +1494,14 @@ typedef struct {
unsigned int n_value; /* value of symbol */
} Stab_Sym;
-ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
-ST_DATA Section *common_section;
-ST_DATA Section *cur_text_section; /* current section where function code is generated */
-#ifdef CONFIG_TCC_ASM
-ST_DATA Section *last_text_section; /* to handle .previous asm directive */
-#endif
-#ifdef CONFIG_TCC_BCHECK
-/* bound check related sections */
-ST_DATA Section *bounds_section; /* contains global data bound description */
-ST_DATA Section *lbounds_section; /* contains local data bound description */
-ST_FUNC void tccelf_bounds_new(TCCState *s);
-#endif
-/* symbol sections */
-ST_DATA Section *symtab_section;
-/* debug sections */
-ST_DATA Section *stab_section, *stabstr_section;
-
ST_FUNC void tccelf_new(TCCState *s);
ST_FUNC void tccelf_delete(TCCState *s);
ST_FUNC void tccelf_stab_new(TCCState *s);
ST_FUNC void tccelf_begin_file(TCCState *s1);
ST_FUNC void tccelf_end_file(TCCState *s1);
-
+#ifdef CONFIG_TCC_BCHECK
+ST_FUNC void tccelf_bounds_new(TCCState *s);
+#endif
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
@@ -1412,37 +1524,44 @@ ST_FUNC int find_elf_sym(Section *s, const char *name);
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol);
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend);
-ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value);
-ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
-ST_FUNC void put_stabn(int type, int other, int desc, int value);
-ST_FUNC void put_stabd(int type, int other, int desc);
+ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value);
+ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
+ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value);
ST_FUNC void resolve_common_syms(TCCState *s1);
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
ST_FUNC void relocate_section(TCCState *s1, Section *s);
+ST_FUNC ssize_t full_read(int fd, void *buf, size_t count);
+ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size);
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
-ST_FUNC int tcc_load_archive(TCCState *s1, int fd);
-ST_FUNC void tcc_add_bcheck(TCCState *s1);
-ST_FUNC void tcc_add_runtime(TCCState *s1);
+ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
+ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
+#if !defined(ELF_OBJ_ONLY) || (defined(TCC_TARGET_MACHO) && defined TCC_IS_NATIVE)
ST_FUNC void build_got_entries(TCCState *s1);
+#endif
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
-ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err);
-#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
-ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
-#endif
+ST_FUNC addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc);
+ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
+ void (*symbol_cb)(void *ctx, const char *name, const void *val));
+ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs);
-#ifndef TCC_TARGET_PE
+/* Browse each elem of type <type> in section <sec> starting at elem <startoff>
+ using variable <elem> */
+#define for_each_elem(sec, startoff, elem, type) \
+ for (elem = (type *) sec->data + startoff; \
+ elem < (type *) (sec->data + sec->data_offset); elem++)
+
+#ifndef ELF_OBJ_ONLY
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
-ST_FUNC int tcc_load_ldscript(TCCState *s1);
-ST_FUNC uint8_t *parse_comment(uint8_t *p);
-ST_FUNC void minp(void);
-ST_INLN void inp(void);
-ST_FUNC int handle_eob(void);
+ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
+#endif
+#ifndef TCC_TARGET_PE
+ST_FUNC void tcc_add_runtime(TCCState *s1);
#endif
/* ------------ xxx-link.c ------------ */
@@ -1456,12 +1575,15 @@ enum gotplt_entry {
ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */
};
+#if !defined(ELF_OBJ_ONLY) || defined(TCC_TARGET_MACHO)
ST_FUNC int code_reloc (int reloc_type);
ST_FUNC int gotplt_entry_type (int reloc_type);
+#if !defined(TCC_TARGET_MACHO) || defined TCC_IS_NATIVE
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr);
-ST_FUNC void relocate_init(Section *sr);
-ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
ST_FUNC void relocate_plt(TCCState *s1);
+#endif
+#endif
+ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
/* ------------ xxx-gen.c ------------ */
@@ -1473,27 +1595,22 @@ ST_FUNC void load(int r, SValue *sv);
ST_FUNC void store(int r, SValue *v);
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
ST_FUNC void gfunc_call(int nb_args);
-ST_FUNC void gfunc_prolog(CType *func_type);
+ST_FUNC void gfunc_prolog(Sym *func_sym);
ST_FUNC void gfunc_epilog(void);
+ST_FUNC void gen_fill_nops(int);
ST_FUNC int gjmp(int t);
ST_FUNC void gjmp_addr(int a);
-ST_FUNC int gtst(int inv, int t);
-#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
-ST_FUNC void gtst_addr(int inv, int a);
-#else
-#define gtst_addr(inv, a) gsym_addr(gtst(inv, 0), a)
-#endif
+ST_FUNC int gjmp_cond(int op, int t);
+ST_FUNC int gjmp_append(int n, int t);
ST_FUNC void gen_opi(int op);
ST_FUNC void gen_opf(int op);
ST_FUNC void gen_cvt_ftoi(int t);
+ST_FUNC void gen_cvt_itof(int t);
ST_FUNC void gen_cvt_ftof(int t);
ST_FUNC void ggoto(void);
#ifndef TCC_TARGET_C67
ST_FUNC void o(unsigned int c);
#endif
-#ifndef TCC_TARGET_ARM
-ST_FUNC void gen_cvt_itof(int t);
-#endif
ST_FUNC void gen_vla_sp_save(int addr);
ST_FUNC void gen_vla_sp_restore(int addr);
ST_FUNC void gen_vla_alloc(CType *type, int align);
@@ -1530,11 +1647,7 @@ ST_FUNC void gen_le16(int c);
ST_FUNC void gen_le32(int c);
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
-#endif
-
-#ifdef CONFIG_TCC_BCHECK
-ST_FUNC void gen_bounded_ptr_add(void);
-ST_FUNC void gen_bounded_ptr_deref(void);
+ST_FUNC void gen_cvt_csti(int t);
#endif
/* ------------ x86_64-gen.c ------------ */
@@ -1544,6 +1657,8 @@ ST_FUNC void gen_opl(int op);
#ifdef TCC_TARGET_PE
ST_FUNC void gen_vla_result(int addr);
#endif
+ST_FUNC void gen_cvt_sxtw(void);
+ST_FUNC void gen_cvt_csti(int t);
#endif
/* ------------ arm-gen.c ------------ */
@@ -1552,17 +1667,26 @@ ST_FUNC void gen_vla_result(int addr);
PUB_FUNC const char *default_elfinterp(struct TCCState *s);
#endif
ST_FUNC void arm_init(struct TCCState *s);
-ST_FUNC void gen_cvt_itof1(int t);
#endif
/* ------------ arm64-gen.c ------------ */
#ifdef TCC_TARGET_ARM64
-ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_opl(int op);
ST_FUNC void gfunc_return(CType *func_type);
ST_FUNC void gen_va_start(void);
ST_FUNC void gen_va_arg(CType *t);
ST_FUNC void gen_clear_cache(void);
+ST_FUNC void gen_cvt_sxtw(void);
+ST_FUNC void gen_cvt_csti(int t);
+#endif
+
+/* ------------ riscv64-gen.c ------------ */
+#ifdef TCC_TARGET_RISCV64
+ST_FUNC void gen_opl(int op);
+//ST_FUNC void gfunc_return(CType *func_type);
+ST_FUNC void gen_va_start(void);
+ST_FUNC void arch_transfer_ret_regs(int);
+ST_FUNC void gen_cvt_sxtw(void);
#endif
/* ------------ c67-gen.c ------------ */
@@ -1617,6 +1741,11 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
#endif
#define ST_ASM_SET 0x04
+/* ------------ tccmacho.c ----------------- */
+#ifdef TCC_TARGET_MACHO
+ST_FUNC int macho_output_file(TCCState * s1, const char *filename);
+ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev);
+#endif
/* ------------ tccrun.c ----------------- */
#ifdef TCC_IS_NATIVE
#ifdef CONFIG_TCC_STATIC
@@ -1630,12 +1759,6 @@ ST_FUNC void dlclose(void *p);
ST_FUNC const char *dlerror(void);
ST_FUNC void *dlsym(void *handle, const char *symbol);
#endif
-#ifdef CONFIG_TCC_BACKTRACE
-ST_DATA int rt_num_callers;
-ST_DATA const char **rt_bound_error_msg;
-ST_DATA void *rt_prog_main;
-ST_FUNC void tcc_set_num_callers(int n);
-#endif
ST_FUNC void tcc_run_free(TCCState *s1);
#endif
@@ -1657,4 +1780,42 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
#define ST_DATA
#endif
/********************************************************/
+
+#define text_section TCC_STATE_VAR(text_section)
+#define data_section TCC_STATE_VAR(data_section)
+#define bss_section TCC_STATE_VAR(bss_section)
+#define common_section TCC_STATE_VAR(common_section)
+#define cur_text_section TCC_STATE_VAR(cur_text_section)
+#define bounds_section TCC_STATE_VAR(bounds_section)
+#define lbounds_section TCC_STATE_VAR(lbounds_section)
+#define symtab_section TCC_STATE_VAR(symtab_section)
+#define stab_section TCC_STATE_VAR(stab_section)
+#define stabstr_section stab_section->link
+#define gnu_ext TCC_STATE_VAR(gnu_ext)
+#define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort)
+#define tcc_error TCC_SET_STATE(_tcc_error)
+#define tcc_warning TCC_SET_STATE(_tcc_warning)
+
+#define total_idents TCC_STATE_VAR(total_idents)
+#define total_lines TCC_STATE_VAR(total_lines)
+#define total_bytes TCC_STATE_VAR(total_bytes)
+
+PUB_FUNC void tcc_enter_state(TCCState *s1);
+PUB_FUNC void tcc_exit_state(void);
+
+/********************************************************/
#endif /* _TCC_H */
+
+#undef TCC_STATE_VAR
+#undef TCC_SET_STATE
+
+#ifdef USING_GLOBALS
+# define TCC_STATE_VAR(sym) tcc_state->sym
+# define TCC_SET_STATE(fn) fn
+# undef USING_GLOBALS
+#else
+# define TCC_STATE_VAR(sym) s1->sym
+# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
+/* actually we could avoid the tcc_enter_state(s1) hack by using
+ __VA_ARGS__ except that some compiler doesn't support it. */
+#endif
diff --git a/tccasm.c b/tccasm.c
index c035c8b..911052d 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -18,9 +18,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define USING_GLOBALS
#include "tcc.h"
#ifdef CONFIG_TCC_ASM
+static Section *last_text_section; /* to handle .previous asm directive */
+
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
{
char buf[64];
@@ -35,21 +38,53 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
static Sym* asm_new_label(TCCState *s1, int label, int is_local);
static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
+/* If a C name has an _ prepended then only asm labels that start
+ with _ are representable in C, by removing the first _. ASM names
+ without _ at the beginning don't correspond to C names, but we use
+ the global C symbol table to track ASM names as well, so we need to
+ transform those into ones that don't conflict with a C name,
+ so prepend a '.' for them, but force the ELF asm name to be set. */
+static int asm2cname(int v, int *addeddot)
+{
+ const char *name;
+ *addeddot = 0;
+ if (!tcc_state->leading_underscore)
+ return v;
+ name = get_tok_str(v, NULL);
+ if (!name)
+ return v;
+ if (name[0] == '_') {
+ v = tok_alloc(name + 1, strlen(name) - 1)->tok;
+ } else if (!strchr(name, '.')) {
+ int n = strlen(name) + 2;
+ char newname[256];
+ snprintf(newname, sizeof newname, ".%s", name);
+ v = tok_alloc(newname, n - 1)->tok;
+ *addeddot = 1;
+ }
+ return v;
+}
+
static Sym *asm_label_find(int v)
{
- Sym *sym = sym_find(v);
- while (sym && sym->sym_scope)
+ Sym *sym;
+ int addeddot;
+ v = asm2cname(v, &addeddot);
+ sym = sym_find(v);
+ while (sym && sym->sym_scope && !(sym->type.t & VT_STATIC))
sym = sym->prev_tok;
return sym;
}
static Sym *asm_label_push(int v)
{
+ int addeddot, v2 = asm2cname(v, &addeddot);
/* We always add VT_EXTERN, for sym definition that's tentative
(for .set, removed for real defs), for mere references it's correct
as is. */
- Sym *sym = global_identifier_push(v, VT_ASM | VT_EXTERN | VT_STATIC, 0);
- sym->r = VT_CONST | VT_SYM;
+ Sym *sym = global_identifier_push(v2, VT_ASM | VT_EXTERN | VT_STATIC, 0);
+ if (addeddot)
+ sym->asm_label = v;
return sym;
}
@@ -107,7 +142,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF))
sym = sym->prev_tok;
if (!sym)
- tcc_error("local label '%d' not found backward", n);
+ tcc_error("local label '%d' not found backward", (int)n);
} else {
/* forward */
if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
@@ -389,7 +424,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
sym = asm_label_push(label);
}
if (!sym->c)
- put_extern_sym2(sym, SHN_UNDEF, 0, 0, 0);
+ put_extern_sym2(sym, SHN_UNDEF, 0, 0, 1);
esym = elfsym(sym);
esym->st_shndx = sh_num;
esym->st_value = value;
@@ -914,9 +949,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
next();
if (tok == TOK_EOF)
break;
- /* generate line number info */
- if (global && s1->do_debug)
- tcc_debug_line(s1);
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
redo:
if (tok == '#') {
@@ -988,6 +1020,7 @@ static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
{
const int *saved_macro_ptr = macro_ptr;
int dotid = set_idnum('.', IS_ID);
+ int dolid = set_idnum('$', 0);
tcc_open_bf(s1, ":asm:", len);
memcpy(file->buffer, str, len);
@@ -995,6 +1028,7 @@ static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
tcc_assemble_internal(s1, 0, global);
tcc_close();
+ set_idnum('$', dolid);
set_idnum('.', dotid);
macro_ptr = saved_macro_ptr;
}
@@ -1148,8 +1182,8 @@ ST_FUNC void asm_instr(void)
ASMOperand operands[MAX_ASM_OPERANDS];
int nb_outputs, nb_operands, i, must_subst, out_reg;
uint8_t clobber_regs[NB_ASM_REGS];
+ Section *sec;
- next();
/* since we always generate the asm() instruction, we can ignore
volatile */
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
@@ -1222,8 +1256,15 @@ ST_FUNC void asm_instr(void)
asm_gen_code(operands, nb_operands, nb_outputs, 0,
clobber_regs, out_reg);
+ /* We don't allow switching section within inline asm to
+ bleed out to surrounding code. */
+ sec = cur_text_section;
/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
+ if (sec != cur_text_section) {
+ tcc_warning("inline asm tries to change current section");
+ use_section1(tcc_state, sec);
+ }
/* restore the current C token */
next();
diff --git a/tcccoff.c b/tcccoff.c
index 1421ca2..651bbe8 100644
--- a/tcccoff.c
+++ b/tcccoff.c
@@ -40,12 +40,12 @@ int FuncEntries[MAX_FUNCS];
int OutputTheSection(Section * sect);
short int GetCoffFlags(const char *s);
-void SortSymbolTable(void);
+void SortSymbolTable(TCCState *s1);
Section *FindSection(TCCState * s1, const char *sname);
int C67_main_entry_point;
-int FindCoffSymbolIndex(const char *func_name);
+int FindCoffSymbolIndex(TCCState * s1, const char *func_name);
int nb_syms;
typedef struct {
@@ -92,7 +92,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
sbss = FindSection(s1, ".bss");
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
- coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1");
+ coff_nb_syms = FindCoffSymbolIndex(s1, "XXXXXXXXXX1");
file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */
file_hdr.f_timdat = 0; /* time & date stamp */
@@ -366,7 +366,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// finally global symbols
if (s1->do_debug)
- SortSymbolTable();
+ SortSymbolTable(s1);
// write line no data
@@ -437,7 +437,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// output a function begin
CoffLineNo.l_addr.l_symndx =
- FindCoffSymbolIndex(func_name);
+ FindCoffSymbolIndex(s1, func_name);
CoffLineNo.l_lnno = 0;
fwrite(&CoffLineNo, 6, 1, f);
@@ -690,7 +690,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
-void SortSymbolTable(void)
+void SortSymbolTable(TCCState *s1)
{
int i, j, k, n = 0;
Elf32_Sym *p, *p2, *NewTable;
@@ -770,7 +770,7 @@ void SortSymbolTable(void)
}
-int FindCoffSymbolIndex(const char *func_name)
+int FindCoffSymbolIndex(TCCState *s1, const char *func_name)
{
int i, n = 0;
Elf32_Sym *p;
diff --git a/tccelf.c b/tccelf.c
index 70d47e1..ff83eb4 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -26,24 +26,21 @@
/********************************************************/
/* global variables */
-ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
-ST_DATA Section *common_section;
-ST_DATA Section *cur_text_section; /* current section where function code is generated */
-#ifdef CONFIG_TCC_ASM
-ST_DATA Section *last_text_section; /* to handle .previous asm directive */
-#endif
-#ifdef CONFIG_TCC_BCHECK
-/* bound check related sections */
-ST_DATA Section *bounds_section; /* contains global data bound description */
-ST_DATA Section *lbounds_section; /* contains local data bound description */
-#endif
-/* symbol sections */
-ST_DATA Section *symtab_section;
-/* debug sections */
-ST_DATA Section *stab_section, *stabstr_section;
+/* elf version information */
+struct sym_version {
+ char *lib;
+ char *version;
+ int out_index;
+ int prev_same_lib;
+};
-/* XXX: avoid static variable */
-static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
+#define nb_sym_versions s1->nb_sym_versions
+#define sym_versions s1->sym_versions
+#define nb_sym_to_version s1->nb_sym_to_version
+#define sym_to_version s1->sym_to_version
+#define dt_verneednum s1->dt_verneednum
+#define versym_section s1->versym_section
+#define verneed_section s1->verneed_section
/* special flag to indicate that the section should not be linked to the other ones */
#define SHF_PRIVATE 0x80000000
@@ -54,6 +51,7 @@ static int new_undef_sym = 0; /* Is there a new undefined sym since last new_und
ST_FUNC void tccelf_new(TCCState *s)
{
+ TCCState *s1 = s;
/* no section zero */
dynarray_add(&s->sections, &s->nb_sections, NULL);
@@ -80,6 +78,7 @@ ST_FUNC void tccelf_new(TCCState *s)
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tccelf_bounds_new(TCCState *s)
{
+ TCCState *s1 = s;
/* create bounds sections */
bounds_section = new_section(s, ".bounds",
SHT_PROGBITS, SHF_ALLOC);
@@ -90,13 +89,19 @@ ST_FUNC void tccelf_bounds_new(TCCState *s)
ST_FUNC void tccelf_stab_new(TCCState *s)
{
- stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
+ TCCState *s1 = s;
+ int shf = 0;
+#ifdef CONFIG_TCC_BACKTRACE
+ /* include stab info with standalone backtrace support */
+ if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY)
+ shf = SHF_ALLOC;
+#endif
+ stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
stab_section->sh_entsize = sizeof(Stab_Sym);
- stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
- put_elf_str(stabstr_section, "");
- stab_section->link = stabstr_section;
+ stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
+ stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
/* put first entry */
- put_stabs("", 0, 0, 0, 0);
+ put_stabs(s, "", 0, 0, 0, 0);
}
static void free_section(Section *s)
@@ -108,6 +113,16 @@ ST_FUNC void tccelf_delete(TCCState *s1)
{
int i;
+#ifndef ELF_OBJ_ONLY
+ /* free symbol versions */
+ for (i = 0; i < nb_sym_versions; i++) {
+ tcc_free(sym_versions[i].version);
+ tcc_free(sym_versions[i].lib);
+ }
+ tcc_free(sym_versions);
+ tcc_free(sym_to_version);
+#endif
+
/* free all sections */
for(i = 1; i < s1->nb_sections; i++)
free_section(s1->sections[i]);
@@ -171,7 +186,7 @@ ST_FUNC void tccelf_end_file(TCCState *s1)
&& ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info));
tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info,
- sym->st_other, sym->st_shndx, s->link->data + sym->st_name);
+ sym->st_other, sym->st_shndx, (char*)s->link->data + sym->st_name);
}
/* now update relocations */
for (i = 1; i < s1->nb_sections; i++) {
@@ -194,17 +209,23 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
Section *sec;
sec = tcc_mallocz(sizeof(Section) + strlen(name));
+ sec->s1 = s1;
strcpy(sec->name, name);
sec->sh_type = sh_type;
sec->sh_flags = sh_flags;
switch(sh_type) {
+ case SHT_GNU_versym:
+ sec->sh_addralign = 2;
+ break;
case SHT_HASH:
case SHT_REL:
case SHT_RELA:
case SHT_DYNSYM:
case SHT_SYMTAB:
case SHT_DYNAMIC:
- sec->sh_addralign = 4;
+ case SHT_GNU_verneed:
+ case SHT_GNU_verdef:
+ sec->sh_addralign = PTR_SIZE;
break;
case SHT_STRTAB:
sec->sh_addralign = 1;
@@ -303,9 +324,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size)
sec->data_offset = size;
}
-/* return a reference to a section, and create it if it does not
- exists */
-ST_FUNC Section *find_section(TCCState *s1, const char *name)
+static Section *find_section_create (TCCState *s1, const char *name, int create)
{
Section *sec;
int i;
@@ -315,7 +334,14 @@ ST_FUNC Section *find_section(TCCState *s1, const char *name)
return sec;
}
/* sections are created as PROGBITS */
- return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
+ return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL;
+}
+
+/* return a reference to a section, and create it if it does not
+ exists */
+ST_FUNC Section *find_section(TCCState *s1, const char *name)
+{
+ return find_section_create (s1, name, 1);
}
/* ------------------------------------------------------------------------- */
@@ -455,18 +481,29 @@ ST_FUNC int find_elf_sym(Section *s, const char *name)
return 0;
}
-/* return elf symbol value, signal error if 'err' is nonzero */
-ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err)
+/* return elf symbol value, signal error if 'err' is nonzero, decorate
+ name if FORC */
+ST_FUNC addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc)
{
int sym_index;
ElfW(Sym) *sym;
-
- sym_index = find_elf_sym(s->symtab, name);
- sym = &((ElfW(Sym) *)s->symtab->data)[sym_index];
+ char buf[256];
+ if (forc && s1->leading_underscore
+#ifdef TCC_TARGET_PE
+ /* win32-32bit stdcall symbols always have _ already */
+ && !strchr(name, '@')
+#endif
+ ) {
+ buf[0] = '_';
+ pstrcpy(buf + 1, sizeof(buf) - 1, name);
+ name = buf;
+ }
+ sym_index = find_elf_sym(s1->symtab, name);
+ sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index];
if (!sym_index || sym->st_shndx == SHN_UNDEF) {
if (err)
tcc_error("%s not defined", name);
- return 0;
+ return (addr_t)-1;
}
return sym->st_value;
}
@@ -474,14 +511,122 @@ ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err)
/* return elf symbol value */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name)
{
- return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0);
+ addr_t addr = get_sym_addr(s, name, 0, 1);
+ return addr == -1 ? NULL : (void*)(uintptr_t)addr;
+}
+
+/* list elf symbol names and values */
+ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
+ void (*symbol_cb)(void *ctx, const char *name, const void *val))
+{
+ ElfW(Sym) *sym;
+ Section *symtab;
+ int sym_index, end_sym;
+ const char *name;
+ unsigned char sym_vis, sym_bind;
+
+ symtab = s->symtab;
+ end_sym = symtab->data_offset / sizeof (ElfSym);
+ for (sym_index = 0; sym_index < end_sym; ++sym_index) {
+ sym = &((ElfW(Sym) *)symtab->data)[sym_index];
+ if (sym->st_value) {
+ name = (char *) symtab->link->data + sym->st_name;
+ sym_bind = ELFW(ST_BIND)(sym->st_info);
+ sym_vis = ELFW(ST_VISIBILITY)(sym->st_other);
+ if (sym_bind == STB_GLOBAL && sym_vis == STV_DEFAULT)
+ symbol_cb(ctx, name, (void*)(uintptr_t)sym->st_value);
+ }
+ }
}
-#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
-/* return elf symbol value or error */
-ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
+/* list elf symbol names and values */
+LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
+ void (*symbol_cb)(void *ctx, const char *name, const void *val))
{
- return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1);
+ list_elf_symbols(s, ctx, symbol_cb);
+}
+
+#ifndef ELF_OBJ_ONLY
+static void
+version_add (TCCState *s1)
+{
+ int i;
+ ElfW(Sym) *sym;
+ ElfW(Verneed) *vn = NULL;
+ Section *symtab;
+ int sym_index, end_sym, nb_versions = 2, nb_entries = 0;
+ ElfW(Half) *versym;
+ const char *name;
+
+ if (0 == nb_sym_versions)
+ return;
+ versym_section = new_section(s1, ".gnu.version", SHT_GNU_versym, SHF_ALLOC);
+ versym_section->sh_entsize = sizeof(ElfW(Half));
+ versym_section->link = s1->dynsym;
+
+ /* add needed symbols */
+ symtab = s1->dynsym;
+ end_sym = symtab->data_offset / sizeof (ElfSym);
+ versym = section_ptr_add(versym_section, end_sym * sizeof(ElfW(Half)));
+ for (sym_index = 0; sym_index < end_sym; ++sym_index) {
+ int dllindex, verndx;
+ sym = &((ElfW(Sym) *)symtab->data)[sym_index];
+ name = (char *) symtab->link->data + sym->st_name;
+ dllindex = find_elf_sym(s1->dynsymtab_section, name);
+ verndx = (dllindex && dllindex < nb_sym_to_version)
+ ? sym_to_version[dllindex] : -1;
+ if (verndx >= 0) {
+ if (!sym_versions[verndx].out_index)
+ sym_versions[verndx].out_index = nb_versions++;
+ versym[sym_index] = sym_versions[verndx].out_index;
+ } else
+ versym[sym_index] = 0;
+ }
+ /* generate verneed section, but not when it will be empty. Some
+ dynamic linkers look at their contents even when DTVERNEEDNUM and
+ section size is zero. */
+ if (nb_versions > 2) {
+ verneed_section = new_section(s1, ".gnu.version_r",
+ SHT_GNU_verneed, SHF_ALLOC);
+ verneed_section->link = s1->dynsym->link;
+ for (i = nb_sym_versions; i-- > 0;) {
+ struct sym_version *sv = &sym_versions[i];
+ int n_same_libs = 0, prev;
+ size_t vnofs;
+ ElfW(Vernaux) *vna = 0;
+ if (sv->out_index < 1)
+ continue;
+ vnofs = section_add(verneed_section, sizeof(*vn), 1);
+ vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
+ vn->vn_version = 1;
+ vn->vn_file = put_elf_str(verneed_section->link, sv->lib);
+ vn->vn_aux = sizeof (*vn);
+ do {
+ prev = sv->prev_same_lib;
+ if (sv->out_index > 0) {
+ vna = section_ptr_add(verneed_section, sizeof(*vna));
+ vna->vna_hash = elf_hash ((const unsigned char *)sv->version);
+ vna->vna_flags = 0;
+ vna->vna_other = sv->out_index;
+ sv->out_index = -2;
+ vna->vna_name = put_elf_str(verneed_section->link, sv->version);
+ vna->vna_next = sizeof (*vna);
+ n_same_libs++;
+ }
+ if (prev >= 0)
+ sv = &sym_versions[prev];
+ } while(prev >= 0);
+ vna->vna_next = 0;
+ vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
+ vn->vn_cnt = n_same_libs;
+ vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna);
+ nb_entries++;
+ }
+ if (vn)
+ vn->vn_next = 0;
+ verneed_section->sh_info = nb_entries;
+ }
+ dt_verneednum = nb_entries;
}
#endif
@@ -490,6 +635,7 @@ ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
int info, int other, int shndx, const char *name)
{
+ TCCState *s1 = s->s1;
ElfW(Sym) *esym;
int sym_bind, sym_index, sym_type, esym_bind;
unsigned char sym_vis, esym_vis, new_vis;
@@ -559,7 +705,7 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
do_patch:
esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
esym->st_shndx = shndx;
- new_undef_sym = 1;
+ s1->new_undef_sym = 1;
esym->st_value = value;
esym->st_size = size;
esym->st_other = other;
@@ -577,6 +723,7 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
int type, int symbol, addr_t addend)
{
+ TCCState *s1 = s->s1;
char buf[256];
Section *sr;
ElfW_Rel *rel;
@@ -587,7 +734,7 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
/* if the symtab is allocated, then we consider the relocation
are also */
- sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags);
+ sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags);
sr->sh_entsize = sizeof(ElfW_Rel);
sr->link = symtab;
sr->sh_info = s->sh_num;
@@ -598,10 +745,9 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
rel->r_info = ELFW(R_INFO)(symbol, type);
#if SHT_RELX == SHT_RELA
rel->r_addend = addend;
-#else
- if (addend)
- tcc_error("non-zero addend on REL architecture");
#endif
+ if (SHT_RELX != SHT_RELA && addend)
+ tcc_error("non-zero addend on REL architecture");
}
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
@@ -649,14 +795,25 @@ ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
/* put stab debug information */
-ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
+ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc,
unsigned long value)
{
Stab_Sym *sym;
+ unsigned offset;
+ if (type == N_SLINE
+ && (offset = stab_section->data_offset)
+ && (sym = (Stab_Sym*)(stab_section->data + offset) - 1)
+ && sym->n_type == type
+ && sym->n_value == value) {
+ /* just update line_number in previous entry */
+ sym->n_desc = desc;
+ return;
+ }
+
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
if (str) {
- sym->n_strx = put_elf_str(stabstr_section, str);
+ sym->n_strx = put_elf_str(stab_section->link, str);
} else {
sym->n_strx = 0;
}
@@ -666,23 +823,19 @@ ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
sym->n_value = value;
}
-ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc,
+ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc,
unsigned long value, Section *sec, int sym_index)
{
- put_stabs(str, type, other, desc, value);
put_elf_reloc(symtab_section, stab_section,
- stab_section->data_offset - sizeof(unsigned int),
- R_DATA_32, sym_index);
+ stab_section->data_offset + 8,
+ sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32,
+ sym_index);
+ put_stabs(s1, str, type, other, desc, value);
}
-ST_FUNC void put_stabn(int type, int other, int desc, int value)
+ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
{
- put_stabs(NULL, type, other, desc, value);
-}
-
-ST_FUNC void put_stabd(int type, int other, int desc)
-{
- put_stabs(NULL, type, other, desc, 0);
+ put_stabs(s1, NULL, type, other, desc, value);
}
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc)
@@ -706,12 +859,6 @@ ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc)
return &s1->sym_attrs[index];
}
-/* Browse each elem of type <type> in section <sec> starting at elem <startoff>
- using variable <elem> */
-#define for_each_elem(sec, startoff, elem, type) \
- for (elem = (type *) sec->data + startoff; \
- elem < (type *) (sec->data + sec->data_offset); elem++)
-
/* In an ELF file symbol table, the local symbols must appear below
the global and weak ones. Since TCC cannot sort it while generating
the code, we must do it after. All the relocation tables are also
@@ -789,7 +936,13 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
/* Use ld.so to resolve symbol for us (for tcc -run) */
if (do_resolve) {
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
+#ifdef TCC_TARGET_MACHO
+ /* The symbols in the symtables have a prepended '_'
+ but dlsym() needs the undecorated name. */
+ void *addr = dlsym(RTLD_DEFAULT, name + 1);
+#else
void *addr = dlsym(RTLD_DEFAULT, name);
+#endif
if (addr) {
sym->st_value = (addr_t) addr;
#ifdef DEBUG_RELOC
@@ -831,7 +984,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
unsigned char *ptr;
addr_t tgt, addr;
- relocate_init(sr);
+ qrel = (ElfW_Rel *)sr->data;
for_each_elem(sr, 0, rel, ElfW_Rel) {
ptr = s->data + rel->r_offset;
@@ -846,10 +999,19 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
relocate(s1, rel, type, ptr, addr, tgt);
}
/* if the relocation is allocated, we change its symbol table */
- if (sr->sh_flags & SHF_ALLOC)
+ if (sr->sh_flags & SHF_ALLOC) {
sr->link = s1->dynsym;
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ size_t r = (uint8_t*)qrel - sr->data;
+ if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE
+ && 0 == strcmp(s->name, ".stab"))
+ r = 0; /* cannot apply 64bit relocation to 32bit value */
+ sr->data_offset = sr->sh_size = r;
+ }
+ }
}
+#ifndef ELF_OBJ_ONLY
/* relocate relocation table in 'sr' */
static void relocate_rel(TCCState *s1, Section *sr)
{
@@ -865,13 +1027,14 @@ static void relocate_rel(TCCState *s1, Section *sr)
their space */
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
{
+ int count = 0;
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || \
+ defined(TCC_TARGET_ARM) || defined(TCC_TARGET_ARM64) || \
+ defined(TCC_TARGET_RISCV64)
ElfW_Rel *rel;
- int sym_index, type, count;
-
- count = 0;
for_each_elem(sr, 0, rel, ElfW_Rel) {
- sym_index = ELFW(R_SYM)(rel->r_info);
- type = ELFW(R_TYPE)(rel->r_info);
+ int sym_index = ELFW(R_SYM)(rel->r_info);
+ int type = ELFW(R_TYPE)(rel->r_info);
switch(type) {
#if defined(TCC_TARGET_I386)
case R_386_32:
@@ -885,6 +1048,14 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
+#elif defined(TCC_TARGET_ARM)
+ case R_ARM_ABS32:
+#elif defined(TCC_TARGET_ARM64)
+ case R_AARCH64_ABS32:
+ case R_AARCH64_ABS64:
+#elif defined(TCC_TARGET_RISCV64)
+ case R_RISCV_32:
+ case R_RISCV_64:
#endif
count++;
break;
@@ -892,6 +1063,8 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
case R_386_PC32:
#elif defined(TCC_TARGET_X86_64)
case R_X86_64_PC32:
+#elif defined(TCC_TARGET_ARM64)
+ case R_AARCH64_PREL32:
#endif
if (get_sym_attr(s1, sym_index, 0)->dyn_index)
count++;
@@ -905,9 +1078,12 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
sr->sh_flags |= SHF_ALLOC;
sr->sh_size = count * sizeof(ElfW_Rel);
}
+#endif
return count;
}
+#endif
+#if !defined(ELF_OBJ_ONLY) || (defined(TCC_TARGET_MACHO) && defined TCC_IS_NATIVE)
static void build_got(TCCState *s1)
{
/* if no got, then create it */
@@ -924,8 +1100,7 @@ static void build_got(TCCState *s1)
relocation, use 'size' and 'info' for the corresponding symbol metadata.
Returns the offset of the GOT or (if any) PLT entry. */
static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
- unsigned long size,
- int info, int sym_index)
+ int sym_index)
{
int need_plt_entry;
const char *name;
@@ -979,8 +1154,9 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
sym_index);
} else {
if (0 == attr->dyn_index)
- attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size,
- info, 0, sym->st_shndx, name);
+ attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value,
+ sym->st_size, sym->st_info, 0,
+ sym->st_shndx, name);
put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
attr->dyn_index);
}
@@ -1033,6 +1209,8 @@ ST_FUNC void build_got_entries(TCCState *s1)
for_each_elem(s, 0, rel, ElfW_Rel) {
type = ELFW(R_TYPE)(rel->r_info);
gotplt_entry = gotplt_entry_type(type);
+ if (gotplt_entry == -1)
+ tcc_error ("Unknown relocation type for got: %d", type);
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@@ -1080,13 +1258,18 @@ ST_FUNC void build_got_entries(TCCState *s1)
#ifdef TCC_TARGET_X86_64
if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) &&
+ sym->st_shndx != SHN_UNDEF &&
(ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
- ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)) {
+ ELFW(ST_BIND)(sym->st_info) == STB_LOCAL ||
+ s1->output_type == TCC_OUTPUT_EXE)) {
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
continue;
}
#endif
- if (code_reloc(type)) {
+ reloc_type = code_reloc(type);
+ if (reloc_type == -1)
+ tcc_error ("Unknown relocation type: %d", type);
+ else if (reloc_type != 0) {
jmp_slot:
reloc_type = R_JMP_SLOT;
} else
@@ -1098,35 +1281,29 @@ ST_FUNC void build_got_entries(TCCState *s1)
if (gotplt_entry == BUILD_GOT_ONLY)
continue;
- attr = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
- sym_index);
+ attr = put_got_entry(s1, reloc_type, sym_index);
if (reloc_type == R_JMP_SLOT)
rel->r_info = ELFW(R_INFO)(attr->plt_sym, type);
}
}
}
+#endif
-/* put dynamic tag */
-static void put_dt(Section *dynamic, int dt, addr_t val)
+ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs)
{
- ElfW(Dyn) *dyn;
- dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn)));
- dyn->d_tag = dt;
- dyn->d_un.d_val = val;
+ int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF;
+ if (sec && offs == -1)
+ offs = sec->data_offset;
+ return set_elf_sym(symtab_section, offs, 0,
+ ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
}
-#ifndef TCC_TARGET_PE
static void add_init_array_defines(TCCState *s1, const char *section_name)
{
Section *s;
- long end_offset;
- char sym_start[1024];
- char sym_end[1024];
-
- snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
- snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
-
+ addr_t end_offset;
+ char buf[1024];
s = find_section(s1, section_name);
if (!s) {
end_offset = 0;
@@ -1134,63 +1311,126 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
} else {
end_offset = s->data_offset;
}
-
- set_elf_sym(symtab_section,
- 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, sym_start);
- set_elf_sym(symtab_section,
- end_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, sym_end);
+ snprintf(buf, sizeof(buf), "__%s_start", section_name + 1);
+ set_global_sym(s1, buf, s, 0);
+ snprintf(buf, sizeof(buf), "__%s_end", section_name + 1);
+ set_global_sym(s1, buf, s, end_offset);
}
-#endif
+#ifndef TCC_TARGET_PE
static int tcc_add_support(TCCState *s1, const char *filename)
{
char buf[1024];
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename);
return tcc_add_file(s1, buf);
}
+#endif
-ST_FUNC void tcc_add_bcheck(TCCState *s1)
+ST_FUNC void add_array (TCCState *s1, const char *sec, int c)
{
-#ifdef CONFIG_TCC_BCHECK
- addr_t *ptr;
- int sym_index;
+ Section *s;
+ s = find_section(s1, sec);
+ s->sh_flags |= SHF_WRITE;
+#ifndef TCC_TARGET_PE
+ s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY;
+#endif
+ put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
+ section_ptr_add(s, PTR_SIZE);
+}
+#ifdef CONFIG_TCC_BCHECK
+ST_FUNC void tcc_add_bcheck(TCCState *s1)
+{
if (0 == s1->do_bounds_check)
return;
- /* XXX: add an object file to do that */
- ptr = section_ptr_add(bounds_section, sizeof(*ptr));
- *ptr = 0;
- set_elf_sym(symtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- bounds_section->sh_num, "__bounds_start");
- /* pull bcheck.o from libtcc1.a */
- sym_index = set_elf_sym(symtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- SHN_UNDEF, "__bound_init");
- if (s1->output_type != TCC_OUTPUT_MEMORY) {
- /* add 'call __bound_init()' in .init section */
- Section *init_section = find_section(s1, ".init");
- unsigned char *pinit = section_ptr_add(init_section, 5);
- pinit[0] = 0xe8;
- write32le(pinit + 1, -4);
- put_elf_reloc(symtab_section, init_section,
- init_section->data_offset - 4, R_386_PC32, sym_index);
- /* R_386_PC32 = R_X86_64_PC32 = 2 */
+ section_ptr_add(bounds_section, sizeof(addr_t));
+}
+#endif
+
+#ifdef CONFIG_TCC_BACKTRACE
+static void put_ptr(TCCState *s1, Section *s, int offs)
+{
+ int c;
+ c = set_global_sym(s1, NULL, s, offs);
+ s = data_section;
+ put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
+ section_ptr_add(s, PTR_SIZE);
+}
+
+/* set symbol to STB_LOCAL and resolve. The point is to not export it as
+ a dynamic symbol to allow so's to have one each with a different value. */
+static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset)
+{
+ int c = find_elf_sym(s1->symtab, name);
+ if (c) {
+ ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c;
+ esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE);
+ esym->st_value = offset;
+ esym->st_shndx = s->sh_num;
+ }
+}
+
+ST_FUNC void tcc_add_btstub(TCCState *s1)
+{
+ Section *s;
+ int n, o;
+ CString cstr;
+
+ s = data_section;
+ o = s->data_offset;
+ /* create (part of) a struct rt_context (see tccrun.c) */
+ put_ptr(s1, stab_section, 0);
+ put_ptr(s1, stab_section, -1);
+ put_ptr(s1, stab_section->link, 0);
+ section_ptr_add(s, 3 * PTR_SIZE);
+ /* prog_base */
+#ifndef TCC_TARGET_MACHO
+ /* XXX this relocation is wrong, it uses sym-index 0 (local,undef) */
+ put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0);
+#endif
+ section_ptr_add(s, PTR_SIZE);
+ n = 2 * PTR_SIZE;
+#ifdef CONFIG_TCC_BCHECK
+ if (s1->do_bounds_check) {
+ put_ptr(s1, bounds_section, 0);
+ n -= PTR_SIZE;
}
#endif
+ section_ptr_add(s, n);
+
+ cstr_new(&cstr);
+ cstr_printf(&cstr,
+ " extern void __bt_init(),*__rt_info[],__bt_init_dll();"
+ "__attribute__((constructor)) static void __bt_init_rt(){");
+#ifdef TCC_TARGET_PE
+ if (s1->output_type == TCC_OUTPUT_DLL)
+#ifdef CONFIG_TCC_BCHECK
+ cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check);
+#else
+ cstr_printf(&cstr, "__bt_init_dll(0);");
+#endif
+#endif
+ cstr_printf(&cstr, "__bt_init(__rt_info,%d, 0);}",
+ s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
+ tcc_compile_string(s1, cstr.data);
+ cstr_free(&cstr);
+ set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o);
}
+#endif
+#ifndef TCC_TARGET_PE
/* add tcc runtime libraries */
ST_FUNC void tcc_add_runtime(TCCState *s1)
{
+ s1->filetype = 0;
+#ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1);
+#endif
tcc_add_pragma_libs(s1);
/* add libc */
if (!s1->nostdlib) {
+ if (s1->option_pthread)
+ tcc_add_library_err(s1, "pthread");
tcc_add_library_err(s1, "c");
#ifdef TCC_LIBGCC
if (!s1->static_link) {
@@ -1200,12 +1440,32 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
tcc_add_dll(s1, TCC_LIBGCC, 0);
}
#endif
+#ifdef CONFIG_TCC_BCHECK
+ if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
+ tcc_add_library_err(s1, "pthread");
+ tcc_add_library_err(s1, "dl");
+ tcc_add_support(s1, "bcheck.o");
+ }
+#endif
+#ifdef CONFIG_TCC_BACKTRACE
+ if (s1->do_backtrace) {
+ if (s1->output_type == TCC_OUTPUT_EXE)
+ tcc_add_support(s1, "bt-exe.o");
+ if (s1->output_type != TCC_OUTPUT_DLL)
+ tcc_add_support(s1, "bt-log.o");
+ if (s1->output_type != TCC_OUTPUT_MEMORY)
+ tcc_add_btstub(s1);
+ }
+#endif
tcc_add_support(s1, TCC_LIBTCC1);
+#ifndef TCC_TARGET_MACHO
/* add crt end if not memory output */
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_crt(s1, "crtn.o");
+#endif
}
}
+#endif
/* add various standard linker symbols (must be done after the
sections are filled (for example after allocating common
@@ -1216,54 +1476,39 @@ static void tcc_add_linker_symbols(TCCState *s1)
int i;
Section *s;
- set_elf_sym(symtab_section,
- text_section->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- text_section->sh_num, "_etext");
- set_elf_sym(symtab_section,
- data_section->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- data_section->sh_num, "_edata");
- set_elf_sym(symtab_section,
- bss_section->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- bss_section->sh_num, "_end");
-#ifndef TCC_TARGET_PE
+ set_global_sym(s1, "_etext", text_section, -1);
+ set_global_sym(s1, "_edata", data_section, -1);
+ set_global_sym(s1, "_end", bss_section, -1);
+#ifdef TCC_TARGET_RISCV64
+ /* XXX should be .sdata+0x800, not .data+0x800 */
+ set_global_sym(s1, "__global_pointer$", data_section, 0x800);
+#endif
/* horrible new standard ldscript defines */
add_init_array_defines(s1, ".preinit_array");
add_init_array_defines(s1, ".init_array");
add_init_array_defines(s1, ".fini_array");
-#endif
-
/* add start and stop symbols for sections whose name can be
expressed in C */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
- if (s->sh_type == SHT_PROGBITS &&
- (s->sh_flags & SHF_ALLOC)) {
+ if ((s->sh_flags & SHF_ALLOC)
+ && (s->sh_type == SHT_PROGBITS
+ || s->sh_type == SHT_STRTAB)) {
const char *p;
- int ch;
-
/* check if section name can be expressed in C */
p = s->name;
for(;;) {
- ch = *p;
- if (!ch)
+ int c = *p;
+ if (!c)
break;
- if (!isid(ch) && !isnum(ch))
+ if (!isid(c) && !isnum(c))
goto next_sec;
p++;
}
snprintf(buf, sizeof(buf), "__start_%s", s->name);
- set_elf_sym(symtab_section,
- 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, buf);
+ set_global_sym(s1, buf, s, 0);
snprintf(buf, sizeof(buf), "__stop_%s", s->name);
- set_elf_sym(symtab_section,
- s->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, buf);
+ set_global_sym(s1, buf, s, -1);
}
next_sec: ;
}
@@ -1309,6 +1554,7 @@ static void tcc_output_binary(TCCState *s1, FILE *f,
}
}
+#ifndef ELF_OBJ_ONLY
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
{
int sym_index = ELFW(R_SYM) (rel->r_info);
@@ -1319,7 +1565,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
if (0 == offset)
return;
section_reserve(s1->got, offset + PTR_SIZE);
-#ifdef TCC_TARGET_X86_64
+#if PTR_SIZE == 8
write64le(s1->got->data + offset, sym->st_value);
#else
write32le(s1->got->data + offset, sym->st_value);
@@ -1359,6 +1605,8 @@ ST_FUNC void fill_got(TCCState *s1)
static void fill_local_got_entries(TCCState *s1)
{
ElfW_Rel *rel;
+ if (!s1->got->reloc)
+ return;
for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) {
if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) {
int sym_index = ELFW(R_SYM) (rel->r_info);
@@ -1509,6 +1757,7 @@ static void export_global_syms(TCCState *s1)
}
}
}
+#endif
/* Allocate strings for section names and decide if an unallocated section
should be output.
@@ -1524,20 +1773,34 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
s = s1->sections[i];
/* when generating a DLL, we include relocations but we may
patch them */
+#ifndef ELF_OBJ_ONLY
if (file_type == TCC_OUTPUT_DLL &&
s->sh_type == SHT_RELX &&
!(s->sh_flags & SHF_ALLOC) &&
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
prepare_dynamic_rel(s1, s)) {
- if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
- textrel = 1;
- } else if (s1->do_debug ||
+ if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE))
+ textrel = 1;
+ } else
+#endif
+ if ((s1->do_debug && s->sh_type != SHT_RELX) ||
file_type == TCC_OUTPUT_OBJ ||
(s->sh_flags & SHF_ALLOC) ||
- i == (s1->nb_sections - 1)) {
+ i == (s1->nb_sections - 1)
+#ifdef TCC_TARGET_ARM
+ || s->sh_type == SHT_ARM_ATTRIBUTES
+#endif
+ ) {
/* we output all sections if debug or object file */
s->sh_size = s->data_offset;
}
+#ifdef TCC_TARGET_ARM
+ /* XXX: Suppress stack unwinding section. */
+ if (s->sh_type == SHT_ARM_EXIDX) {
+ s->sh_flags = 0;
+ s->sh_size = 0;
+ }
+#endif
if (s->sh_size || (s->sh_flags & SHF_ALLOC))
s->sh_name = put_elf_str(strsec, s->name);
}
@@ -1642,9 +1905,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
if (s == interp) {
if (k != 0)
continue;
- } else if (s->sh_type == SHT_DYNSYM ||
- s->sh_type == SHT_STRTAB ||
- s->sh_type == SHT_HASH) {
+ } else if ((s->sh_type == SHT_DYNSYM ||
+ s->sh_type == SHT_STRTAB ||
+ s->sh_type == SHT_HASH)
+ && !strstr(s->name, ".stab")) {
if (k != 1)
continue;
} else if (s->sh_type == SHT_RELX) {
@@ -1738,6 +2002,16 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
return file_offset;
}
+#ifndef ELF_OBJ_ONLY
+/* put dynamic tag */
+static void put_dt(Section *dynamic, int dt, addr_t val)
+{
+ ElfW(Dyn) *dyn;
+ dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn)));
+ dyn->d_tag = dt;
+ dyn->d_un.d_val = val;
+}
+
static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
Section *dynamic)
{
@@ -1786,6 +2060,7 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
{
Section *dynamic = dyninf->dynamic;
+ Section *s;
/* put dynamic section entries */
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
@@ -1811,6 +2086,35 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
#endif
#endif
+ if (versym_section)
+ put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
+ if (verneed_section) {
+ put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
+ put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
+ }
+ s = find_section_create (s1, ".preinit_array", 0);
+ if (s && s->data_offset) {
+ put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr);
+ put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset);
+ }
+ s = find_section_create (s1, ".init_array", 0);
+ if (s && s->data_offset) {
+ put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr);
+ put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset);
+ }
+ s = find_section_create (s1, ".fini_array", 0);
+ if (s && s->data_offset) {
+ put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr);
+ put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset);
+ }
+ s = find_section_create (s1, ".init", 0);
+ if (s && s->data_offset) {
+ put_dt(dynamic, DT_INIT, s->sh_addr);
+ }
+ s = find_section_create (s1, ".fini", 0);
+ if (s && s->data_offset) {
+ put_dt(dynamic, DT_FINI, s->sh_addr);
+ }
if (s1->do_debug)
put_dt(dynamic, DT_DEBUG, 0);
put_dt(dynamic, DT_NULL, 0);
@@ -1832,14 +2136,7 @@ static int final_sections_reloc(TCCState *s1)
/* XXX: ignore sections with allocated relocations ? */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
-#if defined(TCC_TARGET_I386) || defined(TCC_MUSL)
- if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr
- /* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC
- checking is removed */
-#else
- if (s->reloc && s != s1->got)
- /* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */
-#endif
+ if (s->reloc && (s != s1->got || s1->static_link))
relocate_section(s1, s);
}
@@ -1854,6 +2151,7 @@ static int final_sections_reloc(TCCState *s1)
}
return 0;
}
+#endif
/* Create an ELF file on disk.
This function handle ELF specific layout requirements */
@@ -1904,12 +2202,14 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
#else
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
#endif
+#elif defined TCC_TARGET_RISCV64
+ ehdr.e_flags = EF_RISCV_FLOAT_ABI_DOUBLE;
#endif
switch(file_type) {
default:
case TCC_OUTPUT_EXE:
ehdr.e_type = ET_EXEC;
- ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1);
+ ehdr.e_entry = get_sym_addr(s1, "_start", 1, 0);
break;
case TCC_OUTPUT_DLL:
ehdr.e_type = ET_DYN;
@@ -2009,6 +2309,7 @@ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum,
return 0;
}
+#ifndef ELF_OBJ_ONLY
/* Sort section headers by assigned sh_addr, remove sections
that we aren't going to output. */
static void tidy_section_headers(TCCState *s1, int *sec_order)
@@ -2054,17 +2355,56 @@ static void tidy_section_headers(TCCState *s1, int *sec_order)
s1->nb_sections = nnew;
tcc_free(backmap);
}
+#endif
+
+#ifdef TCC_TARGET_ARM
+static void create_arm_attribute_section(TCCState *s1)
+{
+ // Needed for DLL support.
+ static const unsigned char arm_attr[] = {
+ 0x41, // 'A'
+ 0x2c, 0x00, 0x00, 0x00, // size 0x2c
+ 'a', 'e', 'a', 'b', 'i', 0x00, // "aeabi"
+ 0x01, 0x22, 0x00, 0x00, 0x00, // 'File Attributes', size 0x22
+ 0x05, 0x36, 0x00, // 'CPU_name', "6"
+ 0x06, 0x06, // 'CPU_arch', 'v6'
+ 0x08, 0x01, // 'ARM_ISA_use', 'Yes'
+ 0x09, 0x01, // 'THUMB_ISA_use', 'Thumb-1'
+ 0x0a, 0x02, // 'FP_arch', 'VFPv2'
+ 0x12, 0x04, // 'ABI_PCS_wchar_t', 4
+ 0x14, 0x01, // 'ABI_FP_denormal', 'Needed'
+ 0x15, 0x01, // 'ABI_FP_exceptions', 'Needed'
+ 0x17, 0x03, // 'ABI_FP_number_model', 'IEEE 754'
+ 0x18, 0x01, // 'ABI_align_needed', '8-byte'
+ 0x19, 0x01, // 'ABI_align_preserved', '8-byte, except leaf SP'
+ 0x1a, 0x02, // 'ABI_enum_size', 'int'
+ 0x1c, 0x01, // 'ABI_VFP_args', 'VFP registers'
+ 0x22, 0x01 // 'CPU_unaligned_access', 'v6'
+ };
+ Section *attr = new_section(s1, ".ARM.attributes", SHT_ARM_ATTRIBUTES, 0);
+ unsigned char *ptr = section_ptr_add(attr, sizeof(arm_attr));
+ attr->sh_addralign = 1;
+ memcpy(ptr, arm_attr, sizeof(arm_attr));
+ if (s1->float_abi != ARM_HARD_FLOAT) {
+ ptr[26] = 0x00; // 'FP_arch', 'No'
+ ptr[41] = 0x1e; // 'ABI_optimization_goals'
+ ptr[42] = 0x06; // 'Aggressive Debug'
+ }
+}
+#endif
/* Output an elf, coff or binary file */
/* XXX: suppress unneeded sections */
static int elf_output_file(TCCState *s1, const char *filename)
{
- int i, ret, phnum, shnum, file_type, file_offset, *sec_order;
+ int ret, phnum, shnum, file_type, file_offset, *sec_order;
struct dyn_inf dyninf = {0};
ElfW(Phdr) *phdr;
- ElfW(Sym) *sym;
Section *strsec, *interp, *dynamic, *dynstr;
- int textrel;
+
+#ifdef TCC_TARGET_ARM
+ create_arm_attribute_section (s1);
+#endif
file_type = s1->output_type;
s1->nb_errors = 0;
@@ -2072,8 +2412,8 @@ static int elf_output_file(TCCState *s1, const char *filename)
phdr = NULL;
sec_order = NULL;
interp = dynamic = dynstr = NULL; /* avoid warning */
- textrel = 0;
+#ifndef ELF_OBJ_ONLY
if (file_type != TCC_OUTPUT_OBJ) {
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
tcc_add_runtime(s1);
@@ -2098,7 +2438,6 @@ static int elf_output_file(TCCState *s1, const char *filename)
".dynstr",
".hash", SHF_ALLOC);
dynstr = s1->dynsym->link;
-
/* add dynamic section */
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
SHF_ALLOC | SHF_WRITE);
@@ -2118,16 +2457,20 @@ static int elf_output_file(TCCState *s1, const char *filename)
}
}
build_got_entries(s1);
+ version_add (s1);
}
+#endif
/* we add a section for symbols */
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
put_elf_str(strsec, "");
/* Allocate strings for section names */
- textrel = alloc_sec_names(s1, file_type, strsec);
+ ret = alloc_sec_names(s1, file_type, strsec);
+#ifndef ELF_OBJ_ONLY
if (dynamic) {
+ int i;
/* add a list of needed dlls */
for(i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *dllref = s1->loaded_dlls[i];
@@ -2144,7 +2487,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
/* XXX: currently, since we do not handle PIC code, we
must relocate the readonly segments */
- if (textrel)
+ if (ret)
put_dt(dynamic, DT_TEXTREL, 0);
}
@@ -2159,6 +2502,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
dynamic->sh_size = dynamic->data_offset;
dynstr->sh_size = dynstr->data_offset;
}
+#endif
/* compute number of program headers */
if (file_type == TCC_OUTPUT_OBJ)
@@ -2184,11 +2528,13 @@ static int elf_output_file(TCCState *s1, const char *filename)
file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf,
sec_order);
+#ifndef ELF_OBJ_ONLY
/* Fill remaining program header and finalize relocation related to dynamic
linking. */
if (file_type != TCC_OUTPUT_OBJ) {
fill_unloadable_phdr(phdr, phnum, interp, dynamic);
if (dynamic) {
+ ElfW(Sym) *sym;
dynamic->data_offset = dyninf.data_offset;
fill_dynamic(s1, &dyninf);
@@ -2220,10 +2566,12 @@ static int elf_output_file(TCCState *s1, const char *filename)
else if (s1->got)
fill_local_got_entries(s1);
}
+#endif
/* Create the ELF file with name 'filename' */
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
s1->nb_sections = shnum;
+ goto the_end;
the_end:
tcc_free(sec_order);
tcc_free(phdr);
@@ -2237,18 +2585,34 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename)
if (s->output_type != TCC_OUTPUT_OBJ) {
ret = pe_output_file(s, filename);
} else
+#elif TCC_TARGET_MACHO
+ if (s->output_type != TCC_OUTPUT_OBJ) {
+ ret = macho_output_file(s, filename);
+ } else
#endif
ret = elf_output_file(s, filename);
return ret;
}
-static void *load_data(int fd, unsigned long file_offset, unsigned long size)
+ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) {
+ char *cbuf = buf;
+ size_t rnum = 0;
+ while (1) {
+ ssize_t num = read(fd, cbuf, count-rnum);
+ if (num < 0) return num;
+ if (num == 0) return rnum;
+ rnum += num;
+ cbuf += num;
+ }
+}
+
+ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size)
{
void *data;
data = tcc_malloc(size);
lseek(fd, file_offset, SEEK_SET);
- read(fd, data, size);
+ full_read(fd, data, size);
return data;
}
@@ -2261,7 +2625,7 @@ typedef struct SectionMergeInfo {
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h)
{
- int size = read(fd, h, sizeof *h);
+ int size = full_read(fd, h, sizeof *h);
if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) {
if (h->e_type == ET_REL)
return AFF_BINTYPE_REL;
@@ -2286,7 +2650,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
ElfW(Ehdr) ehdr;
ElfW(Shdr) *shdr, *sh;
int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed;
- unsigned char *strsec, *strtab;
+ char *strsec, *strtab;
+ int stab_index, stabstr_index;
int *old_to_new_syms;
char *sh_name, *name;
SectionMergeInfo *sm_table, *sm;
@@ -2294,11 +2659,6 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
ElfW_Rel *rel;
Section *s;
- int stab_index;
- int stabstr_index;
-
- stab_index = stabstr_index = 0;
-
lseek(fd, file_offset, SEEK_SET);
if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL)
goto fail1;
@@ -2324,6 +2684,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
strtab = NULL;
nb_syms = 0;
seencompressed = 0;
+ stab_index = stabstr_index = 0;
+
for(i = 1; i < ehdr.e_shnum; i++) {
sh = &shdr[i];
if (sh->sh_type == SHT_SYMTAB) {
@@ -2352,10 +2714,10 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
if (i == ehdr.e_shstrndx)
continue;
sh = &shdr[i];
- sh_name = (char *) strsec + sh->sh_name;
- /* ignore sections types we do not handle */
+ if (sh->sh_type == SHT_RELX)
+ sh = &shdr[sh->sh_info];
+ /* ignore sections types we do not handle (plus relocs to those) */
if (sh->sh_type != SHT_PROGBITS &&
- sh->sh_type != SHT_RELX &&
#ifdef TCC_ARM_EABI
sh->sh_type != SHT_ARM_EXIDX &&
#endif
@@ -2363,15 +2725,15 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
sh->sh_type != SHT_PREINIT_ARRAY &&
sh->sh_type != SHT_INIT_ARRAY &&
sh->sh_type != SHT_FINI_ARRAY &&
- strcmp(sh_name, ".stabstr")
+ strcmp(strsec + sh->sh_name, ".stabstr")
)
continue;
if (seencompressed
- && (!strncmp(sh_name, ".debug_", sizeof(".debug_")-1)
- || (sh->sh_type == SHT_RELX
- && !strncmp((char*)strsec + shdr[sh->sh_info].sh_name,
- ".debug_", sizeof(".debug_")-1))))
+ && !strncmp(strsec + sh->sh_name, ".debug_", sizeof(".debug_")-1))
continue;
+
+ sh = &shdr[i];
+ sh_name = strsec + sh->sh_name;
if (sh->sh_addralign < 1)
sh->sh_addralign = 1;
/* find corresponding section, if any */
@@ -2386,9 +2748,14 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
it. */
sm_table[i].link_once = 1;
goto next;
- } else {
- goto found;
}
+ if (stab_section) {
+ if (s == stab_section)
+ stab_index = i;
+ if (s == stab_section->link)
+ stabstr_index = i;
+ }
+ goto found;
}
}
/* not found: create new section */
@@ -2403,26 +2770,11 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
tcc_error_noabort("invalid section type");
goto fail;
}
-
/* align start of section */
- offset = s->data_offset;
-
- if (0 == strcmp(sh_name, ".stab")) {
- stab_index = i;
- goto no_align;
- }
- if (0 == strcmp(sh_name, ".stabstr")) {
- stabstr_index = i;
- goto no_align;
- }
-
- size = sh->sh_addralign - 1;
- offset = (offset + size) & ~size;
+ s->data_offset += -s->data_offset & (sh->sh_addralign - 1);
if (sh->sh_addralign > s->sh_addralign)
s->sh_addralign = sh->sh_addralign;
- s->data_offset = offset;
- no_align:
- sm_table[i].offset = offset;
+ sm_table[i].offset = s->data_offset;
sm_table[i].s = s;
/* concatenate sections */
size = sh->sh_size;
@@ -2430,7 +2782,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
unsigned char *ptr;
lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
ptr = section_ptr_add(s, size);
- read(fd, ptr, size);
+ full_read(fd, ptr, size);
} else {
s->data_offset += size;
}
@@ -2445,8 +2797,11 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
b = (Stab_Sym *)(s->data + s->data_offset);
o = sm_table[stabstr_index].offset;
- while (a < b)
- a->n_strx += o, a++;
+ while (a < b) {
+ if (a->n_strx)
+ a->n_strx += o;
+ a++;
+ }
}
/* second short pass to update sh_link and sh_info fields of new
@@ -2464,7 +2819,6 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
s1->sections[s->sh_info]->reloc = s;
}
}
- sm = sm_table;
/* resolve symbols */
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
@@ -2479,7 +2833,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
already defined symbol. It is very important to get
correct relocations */
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
- name = (char *) strtab + sym->st_name;
+ name = strtab + sym->st_name;
sym_index = find_elf_sym(symtab_section, name);
if (sym_index)
old_to_new_syms[i] = sym_index;
@@ -2495,7 +2849,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
sym->st_value += sm->offset;
}
/* add symbol */
- name = (char *) strtab + sym->st_name;
+ name = strtab + sym->st_name;
sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size,
sym->st_info, sym->st_other,
sym->st_shndx, name);
@@ -2524,14 +2878,17 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
goto invalid_reloc;
sym_index = old_to_new_syms[sym_index];
/* ignore link_once in rel section. */
- if (!sym_index && !sm->link_once
+ if (!sym_index && !sm_table[sh->sh_info].link_once
#ifdef TCC_TARGET_ARM
&& type != R_ARM_V4BX
+#elif defined TCC_TARGET_RISCV64
+ && type != R_RISCV_ALIGN
+ && type != R_RISCV_RELAX
#endif
) {
invalid_reloc:
tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x",
- i, strsec + sh->sh_name, rel->r_offset);
+ i, strsec + sh->sh_name, (int)rel->r_offset);
goto fail;
}
rel->r_info = ELFW(R_INFO)(sym_index, type);
@@ -2577,53 +2934,72 @@ typedef struct ArchiveHeader {
char ar_fmag[2]; /* should contain ARFMAG */
} ArchiveHeader;
-static int get_be32(const uint8_t *b)
+#define ARFMAG "`\n"
+
+static unsigned long long get_be(const uint8_t *b, int n)
{
- return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
+ unsigned long long ret = 0;
+ while (n)
+ ret = (ret << 8) | *b++, --n;
+ return ret;
}
-static long get_be64(const uint8_t *b)
+static int read_ar_header(int fd, int offset, ArchiveHeader *hdr)
{
- long long ret = get_be32(b);
- ret = (ret << 32) | (unsigned)get_be32(b+4);
- return (long)ret;
+ char *p, *e;
+ int len;
+ lseek(fd, offset, SEEK_SET);
+ len = full_read(fd, hdr, sizeof(ArchiveHeader));
+ if (len != sizeof(ArchiveHeader))
+ return len ? -1 : 0;
+ p = hdr->ar_name;
+ for (e = p + sizeof hdr->ar_name; e > p && e[-1] == ' ';)
+ --e;
+ *e = '\0';
+ hdr->ar_size[sizeof hdr->ar_size-1] = 0;
+ return len;
}
/* load only the objects which resolve undefined symbols */
static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
{
- long i, bound, nsyms, sym_index, off, ret;
+ int i, bound, nsyms, sym_index, len, ret = -1;
+ unsigned long long off;
uint8_t *data;
const char *ar_names, *p;
const uint8_t *ar_index;
ElfW(Sym) *sym;
+ ArchiveHeader hdr;
data = tcc_malloc(size);
- if (read(fd, data, size) != size)
- goto fail;
- nsyms = entrysize == 4 ? get_be32(data) : get_be64(data);
+ if (full_read(fd, data, size) != size)
+ goto the_end;
+ nsyms = get_be(data, entrysize);
ar_index = data + entrysize;
ar_names = (char *) ar_index + nsyms * entrysize;
do {
bound = 0;
- for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
- sym_index = find_elf_sym(symtab_section, p);
- if(sym_index) {
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if(sym->st_shndx == SHN_UNDEF) {
- off = (entrysize == 4
- ? get_be32(ar_index + i * 4)
- : get_be64(ar_index + i * 8))
- + sizeof(ArchiveHeader);
- ++bound;
- if(tcc_load_object_file(s1, fd, off) < 0) {
- fail:
- ret = -1;
- goto the_end;
- }
- }
+ for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
+ Section *s = symtab_section;
+ sym_index = find_elf_sym(s, p);
+ if (!sym_index)
+ continue;
+ sym = &((ElfW(Sym) *)s->data)[sym_index];
+ if(sym->st_shndx != SHN_UNDEF)
+ continue;
+ off = get_be(ar_index + i * entrysize, entrysize);
+ len = read_ar_header(fd, off, &hdr);
+ if (len <= 0 || memcmp(hdr.ar_fmag, ARFMAG, 2)) {
+ tcc_error_noabort("invalid archive");
+ goto the_end;
}
+ off += len;
+ if (s1->verbose == 2)
+ printf(" -> %s\n", hdr.ar_name);
+ if (tcc_load_object_file(s1, fd, off) < 0)
+ goto the_end;
+ ++bound;
}
} while(bound);
ret = 0;
@@ -2633,58 +3009,178 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
}
/* load a '.a' file */
-ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
+ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte)
{
ArchiveHeader hdr;
- char ar_size[11];
- char ar_name[17];
- char magic[8];
- int size, len, i;
+ /* char magic[8]; */
+ int size, len;
unsigned long file_offset;
+ ElfW(Ehdr) ehdr;
/* skip magic which was already checked */
- read(fd, magic, sizeof(magic));
+ /* full_read(fd, magic, sizeof(magic)); */
+ file_offset = sizeof ARMAG - 1;
for(;;) {
- len = read(fd, &hdr, sizeof(hdr));
+ len = read_ar_header(fd, file_offset, &hdr);
if (len == 0)
- break;
- if (len != sizeof(hdr)) {
+ return 0;
+ if (len < 0) {
tcc_error_noabort("invalid archive");
return -1;
}
- memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size));
- ar_size[sizeof(hdr.ar_size)] = '\0';
- size = strtol(ar_size, NULL, 0);
- memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name));
- for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) {
- if (ar_name[i] != ' ')
- break;
- }
- ar_name[i + 1] = '\0';
- file_offset = lseek(fd, 0, SEEK_CUR);
+ file_offset += len;
+ size = strtol(hdr.ar_size, NULL, 0);
/* align to even */
size = (size + 1) & ~1;
- if (!strcmp(ar_name, "/")) {
+ if (alacarte) {
/* coff symbol table : we handle it */
- if(s1->alacarte_link)
+ if (!strcmp(hdr.ar_name, "/"))
return tcc_load_alacarte(s1, fd, size, 4);
- } else if (!strcmp(ar_name, "/SYM64/")) {
- if(s1->alacarte_link)
+ if (!strcmp(hdr.ar_name, "/SYM64/"))
return tcc_load_alacarte(s1, fd, size, 8);
- } else {
- ElfW(Ehdr) ehdr;
- if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
- if (tcc_load_object_file(s1, fd, file_offset) < 0)
- return -1;
- }
+ } else if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
+ if (s1->verbose == 2)
+ printf(" -> %s\n", hdr.ar_name);
+ if (tcc_load_object_file(s1, fd, file_offset) < 0)
+ return -1;
}
- lseek(fd, file_offset + size, SEEK_SET);
+ file_offset += size;
}
- return 0;
}
-#ifndef TCC_TARGET_PE
+#ifndef ELF_OBJ_ONLY
+/* Set LV[I] to the global index of sym-version (LIB,VERSION). Maybe resizes
+ LV, maybe create a new entry for (LIB,VERSION). */
+static void set_ver_to_ver(TCCState *s1, int *n, int **lv, int i, char *lib, char *version)
+{
+ while (i >= *n) {
+ *lv = tcc_realloc(*lv, (*n + 1) * sizeof(**lv));
+ (*lv)[(*n)++] = -1;
+ }
+ if ((*lv)[i] == -1) {
+ int v, prev_same_lib = -1;
+ for (v = 0; v < nb_sym_versions; v++) {
+ if (strcmp(sym_versions[v].lib, lib))
+ continue;
+ prev_same_lib = v;
+ if (!strcmp(sym_versions[v].version, version))
+ break;
+ }
+ if (v == nb_sym_versions) {
+ sym_versions = tcc_realloc (sym_versions,
+ (v + 1) * sizeof(*sym_versions));
+ sym_versions[v].lib = tcc_strdup(lib);
+ sym_versions[v].version = tcc_strdup(version);
+ sym_versions[v].out_index = 0;
+ sym_versions[v].prev_same_lib = prev_same_lib;
+ nb_sym_versions++;
+ }
+ (*lv)[i] = v;
+ }
+}
+
+/* Associates symbol SYM_INDEX (in dynsymtab) with sym-version index
+ VERNDX. */
+static void
+set_sym_version(TCCState *s1, int sym_index, int verndx)
+{
+ if (sym_index >= nb_sym_to_version) {
+ int newelems = sym_index ? sym_index * 2 : 1;
+ sym_to_version = tcc_realloc(sym_to_version,
+ newelems * sizeof(*sym_to_version));
+ memset(sym_to_version + nb_sym_to_version, -1,
+ (newelems - nb_sym_to_version) * sizeof(*sym_to_version));
+ nb_sym_to_version = newelems;
+ }
+ if (sym_to_version[sym_index] < 0)
+ sym_to_version[sym_index] = verndx;
+}
+
+struct versym_info {
+ int nb_versyms;
+ ElfW(Verdef) *verdef;
+ ElfW(Verneed) *verneed;
+ ElfW(Half) *versym;
+ int nb_local_ver, *local_ver;
+};
+
+
+static void store_version(TCCState *s1, struct versym_info *v, char *dynstr)
+{
+ char *lib, *version;
+ uint32_t next;
+ int i;
+
+#define DEBUG_VERSION 0
+
+ if (v->versym && v->verdef) {
+ ElfW(Verdef) *vdef = v->verdef;
+ lib = NULL;
+ do {
+ ElfW(Verdaux) *verdaux =
+ (ElfW(Verdaux) *) (((char *) vdef) + vdef->vd_aux);
+
+#if DEBUG_VERSION
+ printf ("verdef: version:%u flags:%u index:%u, hash:%u\n",
+ vdef->vd_version, vdef->vd_flags, vdef->vd_ndx,
+ vdef->vd_hash);
+#endif
+ if (vdef->vd_cnt) {
+ version = dynstr + verdaux->vda_name;
+
+ if (lib == NULL)
+ lib = version;
+ else
+ set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vdef->vd_ndx,
+ lib, version);
+#if DEBUG_VERSION
+ printf (" verdaux(%u): %s\n", vdef->vd_ndx, version);
+#endif
+ }
+ next = vdef->vd_next;
+ vdef = (ElfW(Verdef) *) (((char *) vdef) + next);
+ } while (next);
+ }
+ if (v->versym && v->verneed) {
+ ElfW(Verneed) *vneed = v->verneed;
+ do {
+ ElfW(Vernaux) *vernaux =
+ (ElfW(Vernaux) *) (((char *) vneed) + vneed->vn_aux);
+
+ lib = dynstr + vneed->vn_file;
+#if DEBUG_VERSION
+ printf ("verneed: %u %s\n", vneed->vn_version, lib);
+#endif
+ for (i = 0; i < vneed->vn_cnt; i++) {
+ if ((vernaux->vna_other & 0x8000) == 0) { /* hidden */
+ version = dynstr + vernaux->vna_name;
+ set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vernaux->vna_other,
+ lib, version);
+#if DEBUG_VERSION
+ printf (" vernaux(%u): %u %u %s\n",
+ vernaux->vna_other, vernaux->vna_hash,
+ vernaux->vna_flags, version);
+#endif
+ }
+ vernaux = (ElfW(Vernaux) *) (((char *) vernaux) + vernaux->vna_next);
+ }
+ next = vneed->vn_next;
+ vneed = (ElfW(Verneed) *) (((char *) vneed) + next);
+ } while (next);
+ }
+
+#if DEBUG_VERSION
+ for (i = 0; i < v->nb_local_ver; i++) {
+ if (v->local_ver[i] > 0) {
+ printf ("%d: lib: %s, version %s\n",
+ i, sym_versions[v->local_ver[i]].lib,
+ sym_versions[v->local_ver[i]].version);
+ }
+ }
+#endif
+}
+
/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
is referenced by the user (so it should be added as DT_NEEDED in
the generated ELF file) */
@@ -2695,11 +3191,14 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
int i, j, nb_syms, nb_dts, sym_bind, ret;
ElfW(Sym) *sym, *dynsym;
ElfW(Dyn) *dt, *dynamic;
- unsigned char *dynstr;
+
+ char *dynstr;
+ int sym_index;
const char *name, *soname;
DLLReference *dllref;
+ struct versym_info v;
- read(fd, &ehdr, sizeof(ehdr));
+ full_read(fd, &ehdr, sizeof(ehdr));
/* test CPU specific stuff */
if (ehdr.e_ident[5] != ELFDATA2LSB ||
@@ -2717,6 +3216,8 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
dynamic = NULL;
dynsym = NULL; /* avoid warning */
dynstr = NULL; /* avoid warning */
+ memset(&v, 0, sizeof v);
+
for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
switch(sh->sh_type) {
case SHT_DYNAMIC:
@@ -2729,6 +3230,16 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
sh1 = &shdr[sh->sh_link];
dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
break;
+ case SHT_GNU_verdef:
+ v.verdef = load_data(fd, sh->sh_offset, sh->sh_size);
+ break;
+ case SHT_GNU_verneed:
+ v.verneed = load_data(fd, sh->sh_offset, sh->sh_size);
+ break;
+ case SHT_GNU_versym:
+ v.nb_versyms = sh->sh_size / sizeof(ElfW(Half));
+ v.versym = load_data(fd, sh->sh_offset, sh->sh_size);
+ break;
default:
break;
}
@@ -2739,7 +3250,7 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
if (dt->d_tag == DT_SONAME) {
- soname = (char *) dynstr + dt->d_un.d_val;
+ soname = dynstr + dt->d_un.d_val;
}
}
@@ -2755,6 +3266,11 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
}
}
+ if (v.nb_versyms != nb_syms)
+ tcc_free (v.versym), v.versym = NULL;
+ else
+ store_version(s1, &v, dynstr);
+
/* add the dll and its level */
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
dllref->level = level;
@@ -2766,16 +3282,21 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
sym_bind = ELFW(ST_BIND)(sym->st_info);
if (sym_bind == STB_LOCAL)
continue;
- name = (char *) dynstr + sym->st_name;
- set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
- sym->st_info, sym->st_other, sym->st_shndx, name);
+ name = dynstr + sym->st_name;
+ sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
+ sym->st_info, sym->st_other, sym->st_shndx, name);
+ if (v.versym) {
+ ElfW(Half) vsym = v.versym[i];
+ if ((vsym & 0x8000) == 0 && vsym > 0 && vsym < v.nb_local_ver)
+ set_sym_version(s1, sym_index, v.local_ver[vsym]);
+ }
}
/* load all referenced DLLs */
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
switch(dt->d_tag) {
case DT_NEEDED:
- name = (char *) dynstr + dt->d_un.d_val;
+ name = dynstr + dt->d_un.d_val;
for(j = 0; j < s1->nb_loaded_dlls; j++) {
dllref = s1->loaded_dlls[j];
if (!strcmp(name, dllref->name))
@@ -2796,19 +3317,37 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
tcc_free(dynsym);
tcc_free(dynamic);
tcc_free(shdr);
+ tcc_free(v.local_ver);
+ tcc_free(v.verdef);
+ tcc_free(v.verneed);
+ tcc_free(v.versym);
return ret;
}
#define LD_TOK_NAME 256
#define LD_TOK_EOF (-1)
+static int ld_inp(TCCState *s1)
+{
+ char b;
+ if (s1->cc != -1) {
+ int c = s1->cc;
+ s1->cc = -1;
+ return c;
+ }
+ if (1 == read(s1->fd, &b, 1))
+ return b;
+ return CH_EOF;
+}
+
/* return next ld script token */
static int ld_next(TCCState *s1, char *name, int name_size)
{
- int c;
+ int c, d, ch;
char *q;
redo:
+ ch = ld_inp(s1);
switch(ch) {
case ' ':
case '\t':
@@ -2816,13 +3355,15 @@ static int ld_next(TCCState *s1, char *name, int name_size)
case '\v':
case '\r':
case '\n':
- inp();
goto redo;
case '/':
- minp();
- if (ch == '*') {
- file->buf_ptr = parse_comment(file->buf_ptr);
- ch = file->buf_ptr[0];
+ ch = ld_inp(s1);
+ if (ch == '*') { /* comment */
+ for (d = 0;; d = ch) {
+ ch = ld_inp(s1);
+ if (ch == CH_EOF || (ch == '/' && d == '*'))
+ break;
+ }
goto redo;
} else {
q = name;
@@ -2831,10 +3372,6 @@ static int ld_next(TCCState *s1, char *name, int name_size)
}
break;
case '\\':
- ch = handle_eob();
- if (ch != '\\')
- goto redo;
- /* fall through */
/* case 'a' ... 'z': */
case 'a':
case 'b':
@@ -2904,8 +3441,9 @@ static int ld_next(TCCState *s1, char *name, int name_size)
if ((q - name) < name_size - 1) {
*q++ = ch;
}
- minp();
+ ch = ld_inp(s1);
}
+ s1->cc = ch;
*q = '\0';
c = LD_TOK_NAME;
break;
@@ -2914,7 +3452,6 @@ static int ld_next(TCCState *s1, char *name, int name_size)
break;
default:
c = ch;
- inp();
break;
}
return c;
@@ -2931,14 +3468,6 @@ static int ld_add_file(TCCState *s1, const char filename[])
return tcc_add_dll(s1, filename, 0);
}
-static inline int new_undef_syms(void)
-{
- int ret = 0;
- ret = new_undef_sym;
- new_undef_sym = 0;
- return ret;
-}
-
static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
{
char filename[1024], libname[1024];
@@ -2947,10 +3476,13 @@ static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
group = !strcmp(cmd, "GROUP");
if (!as_needed)
- new_undef_syms();
+ s1->new_undef_sym = 0;
t = ld_next(s1, filename, sizeof(filename));
- if (t != '(')
- expect("(");
+ if (t != '(') {
+ tcc_error_noabort("( expected");
+ ret = -1;
+ goto lib_parse_error;
+ }
t = ld_next(s1, filename, sizeof(filename));
for(;;) {
libname[0] = '\0';
@@ -3002,9 +3534,9 @@ static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
}
}
if (group && !as_needed) {
- while (new_undef_syms()) {
+ while (s1->new_undef_sym) {
int i;
-
+ s1->new_undef_sym = 0;
for (i = 0; i < nblibs; i ++)
ld_add_file(s1, libs[i]);
}
@@ -3016,13 +3548,14 @@ lib_parse_error:
/* interpret a subset of GNU ldscripts to handle the dummy libc.so
files */
-ST_FUNC int tcc_load_ldscript(TCCState *s1)
+ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd)
{
char cmd[64];
char filename[1024];
int t, ret;
- ch = handle_eob();
+ s1->fd = fd;
+ s1->cc = -1;
for(;;) {
t = ld_next(s1, cmd, sizeof(cmd));
if (t == LD_TOK_EOF)
@@ -3038,8 +3571,10 @@ ST_FUNC int tcc_load_ldscript(TCCState *s1)
!strcmp(cmd, "TARGET")) {
/* ignore some commands */
t = ld_next(s1, cmd, sizeof(cmd));
- if (t != '(')
- expect("(");
+ if (t != '(') {
+ tcc_error_noabort("( expected");
+ return -1;
+ }
for(;;) {
t = ld_next(s1, filename, sizeof(filename));
if (t == LD_TOK_EOF) {
@@ -3055,4 +3590,4 @@ ST_FUNC int tcc_load_ldscript(TCCState *s1)
}
return 0;
}
-#endif /* !TCC_TARGET_PE */
+#endif /* !ELF_OBJ_ONLY */
diff --git a/tccgen.c b/tccgen.c
index e0b744e..4aa947c 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define USING_GLOBALS
#include "tcc.h"
/********************************************************/
@@ -30,38 +31,68 @@
*/
ST_DATA int rsym, anon_sym, ind, loc;
-ST_DATA Sym *sym_free_first;
-ST_DATA void **sym_pools;
-ST_DATA int nb_sym_pools;
-
ST_DATA Sym *global_stack;
ST_DATA Sym *local_stack;
ST_DATA Sym *define_stack;
ST_DATA Sym *global_label_stack;
ST_DATA Sym *local_label_stack;
+
+static Sym *sym_free_first;
+static void **sym_pools;
+static int nb_sym_pools;
+
+static Sym *all_cleanups, *pending_gotos;
static int local_scope;
static int in_sizeof;
+static int in_generic;
static int section_sym;
-ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */
-ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */
-ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */
-
-ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
+ST_DATA SValue *vtop;
+static SValue _vstack[1 + VSTACK_SIZE];
+#define vstack (_vstack + 1)
ST_DATA int const_wanted; /* true if constant wanted */
ST_DATA int nocode_wanted; /* no code generation wanted */
+#define unevalmask 0xffff /* unevaluated subexpression */
#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */
#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */
+
+/* Automagical code suppression ----> */
+#define CODE_OFF() (nocode_wanted |= 0x20000000)
+#define CODE_ON() (nocode_wanted &= ~0x20000000)
+
+/* Clear 'nocode_wanted' at label if it was used */
+ST_FUNC void gsym(int t) { if (t) { gsym_addr(t, ind); CODE_ON(); }}
+static int gind(void) { CODE_ON(); return ind; }
+
+/* Set 'nocode_wanted' after unconditional jumps */
+static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); }
+static int gjmp_acs(int t) { t = gjmp(t); CODE_OFF(); return t; }
+
+/* These are #undef'd at the end of this file */
+#define gjmp_addr gjmp_addr_acs
+#define gjmp gjmp_acs
+/* <---- */
+
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc;
-ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
+static int last_line_num, new_file, func_ind; /* debug info control */
ST_DATA const char *funcname;
-ST_DATA int g_debug;
+ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
+static CString initstr;
-ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type;
+#if PTR_SIZE == 4
+#define VT_SIZE_T (VT_INT | VT_UNSIGNED)
+#define VT_PTRDIFF_T VT_INT
+#elif LONG_SIZE == 4
+#define VT_SIZE_T (VT_LLONG | VT_UNSIGNED)
+#define VT_PTRDIFF_T VT_LLONG
+#else
+#define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED)
+#define VT_PTRDIFF_T (VT_LONG | VT_LLONG)
+#endif
ST_DATA struct switch_t {
struct case_t {
@@ -69,10 +100,117 @@ ST_DATA struct switch_t {
int sym;
} **p; int n; /* list of case ranges */
int def_sym; /* default symbol */
+ int *bsym;
+ struct scope *scope;
+ struct switch_t *prev;
+ SValue sv;
} *cur_switch; /* current switch */
-/* ------------------------------------------------------------------------- */
+#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
+/*list of temporary local variables on the stack in current function. */
+ST_DATA struct temp_local_variable {
+ int location; //offset on stack. Svalue.c.i
+ short size;
+ short align;
+} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
+short nb_temp_local_vars;
+
+static struct scope {
+ struct scope *prev;
+ struct { int loc, num; } vla;
+ struct { Sym *s; int n; } cl;
+ int *bsym, *csym;
+ Sym *lstk, *llstk;
+} *cur_scope, *loop_scope, *root_scope;
+
+/********************************************************/
+/* stab debug support */
+
+static const struct {
+ int type;
+ const char *name;
+} default_debug[] = {
+ { VT_INT, "int:t1=r1;-2147483648;2147483647;" },
+ { VT_BYTE, "char:t2=r2;0;127;" },
+#if LONG_SIZE == 4
+ { VT_LONG | VT_INT, "long int:t3=r3;-2147483648;2147483647;" },
+#else
+ { VT_LLONG | VT_LONG, "long int:t3=r3;-9223372036854775808;9223372036854775807;" },
+#endif
+ { VT_INT | VT_UNSIGNED, "unsigned int:t4=r4;0;037777777777;" },
+#if LONG_SIZE == 4
+ { VT_LONG | VT_INT | VT_UNSIGNED, "long unsigned int:t5=r5;0;037777777777;" },
+#else
+ /* use octal instead of -1 so size_t works (-gstabs+ in gcc) */
+ { VT_LLONG | VT_LONG | VT_UNSIGNED, "long unsigned int:t5=r5;0;01777777777777777777777;" },
+#endif
+ { VT_QLONG, "__int128:t6=r6;0;-1;" },
+ { VT_QLONG | VT_UNSIGNED, "__int128 unsigned:t7=r7;0;-1;" },
+ { VT_LLONG, "long long int:t8=r8;-9223372036854775808;9223372036854775807;" },
+ { VT_LLONG | VT_UNSIGNED, "long long unsigned int:t9=r9;0;01777777777777777777777;" },
+ { VT_SHORT, "short int:t10=r10;-32768;32767;" },
+ { VT_SHORT | VT_UNSIGNED, "short unsigned int:t11=r11;0;65535;" },
+ { VT_BYTE | VT_DEFSIGN, "signed char:t12=r12;-128;127;" },
+ { VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, "unsigned char:t13=r13;0;255;" },
+ { VT_FLOAT, "float:t14=r1;4;0;" },
+ { VT_DOUBLE, "double:t15=r1;8;0;" },
+ { VT_LDOUBLE, "long double:t16=r1;16;0;" },
+ { -1, "_Float32:t17=r1;4;0;" },
+ { -1, "_Float64:t18=r1;8;0;" },
+ { -1, "_Float128:t19=r1;16;0;" },
+ { -1, "_Float32x:t20=r1;8;0;" },
+ { -1, "_Float64x:t21=r1;16;0;" },
+ { -1, "_Decimal32:t22=r1;4;0;" },
+ { -1, "_Decimal64:t23=r1;8;0;" },
+ { -1, "_Decimal128:t24=r1;16;0;" },
+ /* if default char is unsigned */
+ { VT_BYTE | VT_UNSIGNED, "unsigned char:t25=r25;0;255;" },
+ /* boolean type */
+ { VT_BOOL, "bool:t26=r26;0;255;" },
+ { VT_VOID, "void:t27=27" },
+};
+
+static int debug_next_type;
+
+static struct debug_hash {
+ int debug_type;
+ Sym *type;
+} *debug_hash;
+
+static int n_debug_hash;
+
+static struct debug_info {
+ int start;
+ int end;
+ int n_sym;
+ struct debug_sym {
+ int type;
+ unsigned long value;
+ char *str;
+ Section *sec;
+ int sym_index;
+ } *sym;
+ struct debug_info *child, *next, *last, *parent;
+} *debug_info, *debug_info_root;
+/********************************************************/
+#if 1
+#define precedence_parser
+static void init_prec(void);
+#endif
+/********************************************************/
+#ifndef CONFIG_TCC_ASM
+ST_FUNC void asm_instr(void)
+{
+ tcc_error("inline asm() not supported");
+}
+ST_FUNC void asm_global_instr(void)
+{
+ tcc_error("inline asm() not supported");
+}
+#endif
+
+/* ------------------------------------------------------------------------- */
static void gen_cast(CType *type);
static void gen_cast_s(int t);
static inline CType *pointed_type(CType *type);
@@ -81,29 +219,135 @@ static int parse_btype(CType *type, AttributeDef *ad);
static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);
static void parse_expr_type(CType *type);
static void init_putv(CType *type, Section *sec, unsigned long c);
-static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
-static void block(int *bsym, int *csym, int is_expr);
+static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags);
+static void block(int is_expr);
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
static void decl(int l);
static int decl0(int l, int is_for_loop_init, Sym *);
static void expr_eq(void);
static void vla_runtime_type_size(CType *type, int *a);
-static void vla_sp_restore(void);
-static void vla_sp_restore_root(void);
static int is_compatible_unqualified_types(CType *type1, CType *type2);
static inline int64_t expr_const64(void);
static void vpush64(int ty, unsigned long long v);
static void vpush(CType *type);
static int gvtst(int inv, int t);
static void gen_inline_functions(TCCState *s);
+static void free_inline_functions(TCCState *s);
static void skip_or_save_block(TokenString **str);
static void gv_dup(void);
+static int get_temp_local_var(int size,int align);
+static void clear_temp_local_var_list();
+static void cast_error(CType *st, CType *dt);
ST_INLN int is_float(int t)
{
- int bt;
- bt = t & VT_BTYPE;
- return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT;
+ int bt = t & VT_BTYPE;
+ return bt == VT_LDOUBLE
+ || bt == VT_DOUBLE
+ || bt == VT_FLOAT
+ || bt == VT_QFLOAT;
+}
+
+static inline int is_integer_btype(int bt)
+{
+ return bt == VT_BYTE
+ || bt == VT_BOOL
+ || bt == VT_SHORT
+ || bt == VT_INT
+ || bt == VT_LLONG;
+}
+
+static int btype_size(int bt)
+{
+ return bt == VT_BYTE || bt == VT_BOOL ? 1 :
+ bt == VT_SHORT ? 2 :
+ bt == VT_INT ? 4 :
+ bt == VT_LLONG ? 8 :
+ bt == VT_PTR ? PTR_SIZE : 0;
+}
+
+/* returns function return register from type */
+static int R_RET(int t)
+{
+ if (!is_float(t))
+ return REG_IRET;
+#ifdef TCC_TARGET_X86_64
+ if ((t & VT_BTYPE) == VT_LDOUBLE)
+ return TREG_ST0;
+#elif defined TCC_TARGET_RISCV64
+ if ((t & VT_BTYPE) == VT_LDOUBLE)
+ return REG_IRET;
+#endif
+ return REG_FRET;
+}
+
+/* returns 2nd function return register, if any */
+static int R2_RET(int t)
+{
+ t &= VT_BTYPE;
+#if PTR_SIZE == 4
+ if (t == VT_LLONG)
+ return REG_IRE2;
+#elif defined TCC_TARGET_X86_64
+ if (t == VT_QLONG)
+ return REG_IRE2;
+ if (t == VT_QFLOAT)
+ return REG_FRE2;
+#elif defined TCC_TARGET_RISCV64
+ if (t == VT_LDOUBLE)
+ return REG_IRE2;
+#endif
+ return VT_CONST;
+}
+
+/* returns true for two-word types */
+#define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST)
+
+/* put function return registers to stack value */
+static void PUT_R_RET(SValue *sv, int t)
+{
+ sv->r = R_RET(t), sv->r2 = R2_RET(t);
+}
+
+/* returns function return register class for type t */
+static int RC_RET(int t)
+{
+ return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT);
+}
+
+/* returns generic register class for type t */
+static int RC_TYPE(int t)
+{
+ if (!is_float(t))
+ return RC_INT;
+#ifdef TCC_TARGET_X86_64
+ if ((t & VT_BTYPE) == VT_LDOUBLE)
+ return RC_ST0;
+ if ((t & VT_BTYPE) == VT_QFLOAT)
+ return RC_FRET;
+#elif defined TCC_TARGET_RISCV64
+ if ((t & VT_BTYPE) == VT_LDOUBLE)
+ return RC_INT;
+#endif
+ return RC_FLOAT;
+}
+
+/* returns 2nd register class corresponding to t and rc */
+static int RC2_TYPE(int t, int rc)
+{
+ if (!USING_TWO_WORDS(t))
+ return 0;
+#ifdef RC_IRE2
+ if (rc == RC_IRET)
+ return RC_IRE2;
+#endif
+#ifdef RC_FRE2
+ if (rc == RC_FRET)
+ return RC_FRE2;
+#endif
+ if (rc & RC_FLOAT)
+ return RC_FLOAT;
+ return RC_INT;
}
/* we use our own 'finite' function to avoid potential problems with
@@ -130,8 +374,9 @@ ST_FUNC void test_lvalue(void)
ST_FUNC void check_vstack(void)
{
- if (pvtop != vtop)
- tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop);
+ if (vtop != vstack - 1)
+ tcc_error("internal compiler error: vstack leak (%d)",
+ (int)(vtop - vstack + 1));
}
/* ------------------------------------------------------------------------- */
@@ -154,6 +399,7 @@ void pv (const char *lbl, int a, int b)
ST_FUNC void tcc_debug_start(TCCState *s1)
{
if (s1->do_debug) {
+ int i;
char buf[512];
/* file info: full path + filename */
@@ -165,12 +411,21 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
normalize_slashes(buf);
#endif
pstrcat(buf, sizeof(buf), "/");
- put_stabs_r(buf, N_SO, 0, 0,
+ put_stabs_r(s1, buf, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
- put_stabs_r(file->filename, N_SO, 0, 0,
+ put_stabs_r(s1, file->prev->filename, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
- last_ind = 0;
- last_line_num = 0;
+ for (i = 0; i < sizeof (default_debug) / sizeof (default_debug[0]); i++)
+ put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0);
+
+ new_file = last_line_num = 0;
+ func_ind = -1;
+ debug_next_type = sizeof(default_debug) / sizeof(default_debug[0]);
+ debug_hash = NULL;
+ n_debug_hash = 0;
+
+ /* we're currently 'including' the <command line> */
+ tcc_debug_bincl(s1);
}
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
@@ -180,47 +435,297 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
SHN_ABS, file->filename);
}
+static void tcc_debug_stabs (TCCState *s1, const char *str, int type, unsigned long value,
+ Section *sec, int sym_index)
+{
+ struct debug_sym *s;
+
+ if (debug_info) {
+ debug_info->sym =
+ (struct debug_sym *)tcc_realloc (debug_info->sym,
+ sizeof(struct debug_sym) *
+ (debug_info->n_sym + 1));
+ s = debug_info->sym + debug_info->n_sym++;
+ s->type = type;
+ s->value = value;
+ s->str = tcc_strdup(str);
+ s->sec = sec;
+ s->sym_index = sym_index;
+ }
+ else if (sec)
+ put_stabs_r (s1, str, type, 0, 0, value, sec, sym_index);
+ else
+ put_stabs (s1, str, type, 0, 0, value);
+}
+
+static void tcc_debug_stabn(int type, int value)
+{
+ if (type == N_LBRAC) {
+ struct debug_info *info =
+ (struct debug_info *) tcc_mallocz(sizeof (*info));
+
+ info->start = value;
+ info->parent = debug_info;
+ if (debug_info) {
+ if (debug_info->child) {
+ if (debug_info->child->last)
+ debug_info->child->last->next = info;
+ else
+ debug_info->child->next = info;
+ debug_info->child->last = info;
+ }
+ else
+ debug_info->child = info;
+ }
+ else
+ debug_info_root = info;
+ debug_info = info;
+ }
+ else {
+ debug_info->end = value;
+ debug_info = debug_info->parent;
+ }
+}
+
+static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
+{
+ int type;
+ int n = 0;
+ int debug_type = -1;
+ Sym *t = s;
+ CString str;
+
+ for (;;) {
+ type = t->type.t & ~(VT_EXTERN | VT_STATIC | VT_CONSTANT | VT_VOLATILE);
+ if ((type & VT_BTYPE) != VT_BYTE)
+ type &= ~VT_DEFSIGN;
+ if (type == VT_PTR || type == (VT_PTR | VT_ARRAY))
+ n++, t = t->type.ref;
+ else
+ break;
+ }
+ if ((type & VT_BTYPE) == VT_STRUCT) {
+ int i;
+
+ t = t->type.ref;
+ for (i = 0; i < n_debug_hash; i++) {
+ if (t == debug_hash[i].type) {
+ debug_type = debug_hash[i].debug_type;
+ break;
+ }
+ }
+ if (debug_type == -1) {
+ debug_type = ++debug_next_type;
+ debug_hash = (struct debug_hash *)
+ tcc_realloc (debug_hash,
+ (n_debug_hash + 1) * sizeof(*debug_hash));
+ debug_hash[n_debug_hash].debug_type = debug_type;
+ debug_hash[n_debug_hash++].type = t;
+ cstr_new (&str);
+ cstr_printf (&str, "%s:T%d=%c%d",
+ (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM
+ ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL),
+ debug_type,
+ IS_UNION (t->type.t) ? 'u' : 's',
+ t->c);
+ while (t->next) {
+ int pos, size, align;
+
+ t = t->next;
+ cstr_printf (&str, "%s:",
+ (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
+ ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL));
+ tcc_get_debug_info (s1, t, &str);
+ if (t->type.t & VT_BITFIELD) {
+ pos = t->c * 8 + BIT_POS(t->type.t);
+ size = BIT_SIZE(t->type.t);
+ }
+ else {
+ pos = t->c * 8;
+ size = type_size(&t->type, &align) * 8;
+ }
+ cstr_printf (&str, ",%d,%d;", pos, size);
+ }
+ cstr_printf (&str, ";");
+ tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0);
+ cstr_free (&str);
+ }
+ }
+ else if (IS_ENUM(type)) {
+ Sym *e = t = t->type.ref;
+
+ debug_type = ++debug_next_type;
+ cstr_new (&str);
+ cstr_printf (&str, "%s:T%d=e",
+ (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM
+ ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL),
+ debug_type);
+ while (t->next) {
+ t = t->next;
+ cstr_printf (&str, "%s:",
+ (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
+ ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL));
+ cstr_printf (&str, e->type.t & VT_UNSIGNED ? "%u," : "%d,",
+ (int)t->enum_val);
+ }
+ cstr_printf (&str, ";");
+ tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0);
+ cstr_free (&str);
+ }
+ else if ((type & VT_BTYPE) != VT_FUNC) {
+ type &= ~VT_STRUCT_MASK;
+ for (debug_type = 1;
+ debug_type <= sizeof(default_debug) / sizeof(default_debug[0]);
+ debug_type++)
+ if (default_debug[debug_type - 1].type == type)
+ break;
+ if (debug_type > sizeof(default_debug) / sizeof(default_debug[0]))
+ return;
+ }
+ if (n > 0)
+ cstr_printf (result, "%d=", ++debug_next_type);
+ t = s;
+ for (;;) {
+ type = t->type.t & ~(VT_EXTERN | VT_STATIC | VT_CONSTANT | VT_VOLATILE);
+ if ((type & VT_BTYPE) != VT_BYTE)
+ type &= ~VT_DEFSIGN;
+ if (type == VT_PTR)
+ cstr_printf (result, "%d=*", ++debug_next_type);
+ else if (type == (VT_PTR | VT_ARRAY))
+ cstr_printf (result, "%d=ar1;0;%d;",
+ ++debug_next_type, t->type.ref->c - 1);
+ else if (type == VT_FUNC) {
+ cstr_printf (result, "%d=f", ++debug_next_type);
+ tcc_get_debug_info (s1, t->type.ref, result);
+ return;
+ }
+ else
+ break;
+ t = t->type.ref;
+ }
+ cstr_printf (result, "%d", debug_type);
+}
+
+static void tcc_debug_finish (TCCState *s1, struct debug_info *cur)
+{
+ while (cur) {
+ int i;
+ struct debug_info *next = cur->next;
+
+ for (i = 0; i < cur->n_sym; i++) {
+ struct debug_sym *s = &cur->sym[i];
+
+ if (s->sec)
+ put_stabs_r(s1, s->str, s->type, 0, 0, s->value,
+ s->sec, s->sym_index);
+ else
+ put_stabs(s1, s->str, s->type, 0, 0, s->value);
+ tcc_free (s->str);
+ }
+ tcc_free (cur->sym);
+ put_stabn(s1, N_LBRAC, 0, 0, cur->start);
+ tcc_debug_finish (s1, cur->child);
+ put_stabn(s1, N_RBRAC, 0, 0, cur->end);
+ tcc_free (cur);
+ cur = next;
+ }
+}
+
+static void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e)
+{
+ CString debug_str;
+ cstr_new (&debug_str);
+ for (; s != e; s = s->prev) {
+ if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
+ continue;
+ cstr_reset (&debug_str);
+ cstr_printf (&debug_str, "%s:%s", get_tok_str(s->v, NULL), param ? "p" : "");
+ tcc_get_debug_info(s1, s, &debug_str);
+ tcc_debug_stabs(s1, debug_str.data, param ? N_PSYM : N_LSYM, s->c, NULL, 0);
+ }
+ cstr_free (&debug_str);
+}
+
+static void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bind)
+{
+ Section *s = s1->sections[sh_num];
+ CString str;
+
+ cstr_new (&str);
+ cstr_printf (&str, "%s:%c",
+ get_tok_str(sym->v, NULL),
+ sym_bind == STB_GLOBAL ? 'G' : local_scope ? 'V' : 'S'
+ );
+ tcc_get_debug_info(s1, sym, &str);
+ if (sym_bind == STB_GLOBAL)
+ tcc_debug_stabs(s1, str.data, N_GSYM, 0, NULL, 0);
+ else
+ tcc_debug_stabs(s1, str.data,
+ (sym->type.t & VT_STATIC) && data_section == s
+ ? N_STSYM : N_LCSYM, 0, s, sym->c);
+ cstr_free (&str);
+}
+
/* put end of translation unit info */
ST_FUNC void tcc_debug_end(TCCState *s1)
{
if (!s1->do_debug)
return;
- put_stabs_r(NULL, N_SO, 0, 0,
+ put_stabs_r(s1, NULL, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
+ tcc_free(debug_hash);
+}
+static BufferedFile* put_new_file(TCCState *s1)
+{
+ BufferedFile *f = file;
+ /* use upper file if from inline ":asm:" */
+ if (f->filename[0] == ':')
+ f = f->prev;
+ if (f && new_file) {
+ put_stabs_r(s1, f->filename, N_SOL, 0, 0, ind, text_section, section_sym);
+ new_file = last_line_num = 0;
+ }
+ return f;
}
/* generate line number info */
ST_FUNC void tcc_debug_line(TCCState *s1)
{
- if (!s1->do_debug)
+ BufferedFile *f;
+ if (!s1->do_debug
+ || cur_text_section != text_section
+ || !(f = put_new_file(s1))
+ || last_line_num == f->line_num)
return;
- if ((last_line_num != file->line_num || last_ind != ind)) {
- put_stabn(N_SLINE, 0, file->line_num, ind - func_ind);
- last_ind = ind;
- last_line_num = file->line_num;
+ if (func_ind != -1) {
+ put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind);
+ } else {
+ /* from tcc_assemble */
+ put_stabs_r(s1, NULL, N_SLINE, 0, f->line_num, ind, text_section, section_sym);
}
+ last_line_num = f->line_num;
}
/* put function symbol */
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym)
{
- char buf[512];
-
+ CString debug_str;
+ BufferedFile *f;
if (!s1->do_debug)
return;
+ debug_info_root = NULL;
+ debug_info = NULL;
+ tcc_debug_stabn(N_LBRAC, ind - func_ind);
+ if (!(f = put_new_file(s1)))
+ return;
+ cstr_new (&debug_str);
+ cstr_printf(&debug_str, "%s:%c", funcname, sym->type.t & VT_STATIC ? 'f' : 'F');
+ tcc_get_debug_info(s1, sym->type.ref, &debug_str);
+ put_stabs_r(s1, debug_str.data, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c);
+ cstr_free (&debug_str);
- /* stabs info */
- /* XXX: we put here a dummy type */
- snprintf(buf, sizeof(buf), "%s:%c1",
- funcname, sym->type.t & VT_STATIC ? 'f' : 'F');
- put_stabs_r(buf, N_FUN, 0, file->line_num, 0,
- cur_text_section, sym->c);
- /* //gr gdb wants a line at the function */
- put_stabn(N_SLINE, 0, file->line_num, 0);
-
- last_ind = 0;
- last_line_num = 0;
+ tcc_debug_line(s1);
}
/* put function size */
@@ -228,48 +733,80 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
{
if (!s1->do_debug)
return;
- put_stabn(N_FUN, 0, 0, size);
+ tcc_debug_stabn(N_RBRAC, size);
+ tcc_debug_finish (s1, debug_info_root);
+}
+
+/* put alternative filename */
+ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename)
+{
+ if (0 == strcmp(file->filename, filename))
+ return;
+ pstrcpy(file->filename, sizeof(file->filename), filename);
+ new_file = 1;
+}
+
+/* begin of #include */
+ST_FUNC void tcc_debug_bincl(TCCState *s1)
+{
+ if (!s1->do_debug)
+ return;
+ put_stabs(s1, file->filename, N_BINCL, 0, 0, 0);
+ new_file = 1;
+}
+
+/* end of #include */
+ST_FUNC void tcc_debug_eincl(TCCState *s1)
+{
+ if (!s1->do_debug)
+ return;
+ put_stabn(s1, N_EINCL, 0, 0, 0);
+ new_file = 1;
}
/* ------------------------------------------------------------------------- */
-ST_FUNC int tccgen_compile(TCCState *s1)
+/* initialize vstack and types. This must be done also for tcc -E */
+ST_FUNC void tccgen_init(TCCState *s1)
{
- cur_text_section = NULL;
- funcname = "";
- anon_sym = SYM_FIRST_ANOM;
- section_sym = 0;
- const_wanted = 0;
- nocode_wanted = 0x80000000;
+ vtop = vstack - 1;
+ memset(vtop, 0, sizeof *vtop);
/* define some often used types */
int_type.t = VT_INT;
- char_pointer_type.t = VT_BYTE;
+
+ char_type.t = VT_BYTE;
+ if (s1->char_is_unsigned)
+ char_type.t |= VT_UNSIGNED;
+ char_pointer_type = char_type;
mk_pointer(&char_pointer_type);
-#if PTR_SIZE == 4
- size_type.t = VT_INT | VT_UNSIGNED;
- ptrdiff_type.t = VT_INT;
-#elif LONG_SIZE == 4
- size_type.t = VT_LLONG | VT_UNSIGNED;
- ptrdiff_type.t = VT_LLONG;
-#else
- size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED;
- ptrdiff_type.t = VT_LONG | VT_LLONG;
-#endif
+
func_old_type.t = VT_FUNC;
func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);
func_old_type.ref->f.func_call = FUNC_CDECL;
func_old_type.ref->f.func_type = FUNC_OLD;
+#ifdef precedence_parser
+ init_prec();
+#endif
+ cstr_new(&initstr);
+}
- tcc_debug_start(s1);
+ST_FUNC int tccgen_compile(TCCState *s1)
+{
+ cur_text_section = NULL;
+ funcname = "";
+ anon_sym = SYM_FIRST_ANOM;
+ section_sym = 0;
+ const_wanted = 0;
+ nocode_wanted = 0x80000000;
+ local_scope = 0;
+ tcc_debug_start(s1);
#ifdef TCC_TARGET_ARM
arm_init(s1);
#endif
-
#ifdef INC_DEBUG
printf("%s: **** new file\n", file->filename);
#endif
-
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
next();
decl(VT_CONST);
@@ -280,6 +817,19 @@ ST_FUNC int tccgen_compile(TCCState *s1)
return 0;
}
+ST_FUNC void tccgen_finish(TCCState *s1)
+{
+ cstr_free(&initstr);
+ free_inline_functions(s1);
+ sym_pop(&global_stack, NULL, 0);
+ sym_pop(&local_stack, NULL, 0);
+ /* free preprocessor macros */
+ free_defines(NULL);
+ /* free sym_pools */
+ dynarray_reset(&sym_pools, &nb_sym_pools);
+ sym_free_first = NULL;
+}
+
/* ------------------------------------------------------------------------- */
ST_FUNC ElfSym *elfsym(Sym *s)
{
@@ -302,7 +852,7 @@ ST_FUNC void update_storage(Sym *sym)
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
| sym->a.visibility;
- if (sym->type.t & VT_STATIC)
+ if (sym->type.t & (VT_STATIC | VT_INLINE))
sym_bind = STB_LOCAL;
else if (sym->a.weak)
sym_bind = STB_WEAK;
@@ -343,39 +893,9 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
ElfSym *esym;
const char *name;
char buf1[256];
-#ifdef CONFIG_TCC_BCHECK
- char buf[32];
-#endif
if (!sym->c) {
name = get_tok_str(sym->v, NULL);
-#ifdef CONFIG_TCC_BCHECK
- if (tcc_state->do_bounds_check) {
- /* XXX: avoid doing that for statics ? */
- /* if bound checking is activated, we change some function
- names by adding the "__bound" prefix */
- switch(sym->v) {
-#ifdef TCC_TARGET_PE
- /* XXX: we rely only on malloc hooks */
- case TOK_malloc:
- case TOK_free:
- case TOK_realloc:
- case TOK_memalign:
- case TOK_calloc:
-#endif
- case TOK_memcpy:
- case TOK_memmove:
- case TOK_memset:
- case TOK_strlen:
- case TOK_strcpy:
- case TOK_alloca:
- strcpy(buf, "__bound_");
- strcat(buf, name);
- name = buf;
- break;
- }
- }
-#endif
t = sym->type.t;
if ((t & VT_BTYPE) == VT_FUNC) {
sym_type = STT_FUNC;
@@ -384,14 +904,18 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
} else {
sym_type = STT_OBJECT;
}
- if (t & VT_STATIC)
+ if (t & (VT_STATIC | VT_INLINE))
sym_bind = STB_LOCAL;
else
sym_bind = STB_GLOBAL;
other = 0;
+
#ifdef TCC_TARGET_PE
if (sym_type == STT_FUNC && sym->type.ref) {
Sym *ref = sym->type.ref;
+ if (ref->a.nodecorate) {
+ can_add_underscore = 0;
+ }
if (ref->f.func_call == FUNC_STDCALL && can_add_underscore) {
sprintf(buf1, "_%s@%d", name, ref->f.func_args * PTR_SIZE);
name = buf1;
@@ -400,15 +924,28 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
}
}
#endif
+
+ if (sym->asm_label) {
+ name = get_tok_str(sym->asm_label & ~SYM_FIELD, NULL);
+ /* with SYM_FIELD it was __attribute__((alias("..."))) actually */
+ if (!(sym->asm_label & SYM_FIELD))
+ can_add_underscore = 0;
+ }
+
if (tcc_state->leading_underscore && can_add_underscore) {
buf1[0] = '_';
pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
name = buf1;
}
- if (sym->asm_label)
- name = get_tok_str(sym->asm_label, NULL);
+
info = ELFW(ST_INFO)(sym_bind, sym_type);
sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name);
+
+ if (tcc_state->do_debug
+ && sym_type != STT_FUNC
+ && sym->v < SYM_FIRST_ANOM)
+ tcc_debug_extern_sym(tcc_state, sym, sh_num, sym_bind);
+
} else {
esym = elfsym(sym);
esym->st_value = value;
@@ -545,6 +1082,14 @@ ST_INLN Sym *sym_find(int v)
return table_ident[v]->sym_identifier;
}
+static int sym_scope(Sym *s)
+{
+ if (IS_ENUM_VAL (s->type.t))
+ return s->type.ref->sym_scope;
+ else
+ return s->sym_scope;
+}
+
/* push a given symbol on the symbol stack */
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
{
@@ -570,7 +1115,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
s->prev_tok = *ps;
*ps = s;
s->sym_scope = local_scope;
- if (s->prev_tok && s->prev_tok->sym_scope == s->sym_scope)
+ if (s->prev_tok && sym_scope(s->prev_tok) == s->sym_scope)
tcc_error("redeclaration of '%s'",
get_tok_str(v & ~SYM_STRUCT, NULL));
}
@@ -582,11 +1127,12 @@ ST_FUNC Sym *global_identifier_push(int v, int t, int c)
{
Sym *s, **ps;
s = sym_push2(&global_stack, v, t, c);
+ s->r = VT_CONST | VT_SYM;
/* don't record anonymous symbol */
if (v < SYM_FIRST_ANOM) {
ps = &table_ident[v - TOK_IDENT]->sym_identifier;
- /* modify the top most local identifier, so that
- sym_identifier will point to 's' when popped */
+ /* modify the top most local identifier, so that sym_identifier will
+ point to 's' when popped; happens when called from inline asm */
while (*ps != NULL && (*ps)->sym_scope)
ps = &(*ps)->prev_tok;
s->prev_tok = *ps;
@@ -626,13 +1172,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
}
/* ------------------------------------------------------------------------- */
-
-static void vsetc(CType *type, int r, CValue *vc)
+static void vcheck_cmp(void)
{
- int v;
-
- if (vtop >= vstack + (VSTACK_SIZE - 1))
- tcc_error("memory full (vstack)");
/* cannot let cpu flags if other instruction are generated. Also
avoid leaving VT_JMP anywhere except on the top of the stack
because it would complicate the code generator.
@@ -643,15 +1184,17 @@ static void vsetc(CType *type, int r, CValue *vc)
as their value might still be used for real. All values
we push under nocode_wanted will eventually be popped
again, so that the VT_CMP/VT_JMP value will be in vtop
- when code is unsuppressed again.
+ when code is unsuppressed again. */
- Same logic below in vswap(); */
- if (vtop >= vstack && !nocode_wanted) {
- v = vtop->r & VT_VALMASK;
- if (v == VT_CMP || (v & ~1) == VT_JMP)
- gv(RC_INT);
- }
+ if (vtop->r == VT_CMP && !nocode_wanted)
+ gv(RC_INT);
+}
+static void vsetc(CType *type, int r, CValue *vc)
+{
+ if (vtop >= vstack + (VSTACK_SIZE - 1))
+ tcc_error("memory full (vstack)");
+ vcheck_cmp();
vtop++;
vtop->type = *type;
vtop->r = r;
@@ -663,12 +1206,8 @@ static void vsetc(CType *type, int r, CValue *vc)
ST_FUNC void vswap(void)
{
SValue tmp;
- /* cannot vswap cpu flags. See comment at vsetc() above */
- if (vtop >= vstack && !nocode_wanted) {
- int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP || (v & ~1) == VT_JMP)
- gv(RC_INT);
- }
+
+ vcheck_cmp();
tmp = vtop[0];
vtop[0] = vtop[-1];
vtop[-1] = tmp;
@@ -685,44 +1224,41 @@ ST_FUNC void vpop(void)
o(0xd8dd); /* fstp %st(0) */
} else
#endif
- if (v == VT_JMP || v == VT_JMPI) {
+ if (v == VT_CMP) {
/* need to put correct jump if && or || without test */
- gsym(vtop->c.i);
+ gsym(vtop->jtrue);
+ gsym(vtop->jfalse);
}
vtop--;
}
/* push constant of type "type" with useless value */
-ST_FUNC void vpush(CType *type)
+static void vpush(CType *type)
{
vset(type, VT_CONST, 0);
}
-/* push integer constant */
-ST_FUNC void vpushi(int v)
+/* push arbitrary 64bit constant */
+static void vpush64(int ty, unsigned long long v)
{
CValue cval;
+ CType ctype;
+ ctype.t = ty;
+ ctype.ref = NULL;
cval.i = v;
- vsetc(&int_type, VT_CONST, &cval);
+ vsetc(&ctype, VT_CONST, &cval);
}
-/* push a pointer sized constant */
-static void vpushs(addr_t v)
+/* push integer constant */
+ST_FUNC void vpushi(int v)
{
- CValue cval;
- cval.i = v;
- vsetc(&size_type, VT_CONST, &cval);
+ vpush64(VT_INT, v);
}
-/* push arbitrary 64bit constant */
-ST_FUNC void vpush64(int ty, unsigned long long v)
+/* push a pointer sized constant */
+static void vpushs(addr_t v)
{
- CValue cval;
- CType ctype;
- ctype.t = ty;
- ctype.ref = NULL;
- cval.i = v;
- vsetc(&ctype, VT_CONST, &cval);
+ vpush64(VT_SIZE_T, v);
}
/* push long long constant */
@@ -734,7 +1270,6 @@ static inline void vpushll(long long v)
ST_FUNC void vset(CType *type, int r, int v)
{
CValue cval;
-
cval.i = v;
vsetc(type, r, &cval);
}
@@ -768,6 +1303,7 @@ ST_FUNC void vrotb(int n)
int i;
SValue tmp;
+ vcheck_cmp();
tmp = vtop[-n + 1];
for(i=-n+1;i!=0;i++)
vtop[i] = vtop[i+1];
@@ -782,6 +1318,7 @@ ST_FUNC void vrote(SValue *e, int n)
int i;
SValue tmp;
+ vcheck_cmp();
tmp = *e;
for(i = 0;i < n - 1; i++)
e[-i] = e[-i - 1];
@@ -796,6 +1333,94 @@ ST_FUNC void vrott(int n)
vrote(vtop, n);
}
+/* ------------------------------------------------------------------------- */
+/* vtop->r = VT_CMP means CPU-flags have been set from comparison or test. */
+
+/* called from generators to set the result from relational ops */
+ST_FUNC void vset_VT_CMP(int op)
+{
+ vtop->r = VT_CMP;
+ vtop->cmp_op = op;
+ vtop->jfalse = 0;
+ vtop->jtrue = 0;
+}
+
+/* called once before asking generators to load VT_CMP to a register */
+static void vset_VT_JMP(void)
+{
+ int op = vtop->cmp_op;
+
+ if (vtop->jtrue || vtop->jfalse) {
+ /* we need to jump to 'mov $0,%R' or 'mov $1,%R' */
+ int inv = op & (op < 2); /* small optimization */
+ vseti(VT_JMP+inv, gvtst(inv, 0));
+ } else {
+ /* otherwise convert flags (rsp. 0/1) to register */
+ vtop->c.i = op;
+ if (op < 2) /* doesn't seem to happen */
+ vtop->r = VT_CONST;
+ }
+}
+
+/* Set CPU Flags, doesn't yet jump */
+static void gvtst_set(int inv, int t)
+{
+ int *p;
+
+ if (vtop->r != VT_CMP) {
+ vpushi(0);
+ gen_op(TOK_NE);
+ if (vtop->r != VT_CMP) /* must be VT_CONST then */
+ vset_VT_CMP(vtop->c.i != 0);
+ }
+
+ p = inv ? &vtop->jfalse : &vtop->jtrue;
+ *p = gjmp_append(*p, t);
+}
+
+/* Generate value test
+ *
+ * Generate a test for any value (jump, comparison and integers) */
+static int gvtst(int inv, int t)
+{
+ int op, x, u;
+
+ gvtst_set(inv, t);
+ t = vtop->jtrue, u = vtop->jfalse;
+ if (inv)
+ x = u, u = t, t = x;
+ op = vtop->cmp_op;
+
+ /* jump to the wanted target */
+ if (op > 1)
+ t = gjmp_cond(op ^ inv, t);
+ else if (op != inv)
+ t = gjmp(t);
+ /* resolve complementary jumps to here */
+ gsym(u);
+
+ vtop--;
+ return t;
+}
+
+/* generate a zero or nozero test */
+static void gen_test_zero(int op)
+{
+ if (vtop->r == VT_CMP) {
+ int j;
+ if (op == TOK_EQ) {
+ j = vtop->jfalse;
+ vtop->jfalse = vtop->jtrue;
+ vtop->jtrue = j;
+ vtop->cmp_op ^= 1;
+ }
+ } else {
+ vpushi(0);
+ gen_op(op);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
/* push a symbol value of TYPE */
static inline void vpushsym(CType *type, Sym *sym)
{
@@ -812,9 +1437,8 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
Sym *sym;
v = anon_sym++;
- sym = global_identifier_push(v, type->t | VT_STATIC, 0);
- sym->type.ref = type->ref;
- sym->r = VT_CONST | VT_SYM;
+ sym = sym_push(v, type, VT_CONST | VT_SYM, 0);
+ sym->type.t |= VT_STATIC;
put_extern_sym(sym, sec, offset, size);
return sym;
}
@@ -826,7 +1450,7 @@ static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned
}
/* define a new external reference to a symbol 'v' of type 'u' */
-ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
+ST_FUNC Sym *external_global_sym(int v, CType *type)
{
Sym *s;
@@ -835,7 +1459,6 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
/* push forward reference */
s = global_identifier_push(v, type->t | VT_EXTERN, 0);
s->type.ref = type->ref;
- s->r = r | VT_CONST | VT_SYM;
} else if (IS_ASM_SYM(s)) {
s->type.t = type->t | (s->type.t & VT_EXTERN);
s->type.ref = type->ref;
@@ -844,10 +1467,62 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
return s;
}
+/* Merge symbol attributes. */
+static void merge_symattr(struct SymAttr *sa, struct SymAttr *sa1)
+{
+ if (sa1->aligned && !sa->aligned)
+ sa->aligned = sa1->aligned;
+ sa->packed |= sa1->packed;
+ sa->weak |= sa1->weak;
+ if (sa1->visibility != STV_DEFAULT) {
+ int vis = sa->visibility;
+ if (vis == STV_DEFAULT
+ || vis > sa1->visibility)
+ vis = sa1->visibility;
+ sa->visibility = vis;
+ }
+ sa->dllexport |= sa1->dllexport;
+ sa->nodecorate |= sa1->nodecorate;
+ sa->dllimport |= sa1->dllimport;
+}
+
+/* Merge function attributes. */
+static void merge_funcattr(struct FuncAttr *fa, struct FuncAttr *fa1)
+{
+ if (fa1->func_call && !fa->func_call)
+ fa->func_call = fa1->func_call;
+ if (fa1->func_type && !fa->func_type)
+ fa->func_type = fa1->func_type;
+ if (fa1->func_args && !fa->func_args)
+ fa->func_args = fa1->func_args;
+ if (fa1->func_noreturn)
+ fa->func_noreturn = 1;
+ if (fa1->func_ctor)
+ fa->func_ctor = 1;
+ if (fa1->func_dtor)
+ fa->func_dtor = 1;
+ if (fa1->no_bcheck)
+ fa->no_bcheck = 1;
+}
+
+/* Merge attributes. */
+static void merge_attr(AttributeDef *ad, AttributeDef *ad1)
+{
+ merge_symattr(&ad->a, &ad1->a);
+ merge_funcattr(&ad->f, &ad1->f);
+
+ if (ad1->section)
+ ad->section = ad1->section;
+ if (ad1->asm_label)
+ ad->asm_label = ad1->asm_label;
+ if (ad1->attr_mode)
+ ad->attr_mode = ad1->attr_mode;
+}
+
/* Merge some type attributes. */
static void patch_type(Sym *sym, CType *type)
{
- if (!(type->t & VT_EXTERN)) {
+ if (!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t)) {
if (!(sym->type.t & VT_EXTERN))
tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
sym->type.t &= ~VT_EXTERN;
@@ -866,25 +1541,40 @@ static void patch_type(Sym *sym, CType *type)
} else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
int static_proto = sym->type.t & VT_STATIC;
/* warn if static follows non-static function declaration */
- if ((type->t & VT_STATIC) && !static_proto && !(type->t & VT_INLINE))
+ if ((type->t & VT_STATIC) && !static_proto
+ /* XXX this test for inline shouldn't be here. Until we
+ implement gnu-inline mode again it silences a warning for
+ mingw caused by our workarounds. */
+ && !((type->t | sym->type.t) & VT_INLINE))
tcc_warning("static storage ignored for redefinition of '%s'",
get_tok_str(sym->v, NULL));
+ /* set 'inline' if both agree or if one has static */
+ if ((type->t | sym->type.t) & VT_INLINE) {
+ if (!((type->t ^ sym->type.t) & VT_INLINE)
+ || ((type->t | sym->type.t) & VT_STATIC))
+ static_proto |= VT_INLINE;
+ }
+
if (0 == (type->t & VT_EXTERN)) {
+ struct FuncAttr f = sym->type.ref->f;
/* put complete type, use static from prototype */
- sym->type.t = (type->t & ~VT_STATIC) | static_proto;
- if (type->t & VT_INLINE)
- sym->type.t = type->t;
+ sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto;
+ sym->type.ref = type->ref;
+ merge_funcattr(&sym->type.ref->f, &f);
+ } else {
+ sym->type.t &= ~VT_INLINE | static_proto;
+ }
+
+ if (sym->type.ref->f.func_type == FUNC_OLD
+ && type->ref->f.func_type != FUNC_OLD) {
sym->type.ref = type->ref;
}
} else {
if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) {
/* set array size if it was omitted in extern declaration */
- if (sym->type.ref->c < 0)
- sym->type.ref->c = type->ref->c;
- else if (sym->type.ref->c != type->ref->c)
- tcc_error("conflicting type for '%s'", get_tok_str(sym->v, NULL));
+ sym->type.ref->c = type->ref->c;
}
if ((type->t ^ sym->type.t) & VT_STATIC)
tcc_warning("storage mismatch for redefinition of '%s'",
@@ -892,7 +1582,6 @@ static void patch_type(Sym *sym, CType *type)
}
}
-
/* Merge some storage attributes. */
static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
{
@@ -903,51 +1592,73 @@ static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
if (sym->a.dllimport != ad->a.dllimport)
tcc_error("incompatible dll linkage for redefinition of '%s'",
get_tok_str(sym->v, NULL));
- sym->a.dllexport |= ad->a.dllexport;
#endif
- sym->a.weak |= ad->a.weak;
- if (ad->a.visibility) {
- int vis = sym->a.visibility;
- int vis2 = ad->a.visibility;
- if (vis == STV_DEFAULT)
- vis = vis2;
- else if (vis2 != STV_DEFAULT)
- vis = (vis < vis2) ? vis : vis2;
- sym->a.visibility = vis;
- }
- if (ad->a.aligned)
- sym->a.aligned = ad->a.aligned;
+ merge_symattr(&sym->a, &ad->a);
if (ad->asm_label)
sym->asm_label = ad->asm_label;
update_storage(sym);
}
+/* copy sym to other stack */
+static Sym *sym_copy(Sym *s0, Sym **ps)
+{
+ Sym *s;
+ s = sym_malloc(), *s = *s0;
+ s->prev = *ps, *ps = s;
+ if (s->v < SYM_FIRST_ANOM) {
+ ps = &table_ident[s->v - TOK_IDENT]->sym_identifier;
+ s->prev_tok = *ps, *ps = s;
+ }
+ return s;
+}
+
+/* copy s->type.ref to stack 'ps' for VT_FUNC and VT_PTR */
+static void sym_copy_ref(Sym *s, Sym **ps)
+{
+ int bt = s->type.t & VT_BTYPE;
+ if (bt == VT_FUNC || bt == VT_PTR) {
+ Sym **sp = &s->type.ref;
+ for (s = *sp, *sp = NULL; s; s = s->next) {
+ Sym *s2 = sym_copy(s, ps);
+ sp = &(*sp = s2)->next;
+ sym_copy_ref(s2, ps);
+ }
+ }
+}
+
/* define a new external reference to a symbol 'v' */
static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
{
Sym *s;
+
+ /* look for global symbol */
s = sym_find(v);
+ while (s && s->sym_scope)
+ s = s->prev_tok;
+
if (!s) {
/* push forward reference */
- s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
- s->type.t |= VT_EXTERN;
+ s = global_identifier_push(v, type->t, 0);
+ s->r |= r;
s->a = ad->a;
- s->sym_scope = 0;
+ s->asm_label = ad->asm_label;
+ s->type.ref = type->ref;
+ /* copy type to the global stack */
+ if (local_stack)
+ sym_copy_ref(s, &global_stack);
} else {
- if (s->type.ref == func_old_type.ref) {
- s->type.ref = type->ref;
- s->r = r | VT_CONST | VT_SYM;
- s->type.t |= VT_EXTERN;
- }
patch_storage(s, ad, type);
}
+ /* push variables on local_stack if any */
+ if (local_stack && (s->type.t & VT_BTYPE) != VT_FUNC)
+ s = sym_copy(s, &local_stack);
return s;
}
/* push a reference to global symbol v */
ST_FUNC void vpush_global_sym(CType *type, int v)
{
- vpushsym(type, external_global_sym(v, type, 0));
+ vpushsym(type, external_global_sym(v, type));
}
/* save registers up to (vtop - n) stack entry */
@@ -968,55 +1679,40 @@ ST_FUNC void save_reg(int r)
if seen up to (vtop - n) stack entry */
ST_FUNC void save_reg_upstack(int r, int n)
{
- int l, saved, size, align;
+ int l, size, align, bt;
SValue *p, *p1, sv;
- CType *type;
if ((r &= VT_VALMASK) >= VT_CONST)
return;
if (nocode_wanted)
return;
-
- /* modify all stack values */
- saved = 0;
l = 0;
for(p = vstack, p1 = vtop - n; p <= p1; p++) {
- if ((p->r & VT_VALMASK) == r ||
- ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) {
+ if ((p->r & VT_VALMASK) == r || p->r2 == r) {
/* must save value on stack if not already done */
- if (!saved) {
- /* NOTE: must reload 'r' because r might be equal to r2 */
- r = p->r & VT_VALMASK;
- /* store register in the stack */
- type = &p->type;
- if ((p->r & VT_LVAL) ||
- (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
-#if PTR_SIZE == 8
- type = &char_pointer_type;
-#else
- type = &int_type;
-#endif
- size = type_size(type, &align);
- loc = (loc - size) & -align;
- sv.type.t = type->t;
+ if (!l) {
+ bt = p->type.t & VT_BTYPE;
+ if (bt == VT_VOID)
+ continue;
+ if ((p->r & VT_LVAL) || bt == VT_FUNC)
+ bt = VT_PTR;
+ sv.type.t = bt;
+ size = type_size(&sv.type, &align);
+ l = get_temp_local_var(size,align);
sv.r = VT_LOCAL | VT_LVAL;
- sv.c.i = loc;
- store(r, &sv);
+ sv.c.i = l;
+ store(p->r & VT_VALMASK, &sv);
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
/* x86 specific: need to pop fp register ST0 if saved */
if (r == TREG_ST0) {
o(0xd8dd); /* fstp %st(0) */
}
#endif
-#if PTR_SIZE == 4
/* special long long case */
- if ((type->t & VT_BTYPE) == VT_LLONG) {
- sv.c.i += 4;
+ if (p->r2 < VT_CONST && USING_TWO_WORDS(bt)) {
+ sv.c.i += PTR_SIZE;
store(p->r2, &sv);
}
-#endif
- l = loc;
- saved = 1;
}
/* mark that stack entry as being saved on the stack */
if (p->r & VT_LVAL) {
@@ -1025,7 +1721,7 @@ ST_FUNC void save_reg_upstack(int r, int n)
p->c.i */
p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
} else {
- p->r = lvalue_type(p->type.t) | VT_LOCAL;
+ p->r = VT_LVAL | VT_LOCAL;
}
p->r2 = VT_CONST;
p->c.i = l;
@@ -1047,7 +1743,7 @@ ST_FUNC int get_reg_ex(int rc, int rc2)
n=0;
for(p = vstack; p <= vtop; p++) {
if ((p->r & VT_VALMASK) == r ||
- (p->r2 & VT_VALMASK) == r)
+ p->r2 == r)
n++;
}
if (n <= 1)
@@ -1071,7 +1767,7 @@ ST_FUNC int get_reg(int rc)
return r;
for(p=vstack;p<=vtop;p++) {
if ((p->r & VT_VALMASK) == r ||
- (p->r2 & VT_VALMASK) == r)
+ p->r2 == r)
goto notfound;
}
return r;
@@ -1084,7 +1780,7 @@ ST_FUNC int get_reg(int rc)
spill registers used in gen_opi()) */
for(p=vstack;p<=vtop;p++) {
/* look at second register (if long long) */
- r = p->r2 & VT_VALMASK;
+ r = p->r2;
if (r < VT_CONST && (reg_classes[r] & rc))
goto save_found;
r = p->r & VT_VALMASK;
@@ -1098,6 +1794,56 @@ ST_FUNC int get_reg(int rc)
return -1;
}
+/* find a free temporary local variable (return the offset on stack) match the size and align. If none, add new temporary stack variable*/
+static int get_temp_local_var(int size,int align){
+ int i;
+ struct temp_local_variable *temp_var;
+ int found_var;
+ SValue *p;
+ int r;
+ char free;
+ char found;
+ found=0;
+ for(i=0;i<nb_temp_local_vars;i++){
+ temp_var=&arr_temp_local_vars[i];
+ if(temp_var->size<size||align!=temp_var->align){
+ continue;
+ }
+ /*check if temp_var is free*/
+ free=1;
+ for(p=vstack;p<=vtop;p++) {
+ r=p->r&VT_VALMASK;
+ if(r==VT_LOCAL||r==VT_LLOCAL){
+ if(p->c.i==temp_var->location){
+ free=0;
+ break;
+ }
+ }
+ }
+ if(free){
+ found_var=temp_var->location;
+ found=1;
+ break;
+ }
+ }
+ if(!found){
+ loc = (loc - size) & -align;
+ if(nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER){
+ temp_var=&arr_temp_local_vars[i];
+ temp_var->location=loc;
+ temp_var->size=size;
+ temp_var->align=align;
+ nb_temp_local_vars++;
+ }
+ found_var=loc;
+ }
+ return found_var;
+}
+
+static void clear_temp_local_var_list(){
+ nb_temp_local_vars=0;
+}
+
/* move register 's' (of type 't') to 'r', and flush previous value of r to memory
if needed */
static void move_reg(int r, int s, int t)
@@ -1120,16 +1866,67 @@ ST_FUNC void gaddrof(void)
vtop->r &= ~VT_LVAL;
/* tricky: if saved lvalue, then we can go back to lvalue */
if ((vtop->r & VT_VALMASK) == VT_LLOCAL)
- vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL;
+ vtop->r = (vtop->r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
+}
+
+#ifdef CONFIG_TCC_BCHECK
+/* generate a bounded pointer addition */
+static void gen_bounded_ptr_add(void)
+{
+ int save = (vtop[-1].r & VT_VALMASK) == VT_LOCAL;
+ if (save) {
+ vpushv(&vtop[-1]);
+ vrott(3);
+ }
+ vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
+ vrott(3);
+ gfunc_call(2);
+ vtop -= save;
+ vpushi(0);
+ /* returned pointer is in REG_IRET */
+ vtop->r = REG_IRET | VT_BOUNDED;
+ if (nocode_wanted)
+ return;
+ /* relocation offset of the bounding function call point */
+ vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW_Rel));
+}
+/* patch pointer addition in vtop so that pointer dereferencing is
+ also tested */
+static void gen_bounded_ptr_deref(void)
+{
+ addr_t func;
+ int size, align;
+ ElfW_Rel *rel;
+ Sym *sym;
+
+ if (nocode_wanted)
+ return;
+ size = type_size(&vtop->type, &align);
+ switch(size) {
+ case 1: func = TOK___bound_ptr_indir1; break;
+ case 2: func = TOK___bound_ptr_indir2; break;
+ case 4: func = TOK___bound_ptr_indir4; break;
+ case 8: func = TOK___bound_ptr_indir8; break;
+ case 12: func = TOK___bound_ptr_indir12; break;
+ case 16: func = TOK___bound_ptr_indir16; break;
+ default:
+ /* may happen with struct member access */
+ return;
+ }
+ sym = external_global_sym(func, &func_old_type);
+ if (!sym->c)
+ put_extern_sym(sym, NULL, 0, 0);
+ /* patch relocation */
+ /* XXX: find a better solution ? */
+ rel = (ElfW_Rel *)(cur_text_section->reloc->data + vtop->c.i);
+ rel->r_info = ELFW(R_INFO)(sym->c, ELFW(R_TYPE)(rel->r_info));
}
-#ifdef CONFIG_TCC_BCHECK
/* generate lvalue bound code */
static void gbound(void)
{
- int lval_type;
CType type1;
vtop->r &= ~VT_MUSTBOUND;
@@ -1137,32 +1934,97 @@ static void gbound(void)
if (vtop->r & VT_LVAL) {
/* if not VT_BOUNDED value, then make one */
if (!(vtop->r & VT_BOUNDED)) {
- lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
/* must save type because we must set it to int to get pointer */
type1 = vtop->type;
vtop->type.t = VT_PTR;
gaddrof();
vpushi(0);
gen_bounded_ptr_add();
- vtop->r |= lval_type;
+ vtop->r |= VT_LVAL;
vtop->type = type1;
}
/* then check for dereferencing */
gen_bounded_ptr_deref();
}
}
+
+/* we need to call __bound_ptr_add before we start to load function
+ args into registers */
+ST_FUNC void gbound_args(int nb_args)
+{
+ int i, v;
+ SValue *sv;
+
+ for (i = 1; i <= nb_args; ++i)
+ if (vtop[1 - i].r & VT_MUSTBOUND) {
+ vrotb(i);
+ gbound();
+ vrott(i);
+ }
+
+ sv = vtop - nb_args;
+ if (sv->r & VT_SYM) {
+ v = sv->sym->v;
+ if (v == TOK_setjmp
+ || v == TOK__setjmp
+#ifndef TCC_TARGET_PE
+ || v == TOK_sigsetjmp
+ || v == TOK___sigsetjmp
+#endif
+ ) {
+ vpush_global_sym(&func_old_type, TOK___bound_setjmp);
+ vpushv(sv + 1);
+ gfunc_call(1);
+ func_bound_add_epilog = 1;
+ }
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
+ if (v == TOK_alloca)
+ func_bound_add_epilog = 1;
+#endif
+ }
+}
+
+/* Add bounds for local symbols from S to E (via ->prev) */
+static void add_local_bounds(Sym *s, Sym *e)
+{
+ for (; s != e; s = s->prev) {
+ if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
+ continue;
+ /* Add arrays/structs/unions because we always take address */
+ if ((s->type.t & VT_ARRAY)
+ || (s->type.t & VT_BTYPE) == VT_STRUCT
+ || s->a.addrtaken) {
+ /* add local bound info */
+ int align, size = type_size(&s->type, &align);
+ addr_t *bounds_ptr = section_ptr_add(lbounds_section,
+ 2 * sizeof(addr_t));
+ bounds_ptr[0] = s->c;
+ bounds_ptr[1] = size;
+ }
+ }
+}
+#endif
+
+/* Wrapper around sym_pop, that potentially also registers local bounds. */
+static void pop_local_syms(Sym **ptop, Sym *b, int keep, int ellipsis)
+{
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check && !ellipsis && !keep)
+ add_local_bounds(*ptop, b);
#endif
+ if (tcc_state->do_debug)
+ tcc_add_debug_info (tcc_state, !local_scope, *ptop, b);
+ sym_pop(ptop, b, keep);
+}
static void incr_bf_adr(int o)
{
vtop->type = char_pointer_type;
gaddrof();
- vpushi(o);
+ vpushs(o);
gen_op('+');
- vtop->type.t = (vtop->type.t & ~(VT_BTYPE|VT_DEFSIGN))
- | (VT_BYTE|VT_UNSIGNED);
- vtop->r = (vtop->r & ~VT_LVAL_TYPE)
- | (VT_LVAL_BYTE|VT_LVAL_UNSIGNED|VT_LVAL);
+ vtop->type.t = VT_BYTE | VT_UNSIGNED;
+ vtop->r |= VT_LVAL;
}
/* single-byte load mode for packed or otherwise unaligned bitfields */
@@ -1241,8 +2103,8 @@ static int adjust_bf(SValue *sv, int bit_pos, int bit_size)
return 0;
t = sv->type.ref->auxtype;
if (t != -1 && t != VT_STRUCT) {
- sv->type.t = (sv->type.t & ~VT_BTYPE) | t;
- sv->r = (sv->r & ~VT_LVAL_TYPE) | lvalue_type(sv->type.t);
+ sv->type.t = (sv->type.t & ~(VT_BTYPE | VT_LONG)) | t;
+ sv->r |= VT_LVAL;
}
return t;
}
@@ -1252,7 +2114,8 @@ static int adjust_bf(SValue *sv, int bit_pos, int bit_size)
register value (such as structures). */
ST_FUNC int gv(int rc)
{
- int r, bit_pos, bit_size, size, align, rc2;
+ int r, r2, r_ok, r2_ok, rc2, bt;
+ int bit_pos, bit_size, size, align;
/* NOTE: get_reg can modify vstack[] */
if (vtop->type.t & VT_BITFIELD) {
@@ -1309,80 +2172,61 @@ ST_FUNC int gv(int rc)
gbound();
#endif
- r = vtop->r & VT_VALMASK;
- rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT;
-#ifndef TCC_TARGET_ARM64
- if (rc == RC_IRET)
- rc2 = RC_LRET;
-#ifdef TCC_TARGET_X86_64
- else if (rc == RC_FRET)
- rc2 = RC_QRET;
-#endif
+ bt = vtop->type.t & VT_BTYPE;
+
+#ifdef TCC_TARGET_RISCV64
+ /* XXX mega hack */
+ if (bt == VT_LDOUBLE && rc == RC_FLOAT)
+ rc = RC_INT;
#endif
+ rc2 = RC2_TYPE(bt, rc);
+
/* need to reload if:
- constant
- lvalue (need to dereference pointer)
- already a register, but not in the right class */
- if (r >= VT_CONST
- || (vtop->r & VT_LVAL)
- || !(reg_classes[r] & rc)
-#if PTR_SIZE == 8
- || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2))
- || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2))
-#else
- || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2))
-#endif
- )
- {
- r = get_reg(rc);
-#if PTR_SIZE == 8
- if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) {
- int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
-#else
- if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
- int addr_type = VT_INT, load_size = 4, load_type = VT_INT;
- unsigned long long ll;
-#endif
- int r2, original_type;
- original_type = vtop->type.t;
- /* two register type load : expand to two words
- temporarily */
-#if PTR_SIZE == 4
+ r = vtop->r & VT_VALMASK;
+ r_ok = !(vtop->r & VT_LVAL) && (r < VT_CONST) && (reg_classes[r] & rc);
+ r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2));
+
+ if (!r_ok || !r2_ok) {
+ if (!r_ok)
+ r = get_reg(rc);
+ if (rc2) {
+ int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;
+ int original_type = vtop->type.t;
+
+ /* two register type load :
+ expand to two words temporarily */
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* load constant */
- ll = vtop->c.i;
+ unsigned long long ll = vtop->c.i;
vtop->c.i = ll; /* first word */
load(r, vtop);
vtop->r = r; /* save register value */
vpushi(ll >> 32); /* second word */
- } else
-#endif
- if (vtop->r & VT_LVAL) {
- /* We do not want to modifier the long long
- pointer here, so the safest (and less
- efficient) is to save all the other registers
- in the stack. XXX: totally inefficient. */
- #if 0
- save_regs(1);
- #else
- /* lvalue_save: save only if used further down the stack */
+ } else if (vtop->r & VT_LVAL) {
+ /* We do not want to modifier the long long pointer here.
+ So we save any other instances down the stack */
save_reg_upstack(vtop->r, 1);
- #endif
/* load from memory */
vtop->type.t = load_type;
load(r, vtop);
vdup();
vtop[-1].r = r; /* save register value */
/* increment pointer to get second word */
- vtop->type.t = addr_type;
+ vtop->type.t = VT_PTRDIFF_T;
gaddrof();
- vpushi(load_size);
+ vpushs(PTR_SIZE);
gen_op('+');
vtop->r |= VT_LVAL;
vtop->type.t = load_type;
} else {
/* move registers */
- load(r, vtop);
+ if (!r_ok)
+ load(r, vtop);
+ if (r2_ok && vtop->r2 < VT_CONST)
+ goto done;
vdup();
vtop[-1].r = r; /* save register value */
vtop->r = vtop[-1].r2;
@@ -1394,25 +2238,11 @@ ST_FUNC int gv(int rc)
vpop();
/* write second register */
vtop->r2 = r2;
+ done:
vtop->type.t = original_type;
- } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) {
- int t1, t;
- /* lvalue of scalar type : need to use lvalue type
- because of possible cast */
- t = vtop->type.t;
- t1 = t;
- /* compute memory access type */
- if (vtop->r & VT_LVAL_BYTE)
- t = VT_BYTE;
- else if (vtop->r & VT_LVAL_SHORT)
- t = VT_SHORT;
- if (vtop->r & VT_LVAL_UNSIGNED)
- t |= VT_UNSIGNED;
- vtop->type.t = t;
- load(r, vtop);
- /* restore wanted type */
- vtop->type.t = t1;
} else {
+ if (vtop->r == VT_CMP)
+ vset_VT_JMP();
/* one register type load */
load(r, vtop);
}
@@ -1420,7 +2250,7 @@ ST_FUNC int gv(int rc)
vtop->r = r;
#ifdef TCC_TARGET_C67
/* uses register pairs for doubles */
- if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
+ if (bt == VT_DOUBLE)
vtop->r2 = r+1;
#endif
}
@@ -1430,13 +2260,10 @@ ST_FUNC int gv(int rc)
/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */
ST_FUNC void gv2(int rc1, int rc2)
{
- int v;
-
/* generate more generic register first. But VT_JMP or VT_CMP
values must be generated first in all cases to avoid possible
reload errors */
- v = vtop[0].r & VT_VALMASK;
- if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) {
+ if (vtop->r != VT_CMP && rc1 <= rc2) {
vswap();
gv(rc1);
vswap();
@@ -1459,33 +2286,9 @@ ST_FUNC void gv2(int rc1, int rc2)
}
}
-#ifndef TCC_TARGET_ARM64
-/* wrapper around RC_FRET to return a register by type */
-static int rc_fret(int t)
-{
-#ifdef TCC_TARGET_X86_64
- if (t == VT_LDOUBLE) {
- return RC_ST0;
- }
-#endif
- return RC_FRET;
-}
-#endif
-
-/* wrapper around REG_FRET to return a register by type */
-static int reg_fret(int t)
-{
-#ifdef TCC_TARGET_X86_64
- if (t == VT_LDOUBLE) {
- return TREG_ST0;
- }
-#endif
- return REG_FRET;
-}
-
#if PTR_SIZE == 4
/* expand 64bit on stack in two ints */
-static void lexpand(void)
+ST_FUNC void lexpand(void)
{
int u, v;
u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED);
@@ -1506,34 +2309,6 @@ static void lexpand(void)
}
#endif
-#ifdef TCC_TARGET_ARM
-/* expand long long on stack */
-ST_FUNC void lexpand_nr(void)
-{
- int u,v;
-
- u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED);
- vdup();
- vtop->r2 = VT_CONST;
- vtop->type.t = VT_INT | u;
- v=vtop[-1].r & (VT_VALMASK | VT_LVAL);
- if (v == VT_CONST) {
- vtop[-1].c.i = vtop->c.i;
- vtop->c.i = vtop->c.i >> 32;
- vtop->r = VT_CONST;
- } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) {
- vtop->c.i += 4;
- vtop->r = vtop[-1].r;
- } else if (v > VT_CONST) {
- vtop--;
- lexpand();
- } else
- vtop->r = vtop[-1].r2;
- vtop[-1].r2 = VT_CONST;
- vtop[-1].type.t = VT_INT | u;
-}
-#endif
-
#if PTR_SIZE == 4
/* build a long long from two ints */
static void lbuild(int t)
@@ -1549,8 +2324,7 @@ static void lbuild(int t)
register */
static void gv_dup(void)
{
- int rc, t, r, r1;
- SValue sv;
+ int t, rc, r;
t = vtop->type.t;
#if PTR_SIZE == 4
@@ -1572,51 +2346,16 @@ static void gv_dup(void)
vswap();
lbuild(t);
vswap();
- } else
-#endif
- {
- /* duplicate value */
- rc = RC_INT;
- sv.type.t = VT_INT;
- if (is_float(t)) {
- rc = RC_FLOAT;
-#ifdef TCC_TARGET_X86_64
- if ((t & VT_BTYPE) == VT_LDOUBLE) {
- rc = RC_ST0;
- }
-#endif
- sv.type.t = t;
- }
- r = gv(rc);
- r1 = get_reg(rc);
- sv.r = r;
- sv.c.i = 0;
- load(r1, &sv); /* move r to r1 */
- vdup();
- /* duplicates value */
- if (r != r1)
- vtop->r = r1;
- }
-}
-
-/* Generate value test
- *
- * Generate a test for any value (jump, comparison and integers) */
-ST_FUNC int gvtst(int inv, int t)
-{
- int v = vtop->r & VT_VALMASK;
- if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) {
- vpushi(0);
- gen_op(TOK_NE);
- }
- if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- /* constant jmp optimization */
- if ((vtop->c.i != 0) != inv)
- t = gjmp(t);
- vtop--;
- return t;
+ return;
}
- return gtst(inv, t);
+#endif
+ /* duplicate value */
+ rc = RC_TYPE(t);
+ gv(rc);
+ r = get_reg(rc);
+ vdup();
+ load(r, vtop);
+ vtop->r = r;
}
#if PTR_SIZE == 4
@@ -1626,7 +2365,7 @@ static void gen_opl(int op)
int t, a, b, op1, c, i;
int func;
unsigned short reg_iret = REG_IRET;
- unsigned short reg_lret = REG_LRET;
+ unsigned short reg_lret = REG_IRE2;
SValue tmp;
switch(op) {
@@ -1803,6 +2542,7 @@ static void gen_opl(int op)
vtop[-1] = vtop[-2];
vtop[-2] = tmp;
/* stack: L1 L2 H1 H2 */
+ save_regs(4);
/* compare high */
op1 = op;
/* when values are equal, we need to compare low words. since
@@ -1824,8 +2564,8 @@ static void gen_opl(int op)
a = gvtst(1, 0);
if (op != TOK_EQ) {
/* generate non equal test */
- vpushi(TOK_NE);
- vtop->r = VT_CMP;
+ vpushi(0);
+ vset_VT_CMP(TOK_NE);
b = gvtst(0, 0);
}
}
@@ -1840,9 +2580,12 @@ static void gen_opl(int op)
else if (op1 == TOK_GE)
op1 = TOK_UGE;
gen_op(op1);
- a = gvtst(1, a);
- gsym(b);
- vseti(VT_JMPI, a);
+#if 0//def TCC_TARGET_I386
+ if (op == TOK_NE) { gsym(b); break; }
+ if (op == TOK_EQ) { gsym(a); break; }
+#endif
+ gvtst_set(1, a);
+ gvtst_set(0, b);
break;
}
}
@@ -1896,7 +2639,7 @@ static void gen_opic(int op)
case TOK_UMOD:
/* if division by zero, generate explicit division */
if (l2 == 0) {
- if (const_wanted)
+ if (const_wanted && !(nocode_wanted & unevalmask))
tcc_error("division by zero in constant");
goto general_case;
}
@@ -1937,7 +2680,7 @@ static void gen_opic(int op)
} else {
/* if commutative ops, put c2 as constant */
if (c1 && (op == '+' || op == '&' || op == '^' ||
- op == '|' || op == '*')) {
+ op == '|' || op == '*' || op == TOK_EQ || op == TOK_NE)) {
vswap();
c2 = c1; //c = c1, c1 = c2, c2 = c;
l2 = l1; //l = l1, l1 = l2, l2 = l;
@@ -2015,7 +2758,7 @@ static void gen_opif(int op)
{
int c1, c2;
SValue *v1, *v2;
-#if defined _MSC_VER && defined _AMD64_
+#if defined _MSC_VER && defined __x86_64__
/* avoid bad optimization with f1 -= f2 for f1:-0.0, f2:0.0 */
volatile
#endif
@@ -2049,9 +2792,10 @@ static void gen_opif(int op)
case '*': f1 *= f2; break;
case '/':
if (f2 == 0.0) {
- if (const_wanted)
- tcc_error("division by zero in constant");
- goto general_case;
+ /* If not in initializer we need to potentially generate
+ FP exceptions at runtime, otherwise we want to fold. */
+ if (!const_wanted)
+ goto general_case;
}
f1 /= f2;
break;
@@ -2074,6 +2818,160 @@ static void gen_opif(int op)
}
}
+/* print a type. If 'varstr' is not NULL, then the variable is also
+ printed in the type */
+/* XXX: union */
+/* XXX: add array and function pointers */
+static void type_to_str(char *buf, int buf_size,
+ CType *type, const char *varstr)
+{
+ int bt, v, t;
+ Sym *s, *sa;
+ char buf1[256];
+ const char *tstr;
+
+ t = type->t;
+ bt = t & VT_BTYPE;
+ buf[0] = '\0';
+
+ if (t & VT_EXTERN)
+ pstrcat(buf, buf_size, "extern ");
+ if (t & VT_STATIC)
+ pstrcat(buf, buf_size, "static ");
+ if (t & VT_TYPEDEF)
+ pstrcat(buf, buf_size, "typedef ");
+ if (t & VT_INLINE)
+ pstrcat(buf, buf_size, "inline ");
+ if (t & VT_VOLATILE)
+ pstrcat(buf, buf_size, "volatile ");
+ if (t & VT_CONSTANT)
+ pstrcat(buf, buf_size, "const ");
+
+ if (((t & VT_DEFSIGN) && bt == VT_BYTE)
+ || ((t & VT_UNSIGNED)
+ && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG)
+ && !IS_ENUM(t)
+ ))
+ pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed ");
+
+ buf_size -= strlen(buf);
+ buf += strlen(buf);
+
+ switch(bt) {
+ case VT_VOID:
+ tstr = "void";
+ goto add_tstr;
+ case VT_BOOL:
+ tstr = "_Bool";
+ goto add_tstr;
+ case VT_BYTE:
+ tstr = "char";
+ goto add_tstr;
+ case VT_SHORT:
+ tstr = "short";
+ goto add_tstr;
+ case VT_INT:
+ tstr = "int";
+ goto maybe_long;
+ case VT_LLONG:
+ tstr = "long long";
+ maybe_long:
+ if (t & VT_LONG)
+ tstr = "long";
+ if (!IS_ENUM(t))
+ goto add_tstr;
+ tstr = "enum ";
+ goto tstruct;
+ case VT_FLOAT:
+ tstr = "float";
+ goto add_tstr;
+ case VT_DOUBLE:
+ tstr = "double";
+ if (!(t & VT_LONG))
+ goto add_tstr;
+ case VT_LDOUBLE:
+ tstr = "long double";
+ add_tstr:
+ pstrcat(buf, buf_size, tstr);
+ break;
+ case VT_STRUCT:
+ tstr = "struct ";
+ if (IS_UNION(t))
+ tstr = "union ";
+ tstruct:
+ pstrcat(buf, buf_size, tstr);
+ v = type->ref->v & ~SYM_STRUCT;
+ if (v >= SYM_FIRST_ANOM)
+ pstrcat(buf, buf_size, "<anonymous>");
+ else
+ pstrcat(buf, buf_size, get_tok_str(v, NULL));
+ break;
+ case VT_FUNC:
+ s = type->ref;
+ buf1[0]=0;
+ if (varstr && '*' == *varstr) {
+ pstrcat(buf1, sizeof(buf1), "(");
+ pstrcat(buf1, sizeof(buf1), varstr);
+ pstrcat(buf1, sizeof(buf1), ")");
+ }
+ pstrcat(buf1, buf_size, "(");
+ sa = s->next;
+ while (sa != NULL) {
+ char buf2[256];
+ type_to_str(buf2, sizeof(buf2), &sa->type, NULL);
+ pstrcat(buf1, sizeof(buf1), buf2);
+ sa = sa->next;
+ if (sa)
+ pstrcat(buf1, sizeof(buf1), ", ");
+ }
+ if (s->f.func_type == FUNC_ELLIPSIS)
+ pstrcat(buf1, sizeof(buf1), ", ...");
+ pstrcat(buf1, sizeof(buf1), ")");
+ type_to_str(buf, buf_size, &s->type, buf1);
+ goto no_var;
+ case VT_PTR:
+ s = type->ref;
+ if (t & VT_ARRAY) {
+ if (varstr && '*' == *varstr)
+ snprintf(buf1, sizeof(buf1), "(%s)[%d]", varstr, s->c);
+ else
+ snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c);
+ type_to_str(buf, buf_size, &s->type, buf1);
+ goto no_var;
+ }
+ pstrcpy(buf1, sizeof(buf1), "*");
+ if (t & VT_CONSTANT)
+ pstrcat(buf1, buf_size, "const ");
+ if (t & VT_VOLATILE)
+ pstrcat(buf1, buf_size, "volatile ");
+ if (varstr)
+ pstrcat(buf1, sizeof(buf1), varstr);
+ type_to_str(buf, buf_size, &s->type, buf1);
+ goto no_var;
+ }
+ if (varstr) {
+ pstrcat(buf, buf_size, " ");
+ pstrcat(buf, buf_size, varstr);
+ }
+ no_var: ;
+}
+
+static void type_incompatibility_error(CType* st, CType* dt, const char* fmt)
+{
+ char buf1[256], buf2[256];
+ type_to_str(buf1, sizeof(buf1), st, NULL);
+ type_to_str(buf2, sizeof(buf2), dt, NULL);
+ tcc_error(fmt, buf1, buf2);
+}
+
+static void type_incompatibility_warning(CType* st, CType* dt, const char* fmt)
+{
+ char buf1[256], buf2[256];
+ type_to_str(buf1, sizeof(buf1), st, NULL);
+ type_to_str(buf2, sizeof(buf2), dt, NULL);
+ tcc_warning(fmt, buf1, buf2);
+}
+
static int pointed_size(CType *type)
{
int align;
@@ -2093,68 +2991,216 @@ static inline int is_null_pointer(SValue *p)
return ((p->type.t & VT_BTYPE) == VT_INT && (uint32_t)p->c.i == 0) ||
((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) ||
((p->type.t & VT_BTYPE) == VT_PTR &&
- (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0));
+ (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0) &&
+ ((pointed_type(&p->type)->t & VT_BTYPE) == VT_VOID) &&
+ 0 == (pointed_type(&p->type)->t & (VT_CONSTANT | VT_VOLATILE))
+ );
}
-static inline int is_integer_btype(int bt)
+/* compare function types. OLD functions match any new functions */
+static int is_compatible_func(CType *type1, CType *type2)
{
- return (bt == VT_BYTE || bt == VT_SHORT ||
- bt == VT_INT || bt == VT_LLONG);
+ Sym *s1, *s2;
+
+ s1 = type1->ref;
+ s2 = type2->ref;
+ if (s1->f.func_call != s2->f.func_call)
+ return 0;
+ if (s1->f.func_type != s2->f.func_type
+ && s1->f.func_type != FUNC_OLD
+ && s2->f.func_type != FUNC_OLD)
+ return 0;
+ /* we should check the function return type for FUNC_OLD too
+ but that causes problems with the internally used support
+ functions such as TOK_memmove */
+ if (s1->f.func_type == FUNC_OLD && !s1->next)
+ return 1;
+ if (s2->f.func_type == FUNC_OLD && !s2->next)
+ return 1;
+ for (;;) {
+ if (!is_compatible_unqualified_types(&s1->type, &s2->type))
+ return 0;
+ s1 = s1->next;
+ s2 = s2->next;
+ if (!s1)
+ return !s2;
+ if (!s2)
+ return 0;
+ }
}
-/* check types for comparison or subtraction of pointers */
-static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
+/* return true if type1 and type2 are the same. If unqualified is
+ true, qualifiers on the types are ignored.
+ */
+static int compare_types(CType *type1, CType *type2, int unqualified)
{
- CType *type1, *type2, tmp_type1, tmp_type2;
- int bt1, bt2;
-
- /* null pointers are accepted for all comparisons as gcc */
- if (is_null_pointer(p1) || is_null_pointer(p2))
- return;
- type1 = &p1->type;
- type2 = &p2->type;
- bt1 = type1->t & VT_BTYPE;
- bt2 = type2->t & VT_BTYPE;
- /* accept comparison between pointer and integer with a warning */
- if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') {
- if (op != TOK_LOR && op != TOK_LAND )
- tcc_warning("comparison between pointer and integer");
- return;
+ int bt1, t1, t2;
+
+ t1 = type1->t & VT_TYPE;
+ t2 = type2->t & VT_TYPE;
+ if (unqualified) {
+ /* strip qualifiers before comparing */
+ t1 &= ~(VT_CONSTANT | VT_VOLATILE);
+ t2 &= ~(VT_CONSTANT | VT_VOLATILE);
+ }
+
+ /* Default Vs explicit signedness only matters for char */
+ if ((t1 & VT_BTYPE) != VT_BYTE) {
+ t1 &= ~VT_DEFSIGN;
+ t2 &= ~VT_DEFSIGN;
}
+ /* XXX: bitfields ? */
+ if (t1 != t2)
+ return 0;
+
+ if ((t1 & VT_ARRAY)
+ && !(type1->ref->c < 0
+ || type2->ref->c < 0
+ || type1->ref->c == type2->ref->c))
+ return 0;
- /* both must be pointers or implicit function pointers */
+ /* test more complicated cases */
+ bt1 = t1 & VT_BTYPE;
if (bt1 == VT_PTR) {
type1 = pointed_type(type1);
- } else if (bt1 != VT_FUNC)
- goto invalid_operands;
-
- if (bt2 == VT_PTR) {
type2 = pointed_type(type2);
- } else if (bt2 != VT_FUNC) {
- invalid_operands:
- tcc_error("invalid operands to binary %s", get_tok_str(op, NULL));
+ return is_compatible_types(type1, type2);
+ } else if (bt1 == VT_STRUCT) {
+ return (type1->ref == type2->ref);
+ } else if (bt1 == VT_FUNC) {
+ return is_compatible_func(type1, type2);
+ } else if (IS_ENUM(type1->t) && IS_ENUM(type2->t)) {
+ /* If both are enums then they must be the same, if only one is then
+ t1 and t2 must be equal, which was checked above already. */
+ return type1->ref == type2->ref;
+ } else {
+ return 1;
}
- if ((type1->t & VT_BTYPE) == VT_VOID ||
- (type2->t & VT_BTYPE) == VT_VOID)
- return;
- tmp_type1 = *type1;
- tmp_type2 = *type2;
- tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
- tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
- if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
- /* gcc-like error if '-' is used */
- if (op == '-')
- goto invalid_operands;
- else
- tcc_warning("comparison of distinct pointer types lacks a cast");
+}
+
+/* Check if OP1 and OP2 can be "combined" with operation OP, the combined
+ type is stored in DEST if non-null (except for pointer plus/minus) . */
+static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
+{
+ CType *type1 = &op1->type, *type2 = &op2->type, type;
+ int t1 = type1->t, t2 = type2->t, bt1 = t1 & VT_BTYPE, bt2 = t2 & VT_BTYPE;
+ int ret = 1;
+
+ type.t = VT_VOID;
+ type.ref = NULL;
+
+ if (bt1 == VT_VOID || bt2 == VT_VOID) {
+ ret = op == '?' ? 1 : 0;
+ /* NOTE: as an extension, we accept void on only one side */
+ type.t = VT_VOID;
+ } else if (bt1 == VT_PTR || bt2 == VT_PTR) {
+ if (op == '+') ; /* Handled in caller */
+ /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */
+ /* If one is a null ptr constant the result type is the other. */
+ else if (is_null_pointer (op2)) type = *type1;
+ else if (is_null_pointer (op1)) type = *type2;
+ else if (bt1 != bt2) {
+ /* accept comparison or cond-expr between pointer and integer
+ with a warning */
+ if ((op == '?' || TOK_ISCOND(op))
+ && (is_integer_btype(bt1) || is_integer_btype(bt2)))
+ tcc_warning("pointer/integer mismatch in %s",
+ op == '?' ? "conditional expression" : "comparison");
+ else if (op != '-' || !is_integer_btype(bt2))
+ ret = 0;
+ type = *(bt1 == VT_PTR ? type1 : type2);
+ } else {
+ CType *pt1 = pointed_type(type1);
+ CType *pt2 = pointed_type(type2);
+ int pbt1 = pt1->t & VT_BTYPE;
+ int pbt2 = pt2->t & VT_BTYPE;
+ int newquals, copied = 0;
+ if (pbt1 != VT_VOID && pbt2 != VT_VOID
+ && !compare_types(pt1, pt2, 1/*unqualif*/)) {
+ if (op != '?' && !TOK_ISCOND(op))
+ ret = 0;
+ else
+ type_incompatibility_warning(type1, type2,
+ op == '?'
+ ? "pointer type mismatch in conditional expression ('%s' and '%s')"
+ : "pointer type mismatch in comparison('%s' and '%s')");
+ }
+ if (op == '?') {
+ /* pointers to void get preferred, otherwise the
+ pointed to types minus qualifs should be compatible */
+ type = *((pbt1 == VT_VOID) ? type1 : type2);
+ /* combine qualifs */
+ newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE));
+ if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE))
+ & newquals)
+ {
+ /* copy the pointer target symbol */
+ type.ref = sym_push(SYM_FIELD, &type.ref->type,
+ 0, type.ref->c);
+ copied = 1;
+ pointed_type(&type)->t |= newquals;
+ }
+ /* pointers to incomplete arrays get converted to
+ pointers to completed ones if possible */
+ if (pt1->t & VT_ARRAY
+ && pt2->t & VT_ARRAY
+ && pointed_type(&type)->ref->c < 0
+ && (pt1->ref->c > 0 || pt2->ref->c > 0))
+ {
+ if (!copied)
+ type.ref = sym_push(SYM_FIELD, &type.ref->type,
+ 0, type.ref->c);
+ pointed_type(&type)->ref =
+ sym_push(SYM_FIELD, &pointed_type(&type)->ref->type,
+ 0, pointed_type(&type)->ref->c);
+ pointed_type(&type)->ref->c =
+ 0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c;
+ }
+ }
+ }
+ if (TOK_ISCOND(op))
+ type.t = VT_SIZE_T;
+ } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
+ if (op != '?' || !compare_types(type1, type2, 1))
+ ret = 0;
+ type = *type1;
+ } else if (is_float(bt1) || is_float(bt2)) {
+ if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
+ type.t = VT_LDOUBLE;
+ } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
+ type.t = VT_DOUBLE;
+ } else {
+ type.t = VT_FLOAT;
+ }
+ } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
+ /* cast to biggest op */
+ type.t = VT_LLONG | VT_LONG;
+ if (bt1 == VT_LLONG)
+ type.t &= t1;
+ if (bt2 == VT_LLONG)
+ type.t &= t2;
+ /* convert to unsigned if it does not fit in a long long */
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
+ (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
+ type.t |= VT_UNSIGNED;
+ } else {
+ /* integer operations */
+ type.t = VT_INT | (VT_LONG & (t1 | t2));
+ /* convert to unsigned if it does not fit in an integer */
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
+ (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
+ type.t |= VT_UNSIGNED;
}
+ if (dest)
+ *dest = type;
+ return ret;
}
/* generic gen_op: handles types problems */
ST_FUNC void gen_op(int op)
{
int u, t1, t2, bt1, bt2, t;
- CType type1;
+ CType type1, combtype;
redo:
t1 = vtop[-1].type.t;
@@ -2162,9 +3208,7 @@ redo:
bt1 = t1 & VT_BTYPE;
bt2 = t2 & VT_BTYPE;
- if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
- tcc_error("operation on a struct");
- } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
+ if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
if (bt2 == VT_FUNC) {
mk_pointer(&vtop->type);
gaddrof();
@@ -2176,25 +3220,18 @@ redo:
vswap();
}
goto redo;
+ } else if (!combine_types(&combtype, vtop - 1, vtop, op)) {
+ tcc_error_noabort("invalid operand types for binary operation");
+ vpop();
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
/* at least one operand is a pointer */
/* relational op: must be both pointers */
- if (op >= TOK_ULT && op <= TOK_LOR) {
- check_comparison_pointer_types(vtop - 1, vtop, op);
- /* pointers are handled are unsigned */
-#if PTR_SIZE == 8
- t = VT_LLONG | VT_UNSIGNED;
-#else
- t = VT_INT | VT_UNSIGNED;
-#endif
+ if (TOK_ISCOND(op))
goto std_op;
- }
/* if both pointers, then it must be the '-' op */
if (bt1 == VT_PTR && bt2 == VT_PTR) {
if (op != '-')
tcc_error("cannot use pointers here");
- check_comparison_pointer_types(vtop - 1, vtop, op);
- /* XXX: check that types are compatible */
if (vtop[-1].type.t & VT_VLA) {
vla_runtime_pointed_size(&vtop[-1].type);
} else {
@@ -2202,7 +3239,7 @@ redo:
}
vrott(3);
gen_opic(op);
- vtop->type.t = ptrdiff_type.t;
+ vtop->type.t = VT_PTRDIFF_T;
vswap();
gen_op(TOK_PDIV);
} else {
@@ -2220,7 +3257,6 @@ redo:
gen_cast_s(VT_INT);
#endif
type1 = vtop[-1].type;
- type1.t &= ~VT_ARRAY;
if (vtop[-1].type.t & VT_VLA)
vla_runtime_pointed_size(&vtop[-1].type);
else {
@@ -2235,24 +3271,7 @@ redo:
#endif
}
gen_op('*');
-#if 0
-/* #ifdef CONFIG_TCC_BCHECK
- The main reason to removing this code:
- #include <stdio.h>
- int main ()
- {
- int v[10];
- int i = 10;
- int j = 9;
- fprintf(stderr, "v+i-j = %p\n", v+i-j);
- fprintf(stderr, "v+(i-j) = %p\n", v+(i-j));
- }
- When this code is on. then the output looks like
- v+i-j = 0xfffffffe
- v+(i-j) = 0xbff84000
- */
- /* if evaluating constant expression, no code should be
- generated, so no bound check */
+#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && !const_wanted) {
/* if bounded pointers, we generate a special code to
test bounds */
@@ -2267,49 +3286,25 @@ redo:
{
gen_opic(op);
}
+ type1.t &= ~VT_ARRAY;
/* put again type if gen_opic() swaped operands */
vtop->type = type1;
}
- } else if (is_float(bt1) || is_float(bt2)) {
- /* compute bigger type and do implicit casts */
- if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
- t = VT_LDOUBLE;
- } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
- t = VT_DOUBLE;
- } else {
- t = VT_FLOAT;
- }
+ } else {
/* floats can only be used for a few operations */
- if (op != '+' && op != '-' && op != '*' && op != '/' &&
- (op < TOK_ULT || op > TOK_GT))
+ if (is_float(combtype.t)
+ && op != '+' && op != '-' && op != '*' && op != '/'
+ && !TOK_ISCOND(op))
tcc_error("invalid operands for binary operation");
- goto std_op;
- } else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) {
- t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
- if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
- t |= VT_UNSIGNED;
- t |= (VT_LONG & t1);
- goto std_op;
- } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
- /* cast to biggest op */
- t = VT_LLONG | VT_LONG;
- if (bt1 == VT_LLONG)
- t &= t1;
- if (bt2 == VT_LLONG)
- t &= t2;
- /* convert to unsigned if it does not fit in a long long */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
- t |= VT_UNSIGNED;
- goto std_op;
- } else {
- /* integer operations */
- t = VT_INT | (VT_LONG & (t1 | t2));
- /* convert to unsigned if it does not fit in an integer */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
- t |= VT_UNSIGNED;
+ else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) {
+ t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
+ t |= VT_UNSIGNED;
+ t |= (VT_LONG & t1);
+ combtype.t = t;
+ }
std_op:
+ t = t2 = combtype.t;
/* XXX: currently, some unsigned operations are explicit, so
we modify them here */
if (t & VT_UNSIGNED) {
@@ -2329,20 +3324,18 @@ redo:
op = TOK_UGE;
}
vswap();
- type1.t = t;
- type1.ref = NULL;
- gen_cast(&type1);
+ gen_cast_s(t);
vswap();
/* special case for shifts and long long: we keep the shift as
an integer */
if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL)
- type1.t = VT_INT;
- gen_cast(&type1);
+ t2 = VT_INT;
+ gen_cast_s(t2);
if (is_float(t))
gen_opif(op);
else
gen_opic(op);
- if (op >= TOK_ULT && op <= TOK_GT) {
+ if (TOK_ISCOND(op)) {
/* relational op: the result is an int */
vtop->type.t = VT_INT;
} else {
@@ -2354,13 +3347,12 @@ redo:
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
}
-#ifndef TCC_TARGET_ARM
+#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
+#define gen_cvt_itof1 gen_cvt_itof
+#else
/* generic itof for unsigned long long case */
static void gen_cvt_itof1(int t)
{
-#ifdef TCC_TARGET_ARM64
- gen_cvt_itof(t);
-#else
if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
(VT_LLONG | VT_UNSIGNED)) {
@@ -2375,22 +3367,20 @@ static void gen_cvt_itof1(int t)
vrott(2);
gfunc_call(1);
vpushi(0);
- vtop->r = reg_fret(t);
+ PUT_R_RET(vtop, t);
} else {
gen_cvt_itof(t);
}
-#endif
}
#endif
+#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
+#define gen_cvt_ftoi1 gen_cvt_ftoi
+#else
/* generic ftoi for unsigned long long case */
static void gen_cvt_ftoi1(int t)
{
-#ifdef TCC_TARGET_ARM64
- gen_cvt_ftoi(t);
-#else
int st;
-
if (t == (VT_LLONG | VT_UNSIGNED)) {
/* not handled natively */
st = vtop->type.t & VT_BTYPE;
@@ -2405,49 +3395,24 @@ static void gen_cvt_ftoi1(int t)
vrott(2);
gfunc_call(1);
vpushi(0);
- vtop->r = REG_IRET;
- vtop->r2 = REG_LRET;
+ PUT_R_RET(vtop, t);
} else {
gen_cvt_ftoi(t);
}
-#endif
}
+#endif
-/* force char or short cast */
-static void force_charshort_cast(int t)
+/* special delayed cast for char/short */
+static void force_charshort_cast(void)
{
- int bits, dbt;
-
- /* cannot cast static initializers */
- if (STATIC_DATA_WANTED)
- return;
-
- dbt = t & VT_BTYPE;
- /* XXX: add optimization if lvalue : just change type and offset */
- if (dbt == VT_BYTE)
- bits = 8;
- else
- bits = 16;
- if (t & VT_UNSIGNED) {
- vpushi((1 << bits) - 1);
- gen_op('&');
- } else {
- if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
- bits = 64 - bits;
- else
- bits = 32 - bits;
- vpushi(bits);
- gen_op(TOK_SHL);
- /* result must be signed or the SAR is converted to an SHL
- This was not the case when "t" was a signed short
- and the last value on the stack was an unsigned int */
- vtop->type.t &= ~VT_UNSIGNED;
- vpushi(bits);
- gen_op(TOK_SAR);
- }
+ int sbt = BFGET(vtop->r, VT_MUSTCAST) == 2 ? VT_LLONG : VT_INT;
+ int dbt = vtop->type.t;
+ vtop->r &= ~VT_MUSTCAST;
+ vtop->type.t = sbt;
+ gen_cast_s(dbt == VT_BOOL ? VT_BYTE|VT_UNSIGNED : dbt);
+ vtop->type.t = dbt;
}
-/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */
static void gen_cast_s(int t)
{
CType type;
@@ -2456,33 +3421,35 @@ static void gen_cast_s(int t)
gen_cast(&type);
}
+/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */
static void gen_cast(CType *type)
{
- int sbt, dbt, sf, df, c, p;
+ int sbt, dbt, sf, df, c;
+ int dbt_bt, sbt_bt, ds, ss, bits, trunc;
/* special delayed cast for char/short */
- /* XXX: in some cases (multiple cascaded casts), it may still
- be incorrect */
- if (vtop->r & VT_MUSTCAST) {
- vtop->r &= ~VT_MUSTCAST;
- force_charshort_cast(vtop->type.t);
- }
+ if (vtop->r & VT_MUSTCAST)
+ force_charshort_cast();
/* bitfields first get cast to ints */
- if (vtop->type.t & VT_BITFIELD) {
+ if (vtop->type.t & VT_BITFIELD)
gv(RC_INT);
- }
dbt = type->t & (VT_BTYPE | VT_UNSIGNED);
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
+ if (sbt == VT_FUNC)
+ sbt = VT_PTR;
+again:
if (sbt != dbt) {
sf = is_float(sbt);
df = is_float(dbt);
+ dbt_bt = dbt & VT_BTYPE;
+ sbt_bt = sbt & VT_BTYPE;
+
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
- p = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM);
#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387
- c &= dbt != VT_LDOUBLE;
+ c &= (dbt != VT_LDOUBLE) | !!nocode_wanted;
#endif
if (c) {
/* constant case: we can do it now */
@@ -2493,7 +3460,7 @@ static void gen_cast(CType *type)
vtop->c.ld = vtop->c.d;
if (df) {
- if ((sbt & VT_BTYPE) == VT_LLONG) {
+ if (sbt_bt == VT_LLONG) {
if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63))
vtop->c.ld = vtop->c.i;
else
@@ -2509,150 +3476,177 @@ static void gen_cast(CType *type)
vtop->c.f = (float)vtop->c.ld;
else if (dbt == VT_DOUBLE)
vtop->c.d = (double)vtop->c.ld;
- } else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) {
- vtop->c.i = vtop->c.ld;
} else if (sf && dbt == VT_BOOL) {
vtop->c.i = (vtop->c.ld != 0);
} else {
if(sf)
vtop->c.i = vtop->c.ld;
- else if (sbt == (VT_LLONG|VT_UNSIGNED))
+ else if (sbt_bt == VT_LLONG || (PTR_SIZE == 8 && sbt == VT_PTR))
;
else if (sbt & VT_UNSIGNED)
vtop->c.i = (uint32_t)vtop->c.i;
-#if PTR_SIZE == 8
- else if (sbt == VT_PTR)
- ;
-#endif
- else if (sbt != VT_LLONG)
- vtop->c.i = ((uint32_t)vtop->c.i |
- -(vtop->c.i & 0x80000000));
+ else
+ vtop->c.i = ((uint32_t)vtop->c.i | -(vtop->c.i & 0x80000000));
- if (dbt == (VT_LLONG|VT_UNSIGNED))
+ if (dbt_bt == VT_LLONG || (PTR_SIZE == 8 && dbt == VT_PTR))
;
else if (dbt == VT_BOOL)
vtop->c.i = (vtop->c.i != 0);
-#if PTR_SIZE == 8
- else if (dbt == VT_PTR)
- ;
-#endif
- else if (dbt != VT_LLONG) {
- uint32_t m = ((dbt & VT_BTYPE) == VT_BYTE ? 0xff :
- (dbt & VT_BTYPE) == VT_SHORT ? 0xffff :
- 0xffffffff);
+ else {
+ uint32_t m = dbt_bt == VT_BYTE ? 0xff :
+ dbt_bt == VT_SHORT ? 0xffff :
+ 0xffffffff;
vtop->c.i &= m;
if (!(dbt & VT_UNSIGNED))
vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1));
}
}
- } else if (p && dbt == VT_BOOL) {
+ goto done;
+
+ } else if (dbt == VT_BOOL
+ && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM))
+ == (VT_CONST | VT_SYM)) {
+ /* addresses are considered non-zero (see tcctest.c:sinit23) */
vtop->r = VT_CONST;
vtop->c.i = 1;
- } else {
- /* non constant case: generate code */
+ goto done;
+ }
+
+ /* cannot generate code for global or static initializers */
+ if (STATIC_DATA_WANTED)
+ goto done;
+
+ /* non constant case: generate code */
+ if (dbt == VT_BOOL) {
+ gen_test_zero(TOK_NE);
+ goto done;
+ }
+
+ if (sf || df) {
if (sf && df) {
/* convert from fp to fp */
gen_cvt_ftof(dbt);
} else if (df) {
/* convert int to fp */
gen_cvt_itof1(dbt);
- } else if (sf) {
+ } else {
/* convert fp to int */
- if (dbt == VT_BOOL) {
- vpushi(0);
- gen_op(TOK_NE);
- } else {
- /* we handle char/short/etc... with generic code */
- if (dbt != (VT_INT | VT_UNSIGNED) &&
- dbt != (VT_LLONG | VT_UNSIGNED) &&
- dbt != VT_LLONG)
- dbt = VT_INT;
- gen_cvt_ftoi1(dbt);
- if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) {
- /* additional cast for char/short... */
- vtop->type.t = dbt;
- gen_cast(type);
- }
- }
+ sbt = dbt;
+ if (dbt_bt != VT_LLONG && dbt_bt != VT_INT)
+ sbt = VT_INT;
+ gen_cvt_ftoi1(sbt);
+ goto again; /* may need char/short cast */
+ }
+ goto done;
+ }
+
+ ds = btype_size(dbt_bt);
+ ss = btype_size(sbt_bt);
+ if (ds == 0 || ss == 0) {
+ if (dbt_bt == VT_VOID)
+ goto done;
+ cast_error(&vtop->type, type);
+ }
+ if (IS_ENUM(type->t) && type->ref->c < 0)
+ tcc_error("cast to incomplete type");
+
+ /* same size and no sign conversion needed */
+ if (ds == ss && ds >= 4)
+ goto done;
+ if (dbt_bt == VT_PTR || sbt_bt == VT_PTR) {
+ tcc_warning("cast between pointer and integer of different size");
+ if (sbt_bt == VT_PTR) {
+ /* put integer type to allow logical operations below */
+ vtop->type.t = (PTR_SIZE == 8 ? VT_LLONG : VT_INT);
+ }
+ }
+
+ /* processor allows { int a = 0, b = *(char*)&a; }
+ That means that if we cast to less width, we can just
+ change the type and read it still later. */
+ #define ALLOW_SUBTYPE_ACCESS 1
+
+ if (ALLOW_SUBTYPE_ACCESS && (vtop->r & VT_LVAL)) {
+ /* value still in memory */
+ if (ds <= ss)
+ goto done;
+ /* ss <= 4 here */
+ if (ds <= 4) {
+ gv(RC_INT);
+ goto done; /* no 64bit envolved */
+ }
+ }
+ gv(RC_INT);
+
+ trunc = 0;
#if PTR_SIZE == 4
- } else if ((dbt & VT_BTYPE) == VT_LLONG) {
- if ((sbt & VT_BTYPE) != VT_LLONG) {
- /* scalar to long long */
- /* machine independent conversion */
- gv(RC_INT);
- /* generate high word */
- if (sbt == (VT_INT | VT_UNSIGNED)) {
- vpushi(0);
- gv(RC_INT);
- } else {
- if (sbt == VT_PTR) {
- /* cast from pointer to int before we apply
- shift operation, which pointers don't support*/
- gen_cast_s(VT_INT);
- }
- gv_dup();
- vpushi(31);
- gen_op(TOK_SAR);
- }
- /* patch second register */
- vtop[-1].r2 = vtop->r;
- vpop();
- }
-#else
- } else if ((dbt & VT_BTYPE) == VT_LLONG ||
- (dbt & VT_BTYPE) == VT_PTR ||
- (dbt & VT_BTYPE) == VT_FUNC) {
- if ((sbt & VT_BTYPE) != VT_LLONG &&
- (sbt & VT_BTYPE) != VT_PTR &&
- (sbt & VT_BTYPE) != VT_FUNC) {
- /* need to convert from 32bit to 64bit */
- gv(RC_INT);
- if (sbt != (VT_INT | VT_UNSIGNED)) {
-#if defined(TCC_TARGET_ARM64)
- gen_cvt_sxtw();
-#elif defined(TCC_TARGET_X86_64)
- int r = gv(RC_INT);
- /* x86_64 specific: movslq */
- o(0x6348);
- o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
+ if (ds == 8) {
+ /* generate high word */
+ if (sbt & VT_UNSIGNED) {
+ vpushi(0);
+ gv(RC_INT);
+ } else {
+ gv_dup();
+ vpushi(31);
+ gen_op(TOK_SAR);
+ }
+ lbuild(dbt);
+ } else if (ss == 8) {
+ /* from long long: just take low order word */
+ lexpand();
+ vpop();
+ }
+ ss = 4;
+
+#elif PTR_SIZE == 8
+ if (ds == 8) {
+ /* need to convert from 32bit to 64bit */
+ if (sbt & VT_UNSIGNED) {
+#if defined(TCC_TARGET_RISCV64)
+ /* RISC-V keeps 32bit vals in registers sign-extended.
+ So here we need a zero-extension. */
+ trunc = 32;
#else
-#error
+ goto done;
#endif
- }
- }
+ } else {
+ gen_cvt_sxtw();
+ goto done;
+ }
+ ss = ds, ds = 4, dbt = sbt;
+ } else if (ss == 8) {
+ /* RISC-V keeps 32bit vals in registers sign-extended.
+ So here we need a sign-extension for signed types and
+ zero-extension. for unsigned types. */
+#if !defined(TCC_TARGET_RISCV64)
+ trunc = 32; /* zero upper 32 bits for non RISC-V targets */
#endif
- } else if (dbt == VT_BOOL) {
- /* scalar to bool */
- vpushi(0);
- gen_op(TOK_NE);
- } else if ((dbt & VT_BTYPE) == VT_BYTE ||
- (dbt & VT_BTYPE) == VT_SHORT) {
- if (sbt == VT_PTR) {
- vtop->type.t = VT_INT;
- tcc_warning("nonportable conversion from pointer to char/short");
- }
- force_charshort_cast(dbt);
-#if PTR_SIZE == 4
- } else if ((dbt & VT_BTYPE) == VT_INT) {
- /* scalar to int */
- if ((sbt & VT_BTYPE) == VT_LLONG) {
- /* from long long: just take low order word */
- lexpand();
- vpop();
- }
- /* if lvalue and single word type, nothing to do because
- the lvalue already contains the real type size (see
- VT_LVAL_xxx constants) */
+ } else {
+ ss = 4;
+ }
#endif
- }
+
+ if (ds >= ss)
+ goto done;
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64
+ if (ss == 4) {
+ gen_cvt_csti(dbt);
+ goto done;
}
- } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) {
- /* if we are casting between pointer types,
- we must update the VT_LVAL_xxx size */
- vtop->r = (vtop->r & ~VT_LVAL_TYPE)
- | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE);
+#endif
+ bits = (ss - ds) * 8;
+ /* for unsigned, gen_op will convert SAR to SHR */
+ vtop->type.t = (ss == 8 ? VT_LLONG : VT_INT) | (dbt & VT_UNSIGNED);
+ vpushi(bits);
+ gen_op(TOK_SHL);
+ vpushi(bits - trunc);
+ gen_op(TOK_SAR);
+ vpushi(trunc);
+ gen_op(TOK_SHR);
}
+done:
vtop->type = *type;
+ vtop->type.t &= ~ ( VT_CONSTANT | VT_VOLATILE | VT_ARRAY );
}
/* return type size as known at compile time. Put alignment at 'a' */
@@ -2682,7 +3676,7 @@ ST_FUNC int type_size(CType *type, int *a)
*a = PTR_SIZE;
return PTR_SIZE;
}
- } else if (IS_ENUM(type->t) && type->ref->c == -1) {
+ } else if (IS_ENUM(type->t) && type->ref->c < 0) {
return -1; /* incomplete enum */
} else if (bt == VT_LDOUBLE) {
*a = LDOUBLE_ALIGN;
@@ -2732,18 +3726,6 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a)
}
}
-static void vla_sp_restore(void) {
- if (vlas_in_scope) {
- gen_vla_sp_restore(vla_sp_loc);
- }
-}
-
-static void vla_sp_restore_root(void) {
- if (vlas_in_scope) {
- gen_vla_sp_restore(vla_sp_root_loc);
- }
-}
-
/* return the pointed type of t */
static inline CType *pointed_type(CType *type)
{
@@ -2759,76 +3741,6 @@ ST_FUNC void mk_pointer(CType *type)
type->ref = s;
}
-/* compare function types. OLD functions match any new functions */
-static int is_compatible_func(CType *type1, CType *type2)
-{
- Sym *s1, *s2;
-
- s1 = type1->ref;
- s2 = type2->ref;
- if (!is_compatible_types(&s1->type, &s2->type))
- return 0;
- /* check func_call */
- if (s1->f.func_call != s2->f.func_call)
- return 0;
- /* XXX: not complete */
- if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD)
- return 1;
- if (s1->f.func_type != s2->f.func_type)
- return 0;
- while (s1 != NULL) {
- if (s2 == NULL)
- return 0;
- if (!is_compatible_unqualified_types(&s1->type, &s2->type))
- return 0;
- s1 = s1->next;
- s2 = s2->next;
- }
- if (s2)
- return 0;
- return 1;
-}
-
-/* return true if type1 and type2 are the same. If unqualified is
- true, qualifiers on the types are ignored.
-
- - enums are not checked as gcc __builtin_types_compatible_p ()
- */
-static int compare_types(CType *type1, CType *type2, int unqualified)
-{
- int bt1, t1, t2;
-
- t1 = type1->t & VT_TYPE;
- t2 = type2->t & VT_TYPE;
- if (unqualified) {
- /* strip qualifiers before comparing */
- t1 &= ~(VT_CONSTANT | VT_VOLATILE);
- t2 &= ~(VT_CONSTANT | VT_VOLATILE);
- }
-
- /* Default Vs explicit signedness only matters for char */
- if ((t1 & VT_BTYPE) != VT_BYTE) {
- t1 &= ~VT_DEFSIGN;
- t2 &= ~VT_DEFSIGN;
- }
- /* XXX: bitfields ? */
- if (t1 != t2)
- return 0;
- /* test more complicated cases */
- bt1 = t1 & VT_BTYPE;
- if (bt1 == VT_PTR) {
- type1 = pointed_type(type1);
- type2 = pointed_type(type2);
- return is_compatible_types(type1, type2);
- } else if (bt1 == VT_STRUCT) {
- return (type1->ref == type2->ref);
- } else if (bt1 == VT_FUNC) {
- return is_compatible_func(type1, type2);
- } else {
- return 1;
- }
-}
-
/* return true if type1 and type2 are exactly the same (including
qualifiers).
*/
@@ -2844,200 +3756,74 @@ static int is_compatible_unqualified_types(CType *type1, CType *type2)
return compare_types(type1,type2,1);
}
-/* print a type. If 'varstr' is not NULL, then the variable is also
- printed in the type */
-/* XXX: union */
-/* XXX: add array and function pointers */
-static void type_to_str(char *buf, int buf_size,
- CType *type, const char *varstr)
+static void cast_error(CType *st, CType *dt)
{
- int bt, v, t;
- Sym *s, *sa;
- char buf1[256];
- const char *tstr;
-
- t = type->t;
- bt = t & VT_BTYPE;
- buf[0] = '\0';
-
- if (t & VT_EXTERN)
- pstrcat(buf, buf_size, "extern ");
- if (t & VT_STATIC)
- pstrcat(buf, buf_size, "static ");
- if (t & VT_TYPEDEF)
- pstrcat(buf, buf_size, "typedef ");
- if (t & VT_INLINE)
- pstrcat(buf, buf_size, "inline ");
- if (t & VT_VOLATILE)
- pstrcat(buf, buf_size, "volatile ");
- if (t & VT_CONSTANT)
- pstrcat(buf, buf_size, "const ");
-
- if (((t & VT_DEFSIGN) && bt == VT_BYTE)
- || ((t & VT_UNSIGNED)
- && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG)
- && !IS_ENUM(t)
- ))
- pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed ");
-
- buf_size -= strlen(buf);
- buf += strlen(buf);
-
- switch(bt) {
- case VT_VOID:
- tstr = "void";
- goto add_tstr;
- case VT_BOOL:
- tstr = "_Bool";
- goto add_tstr;
- case VT_BYTE:
- tstr = "char";
- goto add_tstr;
- case VT_SHORT:
- tstr = "short";
- goto add_tstr;
- case VT_INT:
- tstr = "int";
- goto maybe_long;
- case VT_LLONG:
- tstr = "long long";
- maybe_long:
- if (t & VT_LONG)
- tstr = "long";
- if (!IS_ENUM(t))
- goto add_tstr;
- tstr = "enum ";
- goto tstruct;
- case VT_FLOAT:
- tstr = "float";
- goto add_tstr;
- case VT_DOUBLE:
- tstr = "double";
- goto add_tstr;
- case VT_LDOUBLE:
- tstr = "long double";
- add_tstr:
- pstrcat(buf, buf_size, tstr);
- break;
- case VT_STRUCT:
- tstr = "struct ";
- if (IS_UNION(t))
- tstr = "union ";
- tstruct:
- pstrcat(buf, buf_size, tstr);
- v = type->ref->v & ~SYM_STRUCT;
- if (v >= SYM_FIRST_ANOM)
- pstrcat(buf, buf_size, "<anonymous>");
- else
- pstrcat(buf, buf_size, get_tok_str(v, NULL));
- break;
- case VT_FUNC:
- s = type->ref;
- type_to_str(buf, buf_size, &s->type, varstr);
- pstrcat(buf, buf_size, "(");
- sa = s->next;
- while (sa != NULL) {
- type_to_str(buf1, sizeof(buf1), &sa->type, NULL);
- pstrcat(buf, buf_size, buf1);
- sa = sa->next;
- if (sa)
- pstrcat(buf, buf_size, ", ");
- }
- pstrcat(buf, buf_size, ")");
- goto no_var;
- case VT_PTR:
- s = type->ref;
- if (t & VT_ARRAY) {
- snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c);
- type_to_str(buf, buf_size, &s->type, buf1);
- goto no_var;
- }
- pstrcpy(buf1, sizeof(buf1), "*");
- if (t & VT_CONSTANT)
- pstrcat(buf1, buf_size, "const ");
- if (t & VT_VOLATILE)
- pstrcat(buf1, buf_size, "volatile ");
- if (varstr)
- pstrcat(buf1, sizeof(buf1), varstr);
- type_to_str(buf, buf_size, &s->type, buf1);
- goto no_var;
- }
- if (varstr) {
- pstrcat(buf, buf_size, " ");
- pstrcat(buf, buf_size, varstr);
- }
- no_var: ;
+ type_incompatibility_error(st, dt, "cannot convert '%s' to '%s'");
}
-/* verify type compatibility to store vtop in 'dt' type, and generate
- casts if needed. */
-static void gen_assign_cast(CType *dt)
+/* verify type compatibility to store vtop in 'dt' type */
+static void verify_assign_cast(CType *dt)
{
CType *st, *type1, *type2;
- char buf1[256], buf2[256];
- int dbt, sbt;
+ int dbt, sbt, qualwarn, lvl;
st = &vtop->type; /* source type */
dbt = dt->t & VT_BTYPE;
sbt = st->t & VT_BTYPE;
- if (sbt == VT_VOID || dbt == VT_VOID) {
- if (sbt == VT_VOID && dbt == VT_VOID)
- ; /*
- It is Ok if both are void
- A test program:
- void func1() {}
- void func2() {
- return func1();
- }
- gcc accepts this program
- */
- else
- tcc_error("cannot cast from/to void");
- }
if (dt->t & VT_CONSTANT)
tcc_warning("assignment of read-only location");
switch(dbt) {
+ case VT_VOID:
+ if (sbt != dbt)
+ tcc_error("assignment to void expression");
+ break;
case VT_PTR:
/* special cases for pointers */
/* '0' can also be a pointer */
if (is_null_pointer(vtop))
- goto type_ok;
+ break;
/* accept implicit pointer to integer cast with warning */
if (is_integer_btype(sbt)) {
tcc_warning("assignment makes pointer from integer without a cast");
- goto type_ok;
+ break;
}
type1 = pointed_type(dt);
- /* a function is implicitly a function pointer */
- if (sbt == VT_FUNC) {
- if ((type1->t & VT_BTYPE) != VT_VOID &&
- !is_compatible_types(pointed_type(dt), st))
- tcc_warning("assignment from incompatible pointer type");
- goto type_ok;
- }
- if (sbt != VT_PTR)
+ if (sbt == VT_PTR)
+ type2 = pointed_type(st);
+ else if (sbt == VT_FUNC)
+ type2 = st; /* a function is implicitly a function pointer */
+ else
goto error;
- type2 = pointed_type(st);
- if ((type1->t & VT_BTYPE) == VT_VOID ||
- (type2->t & VT_BTYPE) == VT_VOID) {
- /* void * can match anything */
- } else {
- //printf("types %08x %08x\n", type1->t, type2->t);
- /* exact type match, except for qualifiers */
- if (!is_compatible_unqualified_types(type1, type2)) {
+ if (is_compatible_types(type1, type2))
+ break;
+ for (qualwarn = lvl = 0;; ++lvl) {
+ if (((type2->t & VT_CONSTANT) && !(type1->t & VT_CONSTANT)) ||
+ ((type2->t & VT_VOLATILE) && !(type1->t & VT_VOLATILE)))
+ qualwarn = 1;
+ dbt = type1->t & (VT_BTYPE|VT_LONG);
+ sbt = type2->t & (VT_BTYPE|VT_LONG);
+ if (dbt != VT_PTR || sbt != VT_PTR)
+ break;
+ type1 = pointed_type(type1);
+ type2 = pointed_type(type2);
+ }
+ if (!is_compatible_unqualified_types(type1, type2)) {
+ if ((dbt == VT_VOID || sbt == VT_VOID) && lvl == 0) {
+ /* void * can match anything */
+ } else if (dbt == sbt
+ && is_integer_btype(sbt & VT_BTYPE)
+ && IS_ENUM(type1->t) + IS_ENUM(type2->t)
+ + !!((type1->t ^ type2->t) & VT_UNSIGNED) < 2) {
/* Like GCC don't warn by default for merely changes
in pointer target signedness. Do warn for different
base types, though, in particular for unsigned enums
and signed int targets. */
- if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG))
- || IS_ENUM(type1->t) || IS_ENUM(type2->t)
- )
- tcc_warning("assignment from incompatible pointer type");
- }
+ } else {
+ tcc_warning("assignment from incompatible pointer type");
+ break;
+ }
}
- /* check const and volatile */
- if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) ||
- (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE)))
+ if (qualwarn)
tcc_warning("assignment discards qualifiers from pointer target type");
break;
case VT_BYTE:
@@ -3054,39 +3840,29 @@ static void gen_assign_cast(CType *dt)
case VT_STRUCT:
case_VT_STRUCT:
if (!is_compatible_unqualified_types(dt, st)) {
- error:
- type_to_str(buf1, sizeof(buf1), st, NULL);
- type_to_str(buf2, sizeof(buf2), dt, NULL);
- tcc_error("cannot cast '%s' to '%s'", buf1, buf2);
+ error:
+ cast_error(st, dt);
}
break;
}
- type_ok:
+}
+
+static void gen_assign_cast(CType *dt)
+{
+ verify_assign_cast(dt);
gen_cast(dt);
}
/* store vtop in lvalue pushed on stack */
ST_FUNC void vstore(void)
{
- int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast;
+ int sbt, dbt, ft, r, size, align, bit_size, bit_pos, delayed_cast;
ft = vtop[-1].type.t;
sbt = vtop->type.t & VT_BTYPE;
dbt = ft & VT_BTYPE;
- if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) ||
- (sbt == VT_INT && dbt == VT_SHORT))
- && !(vtop->type.t & VT_BITFIELD)) {
- /* optimize char/short casts */
- delayed_cast = VT_MUSTCAST;
- vtop->type.t = ft & VT_TYPE;
- /* XXX: factorize */
- if (ft & VT_CONSTANT)
- tcc_warning("assignment of read-only location");
- } else {
- delayed_cast = 0;
- if (!(ft & VT_BITFIELD))
- gen_assign_cast(&vtop[-1].type);
- }
+
+ verify_assign_cast(&vtop[-1].type);
if (sbt == VT_STRUCT) {
/* if structure, only generate pointer */
@@ -3096,15 +3872,19 @@ ST_FUNC void vstore(void)
/* destination */
vswap();
+#ifdef CONFIG_TCC_BCHECK
+ if (vtop->r & VT_MUSTBOUND)
+ gbound(); /* check would be wrong after gaddrof() */
+#endif
vtop->type.t = VT_PTR;
gaddrof();
/* address of memcpy() */
#ifdef TCC_ARM_EABI
if(!(align & 7))
- vpush_global_sym(&func_old_type, TOK_memcpy8);
+ vpush_global_sym(&func_old_type, TOK_memmove8);
else if(!(align & 3))
- vpush_global_sym(&func_old_type, TOK_memcpy4);
+ vpush_global_sym(&func_old_type, TOK_memmove4);
else
#endif
/* Use memmove, rather than memcpy, as dest and src may be same: */
@@ -3113,13 +3893,17 @@ ST_FUNC void vstore(void)
vswap();
/* source */
vpushv(vtop - 2);
+#ifdef CONFIG_TCC_BCHECK
+ if (vtop->r & VT_MUSTBOUND)
+ gbound();
+#endif
vtop->type.t = VT_PTR;
gaddrof();
/* type size */
vpushi(size);
gfunc_call(3);
-
/* leave source on stack */
+
} else if (ft & VT_BITFIELD) {
/* bitfield store handling */
@@ -3131,20 +3915,22 @@ ST_FUNC void vstore(void)
/* remove bit field info to avoid loops */
vtop[-1].type.t = ft & ~VT_STRUCT_MASK;
- if ((ft & VT_BTYPE) == VT_BOOL) {
+ if (dbt == VT_BOOL) {
gen_cast(&vtop[-1].type);
vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
}
-
r = adjust_bf(vtop - 1, bit_pos, bit_size);
+ if (dbt != VT_BOOL) {
+ gen_cast(&vtop[-1].type);
+ dbt = vtop[-1].type.t & VT_BTYPE;
+ }
if (r == VT_STRUCT) {
- gen_cast_s((ft & VT_BTYPE) == VT_LLONG ? VT_LLONG : VT_INT);
store_packed_bf(bit_pos, bit_size);
} else {
unsigned long long mask = (1ULL << bit_size) - 1;
- if ((ft & VT_BTYPE) != VT_BOOL) {
+ if (dbt != VT_BOOL) {
/* mask source */
- if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG)
+ if (dbt == VT_LLONG)
vpushll(mask);
else
vpushi((unsigned)mask);
@@ -3158,7 +3944,7 @@ ST_FUNC void vstore(void)
vdup();
vrott(3);
/* load destination, mask and or with source */
- if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
+ if (dbt == VT_LLONG)
vpushll(~(mask << bit_pos));
else
vpushi(~((unsigned)mask << bit_pos));
@@ -3172,6 +3958,20 @@ ST_FUNC void vstore(void)
} else if (dbt == VT_VOID) {
--vtop;
} else {
+ /* optimize char/short casts */
+ delayed_cast = 0;
+ if ((dbt == VT_BYTE || dbt == VT_SHORT)
+ && is_integer_btype(sbt)
+ ) {
+ if ((vtop->r & VT_MUSTCAST)
+ && btype_size(dbt) > btype_size(sbt)
+ )
+ force_charshort_cast();
+ delayed_cast = 1;
+ } else {
+ gen_cast(&vtop[-1].type);
+ }
+
#ifdef CONFIG_TCC_BCHECK
/* bound check case */
if (vtop[-1].r & VT_MUSTBOUND) {
@@ -3180,47 +3980,37 @@ ST_FUNC void vstore(void)
vswap();
}
#endif
- rc = RC_INT;
- if (is_float(ft)) {
- rc = RC_FLOAT;
-#ifdef TCC_TARGET_X86_64
- if ((ft & VT_BTYPE) == VT_LDOUBLE) {
- rc = RC_ST0;
- } else if ((ft & VT_BTYPE) == VT_QFLOAT) {
- rc = RC_FRET;
- }
-#endif
+ gv(RC_TYPE(dbt)); /* generate value */
+
+ if (delayed_cast) {
+ vtop->r |= BFVAL(VT_MUSTCAST, (sbt == VT_LLONG) + 1);
+ //tcc_warning("deley cast %x -> %x", sbt, dbt);
+ vtop->type.t = ft & VT_TYPE;
}
- r = gv(rc); /* generate value */
+
/* if lvalue was saved on stack, must read it */
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
SValue sv;
- t = get_reg(RC_INT);
-#if PTR_SIZE == 8
- sv.type.t = VT_PTR;
-#else
- sv.type.t = VT_INT;
-#endif
+ r = get_reg(RC_INT);
+ sv.type.t = VT_PTRDIFF_T;
sv.r = VT_LOCAL | VT_LVAL;
sv.c.i = vtop[-1].c.i;
- load(t, &sv);
- vtop[-1].r = t | VT_LVAL;
+ load(r, &sv);
+ vtop[-1].r = r | VT_LVAL;
}
- /* two word case handling : store second register at word + 4 (or +8 for x86-64) */
-#if PTR_SIZE == 8
- if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) {
- int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
-#else
- if ((ft & VT_BTYPE) == VT_LLONG) {
- int addr_type = VT_INT, load_size = 4, load_type = VT_INT;
-#endif
+
+ r = vtop->r & VT_VALMASK;
+ /* two word case handling :
+ store second register at word + 4 (or +8 for x86-64) */
+ if (USING_TWO_WORDS(dbt)) {
+ int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T;
vtop[-1].type.t = load_type;
store(r, vtop - 1);
vswap();
/* convert to int to increment easily */
- vtop->type.t = addr_type;
+ vtop->type.t = VT_PTRDIFF_T;
gaddrof();
- vpushi(load_size);
+ vpushs(PTR_SIZE);
gen_op('+');
vtop->r |= VT_LVAL;
vswap();
@@ -3228,12 +4018,11 @@ ST_FUNC void vstore(void)
/* XXX: it works because r2 is spilled last ! */
store(vtop->r2, vtop - 1);
} else {
+ /* single word */
store(r, vtop - 1);
}
-
vswap();
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
- vtop->r |= delayed_cast;
}
}
@@ -3271,7 +4060,7 @@ ST_FUNC void parse_mult_str (CString *astr, const char *msg)
/* If I is >= 1 and a power of two, returns log2(i)+1.
If I is 0 returns 0. */
-static int exact_log2p1(int i)
+ST_FUNC int exact_log2p1(int i)
{
int ret;
if (!i)
@@ -3305,6 +4094,42 @@ redo:
t = tok;
next();
switch(t) {
+ case TOK_CLEANUP1:
+ case TOK_CLEANUP2:
+ {
+ Sym *s;
+
+ skip('(');
+ s = sym_find(tok);
+ if (!s) {
+ tcc_warning("implicit declaration of function '%s'",
+ get_tok_str(tok, &tokc));
+ s = external_global_sym(tok, &func_old_type);
+ } else if ((s->type.t & VT_BTYPE) != VT_FUNC)
+ tcc_error("'%s' is not declared as function", get_tok_str(tok, &tokc));
+ ad->cleanup_func = s;
+ next();
+ skip(')');
+ break;
+ }
+ case TOK_CONSTRUCTOR1:
+ case TOK_CONSTRUCTOR2:
+ ad->f.func_ctor = 1;
+ break;
+ case TOK_DESTRUCTOR1:
+ case TOK_DESTRUCTOR2:
+ ad->f.func_dtor = 1;
+ break;
+ case TOK_ALWAYS_INLINE1:
+ case TOK_ALWAYS_INLINE2:
+ ad->f.func_alwinl = 1;
+ break;
+#ifdef CONFIG_TCC_BCHECK
+ case TOK_NO_BOUND_CHECK1:
+ case TOK_NO_BOUND_CHECK2:
+ ad->f.no_bcheck = 1;
+ break;
+#endif
case TOK_SECTION1:
case TOK_SECTION2:
skip('(');
@@ -3317,8 +4142,8 @@ redo:
case TOK_ALIAS2:
skip('(');
parse_mult_str(&astr, "alias(\"target\")");
- ad->alias_target = /* save string as token, for later */
- tok_alloc((char*)astr.data, astr.size-1)->tok;
+ ad->asm_label = /* save string as token, for later */
+ tok_alloc((char*)astr.data, astr.size-1)->tok | SYM_FIELD;
skip(')');
cstr_free(&astr);
break;
@@ -3370,8 +4195,7 @@ redo:
break;
case TOK_NORETURN1:
case TOK_NORETURN2:
- /* currently, no need to handle it because tcc does not
- track unused objects */
+ ad->f.func_noreturn = 1;
break;
case TOK_CDECL1:
case TOK_CDECL2:
@@ -3428,6 +4252,9 @@ redo:
case TOK_DLLEXPORT:
ad->a.dllexport = 1;
break;
+ case TOK_NODECORATE:
+ ad->a.nodecorate = 1;
+ break;
case TOK_DLLIMPORT:
ad->a.dllimport = 1;
break;
@@ -3456,7 +4283,7 @@ redo:
goto redo;
}
-static Sym * find_field (CType *type, int v)
+static Sym * find_field (CType *type, int v, int *cumofs)
{
Sym *s = type->ref;
v |= SYM_FIELD;
@@ -3464,9 +4291,11 @@ static Sym * find_field (CType *type, int v)
if ((s->v & SYM_FIELD) &&
(s->type.t & VT_BTYPE) == VT_STRUCT &&
(s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
- Sym *ret = find_field (&s->type, v);
- if (ret)
+ Sym *ret = find_field (&s->type, v, cumofs);
+ if (ret) {
+ *cumofs += s->c;
return ret;
+ }
}
if (s->v == v)
break;
@@ -3474,18 +4303,6 @@ static Sym * find_field (CType *type, int v)
return s;
}
-static void struct_add_offset (Sym *s, int offset)
-{
- while ((s = s->next) != NULL) {
- if ((s->v & SYM_FIELD) &&
- (s->type.t & VT_BTYPE) == VT_STRUCT &&
- (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
- struct_add_offset(s->type.ref, offset);
- } else
- s->c += offset;
- }
-}
-
static void struct_layout(CType *type, AttributeDef *ad)
{
int size, align, maxalign, offset, c, bit_pos, bit_size;
@@ -3635,41 +4452,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
printf("\n");
#endif
- if (f->v & SYM_FIRST_ANOM && (f->type.t & VT_BTYPE) == VT_STRUCT) {
- Sym *ass;
- /* An anonymous struct/union. Adjust member offsets
- to reflect the real offset of our containing struct.
- Also set the offset of this anon member inside
- the outer struct to be zero. Via this it
- works when accessing the field offset directly
- (from base object), as well as when recursing
- members in initializer handling. */
- int v2 = f->type.ref->v;
- if (!(v2 & SYM_FIELD) &&
- (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
- Sym **pps;
- /* This happens only with MS extensions. The
- anon member has a named struct type, so it
- potentially is shared with other references.
- We need to unshare members so we can modify
- them. */
- ass = f->type.ref;
- f->type.ref = sym_push(anon_sym++ | SYM_FIELD,
- &f->type.ref->type, 0,
- f->type.ref->c);
- pps = &f->type.ref->next;
- while ((ass = ass->next) != NULL) {
- *pps = sym_push(ass->v, &ass->type, 0, ass->c);
- pps = &((*pps)->next);
- }
- *pps = NULL;
- }
- struct_add_offset(f->type.ref, offset);
- f->c = 0;
- } else {
- f->c = offset;
- }
-
+ f->c = offset;
f->r = 0;
}
@@ -3714,6 +4497,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
/* try to access the field using a different type */
c0 = -1, s = align = 1;
+ t.t = VT_BYTE;
for (;;) {
px = f->c * 8 + bit_pos;
cx = (px >> 3) & -align;
@@ -3802,6 +4586,7 @@ do_decl:
next();
if (s->c != -1)
tcc_error("struct/union/enum already defined");
+ s->c = -2;
/* cannot be empty */
/* non empty enums are not allowed */
ps = &s->next;
@@ -3900,6 +4685,7 @@ do_decl:
get_tok_str(v, NULL));
}
if ((type1.t & VT_BTYPE) == VT_FUNC ||
+ (type1.t & VT_BTYPE) == VT_VOID ||
(type1.t & VT_STORAGE))
tcc_error("invalid type for '%s'",
get_tok_str(v, NULL));
@@ -3967,21 +4753,18 @@ do_decl:
}
skip('}');
parse_attribute(&ad);
- struct_layout(type, &ad);
+ if (ad.cleanup_func) {
+ tcc_warning("attribute '__cleanup__' ignored on type");
+ }
+ struct_layout(type, &ad);
}
}
}
static void sym_to_attr(AttributeDef *ad, Sym *s)
{
- if (s->a.aligned && 0 == ad->a.aligned)
- ad->a.aligned = s->a.aligned;
- if (s->f.func_call && 0 == ad->f.func_call)
- ad->f.func_call = s->f.func_call;
- if (s->f.func_type && 0 == ad->f.func_type)
- ad->f.func_type = s->f.func_type;
- if (s->a.packed)
- ad->a.packed = 1;
+ merge_symattr(&ad->a, &s->a);
+ merge_funcattr(&ad->f, &s->f);
}
/* Add type qualifiers to a type. If the type is an array then the qualifiers
@@ -4000,7 +4783,7 @@ static void parse_btype_qualify(CType *type, int qualifiers)
*/
static int parse_btype(CType *type, AttributeDef *ad)
{
- int t, u, bt, st, type_found, typespec_found, g;
+ int t, u, bt, st, type_found, typespec_found, g, n;
Sym *s;
CType type1;
@@ -4046,6 +4829,27 @@ static int parse_btype(CType *type, AttributeDef *ad)
case TOK_INT:
u = VT_INT;
goto basic_type;
+ case TOK_ALIGNAS:
+ { int n;
+ AttributeDef ad1;
+ next();
+ skip('(');
+ memset(&ad1, 0, sizeof(AttributeDef));
+ if (parse_btype(&type1, &ad1)) {
+ type_decl(&type1, &ad1, &n, TYPE_ABSTRACT);
+ if (ad1.a.aligned)
+ n = 1 << (ad1.a.aligned - 1);
+ else
+ type_size(&type1, &n);
+ } else {
+ n = expr_const();
+ if (n <= 0 || (n & (n - 1)) != 0)
+ tcc_error("alignment must be a positive power of two");
+ }
+ skip(')');
+ ad->a.aligned = exact_log2p1(n);
+ }
+ continue;
case TOK_LONG:
if ((t & VT_BTYPE) == VT_DOUBLE) {
t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
@@ -4155,7 +4959,10 @@ static int parse_btype(CType *type, AttributeDef *ad)
t |= VT_INLINE;
next();
break;
-
+ case TOK_NORETURN3:
+ next();
+ ad->f.func_noreturn = 1;
+ break;
/* GNUC attribute */
case TOK_ATTRIBUTE1:
case TOK_ATTRIBUTE2:
@@ -4164,7 +4971,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
u = ad->attr_mode -1;
t = (t & ~(VT_BTYPE|VT_LONG)) | u;
}
- break;
+ continue;
/* GNUC typeof */
case TOK_TYPEOF1:
case TOK_TYPEOF2:
@@ -4182,6 +4989,14 @@ static int parse_btype(CType *type, AttributeDef *ad)
s = sym_find(tok);
if (!s || !(s->type.t & VT_TYPEDEF))
goto the_end;
+
+ n = tok, next();
+ if (tok == ':' && !in_generic) {
+ /* ignore if it's a label */
+ unget_tok(n);
+ goto the_end;
+ }
+
t &= ~(VT_BTYPE|VT_LONG);
u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
type->t = (s->type.t & ~VT_TYPEDEF) | u;
@@ -4191,7 +5006,6 @@ static int parse_btype(CType *type, AttributeDef *ad)
t = type->t;
/* get attributes from typedef */
sym_to_attr(ad, s);
- next();
typespec_found = 1;
st = bt = -2;
break;
@@ -4207,9 +5021,9 @@ the_end:
bt = t & (VT_BTYPE|VT_LONG);
if (bt == VT_LONG)
t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT;
-#ifdef TCC_TARGET_PE
+#if defined TCC_TARGET_PE || (defined _WIN32 && defined _MSC_VER)
if (bt == VT_LDOUBLE)
- t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE;
+ t = (t & ~(VT_BTYPE|VT_LONG)) | (VT_DOUBLE|VT_LONG);
#endif
type->t = t;
return type_found;
@@ -4254,7 +5068,7 @@ static int asm_label_instr(void)
static int post_type(CType *type, AttributeDef *ad, int storage, int td)
{
- int n, l, t1, arg_size, align;
+ int n, l, t1, arg_size, align, unused_align;
Sym **plast, *s, *first;
AttributeDef ad1;
CType pt;
@@ -4268,9 +5082,10 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
l = 0;
else if (parse_btype(&pt, &ad1))
l = FUNC_NEW;
- else if (td)
- return 0;
- else
+ else if (td) {
+ merge_attr (ad, &ad1);
+ return 0;
+ } else
l = FUNC_OLD;
first = NULL;
plast = &first;
@@ -4284,15 +5099,16 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT);
if ((pt.t & VT_BTYPE) == VT_VOID)
tcc_error("parameter declared as void");
- arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
} else {
n = tok;
if (n < TOK_UIDENT)
expect("identifier");
pt.t = VT_VOID; /* invalid type */
+ pt.ref = NULL;
next();
}
convert_parameter_type(&pt);
+ arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
s = sym_push(n | SYM_FIELD, &pt, 0, 0);
*plast = s;
plast = &s->next;
@@ -4335,8 +5151,23 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
int saved_nocode_wanted = nocode_wanted;
/* array definition */
next();
- if (tok == TOK_RESTRICT1)
- next();
+ while (1) {
+ /* XXX The optional type-quals and static should only be accepted
+ in parameter decls. The '*' as well, and then even only
+ in prototypes (not function defs). */
+ switch (tok) {
+ case TOK_RESTRICT1: case TOK_RESTRICT2: case TOK_RESTRICT3:
+ case TOK_CONST1:
+ case TOK_VOLATILE1:
+ case TOK_STATIC:
+ case '*':
+ next();
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
n = -1;
t1 = 0;
if (tok != ']') {
@@ -4357,17 +5188,25 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
} else {
if (!is_integer_btype(vtop->type.t & VT_BTYPE))
tcc_error("size of variable length array should be an integer");
+ n = 0;
t1 = VT_VLA;
}
}
skip(']');
/* parse next post type */
post_type(type, ad, storage, 0);
- if (type->t == VT_FUNC)
+
+ if ((type->t & VT_BTYPE) == VT_FUNC)
tcc_error("declaration of an array of functions");
+ if ((type->t & VT_BTYPE) == VT_VOID
+ || type_size(type, &unused_align) < 0)
+ tcc_error("declaration of an array of incomplete type elements");
+
t1 |= type->t & VT_VLA;
-
+
if (t1 & VT_VLA) {
+ if (n < 0)
+ tcc_error("need explicit inner array size in VLAs");
loc -= type_size(&int_type, &align);
loc &= -align;
n = loc;
@@ -4451,12 +5290,14 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
parse_attribute(ad);
post = type_decl(type, ad, v, td);
skip(')');
- }
+ } else
+ goto abstract;
} else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
/* type identifier */
*v = tok;
next();
} else {
+ abstract:
if (!(td & TYPE_ABSTRACT))
expect("identifier");
*v = 0;
@@ -4467,23 +5308,6 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
return ret;
}
-/* compute the lvalue VT_LVAL_xxx needed to match type t. */
-ST_FUNC int lvalue_type(int t)
-{
- int bt, r;
- r = VT_LVAL;
- bt = t & VT_BTYPE;
- if (bt == VT_BYTE || bt == VT_BOOL)
- r |= VT_LVAL_BYTE;
- else if (bt == VT_SHORT)
- r |= VT_LVAL_SHORT;
- else
- return r;
- if (t & VT_UNSIGNED)
- r |= VT_LVAL_UNSIGNED;
- return r;
-}
-
/* indirection with full error checking and bound check */
ST_FUNC void indir(void)
{
@@ -4496,9 +5320,9 @@ ST_FUNC void indir(void)
gv(RC_INT);
vtop->type = *pointed_type(&vtop->type);
/* Arrays and functions are never lvalues */
- if (!(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_VLA)
+ if (!(vtop->type.t & (VT_ARRAY | VT_VLA))
&& (vtop->type.t & VT_BTYPE) != VT_FUNC) {
- vtop->r |= lvalue_type(vtop->type.t);
+ vtop->r |= VT_LVAL;
/* if bound checking, the referenced pointer must be checked */
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
@@ -4523,6 +5347,8 @@ static void gfunc_param_typed(Sym *func, Sym *arg)
type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
type.ref = vtop->type.ref;
gen_cast(&type);
+ } else if (vtop->r & VT_MUSTCAST) {
+ force_charshort_cast();
}
} else if (arg == NULL) {
tcc_error("too many arguments to function");
@@ -4573,18 +5399,48 @@ static void parse_type(CType *type)
static void parse_builtin_params(int nc, const char *args)
{
char c, sep = '(';
- CType t;
+ CType type;
if (nc)
nocode_wanted++;
next();
+ if (*args == 0)
+ skip(sep);
while ((c = *args++)) {
skip(sep);
sep = ',';
+ if (c == 't') {
+ parse_type(&type);
+ vpush(&type);
+ continue;
+ }
+ expr_eq();
+ type.ref = NULL;
+ type.t = 0;
switch (c) {
- case 'e': expr_eq(); continue;
- case 't': parse_type(&t); vpush(&t); continue;
- default: tcc_error("internal error"); break;
+ case 'e':
+ continue;
+ case 'V':
+ type.t = VT_CONSTANT;
+ case 'v':
+ type.t |= VT_VOID;
+ mk_pointer (&type);
+ break;
+ case 'S':
+ type.t = VT_CONSTANT;
+ case 's':
+ type.t |= char_type.t;
+ mk_pointer (&type);
+ break;
+ case 'i':
+ type.t = VT_INT;
+ break;
+ case 'l':
+ type.t = VT_SIZE_T;
+ break;
+ default:
+ tcc_error("internal error");
}
+ gen_assign_cast(&type);
}
skip(')');
if (nc)
@@ -4598,6 +5454,10 @@ ST_FUNC void unary(void)
Sym *s;
AttributeDef ad;
+ /* generate line number info */
+ if (tcc_state->do_debug)
+ tcc_debug_line(tcc_state);
+
sizeof_caller = in_sizeof;
in_sizeof = 0;
type.ref = NULL;
@@ -4704,7 +5564,7 @@ ST_FUNC void unary(void)
r = VT_LOCAL;
/* all except arrays are lvalues */
if (!(type.t & VT_ARRAY))
- r |= lvalue_type(type.t);
+ r |= VT_LVAL;
memset(&ad, 0, sizeof(AttributeDef));
decl_initializer_alloc(&type, &ad, r, 1, 0, 0);
} else {
@@ -4717,7 +5577,7 @@ ST_FUNC void unary(void)
}
} else if (tok == '{') {
int saved_nocode_wanted = nocode_wanted;
- if (const_wanted)
+ if (const_wanted && !(nocode_wanted & unevalmask))
tcc_error("expected constant");
/* save all registers */
save_regs(0);
@@ -4726,7 +5586,7 @@ ST_FUNC void unary(void)
as statement expressions can't ever be entered from the
outside, so any reactivation of code emission (from labels
or loop heads) can be disabled again after the end of it. */
- block(NULL, NULL, 1);
+ block(1);
nocode_wanted = saved_nocode_wanted;
skip(')');
} else {
@@ -4750,21 +5610,15 @@ ST_FUNC void unary(void)
if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
!(vtop->type.t & VT_ARRAY))
test_lvalue();
+ if (vtop->sym)
+ vtop->sym->a.addrtaken = 1;
mk_pointer(&vtop->type);
gaddrof();
break;
case '!':
next();
unary();
- if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- gen_cast_s(VT_BOOL);
- vtop->c.i = !vtop->c.i;
- } else if ((vtop->r & VT_VALMASK) == VT_CMP)
- vtop->c.i ^= 1;
- else {
- save_regs(1);
- vseti(VT_JMP, gvtst(1, 0));
- }
+ gen_test_zero(TOK_EQ);
break;
case '~':
next();
@@ -4788,11 +5642,14 @@ ST_FUNC void unary(void)
case TOK_SIZEOF:
case TOK_ALIGNOF1:
case TOK_ALIGNOF2:
+ case TOK_ALIGNOF3:
t = tok;
next();
in_sizeof++;
expr_type(&type, unary); /* Perform a in_sizeof = 0; */
- s = vtop[1].sym; /* hack: accessing previous vtop */
+ s = NULL;
+ if (vtop[1].r & VT_SYM)
+ s = vtop[1].sym; /* hack: accessing previous vtop */
size = type_size(&type, &align);
if (s && s->a.aligned)
align = 1 << (s->a.aligned - 1);
@@ -4876,18 +5733,42 @@ ST_FUNC void unary(void)
mk_pointer(&type);
vset(&type, VT_LOCAL, 0); /* local frame */
while (level--) {
+#ifdef TCC_TARGET_RISCV64
+ vpushi(2*PTR_SIZE);
+ gen_op('-');
+#endif
mk_pointer(&vtop->type);
indir(); /* -> parent frame */
}
if (tok1 == TOK_builtin_return_address) {
// assume return address is just above frame pointer on stack
+#ifdef TCC_TARGET_ARM
+ vpushi(2*PTR_SIZE);
+ gen_op('+');
+#elif defined TCC_TARGET_RISCV64
+ vpushi(PTR_SIZE);
+ gen_op('-');
+#else
vpushi(PTR_SIZE);
gen_op('+');
+#endif
mk_pointer(&vtop->type);
indir();
}
}
break;
+#ifdef TCC_TARGET_RISCV64
+ case TOK_builtin_va_start:
+ parse_builtin_params(0, "ee");
+ r = vtop->r & VT_VALMASK;
+ if (r == VT_LLOCAL)
+ r = VT_LOCAL;
+ if (r != VT_LOCAL)
+ tcc_error("__builtin_va_start expects a local variable");
+ gen_va_start();
+ vstore();
+ break;
+#endif
#ifdef TCC_TARGET_X86_64
#ifdef TCC_TARGET_PE
case TOK_builtin_va_start:
@@ -4908,12 +5789,12 @@ ST_FUNC void unary(void)
vpushi(classify_x86_64_va_arg(&vtop->type));
vswap();
vpop();
- break;
+ break;
#endif
#endif
#ifdef TCC_TARGET_ARM64
- case TOK___va_start: {
+ case TOK_builtin_va_start: {
parse_builtin_params(0, "ee");
//xx check types
gen_va_start();
@@ -4921,7 +5802,7 @@ ST_FUNC void unary(void)
vtop->type.t = VT_VOID;
break;
}
- case TOK___va_arg: {
+ case TOK_builtin_va_arg: {
parse_builtin_params(0, "et");
type = vtop->type;
vpop();
@@ -4938,6 +5819,7 @@ ST_FUNC void unary(void)
break;
}
#endif
+
/* pre operations */
case TOK_INC:
case TOK_DEC:
@@ -4958,7 +5840,7 @@ ST_FUNC void unary(void)
vtop->c.f = -1.0 * 0.0;
else if (t == VT_DOUBLE)
vtop->c.d = -1.0 * 0.0;
- else
+ else
vtop->c.ld = -1.0 * 0.0;
} else
vpushi(0);
@@ -4995,11 +5877,16 @@ ST_FUNC void unary(void)
int has_match = 0;
int learn = 0;
TokenString *str = NULL;
+ int saved_const_wanted = const_wanted;
next();
skip('(');
+ const_wanted = 0;
expr_type(&controlling_type, expr_eq);
controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY);
+ if ((controlling_type.t & VT_BTYPE) == VT_FUNC)
+ mk_pointer(&controlling_type);
+ const_wanted = saved_const_wanted;
for (;;) {
learn = 0;
skip(',');
@@ -5014,7 +5901,11 @@ ST_FUNC void unary(void)
AttributeDef ad_tmp;
int itmp;
CType cur_type;
+
+ in_generic++;
parse_btype(&cur_type, &ad_tmp);
+ in_generic--;
+
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
if (compare_types(&controlling_type, &cur_type, 0)) {
if (has_match) {
@@ -5051,17 +5942,18 @@ ST_FUNC void unary(void)
}
// special qnan , snan and infinity values
case TOK___NAN__:
- vpush64(VT_DOUBLE, 0x7ff8000000000000ULL);
+ n = 0x7fc00000;
+special_math_val:
+ vpushi(n);
+ vtop->type.t = VT_FLOAT;
next();
break;
case TOK___SNAN__:
- vpush64(VT_DOUBLE, 0x7ff0000000000001ULL);
- next();
- break;
+ n = 0x7f800001;
+ goto special_math_val;
case TOK___INF__:
- vpush64(VT_DOUBLE, 0x7ff0000000000000ULL);
- next();
- break;
+ n = 0x7f800000;
+ goto special_math_val;
default:
tok_identifier:
@@ -5070,6 +5962,26 @@ ST_FUNC void unary(void)
if (t < TOK_UIDENT)
expect("identifier");
s = sym_find(t);
+#ifdef CONFIG_TCC_BCHECK
+ /* HACK to undo alias definition in tccpp.c
+ if function has no bound checking */
+ if (tcc_state->do_bounds_check == 0 && s &&
+ (s->type.t & VT_BTYPE) == VT_FUNC && (s->asm_label & SYM_FIELD)) {
+ const char *name = get_tok_str(s->asm_label & ~SYM_FIELD, NULL);
+
+ if (name && strncmp (name, "__bound_", strlen("__bound_")) == 0) {
+ char str[100];
+ int v = s->v;
+
+ sprintf (str, "!%s", name); /* illegal name */
+ t = tok_alloc(str, strlen(str))->tok;
+ s = sym_find(t);
+ if (s == NULL)
+ s = external_global_sym(t, &func_old_type);
+ s->asm_label = v | SYM_FIELD; /* use old name as alias */
+ }
+ }
+#endif
if (!s || IS_ASM_SYM(s)) {
const char *name = get_tok_str(t, NULL);
if (tok != '(')
@@ -5084,7 +5996,7 @@ ST_FUNC void unary(void)
#endif
)
tcc_warning("implicit declaration of function '%s'", name);
- s = external_global_sym(t, &func_old_type, 0);
+ s = external_global_sym(t, &func_old_type);
}
r = s->r;
@@ -5113,7 +6025,7 @@ ST_FUNC void unary(void)
inc(1, tok);
next();
} else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) {
- int qualifiers;
+ int qualifiers, cumofs = 0;
/* field */
if (tok == TOK_ARROW)
indir();
@@ -5128,22 +6040,22 @@ ST_FUNC void unary(void)
next();
if (tok == TOK_CINT || tok == TOK_CUINT)
expect("field name");
- s = find_field(&vtop->type, tok);
+ s = find_field(&vtop->type, tok, &cumofs);
if (!s)
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc));
/* add field offset to pointer */
vtop->type = char_pointer_type; /* change type to 'char *' */
- vpushi(s->c);
+ vpushi(cumofs + s->c);
gen_op('+');
/* change type to field type, and set to lvalue */
vtop->type = s->type;
vtop->type.t |= qualifiers;
/* an array is never an lvalue */
if (!(vtop->type.t & VT_ARRAY)) {
- vtop->r |= lvalue_type(vtop->type.t);
+ vtop->r |= VT_LVAL;
#ifdef CONFIG_TCC_BCHECK
/* if bound checking, the referenced pointer must be checked */
- if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL)
+ if (tcc_state->do_bounds_check)
vtop->r |= VT_MUSTBOUND;
#endif
}
@@ -5184,7 +6096,7 @@ ST_FUNC void unary(void)
variadic = (s->f.func_type == FUNC_ELLIPSIS);
ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
&ret_align, &regsize);
- if (!ret_nregs) {
+ if (ret_nregs <= 0) {
/* get some space for the returned structure */
size = type_size(&s->type, &align);
#ifdef TCC_TARGET_ARM64
@@ -5203,33 +6115,20 @@ ST_FUNC void unary(void)
problems */
vseti(VT_LOCAL, loc);
ret.c = vtop->c;
- nb_args++;
+ if (ret_nregs < 0)
+ vtop--;
+ else
+ nb_args++;
}
} else {
ret_nregs = 1;
ret.type = s->type;
}
- if (ret_nregs) {
+ if (ret_nregs > 0) {
/* return in register */
- if (is_float(ret.type.t)) {
- ret.r = reg_fret(ret.type.t);
-#ifdef TCC_TARGET_X86_64
- if ((ret.type.t & VT_BTYPE) == VT_QFLOAT)
- ret.r2 = REG_QRET;
-#endif
- } else {
-#ifndef TCC_TARGET_ARM64
-#ifdef TCC_TARGET_X86_64
- if ((ret.type.t & VT_BTYPE) == VT_QLONG)
-#else
- if ((ret.type.t & VT_BTYPE) == VT_LLONG)
-#endif
- ret.r2 = REG_LRET;
-#endif
- ret.r = REG_IRET;
- }
ret.c.i = 0;
+ PUT_R_RET(&ret, ret.type.t);
}
if (tok != ')') {
for(;;) {
@@ -5248,61 +6147,84 @@ ST_FUNC void unary(void)
skip(')');
gfunc_call(nb_args);
- /* return value */
- for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) {
- vsetc(&ret.type, r, &ret.c);
- vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */
- }
+ if (ret_nregs < 0) {
+ vsetc(&ret.type, ret.r, &ret.c);
+#ifdef TCC_TARGET_RISCV64
+ arch_transfer_ret_regs(1);
+#endif
+ } else {
+ /* return value */
+ for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) {
+ vsetc(&ret.type, r, &ret.c);
+ vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */
+ }
- /* handle packed struct return */
- if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
- int addr, offset;
+ /* handle packed struct return */
+ if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
+ int addr, offset;
- size = type_size(&s->type, &align);
- /* We're writing whole regs often, make sure there's enough
- space. Assume register size is power of 2. */
- if (regsize > align)
- align = regsize;
- loc = (loc - size) & -align;
- addr = loc;
- offset = 0;
- for (;;) {
- vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
- vswap();
- vstore();
- vtop--;
- if (--ret_nregs == 0)
- break;
- offset += regsize;
+ size = type_size(&s->type, &align);
+ /* We're writing whole regs often, make sure there's enough
+ space. Assume register size is power of 2. */
+ if (regsize > align)
+ align = regsize;
+ loc = (loc - size) & -align;
+ addr = loc;
+ offset = 0;
+ for (;;) {
+ vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
+ vswap();
+ vstore();
+ vtop--;
+ if (--ret_nregs == 0)
+ break;
+ offset += regsize;
+ }
+ vset(&s->type, VT_LOCAL | VT_LVAL, addr);
+ }
+
+ /* Promote char/short return values. This is matters only
+ for calling function that were not compiled by TCC and
+ only on some architectures. For those where it doesn't
+ matter we expect things to be already promoted to int,
+ but not larger. */
+ t = s->type.t & VT_BTYPE;
+ if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL) {
+#ifdef PROMOTE_RET
+ vtop->r |= BFVAL(VT_MUSTCAST, 1);
+#else
+ vtop->type.t = VT_INT;
+#endif
}
- vset(&s->type, VT_LOCAL | VT_LVAL, addr);
}
+ if (s->f.func_noreturn)
+ CODE_OFF();
} else {
break;
}
}
}
-ST_FUNC void expr_prod(void)
+#ifndef precedence_parser /* original top-down parser */
+
+static void expr_prod(void)
{
int t;
unary();
- while (tok == '*' || tok == '/' || tok == '%') {
- t = tok;
+ while ((t = tok) == '*' || t == '/' || t == '%') {
next();
unary();
gen_op(t);
}
}
-ST_FUNC void expr_sum(void)
+static void expr_sum(void)
{
int t;
expr_prod();
- while (tok == '+' || tok == '-') {
- t = tok;
+ while ((t = tok) == '+' || t == '-') {
next();
expr_prod();
gen_op(t);
@@ -5314,8 +6236,7 @@ static void expr_shift(void)
int t;
expr_sum();
- while (tok == TOK_SHL || tok == TOK_SAR) {
- t = tok;
+ while ((t = tok) == TOK_SHL || t == TOK_SAR) {
next();
expr_sum();
gen_op(t);
@@ -5327,9 +6248,8 @@ static void expr_cmp(void)
int t;
expr_shift();
- while ((tok >= TOK_ULE && tok <= TOK_GT) ||
- tok == TOK_ULT || tok == TOK_UGE) {
- t = tok;
+ while (((t = tok) >= TOK_ULE && t <= TOK_GT) ||
+ t == TOK_ULT || t == TOK_UGE) {
next();
expr_shift();
gen_op(t);
@@ -5341,8 +6261,7 @@ static void expr_cmpeq(void)
int t;
expr_cmp();
- while (tok == TOK_EQ || tok == TOK_NE) {
- t = tok;
+ while ((t = tok) == TOK_EQ || t == TOK_NE) {
next();
expr_cmp();
gen_op(t);
@@ -5379,87 +6298,74 @@ static void expr_or(void)
}
}
+static void expr_landor(int op);
+
static void expr_land(void)
{
expr_or();
- if (tok == TOK_LAND) {
- int t = 0;
- for(;;) {
- if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- gen_cast_s(VT_BOOL);
- if (vtop->c.i) {
- vpop();
- } else {
- nocode_wanted++;
- while (tok == TOK_LAND) {
- next();
- expr_or();
- vpop();
- }
- nocode_wanted--;
- if (t)
- gsym(t);
- gen_cast_s(VT_INT);
- break;
- }
- } else {
- if (!t)
- save_regs(1);
- t = gvtst(1, t);
- }
- if (tok != TOK_LAND) {
- if (t)
- vseti(VT_JMPI, t);
- else
- vpushi(1);
- break;
- }
- next();
- expr_or();
- }
- }
+ if (tok == TOK_LAND)
+ expr_landor(tok);
}
static void expr_lor(void)
{
expr_land();
- if (tok == TOK_LOR) {
- int t = 0;
- for(;;) {
- if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- gen_cast_s(VT_BOOL);
- if (!vtop->c.i) {
- vpop();
- } else {
- nocode_wanted++;
- while (tok == TOK_LOR) {
- next();
- expr_land();
- vpop();
- }
- nocode_wanted--;
- if (t)
- gsym(t);
- gen_cast_s(VT_INT);
- break;
- }
- } else {
- if (!t)
- save_regs(1);
- t = gvtst(0, t);
- }
- if (tok != TOK_LOR) {
- if (t)
- vseti(VT_JMP, t);
- else
- vpushi(0);
- break;
- }
- next();
- expr_land();
- }
+ if (tok == TOK_LOR)
+ expr_landor(tok);
+}
+
+# define expr_landor_next(op) op == TOK_LAND ? expr_or() : expr_land()
+#else /* defined precedence_parser */
+# define expr_landor_next(op) unary(), expr_infix(precedence(op) + 1)
+# define expr_lor() unary(), expr_infix(1)
+
+static int precedence(int tok)
+{
+ switch (tok) {
+ case TOK_LOR: return 1;
+ case TOK_LAND: return 2;
+ case '|': return 3;
+ case '^': return 4;
+ case '&': return 5;
+ case TOK_EQ: case TOK_NE: return 6;
+ relat: case TOK_ULT: case TOK_UGE: return 7;
+ case TOK_SHL: case TOK_SAR: return 8;
+ case '+': case '-': return 9;
+ case '*': case '/': case '%': return 10;
+ default:
+ if (tok >= TOK_ULE && tok <= TOK_GT)
+ goto relat;
+ return 0;
+ }
+}
+static unsigned char prec[256];
+static void init_prec(void)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ prec[i] = precedence(i);
+}
+#define precedence(i) ((unsigned)i < 256 ? prec[i] : 0)
+
+static void expr_landor(int op);
+
+static void expr_infix(int p)
+{
+ int t = tok, p2;
+ while ((p2 = precedence(t)) >= p) {
+ if (t == TOK_LOR || t == TOK_LAND) {
+ expr_landor(t);
+ } else {
+ next();
+ unary();
+ if (precedence(tok) > p2)
+ expr_infix(p2 + 1);
+ gen_op(t);
+ }
+ t = tok;
}
}
+#endif
/* Assuming vtop is a value used in a conditional context
(i.e. compared with zero) return 0 if it's false, 1 if
@@ -5477,178 +6383,177 @@ static int condition_3way(void)
return c;
}
+static void expr_landor(int op)
+{
+ int t = 0, cc = 1, f = 0, i = op == TOK_LAND, c;
+ for(;;) {
+ c = f ? i : condition_3way();
+ if (c < 0)
+ save_regs(1), cc = 0;
+ else if (c != i)
+ nocode_wanted++, f = 1;
+ if (tok != op)
+ break;
+ if (c < 0)
+ t = gvtst(i, t);
+ else
+ vpop();
+ next();
+ expr_landor_next(op);
+ }
+ if (cc || f) {
+ vpop();
+ vpushi(i ^ f);
+ gsym(t);
+ nocode_wanted -= f;
+ } else {
+ gvtst_set(i, t);
+ }
+}
+
+static int is_cond_bool(SValue *sv)
+{
+ if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST
+ && (sv->type.t & VT_BTYPE) == VT_INT)
+ return (unsigned)sv->c.i < 2;
+ if (sv->r == VT_CMP)
+ return 1;
+ return 0;
+}
+
static void expr_cond(void)
{
- int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g;
+ int tt, u, r1, r2, rc, t1, t2, islv, c, g;
SValue sv;
- CType type, type1, type2;
+ CType type;
+ int ncw_prev;
expr_lor();
if (tok == '?') {
next();
c = condition_3way();
g = (tok == ':' && gnu_ext);
- if (c < 0) {
+ tt = 0;
+ if (!g) {
+ if (c < 0) {
+ save_regs(1);
+ tt = gvtst(1, 0);
+ } else {
+ vpop();
+ }
+ } else if (c < 0) {
/* needed to avoid having different registers saved in
each branch */
- if (is_float(vtop->type.t)) {
- rc = RC_FLOAT;
-#ifdef TCC_TARGET_X86_64
- if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
- rc = RC_ST0;
- }
-#endif
- } else
- rc = RC_INT;
- gv(rc);
save_regs(1);
- if (g)
- gv_dup();
- tt = gvtst(1, 0);
-
- } else {
- if (!g)
- vpop();
- tt = 0;
+ gv_dup();
+ tt = gvtst(0, 0);
}
- if (1) {
- if (c == 0)
- nocode_wanted++;
- if (!g)
- gexpr();
+ ncw_prev = nocode_wanted;
+ if (c == 0)
+ nocode_wanted++;
+ if (!g)
+ gexpr();
- type1 = vtop->type;
- sv = *vtop; /* save value to handle it later */
- vtop--; /* no vpop so that FP stack is not flushed */
- skip(':');
+ if (c < 0 && vtop->r == VT_CMP) {
+ t1 = gvtst(0, 0);
+ vpushi(0);
+ gvtst_set(0, t1);
+ gv(RC_INT);
+ }
- u = 0;
- if (c < 0)
- u = gjmp(0);
+ if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
+ mk_pointer(&vtop->type);
+ sv = *vtop; /* save value to handle it later */
+ vtop--; /* no vpop so that FP stack is not flushed */
+
+ if (g) {
+ u = tt;
+ } else if (c < 0) {
+ u = gjmp(0);
gsym(tt);
+ } else
+ u = 0;
- if (c == 0)
- nocode_wanted--;
- if (c == 1)
- nocode_wanted++;
- expr_cond();
- if (c == 1)
- nocode_wanted--;
-
- type2 = vtop->type;
- t1 = type1.t;
- bt1 = t1 & VT_BTYPE;
- t2 = type2.t;
- bt2 = t2 & VT_BTYPE;
- type.ref = NULL;
-
- /* cast operands to correct type according to ISOC rules */
- if (is_float(bt1) || is_float(bt2)) {
- if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
- type.t = VT_LDOUBLE;
-
- } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
- type.t = VT_DOUBLE;
- } else {
- type.t = VT_FLOAT;
- }
- } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
- /* cast to biggest op */
- type.t = VT_LLONG | VT_LONG;
- if (bt1 == VT_LLONG)
- type.t &= t1;
- if (bt2 == VT_LLONG)
- type.t &= t2;
- /* convert to unsigned if it does not fit in a long long */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
- type.t |= VT_UNSIGNED;
- } else if (bt1 == VT_PTR || bt2 == VT_PTR) {
- /* If one is a null ptr constant the result type
- is the other. */
- if (is_null_pointer (vtop))
- type = type1;
- else if (is_null_pointer (&sv))
- type = type2;
- /* XXX: test pointer compatibility, C99 has more elaborate
- rules here. */
- else
- type = type1;
- } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
- /* XXX: test function pointer compatibility */
- type = bt1 == VT_FUNC ? type1 : type2;
- } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
- /* XXX: test structure compatibility */
- type = bt1 == VT_STRUCT ? type1 : type2;
- } else if (bt1 == VT_VOID || bt2 == VT_VOID) {
- /* NOTE: as an extension, we accept void on only one side */
- type.t = VT_VOID;
+ nocode_wanted = ncw_prev;
+ if (c == 1)
+ nocode_wanted++;
+ skip(':');
+ expr_cond();
+
+ if (c < 0 && is_cond_bool(vtop) && is_cond_bool(&sv)) {
+ if (sv.r == VT_CMP) {
+ t1 = sv.jtrue;
+ t2 = u;
} else {
- /* integer operations */
- type.t = VT_INT | (VT_LONG & (t1 | t2));
- /* convert to unsigned if it does not fit in an integer */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
- type.t |= VT_UNSIGNED;
+ t1 = gvtst(0, 0);
+ t2 = gjmp(0);
+ gsym(u);
+ vpushv(&sv);
}
- /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
- that `(expr ? a : b).mem` does not error with "lvalue expected" */
- islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
- islv &= c < 0;
+ gvtst_set(0, t1);
+ gvtst_set(1, t2);
+ nocode_wanted = ncw_prev;
+ // tcc_warning("two conditions expr_cond");
+ return;
+ }
- /* now we convert second operand */
- if (c != 1) {
- gen_cast(&type);
- if (islv) {
- mk_pointer(&vtop->type);
- gaddrof();
- } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
- gaddrof();
- }
+ if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
+ mk_pointer(&vtop->type);
+
+ /* cast operands to correct type according to ISOC rules */
+ if (!combine_types(&type, &sv, vtop, '?'))
+ type_incompatibility_error(&sv.type, &vtop->type,
+ "type mismatch in conditional expression (have '%s' and '%s')");
+ /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
+ that `(expr ? a : b).mem` does not error with "lvalue expected" */
+ islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
+
+ /* now we convert second operand */
+ if (c != 1) {
+ gen_cast(&type);
+ if (islv) {
+ mk_pointer(&vtop->type);
+ gaddrof();
+ } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
+ gaddrof();
+ }
- rc = RC_INT;
- if (is_float(type.t)) {
- rc = RC_FLOAT;
-#ifdef TCC_TARGET_X86_64
- if ((type.t & VT_BTYPE) == VT_LDOUBLE) {
- rc = RC_ST0;
- }
-#endif
- } else if ((type.t & VT_BTYPE) == VT_LLONG) {
- /* for long longs, we use fixed registers to avoid having
- to handle a complicated move */
- rc = RC_IRET;
- }
+ rc = RC_TYPE(type.t);
+ /* for long longs, we use fixed registers to avoid having
+ to handle a complicated move */
+ if (USING_TWO_WORDS(type.t))
+ rc = RC_RET(type.t);
- tt = r2 = 0;
- if (c < 0) {
- r2 = gv(rc);
- tt = gjmp(0);
- }
- gsym(u);
+ tt = r2 = 0;
+ if (c < 0) {
+ r2 = gv(rc);
+ tt = gjmp(0);
+ }
+ gsym(u);
+ nocode_wanted = ncw_prev;
- /* this is horrible, but we must also convert first
- operand */
- if (c != 0) {
- *vtop = sv;
- gen_cast(&type);
- if (islv) {
- mk_pointer(&vtop->type);
- gaddrof();
- } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
- gaddrof();
- }
+ /* this is horrible, but we must also convert first
+ operand */
+ if (c != 0) {
+ *vtop = sv;
+ gen_cast(&type);
+ if (islv) {
+ mk_pointer(&vtop->type);
+ gaddrof();
+ } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
+ gaddrof();
+ }
- if (c < 0) {
- r1 = gv(rc);
- move_reg(r2, r1, type.t);
- vtop->r = r2;
- gsym(tt);
- if (islv)
- indir();
- }
+ if (c < 0) {
+ r1 = gv(rc);
+ move_reg(r2, r1, islv ? VT_PTR : type.t);
+ vtop->r = r2;
+ gsym(tt);
}
+
+ if (islv)
+ indir();
}
}
@@ -5657,19 +6562,15 @@ static void expr_eq(void)
int t;
expr_cond();
- if (tok == '=' ||
- (tok >= TOK_A_MOD && tok <= TOK_A_DIV) ||
- tok == TOK_A_XOR || tok == TOK_A_OR ||
- tok == TOK_A_SHL || tok == TOK_A_SAR) {
+ if ((t = tok) == '=' || TOK_ASSIGN(t)) {
test_lvalue();
- t = tok;
next();
if (t == '=') {
expr_eq();
} else {
vdup();
expr_eq();
- gen_op(t & 0x7f);
+ gen_op(TOK_ASSIGN_OP(t));
}
vstore();
}
@@ -5690,9 +6591,9 @@ ST_FUNC void gexpr(void)
static void expr_const1(void)
{
const_wanted++;
- nocode_wanted++;
+ nocode_wanted += unevalmask + 1;
expr_cond();
- nocode_wanted--;
+ nocode_wanted -= unevalmask + 1;
const_wanted--;
}
@@ -5720,25 +6621,8 @@ ST_FUNC int expr_const(void)
return c;
}
-/* return the label token if current token is a label, otherwise
- return zero */
-static int is_label(void)
-{
- int last_tok;
-
- /* fast test first */
- if (tok < TOK_UIDENT)
- return 0;
- /* no need to save tokc because tok is an identifier */
- last_tok = tok;
- next();
- if (tok == ':') {
- return last_tok;
- } else {
- unget_tok(last_tok);
- return 0;
- }
-}
+/* ------------------------------------------------------------------------- */
+/* return from function */
#ifndef TCC_TARGET_ARM64
static void gfunc_return(CType *func_type)
@@ -5748,7 +6632,11 @@ static void gfunc_return(CType *func_type)
int ret_align, ret_nregs, regsize;
ret_nregs = gfunc_sret(func_type, func_var, &ret_type,
&ret_align, &regsize);
- if (0 == ret_nregs) {
+ if (ret_nregs < 0) {
+#ifdef TCC_TARGET_RISCV64
+ arch_transfer_ret_regs(0);
+#endif
+ } else if (0 == ret_nregs) {
/* if returning structure, must copy it to implicit
first pointer arg location */
type = *func_type;
@@ -5760,7 +6648,7 @@ static void gfunc_return(CType *func_type)
vstore();
} else {
/* returning structure packed into registers */
- int r, size, addr, align;
+ int size, addr, align, rc;
size = type_size(func_type,&align);
if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
(vtop->c.i & (ret_align-1)))
@@ -5775,37 +6663,49 @@ static void gfunc_return(CType *func_type)
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
}
vtop->type = ret_type;
- if (is_float(ret_type.t))
- r = rc_fret(ret_type.t);
- else
- r = RC_IRET;
-
+ rc = RC_RET(ret_type.t);
if (ret_nregs == 1)
- gv(r);
+ gv(rc);
else {
for (;;) {
vdup();
- gv(r);
+ gv(rc);
vpop();
if (--ret_nregs == 0)
break;
/* We assume that when a structure is returned in multiple
registers, their classes are consecutive values of the
suite s(n) = 2^n */
- r <<= 1;
+ rc <<= 1;
vtop->c.i += regsize;
}
}
}
- } else if (is_float(func_type->t)) {
- gv(rc_fret(func_type->t));
} else {
- gv(RC_IRET);
+ gv(RC_RET(func_type->t));
}
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
}
#endif
+static void check_func_return(void)
+{
+ if ((func_vt.t & VT_BTYPE) == VT_VOID)
+ return;
+ if (!strcmp (funcname, "main")
+ && (func_vt.t & VT_BTYPE) == VT_INT) {
+ /* main returns 0 by default */
+ vpushi(0);
+ gen_assign_cast(&func_vt);
+ gfunc_return(&func_vt);
+ } else {
+ tcc_warning("function might return no value: '%s'", funcname);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* switch/case */
+
static int case_cmp(const void *pa, const void *pb)
{
int64_t a = (*(struct case_t**) pa)->v1;
@@ -5813,13 +6713,17 @@ static int case_cmp(const void *pa, const void *pb)
return a < b ? -1 : a > b;
}
+static void gtst_addr(int t, int a)
+{
+ gsym_addr(gvtst(0, t), a);
+}
+
static void gcase(struct case_t **base, int len, int *bsym)
{
struct case_t *p;
int e;
int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
- gv(RC_INT);
- while (len > 4) {
+ while (len > 8) {
/* binary search */
p = base[len/2];
vdup();
@@ -5828,7 +6732,7 @@ static void gcase(struct case_t **base, int len, int *bsym)
else
vpushi(p->v2);
gen_op(TOK_LE);
- e = gtst(1, 0);
+ e = gvtst(1, 0);
vdup();
if (ll)
vpushll(p->v1);
@@ -5838,10 +6742,6 @@ static void gcase(struct case_t **base, int len, int *bsym)
gtst_addr(0, p->sym); /* v1 <= x <= v2 */
/* x < v1 */
gcase(base, len/2, bsym);
- if (cur_switch->def_sym)
- gjmp_addr(cur_switch->def_sym);
- else
- *bsym = gjmp(*bsym);
/* x > v2 */
gsym(e);
e = len/2 + 1;
@@ -5860,7 +6760,7 @@ static void gcase(struct case_t **base, int len, int *bsym)
gtst_addr(0, p->sym);
} else {
gen_op(TOK_LE);
- e = gtst(1, 0);
+ e = gvtst(1, 0);
vdup();
if (ll)
vpushll(p->v1);
@@ -5871,16 +6771,172 @@ static void gcase(struct case_t **base, int len, int *bsym)
gsym(e);
}
}
+ *bsym = gjmp(*bsym);
}
-static void block(int *bsym, int *csym, int is_expr)
+/* ------------------------------------------------------------------------- */
+/* __attribute__((cleanup(fn))) */
+
+static void try_call_scope_cleanup(Sym *stop)
{
- int a, b, c, d, cond;
- Sym *s;
+ Sym *cls = cur_scope->cl.s;
+
+ for (; cls != stop; cls = cls->ncl) {
+ Sym *fs = cls->next;
+ Sym *vs = cls->prev_tok;
+
+ vpushsym(&fs->type, fs);
+ vset(&vs->type, vs->r, vs->c);
+ vtop->sym = vs;
+ mk_pointer(&vtop->type);
+ gaddrof();
+ gfunc_call(1);
+ }
+}
+
+static void try_call_cleanup_goto(Sym *cleanupstate)
+{
+ Sym *oc, *cc;
+ int ocd, ccd;
+
+ if (!cur_scope->cl.s)
+ return;
+
+ /* search NCA of both cleanup chains given parents and initial depth */
+ ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
+ for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
+ ;
+ for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl)
+ ;
+ for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
+ ;
+
+ try_call_scope_cleanup(cc);
+}
+
+/* call 'func' for each __attribute__((cleanup(func))) */
+static void block_cleanup(struct scope *o)
+{
+ int jmp = 0;
+ Sym *g, **pg;
+ for (pg = &pending_gotos; (g = *pg) && g->c > o->cl.n;) {
+ if (g->prev_tok->r & LABEL_FORWARD) {
+ Sym *pcl = g->next;
+ if (!jmp)
+ jmp = gjmp(0);
+ gsym(pcl->jnext);
+ try_call_scope_cleanup(o->cl.s);
+ pcl->jnext = gjmp(0);
+ if (!o->cl.n)
+ goto remove_pending;
+ g->c = o->cl.n;
+ pg = &g->prev;
+ } else {
+ remove_pending:
+ *pg = g->prev;
+ sym_free(g);
+ }
+ }
+ gsym(jmp);
+ try_call_scope_cleanup(o->cl.s);
+}
+
+/* ------------------------------------------------------------------------- */
+/* VLA */
+
+static void vla_restore(int loc)
+{
+ if (loc)
+ gen_vla_sp_restore(loc);
+}
+
+static void vla_leave(struct scope *o)
+{
+ if (o->vla.num < cur_scope->vla.num)
+ vla_restore(o->vla.loc);
+}
+
+/* ------------------------------------------------------------------------- */
+/* local scopes */
+
+void new_scope(struct scope *o)
+{
+ /* copy and link previous scope */
+ *o = *cur_scope;
+ o->prev = cur_scope;
+ cur_scope = o;
+
+ /* record local declaration stack position */
+ o->lstk = local_stack;
+ o->llstk = local_label_stack;
+
+ ++local_scope;
- /* generate line number info */
if (tcc_state->do_debug)
- tcc_debug_line(tcc_state);
+ tcc_debug_stabn(N_LBRAC, ind - func_ind);
+}
+
+void prev_scope(struct scope *o, int is_expr)
+{
+ vla_leave(o->prev);
+
+ if (o->cl.s != o->prev->cl.s)
+ block_cleanup(o->prev);
+
+ /* pop locally defined labels */
+ label_pop(&local_label_stack, o->llstk, is_expr);
+
+ /* In the is_expr case (a statement expression is finished here),
+ vtop might refer to symbols on the local_stack. Either via the
+ type or via vtop->sym. We can't pop those nor any that in turn
+ might be referred to. To make it easier we don't roll back
+ any symbols in that case; some upper level call to block() will
+ do that. We do have to remove such symbols from the lookup
+ tables, though. sym_pop will do that. */
+
+ /* pop locally defined symbols */
+ pop_local_syms(&local_stack, o->lstk, is_expr, 0);
+ cur_scope = o->prev;
+ --local_scope;
+
+ if (tcc_state->do_debug)
+ tcc_debug_stabn(N_RBRAC, ind - func_ind);
+}
+
+/* leave a scope via break/continue(/goto) */
+void leave_scope(struct scope *o)
+{
+ if (!o)
+ return;
+ try_call_scope_cleanup(o->cl.s);
+ vla_leave(o);
+}
+
+/* ------------------------------------------------------------------------- */
+/* call block from 'for do while' loops */
+
+static void lblock(int *bsym, int *csym)
+{
+ struct scope *lo = loop_scope, *co = cur_scope;
+ int *b = co->bsym, *c = co->csym;
+ if (csym) {
+ co->csym = csym;
+ loop_scope = co;
+ }
+ co->bsym = bsym;
+ block(0);
+ co->bsym = b;
+ if (csym) {
+ co->csym = c;
+ loop_scope = lo;
+ }
+}
+
+static void block(int is_expr)
+{
+ int a, b, c, d, e, t;
+ struct scope o;
+ Sym *s;
if (is_expr) {
/* default return value is (void) */
@@ -5888,152 +6944,114 @@ static void block(int *bsym, int *csym, int is_expr)
vtop->type.t = VT_VOID;
}
- if (tok == TOK_IF) {
- /* if test */
- int saved_nocode_wanted = nocode_wanted;
- next();
+again:
+ t = tok, next();
+
+ if (t == TOK_IF) {
skip('(');
gexpr();
skip(')');
- cond = condition_3way();
- if (cond == 1)
- a = 0, vpop();
- else
- a = gvtst(1, 0);
- if (cond == 0)
- nocode_wanted |= 0x20000000;
- block(bsym, csym, 0);
- if (cond != 1)
- nocode_wanted = saved_nocode_wanted;
- c = tok;
- if (c == TOK_ELSE) {
- next();
+ a = gvtst(1, 0);
+ block(0);
+ if (tok == TOK_ELSE) {
d = gjmp(0);
gsym(a);
- if (cond == 1)
- nocode_wanted |= 0x20000000;
- block(bsym, csym, 0);
+ next();
+ block(0);
gsym(d); /* patch else jmp */
- if (cond != 0)
- nocode_wanted = saved_nocode_wanted;
- } else
+ } else {
gsym(a);
- } else if (tok == TOK_WHILE) {
- int saved_nocode_wanted;
- nocode_wanted &= ~0x20000000;
- next();
- d = ind;
- vla_sp_restore();
+ }
+
+ } else if (t == TOK_WHILE) {
+ d = gind();
skip('(');
gexpr();
skip(')');
a = gvtst(1, 0);
b = 0;
- ++local_scope;
- saved_nocode_wanted = nocode_wanted;
- block(&a, &b, 0);
- nocode_wanted = saved_nocode_wanted;
- --local_scope;
+ lblock(&a, &b);
gjmp_addr(d);
- gsym(a);
gsym_addr(b, d);
- } else if (tok == '{') {
- Sym *llabel;
- int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope;
+ gsym(a);
+
+ } else if (t == '{') {
+ new_scope(&o);
- next();
- /* record local declaration stack position */
- s = local_stack;
- llabel = local_label_stack;
- ++local_scope;
-
/* handle local labels declarations */
- if (tok == TOK_LABEL) {
- next();
- for(;;) {
+ while (tok == TOK_LABEL) {
+ do {
+ next();
if (tok < TOK_UIDENT)
expect("label identifier");
label_push(&local_label_stack, tok, LABEL_DECLARED);
next();
- if (tok == ',') {
- next();
- } else {
- skip(';');
- break;
- }
- }
+ } while (tok == ',');
+ skip(';');
}
+
while (tok != '}') {
- if ((a = is_label()))
- unget_tok(a);
- else
- decl(VT_LOCAL);
+ decl(VT_LOCAL);
if (tok != '}') {
if (is_expr)
vpop();
- block(bsym, csym, is_expr);
+ block(is_expr);
}
}
- /* pop locally defined labels */
- label_pop(&local_label_stack, llabel, is_expr);
- /* pop locally defined symbols */
- --local_scope;
- /* In the is_expr case (a statement expression is finished here),
- vtop might refer to symbols on the local_stack. Either via the
- type or via vtop->sym. We can't pop those nor any that in turn
- might be referred to. To make it easier we don't roll back
- any symbols in that case; some upper level call to block() will
- do that. We do have to remove such symbols from the lookup
- tables, though. sym_pop will do that. */
- sym_pop(&local_stack, s, is_expr);
-
- /* Pop VLA frames and restore stack pointer if required */
- if (vlas_in_scope > saved_vlas_in_scope) {
- vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc;
- vla_sp_restore();
- }
- vlas_in_scope = saved_vlas_in_scope;
-
- next();
- } else if (tok == TOK_RETURN) {
- next();
+
+ prev_scope(&o, is_expr);
+ if (local_scope)
+ next();
+ else if (!nocode_wanted)
+ check_func_return();
+
+ } else if (t == TOK_RETURN) {
+ b = (func_vt.t & VT_BTYPE) != VT_VOID;
if (tok != ';') {
gexpr();
- gen_assign_cast(&func_vt);
- if ((func_vt.t & VT_BTYPE) == VT_VOID)
+ if (b) {
+ gen_assign_cast(&func_vt);
+ } else {
+ if (vtop->type.t != VT_VOID)
+ tcc_warning("void function returns a value");
vtop--;
- else
- gfunc_return(&func_vt);
+ }
+ } else if (b) {
+ tcc_warning("'return' with no value");
+ b = 0;
}
+ leave_scope(root_scope);
+ if (b)
+ gfunc_return(&func_vt);
skip(';');
/* jump unless last stmt in top-level block */
if (tok != '}' || local_scope != 1)
rsym = gjmp(rsym);
- nocode_wanted |= 0x20000000;
- } else if (tok == TOK_BREAK) {
+ CODE_OFF();
+
+ } else if (t == TOK_BREAK) {
/* compute jump */
- if (!bsym)
+ if (!cur_scope->bsym)
tcc_error("cannot break");
- *bsym = gjmp(*bsym);
- next();
+ if (cur_switch && cur_scope->bsym == cur_switch->bsym)
+ leave_scope(cur_switch->scope);
+ else
+ leave_scope(loop_scope);
+ *cur_scope->bsym = gjmp(*cur_scope->bsym);
skip(';');
- nocode_wanted |= 0x20000000;
- } else if (tok == TOK_CONTINUE) {
+
+ } else if (t == TOK_CONTINUE) {
/* compute jump */
- if (!csym)
+ if (!cur_scope->csym)
tcc_error("cannot continue");
- vla_sp_restore_root();
- *csym = gjmp(*csym);
- next();
+ leave_scope(loop_scope);
+ *cur_scope->csym = gjmp(*cur_scope->csym);
skip(';');
- } else if (tok == TOK_FOR) {
- int e;
- int saved_nocode_wanted;
- nocode_wanted &= ~0x20000000;
- next();
+
+ } else if (t == TOK_FOR) {
+ new_scope(&o);
+
skip('(');
- s = local_stack;
- ++local_scope;
if (tok != ';') {
/* c99 for-loop init decl? */
if (!decl0(VT_LOCAL, 1, NULL)) {
@@ -6043,11 +7061,8 @@ static void block(int *bsym, int *csym, int is_expr)
}
}
skip(';');
- d = ind;
- c = ind;
- vla_sp_restore();
- a = 0;
- b = 0;
+ a = b = 0;
+ c = d = gind();
if (tok != ';') {
gexpr();
a = gvtst(1, 0);
@@ -6055,88 +7070,82 @@ static void block(int *bsym, int *csym, int is_expr)
skip(';');
if (tok != ')') {
e = gjmp(0);
- c = ind;
- vla_sp_restore();
+ d = gind();
gexpr();
vpop();
- gjmp_addr(d);
+ gjmp_addr(c);
gsym(e);
}
skip(')');
- saved_nocode_wanted = nocode_wanted;
- block(&a, &b, 0);
- nocode_wanted = saved_nocode_wanted;
- gjmp_addr(c);
+ lblock(&a, &b);
+ gjmp_addr(d);
+ gsym_addr(b, d);
gsym(a);
- gsym_addr(b, c);
- --local_scope;
- sym_pop(&local_stack, s, 0);
-
- } else
- if (tok == TOK_DO) {
- int saved_nocode_wanted;
- nocode_wanted &= ~0x20000000;
- next();
- a = 0;
- b = 0;
- d = ind;
- vla_sp_restore();
- saved_nocode_wanted = nocode_wanted;
- block(&a, &b, 0);
+ prev_scope(&o, 0);
+
+ } else if (t == TOK_DO) {
+ a = b = 0;
+ d = gind();
+ lblock(&a, &b);
+ gsym(b);
skip(TOK_WHILE);
skip('(');
- gsym(b);
gexpr();
+ skip(')');
+ skip(';');
c = gvtst(0, 0);
gsym_addr(c, d);
- nocode_wanted = saved_nocode_wanted;
- skip(')');
gsym(a);
- skip(';');
- } else
- if (tok == TOK_SWITCH) {
- struct switch_t *saved, sw;
- int saved_nocode_wanted = nocode_wanted;
- SValue switchval;
- next();
+
+ } else if (t == TOK_SWITCH) {
+ struct switch_t *sw;
+
+ sw = tcc_mallocz(sizeof *sw);
+ sw->bsym = &a;
+ sw->scope = cur_scope;
+ sw->prev = cur_switch;
+ cur_switch = sw;
+
skip('(');
gexpr();
skip(')');
- switchval = *vtop--;
+ sw->sv = *vtop--; /* save switch value */
+
a = 0;
b = gjmp(0); /* jump to first case */
- sw.p = NULL; sw.n = 0; sw.def_sym = 0;
- saved = cur_switch;
- cur_switch = &sw;
- block(&a, csym, 0);
- nocode_wanted = saved_nocode_wanted;
+ lblock(&a, NULL);
a = gjmp(a); /* add implicit break */
/* case lookup */
gsym(b);
- qsort(sw.p, sw.n, sizeof(void*), case_cmp);
- for (b = 1; b < sw.n; b++)
- if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
+
+ qsort(sw->p, sw->n, sizeof(void*), case_cmp);
+ for (b = 1; b < sw->n; b++)
+ if (sw->p[b - 1]->v2 >= sw->p[b]->v1)
tcc_error("duplicate case value");
+
/* Our switch table sorting is signed, so the compared
value needs to be as well when it's 64bit. */
- if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
- switchval.type.t &= ~VT_UNSIGNED;
- vpushv(&switchval);
- gcase(sw.p, sw.n, &a);
+ vpushv(&sw->sv);
+ if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
+ vtop->type.t &= ~VT_UNSIGNED;
+ gv(RC_INT);
+ d = 0, gcase(sw->p, sw->n, &d);
vpop();
- if (sw.def_sym)
- gjmp_addr(sw.def_sym);
- dynarray_reset(&sw.p, &sw.n);
- cur_switch = saved;
+ if (sw->def_sym)
+ gsym_addr(d, sw->def_sym);
+ else
+ gsym(d);
/* break label */
gsym(a);
- } else
- if (tok == TOK_CASE) {
+
+ dynarray_reset(&sw->p, &sw->n);
+ cur_switch = sw->prev;
+ tcc_free(sw);
+
+ } else if (t == TOK_CASE) {
struct case_t *cr = tcc_malloc(sizeof(struct case_t));
if (!cur_switch)
expect("switch");
- nocode_wanted &= ~0x20000000;
- next();
cr->v1 = cr->v2 = expr_const64();
if (gnu_ext && tok == TOK_DOTS) {
next();
@@ -6144,25 +7153,24 @@ static void block(int *bsym, int *csym, int is_expr)
if (cr->v2 < cr->v1)
tcc_warning("empty case range");
}
- cr->sym = ind;
+ cr->sym = gind();
dynarray_add(&cur_switch->p, &cur_switch->n, cr);
skip(':');
is_expr = 0;
goto block_after_label;
- } else
- if (tok == TOK_DEFAULT) {
- next();
- skip(':');
+
+ } else if (t == TOK_DEFAULT) {
if (!cur_switch)
expect("switch");
if (cur_switch->def_sym)
tcc_error("too many 'default'");
- cur_switch->def_sym = ind;
+ cur_switch->def_sym = gind();
+ skip(':');
is_expr = 0;
goto block_after_label;
- } else
- if (tok == TOK_GOTO) {
- next();
+
+ } else if (t == TOK_GOTO) {
+ vla_restore(root_scope->vla.loc);
if (tok == '*' && gnu_ext) {
/* computed goto */
next();
@@ -6170,56 +7178,73 @@ static void block(int *bsym, int *csym, int is_expr)
if ((vtop->type.t & VT_BTYPE) != VT_PTR)
expect("pointer");
ggoto();
+
} else if (tok >= TOK_UIDENT) {
- s = label_find(tok);
- /* put forward definition if needed */
- if (!s) {
- s = label_push(&global_label_stack, tok, LABEL_FORWARD);
- } else {
- if (s->r == LABEL_DECLARED)
- s->r = LABEL_FORWARD;
- }
- vla_sp_restore_root();
- if (s->r & LABEL_FORWARD)
- s->jnext = gjmp(s->jnext);
- else
- gjmp_addr(s->jnext);
- next();
+ s = label_find(tok);
+ /* put forward definition if needed */
+ if (!s)
+ s = label_push(&global_label_stack, tok, LABEL_FORWARD);
+ else if (s->r == LABEL_DECLARED)
+ s->r = LABEL_FORWARD;
+
+ if (s->r & LABEL_FORWARD) {
+ /* start new goto chain for cleanups, linked via label->next */
+ if (cur_scope->cl.s && !nocode_wanted) {
+ sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n);
+ pending_gotos->prev_tok = s;
+ s = sym_push2(&s->next, SYM_FIELD, 0, 0);
+ pending_gotos->next = s;
+ }
+ s->jnext = gjmp(s->jnext);
+ } else {
+ try_call_cleanup_goto(s->cleanupstate);
+ gjmp_addr(s->jnext);
+ }
+ next();
+
} else {
expect("label identifier");
}
skip(';');
- } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) {
+
+ } else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) {
asm_instr();
+
} else {
- b = is_label();
- if (b) {
+ if (tok == ':' && t >= TOK_UIDENT) {
/* label case */
next();
- s = label_find(b);
+ s = label_find(t);
if (s) {
if (s->r == LABEL_DEFINED)
tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL));
- gsym(s->jnext);
s->r = LABEL_DEFINED;
+ if (s->next) {
+ Sym *pcl; /* pending cleanup goto */
+ for (pcl = s->next; pcl; pcl = pcl->prev)
+ gsym(pcl->jnext);
+ sym_pop(&s->next, NULL, 0);
+ } else
+ gsym(s->jnext);
} else {
- s = label_push(&global_label_stack, b, LABEL_DEFINED);
+ s = label_push(&global_label_stack, t, LABEL_DEFINED);
}
- s->jnext = ind;
- vla_sp_restore();
+ s->jnext = gind();
+ s->cleanupstate = cur_scope->cl.s;
+
+ block_after_label:
+ vla_restore(cur_scope->vla.loc);
/* we accept this, but it is a mistake */
- block_after_label:
- nocode_wanted &= ~0x20000000;
if (tok == '}') {
tcc_warning("deprecated use of label at end of compound statement");
} else {
- if (is_expr)
- vpop();
- block(bsym, csym, is_expr);
+ goto again;
}
+
} else {
/* expression case */
- if (tok != ';') {
+ if (t != ';') {
+ unget_tok(t);
if (is_expr) {
vpop();
gexpr();
@@ -6227,8 +7252,8 @@ static void block(int *bsym, int *csym, int is_expr)
gexpr();
vpop();
}
+ skip(';');
}
- skip(';');
}
}
}
@@ -6287,12 +7312,12 @@ static void parse_init_elem(int expr_type)
/* NOTE: symbols are accepted, as well as lvalue for anon symbols
(compound literals). */
if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST
- && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL)
- || vtop->sym->v < SYM_FIRST_ANOM))
+ && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL)
+ || vtop->sym->v < SYM_FIRST_ANOM))
#ifdef TCC_TARGET_PE
|| ((vtop->r & VT_SYM) && vtop->sym->a.dllimport)
#endif
- )
+ )
tcc_error("initializer element is not constant");
break;
case EXPR_ANY:
@@ -6320,14 +7345,18 @@ static void init_putz(Section *sec, unsigned long c, int size)
}
}
+#define DIF_FIRST 1
+#define DIF_SIZE_ONLY 2
+#define DIF_HAVE_ELEM 4
+
/* t is the array or struct type. c is the array or struct
address. cur_field is the pointer to the current
field, for arrays the 'c' member contains the current start
- index. 'size_only' is true if only size info is needed (only used
- in arrays). al contains the already initialized length of the
+ index. 'flags' is as in decl_initializer.
+ 'al' contains the already initialized length of the
current container (starting at c). This returns the new length of that. */
static int decl_designator(CType *type, Section *sec, unsigned long c,
- Sym **cur_field, int size_only, int al)
+ Sym **cur_field, int flags, int al)
{
Sym *s, *f;
int index, index_last, align, l, nb_elems, elem_size;
@@ -6335,8 +7364,17 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
elem_size = 0;
nb_elems = 1;
- if (gnu_ext && (l = is_label()) != 0)
- goto struct_field;
+
+ if (flags & DIF_HAVE_ELEM)
+ goto no_designator;
+
+ if (gnu_ext && tok >= TOK_UIDENT) {
+ l = tok, next();
+ if (tok == ':')
+ goto struct_field;
+ unget_tok(l);
+ }
+
/* NOTE: we only support ranges for last designator */
while (nb_elems == 1 && (tok == '[' || tok == '.')) {
if (tok == '[') {
@@ -6360,19 +7398,21 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
c += index * elem_size;
nb_elems = index_last - index + 1;
} else {
+ int cumofs;
next();
l = tok;
struct_field:
next();
if ((type->t & VT_BTYPE) != VT_STRUCT)
expect("struct/union type");
- f = find_field(type, l);
+ cumofs = 0;
+ f = find_field(type, l, &cumofs);
if (!f)
expect("field");
if (cur_field)
*cur_field = f;
type = &f->type;
- c += f->c;
+ c += cumofs + f->c;
}
cur_field = NULL;
}
@@ -6383,6 +7423,7 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
expect("=");
}
} else {
+ no_designator:
if (type->t & VT_ARRAY) {
index = (*cur_field)->c;
if (type->ref->c >= 0 && index >= type->ref->c)
@@ -6401,12 +7442,12 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
}
/* must put zero in holes (note that doing it that way
ensures that it even works with designators) */
- if (!size_only && c - corig > al)
+ if (!(flags & DIF_SIZE_ONLY) && c - corig > al)
init_putz(sec, corig + al, c - corig - al);
- decl_initializer(type, sec, c, 0, size_only);
+ decl_initializer(type, sec, c, flags & ~DIF_FIRST);
/* XXX: make it more general */
- if (!size_only && nb_elems > 1) {
+ if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) {
unsigned long c_end;
uint8_t *src, *dst;
int i;
@@ -6484,7 +7525,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
anonymous one. That is, there's no difference in vtop
between '(void *){x}' and '&(void *){x}'. Ignore
pointer typed entities here. Hopefully no real code
- will every use compound literals with scalar type. */
+ will ever use compound literals with scalar type. */
(vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */
Section *ssec;
@@ -6492,7 +7533,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
ElfW_Rel *rel;
esym = elfsym(vtop->sym);
ssec = tcc_state->sections[esym->st_shndx];
- memmove (ptr, ssec->data + esym->st_value, size);
+ memmove (ptr, ssec->data + esym->st_value + (int)vtop->c.i, size);
if (ssec->reloc) {
/* We need to copy over all memory contents, and that
includes relocations. Use the fact that relocs are
@@ -6629,33 +7670,29 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
/* 't' contains the type and storage info. 'c' is the offset of the
object in section 'sec'. If 'sec' is NULL, it means stack based
- allocation. 'first' is true if array '{' must be read (multi
- dimension implicit array init handling). 'size_only' is true if
+ allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi
+ dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if
size only evaluation is wanted (only for arrays). */
static void decl_initializer(CType *type, Section *sec, unsigned long c,
- int first, int size_only)
+ int flags)
{
- int len, n, no_oblock, nb, i;
+ int len, n, no_oblock, i;
int size1, align1;
- int have_elem;
Sym *s, *f;
Sym indexsym;
CType *t1;
- /* If we currently are at an '}' or ',' we have read an initializer
- element in one of our callers, and not yet consumed it. */
- have_elem = tok == '}' || tok == ',';
- if (!have_elem && tok != '{' &&
+ if (!(flags & DIF_HAVE_ELEM) && tok != '{' &&
/* In case of strings we have special handling for arrays, so
don't consume them as initializer value (which would commit them
to some anonymous symbol). */
tok != TOK_LSTR && tok != TOK_STR &&
- !size_only) {
+ !(flags & DIF_SIZE_ONLY)) {
parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
- have_elem = 1;
+ flags |= DIF_HAVE_ELEM;
}
- if (have_elem &&
+ if ((flags & DIF_HAVE_ELEM) &&
!(type->t & VT_ARRAY) &&
/* Use i_c_parameter_t, to strip toplevel qualifiers.
The source type might have VT_CONSTANT set, which is
@@ -6669,7 +7706,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
size1 = type_size(t1, &align1);
no_oblock = 1;
- if ((first && tok != TOK_LSTR && tok != TOK_STR) ||
+ if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) ||
tok == '{') {
if (tok != '{')
tcc_error("character array initializer must be a literal,"
@@ -6687,46 +7724,62 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
(t1->t & VT_BTYPE) == VT_INT
#endif
) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
+ int nb;
len = 0;
+ cstr_reset(&initstr);
+ if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t)))
+ tcc_error("unhandled string literal merging");
while (tok == TOK_STR || tok == TOK_LSTR) {
- int cstr_len, ch;
-
- /* compute maximum number of chars wanted */
+ if (initstr.size)
+ initstr.size -= size1;
if (tok == TOK_STR)
- cstr_len = tokc.str.size;
+ len += tokc.str.size;
else
- cstr_len = tokc.str.size / sizeof(nwchar_t);
- cstr_len--;
- nb = cstr_len;
- if (n >= 0 && nb > (n - len))
- nb = n - len;
- if (!size_only) {
- if (cstr_len > nb)
- tcc_warning("initializer-string for array is too long");
- /* in order to go faster for common case (char
- string in global variable, we handle it
- specifically */
- if (sec && tok == TOK_STR && size1 == 1) {
- if (!NODATA_WANTED)
- memcpy(sec->data + c + len, tokc.str.data, nb);
- } else {
- for(i=0;i<nb;i++) {
- if (tok == TOK_STR)
- ch = ((unsigned char *)tokc.str.data)[i];
- else
- ch = ((nwchar_t *)tokc.str.data)[i];
- vpushi(ch);
- init_putv(t1, sec, c + (len + i) * size1);
- }
+ len += tokc.str.size / sizeof(nwchar_t);
+ len--;
+ cstr_cat(&initstr, tokc.str.data, tokc.str.size);
+ next();
+ }
+ if (tok != ')' && tok != '}' && tok != ',' && tok != ';'
+ && tok != TOK_EOF) {
+ /* Not a lone literal but part of a bigger expression. */
+ unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR);
+ tokc.str.size = initstr.size;
+ tokc.str.data = initstr.data;
+ indexsym.c = 0;
+ f = &indexsym;
+ goto do_init_list;
+ }
+ nb = len;
+ if (n >= 0 && len > n)
+ nb = n;
+ if (!(flags & DIF_SIZE_ONLY)) {
+ if (sec && !NODATA_WANTED &&
+ (c + nb > sec->data_allocated))
+ nb = sec->data_allocated - c;
+ if (len > nb)
+ tcc_warning("initializer-string for array is too long");
+ /* in order to go faster for common case (char
+ string in global variable, we handle it
+ specifically */
+ if (sec && size1 == 1) {
+ if (!NODATA_WANTED)
+ memcpy(sec->data + c, initstr.data, nb);
+ } else {
+ for(i=0;i<nb;i++) {
+ if (size1 == 1)
+ ch = ((unsigned char *)initstr.data)[i];
+ else
+ ch = ((nwchar_t *)initstr.data)[i];
+ vpushi(ch);
+ init_putv(t1, sec, c + i * size1);
}
}
- len += nb;
- next();
}
/* only add trailing zero if enough storage (no
warning in this case since it is standard) */
if (n < 0 || len < n) {
- if (!size_only) {
+ if (!(flags & DIF_SIZE_ONLY)) {
vpushi(0);
init_putv(t1, sec, c + (len * size1));
}
@@ -6739,9 +7792,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
do_init_list:
len = 0;
- while (tok != '}' || have_elem) {
- len = decl_designator(type, sec, c, &f, size_only, len);
- have_elem = 0;
+ while (tok != '}' || (flags & DIF_HAVE_ELEM)) {
+ len = decl_designator(type, sec, c, &f, flags, len);
+ flags &= ~DIF_HAVE_ELEM;
if (type->t & VT_ARRAY) {
++indexsym.c;
/* special test for multi dimensional arrays (may not
@@ -6764,7 +7817,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
}
}
/* put zeros at the end */
- if (!size_only && len < n*size1)
+ if (!(flags & DIF_SIZE_ONLY) && len < n*size1)
init_putz(sec, c + len, n*size1 - len);
if (!no_oblock)
skip('}');
@@ -6774,7 +7827,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
} else if ((type->t & VT_BTYPE) == VT_STRUCT) {
size1 = 1;
no_oblock = 1;
- if (first || tok == '{') {
+ if ((flags & DIF_FIRST) || tok == '{') {
skip('{');
no_oblock = 0;
}
@@ -6783,20 +7836,22 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
n = s->c;
goto do_init_list;
} else if (tok == '{') {
+ if (flags & DIF_HAVE_ELEM)
+ skip(';');
next();
- decl_initializer(type, sec, c, first, size_only);
+ decl_initializer(type, sec, c, flags & ~DIF_HAVE_ELEM);
skip('}');
- } else if (size_only) {
+ } else if ((flags & DIF_SIZE_ONLY)) {
/* If we supported only ISO C we wouldn't have to accept calling
- this on anything than an array size_only==1 (and even then
+ this on anything than an array if DIF_SIZE_ONLY (and even then
only on the outermost level, so no recursion would be needed),
because initializing a flex array member isn't supported.
But GNU C supports it, so we need to recurse even into
- subfields of structs and arrays when size_only is set. */
+ subfields of structs and arrays when DIF_SIZE_ONLY is set. */
/* just skip expression */
skip_or_save_block(NULL);
} else {
- if (!have_elem) {
+ if (!(flags & DIF_HAVE_ELEM)) {
/* This should happen only when we haven't parsed
the init element above for fear of committing a
string constant to memory too early. */
@@ -6829,8 +7884,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
#endif
- if (type->t & VT_STATIC)
- nocode_wanted |= NODATA_WANTED ? 0x40000000 : 0x80000000;
+ /* Always allocate static or global variables */
+ if (v && (r & VT_VALMASK) == VT_CONST)
+ nocode_wanted |= 0x80000000;
flexible_array = NULL;
if ((type->t & VT_BTYPE) == VT_STRUCT) {
@@ -6871,7 +7927,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* compute size */
begin_macro(init_str, 1);
next();
- decl_initializer(type, NULL, 0, 1, 1);
+ decl_initializer(type, NULL, 0, DIF_FIRST | DIF_SIZE_ONLY);
/* prepare second initializer parsing */
macro_ptr = init_str->str;
next();
@@ -6896,30 +7952,23 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
align = 1;
}
- if (NODATA_WANTED)
+ if (!v && NODATA_WANTED)
size = 0, align = 1;
if ((r & VT_VALMASK) == VT_LOCAL) {
sec = NULL;
#ifdef CONFIG_TCC_BCHECK
- if (bcheck && (type->t & VT_ARRAY)) {
+ if (bcheck && v) {
+ /* add padding between stack variables for bound checking */
loc--;
}
#endif
loc = (loc - size) & -align;
addr = loc;
#ifdef CONFIG_TCC_BCHECK
- /* handles bounds */
- /* XXX: currently, since we do only one pass, we cannot track
- '&' operators, so we add only arrays */
- if (bcheck && (type->t & VT_ARRAY)) {
- addr_t *bounds_ptr;
- /* add padding between regions */
+ if (bcheck && v) {
+ /* add padding between stack variables for bound checking */
loc--;
- /* then add local bound info */
- bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
- bounds_ptr[0] = addr;
- bounds_ptr[1] = size;
}
#endif
if (v) {
@@ -6932,6 +7981,15 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
}
#endif
sym = sym_push(v, type, r, addr);
+ if (ad->cleanup_func) {
+ Sym *cls = sym_push2(&all_cleanups,
+ SYM_FIELD | ++cur_scope->cl.n, 0, 0);
+ cls->prev_tok = sym;
+ cls->next = ad->cleanup_func;
+ cls->ncl = cur_scope->cl.s;
+ cur_scope->cl.s = cls;
+ }
+
sym->a = ad->a;
} else {
/* push local reference */
@@ -6975,15 +8033,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
sym = sym_push(v, type, r | VT_SYM, 0);
patch_storage(sym, ad, NULL);
}
- /* Local statics have a scope until now (for
- warnings), remove it here. */
- sym->sym_scope = 0;
/* update symbol definition */
put_extern_sym(sym, sec, addr, size);
} else {
/* push global reference */
- sym = get_sym_ref(type, sec, addr, size);
- vpushsym(type, sym);
+ vpush_ref(type, sec, addr, size);
+ sym = vtop->sym;
vtop->r |= r;
}
@@ -7009,10 +8064,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
goto no_alloc;
/* save current stack pointer */
- if (vlas_in_scope == 0) {
- if (vla_sp_root_loc == -1)
- vla_sp_root_loc = (loc -= PTR_SIZE);
- gen_vla_sp_save(vla_sp_root_loc);
+ if (root_scope->vla.loc == 0) {
+ struct scope *v = cur_scope;
+ gen_vla_sp_save(loc -= PTR_SIZE);
+ do v->vla.loc = loc; while ((v = v->prev));
}
vla_runtime_type_size(type, &a);
@@ -7023,14 +8078,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
gen_vla_result(addr), addr = (loc -= PTR_SIZE);
#endif
gen_vla_sp_save(addr);
- vla_sp_loc = addr;
- vlas_in_scope++;
-
+ cur_scope->vla.loc = addr;
+ cur_scope->vla.num++;
} else if (has_init) {
size_t oldreloc_offset = 0;
if (sec && sec->reloc)
oldreloc_offset = sec->reloc->data_offset;
- decl_initializer(type, sec, addr, 1, 0);
+ decl_initializer(type, sec, addr, DIF_FIRST);
if (sec && sec->reloc)
squeeze_multi_relocs(sec, oldreloc_offset);
/* patch flexible array member size back to -1, */
@@ -7053,35 +8107,56 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
'cur_text_section' */
static void gen_function(Sym *sym)
{
+ /* Initialize VLA state */
+ struct scope f = { 0 };
+#ifdef CONFIG_TCC_BCHECK
+ unsigned char save_bcheck = tcc_state->do_bounds_check;
+
+ if (sym->type.ref->f.no_bcheck)
+ tcc_state->do_bounds_check = 0;
+#endif
+ cur_scope = root_scope = &f;
nocode_wanted = 0;
ind = cur_text_section->data_offset;
+ if (sym->a.aligned) {
+ size_t newoff = section_add(cur_text_section, 0,
+ 1 << (sym->a.aligned - 1));
+ gen_fill_nops(newoff - ind);
+ }
/* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0);
+ if (sym->type.ref->f.func_ctor)
+ add_array (tcc_state, ".init_array", sym->c);
+ if (sym->type.ref->f.func_dtor)
+ add_array (tcc_state, ".fini_array", sym->c);
+
funcname = get_tok_str(sym->v, NULL);
func_ind = ind;
- /* Initialize VLA state */
- vla_sp_loc = -1;
- vla_sp_root_loc = -1;
+ func_vt = sym->type.ref->type;
+ func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
+
/* put debug symbol */
tcc_debug_funcstart(tcc_state, sym);
/* push a dummy symbol to enable local sym storage */
sym_push2(&local_stack, SYM_FIELD, 0, 0);
local_scope = 1; /* for function parameters */
- gfunc_prolog(&sym->type);
+ gfunc_prolog(sym);
local_scope = 0;
rsym = 0;
- block(NULL, NULL, 0);
- nocode_wanted = 0;
+ clear_temp_local_var_list();
+ block(0);
gsym(rsym);
+ nocode_wanted = 0;
+ /* reset local stack */
+ pop_local_syms(&local_stack, NULL, 0, func_var);
gfunc_epilog();
cur_text_section->data_offset = ind;
- label_pop(&global_label_stack, NULL, 0);
- /* reset local stack */
local_scope = 0;
- sym_pop(&local_stack, NULL, 0);
- /* end of function */
+ label_pop(&global_label_stack, NULL, 0);
+ sym_pop(&all_cleanups, NULL, 0);
/* patch symbol size */
elfsym(sym)->st_size = ind - func_ind;
+ /* end of function */
tcc_debug_funcend(tcc_state, ind - func_ind);
/* It's better to crash than to generate wrong code */
cur_text_section = NULL;
@@ -7091,29 +8166,31 @@ static void gen_function(Sym *sym)
ind = 0; /* for safety */
nocode_wanted = 0x80000000;
check_vstack();
+ /* do this after funcend debug info */
+ next();
+#ifdef CONFIG_TCC_BCHECK
+ tcc_state->do_bounds_check = save_bcheck;
+#endif
}
static void gen_inline_functions(TCCState *s)
{
Sym *sym;
- int inline_generated, i, ln;
+ int inline_generated, i;
struct InlineFunc *fn;
- ln = file->line_num;
+ tcc_open_bf(s, ":inline:", 0);
/* iterate while inline function are referenced */
do {
inline_generated = 0;
for (i = 0; i < s->nb_inline_fns; ++i) {
fn = s->inline_fns[i];
sym = fn->sym;
- if (sym && sym->c) {
- /* the function was used: generate its code and
- convert it to a normal function */
+ if (sym && (sym->c || !(sym->type.t & VT_INLINE))) {
+ /* the function was used or forced (and then not internal):
+ generate its code and convert it to a normal function */
fn->sym = NULL;
- if (file)
- pstrcpy(file->filename, sizeof file->filename, fn->filename);
- sym->type.t &= ~VT_INLINE;
-
+ tcc_debug_putfile(s, fn->filename);
begin_macro(fn->func_str, 1);
next();
cur_text_section = text_section;
@@ -7124,10 +8201,10 @@ static void gen_inline_functions(TCCState *s)
}
}
} while (inline_generated);
- file->line_num = ln;
+ tcc_close();
}
-ST_FUNC void free_inline_functions(TCCState *s)
+static void free_inline_functions(TCCState *s)
{
int i;
/* free tokens of unused inline functions */
@@ -7146,10 +8223,35 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
int v, has_init, r;
CType type, btype;
Sym *sym;
- AttributeDef ad;
+ AttributeDef ad, adbase;
while (1) {
- if (!parse_btype(&btype, &ad)) {
+ if (tok == TOK_STATIC_ASSERT) {
+ CString error_str;
+ int c;
+
+ next();
+ skip('(');
+ c = expr_const();
+
+ if (tok == ')') {
+ if (!c)
+ tcc_error("_Static_assert fail");
+ next();
+ goto static_assert_out;
+ }
+
+ skip(',');
+ parse_mult_str(&error_str, "string constant");
+ if (c == 0)
+ tcc_error("%s", (char *)error_str.data);
+ cstr_free(&error_str);
+ skip(')');
+ static_assert_out:
+ skip(';');
+ continue;
+ }
+ if (!parse_btype(&btype, &adbase)) {
if (is_for_loop_init)
return 0;
/* skip redundant ';' if not in old parameter decl scope */
@@ -7197,6 +8299,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
if ((type.t & VT_ARRAY) && type.ref->c < 0) {
type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c);
}
+ ad = adbase;
type_decl(&type, &ad, &v, TYPE_DIRECT);
#if 0
{
@@ -7206,29 +8309,51 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
}
#endif
if ((type.t & VT_BTYPE) == VT_FUNC) {
- if ((type.t & VT_STATIC) && (l == VT_LOCAL)) {
+ if ((type.t & VT_STATIC) && (l == VT_LOCAL))
tcc_error("function without file scope cannot be static");
- }
/* if old style function prototype, we accept a
declaration list */
sym = type.ref;
if (sym->f.func_type == FUNC_OLD && l == VT_CONST)
decl0(VT_CMP, 0, sym);
+#ifdef TCC_TARGET_MACHO
+ if (sym->f.func_alwinl
+ && ((type.t & (VT_EXTERN | VT_INLINE))
+ == (VT_EXTERN | VT_INLINE))) {
+ /* always_inline functions must be handled as if they
+ don't generate multiple global defs, even if extern
+ inline, i.e. GNU inline semantics for those. Rewrite
+ them into static inline. */
+ type.t &= ~VT_EXTERN;
+ type.t |= VT_STATIC;
+ }
+#endif
+ /* always compile 'extern inline' */
+ if (type.t & VT_EXTERN)
+ type.t &= ~VT_INLINE;
}
if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
ad.asm_label = asm_label_instr();
/* parse one last attribute list, after asm label */
parse_attribute(&ad);
+ #if 0
+ /* gcc does not allow __asm__("label") with function definition,
+ but why not ... */
if (tok == '{')
expect(";");
+ #endif
}
#ifdef TCC_TARGET_PE
if (ad.a.dllimport || ad.a.dllexport) {
- if (type.t & (VT_STATIC|VT_TYPEDEF))
- tcc_error("cannot have dll linkage with static or typedef");
- if (ad.a.dllimport) {
+ if (type.t & VT_STATIC)
+ tcc_error("cannot have dll linkage with static");
+ if (type.t & VT_TYPEDEF) {
+ tcc_warning("'%s' attribute ignored for typedef",
+ ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport") :
+ (ad.a.dllexport = 0, "dllexport"));
+ } else if (ad.a.dllimport) {
if ((type.t & VT_BTYPE) == VT_FUNC)
ad.a.dllimport = 0;
else
@@ -7243,35 +8368,29 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
expect("function definition");
/* reject abstract declarators in function definition
- make old style params without decl have int type */
+ make old style params without decl have int type */
sym = type.ref;
while ((sym = sym->next) != NULL) {
if (!(sym->v & ~SYM_FIELD))
expect("identifier");
- if (sym->type.t == VT_VOID)
- sym->type = int_type;
- }
-
- /* XXX: cannot do better now: convert extern line to static inline */
- if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE))
- type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
+ if (sym->type.t == VT_VOID)
+ sym->type = int_type;
+ }
+
+ /* apply post-declaraton attributes */
+ merge_funcattr(&type.ref->f, &ad.f);
/* put function symbol */
- sym = external_global_sym(v, &type, 0);
type.t &= ~VT_EXTERN;
- patch_storage(sym, &ad, &type);
+ sym = external_sym(v, &type, 0, &ad);
/* static inline functions are just recorded as a kind
of macro. Their code will be emitted at the end of
the compilation unit only if they are used */
- if ((type.t & (VT_INLINE | VT_STATIC)) ==
- (VT_INLINE | VT_STATIC)) {
+ if (sym->type.t & VT_INLINE) {
struct InlineFunc *fn;
- const char *filename;
-
- filename = file ? file->filename : "";
- fn = tcc_malloc(sizeof *fn + strlen(filename));
- strcpy(fn->filename, filename);
+ fn = tcc_malloc(sizeof *fn + strlen(file->filename));
+ strcpy(fn->filename, file->filename);
fn->sym = sym;
skip_or_save_block(&fn->func_str);
dynarray_add(&tcc_state->inline_fns,
@@ -7316,6 +8435,9 @@ found:
}
sym->a = ad.a;
sym->f = ad.f;
+ } else if ((type.t & VT_BTYPE) == VT_VOID
+ && !(type.t & VT_EXTERN)) {
+ tcc_error("declaration of void object");
} else {
r = 0;
if ((type.t & VT_BTYPE) == VT_FUNC) {
@@ -7324,33 +8446,21 @@ found:
type.ref->f = ad.f;
} else if (!(type.t & VT_ARRAY)) {
/* not lvalue if array */
- r |= lvalue_type(type.t);
+ r |= VT_LVAL;
}
has_init = (tok == '=');
if (has_init && (type.t & VT_VLA))
tcc_error("variable length array cannot be initialized");
- if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) ||
- ((type.t & VT_BTYPE) == VT_FUNC) ||
- ((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
- !has_init && l == VT_CONST && type.ref->c < 0)) {
+ if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST))
+ || (type.t & VT_BTYPE) == VT_FUNC
+ /* as with GCC, uninitialized global arrays with no size
+ are considered extern: */
+ || ((type.t & VT_ARRAY) && !has_init
+ && l == VT_CONST && type.ref->c < 0)
+ ) {
/* external variable or function */
- /* NOTE: as GCC, uninitialized global static
- arrays of null size are considered as
- extern */
type.t |= VT_EXTERN;
sym = external_sym(v, &type, r, &ad);
- if (ad.alias_target) {
- ElfSym *esym;
- Sym *alias_target;
- alias_target = sym_find(ad.alias_target);
- esym = elfsym(alias_target);
- if (!esym)
- tcc_error("unsupported forward __alias__ attribute");
- /* Local statics have a scope until now (for
- warnings), remove it here. */
- sym->sym_scope = 0;
- put_extern_sym2(sym, esym->st_shndx, esym->st_value, esym->st_size, 0);
- }
} else {
if (type.t & VT_STATIC)
r |= VT_CONST;
@@ -7372,7 +8482,6 @@ found:
}
next();
}
- ad.a.aligned = 0;
}
}
return 0;
@@ -7384,3 +8493,6 @@ static void decl(int l)
}
/* ------------------------------------------------------------------------- */
+#undef gjmp_addr
+#undef gjmp
+/* ------------------------------------------------------------------------- */
diff --git a/tccmacho.c b/tccmacho.c
new file mode 100644
index 0000000..93dee3b
--- /dev/null
+++ b/tccmacho.c
@@ -0,0 +1,982 @@
+/*
+ * Mach-O file handling for TCC
+ *
+ * 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 "tcc.h"
+
+/* In order to make life easy for us we are generating Mach-O files which
+ don't make use of some modern features, but which aren't entirely classic
+ either in that they do use some modern features. We're also only
+ generating 64bit Mach-O files, and only native endian at that.
+
+ In particular we're generating executables that don't make use of
+ DYLD_INFO for dynamic linking info, as that requires us building a
+ trie of exported names. We're simply using classic symbol tables which
+ are still supported by modern dyld.
+
+ But we do use LC_MAIN, which is a "modern" feature in order to not have
+ to setup our own crt code. We're not using lazy linking, so even function
+ calls are resolved at startup. */
+
+#define DEBUG_MACHO 0
+#define dprintf if (DEBUG_MACHO) printf
+
+struct fat_header {
+ uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
+ uint32_t nfat_arch; /* number of structs that follow */
+};
+
+struct fat_arch {
+ int cputype; /* cpu specifier (int) */
+ int cpusubtype; /* machine specifier (int) */
+ uint32_t offset; /* file offset to this object file */
+ uint32_t size; /* size of this object file */
+ uint32_t align; /* alignment as a power of 2 */
+};
+
+#define FAT_MAGIC 0xcafebabe
+#define FAT_CIGAM 0xbebafeca
+#define FAT_MAGIC_64 0xcafebabf
+#define FAT_CIGAM_64 0xbfbafeca
+
+struct mach_header {
+ uint32_t magic; /* mach magic number identifier */
+ int cputype; /* cpu specifier */
+ int cpusubtype; /* machine specifier */
+ uint32_t filetype; /* type of file */
+ uint32_t ncmds; /* number of load commands */
+ uint32_t sizeofcmds; /* the size of all the load commands */
+ uint32_t flags; /* flags */
+};
+
+struct mach_header_64 {
+ struct mach_header mh;
+ uint32_t reserved; /* reserved, pad to 64bit */
+};
+
+/* Constant for the magic field of the mach_header (32-bit architectures) */
+#define MH_MAGIC 0xfeedface /* the mach magic number */
+#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
+#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
+#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
+
+struct load_command {
+ uint32_t cmd; /* type of load command */
+ uint32_t cmdsize; /* total size of command in bytes */
+};
+
+#define LC_REQ_DYLD 0x80000000
+#define LC_SYMTAB 0x2
+#define LC_DYSYMTAB 0xb
+#define LC_LOAD_DYLIB 0xc
+#define LC_ID_DYLIB 0xd
+#define LC_LOAD_DYLINKER 0xe
+#define LC_SEGMENT_64 0x19
+#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD)
+#define LC_MAIN (0x28|LC_REQ_DYLD)
+
+typedef int vm_prot_t;
+
+struct segment_command_64 { /* for 64-bit architectures */
+ uint32_t cmd; /* LC_SEGMENT_64 */
+ uint32_t cmdsize; /* includes sizeof section_64 structs */
+ char segname[16]; /* segment name */
+ uint64_t vmaddr; /* memory address of this segment */
+ uint64_t vmsize; /* memory size of this segment */
+ uint64_t fileoff; /* file offset of this segment */
+ uint64_t filesize; /* amount to map from the file */
+ vm_prot_t maxprot; /* maximum VM protection */
+ vm_prot_t initprot; /* initial VM protection */
+ uint32_t nsects; /* number of sections in segment */
+ uint32_t flags; /* flags */
+};
+
+struct section_64 { /* for 64-bit architectures */
+ char sectname[16]; /* name of this section */
+ char segname[16]; /* segment this section goes in */
+ uint64_t addr; /* memory address of this section */
+ uint64_t size; /* size in bytes of this section */
+ uint32_t offset; /* file offset of this section */
+ uint32_t align; /* section alignment (power of 2) */
+ uint32_t reloff; /* file offset of relocation entries */
+ uint32_t nreloc; /* number of relocation entries */
+ uint32_t flags; /* flags (section type and attributes)*/
+ uint32_t reserved1; /* reserved (for offset or index) */
+ uint32_t reserved2; /* reserved (for count or sizeof) */
+ uint32_t reserved3; /* reserved */
+};
+
+#define S_REGULAR 0x0
+#define S_ZEROFILL 0x1
+#define S_NON_LAZY_SYMBOL_POINTERS 0x6
+#define S_MOD_INIT_FUNC_POINTERS 0x9
+#define S_MOD_TERM_FUNC_POINTERS 0xa
+
+#define S_ATTR_PURE_INSTRUCTIONS 0x80000000
+#define S_ATTR_SOME_INSTRUCTIONS 0x00000400
+
+typedef uint32_t lc_str;
+
+struct dylib_command {
+ uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
+ LC_REEXPORT_DYLIB */
+ uint32_t cmdsize; /* includes pathname string */
+ lc_str name; /* library's path name */
+ uint32_t timestamp; /* library's build time stamp */
+ uint32_t current_version; /* library's current version number */
+ uint32_t compatibility_version; /* library's compatibility vers number*/
+};
+
+struct dylinker_command {
+ uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or
+ LC_DYLD_ENVIRONMENT */
+ uint32_t cmdsize; /* includes pathname string */
+ lc_str name; /* dynamic linker's path name */
+};
+
+struct symtab_command {
+ uint32_t cmd; /* LC_SYMTAB */
+ uint32_t cmdsize; /* sizeof(struct symtab_command) */
+ uint32_t symoff; /* symbol table offset */
+ uint32_t nsyms; /* number of symbol table entries */
+ uint32_t stroff; /* string table offset */
+ uint32_t strsize; /* string table size in bytes */
+};
+
+struct dysymtab_command {
+ uint32_t cmd; /* LC_DYSYMTAB */
+ uint32_t cmdsize; /* sizeof(struct dysymtab_command) */
+
+ uint32_t ilocalsym; /* index to local symbols */
+ uint32_t nlocalsym; /* number of local symbols */
+
+ uint32_t iextdefsym;/* index to externally defined symbols */
+ uint32_t nextdefsym;/* number of externally defined symbols */
+
+ uint32_t iundefsym; /* index to undefined symbols */
+ uint32_t nundefsym; /* number of undefined symbols */
+
+ uint32_t tocoff; /* file offset to table of contents */
+ uint32_t ntoc; /* number of entries in table of contents */
+
+ uint32_t modtaboff; /* file offset to module table */
+ uint32_t nmodtab; /* number of module table entries */
+
+ uint32_t extrefsymoff; /* offset to referenced symbol table */
+ uint32_t nextrefsyms; /* number of referenced symbol table entries */
+
+ uint32_t indirectsymoff;/* file offset to the indirect symbol table */
+ uint32_t nindirectsyms; /* number of indirect symbol table entries */
+
+ uint32_t extreloff; /* offset to external relocation entries */
+ uint32_t nextrel; /* number of external relocation entries */
+ uint32_t locreloff; /* offset to local relocation entries */
+ uint32_t nlocrel; /* number of local relocation entries */
+};
+
+#define INDIRECT_SYMBOL_LOCAL 0x80000000
+
+struct entry_point_command {
+ uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
+ uint32_t cmdsize; /* 24 */
+ uint64_t entryoff; /* file (__TEXT) offset of main() */
+ uint64_t stacksize;/* if not zero, initial stack size */
+};
+
+enum skind {
+ sk_unknown = 0,
+ sk_discard,
+ sk_text,
+ sk_stubs,
+ sk_ro_data,
+ sk_uw_info,
+ sk_nl_ptr, // non-lazy pointers, aka GOT
+ sk_la_ptr, // lazy pointers
+ sk_init,
+ sk_fini,
+ sk_rw_data,
+ sk_bss,
+ sk_linkedit,
+ sk_last
+};
+
+struct nlist_64 {
+ uint32_t n_strx; /* index into the string table */
+ uint8_t n_type; /* type flag, see below */
+ uint8_t n_sect; /* section number or NO_SECT */
+ uint16_t n_desc; /* see <mach-o/stab.h> */
+ uint64_t n_value; /* value of this symbol (or stab offset) */
+};
+
+#define N_UNDF 0x0
+#define N_ABS 0x2
+#define N_EXT 0x1
+#define N_SECT 0xe
+
+#define N_WEAK_REF 0x0040
+#define N_WEAK_DEF 0x0080
+
+struct macho {
+ struct mach_header_64 mh;
+ int seg2lc[4], nseg;
+ struct load_command **lc;
+ struct entry_point_command *ep;
+ int nlc;
+ struct {
+ Section *s;
+ int machosect;
+ } sk_to_sect[sk_last];
+ int *elfsectomacho;
+ int *e2msym;
+ Section *symtab, *strtab, *wdata, *indirsyms, *stubs;
+ int stubsym;
+ uint32_t ilocal, iextdef, iundef;
+};
+
+#define SHT_LINKEDIT (SHT_LOOS + 42)
+#define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */
+
+static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize)
+{
+ struct load_command *lc = tcc_mallocz(cmdsize);
+ lc->cmd = cmd;
+ lc->cmdsize = cmdsize;
+ mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1));
+ mo->lc[mo->nlc++] = lc;
+ return lc;
+}
+
+static struct segment_command_64 * add_segment(struct macho *mo, char *name)
+{
+ struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc));
+ strncpy(sc->segname, name, 16);
+ mo->seg2lc[mo->nseg++] = mo->nlc - 1;
+ return sc;
+}
+
+static struct segment_command_64 * get_segment(struct macho *mo, int i)
+{
+ return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]);
+}
+
+static int add_section(struct macho *mo, struct segment_command_64 **_seg, char *name)
+{
+ struct segment_command_64 *seg = *_seg;
+ int ret = seg->nsects;
+ struct section_64 *sec;
+ seg->nsects++;
+ seg->cmdsize += sizeof(*sec);
+ seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec));
+ sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret;
+ memset(sec, 0, sizeof(*sec));
+ strncpy(sec->sectname, name, 16);
+ strncpy(sec->segname, seg->segname, 16);
+ *_seg = seg;
+ return ret;
+}
+
+static struct section_64 *get_section(struct segment_command_64 *seg, int i)
+{
+ return (struct section_64*)((char*)seg + sizeof(*seg)) + i;
+}
+
+static void * add_dylib(struct macho *mo, char *name)
+{
+ struct dylib_command *lc;
+ int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8;
+ lc = add_lc(mo, LC_LOAD_DYLIB, sz);
+ lc->name = sizeof(*lc);
+ strcpy((char*)lc + lc->name, name);
+ lc->timestamp = 2;
+ lc->current_version = 1 << 16;
+ lc->compatibility_version = 1 << 16;
+ return lc;
+}
+
+static void check_relocs(TCCState *s1, struct macho *mo)
+{
+ Section *s;
+ ElfW_Rel *rel;
+ ElfW(Sym) *sym;
+ int i, type, gotplt_entry, sym_index, for_code;
+ struct sym_attr *attr;
+
+ s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
+ mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
+ for (i = 1; i < s1->nb_sections; i++) {
+ s = s1->sections[i];
+ if (s->sh_type != SHT_RELX)
+ continue;
+ for_each_elem(s, 0, rel, ElfW_Rel) {
+ type = ELFW(R_TYPE)(rel->r_info);
+ gotplt_entry = gotplt_entry_type(type);
+ for_code = code_reloc(type);
+ /* We generate a non-lazy pointer for used undefined symbols
+ and for defined symbols that must have a place for their
+ address due to codegen (i.e. a reloc requiring a got slot). */
+ sym_index = ELFW(R_SYM)(rel->r_info);
+ sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+ if (sym->st_shndx == SHN_UNDEF
+ || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
+ attr = get_sym_attr(s1, sym_index, 1);
+ if (!attr->dyn_index) {
+ uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
+ attr->got_offset = s1->got->data_offset;
+ attr->plt_offset = -1;
+ attr->dyn_index = 1; /* used as flag */
+ section_ptr_add(s1->got, PTR_SIZE);
+ if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
+ if (sym->st_shndx == SHN_UNDEF)
+ tcc_error("undefined local symbol???");
+ *pi = INDIRECT_SYMBOL_LOCAL;
+ /* The pointer slot we generated must point to the
+ symbol, whose address is only known after layout,
+ so register a simple relocation for that. */
+ put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
+ R_DATA_PTR, sym_index);
+ } else
+ *pi = mo->e2msym[sym_index];
+ }
+ if (for_code) {
+ if (attr->plt_offset == -1) {
+ uint8_t *jmp;
+ attr->plt_offset = mo->stubs->data_offset;
+ jmp = section_ptr_add(mo->stubs, 6);
+ jmp[0] = 0xff; /* jmpq *ofs(%rip) */
+ jmp[1] = 0x25;
+ put_elf_reloc(s1->symtab, mo->stubs,
+ attr->plt_offset + 2,
+ R_X86_64_GOTPCREL, sym_index);
+ }
+ rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
+ rel->r_addend += attr->plt_offset;
+ }
+ }
+ }
+ }
+}
+
+static int check_symbols(TCCState *s1, struct macho *mo)
+{
+ int sym_index, sym_end;
+ int ret = 0;
+
+ mo->ilocal = mo->iextdef = mo->iundef = -1;
+ sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
+ for (sym_index = 1; sym_index < sym_end; ++sym_index) {
+ int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
+ ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
+ const char *name = (char*)symtab_section->link->data + sym->st_name;
+ unsigned type = ELFW(ST_TYPE)(sym->st_info);
+ unsigned bind = ELFW(ST_BIND)(sym->st_info);
+ unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
+
+ dprintf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",
+ sym_index, elf_index, sym->st_value,
+ type, bind, vis, sym->st_shndx, name);
+ if (bind == STB_LOCAL) {
+ if (mo->ilocal == -1)
+ mo->ilocal = sym_index - 1;
+ if (mo->iextdef != -1 || mo->iundef != -1)
+ tcc_error("local syms after global ones");
+ } else if (sym->st_shndx != SHN_UNDEF) {
+ if (mo->iextdef == -1)
+ mo->iextdef = sym_index - 1;
+ if (mo->iundef != -1)
+ tcc_error("external defined symbol after undefined");
+ } else if (sym->st_shndx == SHN_UNDEF) {
+ if (mo->iundef == -1)
+ mo->iundef = sym_index - 1;
+ if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK
+ || find_elf_sym(s1->dynsymtab_section, name)) {
+ /* Mark the symbol as coming from a dylib so that
+ relocate_syms doesn't complain. Normally bind_exe_dynsyms
+ would do this check, and place the symbol into dynsym
+ which is checked by relocate_syms. But Mach-O doesn't use
+ bind_exe_dynsyms. */
+ sym->st_shndx = SHN_FROMDLL;
+ continue;
+ }
+ tcc_error_noabort("undefined symbol '%s'", name);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
+{
+ struct nlist_64 n = *pn;
+ ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
+ const char *name = (char*)symtab_section->link->data + sym->st_name;
+ switch(ELFW(ST_TYPE)(sym->st_info)) {
+ case STT_NOTYPE:
+ case STT_OBJECT:
+ case STT_FUNC:
+ case STT_SECTION:
+ n.n_type = N_SECT;
+ break;
+ case STT_FILE:
+ n.n_type = N_ABS;
+ break;
+ default:
+ tcc_error("unhandled ELF symbol type %d %s",
+ ELFW(ST_TYPE)(sym->st_info), name);
+ }
+ if (sym->st_shndx == SHN_UNDEF)
+ tcc_error("should have been rewritten to SHN_FROMDLL: %s", name);
+ else if (sym->st_shndx == SHN_FROMDLL)
+ n.n_type = N_UNDF, n.n_sect = 0;
+ else if (sym->st_shndx == SHN_ABS)
+ n.n_type = N_ABS, n.n_sect = 0;
+ else if (sym->st_shndx >= SHN_LORESERVE)
+ tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name);
+ else if (!mo->elfsectomacho[sym->st_shndx])
+ tcc_error("ELF section %d not mapped into Mach-O for symbol %s",
+ sym->st_shndx, name);
+ else
+ n.n_sect = mo->elfsectomacho[sym->st_shndx];
+ if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL)
+ n.n_type |= N_EXT;
+ else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
+ n.n_desc |= N_WEAK_REF | (n.n_type != N_UNDF ? N_WEAK_DEF : 0);
+ n.n_strx = pn->n_strx;
+ n.n_value = sym->st_value;
+ *pn = n;
+}
+
+static void convert_symbols(TCCState *s1, struct macho *mo)
+{
+ struct nlist_64 *pn;
+ for_each_elem(mo->symtab, 0, pn, struct nlist_64)
+ convert_symbol(s1, mo, pn);
+}
+
+static int machosymcmp(const void *_a, const void *_b)
+{
+ TCCState *s1 = tcc_state;
+ int ea = ((struct nlist_64 *)_a)->n_value;
+ int eb = ((struct nlist_64 *)_b)->n_value;
+ ElfSym *sa = (ElfSym *)symtab_section->data + ea;
+ ElfSym *sb = (ElfSym *)symtab_section->data + eb;
+ int r;
+ /* locals, then defined externals, then undefined externals, the
+ last two sections also by name, otherwise stable sort */
+ r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
+ - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
+ if (r)
+ return r;
+ r = (sa->st_shndx == SHN_UNDEF) - (sb->st_shndx == SHN_UNDEF);
+ if (r)
+ return r;
+ if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
+ const char * na = (char*)symtab_section->link->data + sa->st_name;
+ const char * nb = (char*)symtab_section->link->data + sb->st_name;
+ r = strcmp(na, nb);
+ if (r)
+ return r;
+ }
+ return ea - eb;
+}
+
+static void create_symtab(TCCState *s1, struct macho *mo)
+{
+ int sym_index, sym_end;
+ struct nlist_64 *pn;
+
+ /* Stub creation belongs to check_relocs, but we need to create
+ the symbol now, so its included in the sorting. */
+ mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
+ mo->stubsym = put_elf_sym(s1->symtab, 0, 0,
+ ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
+ mo->stubs->sh_num, ".__stubs");
+
+ mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
+ mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
+ put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
+ sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
+ pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
+ for (sym_index = 1; sym_index < sym_end; ++sym_index) {
+ ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
+ const char *name = (char*)symtab_section->link->data + sym->st_name;
+ pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
+ pn[sym_index - 1].n_value = sym_index;
+ }
+ tcc_enter_state(s1); /* qsort needs global state */
+ qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp);
+ tcc_exit_state();
+ mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
+ mo->e2msym[0] = -1;
+ for (sym_index = 1; sym_index < sym_end; ++sym_index) {
+ mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
+ }
+}
+
+struct {
+ int seg;
+ uint32_t flags;
+ char *name;
+} skinfo[sk_last] = {
+ /*[sk_unknown] =*/ { 0 },
+ /*[sk_discard] =*/ { 0 },
+ /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
+ | S_ATTR_SOME_INSTRUCTIONS, "__text" },
+ /*[sk_stubs] =*/ { 0 },
+ /*[sk_ro_data] =*/ { 1, S_REGULAR, "__rodata" },
+ /*[sk_uw_info] =*/ { 0 },
+ /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" },
+ /*[sk_la_ptr] =*/ { 0 },
+ /*[sk_init] =*/ { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" },
+ /*[sk_fini] =*/ { 2, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" },
+ /*[sk_rw_data] =*/ { 2, S_REGULAR, "__data" },
+ /*[sk_bss] =*/ { 2, S_ZEROFILL, "__bss" },
+ /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL },
+};
+
+static void collect_sections(TCCState *s1, struct macho *mo)
+{
+ int i, sk, numsec;
+ uint64_t curaddr, fileofs;
+ Section *s;
+ struct segment_command_64 *seg = NULL;
+ struct dylinker_command *dyldlc;
+ struct symtab_command *symlc;
+ struct dysymtab_command *dysymlc;
+ char *str;
+
+ seg = add_segment(mo, "__PAGEZERO");
+ seg->vmsize = (uint64_t)1 << 32;
+
+ seg = add_segment(mo, "__TEXT");
+ seg->vmaddr = (uint64_t)1 << 32;
+ seg->maxprot = 7; // rwx
+ seg->initprot = 5; // r-x
+
+ seg = add_segment(mo, "__DATA");
+ seg->vmaddr = -1;
+ seg->maxprot = 7; // rwx
+ seg->initprot = 3; // rw-
+
+ seg = add_segment(mo, "__LINKEDIT");
+ seg->vmaddr = -1;
+ seg->maxprot = 7; // rwx
+ seg->initprot = 1; // r--
+
+ mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep));
+ mo->ep->entryoff = 4096;
+
+ i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
+ dyldlc = add_lc(mo, LC_LOAD_DYLINKER, i);
+ dyldlc->name = sizeof(*dyldlc);
+ str = (char*)dyldlc + dyldlc->name;
+ strcpy(str, "/usr/lib/dyld");
+
+ symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc));
+ dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc));
+
+ for(i = 0; i < s1->nb_loaded_dlls; i++) {
+ DLLReference *dllref = s1->loaded_dlls[i];
+ if (dllref->level == 0)
+ add_dylib(mo, dllref->name);
+ }
+
+ /* dyld requires a writable segment with classic Mach-O, but it ignores
+ zero-sized segments for this, so force to have some data. */
+ section_ptr_add(data_section, 1);
+ memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect));
+ for (i = s1->nb_sections; i-- > 1;) {
+ int type, flags;
+ s = s1->sections[i];
+ type = s->sh_type;
+ flags = s->sh_flags;
+ sk = sk_unknown;
+ if (flags & SHF_ALLOC) {
+ switch (type) {
+ default: sk = sk_unknown; break;
+ case SHT_INIT_ARRAY: sk = sk_init; break;
+ case SHT_FINI_ARRAY: sk = sk_fini; break;
+ case SHT_NOBITS: sk = sk_bss; break;
+ case SHT_SYMTAB: sk = sk_discard; break;
+ case SHT_STRTAB: sk = s == stabstr_section ? sk_ro_data : sk_discard; break;
+ case SHT_RELX: sk = sk_discard; break;
+ case SHT_LINKEDIT: sk = sk_linkedit; break;
+ case SHT_PROGBITS:
+ if (s == s1->got)
+ sk = sk_nl_ptr;
+ else if (flags & SHF_EXECINSTR)
+ sk = sk_text;
+ else if (flags & SHF_WRITE)
+ sk = sk_rw_data;
+ else
+ sk = sk_ro_data;
+ break;
+ }
+ } else
+ sk = sk_discard;
+ s->prev = mo->sk_to_sect[sk].s;
+ mo->sk_to_sect[sk].s = s;
+ }
+ fileofs = 4096; /* leave space for mach-o headers */
+ curaddr = get_segment(mo, 1)->vmaddr;
+ curaddr += 4096;
+ seg = NULL;
+ numsec = 0;
+ mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections);
+ for (sk = sk_unknown; sk < sk_last; sk++) {
+ struct section_64 *sec = NULL;
+ if (seg) {
+ seg->vmsize = curaddr - seg->vmaddr;
+ seg->filesize = fileofs - seg->fileoff;
+ }
+ if (skinfo[sk].seg && mo->sk_to_sect[sk].s) {
+ uint64_t al = 0;
+ int si;
+ seg = get_segment(mo, skinfo[sk].seg);
+ if (skinfo[sk].name) {
+ si = add_section(mo, &seg, skinfo[sk].name);
+ numsec++;
+ mo->lc[mo->seg2lc[skinfo[sk].seg]] = (struct load_command*)seg;
+ mo->sk_to_sect[sk].machosect = si;
+ sec = get_section(seg, si);
+ sec->flags = skinfo[sk].flags;
+ }
+ if (seg->vmaddr == -1) {
+ curaddr = (curaddr + 4095) & -4096;
+ seg->vmaddr = curaddr;
+ fileofs = (fileofs + 4095) & -4096;
+ seg->fileoff = fileofs;
+ }
+
+ for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
+ int a = exact_log2p1(s->sh_addralign);
+ if (a && al < (a - 1))
+ al = a - 1;
+ s->sh_size = s->data_offset;
+ }
+ if (sec)
+ sec->align = al;
+ al = 1ULL << al;
+ if (al > 4096)
+ tcc_warning("alignment > 4096"), sec->align = 12, al = 4096;
+ curaddr = (curaddr + al - 1) & -al;
+ fileofs = (fileofs + al - 1) & -al;
+ if (sec) {
+ sec->addr = curaddr;
+ sec->offset = fileofs;
+ }
+ for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
+ al = s->sh_addralign;
+ curaddr = (curaddr + al - 1) & -al;
+ dprintf("curaddr now 0x%llx\n", curaddr);
+ s->sh_addr = curaddr;
+ curaddr += s->sh_size;
+ if (s->sh_type != SHT_NOBITS) {
+ fileofs = (fileofs + al - 1) & -al;
+ s->sh_offset = fileofs;
+ fileofs += s->sh_size;
+ dprintf("fileofs now %lld\n", fileofs);
+ }
+ if (sec)
+ mo->elfsectomacho[s->sh_num] = numsec;
+ }
+ if (sec)
+ sec->size = curaddr - sec->addr;
+ }
+ if (DEBUG_MACHO)
+ for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
+ int type = s->sh_type;
+ int flags = s->sh_flags;
+ printf("%d section %-16s %-10s %09llx %04x %02d %s,%s,%s\n",
+ sk,
+ s->name,
+ type == SHT_PROGBITS ? "progbits" :
+ type == SHT_NOBITS ? "nobits" :
+ type == SHT_SYMTAB ? "symtab" :
+ type == SHT_STRTAB ? "strtab" :
+ type == SHT_INIT_ARRAY ? "init" :
+ type == SHT_FINI_ARRAY ? "fini" :
+ type == SHT_RELX ? "rel" : "???",
+ s->sh_addr,
+ (unsigned)s->data_offset,
+ s->sh_addralign,
+ flags & SHF_ALLOC ? "alloc" : "",
+ flags & SHF_WRITE ? "write" : "",
+ flags & SHF_EXECINSTR ? "exec" : ""
+ );
+ }
+ }
+ if (seg) {
+ seg->vmsize = curaddr - seg->vmaddr;
+ seg->filesize = fileofs - seg->fileoff;
+ }
+
+ /* Fill symtab info */
+ symlc->symoff = mo->symtab->sh_offset;
+ symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
+ symlc->stroff = mo->strtab->sh_offset;
+ symlc->strsize = mo->strtab->data_offset;
+
+ dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
+ dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
+ dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
+ dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
+ dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
+ dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
+ dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
+ dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
+}
+
+static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
+{
+ int i, sk;
+ uint64_t fileofs = 0;
+ Section *s;
+ mo->mh.mh.magic = MH_MAGIC_64;
+ mo->mh.mh.cputype = 0x1000007; // x86_64
+ mo->mh.mh.cpusubtype = 0x80000003;// all | CPU_SUBTYPE_LIB64
+ mo->mh.mh.filetype = 2; // MH_EXECUTE
+ mo->mh.mh.flags = 4; // DYLDLINK
+ mo->mh.mh.ncmds = mo->nlc;
+ mo->mh.mh.sizeofcmds = 0;
+ for (i = 0; i < mo->nlc; i++)
+ mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize;
+
+ fwrite(&mo->mh, 1, sizeof(mo->mh), fp);
+ fileofs += sizeof(mo->mh);
+ for (i = 0; i < mo->nlc; i++) {
+ fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp);
+ fileofs += mo->lc[i]->cmdsize;
+ }
+
+ for (sk = sk_unknown; sk < sk_last; sk++) {
+ //struct segment_command_64 *seg;
+ if (!skinfo[sk].seg || !mo->sk_to_sect[sk].s)
+ continue;
+ /*seg =*/ get_segment(mo, skinfo[sk].seg);
+ for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
+ if (s->sh_type != SHT_NOBITS) {
+ while (fileofs < s->sh_offset)
+ fputc(0, fp), fileofs++;
+ if (s->sh_size) {
+ fwrite(s->data, 1, s->sh_size, fp);
+ fileofs += s->sh_size;
+ }
+ }
+ }
+ }
+}
+
+ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
+{
+ int fd, mode, file_type;
+ FILE *fp;
+ int i, ret = -1;
+ struct macho mo;
+
+ (void)memset(&mo, 0, sizeof(mo));
+
+ file_type = s1->output_type;
+ if (file_type == TCC_OUTPUT_OBJ)
+ mode = 0666;
+ else
+ mode = 0777;
+ unlink(filename);
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
+ if (fd < 0) {
+ tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
+ return -1;
+ }
+ fp = fdopen(fd, "wb");
+ if (s1->verbose)
+ printf("<- %s\n", filename);
+
+ tcc_add_runtime(s1);
+ resolve_common_syms(s1);
+ create_symtab(s1, &mo);
+ check_relocs(s1, &mo);
+ ret = check_symbols(s1, &mo);
+ if (!ret) {
+ int i;
+ Section *s;
+ collect_sections(s1, &mo);
+ relocate_syms(s1, s1->symtab, 0);
+ mo.ep->entryoff = get_sym_addr(s1, "main", 1, 1)
+ - get_segment(&mo, 1)->vmaddr;
+ if (s1->nb_errors)
+ goto do_ret;
+
+ for(i = 1; i < s1->nb_sections; i++) {
+ s = s1->sections[i];
+ if (s->reloc)
+ relocate_section(s1, s);
+ }
+ convert_symbols(s1, &mo);
+
+ macho_write(s1, &mo, fp);
+ }
+
+ do_ret:
+ for (i = 0; i < mo.nlc; i++)
+ tcc_free(mo.lc[i]);
+ tcc_free(mo.lc);
+ tcc_free(mo.elfsectomacho);
+ tcc_free(mo.e2msym);
+
+ fclose(fp);
+ return ret;
+}
+
+static uint32_t swap32(uint32_t x)
+{
+ return (x >> 24) | (x << 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8);
+}
+#define SWAP(x) (swap ? swap32(x) : (x))
+
+ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev)
+{
+ unsigned char buf[sizeof(struct mach_header_64)];
+ void *buf2;
+ uint32_t machofs = 0;
+ struct fat_header fh;
+ struct mach_header mh;
+ struct load_command *lc;
+ int i, swap = 0;
+ const char *soname = filename;
+ struct nlist_64 *symtab = 0;
+ uint32_t nsyms = 0;
+ char *strtab = 0;
+ uint32_t strsize = 0;
+ uint32_t iextdef = 0;
+ uint32_t nextdef = 0;
+ DLLReference *dllref;
+
+ again:
+ if (full_read(fd, buf, sizeof(buf)) != sizeof(buf))
+ return -1;
+ memcpy(&fh, buf, sizeof(fh));
+ if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) {
+ struct fat_arch *fa = load_data(fd, sizeof(fh),
+ fh.nfat_arch * sizeof(*fa));
+ swap = fh.magic == FAT_CIGAM;
+ for (i = 0; i < SWAP(fh.nfat_arch); i++)
+ if (SWAP(fa[i].cputype) == 0x01000007 /* CPU_TYPE_X86_64 */
+ && SWAP(fa[i].cpusubtype) == 3) /* CPU_SUBTYPE_X86_ALL */
+ break;
+ if (i == SWAP(fh.nfat_arch)) {
+ tcc_free(fa);
+ return -1;
+ }
+ machofs = SWAP(fa[i].offset);
+ tcc_free(fa);
+ lseek(fd, machofs, SEEK_SET);
+ goto again;
+ } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) {
+ tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled",
+ filename, fh.magic);
+ return -1;
+ }
+
+ memcpy(&mh, buf, sizeof(mh));
+ if (mh.magic != MH_MAGIC_64)
+ return -1;
+ dprintf("found Mach-O at %d\n", machofs);
+ buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds);
+ for (i = 0, lc = buf2; i < mh.ncmds; i++) {
+ dprintf("lc %2d: 0x%08x\n", i, lc->cmd);
+ switch (lc->cmd) {
+ case LC_SYMTAB:
+ {
+ struct symtab_command *sc = (struct symtab_command*)lc;
+ nsyms = sc->nsyms;
+ symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab));
+ strsize = sc->strsize;
+ strtab = load_data(fd, machofs + sc->stroff, strsize);
+ break;
+ }
+ case LC_ID_DYLIB:
+ {
+ struct dylib_command *dc = (struct dylib_command*)lc;
+ soname = (char*)lc + dc->name;
+ dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n",
+ dc->timestamp, dc->current_version,
+ dc->compatibility_version, soname);
+ break;
+ }
+ case LC_REEXPORT_DYLIB:
+ {
+ struct dylib_command *dc = (struct dylib_command*)lc;
+ char *name = (char*)lc + dc->name;
+ int subfd = open(name, O_RDONLY | O_BINARY);
+ dprintf(" REEXPORT %s\n", name);
+ if (subfd < 0)
+ tcc_warning("can't open %s (reexported from %s)", name, filename);
+ else {
+ /* Hopefully the REEXPORTs never form a cycle, we don't check
+ for that! */
+ macho_load_dll(s1, subfd, name, lev + 1);
+ close(subfd);
+ }
+ break;
+ }
+ case LC_DYSYMTAB:
+ {
+ struct dysymtab_command *dc = (struct dysymtab_command*)lc;
+ iextdef = dc->iextdefsym;
+ nextdef = dc->nextdefsym;
+ break;
+ }
+ }
+ lc = (struct load_command*) ((char*)lc + lc->cmdsize);
+ }
+
+ /* if the dll is already loaded, do not load it */
+ for(i = 0; i < s1->nb_loaded_dlls; i++) {
+ dllref = s1->loaded_dlls[i];
+ if (!strcmp(soname, dllref->name)) {
+ /* but update level if needed */
+ if (lev < dllref->level)
+ dllref->level = lev;
+ goto the_end;
+ }
+ }
+ dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
+ dllref->level = lev;
+ strcpy(dllref->name, soname);
+ dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+
+ if (!nsyms || !nextdef)
+ tcc_warning("%s doesn't export any symbols?", filename);
+
+ //dprintf("symbols (all):\n");
+ dprintf("symbols (exported):\n");
+ dprintf(" n: typ sec desc value name\n");
+ //for (i = 0; i < nsyms; i++) {
+ for (i = iextdef; i < iextdef + nextdef; i++) {
+ struct nlist_64 *sym = symtab + i;
+ dprintf("%5d: %3d %3d 0x%04x 0x%016llx %s\n",
+ i, sym->n_type, sym->n_sect, sym->n_desc, sym->n_value,
+ strtab + sym->n_strx);
+ set_elf_sym(s1->dynsymtab_section, 0, 0,
+ ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
+ 0, SHN_UNDEF, strtab + sym->n_strx);
+ }
+
+ the_end:
+ tcc_free(strtab);
+ tcc_free(symtab);
+ tcc_free(buf2);
+ return 0;
+}
diff --git a/tccpe.c b/tccpe.c
index a7266c9..9b59d92 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -231,6 +231,15 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_REL_BASED_REL32 7
#define IMAGE_REL_BASED_DIR64 10
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+
#pragma pack(pop)
/* ----------------------------------------------------------- */
@@ -279,17 +288,6 @@ struct pe_rsrc_reloc {
/* ------------------------------------------------------------- */
/* internal temporary structures */
-/*
-#define IMAGE_SCN_CNT_CODE 0x00000020
-#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
-#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
-#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
-#define IMAGE_SCN_MEM_SHARED 0x10000000
-#define IMAGE_SCN_MEM_EXECUTE 0x20000000
-#define IMAGE_SCN_MEM_READ 0x40000000
-#define IMAGE_SCN_MEM_WRITE 0x80000000
-*/
-
enum {
sec_text = 0,
sec_data ,
@@ -299,10 +297,12 @@ enum {
sec_other ,
sec_rsrc ,
sec_stab ,
+ sec_stabstr ,
sec_reloc ,
sec_last
};
+#if 0
static const DWORD pe_sec_flags[] = {
0x60000020, /* ".text" , */
0xC0000040, /* ".data" , */
@@ -314,14 +314,15 @@ static const DWORD pe_sec_flags[] = {
0x42000802, /* ".stab" , */
0x42000040, /* ".reloc" , */
};
+#endif
struct section_info {
- int cls, ord;
+ int cls;
char name[32];
DWORD sh_addr;
DWORD sh_size;
- DWORD sh_flags;
- unsigned char *data;
+ DWORD pe_flags;
+ Section *sec;
DWORD data_size;
IMAGE_SECTION_HEADER ish;
};
@@ -357,7 +358,7 @@ struct pe_info {
int subsystem;
DWORD section_align;
DWORD file_align;
- struct section_info *sec_info;
+ struct section_info **sec_info;
int sec_count;
struct pe_import_info **imp_info;
int imp_count;
@@ -430,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key)
return -1;
}
-#if 0
-ST_FN DWORD umin(DWORD a, DWORD b)
+static DWORD umin(DWORD a, DWORD b)
{
return a < b ? a : b;
}
-#endif
static DWORD umax(DWORD a, DWORD b)
{
@@ -465,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz
hdr->opthdr.DataDirectory[dir].Size = size;
}
-static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
+struct pe_file {
+ FILE *op;
+ DWORD sum;
+ unsigned pos;
+};
+
+static int pe_fwrite(void *data, int len, struct pe_file *pf)
{
- if (psum) {
- DWORD sum = *psum;
- WORD *p = data;
- int i;
- for (i = len; i > 0; i -= 2) {
- sum += (i >= 2) ? *p++ : *(BYTE*)p;
- sum = (sum + (sum >> 16)) & 0xFFFF;
- }
- *psum = sum;
+ WORD *p = data;
+ DWORD sum;
+ int ret, i;
+ pf->pos += (ret = fwrite(data, 1, len, pf->op));
+ sum = pf->sum;
+ for (i = len; i > 0; i -= 2) {
+ sum += (i >= 2) ? *p++ : *(BYTE*)p;
+ sum = (sum + (sum >> 16)) & 0xFFFF;
}
- return len == fwrite(data, 1, len, fp) ? 0 : -1;
+ pf->sum = sum;
+ return len == ret ? 0 : -1;
}
-static void pe_fpad(FILE *fp, DWORD new_pos)
+static void pe_fpad(struct pe_file *pf, DWORD new_pos)
{
- DWORD pos = ftell(fp);
- while (++pos <= new_pos)
- fputc(0, fp);
+ char buf[256];
+ int n, diff = new_pos - pf->pos;
+ memset(buf, 0, sizeof buf);
+ while (diff > 0) {
+ diff -= n = umin(diff, sizeof buf);
+ fwrite(buf, n, 1, pf->op);
+ }
+ pf->pos = new_pos;
}
/*----------------------------------------------------------------------------*/
@@ -596,13 +606,14 @@ static int pe_write(struct pe_info *pe)
struct pe_header pe_header = pe_template;
int i;
- FILE *op;
- DWORD file_offset, sum;
+ struct pe_file pf = {0};
+ DWORD file_offset;
struct section_info *si;
IMAGE_SECTION_HEADER *psh;
+ TCCState *s1 = pe->s1;
- op = fopen(pe->filename, "wb");
- if (NULL == op) {
+ pf.op = fopen(pe->filename, "wb");
+ if (NULL == pf.op) {
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
return -1;
}
@@ -621,7 +632,7 @@ static int pe_write(struct pe_info *pe)
DWORD addr, size;
const char *sh_name;
- si = pe->sec_info + i;
+ si = pe->sec_info[i];
sh_name = si->name;
addr = si->sh_addr - pe->imagebase;
size = si->sh_size;
@@ -633,12 +644,14 @@ static int pe_write(struct pe_info *pe)
switch (si->cls) {
case sec_text:
- pe_header.opthdr.BaseOfCode = addr;
+ if (!pe_header.opthdr.BaseOfCode)
+ pe_header.opthdr.BaseOfCode = addr;
break;
case sec_data:
#ifndef TCC_TARGET_X86_64
- pe_header.opthdr.BaseOfData = addr;
+ if (!pe_header.opthdr.BaseOfData)
+ pe_header.opthdr.BaseOfData = addr;
#endif
break;
@@ -656,27 +669,22 @@ static int pe_write(struct pe_info *pe)
case sec_pdata:
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size);
break;
-
- case sec_stab:
- break;
}
- if (pe->thunk == pe->s1->sections[si->ord]) {
- if (pe->imp_size) {
- pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
- pe->imp_offs + addr, pe->imp_size);
- pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
- pe->iat_offs + addr, pe->iat_size);
- }
- if (pe->exp_size) {
- pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
- pe->exp_offs + addr, pe->exp_size);
- }
+ if (pe->imp_size) {
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
+ pe->imp_offs, pe->imp_size);
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
+ pe->iat_offs, pe->iat_size);
+ }
+ if (pe->exp_size) {
+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
+ pe->exp_offs, pe->exp_size);
}
- strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
+ memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
- psh->Characteristics = pe_sec_flags[si->cls];
+ psh->Characteristics = si->pe_flags;
psh->VirtualAddress = addr;
psh->Misc.VirtualSize = size;
pe_header.opthdr.SizeOfImage =
@@ -705,25 +713,29 @@ static int pe_write(struct pe_info *pe)
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
- sum = 0;
- pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
+ pe_fwrite(&pe_header, sizeof pe_header, &pf);
for (i = 0; i < pe->sec_count; ++i)
- pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
- pe_fpad(op, pe->sizeofheaders);
+ pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
+
+ file_offset = pe->sizeofheaders;
for (i = 0; i < pe->sec_count; ++i) {
- si = pe->sec_info + i;
- psh = &si->ish;
- if (si->data_size) {
- pe_fwrite(si->data, si->data_size, op, &sum);
- file_offset = psh->PointerToRawData + psh->SizeOfRawData;
- pe_fpad(op, file_offset);
+ Section *s;
+ si = pe->sec_info[i];
+ for (s = si->sec; s; s = s->prev) {
+ pe_fpad(&pf, file_offset);
+ pe_fwrite(s->data, s->data_offset, &pf);
+ if (s->prev)
+ file_offset += s->prev->sh_addr - s->sh_addr;
}
+ file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
+ pe_fpad(&pf, file_offset);
}
- pe_header.opthdr.CheckSum = sum + file_offset;
- fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
- pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
- fclose (op);
+ pf.sum += file_offset;
+ fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
+ pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
+
+ fclose (pf.op);
#ifndef _WIN32
chmod(pe->filename, 0777);
#endif
@@ -785,6 +797,7 @@ static void pe_build_imports(struct pe_info *pe)
int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
int ndlls = pe->imp_count;
+ TCCState *s1 = pe->s1;
for (sym_cnt = i = 0; i < ndlls; ++i)
sym_cnt += pe->imp_info[i]->sym_count;
@@ -793,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe)
return;
pe_align_section(pe->thunk, 16);
-
- pe->imp_offs = dll_ptr = pe->thunk->data_offset;
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
- pe->iat_offs = dll_ptr + pe->imp_size;
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
+ dll_ptr = pe->thunk->data_offset;
+ thk_ptr = dll_ptr + pe->imp_size;
+ ent_ptr = thk_ptr + pe->iat_size;
+ pe->imp_offs = dll_ptr + rva_base;
+ pe->iat_offs = thk_ptr + rva_base;
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
- thk_ptr = pe->iat_offs;
- ent_ptr = pe->iat_offs + pe->iat_size;
-
for (i = 0; i < pe->imp_count; ++i) {
IMAGE_IMPORT_DESCRIPTOR *hdr;
int k, n, dllindex;
@@ -849,7 +861,7 @@ static void pe_build_imports(struct pe_info *pe)
v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name);
}
if (!v)
- tcc_error_noabort("can't build symbol '%s'", name);
+ tcc_error_noabort("could not resolve symbol '%s'", name);
} else
#endif
if (ordinal) {
@@ -892,10 +904,11 @@ static void pe_build_exports(struct pe_info *pe)
{
ElfW(Sym) *sym;
int sym_index, sym_end;
- DWORD rva_base, func_o, name_o, ord_o, str_o;
+ DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
IMAGE_EXPORT_DIRECTORY *hdr;
int sym_count, ord;
struct pe_sort_sym **sorted, *p;
+ TCCState *s1 = pe->s1;
FILE *op;
char buf[260];
@@ -933,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe)
pe_align_section(pe->thunk, 16);
dllname = tcc_basename(pe->filename);
- pe->exp_offs = pe->thunk->data_offset;
- func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
+ base_o = pe->thunk->data_offset;
+ func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
name_o = func_o + sym_count * sizeof (DWORD);
ord_o = name_o + sym_count * sizeof (DWORD);
str_o = ord_o + sym_count * sizeof(WORD);
- hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
+ hdr = section_ptr_add(pe->thunk, str_o - base_o);
hdr->Characteristics = 0;
hdr->Base = 1;
hdr->NumberOfFunctions = sym_count;
@@ -981,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe)
if (op)
fprintf(op, "%s\n", name);
}
- pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
+
+ pe->exp_offs = base_o + rva_base;
+ pe->exp_size = pe->thunk->data_offset - base_o;
dynarray_reset(&sorted, &sym_count);
if (op)
fclose(op);
@@ -990,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe)
/* ------------------------------------------------------------- */
static void pe_build_reloc (struct pe_info *pe)
{
- DWORD offset, block_ptr, addr;
+ DWORD offset, block_ptr, sh_addr, addr;
int count, i;
ElfW_Rel *rel, *rel_end;
Section *s = NULL, *sr;
+ struct pe_reloc_header *hdr;
- offset = addr = block_ptr = count = i = 0;
+ sh_addr = offset = block_ptr = count = i = 0;
rel = rel_end = NULL;
for(;;) {
if (rel < rel_end) {
int type = ELFW(R_TYPE)(rel->r_info);
- addr = rel->r_offset + s->sh_addr;
+ addr = rel->r_offset + sh_addr;
++ rel;
if (type != REL_TYPE_DIRECT)
continue;
@@ -1018,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe)
}
-- rel;
- } else if (i < pe->sec_count) {
- sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
+ } else if (s) {
+ sr = s->reloc;
if (sr) {
rel = (ElfW_Rel *)sr->data;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+ sh_addr = s->sh_addr;
}
+ s = s->prev;
continue;
- }
- if (count) {
- /* store the last block and ready for a new one */
- struct pe_reloc_header *hdr;
- if (count & 1) /* align for DWORDS */
- section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
- hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
- hdr -> offset = offset - pe->imagebase;
- hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
- count = 0;
- }
+ } else if (i < pe->sec_count) {
+ s = pe->sec_info[i]->sec, ++i;
+ continue;
- if (rel >= rel_end)
+ } else if (!count)
break;
+
+ /* fill the last block and ready for a new one */
+ if (count & 1) /* align for DWORDS */
+ section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
+ hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
+ hdr -> offset = offset - pe->imagebase;
+ hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
+ count = 0;
}
}
@@ -1064,7 +1082,6 @@ static int pe_section_class(Section *s)
return sec_idata;
if (0 == strcmp(name, ".pdata"))
return sec_pdata;
- return sec_other;
} else if (type == SHT_NOBITS) {
if (flags & SHF_WRITE)
return sec_bss;
@@ -1072,9 +1089,11 @@ static int pe_section_class(Section *s)
} else {
if (0 == strcmp(name, ".reloc"))
return sec_reloc;
- if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */
- return sec_stab;
}
+ if (0 == memcmp(name, ".stab", 5))
+ return name[5] ? sec_stabstr : sec_stab;
+ if (flags & SHF_ALLOC)
+ return sec_other;
return -1;
}
@@ -1088,48 +1107,39 @@ static int pe_assign_addresses (struct pe_info *pe)
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
-
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
for (o = k = 0 ; k < sec_last; ++k) {
for (i = 1; i < pe->s1->nb_sections; ++i) {
s = pe->s1->sections[i];
- if (k == pe_section_class(s)) {
- // printf("%s %d\n", s->name, k);
- s->sh_addr = pe->imagebase;
+ if (k == pe_section_class(s))
section_order[o++] = i;
- }
}
}
- pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
+ si = NULL;
addr = pe->imagebase + 1;
- for (i = 0; i < o; ++i)
- {
+ for (i = 0; i < o; ++i) {
k = section_order[i];
s = pe->s1->sections[k];
c = pe_section_class(s);
- si = &pe->sec_info[pe->sec_count];
-#ifdef PE_MERGE_DATA
- if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
- /* append .bss to .data */
- s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
- addr += s->data_offset;
- si[-1].sh_size = addr - si[-1].sh_addr;
- continue;
- }
-#endif
- if (c == sec_stab && 0 == pe->s1->do_debug)
+ if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
continue;
- strcpy(si->name, s->name);
- si->cls = c;
- si->ord = k;
- si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
- si->sh_flags = s->sh_flags;
+#ifdef PE_MERGE_DATA
+ if (c == sec_bss)
+ c = sec_data;
+#endif
+ if (si && c == si->cls) {
+ /* merge with previous section */
+ s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
+ } else {
+ si = NULL;
+ s->sh_addr = addr = pe_virtual_align(pe, addr);
+ }
if (c == sec_data && NULL == pe->thunk)
pe->thunk = s;
@@ -1138,36 +1148,60 @@ static int pe_assign_addresses (struct pe_info *pe)
pe_build_imports(pe);
pe_build_exports(pe);
}
-
- if (c == sec_reloc)
+ if (s == pe->reloc)
pe_build_reloc (pe);
- if (s->data_offset)
- {
- if (s->sh_type != SHT_NOBITS) {
- si->data = s->data;
- si->data_size = s->data_offset;
- }
+ if (0 == s->data_offset)
+ continue;
+
+ if (si)
+ goto add_section;
+
+ si = tcc_mallocz(sizeof *si);
+ dynarray_add(&pe->sec_info, &pe->sec_count, si);
+
+ strcpy(si->name, s->name);
+ si->cls = c;
+ si->sh_addr = addr;
- addr += s->data_offset;
- si->sh_size = s->data_offset;
- ++pe->sec_count;
+ si->pe_flags = IMAGE_SCN_MEM_READ;
+ if (s->sh_flags & SHF_EXECINSTR)
+ si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
+ else if (s->sh_type == SHT_NOBITS)
+ si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ else
+ si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+ if (s->sh_flags & SHF_WRITE)
+ si->pe_flags |= IMAGE_SCN_MEM_WRITE;
+ if (0 == (s->sh_flags & SHF_ALLOC))
+ si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
+
+add_section:
+ addr += s->data_offset;
+ si->sh_size = addr - si->sh_addr;
+ if (s->sh_type != SHT_NOBITS) {
+ Section **ps = &si->sec;
+ while (*ps)
+ ps = &(*ps)->prev;
+ *ps = s, s->prev = NULL;
+ si->data_size = si->sh_size;
}
- // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name);
+ //printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
}
-
+ tcc_free(section_order);
#if 0
for (i = 1; i < pe->s1->nb_sections; ++i) {
Section *s = pe->s1->sections[i];
int type = s->sh_type;
int flags = s->sh_flags;
- printf("section %-16s %-10s %5x %s,%s,%s\n",
+ printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
s->name,
type == SHT_PROGBITS ? "progbits" :
type == SHT_NOBITS ? "nobits" :
type == SHT_SYMTAB ? "symtab" :
type == SHT_STRTAB ? "strtab" :
type == SHT_RELX ? "rel" : "???",
+ s->sh_addr,
s->data_offset,
flags & SHF_ALLOC ? "alloc" : "",
flags & SHF_WRITE ? "write" : "",
@@ -1176,14 +1210,12 @@ static int pe_assign_addresses (struct pe_info *pe)
}
pe->s1->verbose = 2;
#endif
-
- tcc_free(section_order);
return 0;
}
/*----------------------------------------------------------------------------*/
-static int pe_isafunc(int sym_index)
+static int pe_isafunc(TCCState *s1, int sym_index)
{
Section *sr = text_section->reloc;
ElfW_Rel *rel, *rel_end;
@@ -1203,6 +1235,7 @@ static int pe_check_symbols(struct pe_info *pe)
ElfW(Sym) *sym;
int sym_index, sym_end;
int ret = 0;
+ TCCState *s1 = pe->s1;
pe_align_section(text_section, 8);
@@ -1222,7 +1255,7 @@ static int pe_check_symbols(struct pe_info *pe)
if (type == STT_NOTYPE) {
/* symbols from assembler have no type, find out which */
- if (pe_isafunc(sym_index))
+ if (pe_isafunc(s1, sym_index))
type = STT_FUNC;
else
type = STT_OBJECT;
@@ -1747,7 +1780,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
ret = pe_load_def(s1, fd);
else if (pe_load_res(s1, fd) == 0)
ret = 0;
- else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4))
+ else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2))
ret = pe_load_dll(s1, filename);
return ret;
}
@@ -1757,7 +1790,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
static unsigned pe_add_uwwind_info(TCCState *s1)
{
if (NULL == s1->uw_pdata) {
- s1->uw_pdata = find_section(tcc_state, ".pdata");
+ s1->uw_pdata = find_section(s1, ".pdata");
s1->uw_pdata->sh_addralign = 4;
}
if (0 == s1->uw_sym)
@@ -1820,6 +1853,12 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
#define PE_STDSYM(n,s) "_" n s
#endif
+static void tcc_add_support(TCCState *s1, const char *filename)
+{
+ if (tcc_add_dll(s1, filename, 0) < 0)
+ tcc_error_noabort("%s not found", filename);
+}
+
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{
const char *start_symbol;
@@ -1836,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
else
if (TCC_OUTPUT_DLL == s1->output_type) {
pe_type = PE_DLL;
- /* need this for 'tccelf.c:relocate_section()' */
- s1->output_type = TCC_OUTPUT_EXE;
}
else {
pe_type = PE_EXE;
@@ -1854,41 +1891,53 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
: (unicode_entry ? "__wstart" : "__start")
;
+ pe->start_symbol = start_symbol + 1;
if (!s1->leading_underscore || strchr(start_symbol, '@'))
++start_symbol;
- /* grab the startup code from libtcc1 */
+#ifdef CONFIG_TCC_BACKTRACE
+ if (s1->do_backtrace) {
+#ifdef CONFIG_TCC_BCHECK
+ if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
+ tcc_add_support(s1, "bcheck.o");
+#endif
+ if (s1->output_type == TCC_OUTPUT_EXE)
+ tcc_add_support(s1, "bt-exe.o");
+ if (s1->output_type == TCC_OUTPUT_DLL)
+ tcc_add_support(s1, "bt-dll.o");
+ if (s1->output_type != TCC_OUTPUT_DLL)
+ tcc_add_support(s1, "bt-log.o");
+ if (s1->output_type != TCC_OUTPUT_MEMORY)
+ tcc_add_btstub(s1);
+ }
+#endif
+
+ /* grab the startup code from libtcc1.a */
#ifdef TCC_IS_NATIVE
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
#endif
- set_elf_sym(symtab_section,
- 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- SHN_UNDEF, start_symbol);
-
- tcc_add_pragma_libs(s1);
+ set_global_sym(s1, start_symbol, NULL, 0);
if (0 == s1->nostdlib) {
static const char *libs[] = {
- TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
+ "msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
+ tcc_add_support(s1, TCC_LIBTCC1);
for (pp = libs; 0 != (p = *pp); ++pp) {
- if (0 == *p) {
- if (PE_DLL != pe_type && PE_GUI != pe_type)
- break;
- } else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
- continue;
- } else {
+ if (*p)
tcc_add_library_err(s1, p);
- }
+ else if (PE_DLL != pe_type && PE_GUI != pe_type)
+ break;
}
}
+ /* need this for 'tccelf.c:relocate_section()' */
+ if (TCC_OUTPUT_DLL == s1->output_type)
+ s1->output_type = TCC_OUTPUT_EXE;
if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN;
pe->type = pe_type;
- pe->start_symbol = start_symbol;
}
static void pe_set_options(TCCState * s1, struct pe_info *pe)
@@ -1947,8 +1996,12 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
memset(&pe, 0, sizeof pe);
pe.filename = filename;
pe.s1 = s1;
+ s1->filetype = 0;
+#ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1);
+#endif
+ tcc_add_pragma_libs(s1);
pe_add_runtime(s1, &pe);
resolve_common_syms(s1);
pe_set_options(s1, &pe);
@@ -1967,13 +2020,12 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
}
}
pe.start_addr = (DWORD)
- ((uintptr_t)tcc_get_symbol_err(s1, pe.start_symbol)
- - pe.imagebase);
+ (get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase);
if (s1->nb_errors)
ret = -1;
else
ret = pe_write(&pe);
- tcc_free(pe.sec_info);
+ dynarray_reset(&pe.sec_info, &pe.sec_count);
} else {
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;
diff --git a/tccpp.c b/tccpp.c
index 76f9e42..daf5d92 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define USING_GLOBALS
#include "tcc.h"
/********************************************************/
@@ -33,8 +34,6 @@ ST_DATA const int *macro_ptr;
ST_DATA CString tokcstr; /* current parsed string, if any */
/* display benchmark infos */
-ST_DATA int total_lines;
-ST_DATA int total_bytes;
ST_DATA int tok_ident;
ST_DATA TokenSym **table_ident;
@@ -54,7 +53,6 @@ static void tok_print(const char *msg, const int *str);
static struct TinyAlloc *toksym_alloc;
static struct TinyAlloc *tokstr_alloc;
-static struct TinyAlloc *cstr_alloc;
static TokenString *macro_stack;
@@ -94,7 +92,7 @@ static const unsigned char tok_two_chars[] =
0
};
-static void next_nomacro_spc(void);
+static void next_nomacro(void);
ST_FUNC void skip(int c)
{
@@ -250,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
tail_call:
is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
if ((!p || is_own) && size <= al->limit) {
- if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
+ if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {
header = (tal_header_t *)al->p;
header->size = adj_size;
#ifdef TAL_DEBUG
@@ -263,7 +261,7 @@ tail_call:
al->p += adj_size + sizeof(tal_header_t);
if (is_own) {
header = (((tal_header_t *)p) - 1);
- memcpy(ret, p, header->size);
+ if (p) memcpy(ret, p, header->size);
#ifdef TAL_DEBUG
header->line_num = -header->line_num;
#endif
@@ -282,7 +280,7 @@ tail_call:
al->nb_allocs--;
ret = tal_realloc(*pal, 0, size);
header = (((tal_header_t *)p) - 1);
- memcpy(ret, p, header->size);
+ if (p) memcpy(ret, p, header->size);
#ifdef TAL_DEBUG
header->line_num = -header->line_num;
#endif
@@ -303,7 +301,7 @@ tail_call:
al->nb_allocs--;
ret = tcc_malloc(size);
header = (((tal_header_t *)p) - 1);
- memcpy(ret, p, header->size);
+ if (p) memcpy(ret, p, header->size);
#ifdef TAL_DEBUG
header->line_num = -header->line_num;
#endif
@@ -331,7 +329,7 @@ static void cstr_realloc(CString *cstr, int new_size)
size = 8; /* no need to allocate a too small first string */
while (size < new_size)
size = size * 2;
- cstr->data = tal_realloc(cstr_alloc, cstr->data, size);
+ cstr->data = tcc_realloc(cstr->data, size);
cstr->size_allocated = size;
}
@@ -377,7 +375,7 @@ ST_FUNC void cstr_new(CString *cstr)
/* free string and reset it to NULL */
ST_FUNC void cstr_free(CString *cstr)
{
- tal_free(cstr_alloc, cstr->data);
+ tcc_free(cstr->data);
cstr_new(cstr);
}
@@ -387,6 +385,24 @@ ST_FUNC void cstr_reset(CString *cstr)
cstr->size = 0;
}
+ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
+{
+ va_list v;
+ int len, size;
+
+ va_start(v, fmt);
+ len = vsnprintf(NULL, 0, fmt, v);
+ va_end(v);
+ size = cstr->size + len + 1;
+ if (size > cstr->size_allocated)
+ cstr_realloc(cstr, size);
+ va_start(v, fmt);
+ vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
+ va_end(v);
+ cstr->size += len;
+ return len;
+}
+
/* XXX: unicode ? */
static void add_char(CString *cstr, int c)
{
@@ -584,7 +600,7 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
/* return the current character, handling end of block if necessary
(but not stray) */
-ST_FUNC int handle_eob(void)
+static int handle_eob(void)
{
BufferedFile *bf = file;
int len;
@@ -617,7 +633,7 @@ ST_FUNC int handle_eob(void)
}
/* read next char from current input file and handle end of input buffer */
-ST_INLN void inp(void)
+static inline void inp(void)
{
ch = *(++(file->buf_ptr));
/* end of buffer/file handling */
@@ -703,7 +719,7 @@ static int handle_stray1(uint8_t *p)
/* input with '\[\r]\n' handling. Note that this function cannot
handle other characters after '\', so you cannot call it inside
strings or comments */
-ST_FUNC void minp(void)
+static void minp(void)
{
inp();
if (ch == '\\')
@@ -748,7 +764,7 @@ static uint8_t *parse_line_comment(uint8_t *p)
}
/* C comments */
-ST_FUNC uint8_t *parse_comment(uint8_t *p)
+static uint8_t *parse_comment(uint8_t *p)
{
int c;
@@ -1119,9 +1135,9 @@ ST_FUNC void end_macro(void)
macro_stack = str->prev;
macro_ptr = str->prev_ptr;
file->line_num = str->save_line_num;
- if (str->alloc == 2) {
- str->alloc = 3; /* just mark as finished */
- } else {
+ if (str->alloc != 0) {
+ if (str->alloc == 2)
+ str->str = NULL; /* don't free */
tok_str_free(str);
}
}
@@ -1213,9 +1229,8 @@ ST_FUNC void tok_str_add_tok(TokenString *s)
tok_str_add2(s, tok, &tokc);
}
-/* get a token from an integer array and increment pointer
- accordingly. we code it as a macro to avoid pointer aliasing. */
-static inline void TOK_GET(int *t, const int **pp, CValue *cv)
+/* get a token from an integer array and increment pointer. */
+static inline void tok_get(int *t, const int **pp, CValue *cv)
{
const int *p = *pp;
int n, *tab;
@@ -1278,6 +1293,18 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
*pp = p;
}
+#if 0
+# define TOK_GET(t,p,c) tok_get(t,p,c)
+#else
+# define TOK_GET(t,p,c) do { \
+ int _t = **(p); \
+ if (TOK_HAS_VALUE(_t)) \
+ tok_get(t, p, c); \
+ else \
+ *(t) = _t, ++*(p); \
+ } while (0)
+#endif
+
static int macro_is_equal(const int *a, const int *b)
{
CValue cv;
@@ -1339,18 +1366,6 @@ ST_FUNC void free_defines(Sym *b)
define_undef(top);
sym_free(top);
}
-
- /* restore remaining (-D or predefined) symbols if they were
- #undef'd in the file */
- while (b) {
- int v = b->v;
- if (v >= TOK_IDENT && v < tok_ident) {
- Sym **d = &table_ident[v - TOK_IDENT]->sym_define;
- if (!*d)
- *d = b;
- }
- b = b->prev;
- }
}
/* label lookup */
@@ -1399,9 +1414,12 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
}
}
/* remove label */
- table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
+ if (s->r != LABEL_GONE)
+ table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
if (!keep)
sym_free(s);
+ else
+ s->r = LABEL_GONE;
}
if (!keep)
*ptop = slast;
@@ -1418,7 +1436,7 @@ static void maybe_run_test(TCCState *s)
return;
if (0 != --s->run_test)
return;
- fprintf(s->ppfp, "\n[%s]\n" + !(s->dflag & 32), p), fflush(s->ppfp);
+ fprintf(s->ppfp, &"\n[%s]\n"[!(s->dflag & 32)], p), fflush(s->ppfp);
define_push(tok, MACRO_OBJ, NULL, NULL);
}
@@ -1432,6 +1450,7 @@ static int expr_preprocess(void)
pp_expr = 1;
while (tok != TOK_LINEFEED && tok != TOK_EOF) {
next(); /* do macro subst */
+ redo:
if (tok == TOK_DEFINED) {
next_nomacro();
t = tok;
@@ -1449,10 +1468,26 @@ static int expr_preprocess(void)
}
tok = TOK_CINT;
tokc.i = c;
+ } else if (1 && tok == TOK___HAS_INCLUDE) {
+ next(); /* XXX check if correct to use expansion */
+ skip('(');
+ while (tok != ')' && tok != TOK_EOF)
+ next();
+ if (tok != ')')
+ expect("')'");
+ tok = TOK_CINT;
+ tokc.i = 0;
} else if (tok >= TOK_IDENT) {
- /* if undefined macro */
+ /* if undefined macro, replace with zero, check for func-like */
+ t = tok;
tok = TOK_CINT;
tokc.i = 0;
+ tok_str_add_tok(str);
+ next();
+ if (tok == '(')
+ tcc_error("function-like macro '%s' is not defined",
+ get_tok_str(t, NULL));
+ goto redo;
}
tok_str_add_tok(str);
}
@@ -1487,7 +1522,8 @@ ST_FUNC void parse_define(void)
character. */
parse_flags = ((parse_flags & ~PARSE_FLAG_ASM_FILE) | PARSE_FLAG_SPACES);
/* '(' must be just after macro definition for MACRO_FUNC */
- next_nomacro_spc();
+ next_nomacro();
+ parse_flags &= ~PARSE_FLAG_SPACES;
if (tok == '(') {
int dotid = set_idnum('.', 0);
next_nomacro();
@@ -1515,7 +1551,8 @@ ST_FUNC void parse_define(void)
goto bad_list;
next_nomacro();
}
- next_nomacro_spc();
+ parse_flags |= PARSE_FLAG_SPACES;
+ next_nomacro();
t = MACRO_FUNC;
set_idnum('.', dotid);
}
@@ -1544,7 +1581,7 @@ ST_FUNC void parse_define(void)
}
tok_str_add2(&tokstr_buf, tok, &tokc);
skip:
- next_nomacro_spc();
+ next_nomacro();
}
parse_flags = saved_parse_flags;
@@ -1800,9 +1837,9 @@ ST_FUNC void preprocess(int is_bof)
if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE)
tcc_error("#include recursion too deep");
- /* store current file in stack, but increment stack later below */
- *s1->include_stack_ptr = file;
- i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0;
+ /* push current file on stack */
+ *s1->include_stack_ptr++ = file;
+ i = tok == TOK_INCLUDE_NEXT ? file->include_next_index + 1 : 0;
n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths;
for (; i < n; ++i) {
char buf1[sizeof file->filename];
@@ -1845,24 +1882,29 @@ ST_FUNC void preprocess(int is_bof)
if (tcc_open(s1, buf1) < 0)
continue;
- file->include_next_index = i + 1;
+ file->include_next_index = i;
#ifdef INC_DEBUG
printf("%s: including %s\n", file->prev->filename, file->filename);
#endif
/* update target deps */
- dynarray_add(&s1->target_deps, &s1->nb_target_deps,
- tcc_strdup(buf1));
- /* push current file in stack */
- ++s1->include_stack_ptr;
+ if (s1->gen_deps) {
+ BufferedFile *bf = file;
+ while (i == 1 && (bf = bf->prev))
+ i = bf->include_next_index;
+ /* skip system include files */
+ if (n - i > s1->nb_sysinclude_paths)
+ dynarray_add(&s1->target_deps, &s1->nb_target_deps,
+ tcc_strdup(buf1));
+ }
/* add include file debug info */
- if (s1->do_debug)
- put_stabs(file->filename, N_BINCL, 0, 0, 0);
+ tcc_debug_bincl(tcc_state);
tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
ch = file->buf_ptr[0];
goto the_end;
}
tcc_error("include file '%s' not found", buf);
include_done:
+ --s1->include_stack_ptr;
break;
case TOK_IFNDEF:
c = 1;
@@ -1953,7 +1995,11 @@ include_done:
if (tok == TOK_STR) {
if (file->true_filename == file->filename)
file->true_filename = tcc_strdup(file->filename);
- pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data);
+ /* prepend directory from real file */
+ pstrcpy(buf, sizeof buf, file->true_filename);
+ *tcc_basename(buf) = 0;
+ pstrcat(buf, sizeof buf, (char *)tokc.str.data);
+ tcc_debug_putfile(s1, buf);
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
break;
else
@@ -1963,8 +2009,6 @@ include_done:
if (file->fd > 0)
total_lines += file->line_num - n;
file->line_num = n;
- if (s1->do_debug)
- put_stabs(file->filename, N_BINCL, 0, 0, 0);
break;
case TOK_ERROR:
case TOK_WARNING:
@@ -2278,7 +2322,7 @@ static void parse_number(const char *p)
q--;
ch = *p++;
b = 16;
- } else if (tcc_ext && (ch == 'b' || ch == 'B')) {
+ } else if (tcc_state->tcc_ext && (ch == 'b' || ch == 'B')) {
q--;
ch = *p++;
b = 2;
@@ -2573,6 +2617,7 @@ static inline void next_nomacro1(void)
case '\t':
tok = c;
p++;
+ maybe_space:
if (parse_flags & PARSE_FLAG_SPACES)
goto keep_tok_flags;
while (isidnum_table[*p - CH_EOF] & IS_SPC)
@@ -2621,9 +2666,7 @@ static inline void next_nomacro1(void)
}
/* add end of include file debug info */
- if (tcc_state->do_debug) {
- put_stabd(N_EINCL, 0, 0);
- }
+ tcc_debug_eincl(tcc_state);
/* pop include stack */
tcc_close();
s1->include_stack_ptr--;
@@ -2921,11 +2964,11 @@ maybe_newline:
p = parse_comment(p);
/* comments replaced by a blank */
tok = ' ';
- goto keep_tok_flags;
+ goto maybe_space;
} else if (c == '/') {
p = parse_line_comment(p);
tok = ' ';
- goto keep_tok_flags;
+ goto maybe_space;
} else if (c == '=') {
p++;
tok = TOK_A_DIV;
@@ -2967,34 +3010,6 @@ keep_tok_flags:
#endif
}
-/* return next token without macro substitution. Can read input from
- macro_ptr buffer */
-static void next_nomacro_spc(void)
-{
- if (macro_ptr) {
- redo:
- tok = *macro_ptr;
- if (tok) {
- TOK_GET(&tok, &macro_ptr, &tokc);
- if (tok == TOK_LINENUM) {
- file->line_num = tokc.i;
- goto redo;
- }
- }
- } else {
- next_nomacro1();
- }
- //printf("token = %s\n", get_tok_str(tok, &tokc));
-}
-
-ST_FUNC void next_nomacro(void)
-{
- do {
- next_nomacro_spc();
- } while (tok < 256 && (isidnum_table[tok - CH_EOF] & IS_SPC));
-}
-
-
static void macro_subst(
TokenString *tok_str,
Sym **nested_list,
@@ -3144,7 +3159,7 @@ static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
if (is_space(tok))
continue;
tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid"
- " preprocessing token", n, cstr.data, (char*)cstr.data + n);
+ " preprocessing token", n, (char *)cstr.data, (char*)cstr.data + n);
ret = 0;
break;
}
@@ -3270,7 +3285,7 @@ static int next_argstream(Sym **nested_list, TokenString *ws_str)
if (ws_str)
return t;
- next_nomacro_spc();
+ next_nomacro();
return tok;
}
}
@@ -3361,7 +3376,7 @@ static int macro_subst_tok(
}
do {
next_nomacro(); /* eat '(' */
- } while (tok == TOK_PLCHLDR);
+ } while (tok == TOK_PLCHLDR || is_space(tok));
/* argument macro */
args = NULL;
@@ -3419,8 +3434,6 @@ static int macro_subst_tok(
get_tok_str(s->v, 0));
}
- parse_flags = saved_parse_flags;
-
/* now subst each arg */
mstr = macro_arg_subst(nested_list, mstr, args);
/* free memory */
@@ -3435,6 +3448,7 @@ static int macro_subst_tok(
sym_free(sa);
sa = sa1;
}
+ parse_flags = saved_parse_flags;
}
sym_push2(nested_list, s->v, 0, 0);
@@ -3487,14 +3501,14 @@ static void macro_subst(
}
{
- TokenString str;
- str.str = (int*)macro_str;
- begin_macro(&str, 2);
+ TokenString *str = tok_str_alloc();
+ str->str = (int*)macro_str;
+ begin_macro(str, 2);
tok = t;
macro_subst_tok(tok_str, nested_list, s);
- if (str.alloc == 3) {
+ if (macro_stack != str) {
/* already finished by reading function macro arguments */
break;
}
@@ -3505,8 +3519,6 @@ static void macro_subst(
if (tok_str->len)
spc = is_space(t = tok_str->str[tok_str->lastlen]);
} else {
- if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
- tcc_error("stray '\\' in program");
no_subst:
if (!check_space(t, &spc))
tok_str_add2(tok_str, t, &cval);
@@ -3525,42 +3537,74 @@ no_subst:
}
}
+/* return next token without macro substitution. Can read input from
+ macro_ptr buffer */
+static void next_nomacro(void)
+{
+ int t;
+ if (macro_ptr) {
+ redo:
+ t = *macro_ptr;
+ if (TOK_HAS_VALUE(t)) {
+ tok_get(&tok, &macro_ptr, &tokc);
+ if (t == TOK_LINENUM) {
+ file->line_num = tokc.i;
+ goto redo;
+ }
+ } else {
+ macro_ptr++;
+ if (t < TOK_IDENT) {
+ if (!(parse_flags & PARSE_FLAG_SPACES)
+ && (isidnum_table[t - CH_EOF] & IS_SPC))
+ goto redo;
+ }
+ tok = t;
+ }
+ } else {
+ next_nomacro1();
+ }
+}
+
/* return next token with macro substitution */
ST_FUNC void next(void)
{
+ int t;
redo:
- if (parse_flags & PARSE_FLAG_SPACES)
- next_nomacro_spc();
- else
- next_nomacro();
-
+ next_nomacro();
+ t = tok;
if (macro_ptr) {
- if (tok == TOK_NOSUBST || tok == TOK_PLCHLDR) {
- /* discard preprocessor markers */
- goto redo;
- } else if (tok == 0) {
- /* end of macro or unget token string */
- end_macro();
- goto redo;
+ if (!TOK_HAS_VALUE(t)) {
+ if (t == TOK_NOSUBST || t == TOK_PLCHLDR) {
+ /* discard preprocessor markers */
+ goto redo;
+ } else if (t == 0) {
+ /* end of macro or unget token string */
+ end_macro();
+ goto redo;
+ } else if (t == '\\') {
+ if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
+ tcc_error("stray '\\' in program");
+ }
+ return;
}
- } else if (tok >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) {
- Sym *s;
+ } else if (t >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) {
/* if reading from file, try to substitute macros */
- s = define_find(tok);
+ Sym *s = define_find(t);
if (s) {
Sym *nested_list = NULL;
tokstr_buf.len = 0;
macro_subst_tok(&tokstr_buf, &nested_list, s);
tok_str_add(&tokstr_buf, 0);
- begin_macro(&tokstr_buf, 2);
+ begin_macro(&tokstr_buf, 0);
goto redo;
}
+ return;
}
/* convert preprocessor tokens into C tokens */
- if (tok == TOK_PPNUM) {
+ if (t == TOK_PPNUM) {
if (parse_flags & PARSE_FLAG_TOK_NUM)
parse_number((char *)tokc.str.data);
- } else if (tok == TOK_PPSTR) {
+ } else if (t == TOK_PPSTR) {
if (parse_flags & PARSE_FLAG_TOK_STR)
parse_string((char *)tokc.str.data, tokc.str.size - 1);
}
@@ -3578,10 +3622,119 @@ ST_INLN void unget_tok(int last_tok)
tok = last_tok;
}
-ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
+static void tcc_predefs(CString *cstr)
+{
+ cstr_cat(cstr,
+
+ //"#include <tcc_predefs.h>\n"
+
+#if defined TCC_TARGET_X86_64
+#ifndef TCC_TARGET_PE
+ /* GCC compatible definition of va_list. */
+ /* This should be in sync with the declaration in our lib/libtcc1.c */
+ "typedef struct{\n"
+ "unsigned gp_offset,fp_offset;\n"
+ "union{\n"
+ "unsigned overflow_offset;\n"
+ "char*overflow_arg_area;\n"
+ "};\n"
+ "char*reg_save_area;\n"
+ "}__builtin_va_list[1];\n"
+ "void*__va_arg(__builtin_va_list ap,int arg_type,int size,int align);\n"
+ "#define __builtin_va_start(ap,last) (*(ap)=*(__builtin_va_list)((char*)__builtin_frame_address(0)-24))\n"
+ "#define __builtin_va_arg(ap,t) (*(t*)(__va_arg(ap,__builtin_va_arg_types(t),sizeof(t),__alignof__(t))))\n"
+ "#define __builtin_va_copy(dest,src) (*(dest)=*(src))\n"
+#else /* TCC_TARGET_PE */
+ "typedef char*__builtin_va_list;\n"
+ "#define __builtin_va_arg(ap,t) ((sizeof(t)>8||(sizeof(t)&(sizeof(t)-1)))?**(t**)((ap+=8)-8):*(t*)((ap+=8)-8))\n"
+#endif
+#elif defined TCC_TARGET_ARM
+ "typedef char*__builtin_va_list;\n"
+ "#define _tcc_alignof(type) ((int)&((struct{char c;type x;}*)0)->x)\n"
+ "#define _tcc_align(addr,type) (((unsigned)addr+_tcc_alignof(type)-1)&~(_tcc_alignof(type)-1))\n"
+ "#define __builtin_va_start(ap,last) (ap=((char*)&(last))+((sizeof(last)+3)&~3))\n"
+ "#define __builtin_va_arg(ap,type) (ap=(void*)((_tcc_align(ap,type)+sizeof(type)+3)&~3),*(type*)(ap-((sizeof(type)+3)&~3)))\n"
+#elif defined TCC_TARGET_ARM64
+ "typedef struct{\n"
+ "void*__stack,*__gr_top,*__vr_top;\n"
+ "int __gr_offs,__vr_offs;\n"
+ "}__builtin_va_list;\n"
+#elif defined TCC_TARGET_RISCV64
+ "typedef char*__builtin_va_list;\n"
+ "#define __va_reg_size (__riscv_xlen>>3)\n"
+ "#define _tcc_align(addr,type) (((unsigned long)addr+__alignof__(type)-1)&-(__alignof__(type)))\n"
+ "#define __builtin_va_arg(ap,type) (*(sizeof(type)>(2*__va_reg_size)?*(type**)((ap+=__va_reg_size)-__va_reg_size):(ap=(va_list)(_tcc_align(ap,type)+(sizeof(type)+__va_reg_size-1)&-__va_reg_size),(type*)(ap-((sizeof(type)+__va_reg_size-1)&-__va_reg_size)))))\n"
+#else /* TCC_TARGET_I386 */
+ "typedef char*__builtin_va_list;\n"
+ "#define __builtin_va_start(ap,last) (ap=((char*)&(last))+((sizeof(last)+3)&~3))\n"
+ "#define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3)))\n"
+#endif
+ "#define __builtin_va_end(ap) (void)(ap)\n"
+ "#ifndef __builtin_va_copy\n"
+ "#define __builtin_va_copy(dest,src) (dest)=(src)\n"
+ "#endif\n"
+ /* TCC BBUILTIN AND BOUNDS ALIASES */
+ "#ifdef __BOUNDS_CHECKING_ON\n"
+ "#define __BUILTINBC(ret,name,params) ret __builtin_##name params __attribute__((alias(\"__bound_\"#name)));\n"
+ "#define __BOUND(ret,name,params) ret name params __attribute__((alias(\"__bound_\"#name)));\n"
+ "#else\n"
+ "#define __BUILTINBC(ret,name,params) ret __builtin_##name params __attribute__((alias(#name)));\n"
+ "#define __BOUND(ret,name,params)\n"
+ "#endif\n"
+ "#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)\n"
+ "#define __BUILTIN(ret,name,params) ret __builtin_##name params __attribute__((alias(\"\"#name)));\n"
+ "__BOTH(void*,memcpy,(void*,const void*,__SIZE_TYPE__))\n"
+ "__BOTH(void*,memmove,(void*,const void*,__SIZE_TYPE__))\n"
+ "__BOTH(void*,memset,(void*,int,__SIZE_TYPE__))\n"
+ "__BOTH(int,memcmp,(const void*,const void*,__SIZE_TYPE__))\n"
+ "__BOTH(__SIZE_TYPE__,strlen,(const char*))\n"
+ "__BOTH(char*,strcpy,(char*,const char*))\n"
+ "__BOTH(char*,strncpy,(char*,const char*,__SIZE_TYPE__))\n"
+ "__BOTH(int,strcmp,(const char*,const char*))\n"
+ "__BOTH(int,strncmp,(const char*,const char*,__SIZE_TYPE__))\n"
+ "__BOTH(char*,strcat,(char*,const char*))\n"
+ "__BOTH(char*,strchr,(const char*,int))\n"
+ "__BOTH(char*,strdup,(const char*))\n"
+#ifdef TCC_TARGET_PE
+ "#define __MAYBE_REDIR __BOTH\n"
+#else // HAVE MALLOC_REDIR
+ "#define __MAYBE_REDIR __BUILTIN\n"
+#endif
+ "__MAYBE_REDIR(void*,malloc,(__SIZE_TYPE__))\n"
+ "__MAYBE_REDIR(void*,realloc,(void*,__SIZE_TYPE__))\n"
+ "__MAYBE_REDIR(void*,calloc,(__SIZE_TYPE__,__SIZE_TYPE__))\n"
+ "__MAYBE_REDIR(void*,memalign,(__SIZE_TYPE__,__SIZE_TYPE__))\n"
+ "__MAYBE_REDIR(void,free,(void*))\n"
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
+ "__BOTH(void*,alloca,(__SIZE_TYPE__))\n"
+#endif
+#if defined(TCC_TARGET_ARM) && defined(TCC_ARM_EABI)
+ "__BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__))\n"
+ "__BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__))\n"
+ "__BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__))\n"
+ "__BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__))\n"
+ "__BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__))\n"
+#endif
+ "__BUILTIN(void,abort,(void))\n"
+ "__BOUND(int,longjmp,())\n"
+#ifndef TCC_TARGET_PE
+ "__BOUND(void*,mmap,())\n"
+ "__BOUND(void*,munmap,())\n"
+#endif
+ "#undef __BUILTINBC\n"
+ "#undef __BUILTIN\n"
+ "#undef __BOUND\n"
+ "#undef __BOTH\n"
+ "#undef __MAYBE_REDIR\n"
+ , -1);
+}
+
+ST_FUNC void preprocess_start(TCCState *s1, int filetype)
{
+ int is_asm = !!(filetype & (AFF_TYPE_ASM|AFF_TYPE_ASMPP));
CString cstr;
- int i;
+
+ tccpp_new(s1);
s1->include_stack_ptr = s1->include_stack;
s1->ifdef_stack_ptr = s1->ifdef_stack;
@@ -3590,34 +3743,31 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
pp_counter = 0;
pp_debug_tok = pp_debug_symv = 0;
pp_once++;
- pvtop = vtop = vstack - 1;
s1->pack_stack[0] = 0;
s1->pack_stack_ptr = s1->pack_stack;
- set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0);
+ set_idnum('$', !is_asm && s1->dollars_in_identifiers ? IS_ID : 0);
set_idnum('.', is_asm ? IS_ID : 0);
- cstr_new(&cstr);
- cstr_cat(&cstr, "\"", -1);
- cstr_cat(&cstr, file->filename, -1);
- cstr_cat(&cstr, "\"", 0);
- tcc_define_symbol(s1, "__BASE_FILE__", cstr.data);
-
- cstr_reset(&cstr);
- for (i = 0; i < s1->nb_cmd_include_files; i++) {
- cstr_cat(&cstr, "#include \"", -1);
- cstr_cat(&cstr, s1->cmd_include_files[i], -1);
- cstr_cat(&cstr, "\"\n", -1);
- }
- if (cstr.size) {
+ if (!(filetype & AFF_TYPE_ASM)) {
+ cstr_new(&cstr);
+ if (s1->cmdline_defs.size)
+ cstr_cat(&cstr, s1->cmdline_defs.data, s1->cmdline_defs.size);
+ cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
+ if (is_asm)
+ cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
+ if (s1->output_type == TCC_OUTPUT_MEMORY)
+ cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
+ if (!is_asm && s1->output_type != TCC_OUTPUT_PREPROCESS)
+ tcc_predefs(&cstr);
+ if (s1->cmdline_incl.size)
+ cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
+ //printf("%s\n", (char*)cstr.data);
*s1->include_stack_ptr++ = file;
- tcc_open_bf(s1, "<command line>", cstr.size);
- memcpy(file->buffer, cstr.data, cstr.size);
+ tcc_open_bf(s1, "<command line>", cstr.size);
+ memcpy(file->buffer, cstr.data, cstr.size);
+ cstr_free(&cstr);
}
- cstr_free(&cstr);
-
- if (is_asm)
- tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
@@ -3629,6 +3779,9 @@ ST_FUNC void preprocess_end(TCCState *s1)
while (macro_stack)
end_macro();
macro_ptr = NULL;
+ while (file)
+ tcc_close();
+ tccpp_delete(s1);
}
ST_FUNC void tccpp_new(TCCState *s)
@@ -3636,10 +3789,6 @@ ST_FUNC void tccpp_new(TCCState *s)
int i, c;
const char *p, *r;
- /* might be used in error() before preprocess_start() */
- s->include_stack_ptr = s->include_stack;
- s->ppfp = stdout;
-
/* init isid table */
for(i = CH_EOF; i<128; i++)
set_idnum(i,
@@ -3654,14 +3803,15 @@ ST_FUNC void tccpp_new(TCCState *s)
/* init allocators */
tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
- tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
+ memset(s->cached_includes_hash, 0, sizeof s->cached_includes_hash);
+
cstr_new(&cstr_buf);
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
tok_str_new(&tokstr_buf);
tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
-
+
tok_ident = TOK_IDENT;
p = tcc_keywords;
while (*p) {
@@ -3674,17 +3824,26 @@ ST_FUNC void tccpp_new(TCCState *s)
tok_alloc(p, r - p - 1);
p = r;
}
+
+ /* we add dummy defines for some special macros to speed up tests
+ and to have working defined() */
+ define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
+ define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
+ define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
+ define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
+ define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
}
ST_FUNC void tccpp_delete(TCCState *s)
{
int i, n;
- /* free -D and compiler defines */
- free_defines(NULL);
+ dynarray_reset(&s->cached_includes, &s->nb_cached_includes);
/* free tokens */
n = tok_ident - TOK_IDENT;
+ if (n > total_idents)
+ total_idents = n;
for(i = 0; i < n; i++)
tal_free(toksym_alloc, table_ident[i]);
tcc_free(table_ident);
@@ -3701,8 +3860,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
toksym_alloc = NULL;
tal_delete(tokstr_alloc);
tokstr_alloc = NULL;
- tal_delete(cstr_alloc);
- cstr_alloc = NULL;
}
/* ------------------------------------------------------------------------- */
@@ -3720,7 +3877,7 @@ static void tok_print(const char *msg, const int *str)
TOK_GET(&t, &str, &cval);
if (!t)
break;
- fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1;
+ fprintf(fp, &" %s"[s], get_tok_str(t, &cval)), s = 1;
}
fprintf(fp, "\n");
}
@@ -3847,19 +4004,21 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_P10)
parse_flags |= PARSE_FLAG_TOK_NUM, s1->Pflag = 1;
-#ifdef PP_BENCH
- /* for PP benchmarks */
- do next(); while (tok != TOK_EOF);
- return 0;
-#endif
+ if (s1->do_bench) {
+ /* for PP benchmarks */
+ do next(); while (tok != TOK_EOF);
+ return 0;
+ }
if (s1->dflag & 1) {
pp_debug_builtins(s1);
s1->dflag &= ~1;
}
- token_seen = TOK_LINEFEED, spcs = 0;
- pp_line(s1, file, 0);
+ token_seen = TOK_LINEFEED, spcs = 0, level = 0;
+ if (file->prev)
+ pp_line(s1, file->prev, level++);
+ pp_line(s1, file, level);
for (;;) {
iptr = s1->include_stack_ptr;
next();
diff --git a/tccrun.c b/tccrun.c
index 9360164..17f1eeb 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -23,28 +23,39 @@
/* only native compiler supports -run */
#ifdef TCC_IS_NATIVE
-#ifndef _WIN32
-# include <sys/mman.h>
-#endif
-
#ifdef CONFIG_TCC_BACKTRACE
-# ifndef _WIN32
-# include <signal.h>
-# ifndef __OpenBSD__
-# include <sys/ucontext.h>
-# endif
-# else
-# define ucontext_t CONTEXT
-# endif
-ST_DATA int rt_num_callers = 6;
-ST_DATA const char **rt_bound_error_msg;
-ST_DATA void *rt_prog_main;
-static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
-static void rt_error(ucontext_t *uc, const char *fmt, ...);
+typedef struct rt_context
+{
+ /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
+ Stab_Sym *stab_sym, *stab_sym_end;
+ char *stab_str;
+ ElfW(Sym) *esym_start, *esym_end;
+ char *elf_str;
+ addr_t prog_base;
+ void *bounds_start;
+ struct rt_context *next;
+ /* <-- */
+ int num_callers;
+ addr_t ip, fp, sp;
+ void *top_func;
+ jmp_buf jmp_buf;
+ char do_jmp;
+} rt_context;
+
+static rt_context g_rtctxt;
static void set_exception_handler(void);
+static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
+static void rt_exit(int code);
+#endif /* CONFIG_TCC_BACKTRACE */
+
+/* defined when included from lib/bt-exe.c */
+#ifndef CONFIG_TCC_BACKTRACE_ONLY
+
+#ifndef _WIN32
+# include <sys/mman.h>
#endif
-static void set_pages_executable(void *ptr, unsigned long length);
+static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
#ifdef _WIN64
@@ -84,6 +95,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
ptr_diff = (char*)prx - (char*)ptr;
+ close(fd);
}
#else
ptr = tcc_malloc(size);
@@ -112,66 +124,91 @@ ST_FUNC void tcc_run_free(TCCState *s1)
tcc_free(s1->runtime_mem);
}
+static void run_cdtors(TCCState *s1, const char *start, const char *end,
+ int argc, char **argv, char **envp)
+{
+ void **a = (void **)get_sym_addr(s1, start, 0, 0);
+ void **b = (void **)get_sym_addr(s1, end, 0, 0);
+ while (a != b)
+ ((void(*)(int, char **, char **))*a++)(argc, argv, envp);
+}
+
/* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
- int (*prog_main)(int, char **);
+ int (*prog_main)(int, char **, char **), ret;
+#ifdef CONFIG_TCC_BACKTRACE
+ rt_context *rc = &g_rtctxt;
+#endif
+# if defined(__APPLE__)
+ char **envp = NULL;
+#else
+ char **envp = environ;
+#endif
- s1->runtime_main = "main";
- if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
+ s1->runtime_main = s1->nostdlib ? "_start" : "main";
+ if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->runtime_main, 0, 1))
return 0;
+#ifdef CONFIG_TCC_BACKTRACE
+ if (s1->do_debug)
+ tcc_add_symbol(s1, "exit", rt_exit);
+#endif
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1;
- prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
+ prog_main = (void*)get_sym_addr(s1, s1->runtime_main, 1, 1);
#ifdef CONFIG_TCC_BACKTRACE
+ memset(rc, 0, sizeof *rc);
if (s1->do_debug) {
+ void *p;
+ rc->stab_sym = (Stab_Sym *)stab_section->data;
+ rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
+ rc->stab_str = (char *)stab_section->link->data;
+ rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
+ rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
+ rc->elf_str = (char *)symtab_section->link->data;
+#if PTR_SIZE == 8
+ rc->prog_base = text_section->sh_addr & 0xffffffff00000000ULL;
+#endif
+ rc->top_func = tcc_get_symbol(s1, "main");
+ rc->num_callers = s1->rt_num_callers;
+ rc->do_jmp = 1;
+ if ((p = tcc_get_symbol(s1, "__rt_error")))
+ *(void**)p = _rt_error;
+#ifdef CONFIG_TCC_BCHECK
+ if (s1->do_bounds_check) {
+ if ((p = tcc_get_symbol(s1, "__bound_init")))
+ ((void(*)(void*, int))p)(bounds_section->data, 1);
+ }
+#endif
set_exception_handler();
- rt_prog_main = prog_main;
}
#endif
errno = 0; /* clean errno value */
-
-#ifdef CONFIG_TCC_BCHECK
- if (s1->do_bounds_check) {
- void (*bound_init)(void);
- void (*bound_exit)(void);
- void (*bound_new_region)(void *p, addr_t size);
- int (*bound_delete_region)(void *p);
- int i, ret;
-
- /* set error function */
- rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
- /* XXX: use .init section so that it also work in binary ? */
- bound_init = tcc_get_symbol_err(s1, "__bound_init");
- bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
- bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
- bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
-
- bound_init();
- /* mark argv area as valid */
- bound_new_region(argv, argc*sizeof(argv[0]));
- for (i=0; i<argc; ++i)
- bound_new_region(argv[i], strlen(argv[i]) + 1);
-
- ret = (*prog_main)(argc, argv);
-
- /* unmark argv area */
- for (i=0; i<argc; ++i)
- bound_delete_region(argv[i]);
- bound_delete_region(argv);
- bound_exit();
- return ret;
- }
+ fflush(stdout);
+ fflush(stderr);
+ /* These aren't C symbols, so don't need leading underscore handling. */
+ run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
+#ifdef CONFIG_TCC_BACKTRACE
+ if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf)))
#endif
- return (*prog_main)(argc, argv);
+ {
+ ret = prog_main(argc, argv, envp);
+ }
+ run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL);
+ if ((s1->dflag & 16) && ret)
+ fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
+ return ret;
}
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
+/* To avoid that x86 processors would reload cached instructions
+ each time when data is written in the near, we need to make
+ sure that code and data do not share the same 64 byte unit */
#define RUN_SECTION_ALIGNMENT 63
#else
- #define RUN_SECTION_ALIGNMENT 15
+ #define RUN_SECTION_ALIGNMENT 0
#endif
/* relocate code. Return -1 on error, required size if ptr is NULL,
@@ -179,8 +216,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
{
Section *s;
- unsigned offset, length, fill, i, k;
- addr_t mem;
+ unsigned offset, length, align, max_align, i, k, f;
+ addr_t mem, addr;
if (NULL == ptr) {
s1->nb_errors = 0;
@@ -195,48 +232,41 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
return -1;
}
- offset = 0, mem = (addr_t)ptr;
- fill = -mem & RUN_SECTION_ALIGNMENT;
+ offset = max_align = 0, mem = (addr_t)ptr;
#ifdef _WIN64
- offset += sizeof (void*);
+ offset += sizeof (void*); /* space for function_table pointer */
#endif
for (k = 0; k < 2; ++k) {
+ f = 0, addr = k ? mem : mem + ptr_diff;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
if (k != !(s->sh_flags & SHF_EXECINSTR))
continue;
- offset += fill;
- if (!mem)
- s->sh_addr = 0;
- else if (s->sh_flags & SHF_EXECINSTR)
- s->sh_addr = mem + offset + ptr_diff;
- else
- s->sh_addr = mem + offset;
+ align = s->sh_addralign - 1;
+ if (++f == 1 && align < RUN_SECTION_ALIGNMENT)
+ align = RUN_SECTION_ALIGNMENT;
+ if (max_align < align)
+ max_align = align;
+ offset += -(addr + offset) & align;
+ s->sh_addr = mem ? addr + offset : 0;
+ offset += s->data_offset;
#if 0
if (mem)
- printf("%-16s +%02lx %p %04x\n",
- s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
+ printf("%-16s %p len %04x align %2d\n",
+ s->name, (void*)s->sh_addr, (unsigned)s->data_offset, align + 1);
#endif
- offset += s->data_offset;
- fill = -(mem + offset) & 15;
}
-#if RUN_SECTION_ALIGNMENT > 15
- /* To avoid that x86 processors would reload cached instructions each time
- when data is written in the near, we need to make sure that code and data
- do not share the same 64 byte unit */
- fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
-#endif
}
/* relocate symbols */
- relocate_syms(s1, s1->symtab, 1);
+ relocate_syms(s1, s1->symtab, !(s1->nostdlib));
if (s1->nb_errors)
return -1;
if (0 == mem)
- return offset + RUN_SECTION_ALIGNMENT;
+ return offset + max_align;
#ifdef TCC_TARGET_PE
s1->pe_imagebase = mem;
@@ -248,7 +278,9 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
if (s->reloc)
relocate_section(s1, s);
}
+#if !defined(TCC_TARGET_PE) || defined(TCC_TARGET_MACHO)
relocate_plt(s1);
+#endif
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
@@ -257,14 +289,14 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
length = s->data_offset;
ptr = (void*)s->sh_addr;
if (s->sh_flags & SHF_EXECINSTR)
- ptr = (char*)ptr - ptr_diff;
+ ptr = (char*)((addr_t)ptr - ptr_diff);
if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length);
else
memcpy(ptr, s->data, length);
/* mark executable sections as executable in memory */
if (s->sh_flags & SHF_EXECINSTR)
- set_pages_executable((char*)ptr + ptr_diff, length);
+ set_pages_executable(s1, (char*)((addr_t)ptr + ptr_diff), length);
}
#ifdef _WIN64
@@ -277,7 +309,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
/* ------------------------------------------------------------- */
/* allow to run code in memory */
-static void set_pages_executable(void *ptr, unsigned long length)
+static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length)
{
#ifdef _WIN32
unsigned long old_protect;
@@ -324,218 +356,349 @@ static void win64_del_function_table(void *p)
}
}
#endif
-
+#endif //ndef CONFIG_TCC_BACKTRACE_ONLY
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
-ST_FUNC void tcc_set_num_callers(int n)
+static int rt_vprintf(const char *fmt, va_list ap)
{
- rt_num_callers = n;
+ int ret = vfprintf(stderr, fmt, ap);
+ fflush(stderr);
+ return ret;
+}
+
+static int rt_printf(const char *fmt, ...)
+{
+ va_list ap;
+ int r;
+ va_start(ap, fmt);
+ r = rt_vprintf(fmt, ap);
+ va_end(ap);
+ return r;
}
+#define INCLUDE_STACK_SIZE 32
+
/* print the position in the source file of PC value 'pc' by reading
the stabs debug information */
-static addr_t rt_printline(addr_t wanted_pc, const char *msg)
+static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
+ const char *msg, const char *skip)
{
- char func_name[128], last_func_name[128];
+ char func_name[128];
addr_t func_addr, last_pc, pc;
const char *incl_files[INCLUDE_STACK_SIZE];
- int incl_index, len, last_line_num, i;
+ int incl_index, last_incl_index, len, last_line_num, i;
const char *str, *p;
+ ElfW(Sym) *esym;
+ Stab_Sym *sym;
- Stab_Sym *stab_sym = NULL, *stab_sym_end, *sym;
- int stab_len = 0;
- char *stab_str = NULL;
-
- if (stab_section) {
- stab_len = stab_section->data_offset;
- stab_sym = (Stab_Sym *)stab_section->data;
- stab_str = (char *) stabstr_section->data;
- }
-
+next:
func_name[0] = '\0';
func_addr = 0;
incl_index = 0;
- last_func_name[0] = '\0';
last_pc = (addr_t)-1;
last_line_num = 1;
+ last_incl_index = 0;
- if (!stab_sym)
- goto no_stabs;
+ for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
+ str = rc->stab_str + sym->n_strx;
+ pc = sym->n_value;
+
+ switch(sym->n_type) {
+ case N_SLINE:
+ if (func_addr)
+ goto rel_pc;
+ case N_SO:
+ case N_SOL:
+ goto abs_pc;
+ case N_FUN:
+ if (sym->n_strx == 0) /* end of function */
+ goto rel_pc;
+ abs_pc:
+#if PTR_SIZE == 8
+ /* Stab_Sym.n_value is only 32bits */
+ pc += rc->prog_base;
+#endif
+ goto check_pc;
+ rel_pc:
+ pc += func_addr;
+ check_pc:
+ if (pc >= wanted_pc && wanted_pc >= last_pc)
+ goto found;
+ break;
+ }
- stab_sym_end = (Stab_Sym*)((char*)stab_sym + stab_len);
- for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
switch(sym->n_type) {
/* function start or end */
case N_FUN:
- if (sym->n_strx == 0) {
- /* we test if between last line and end of function */
- pc = sym->n_value + func_addr;
- if (wanted_pc >= last_pc && wanted_pc < pc)
- goto found;
- func_name[0] = '\0';
- func_addr = 0;
- } else {
- str = stab_str + sym->n_strx;
- p = strchr(str, ':');
- if (!p) {
- pstrcpy(func_name, sizeof(func_name), str);
- } else {
- len = p - str;
- if (len > sizeof(func_name) - 1)
- len = sizeof(func_name) - 1;
- memcpy(func_name, str, len);
- func_name[len] = '\0';
- }
- func_addr = sym->n_value;
- }
+ if (sym->n_strx == 0)
+ goto reset_func;
+ p = strchr(str, ':');
+ if (0 == p || (len = p - str + 1, len > sizeof func_name))
+ len = sizeof func_name;
+ pstrcpy(func_name, len, str);
+ func_addr = pc;
break;
/* line number info */
case N_SLINE:
- pc = sym->n_value + func_addr;
- if (wanted_pc >= last_pc && wanted_pc < pc)
- goto found;
last_pc = pc;
last_line_num = sym->n_desc;
- /* XXX: slow! */
- strcpy(last_func_name, func_name);
+ last_incl_index = incl_index;
break;
/* include files */
case N_BINCL:
- str = stab_str + sym->n_strx;
- add_incl:
- if (incl_index < INCLUDE_STACK_SIZE) {
+ if (incl_index < INCLUDE_STACK_SIZE)
incl_files[incl_index++] = str;
- }
break;
case N_EINCL:
if (incl_index > 1)
incl_index--;
break;
+ /* start/end of translation unit */
case N_SO:
- if (sym->n_strx == 0) {
- incl_index = 0; /* end of translation unit */
- } else {
- str = stab_str + sym->n_strx;
+ incl_index = 0;
+ if (sym->n_strx) {
/* do not add path */
len = strlen(str);
if (len > 0 && str[len - 1] != '/')
- goto add_incl;
+ incl_files[incl_index++] = str;
}
+ reset_func:
+ func_name[0] = '\0';
+ func_addr = 0;
+ last_pc = (addr_t)-1;
+ break;
+ /* alternative file name (from #line or #include directives) */
+ case N_SOL:
+ if (incl_index)
+ incl_files[incl_index-1] = str;
break;
}
}
-no_stabs:
- /* second pass: we try symtab symbols (no line number info) */
- incl_index = 0;
- if (symtab_section)
- {
- ElfW(Sym) *sym, *sym_end;
- int type;
-
- sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
- for(sym = (ElfW(Sym) *)symtab_section->data + 1;
- sym < sym_end;
- sym++) {
- type = ELFW(ST_TYPE)(sym->st_info);
- if (type == STT_FUNC || type == STT_GNU_IFUNC) {
- if (wanted_pc >= sym->st_value &&
- wanted_pc < sym->st_value + sym->st_size) {
- pstrcpy(last_func_name, sizeof(last_func_name),
- (char *) symtab_section->link->data + sym->st_name);
- func_addr = sym->st_value;
- goto found;
- }
+ func_name[0] = '\0';
+ func_addr = 0;
+ last_incl_index = 0;
+
+ /* we try symtab symbols (no line number info) */
+ for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) {
+ int type = ELFW(ST_TYPE)(esym->st_info);
+ if (type == STT_FUNC || type == STT_GNU_IFUNC) {
+ if (wanted_pc >= esym->st_value &&
+ wanted_pc < esym->st_value + esym->st_size) {
+ pstrcpy(func_name, sizeof(func_name),
+ rc->elf_str + esym->st_name);
+ func_addr = esym->st_value;
+ goto found;
}
}
}
- /* did not find any info: */
- fprintf(stderr, "%s %p ???\n", msg, (void*)wanted_pc);
- fflush(stderr);
- return 0;
- found:
- i = incl_index;
- if (i > 0)
- fprintf(stderr, "%s:%d: ", incl_files[--i], last_line_num);
- fprintf(stderr, "%s %p", msg, (void*)wanted_pc);
- if (last_func_name[0] != '\0')
- fprintf(stderr, " %s()", last_func_name);
+
+ if ((rc = rc->next))
+ goto next;
+
+found:
+ i = last_incl_index;
+ if (i > 0) {
+ str = incl_files[--i];
+ if (skip[0] && strstr(str, skip))
+ return (addr_t)-1;
+ rt_printf("%s:%d: ", str, last_line_num);
+ } else
+ rt_printf("%08llx : ", (long long)wanted_pc);
+ rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
+#if 0
if (--i >= 0) {
- fprintf(stderr, " (included from ");
+ rt_printf(" (included from ");
for (;;) {
- fprintf(stderr, "%s", incl_files[i]);
+ rt_printf("%s", incl_files[i]);
if (--i < 0)
break;
- fprintf(stderr, ", ");
+ rt_printf(", ");
}
- fprintf(stderr, ")");
+ rt_printf(")");
}
- fprintf(stderr, "\n");
- fflush(stderr);
+#endif
return func_addr;
}
-/* emit a run time error at position 'pc' */
-static void rt_error(ucontext_t *uc, const char *fmt, ...)
+static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
+
+static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
{
- va_list ap;
- addr_t pc;
- int i;
+ rt_context *rc = &g_rtctxt;
+ addr_t pc = 0;
+ char skip[100];
+ int i, level, ret, n;
+ const char *a, *b, *msg;
+
+ if (fp) {
+ /* we're called from tcc_backtrace. */
+ rc->fp = (addr_t)fp;
+ rc->ip = (addr_t)ip;
+ msg = "";
+ } else {
+ /* we're called from signal/exception handler */
+ msg = "RUNTIME ERROR: ";
+ }
- fprintf(stderr, "Runtime error: ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
+ skip[0] = 0;
+ /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
+ if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
+ memcpy(skip, a, b - a), skip[b - a] = 0;
+ fmt = b + 1;
+ }
- for(i=0;i<rt_num_callers;i++) {
- if (rt_get_caller_pc(&pc, uc, i) < 0)
+ n = rc->num_callers ? rc->num_callers : 6;
+ for (i = level = 0; level < n; i++) {
+ ret = rt_get_caller_pc(&pc, rc, i);
+ a = "%s";
+ if (ret != -1) {
+ pc = rt_printline(rc, pc, level ? "by" : "at", skip);
+ if (pc == (addr_t)-1)
+ continue;
+ a = ": %s";
+ }
+ if (level == 0) {
+ rt_printf(a, msg);
+ rt_vprintf(fmt, ap);
+ } else if (ret == -1)
break;
- pc = rt_printline(pc, i ? "by" : "at");
- if (pc == (addr_t)rt_prog_main && pc)
+ rt_printf("\n");
+ if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
break;
+ ++level;
}
+
+ rc->ip = rc->fp = 0;
+ return 0;
+}
+
+/* emit a run time error at position 'pc' */
+static int rt_error(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, fmt);
+ ret = _rt_error(0, 0, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+static void rt_exit(int code)
+{
+ rt_context *rc = &g_rtctxt;
+ if (rc->do_jmp)
+ longjmp(rc->jmp_buf, code ? code : 256);
+ exit(code);
}
/* ------------------------------------------------------------- */
+
#ifndef _WIN32
+# include <signal.h>
+# ifndef __OpenBSD__
+# include <sys/ucontext.h>
+# endif
+#else
+# define ucontext_t CONTEXT
+#endif
+/* translate from ucontext_t* to internal rt_context * */
+static void rt_getcontext(ucontext_t *uc, rt_context *rc)
+{
+#if defined _WIN64
+ rc->ip = uc->Rip;
+ rc->fp = uc->Rbp;
+ rc->sp = uc->Rsp;
+#elif defined _WIN32
+ rc->ip = uc->Eip;
+ rc->fp = uc->Ebp;
+ rc->sp = uc->Esp;
+#elif defined __i386__
+# if defined(__APPLE__)
+ rc->ip = uc->uc_mcontext->__ss.__eip;
+ rc->fp = uc->uc_mcontext->__ss.__ebp;
+# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+ rc->ip = uc->uc_mcontext.mc_eip;
+ rc->fp = uc->uc_mcontext.mc_ebp;
+# elif defined(__dietlibc__)
+ rc->ip = uc->uc_mcontext.eip;
+ rc->fp = uc->uc_mcontext.ebp;
+# elif defined(__NetBSD__)
+ rc->ip = uc->uc_mcontext.__gregs[_REG_EIP];
+ rc->fp = uc->uc_mcontext.__gregs[_REG_EBP];
+# elif defined(__OpenBSD__)
+ rc->ip = uc->sc_eip;
+ rc->fp = uc->sc_ebp;
+# elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
+ rc->ip = uc->uc_mcontext.gregs[EIP];
+ rc->fp = uc->uc_mcontext.gregs[EBP];
+# else
+ rc->ip = uc->uc_mcontext.gregs[REG_EIP];
+ rc->fp = uc->uc_mcontext.gregs[REG_EBP];
+# endif
+#elif defined(__x86_64__)
+# if defined(__APPLE__)
+ rc->ip = uc->uc_mcontext->__ss.__rip;
+ rc->fp = uc->uc_mcontext->__ss.__rbp;
+# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+ rc->ip = uc->uc_mcontext.mc_rip;
+ rc->fp = uc->uc_mcontext.mc_rbp;
+# elif defined(__NetBSD__)
+ rc->ip = uc->uc_mcontext.__gregs[_REG_RIP];
+ rc->fp = uc->uc_mcontext.__gregs[_REG_RBP];
+# else
+ rc->ip = uc->uc_mcontext.gregs[REG_RIP];
+ rc->fp = uc->uc_mcontext.gregs[REG_RBP];
+# endif
+#elif defined(__arm__)
+ rc->ip = uc->uc_mcontext.arm_pc;
+ rc->fp = uc->uc_mcontext.arm_fp;
+#elif defined(__aarch64__)
+ rc->ip = uc->uc_mcontext.pc;
+ rc->fp = uc->uc_mcontext.regs[29];
+#elif defined(__riscv)
+ rc->ip = uc->uc_mcontext.__gregs[REG_PC];
+ rc->fp = uc->uc_mcontext.__gregs[REG_S0];
+#endif
+}
+
+/* ------------------------------------------------------------- */
+#ifndef _WIN32
/* signal handler for fatal errors */
static void sig_error(int signum, siginfo_t *siginf, void *puc)
{
- ucontext_t *uc = puc;
+ rt_context *rc = &g_rtctxt;
+ rt_getcontext(puc, rc);
switch(signum) {
case SIGFPE:
switch(siginf->si_code) {
case FPE_INTDIV:
case FPE_FLTDIV:
- rt_error(uc, "division by zero");
+ rt_error("division by zero");
break;
default:
- rt_error(uc, "floating point exception");
+ rt_error("floating point exception");
break;
}
break;
case SIGBUS:
case SIGSEGV:
- if (rt_bound_error_msg && *rt_bound_error_msg)
- rt_error(uc, *rt_bound_error_msg);
- else
- rt_error(uc, "dereferencing invalid pointer");
+ rt_error("invalid memory access");
break;
case SIGILL:
- rt_error(uc, "illegal instruction");
+ rt_error("illegal instruction");
break;
case SIGABRT:
- rt_error(uc, "abort() called");
+ rt_error("abort() called");
break;
default:
- rt_error(uc, "caught signal %d", signum);
+ rt_error("caught signal %d", signum);
break;
}
- exit(255);
+ rt_exit(255);
}
#ifndef SA_SIGINFO
@@ -549,6 +712,9 @@ static void set_exception_handler(void)
/* install TCC signal handlers to print debug info on fatal
runtime errors */
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
+#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
+ sigact.sa_flags |= SA_ONSTACK;
+#endif
sigact.sa_sigaction = sig_error;
sigemptyset(&sigact.sa_mask);
sigaction(SIGFPE, &sigact, NULL);
@@ -556,239 +722,144 @@ static void set_exception_handler(void)
sigaction(SIGSEGV, &sigact, NULL);
sigaction(SIGBUS, &sigact, NULL);
sigaction(SIGABRT, &sigact, NULL);
-}
-
-/* ------------------------------------------------------------- */
-#ifdef __i386__
+#if 0//def SIGSTKSZ
+ /* This allows stack overflow to be reported instead of a SEGV */
+ {
+ stack_t ss;
+ static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16)));
-/* fix for glibc 2.1 */
-#ifndef REG_EIP
-#define REG_EIP EIP
-#define REG_EBP EBP
+ ss.ss_sp = stack;
+ ss.ss_size = SIGSTKSZ;
+ ss.ss_flags = 0;
+ sigaltstack(&ss, NULL);
+ }
#endif
+}
-/* return the PC at frame level 'level'. Return negative if not found */
-static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
+#else /* WIN32 */
+
+/* signal handler for fatal errors */
+static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
- addr_t fp;
- int i;
+ rt_context *rc = &g_rtctxt;
+ unsigned code;
+ rt_getcontext(ex_info->ContextRecord, rc);
- if (level == 0) {
-#if defined(__APPLE__)
- *paddr = uc->uc_mcontext->__ss.__eip;
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- *paddr = uc->uc_mcontext.mc_eip;
-#elif defined(__dietlibc__)
- *paddr = uc->uc_mcontext.eip;
-#elif defined(__NetBSD__)
- *paddr = uc->uc_mcontext.__gregs[_REG_EIP];
-#elif defined(__OpenBSD__)
- *paddr = uc->sc_eip;
-#else
- *paddr = uc->uc_mcontext.gregs[REG_EIP];
-#endif
- return 0;
- } else {
-#if defined(__APPLE__)
- fp = uc->uc_mcontext->__ss.__ebp;
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- fp = uc->uc_mcontext.mc_ebp;
-#elif defined(__dietlibc__)
- fp = uc->uc_mcontext.ebp;
-#elif defined(__NetBSD__)
- fp = uc->uc_mcontext.__gregs[_REG_EBP];
-#elif defined(__OpenBSD__)
- *paddr = uc->sc_ebp;
-#else
- fp = uc->uc_mcontext.gregs[REG_EBP];
-#endif
- for(i=1;i<level;i++) {
- /* XXX: check address validity with program info */
- if (fp <= 0x1000 || fp >= 0xc0000000)
- return -1;
- fp = ((addr_t *)fp)[0];
- }
- *paddr = ((addr_t *)fp)[1];
- return 0;
+ switch (code = ex_info->ExceptionRecord->ExceptionCode) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ rt_error("invalid memory access");
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ rt_error("stack overflow");
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ rt_error("division by zero");
+ break;
+ case EXCEPTION_BREAKPOINT:
+ case EXCEPTION_SINGLE_STEP:
+ rc->ip = *(addr_t*)rc->sp;
+ rt_error("breakpoint/single-step exception:");
+ return EXCEPTION_CONTINUE_SEARCH;
+ default:
+ rt_error("caught exception %08x", code);
+ break;
}
+ if (rc->do_jmp)
+ rt_exit(255);
+ return EXCEPTION_EXECUTE_HANDLER;
}
-/* ------------------------------------------------------------- */
-#elif defined(__x86_64__)
+/* Generate a stack backtrace when a CPU exception occurs. */
+static void set_exception_handler(void)
+{
+ SetUnhandledExceptionFilter(cpu_exception_handler);
+}
+
+#endif
+/* ------------------------------------------------------------- */
/* return the PC at frame level 'level'. Return negative if not found */
-static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
+#if defined(__i386__) || defined(__x86_64__)
+static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
- addr_t fp;
- int i;
-
+ addr_t ip, fp;
if (level == 0) {
- /* XXX: only support linux */
-#if defined(__APPLE__)
- *paddr = uc->uc_mcontext->__ss.__rip;
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- *paddr = uc->uc_mcontext.mc_rip;
-#elif defined(__NetBSD__)
- *paddr = uc->uc_mcontext.__gregs[_REG_RIP];
-#else
- *paddr = uc->uc_mcontext.gregs[REG_RIP];
-#endif
- return 0;
+ ip = rc->ip;
} else {
-#if defined(__APPLE__)
- fp = uc->uc_mcontext->__ss.__rbp;
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
- fp = uc->uc_mcontext.mc_rbp;
-#elif defined(__NetBSD__)
- fp = uc->uc_mcontext.__gregs[_REG_RBP];
-#else
- fp = uc->uc_mcontext.gregs[REG_RBP];
-#endif
- for(i=1;i<level;i++) {
+ ip = 0;
+ fp = rc->fp;
+ while (--level) {
/* XXX: check address validity with program info */
if (fp <= 0x1000)
- return -1;
+ break;
fp = ((addr_t *)fp)[0];
}
- *paddr = ((addr_t *)fp)[1];
- return 0;
+ if (fp > 0x1000)
+ ip = ((addr_t *)fp)[1];
}
+ if (ip <= 0x1000)
+ return -1;
+ *paddr = ip;
+ return 0;
}
-/* ------------------------------------------------------------- */
#elif defined(__arm__)
-
-/* return the PC at frame level 'level'. Return negative if not found */
-static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
- addr_t fp, sp;
- int i;
-
- if (level == 0) {
- /* XXX: only supports linux */
-#if defined(__linux__)
- *paddr = uc->uc_mcontext.arm_pc;
+ /* XXX: only supports linux */
+#if !defined(__linux__)
+ return -1;
#else
- return -1;
-#endif
- return 0;
+ if (level == 0) {
+ *paddr = rc->ip;
} else {
-#if defined(__linux__)
- fp = uc->uc_mcontext.arm_fp;
- sp = uc->uc_mcontext.arm_sp;
- if (sp < 0x1000)
- sp = 0x1000;
-#else
- return -1;
-#endif
- /* XXX: specific to tinycc stack frames */
- if (fp < sp + 12 || fp & 3)
- return -1;
- for(i = 1; i < level; i++) {
- sp = ((addr_t *)fp)[-2];
- if (sp < fp || sp - fp > 16 || sp & 3)
- return -1;
- fp = ((addr_t *)fp)[-3];
- if (fp <= sp || fp - sp < 12 || fp & 3)
- return -1;
- }
- /* XXX: check address validity with program info */
- *paddr = ((addr_t *)fp)[-1];
- return 0;
+ addr_t fp = rc->fp;
+ while (--level)
+ fp = ((addr_t *)fp)[0];
+ *paddr = ((addr_t *)fp)[2];
}
+ return 0;
+#endif
}
-/* ------------------------------------------------------------- */
#elif defined(__aarch64__)
-
-static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
- if (level < 0)
- return -1;
- else if (level == 0) {
- *paddr = uc->uc_mcontext.pc;
- return 0;
- }
- else {
- addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
- int i;
- for (i = 1; i < level; i++)
+ if (level == 0) {
+ *paddr = rc->ip;
+ } else {
+ addr_t *fp = (addr_t*)rc->fp;
+ while (--level)
fp = (addr_t *)fp[0];
*paddr = fp[1];
- return 0;
}
+ return 0;
}
-/* ------------------------------------------------------------- */
-#else
-
-#warning add arch specific rt_get_caller_pc()
-static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
+#elif defined(__riscv)
+static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
{
- return -1;
-}
-
-#endif /* !__i386__ */
-
-/* ------------------------------------------------------------- */
-#else /* WIN32 */
-
-static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
-{
- EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
- CONTEXT *uc = ex_info->ContextRecord;
- switch (er->ExceptionCode) {
- case EXCEPTION_ACCESS_VIOLATION:
- if (rt_bound_error_msg && *rt_bound_error_msg)
- rt_error(uc, *rt_bound_error_msg);
- else
- rt_error(uc, "access violation");
- break;
- case EXCEPTION_STACK_OVERFLOW:
- rt_error(uc, "stack overflow");
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- rt_error(uc, "division by zero");
- break;
- default:
- rt_error(uc, "exception caught");
- break;
+ if (level == 0) {
+ *paddr = rc->ip;
+ } else {
+ addr_t *fp = (addr_t*)rc->fp;
+ while (--level && fp >= (addr_t*)0x1000)
+ fp = (addr_t *)fp[-2];
+ if (fp < (addr_t*)0x1000)
+ return -1;
+ *paddr = fp[-1];
}
- return EXCEPTION_EXECUTE_HANDLER;
-}
-
-/* Generate a stack backtrace when a CPU exception occurs. */
-static void set_exception_handler(void)
-{
- SetUnhandledExceptionFilter(cpu_exception_handler);
+ return 0;
}
-/* return the PC at frame level 'level'. Return non zero if not found */
-static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
-{
- addr_t fp, pc;
- int i;
-#ifdef _WIN64
- pc = uc->Rip;
- fp = uc->Rbp;
#else
- pc = uc->Eip;
- fp = uc->Ebp;
-#endif
- if (level > 0) {
- for(i=1;i<level;i++) {
- /* XXX: check address validity with program info */
- if (fp <= 0x1000 || fp >= 0xc0000000)
- return -1;
- fp = ((addr_t*)fp)[0];
- }
- pc = ((addr_t*)fp)[1];
- }
- *paddr = pc;
- return 0;
+#warning add arch specific rt_get_caller_pc()
+static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
+{
+ return -1;
}
-#endif /* _WIN32 */
+#endif
#endif /* CONFIG_TCC_BACKTRACE */
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_STATIC
diff --git a/tcctok.h b/tcctok.h
index 317f64c..f465e8f 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -38,6 +38,7 @@
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
DEF(TOK_GENERIC, "_Generic")
+ DEF(TOK_STATIC_ASSERT, "_Static_assert")
DEF(TOK_FLOAT, "float")
DEF(TOK_DOUBLE, "double")
@@ -53,6 +54,8 @@
DEF(TOK_ATTRIBUTE2, "__attribute__")
DEF(TOK_ALIGNOF1, "__alignof")
DEF(TOK_ALIGNOF2, "__alignof__")
+ DEF(TOK_ALIGNOF3, "_Alignof")
+ DEF(TOK_ALIGNAS, "_Alignas")
DEF(TOK_TYPEOF1, "typeof")
DEF(TOK_TYPEOF2, "__typeof")
DEF(TOK_TYPEOF3, "__typeof__")
@@ -88,6 +91,7 @@
DEF(TOK___FUNCTION__, "__FUNCTION__")
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
DEF(TOK___COUNTER__, "__COUNTER__")
+ DEF(TOK___HAS_INCLUDE, "__has_include")
/* special identifiers */
DEF(TOK___FUNC__, "__func__")
@@ -122,6 +126,18 @@
DEF(TOK_FASTCALL3, "__fastcall__")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
+ DEF(TOK_CLEANUP1, "cleanup")
+ DEF(TOK_CLEANUP2, "__cleanup__")
+ DEF(TOK_CONSTRUCTOR1, "constructor")
+ DEF(TOK_CONSTRUCTOR2, "__constructor__")
+ DEF(TOK_DESTRUCTOR1, "destructor")
+ DEF(TOK_DESTRUCTOR2, "__destructor__")
+ DEF(TOK_ALWAYS_INLINE1, "always_inline")
+ DEF(TOK_ALWAYS_INLINE2, "__always_inline__")
+#ifdef CONFIG_TCC_BCHECK
+ DEF(TOK_NO_BOUND_CHECK1, "bound_no_checking")
+ DEF(TOK_NO_BOUND_CHECK2, "__bound_no_checking__")
+#endif
DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__")
@@ -132,8 +148,10 @@
DEF(TOK_DLLEXPORT, "dllexport")
DEF(TOK_DLLIMPORT, "dllimport")
+ DEF(TOK_NODECORATE, "nodecorate")
DEF(TOK_NORETURN1, "noreturn")
DEF(TOK_NORETURN2, "__noreturn__")
+ DEF(TOK_NORETURN3, "_Noreturn")
DEF(TOK_VISIBILITY1, "visibility")
DEF(TOK_VISIBILITY2, "__visibility__")
@@ -149,8 +167,10 @@
#elif defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
#elif defined TCC_TARGET_ARM64
- DEF(TOK___va_start, "__va_start")
- DEF(TOK___va_arg, "__va_arg")
+ DEF(TOK_builtin_va_start, "__builtin_va_start")
+ DEF(TOK_builtin_va_arg, "__builtin_va_arg")
+#elif defined TCC_TARGET_RISCV64
+ DEF(TOK_builtin_va_start, "__builtin_va_start")
#endif
/* pragma */
@@ -192,9 +212,9 @@
#if defined TCC_TARGET_ARM
# ifdef TCC_ARM_EABI
DEF(TOK_memcpy, "__aeabi_memcpy")
- DEF(TOK_memcpy4, "__aeabi_memcpy4")
- DEF(TOK_memcpy8, "__aeabi_memcpy8")
DEF(TOK_memmove, "__aeabi_memmove")
+ DEF(TOK_memmove4, "__aeabi_memmove4")
+ DEF(TOK_memmove8, "__aeabi_memmove8")
DEF(TOK_memset, "__aeabi_memset")
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
@@ -254,7 +274,7 @@
#if defined TCC_TARGET_PE
DEF(TOK___chkstk, "__chkstk")
#endif
-#ifdef TCC_TARGET_ARM64
+#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
DEF(TOK___addtf3, "__addtf3")
DEF(TOK___subtf3, "__subtf3")
@@ -292,15 +312,19 @@
DEF(TOK___bound_main_arg, "__bound_main_arg")
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
+ DEF(TOK___bound_setjmp, "__bound_setjmp")
+ DEF(TOK___bound_new_region, "__bound_new_region")
# ifdef TCC_TARGET_PE
- DEF(TOK_malloc, "malloc")
- DEF(TOK_free, "free")
- DEF(TOK_realloc, "realloc")
- DEF(TOK_memalign, "memalign")
- DEF(TOK_calloc, "calloc")
+# ifdef TCC_TARGET_X86_64
+ DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
+# endif
+# else
+ DEF(TOK_sigsetjmp, "sigsetjmp")
+ DEF(TOK___sigsetjmp, "__sigsetjmp")
+ DEF(TOK_siglongjmp, "siglongjmp")
# endif
- DEF(TOK_strlen, "strlen")
- DEF(TOK_strcpy, "strcpy")
+ DEF(TOK_setjmp, "setjmp")
+ DEF(TOK__setjmp, "_setjmp")
#endif
/* Tiny Assembler */
diff --git a/tcctools.c b/tcctools.c
index 1d4424e..7b6988c 100644
--- a/tcctools.c
+++ b/tcctools.c
@@ -430,7 +430,7 @@ the_end:
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
-ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
+ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int option)
{
tcc_error("-m%d not implemented.", option);
}
@@ -479,7 +479,7 @@ static int execvp_win32(const char *prog, char **argv)
#define execvp execvp_win32
#endif /* _WIN32 */
-ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
+ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int target)
{
char program[4096];
char *a0 = argv[0];
@@ -515,11 +515,11 @@ int _dowildcard = 1;
/* -------------------------------------------------------------- */
/* generate xxx.d file */
-ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
+ST_FUNC void gen_makedeps(TCCState *s1, const char *target, const char *filename)
{
FILE *depout;
char buf[1024];
- int i;
+ int i, k;
if (!filename) {
/* compute filename automatically: dir/file.o -> dir/file.d */
@@ -528,17 +528,21 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
filename = buf;
}
- if (s->verbose)
+ if (s1->verbose)
printf("<- %s\n", filename);
/* XXX return err codes instead of error() ? */
depout = fopen(filename, "w");
if (!depout)
tcc_error("could not open '%s'", filename);
-
- fprintf(depout, "%s: \\\n", target);
- for (i=0; i<s->nb_target_deps; ++i)
- fprintf(depout, " %s \\\n", s->target_deps[i]);
+ fprintf(depout, "%s:", target);
+ for (i = 0; i<s1->nb_target_deps; ++i) {
+ for (k = 0; k < i; ++k)
+ if (0 == strcmp(s1->target_deps[i], s1->target_deps[k]))
+ goto next;
+ fprintf(depout, " \\\n %s", s1->target_deps[i]);
+ next:;
+ }
fprintf(depout, "\n");
fclose(depout);
}
diff --git a/tests/Makefile b/tests/Makefile
index 5f6777d..0b74fbc 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -12,6 +12,7 @@ TESTS = \
hello-exe \
hello-run \
libtest \
+ libtest_mt \
test3 \
memtest \
dlltest \
@@ -22,21 +23,30 @@ TESTS = \
tests2-dir \
pp-dir
-BTESTS = test1b test3b btest
-
-# test4 -- problem with -static
+BTESTS = btest test1b
+# test4_static -- Not all relocation types are implemented yet.
# asmtest / asmtest2 -- minor differences with gcc
-# btest -- works on i386 (including win32)
-# bounds-checking is supported only on i386
-ifneq ($(ARCH),i386)
- TESTS := $(filter-out $(BTESTS),$(TESTS))
+# bounds-checking is supported on i386 and x86_64 on linux and windows
+ifeq (-$(CONFIG_musl)-, --)
+ifeq ($(ARCH),i386)
+ TESTS += $(BTESTS)
+endif
+ifeq ($(ARCH),x86_64)
+ TESTS += $(BTESTS)
+endif
+ifeq ($(ARCH),arm)
+ TESTS += $(BTESTS)
+endif
+ifeq ($(ARCH),arm64)
+ TESTS += $(BTESTS)
endif
-ifdef CONFIG_WIN32
- TESTS := $(filter-out $(BTESTS),$(TESTS))
+ifeq ($(ARCH),riscv64)
+ TESTS += $(BTESTS)
endif
-ifdef CONFIG_OSX # -run only
- TESTS := hello-run libtest tests2-dir pp-dir
+endif
+ifdef CONFIG_OSX # some don't work yet
+ TESTS := $(filter-out dlltest, $(TESTS))
endif
ifeq (,$(filter arm64 i386 x86_64,$(ARCH)))
TESTS := $(filter-out vla_test-run,$(TESTS))
@@ -47,19 +57,42 @@ endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
endif
-ifndef CONFIG_cross
- TESTS := $(filter-out cross-%,$(TESTS))
-endif
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
- PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
+ PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
+endif
+
+ifdef CONFIG_OSX
+LIBS += $(LINK_LIBTCC)
+endif
+
+
+ifeq ($(ARCH),arm)
+# tcctest refers to the alignment of functions, and with thumb mode
+# the low bit of code addresses selects the mode, so the "alignment"
+# of functions via bit masking comes out as 1. Just disable thumb.
+test.ref: CFLAGS+=-marm
+endif
+ifeq ($(ARCH),i386)
+# tcctest.c:get_asm_string uses a construct that is checked too strictly
+# by GCC in 32bit mode when PIC is enabled.
+test.ref: CFLAGS+=-fno-PIC -fno-PIE
+endif
+ifeq ($(CC_NAME),msvc)
+test.ref abitest : CC = gcc
endif
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
+ifdef CONFIG_OSX
+DUMPTCC = (set -x; $(TOP)/tcc -vv; otool -L $(TOP)/tcc; exit 1)
+else
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
+endif
-all test : clean-s $(TESTS)
+all test :
+ @$(MAKE) --no-print-directory -s clean
+ @$(MAKE) --no-print-directory -s -r $(TESTS)
hello-exe: ../examples/ex1.c
@echo ------------ $@ ------------
@@ -69,13 +102,16 @@ hello-run: ../examples/ex1.c
@echo ------------ $@ ------------
$(TCC) -run $< || $(DUMPTCC)
-libtest: libtcc_test$(EXESUF)
+libtes%: libtcc_tes%$(EXESUF)
@echo ------------ $@ ------------
- ./libtcc_test$(EXESUF) $(TCCFLAGS)
+ ./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES)
libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+libtcc_test_mt$(EXESUF): libtcc_test_mt.c $(LIBTCC)
+ $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+
%-dir:
@echo ------------ $@ ------------
$(MAKE) -k -C $*
@@ -88,22 +124,24 @@ test.ref: tcctest.c
# auto test
test1 test1b: tcctest.c test.ref
@echo ------------ $@ ------------
- $(TCC) -run $< > test.out1
- @diff -u test.ref test.out1 && echo "Auto Test OK"
+ $(TCC) $(RUN_TCC) -w -run $< > test.out1
+ @diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
# iterated test2 (compile tcc then compile tcctest.c !)
test2 test2b: tcctest.c test.ref
@echo ------------ $@ ------------
- $(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
- @diff -u test.ref test.out2 && echo "Auto Test2 OK"
+ $(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2
+ @diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3 test3b: tcctest.c test.ref
@echo ------------ $@ ------------
- $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
- @diff -u test.ref test.out3 && echo "Auto Test3 OK"
+ $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3
+ @diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
-test%b : TCCFLAGS += -b
+AUTO_TEST = Auto Test
+test%b : TCCFLAGS += -b -bt1
+test%b : AUTO_TEST = Auto Bound-Test
# binary output test
test4: tcctest.c test.ref
@@ -112,19 +150,22 @@ test4: tcctest.c test.ref
$(TCC) -c -o tcctest3.o $<
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
- @if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
+ @if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
# dynamic output
$(TCC) -o tcctest1 $<
./tcctest1 > test1.out
- @if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
+ @if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 $<
./tcctest4 > test4.out
- @if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
-# static output
+ @if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
+
+test4_static: tcctest.c test.ref
+ @echo ------------ $@ ------------
+# static output.
$(TCC) -static -o tcctest2 $<
./tcctest2 > test2.out
- @if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
+ @if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@@ -145,32 +186,30 @@ memtest:
@echo ------------ $@ ------------
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
- ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
-
+ ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
+ @echo OK
# memory and bound check auto test
-BOUNDS_OK = 1 4 8 10 14
-BOUNDS_FAIL= 2 5 7 9 11 12 13 15
+BOUNDS_OK = 1 4 8 10 14 16
+BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17 18
btest: boundtest.c
@echo ------------ $@ ------------
@for i in $(BOUNDS_OK); do \
- echo ; echo --- boundtest $$i ---; \
- if $(TCC) -b -run $< $$i ; then \
- echo succeeded as expected; \
+ if $(TCC) -b -run $< $$i >/dev/null 2>&1 ; then \
+ echo "Test $$i succeeded as expected" ; \
else\
- echo Failed positive test $$i ; exit 1 ; \
+ echo "Failed positive test $$i" ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
- echo ; echo --- boundtest $$i ---; \
- if $(TCC) -b -run $< $$i ; then \
- echo Failed negative test $$i ; exit 1 ;\
+ if $(TCC) -b -bt1 -run $< $$i >/dev/null 2>&1 ; then \
+ echo "Failed negative test $$i" ; exit 1 ;\
else\
- echo failed as expected; \
+ echo "Test $$i failed as expected" ; \
fi ;\
done ;\
- echo; echo Bound test OK
+ echo Bound test OK
# speed test
speedtest: ex2 ex3
@@ -181,6 +220,7 @@ speedtest: ex2 ex3
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
weaktest: tcctest.c test.ref
+ @echo ------------ $@ ------------
$(TCC) -c $< -o weaktest.tcc.o
$(CC) -c $< -o weaktest.gcc.o $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
objdump -t weaktest.tcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.tcc.o.txt
@@ -206,22 +246,19 @@ asmtest2: MAYBE_RUN_TCC = $(RUN_TCC)
# Check that code generated by libtcc is binary compatible with
# that generated by CC
-abitest-cc$(EXESUF): abitest.c $(LIBTCC)
+abitest-cc.exe: abitest.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
-abitest-tcc$(EXESUF): abitest.c libtcc.c
+abitest-tcc.exe: abitest.c libtcc.c
$(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS)
-ABITESTS := abitest-cc$(EXESUF)
-ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
- ABITESTS += abitest-tcc$(EXESUF)
-endif
-
-abitest: $(ABITESTS)
+abitest-% : abitest-%.exe
@echo ------------ $@ ------------
- ./abitest-cc$(EXESUF) $(TCCFLAGS)
+ ./$< $(TCCFLAGS)
+
+abitest: abitest-cc
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
- ./abitest-tcc$(EXESUF) $(TCCFLAGS)
+abitest: abitest-tcc
endif
vla_test$(EXESUF): vla_test.c
@@ -244,21 +281,18 @@ asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
@echo ------------ $@ ------------
./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1
./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2
- @diff -u asm-c-connect.out1 asm-c-connect.out2 && echo "ok"
+ @diff -u asm-c-connect.out1 asm-c-connect.out2 || (echo "error"; exit 1)
+
+TCC_YY = $(foreach T,$(TCC_X),$(if $(wildcard $(TOP)/$T-tcc$(EXESUF)),$T))
cross-test :
+ $(if $(strip $(TCC_YY)),\
+ $(MAKE) $(foreach T,$(TCC_YY),cross-$T.test) --no-print-directory,:)
+
+cross-%.test :
@echo ------------ $@ ------------
- $(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
- $(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
- $(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
- $(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
+ $(TOP)/$*-tcc$(EXESUF) -v $(TCCFLAGS-$(if $(findstring win,$*),win,unx))\
+ -c $(TOPSRC)/examples/ex3.c
# targets for development
%.bin: %.c tcc
@@ -279,11 +313,8 @@ cache: tcc_g
clean:
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc
rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234]
- rm -f asm-c-connect$(EXESUF)
- rm -f ex? tcc_g weaktest.*.txt *.def
+ rm -f asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
+ rm -f ex? tcc_g weaktest.*.txt *.def *.pdb *.obj libtcc_test_mt
@$(MAKE) -C tests2 $@
@$(MAKE) -C pp $@
-# silent clean, used before running tests
-clean-s:
- @$(MAKE) -s --no-print-directory clean
diff --git a/tests/asm-c-connect-1.c b/tests/asm-c-connect-1.c
index 8a28d78..d79270d 100644
--- a/tests/asm-c-connect-1.c
+++ b/tests/asm-c-connect-1.c
@@ -1,12 +1,19 @@
#include <stdio.h>
-#if defined _WIN32 && !defined __TINYC__
+#if (defined _WIN32 || defined __APPLE__) && (!defined __TINYC__ || defined __leading_underscore)
# define _ "_"
#else
# define _
#endif
-static int x1_c(void)
+#ifdef __clang__
+/* clang needs some help tp not throw functions away even at -O0 */
+#define __USED __attribute__((__used__))
+#else
+#define __USED
+#endif
+
+static int __USED x1_c (void)
{
printf(" x1");
return 1;
@@ -37,7 +44,7 @@ int main(int argc, char *argv[])
}
static
-int x2(void)
+int __USED x2(void)
{
printf(" x2");
return 2;
diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c
index 3440b40..e2b4b59 100644
--- a/tests/asm-c-connect-2.c
+++ b/tests/asm-c-connect-2.c
@@ -1,11 +1,18 @@
#include <stdio.h>
-#if defined _WIN32 && !defined __TINYC__
+#if (defined _WIN32 || defined __APPLE__) && (!defined __TINYC__ || defined __leading_underscore)
# define _ "_"
#else
# define _
#endif
+#ifdef __clang__
+/* clang needs some help tp not throw functions away even at -O0 */
+#define __USED __attribute__((__used__))
+#else
+#define __USED
+#endif
+
int x3(void)
{
printf(" x3");
@@ -30,7 +37,7 @@ void callx5_again(void)
asm("call "_"x6");
}
-static void x6()
+static void __USED x6()
{
printf(" x6-2");
}
diff --git a/tests/boundtest.c b/tests/boundtest.c
index 15bffb4..0d83395 100644
--- a/tests/boundtest.c
+++ b/tests/boundtest.c
@@ -50,15 +50,12 @@ int test4(void)
int i, sum = 0;
int *tab4;
- fprintf(stderr, "%s start\n", __FUNCTION__);
-
tab4 = malloc(20 * sizeof(int));
for(i=0;i<20;i++) {
sum += tab4[i];
}
free(tab4);
- fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
@@ -68,20 +65,16 @@ int test5(void)
int i, sum = 0;
int *tab4;
- fprintf(stderr, "%s start\n", __FUNCTION__);
-
tab4 = malloc(20 * sizeof(int));
for(i=0;i<21;i++) {
sum += tab4[i];
}
free(tab4);
- fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
/* error */
-/* XXX: currently: bug */
int test6(void)
{
int i, sum = 0;
@@ -176,21 +169,34 @@ int test13(void)
return strlen(tab);
}
+#if defined __i386__ || defined __x86_64__
+#define allocf(x)
+#else
+#define alloca(x) malloc(x)
+#define allocf(x) free(x)
+#endif
+
int test14(void)
{
char *p = alloca(TAB_SIZE);
+ size_t ret;
memset(p, 'a', TAB_SIZE);
p[TAB_SIZE-1] = 0;
- return strlen(p);
+ ret = strlen(p);
+ allocf(p);
+ return ret;
}
/* error */
int test15(void)
{
char *p = alloca(TAB_SIZE-1);
+ size_t ret;
memset(p, 'a', TAB_SIZE);
p[TAB_SIZE-1] = 0;
- return strlen(p);
+ ret = strlen(p);
+ allocf(p);
+ return ret;
}
/* ok */
@@ -199,16 +205,14 @@ int test16()
char *demo = "This is only a test.";
char *p;
- fprintf(stderr, "%s start\n", __FUNCTION__);
-
p = alloca(16);
strcpy(p,"12345678901234");
- printf("alloca: p is %s\n", p);
+ allocf(p);
/* Test alloca embedded in a larger expression */
- printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
+ printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
- fprintf(stderr, "%s end\n", __FUNCTION__);
+ return 0;
}
/* error */
@@ -217,16 +221,24 @@ int test17()
char *demo = "This is only a test.";
char *p;
- fprintf(stderr, "%s start\n", __FUNCTION__);
-
p = alloca(16);
strcpy(p,"12345678901234");
- printf("alloca: p is %s\n", p);
+ allocf(p);
/* Test alloca embedded in a larger expression */
- printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
+ printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
+
+ return 0;
+}
- fprintf(stderr, "%s end\n", __FUNCTION__);
+int test18(void)
+{
+ int i, sum = 0, n = TAB_SIZE;
+ int tab[n];
+ for(i=0;i<TAB_SIZE+1;i++) {
+ sum += tab[i];
+ }
+ return sum;
}
int (*table_test[])(void) = {
@@ -247,14 +259,25 @@ int (*table_test[])(void) = {
test15,
test16,
test17,
+ test18
};
int main(int argc, char **argv)
{
+ int i;
+ char *cp;
int index;
int (*ftest)(void);
int index_max = sizeof(table_test)/sizeof(table_test[0]);
+ /* check bounds checking main arg */
+ for (i = 0; i < argc; i++) {
+ cp = argv[i];
+ while (*cp) {
+ cp++;
+ }
+ }
+
if (argc < 2) {
printf(
"test TCC bound checking system\n"
diff --git a/tests/bug.c b/tests/bug.c
new file mode 100644
index 0000000..7ec4410
--- /dev/null
+++ b/tests/bug.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+void tst1(void)
+{
+ /* problem in gen_cast. Should mask unsigned types */
+ signed char c = (signed char) 0xffffffff;
+ int r = (unsigned short) c ^ (signed char) 0x99999999;
+ if (r != 0xffff0066) printf ("%x\n", r);
+}
+
+typedef struct{double x,y;}p;
+
+void tst2(int n,...)
+{
+ /* va_arg for struct double does not work on some targets */
+ int i;
+ va_list args;
+ va_start(args,n);
+ for (i = 0; i < n; i++) {
+ p v = va_arg(args,p);
+ if (v.x != 1 || v.y != 2) printf("%g %g\n", v.x, v.y);
+ }
+ va_end(args);
+}
+
+void tst3(void)
+{
+ /* Should VT_SYM be checked for TOK_builtin_constant_p */
+ int r = __builtin_constant_p("c");
+ if (r == 0) printf("%d\n",r);
+}
+
+int compile_errors(void)
+{
+#if TEST == 1
+ {
+ /* Not constant */
+ static int i = (&"Foobar"[1] - &"Foobar"[0]);
+ }
+#endif
+#if TEST == 2
+ {
+ /* Not constant */
+ struct{int c;}v;
+ static long i=((char*)&(v.c)-(char*)&v);
+ }
+#endif
+#if TEST == 3
+ {
+ /* Not constant */
+ static const short ar[] = { &&l1 - &&l1, &&l2 - &&l1 };
+ void *p = &&l1 + ar[0];
+ goto *p;
+ l1: return 1;
+ l2: return 2;
+ }
+#endif
+#if TEST == 4
+ {
+ /* Only integer allowed */
+ __builtin_return_address(0 + 1) != NULL;
+ }
+#endif
+ return 0;
+}
+
+int
+main(void)
+{
+ p v = { 1, 2};
+ tst1();
+ tst2(1, v);
+ tst3();
+}
diff --git a/tests/gcctestsuite.sh b/tests/gcctestsuite.sh
index f3cc538..2be274c 100755..100644
--- a/tests/gcctestsuite.sh
+++ b/tests/gcctestsuite.sh
@@ -1,33 +1,48 @@
#!/bin/sh
TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
-TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
-rm -f tcc.sum tcc.log
+TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
+rm -f tcc.sum tcc.fail
+nb_ok="0"
nb_failed="0"
+nb_exe_failed="0"
for src in $TESTSUITE_PATH/compile/*.c ; do
- echo $TCC -o /tmp/test.o -c $src
- $TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
+ echo $TCC -o /tmp/tst.o -c $src
+ $TCC -o /tmp/tst.o -c $src >> tcc.fail 2>&1
if [ "$?" = "0" ] ; then
- result="PASS"
+ result="PASS"
+ nb_ok=$(( $nb_ok + 1 ))
else
- result="FAIL"
- nb_failed=$(( $nb_failed + 1 ))
+ result="FAIL"
+ nb_failed=$(( $nb_failed + 1 ))
fi
echo "$result: $src" >> tcc.sum
done
for src in $TESTSUITE_PATH/execute/*.c ; do
- echo $TCC $src
- $TCC $src >> tcc.log 2>&1
+ echo $TCC $src -o /tmp/tst -lm
+ $TCC $src -o /tmp/tst -lm >> tcc.fail 2>&1
if [ "$?" = "0" ] ; then
- result="PASS"
+ result="PASS"
+ if /tmp/tst >> tcc.fail 2>&1
+ then
+ result="PASS"
+ nb_ok=$(( $nb_ok + 1 ))
+ else
+ result="FAILEXE"
+ nb_exe_failed=$(( $nb_exe_failed + 1 ))
+ fi
else
- result="FAIL"
- nb_failed=$(( $nb_failed + 1 ))
+ result="FAIL"
+ nb_failed=$(( $nb_failed + 1 ))
fi
echo "$result: $src" >> tcc.sum
done
+echo "$nb_ok test(s) ok." >> tcc.sum
+echo "$nb_ok test(s) ok."
echo "$nb_failed test(s) failed." >> tcc.sum
echo "$nb_failed test(s) failed."
+echo "$nb_exe_failed test(s) exe failed." >> tcc.sum
+echo "$nb_exe_failed test(s) exe failed."
diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c
index 480d314..d21c7fe 100644
--- a/tests/libtcc_test.c
+++ b/tests/libtcc_test.c
@@ -6,9 +6,15 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <assert.h>
#include "libtcc.h"
+void handle_error(void *opaque, const char *msg)
+{
+ fprintf(opaque, "%s\n", msg);
+}
+
/* this function is called by the generated code */
int add(int a, int b)
{
@@ -53,6 +59,14 @@ int main(int argc, char **argv)
exit(1);
}
+ assert(tcc_get_error_func(s) == NULL);
+ assert(tcc_get_error_opaque(s) == NULL);
+
+ tcc_set_error_func(s, stderr, handle_error);
+
+ assert(tcc_get_error_func(s) == handle_error);
+ assert(tcc_get_error_opaque(s) == stderr);
+
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < argc; ++i) {
char *a = argv[i];
diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c
new file mode 100644
index 0000000..b17e8de
--- /dev/null
+++ b/tests/libtcc_test_mt.c
@@ -0,0 +1,300 @@
+/*
+ * Multi-thread Test for libtcc
+ */
+
+#ifndef FIB
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "libtcc.h"
+
+#define M 20 /* number of states */
+#define F(n) (n % 20 + 2) /* fib argument */
+
+#ifdef _WIN32
+#include <windows.h>
+#define TF_TYPE(func, param) DWORD WINAPI func(void *param)
+typedef TF_TYPE(ThreadFunc, x);
+HANDLE hh[M];
+void create_thread(ThreadFunc f, int n)
+{
+ DWORD tid;
+ hh[n] = CreateThread(NULL, 0, f, (void*)(size_t)n, 0, &tid);
+}
+void wait_threads(int n)
+{
+ WaitForMultipleObjects(n, hh, TRUE, INFINITE);
+ while (n)
+ CloseHandle(hh[--n]);
+}
+void sleep_ms(unsigned n)
+{
+ Sleep(n);
+}
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#include <pthread.h>
+#define TF_TYPE(func, param) void* func(void *param)
+typedef TF_TYPE(ThreadFunc, x);
+pthread_t hh[M];
+void create_thread(ThreadFunc f, int n)
+{
+ pthread_create(&hh[n], NULL, f, (void*)(size_t)n);
+}
+void wait_threads(int n)
+{
+ while (n)
+ pthread_join(hh[--n], NULL);
+
+}
+void sleep_ms(unsigned n)
+{
+ usleep(n * 1000);
+}
+#endif
+
+void handle_error(void *opaque, const char *msg)
+{
+ fprintf(opaque, "%s\n", msg);
+}
+
+/* this function is called by the generated code */
+int add(int a, int b)
+{
+ return a + b;
+}
+
+#define _str(s) #s
+#define str(s) _str(s)
+/* as a trick, prepend #line directive for better error/warning messages */
+#define PROG(lbl) \
+ char lbl[] = "#line " str(__LINE__) " " str(__FILE__) "\n\n"
+
+PROG(my_program)
+"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
+"int add(int a, int b);\n"
+"int fib(int n)\n"
+"{\n"
+" if (n <= 2)\n"
+" return 1;\n"
+" else\n"
+" return add(fib(n-1),fib(n-2));\n"
+"}\n"
+"\n"
+"int foo(int n)\n"
+"{\n"
+" printf(\" %d\", fib(n));\n"
+" return 0;\n"
+"# warning is this the correct file:line...\n"
+"}\n";
+
+int g_argc; char **g_argv;
+
+void parse_args(TCCState *s)
+{
+ int i;
+ /* if tcclib.h and libtcc1.a are not installed, where can we find them */
+ for (i = 1; i < g_argc; ++i) {
+ char *a = g_argv[i];
+ if (a[0] == '-') {
+ if (a[1] == 'B')
+ tcc_set_lib_path(s, a+2);
+ else if (a[1] == 'I')
+ tcc_add_include_path(s, a+2);
+ else if (a[1] == 'L')
+ tcc_add_library_path(s, a+2);
+ else if (a[1] == 'D')
+ tcc_define_symbol(s, a+2, NULL);
+ }
+ }
+}
+
+TCCState *new_state(int w)
+{
+ TCCState *s = tcc_new();
+ if (!s) {
+ fprintf(stderr, __FILE__ ": could not create tcc state\n");
+ exit(1);
+ }
+ tcc_set_error_func(s, stdout, handle_error);
+ parse_args(s);
+ if (!w) tcc_set_options(s, "-w");
+ tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+ return s;
+}
+
+void *reloc_state(TCCState *s, const char *entry)
+{
+ void *func;
+ tcc_add_symbol(s, "add", add);
+ if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) {
+ fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
+ return NULL;
+ }
+ func = tcc_get_symbol(s, entry);
+ if (!func)
+ fprintf(stderr, __FILE__ ": could not get entry symbol.\n");
+ return func;
+}
+
+/* work with several states at the same time */
+int state_test(void)
+{
+ TCCState *s[M];
+ int (*func[M])(int);
+ int n;
+
+ for (n = 0; n < M + 4; ++n) {
+ unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
+ if (a < M)
+ s[a] = new_state(0);
+ if (b < M)
+ if (tcc_compile_string(s[b], my_program) == -1)
+ break;
+ if (c < M)
+ func[c] = reloc_state(s[c], "foo");
+ if (d < M && func[d])
+ func[d](F(d));
+ if (e < M)
+ tcc_delete(s[e]);
+ }
+ return 0;
+}
+
+/* simple compilation in threads */
+TF_TYPE(thread_test_simple, vn)
+{
+ TCCState *s;
+ int (*func)(int);
+ int ret;
+ int n = (size_t)vn;
+
+ s = new_state(0);
+ sleep_ms(1);
+ ret = tcc_compile_string(s, my_program);
+ sleep_ms(1);
+ if (ret >= 0) {
+ func = reloc_state(s, "foo");
+ if (func)
+ func(F(n));
+ }
+ tcc_delete(s);
+ return 0;
+}
+
+/* more complex compilation in threads */
+TF_TYPE(thread_test_complex, vn)
+{
+ TCCState *s;
+ int ret;
+ int n = (size_t)vn;
+ char *argv[30], b[10];
+ int argc = 0, i;
+
+ sprintf(b, "%d", F(n));
+
+ for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
+#if 0
+ argv[argc++] = "-run";
+ for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
+#endif
+ argv[argc++] = "-DFIB";
+ argv[argc++] = "-run";
+ argv[argc++] = __FILE__;
+ argv[argc++] = b;
+ argv[argc] = NULL;
+
+ s = new_state(1);
+ sleep_ms(2);
+ ret = tcc_add_file(s, argv[0]);
+ sleep_ms(3);
+ if (ret < 0)
+ exit(1);
+ tcc_run(s, argc, argv);
+ tcc_delete(s);
+ fflush(stdout);
+ return 0;
+}
+
+void time_tcc(int n, const char *src)
+{
+ TCCState *s;
+ int ret;
+ while (--n >= 0) {
+ s = new_state(1);
+ ret = tcc_add_file(s, src);
+ tcc_delete(s);
+ if (ret < 0)
+ exit(1);
+ }
+}
+
+static unsigned getclock_ms(void)
+{
+#ifdef _WIN32
+ return GetTickCount();
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
+#endif
+}
+
+int main(int argc, char **argv)
+{
+ int n;
+ unsigned t;
+
+ g_argc = argc;
+ g_argv = argv;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
+ return 1;
+ }
+
+#if 1
+ printf("running fib with mixed calls\n "), fflush(stdout);
+ t = getclock_ms();
+ state_test();
+ printf("\n (%u ms)\n", getclock_ms() - t);
+#endif
+#if 1
+ printf("running fib in threads\n "), fflush(stdout);
+ t = getclock_ms();
+ for (n = 0; n < M; ++n)
+ create_thread(thread_test_simple, n);
+ wait_threads(n);
+ printf("\n (%u ms)\n", getclock_ms() - t);
+#endif
+#if 1
+ printf("running tcc.c in threads to run fib\n"), fflush(stdout);
+ t = getclock_ms();
+ for (n = 0; n < M; ++n)
+ create_thread(thread_test_complex, n);
+ wait_threads(n);
+ printf("\n (%u ms)\n", getclock_ms() - t);
+#endif
+#if 1
+ printf("compiling tcc.c 10 times\n"), fflush(stdout);
+ t = getclock_ms();
+ time_tcc(10, argv[1]);
+ printf(" (%u ms)\n", getclock_ms() - t), fflush(stdout);
+#endif
+ return 0;
+}
+
+#else
+#include <tcclib.h>
+int fib(n)
+{
+ return (n <= 2) ? 1 : fib(n-1) + fib(n-2);
+}
+
+int main(int argc, char **argv)
+{
+ printf(" %d", fib(atoi(argv[1]), 2));
+ return 0;
+}
+#endif
diff --git a/tests/misc/c2str.c b/tests/misc/c2str.c
new file mode 100644
index 0000000..01d18db
--- /dev/null
+++ b/tests/misc/c2str.c
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <string.h>
+
+int isid(int c)
+{
+ return (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9')
+ || c == '_';
+}
+
+int isspc(int c)
+{
+ return c == ' ' || c == '\t';
+}
+
+int main(int argc, char **argv)
+{
+ char l[1000], *p, l2[1000], *q;
+ FILE *fp, *op;
+ int c, e, f;
+
+ if (argc < 3)
+ return 1;
+
+ fp = fopen(argv[1], "rb");
+ op = fopen(argv[2], "wb");
+ if (!fp || !op) {
+ fprintf(stderr, "c2str: file error\n");
+ return 1;
+ }
+
+ for (;;) {
+ p = l;
+ append:
+ if (fgets(p, sizeof l - (p - l), fp)) {
+ p = strchr(p, 0);
+ while (p > l && p[-1] == '\n')
+ --p;
+ *p = 0;
+ } else if (p == l)
+ break;
+ if (p > l && p[-1] == '\\') {
+ --p;
+ goto append;
+ }
+
+ if (l[0] == 0)
+ continue;
+ p = l, q = l2, f = e = 0;
+ while (*p && isspc(*p))
+ ++p, ++f;
+
+ if (f < 4) {
+ do {
+ static const char *sr[] = {
+ "__x86_64__", "TCC_TARGET_X86_64",
+ "_WIN64", "TCC_TARGET_PE",
+ "_WIN32", "TCC_TARGET_PE",
+ "__arm__", "TCC_TARGET_ARM",
+ "__aarch64__", "TCC_TARGET_ARM64",
+ "__riscv", "TCC_TARGET_RISCV64",
+ "__i386__", "TCC_TARGET_I386", 0 };
+ for (f = 0; sr[f]; f += 2) {
+ c = strlen(sr[f]);
+ if (0 == memcmp(p, sr[f], c)) {
+ p += c, ++f;
+ q = strchr(strcpy(q, sr[f]), 0);
+ break;
+ }
+
+ }
+ if (sr[f])
+ continue;
+ } while (!!(*q++ = *p++));
+
+ fprintf(op, "%s\n", l2);
+
+ } else if (*p == '/') {
+ strcpy(q, p);
+ fprintf(op, " %s\n", l2);
+
+ } else {
+ f = 0;
+ for (;;) {
+ c = *p++;
+ if (isspc(c)) {
+ if (q == l2 || isspc(q[-1]))
+ continue;
+ if ((f > 2 || e) || (q[-1] != ')' && *p != '(')) {
+ if (!isid(q[-1]) || !isid(*p))
+ continue;
+ }
+ }
+ if (c == '(')
+ ++e, ++f;
+ if (c == ')')
+ --e, ++f;
+ if (c == '\\' || c == '\"')
+ *q++ = '\\';
+ *q++ = c;
+ if (c == 0)
+ break;
+ }
+ fprintf(op, " \"%s\\n\"\n", l2);
+ }
+ }
+
+ fclose(fp);
+ fclose(op);
+ return 0;
+}
diff --git a/tests/misc/tcc_predefs.h b/tests/misc/tcc_predefs.h
new file mode 100644
index 0000000..bbba425
--- /dev/null
+++ b/tests/misc/tcc_predefs.h
@@ -0,0 +1,111 @@
+#if defined __x86_64__
+#ifndef _WIN64
+ /* GCC compatible definition of va_list. */
+ /* This should be in sync with the declaration in our lib/libtcc1.c */
+ typedef struct {
+ unsigned gp_offset, fp_offset;
+ union {
+ unsigned overflow_offset;
+ char *overflow_arg_area;
+ };
+ char *reg_save_area;
+ } __builtin_va_list[1];
+
+ void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
+ #define __builtin_va_start(ap, last) \
+ (*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
+ #define __builtin_va_arg(ap, t) \
+ (*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t))))
+ #define __builtin_va_copy(dest, src) (*(dest) = *(src))
+
+#else /* _WIN64 */
+ typedef char *__builtin_va_list;
+ #define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
+ ? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
+#endif
+
+#elif defined __arm__
+ typedef char *__builtin_va_list;
+ #define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
+ #define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
+ & ~(_tcc_alignof(type) - 1))
+ #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3))
+ #define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
+ &~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
+
+#elif defined __aarch64__
+ typedef struct {
+ void *__stack, *__gr_top, *__vr_top;
+ int __gr_offs, __vr_offs;
+ } __builtin_va_list;
+
+#elif defined __riscv
+ typedef char *__builtin_va_list;
+ #define __va_reg_size (__riscv_xlen >> 3)
+ #define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
+ & -(__alignof__(type)))
+ #define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
+
+#else /* __i386__ */
+ typedef char *__builtin_va_list;
+ #define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3))
+ #define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3)))
+
+#endif
+ #define __builtin_va_end(ap) (void)(ap)
+ #ifndef __builtin_va_copy
+ # define __builtin_va_copy(dest, src) (dest) = (src)
+ #endif
+
+
+ /* TCC BBUILTIN AND BOUNDS ALIASES */
+ #ifdef __BOUNDS_CHECKING_ON
+ # define __BUILTIN(ret,name,params) \
+ ret __builtin_##name params __attribute__((alias("__bound_" #name)));
+ # define __BOUND(ret,name,params) \
+ ret name params __attribute__((alias("__bound_" #name)));
+ #else
+ # define __BUILTIN(ret,name,params) \
+ ret __builtin_##name params __attribute__((alias(#name)));
+ # define __BOUND(ret,name,params)
+ #endif
+ # define __BOTH(ret,name,params) \
+ __BUILTIN(ret,name,params) __BOUND(ret,name,params)
+
+ __BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__))
+ __BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__))
+ __BOTH(void*, memset, (void *, int, __SIZE_TYPE__))
+ __BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__))
+ __BOTH(__SIZE_TYPE__, strlen, (const char *))
+ __BOTH(char*, strcpy, (char *, const char *))
+ __BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__))
+ __BOTH(int, strcmp, (const char*, const char*))
+ __BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__))
+ __BOTH(char*, strcat, (char*, const char*))
+ __BOTH(char*, strchr, (const char*, int))
+ __BOTH(char*, strdup, (const char*))
+
+#ifdef _WIN32
+ #define __MAYBE_REDIR __BOTH
+#else // HAVE MALLOC_REDIR
+ #define __MAYBE_REDIR __BUILTIN
+#endif
+ __MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__))
+ __MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__))
+ __MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__))
+ __MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__))
+ __MAYBE_REDIR(void, free, (void*))
+
+#if defined __i386__ || defined __x86_64__
+ __BOTH(void*, alloca, (__SIZE_TYPE__))
+#endif
+ __BUILTIN(void, abort, (void))
+ __BOUND(int, longjmp, ())
+#ifndef _WIN32
+ __BOUND(void*, mmap, ())
+ __BOUND(void*, munmap, ())
+#endif
+ #undef __BUILTIN
+ #undef __BOUND
+ #undef __BOTH
+ #undef __MAYBE_REDIR
diff --git a/tests/pp/Makefile b/tests/pp/Makefile
index 687aa52..4785db3 100644
--- a/tests/pp/Makefile
+++ b/tests/pp/Makefile
@@ -10,7 +10,7 @@ VPATH = $(SRC)
files = $(patsubst %.$1,%.test,$(notdir $(wildcard $(SRC)/*.$1)))
TESTS = $(call files,c) $(call files,S)
-all test : $(sort $(TESTS))
+all test testspp.all: $(sort $(TESTS))
DIFF_OPTS = -Nu -b -B
@@ -29,6 +29,8 @@ FILTER = 2>&1 | sed 's,$(SRC)/,,g'
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
&& rm -f $*.output
+testspp.%: %.test ;
+
# automatically generate .expect files with gcc:
%.expect: # %.c
gcc -E -P $*.[cS] >$*.expect 2>&1
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 57670be..4ac2cc0 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -3,7 +3,10 @@
*/
#include "config.h"
-#if GCC_MAJOR >= 3
+/* identify the configured reference compiler in use */
+#define CC_gcc 1
+#define CC_clang 2
+#define CC_tcc 3
/* Unfortunately, gcc version < 3 does not handle that! */
#define ALL_ISOC99
@@ -11,9 +14,11 @@
/* only gcc 3 handles _Bool correctly */
#define BOOL_ISOC99
-/* gcc 2.95.3 does not handle correctly CR in strings or after strays */
-#define CORRECT_CR_HANDLING
+/* __VA_ARGS__ and __func__ support */
+#define C99_MACROS
+#ifndef __TINYC__
+typedef __SIZE_TYPE__ uintptr_t;
#endif
#if defined(_WIN32)
@@ -33,12 +38,6 @@
#define LONG_DOUBLE_LITERAL(x) x ## L
#endif
-/* deprecated and no longer supported in gcc 3.3 */
-//#define ACCEPT_CR_IN_STRINGS
-
-/* __VA_ARGS__ and __func__ support */
-#define C99_MACROS
-
/* test various include syntaxes */
#define TCCLIB_INC <tcclib.h>
@@ -64,65 +63,19 @@
#define INC(name) <tests/name.h>
#define funnyname 42test.h
#define incdir tests/
+#ifdef __clang__
+/* clang's preprocessor is broken in this regard and adds spaces
+ to the tokens 'incdir' and 'funnyname' when expanding */
+#define incname <tests/42test.h>
+#else
#define incname < incdir funnyname >
+#endif
#define __stringify(x) #x
#define stringify(x) __stringify(x)
#include INC(42test)
#include incname
#include stringify(funnyname)
-void intdiv_test();
-void string_test();
-void expr_test();
-void macro_test();
-void recursive_macro_test();
-void scope_test();
-void forward_test();
-void funcptr_test();
-void loop_test();
-void switch_test();
-void goto_test();
-void enum_test();
-void typedef_test();
-void struct_test();
-void array_test();
-void expr_ptr_test();
-void bool_test();
-void optimize_out();
-void expr2_test();
-void constant_expr_test();
-void expr_cmp_test();
-void char_short_test();
-void init_test(void);
-void compound_literal_test(void);
-int kr_test();
-void struct_assign_test(void);
-void cast_test(void);
-void bitfield_test(void);
-void c99_bool_test(void);
-void float_test(void);
-void longlong_test(void);
-void manyarg_test(void);
-void stdarg_test(void);
-void whitespace_test(void);
-void relocation_test(void);
-void old_style_function(void);
-void alloca_test(void);
-void c99_vla_test(int size1, int size2);
-void sizeof_test(void);
-void typeof_test(void);
-void local_label_test(void);
-void statement_expr_test(void);
-void asm_test(void);
-void builtin_test(void);
-void weak_test(void);
-void global_data_test(void);
-void cmp_comparison_test(void);
-void math_cmp_test(void);
-void callsave_test(void);
-void builtin_frame_address_test(void);
-void attrib_test(void);
-
int fib(int n);
void num(int n);
void forward_ref(void);
@@ -133,8 +86,6 @@ int isid(int c);
void funny_line_continuation (int, ..\
. );
-char via_volatile (char);
-
#define A 2
#define N 1234 + A
#define pf printf
@@ -178,7 +129,7 @@ static int onetwothree = 123;
#ifdef __TINYC__
/* We try to handle this syntax. Make at least sure it doesn't segfault. */
-char invalid_function_def()[] {}
+char invalid_function_def()[] {return 0;}
#endif
#define __INT64_C(c) c ## LL
@@ -194,74 +145,8 @@ int qq(int x)
#define wq_spin_lock spin_lock
#define TEST2() wq_spin_lock(a)
-#define UINT_MAX ((unsigned) -1)
-
-void intdiv_test(void)
-{
- printf("18/21=%u\n", 18/21);
- printf("18%%21=%u\n", 18%21);
- printf("41/21=%u\n", 41/21);
- printf("41%%21=%u\n", 41%21);
- printf("42/21=%u\n", 42/21);
- printf("42%%21=%u\n", 42%21);
- printf("43/21=%u\n", 43/21);
- printf("43%%21=%u\n", 43%21);
- printf("126/21=%u\n", 126/21);
- printf("126%%21=%u\n", 126%21);
- printf("131/21=%u\n", 131/21);
- printf("131%%21=%u\n", 131%21);
- printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2);
- printf("(UINT_MAX/2+3)%%2=%u\n", (UINT_MAX/2+3)%2);
-
- printf("18/-21=%u\n", 18/-21);
- printf("18%%-21=%u\n", 18%-21);
- printf("41/-21=%u\n", 41/-21);
- printf("41%%-21=%u\n", 41%-21);
- printf("42/-21=%u\n", 42/-21);
- printf("42%%-21=%u\n", 42%-21);
- printf("43/-21=%u\n", 43/-21);
- printf("43%%-21=%u\n", 43%-21);
- printf("126/-21=%u\n", 126/-21);
- printf("126%%-21=%u\n", 126%-21);
- printf("131/-21=%u\n", 131/-21);
- printf("131%%-21=%u\n", 131%-21);
- printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2);
- printf("(UINT_MAX/2+3)%%-2=%u\n", (UINT_MAX/2+3)%-2);
-
- printf("-18/21=%u\n", -18/21);
- printf("-18%%21=%u\n", -18%21);
- printf("-41/21=%u\n", -41/21);
- printf("-41%%21=%u\n", -41%21);
- printf("-42/21=%u\n", -42/21);
- printf("-42%%21=%u\n", -42%21);
- printf("-43/21=%u\n", -43/21);
- printf("-43%%21=%u\n", -43%21);
- printf("-126/21=%u\n", -126/21);
- printf("-126%%21=%u\n", -126%21);
- printf("-131/21=%u\n", -131/21);
- printf("-131%%21=%u\n", -131%21);
- printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2);
- printf("-(UINT_MAX/2+3)%%2=%u\n", (0-(UINT_MAX/2+3))%2);
-
- printf("-18/-21=%u\n", -18/-21);
- printf("-18%%-21=%u\n", -18%-21);
- printf("-41/-21=%u\n", -41/-21);
- printf("-41%%-21=%u\n", -41%-21);
- printf("-42/-21=%u\n", -42/-21);
- printf("-42%%-21=%u\n", -42%-21);
- printf("-43/-21=%u\n", -43/-21);
- printf("-43%%-21=%u\n", -43%-21);
- printf("-126/-21=%u\n", -126/-21);
- printf("-126%%-21=%u\n", -126%-21);
- printf("-131/-21=%u\n", -131/-21);
- printf("-131%%-21=%u\n", -131%-21);
- printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2);
- printf("-(UINT_MAX/2+3)%%-2=%u\n", (0-(UINT_MAX/2+3))%-2);
-}
-
void macro_test(void)
{
- printf("macro:\n");
pf("N=%d\n", N);
printf("aaa=%d\n", AAA);
@@ -336,22 +221,6 @@ void macro_test(void)
MACRO_NOARGS();
-#ifdef __LINE__
- printf("__LINE__ defined\n");
-#endif
-
- printf("__LINE__=%d __FILE__=%s\n",
- __LINE__, __FILE__);
-#if 0
-#line 200
- printf("__LINE__=%d __FILE__=%s\n",
- __LINE__, __FILE__);
-#line 203 "test"
- printf("__LINE__=%d __FILE__=%s\n",
- __LINE__, __FILE__);
-#line 227 "tcctest.c"
-#endif
-
/* not strictly preprocessor, but we test it there */
#ifdef C99_MACROS
printf("__func__ = %s\n", __func__);
@@ -408,15 +277,25 @@ comment
comment. */
TEST2 /* the comment */ ();
- printf("%s\n", get_basefile_from_header());
- printf("%s\n", __BASE_FILE__);
- printf("%s\n", get_file_from_header());
- printf("%s\n", __FILE__);
+ printf("basefromheader %s\n", get_basefile_from_header());
+ printf("base %s\n", __BASE_FILE__);
+ {
+ /* Some compilers (clang) prepend './' to __FILE__ from included
+ files. */
+ const char *fn = get_file_from_header();
+ if (fn[0] == '.' && fn[1] == '/')
+ fn += 2;
+ printf("filefromheader %s\n", fn);
+ }
+ printf("file %s\n", __FILE__);
/* Check that funnily named include was in fact included */
have_included_42test_h = 1;
have_included_42test_h_second = 1;
have_included_42test_h_third = 1;
+
+ /* Check that we don't complain about stray \ here */
+ printf("print a backslash: %s\n", stringify(\\));
}
@@ -461,6 +340,56 @@ int ret(a)
return 0;
}
+#if !defined(__TINYC__) && (__GNUC__ >= 8)
+/* Old GCCs don't regard "foo"[1] as constant, even in GNU dialect. */
+#define CONSTANTINDEXEDSTRLIT
+#endif
+char str_ag1[] = "b";
+char str_ag2[] = { "b" };
+/*char str_bg1[] = ("cccc"); GCC accepts this with pedantic warning, TCC not */
+#ifdef CONSTANTINDEXEDSTRLIT
+char str_ag3[] = { "ab"[1], 0 };
+char str_x[2] = { "xy" "z"[2], 0 };
+#endif
+char *str_ar[] = { "one", "two" };
+struct str_SS {unsigned char a[3], b; };
+struct str_SS str_sinit15 = { "r" };
+struct str_SS str_sinit16[] = { { "q" }, 2 };
+
+static void string_test2()
+{
+ char *p = "hello";
+ char a3[2] = { "p" };
+ char a4[2] = { "ab" "c"[2], 0 };
+ char *pa1 = "def" + 1;
+ char *pa2 = { "xyz" + 1 };
+ int i = 0;
+ struct str_SS ss = { { [0 ... 1] = 'a' }, 0 };
+#ifndef CONSTANTINDEXEDSTRLIT
+ char str_ag3[] = { "ab"[1], 0 };
+ char str_x[2] = { "xy" "z"[2], 0 };
+#endif
+ puts("string_test2");
+ puts(str_ag1);
+ puts(str_ag2);
+ /*puts(str_bg1);*/
+ puts(str_ag3);
+ puts(str_x);
+ puts(str_sinit15.a);
+ puts(str_sinit16[0].a);
+ puts(a3);
+ puts(a4);
+ puts(p);
+ puts("world");
+ printf("%s\n", "bla");
+ puts(str_ar[0]);
+ puts(str_ar[1]);
+ puts(ss.a);
+ puts(i >= 0 ? "one" : "two");
+ puts(pa1);
+ puts(pa2);
+}
+
void ps(const char *s)
{
int c;
@@ -505,6 +434,52 @@ void string_test()
num(b);
b = b * 2;
}
+ string_test2();
+}
+
+
+void if1t(int n, int a, int b, int c)
+{
+ if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b);
+ if (a && !b) printf("if1t: %d 2 %d %d\n", n, a, b);
+ if (!a && b) printf("if1t: %d 3 %d %d\n", n, a, b);
+ if (!a && !b) printf("if1t: %d 4 %d %d\n", n, a, b);
+ if (a || b) printf("if1t: %d 5 %d %d\n", n, a, b);
+ if (a || !b) printf("if1t: %d 6 %d %d\n", n, a, b);
+ if (!a || b) printf("if1t: %d 7 %d %d\n", n, a, b);
+ if (!a || !b) printf("if1t: %d 8 %d %d\n", n, a, b);
+ if (a && b || c) printf("if1t: %d 9 %d %d %d\n", n, a, b, c);
+ if (a || b && c) printf("if1t: %d 10 %d %d %d\n", n, a, b, c);
+ if (a > b - 1 && c) printf("if1t: %d 11 %d %d %d\n", n, a, b, c);
+ if (a > b - 1 || c) printf("if1t: %d 12 %d %d %d\n", n, a, b, c);
+ if (a > 0 && 1) printf("if1t: %d 13 %d %d %d\n", n, a, b, c);
+ if (a > 0 || 0) printf("if1t: %d 14 %d %d %d\n", n, a, b, c);
+}
+
+void if2t(void)
+{
+ if (0 && 1 || printf("if2t:ok\n") || 1)
+ printf("if2t:ok2\n");
+ printf("if2t:ok3\n");
+}
+
+void if3t(void)
+{
+ volatile long long i = 1;
+ if (i <= 18446744073709551615ULL)
+ ;
+ else
+ printf ("if3t:wrong 1\n");
+}
+
+void if_test(void)
+{
+ if1t(1, 0, 0, 0);
+ if1t(2, 0, 3, 0);
+ if1t(3, 2, 0, 0);
+ if1t(4, 2, 3, 0);
+ if2t();
+ if3t();
}
void loop_test()
@@ -568,9 +543,10 @@ void goto_test()
int i;
static void *label_table[3] = { &&label1, &&label2, &&label3 };
- printf("goto:\n");
+ printf("\ngoto:\n");
i = 0;
/* This needs to parse as label, not as start of decl. */
+ typedef_and_label x;
typedef_and_label:
s_loop:
if (i >= 10)
@@ -635,8 +611,7 @@ void enum_test()
/* The following should give no warning */
unsigned *p = &b1;
struct S_enum s = {E7};
- printf("enum: %d\n", s.e);
- printf("enum:\n%d %d %d %d %d %d\n",
+ printf("%d %d %d %d %d %d %d\n", s.e,
E0, E1, E2, E3, E4, E5);
b1 = 1;
printf("b1=%d\n", b1);
@@ -665,7 +640,6 @@ void typedef_test()
a = &b;
*a = 1234;
- printf("typedef:\n");
printf("a=%d\n", *a);
mytype2 = 2;
printf("mytype2=%d\n", mytype2);
@@ -673,7 +647,6 @@ void typedef_test()
void forward_test()
{
- printf("forward:\n");
forward_ref();
forward_ref();
}
@@ -711,66 +684,6 @@ struct empty_mem {
int x;
};
-int main(int argc, char **argv)
-{
- string_test();
- expr_test();
- macro_test();
- recursive_macro_test();
- scope_test();
- forward_test();
- funcptr_test();
- loop_test();
- switch_test();
- goto_test();
- enum_test();
- typedef_test();
- struct_test();
- array_test();
- expr_ptr_test();
- bool_test();
- optimize_out();
- expr2_test();
- constant_expr_test();
- expr_cmp_test();
- char_short_test();
- init_test();
- compound_literal_test();
- kr_test();
- struct_assign_test();
- cast_test();
- bitfield_test();
- c99_bool_test();
- float_test();
- longlong_test();
- manyarg_test();
- stdarg_test();
- whitespace_test();
- relocation_test();
- old_style_function();
- alloca_test();
- c99_vla_test(5, 2);
- sizeof_test();
- typeof_test();
- statement_expr_test();
- local_label_test();
- asm_test();
- builtin_test();
-#ifndef _WIN32
- weak_test();
-#endif
- global_data_test();
- cmp_comparison_test();
- math_cmp_test();
- callsave_test();
- builtin_frame_address_test();
- intdiv_test();
- if (via_volatile (42) != 42)
- printf ("via_volatile broken\n");
- attrib_test();
- return 0;
-}
-
int tab[3];
int tab2[3][2];
@@ -783,7 +696,6 @@ void f1(g)
void scope_test()
{
- printf("scope:\n");
g = 2;
f1(1);
printf("g2=%d\n", g);
@@ -800,11 +712,34 @@ void scope_test()
printf("g5=%d\n", g);
}
+int st2_i;
+int *st2_p = &st2_i;
+void scope2_test()
+{
+ char a[50];
+ st2_i = 42;
+ for (int st2_i = 1; st2_i < 10; st2_i++) {
+ extern int st2_i;
+ st2_i++;
+ printf("exloc: %d\n", st2_i);
+ }
+ printf("exloc: %d\n", *st2_p);
+}
+
+/* C has tentative definition, and they may be repeated. */
+extern int st_global1;
+int st_global1=42;
+extern int st_global1;
+int st_global1;
+extern int st_global2;
+int st_global2;
+extern int st_global2;
+int st_global2;
+
void array_test()
{
int i, j, a[4];
- printf("array:\n");
printf("sizeof(a) = %d\n", sizeof(a));
printf("sizeof(\"a\") = %d\n", sizeof("a"));
#ifdef C99_MACROS
@@ -909,7 +844,6 @@ void expr2_test()
{
int a, b;
- printf("expr2:\n");
vstack_ptr = vstack;
vpush(1432432, 2);
vstack_ptr[-2] &= ~0xffffff80;
@@ -917,14 +851,16 @@ void expr2_test()
printf("res= %d %d\n", a, b);
}
+int const_len_ar[sizeof(1/0)]; /* div-by-zero, but in unevaluated context */
+
void constant_expr_test()
{
int a;
- printf("constant_expr:\n");
a = 3;
printf("%d\n", a * 16);
printf("%d\n", a * 1);
printf("%d\n", a + 0);
+ printf("%d\n", sizeof(const_len_ar));
}
int tab4[10];
@@ -934,7 +870,6 @@ void expr_ptr_test()
int *p, *q;
int i = -1;
- printf("expr_ptr:\n");
p = tab4;
q = tab4 + 10;
printf("diff=%d\n", q - p);
@@ -990,7 +925,6 @@ void expr_ptr_test()
void expr_cmp_test()
{
int a, b;
- printf("constant_expr:\n");
a = -1;
b = 1;
printf("%d\n", a == a);
@@ -1110,7 +1044,6 @@ void struct_test()
union union2 u;
struct Large ls;
- printf("struct:\n");
printf("sizes: %d %d %d %d\n",
sizeof(struct struct1),
sizeof(struct struct2),
@@ -1134,7 +1067,7 @@ void struct_test()
s->f3 = 1;
printf("st2: %d %d %d\n",
s->f1, s->f2, s->f3);
- printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1);
+ printf("str_addr=%x\n", (int)(uintptr_t)st1.str - (int)(uintptr_t)&st1.f1);
/* align / size tests */
printf("aligntest1 sizeof=%d alignof=%d\n",
@@ -1174,17 +1107,22 @@ void struct_test()
printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
}
+/* simulate char/short return value with undefined upper bits */
+static int __csf(int x) { return x; }
+static void *_csf = __csf;
+#define csf(t,n) ((t(*)(int))_csf)(n)
+
/* XXX: depend on endianness */
void char_short_test()
{
int var1, var2;
-
- printf("char_short:\n");
+ signed char var3;
+ long long var4;
var1 = 0x01020304;
var2 = 0xfffefdfc;
printf("s8=%d %d\n",
- *(char *)&var1, *(char *)&var2);
+ *(signed char *)&var1, *(signed char *)&var2);
printf("u8=%d %d\n",
*(unsigned char *)&var1, *(unsigned char *)&var2);
printf("s16=%d %d\n",
@@ -1195,12 +1133,44 @@ void char_short_test()
*(int *)&var1, *(int *)&var2);
printf("u32=%d %d\n",
*(unsigned int *)&var1, *(unsigned int *)&var2);
- *(char *)&var1 = 0x08;
+ *(signed char *)&var1 = 0x08;
printf("var1=%x\n", var1);
*(short *)&var1 = 0x0809;
printf("var1=%x\n", var1);
*(int *)&var1 = 0x08090a0b;
printf("var1=%x\n", var1);
+
+ var1 = 0x778899aa;
+ var4 = 0x11223344aa998877ULL;
+ var1 = var3 = var1 + 1;
+ var4 = var3 = var4 + 1;
+ printf("promote char/short assign %d "LONG_LONG_FORMAT"\n", var1, var4);
+ var1 = 0x778899aa;
+ var4 = 0x11223344aa998877ULL;
+ printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
+ printf("promote char/short cast VA %d %d\n", (signed char)(var1 + 1), (signed char)(var4 + 1));
+#if !defined(__arm__)
+ /* We can't really express GCC behaviour of return type promotion in
+ the presence of undefined behaviour (like __csf is). */
+ var1 = csf(unsigned char,0x89898989);
+ var4 = csf(signed char,0xabababab);
+ printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4);
+ printf("promote char/short fumcret VA %d %d %d %d\n",
+ csf(unsigned short,0xcdcdcdcd),
+ csf(short,0xefefefef),
+ csf(_Bool,0x33221100),
+ csf(_Bool,0x33221101));
+#endif
+ var3 = -10;
+ var1 = (signed char)(unsigned char)(var3 + 1);
+ var4 = (signed char)(unsigned char)(var3 + 1);
+ printf("promote multicast (char)(unsigned char) %d "LONG_LONG_FORMAT"\n", var1, var4);
+ var4 = 0x11223344aa998877ULL;
+ var4 = (unsigned)(int)(var4 + 1);
+ printf("promote multicast (unsigned)(int) "LONG_LONG_FORMAT"\n", var4);
+ var4 = 0x11223344bbaa9988ULL;
+ var4 = (unsigned)(signed char)(var4 + 1);
+ printf("promote multicast (unsigned)(char) "LONG_LONG_FORMAT"\n", var4);
}
/******************/
@@ -1307,12 +1277,16 @@ void bool_test()
extern int undefined_function(void);
extern int defined_function(void);
+#ifdef __clang__
+int undefined_function(void) {}
+#endif
+
static inline void refer_to_undefined(void)
{
undefined_function();
}
-void optimize_out(void)
+void optimize_out_test(void)
{
int i = 0 ? undefined_function() : defined_function();
printf ("oo:%d\n", i);
@@ -1374,6 +1348,12 @@ void optimize_out(void)
printf("ool6:%d\n", defined_function());
goto breakhere;
}
+ j = 1;
+ while (j) {
+ j--;
+ continue;
+ printf("ool7:%d\n", undefined_function());
+ }
/* Test that constants in logical && are optimized: */
i = 0 && undefined_function();
@@ -1433,6 +1413,9 @@ int defined_function(void)
static int tab_reinit[];
static int tab_reinit[10];
+static int tentative_ar[];
+static int tentative_ar[] = {1,2,3};
+
//int cinit1; /* a global variable can be defined several times without error ! */
int cinit1;
int cinit1;
@@ -1444,8 +1427,6 @@ void compound_literal_test(void)
int *p, i;
char *q, *q3;
- printf("compound_test:\n");
-
p = (int []){1, 2, 3};
for(i=0;i<3;i++)
printf(" %d", p[i]);
@@ -1497,7 +1478,6 @@ int kr_func2(a, b)
kr_test()
{
- printf("kr_test:\n");
printf("func1=%d\n", kr_func1(3, 4));
printf("func2=%d\n", kr_func2(3, 4));
return 0;
@@ -1553,8 +1533,6 @@ void struct_assign_test(void)
ps = &s;
ps->i = 4;
#if 0
- printf("struct_assign_test:\n");
-
s.lsta1.f1 = 1;
s.lsta1.f2 = 2;
printf("%d %d\n", s.lsta1.f1, s.lsta1.f2);
@@ -1597,9 +1575,9 @@ void cast_test()
unsigned b,d;
short s;
char *p = NULL;
+ unsigned long ul = 0x80000000UL;
p -= 0x700000000042;
- printf("cast_test:\n");
a = 0xfffff;
cast1(a, a, a, a);
a = 0xffffe;
@@ -1640,15 +1618,20 @@ void cast_test()
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
+#if CC_NAME != CC_clang /* clang doesn't support non-portable conversions */
/* from pointer to integer types */
printf("%d %d %ld %ld %lld %lld\n",
(int)p, (unsigned int)p,
(long)p, (unsigned long)p,
(long long)p, (unsigned long long)p);
+#endif
/* from integers to pointers */
printf("%p %p %p %p\n",
(void *)a, (void *)b, (void *)c, (void *)d);
+
+ /* int to int with sign set */
+ printf("0x%lx\n", (unsigned long)(int)ul);
}
/* initializers tests */
@@ -1752,6 +1735,8 @@ arrtype2 sinit22 = {5,6,7};
int sinit23[2] = { "astring" ? sizeof("astring") : -1,
&sinit23 ? 42 : -1 };
+int sinit24 = 2 || 1 / 0; /* exception in constant but unevaluated context */
+
extern int external_inited = 42;
void init_test(void)
@@ -1772,8 +1757,6 @@ void init_test(void)
/* Addresses on non-weak symbols are non-zero, but not the access itself */
int linit18[2] = {&zero ? 1 : -1, zero ? -1 : 1 };
- printf("init_test:\n");
-
printf("sinit1=%d\n", sinit1);
printf("sinit2=%d\n", sinit2);
printf("sinit3=%d %d %d %d\n",
@@ -1866,6 +1849,7 @@ void init_test(void)
printf("arrtype6: %d\n", sizeof(arrtype2));
printf("sinit23= %d %d\n", sinit23[0], sinit23[1]);
+ printf("sinit24=%d\n", sinit24);
printf("linit18= %d %d\n", linit18[0], linit18[1]);
}
@@ -1991,9 +1975,8 @@ void c99_bool_test(void)
{
#ifdef BOOL_ISOC99
int a;
- _Bool b;
+ _Bool b, b2;
- printf("bool_test:\n");
printf("sizeof(_Bool) = %d\n", sizeof(_Bool));
a = 3;
printf("cast: %d %d %d\n", (_Bool)10, (_Bool)0, (_Bool)a);
@@ -2001,6 +1984,9 @@ void c99_bool_test(void)
printf("b = %d\n", b);
b++;
printf("b = %d\n", b);
+ b2 = 0;
+ printf("sizeof(x ? _Bool : _Bool) = %d (should be sizeof int)\n",
+ sizeof((volatile)a ? b : b2));
#endif
}
@@ -2018,7 +2004,6 @@ void bitfield_test(void)
int f4 : 7;
unsigned int f5 : 7;
} st1;
- printf("bitfield_test:");
printf("sizeof(st1) = %d\n", sizeof(st1));
st1.f1 = 3;
@@ -2230,12 +2215,15 @@ double ftab1[3] = { 1.2, 3.4, -5.6 };
void float_test(void)
{
#if !defined(__arm__) || defined(__ARM_PCS_VFP)
- float fa, fb;
- double da, db;
+ volatile float fa, fb;
+ volatile double da, db;
int a;
unsigned int b;
+ static double nan2 = 0.0/0.0;
+ static double inf1 = 1.0/0.0;
+ static double inf2 = 1e5000;
+ volatile LONG_DOUBLE la;
- printf("float_test:\n");
printf("sizeof(float) = %d\n", sizeof(float));
printf("sizeof(double) = %d\n", sizeof(double));
printf("sizeof(long double) = %d\n", sizeof(LONG_DOUBLE));
@@ -2255,6 +2243,31 @@ void float_test(void)
b = 4000000000;
db = b;
printf("db = %f\n", db);
+ printf("nan != nan = %d, inf1 = %f, inf2 = %f\n", nan2 != nan2, inf1, inf2);
+ da = 0x0.88p-1022; /* a subnormal */
+ la = da;
+ printf ("da subnormal = %a\n", da);
+ printf ("da subnormal = %.40g\n", da);
+ printf ("la subnormal = %La\n", la);
+ printf ("la subnormal = %.40Lg\n", la);
+ da /= 2;
+ la = da;
+ printf ("da/2 subnormal = %a\n", da);
+ printf ("da/2 subnormal = %.40g\n", da);
+ printf ("la/2 subnormal = %La\n", la);
+ printf ("la/2 subnormal = %.40Lg\n", la);
+ fa = 0x0.88p-126f; /* a subnormal */
+ la = fa;
+ printf ("fa subnormal = %a\n", fa);
+ printf ("fa subnormal = %.40g\n", fa);
+ printf ("la subnormal = %La\n", la);
+ printf ("la subnormal = %.40Lg\n", la);
+ fa /= 2;
+ la = fa;
+ printf ("fa/2 subnormal = %a\n", fa);
+ printf ("fa/2 subnormal = %.40g\n", fa);
+ printf ("la/2 subnormal = %La\n", la);
+ printf ("la/2 subnormal = %.40Lg\n", la);
#endif
}
@@ -2266,6 +2279,12 @@ int fib(int n)
return fib(n-1) + fib(n-2);
}
+#if __GNUC__ == 3
+# define aligned_function 0
+#else
+void __attribute__((aligned(16))) aligned_function(int i) {}
+#endif
+
void funcptr_test()
{
void (*func)(int);
@@ -2276,7 +2295,6 @@ void funcptr_test()
} st1;
long diff;
- printf("funcptr:\n");
func = &num;
(*func)(12345);
func = num;
@@ -2296,6 +2314,10 @@ void funcptr_test()
func(42);
(func + diff)(42);
(num + a)(43);
+
+ /* Check that we can align functions */
+ func = aligned_function;
+ printf("aligned_function (should be zero): %d\n", ((int)(uintptr_t)func) & 15);
}
void lloptest(long long a, long long b)
@@ -2420,12 +2442,16 @@ long long llfunc2(long long x, long long y, int z)
return x * y * z;
}
+void check_opl_save_regs(char *a, long long b, int c)
+{
+ *a = b < 0 && !c;
+}
+
void longlong_test(void)
{
long long a, b, c;
int ia;
unsigned int ua;
- printf("longlong_test:\n");
printf("sizeof(long long) = %d\n", sizeof(long long));
ia = -1;
ua = -2;
@@ -2487,12 +2513,24 @@ void longlong_test(void)
a = 0x123;
long long *p = &a;
llshift(*p, 5);
+
+ /* shortening followed by widening */
+ unsigned long long u = 0x8000000000000001ULL;
+ u = (unsigned)(u + 1);
+ printf("long long u=" ULONG_LONG_FORMAT "\n", u);
+ u = 0x11223344aa998877ULL;
+ u = (unsigned)(int)(u + 1);
+ printf("long long u=" ULONG_LONG_FORMAT "\n", u);
+
+ /* was a problem with missing save_regs in gen_opl on 32-bit platforms */
+ char cc = 78;
+ check_opl_save_regs(&cc, -1, 0);
+ printf("check_opl_save_regs: %d\n", cc);
}
void manyarg_test(void)
{
LONG_DOUBLE ld = 1234567891234LL;
- printf("manyarg_test:\n");
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
@@ -2524,6 +2562,18 @@ void manyarg_test(void)
42.0, 43.0, ld);
}
+void*
+va_arg_with_struct_ptr(va_list ap) {
+ /*
+ * This was a BUG identified with FFTW-3.3.8 on arm64.
+ * The test case only checks it compiles on all supported
+ * architectures. This function is not currently called.
+ */
+ struct X { int _x; };
+ struct X *x = va_arg(ap, struct X *);
+ return x;
+}
+
void vprintf1(const char *fmt, ...)
{
va_list ap, aq;
@@ -2601,6 +2651,19 @@ void stdarg_for_libc(const char *fmt, ...)
va_end(args);
}
+void stdarg_syntax(int n, ...)
+{
+ int i;
+ va_list ap;
+ if (1)
+ va_start(ap, n);
+ else
+ ;
+ i = va_arg(ap, int);
+ printf("stdarg_void_expr: %d\n", i);
+ (va_end(ap));
+}
+
void stdarg_test(void)
{
LONG_DOUBLE ld = 1234567891234LL;
@@ -2648,38 +2711,7 @@ void stdarg_test(void)
bob.profile = 42;
stdarg_for_struct(bob, bob, bob, bob.profile);
stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456);
-}
-
-void whitespace_test(void)
-{
- char *str;
-
- #if 1
- pri\
-ntf("whitspace:\n");
-#endif
- pf("N=%d\n", 2);
-
-#ifdef CORRECT_CR_HANDLING
- pri\
-ntf("aaa=%d\n", 3);
-#endif
-
- pri\
-\
-ntf("min=%d\n", 4);
-
-#ifdef ACCEPT_CR_IN_STRINGS
- printf("len1=%d\n", strlen("
-"));
-#ifdef CORRECT_CR_HANDLING
- str = "
-";
- printf("len1=%d str[0]=%d\n", strlen(str), str[0]);
-#endif
- printf("len1=%d\n", strlen(" a
-"));
-#endif /* ACCEPT_CR_IN_STRINGS */
+ stdarg_syntax(1, 17);
}
int reltab[3] = { 1, 2, 3 };
@@ -2738,7 +2770,7 @@ int cmpfn();
printf("cmpfn=%lx\n", (long)cmpfn);
}
-void old_style_function(void)
+void old_style_function_test(void)
{
old_style_f((void *)1, 2, 3.0);
decl_func1(NULL);
@@ -2765,7 +2797,7 @@ void *bounds_checking_is_enabled()
typedef int constant_negative_array_size_as_compile_time_assertion_idiom[(1 ? 2 : 0) - 1];
-void c99_vla_test(int size1, int size2)
+void c99_vla_test_1(int size1, int size2)
{
#if defined __i386__ || defined __x86_64__
int size = size1 * size2;
@@ -2816,9 +2848,11 @@ void c99_vla_test(int size1, int size2)
#endif
}
-#ifndef __TINYC__
-typedef __SIZE_TYPE__ uintptr_t;
-#endif
+void c99_vla_test(void)
+{
+ c99_vla_test_1(5, 2);
+}
+
void sizeof_test(void)
{
@@ -2962,6 +2996,22 @@ void statement_expr_test(void)
/* Test that we can give out addresses of local labels. */
consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
+
+ /* Test interaction between local and global label stacks and the
+ need to defer popping symbol from them when within statement
+ expressions. Note how the labels are both named LBL. */
+ i = 0;
+ ({
+ {
+ __label__ LBL;
+ LBL: if (i++ == 0) goto LBL;
+ }
+ /* jump to a classical label out of an expr-stmt that had previously
+ overshadowed that classical label */
+ goto LBL;
+ });
+ LBL:
+ printf("stmtexpr: %d should be 2\n", i);
}
void local_label_test(void)
@@ -3087,6 +3137,8 @@ static __inline__ void sigdelset1(unsigned int *set, int _sig)
asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc", "flags");
}
+#ifndef __APPLE__
+/* clang's inline asm is uncapable of 'xchgb %b0,%h0' */
static __inline__ __const__ unsigned int swab32(unsigned int x)
{
__asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
@@ -3096,6 +3148,7 @@ static __inline__ __const__ unsigned int swab32(unsigned int x)
: "0" (x));
return x;
}
+#endif
static __inline__ unsigned long long mul64(unsigned int a, unsigned int b)
{
@@ -3172,6 +3225,7 @@ void base_func(void)
printf ("asmc: base\n");
}
+#ifndef __APPLE__
extern void override_func1 (void);
extern void override_func2 (void);
@@ -3189,6 +3243,21 @@ void override_func2 (void)
extern int bug_table[] __attribute__((section("__bug_table")));
char * get_asm_string (void)
{
+ /* On i386 when -fPIC is enabled this would cause a compile error with GCC,
+ the problem being the "i" constraint used with a symbolic operand
+ resolving to a local label. That check is overly zealous as the code
+ within the asm makes sure to use it only in PIC-possible contexts,
+ but all GCC versions behave like so. We arrange for PIC to be disabled
+ for compiling tcctest.c in the Makefile.
+
+ Additionally the usage of 'c' in "%c0" in the template is actually wrong,
+ as that would expect an operand that is a condition code. The operand
+ as is (a local label) is accepted by GCC in non-PIC mode, and on x86-64.
+ What the linux kernel really wanted is 'p' to disable the addition of '$'
+ to the printed operand (as in "$.LC0" where the template only wants the
+ bare operand ".LC0"). But the code below is what the linux kernel
+ happens to use and as such is the one we want to test. */
+#ifndef __clang__
extern int some_symbol;
asm volatile (".globl some_symbol\n"
"jmp .+6\n"
@@ -3204,6 +3273,9 @@ char * get_asm_string (void)
".popsection\n" : : "i" ("A string"));
char * str = ((char*)bug_table) + bug_table[1];
return str;
+#else
+ return (char *) "A string";
+#endif
}
/* This checks another constructs with local labels. */
@@ -3225,6 +3297,7 @@ void asm_local_label_diff (void)
{
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
}
+#endif
/* This checks that static local variables are available from assembler. */
void asm_local_statics (void)
@@ -3255,7 +3328,7 @@ void clobber_r12(void)
}
#endif
-void test_high_clobbers(void)
+void test_high_clobbers_really(void)
{
#if defined __x86_64__ && !defined _WIN64
register long val asm("r12");
@@ -3271,6 +3344,20 @@ void test_high_clobbers(void)
#endif
}
+void test_high_clobbers(void)
+{
+#if defined __x86_64__ && !defined _WIN64
+ long x1, x2;
+ asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
+ test_high_clobbers_really();
+ asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
+ asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */
+ /* should be 0 but tcc doesn't save r12 automatically, which has
+ bad effects when gcc helds TCCState *s in r12 in tcc.c:main */
+ //printf("r12-clobber-diff: %lx\n", x2 - x1);
+#endif
+}
+
static long cpu_number;
void trace_console(long len, long len2)
{
@@ -3359,8 +3446,10 @@ void test_asm_call(void)
tested here). */
/* two pushes so stack remains aligned */
asm volatile ("push %%rdi; push %%rdi; mov %0, %%rdi;"
-#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__))
+#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__)) && !defined(__APPLE__)
"call getenv@plt;"
+#elif defined(__APPLE__)
+ "call _getenv;"
#else
"call getenv;"
#endif
@@ -3378,6 +3467,7 @@ void test_asm_call(void)
void asm_dot_test(void)
{
+#ifndef __APPLE__
int x;
for (x = 1;; ++x) {
int r = x;
@@ -3385,13 +3475,31 @@ void asm_dot_test(void)
case 1:
asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0");
case 2:
+#ifndef __clang__
+ /* clangs internal assembler is broken */
asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0");
+#else
+ asm(".text; mov $123, %eax; jmp p0");
+#endif
case 3:
- asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4");
+#if !defined(_WIN32) && !defined(__clang__)
+ asm(".pushsection \".data\"; Y=.; .int 999; X=Y; .int 456; X=.-4; .popsection");
+#else
+ asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4; .text");
+#endif
asm(".text; mov X"RX",%eax; jmp p0");
case 4:
- asm(".data; X=.; .int 789; Y=.; .int 999");
+#ifdef __clang__
+ /* Bah! Clang! Doesn't want to redefine 'X' */
+ asm(".text; mov $789,%eax; jmp p0");
+#else
+#ifndef _WIN32
+ asm(".data; X=.; .int 789; Y=.; .int 999; .previous");
+#else
+ asm(".data; X=.; .int 789; Y=.; .int 999; .text");
+#endif
asm(".text; mov X"RX",%eax; X=Y; jmp p0");
+#endif
case 0:
asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
}
@@ -3399,6 +3507,7 @@ void asm_dot_test(void)
break;
printf("asm_dot_test %d: %d\n", x, r);
}
+#endif
}
void asm_test(void)
@@ -3417,8 +3526,6 @@ void asm_test(void)
#endif
register int regvar asm("%esi");
- printf("inline asm:\n");
-
// parse 0x1E-1 as 3 tokens in asm mode
asm volatile ("mov $0x1E-1,%eax");
@@ -3452,8 +3559,11 @@ void asm_test(void)
__asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
printf("set=0x%x\n", set);
val = 0x01020304;
+#ifndef __APPLE__
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
+#endif
#ifndef _WIN32
+#ifndef __APPLE__
override_func1();
override_func2();
/* The base_func ref from the following inline asm should find
@@ -3462,13 +3572,17 @@ void asm_test(void)
override_func3();
printf("asmstr: %s\n", get_asm_string());
asm_local_label_diff();
+#endif
asm_local_statics();
#endif
+#ifndef __clang__
+ /* clang can't deal with the type change */
/* Check that we can also load structs of appropriate layout
into registers. */
asm volatile("" : "=r" (asmret) : "0"(s2));
if (asmret != s2.addr)
printf("asmstr: failed\n");
+#endif
#ifdef BOOL_ISOC99
/* Check that the typesize correctly sets the register size to
8 bit. */
@@ -3530,11 +3644,24 @@ void builtin_test(void)
/* space is needed because tcc preprocessor introduces a space between each token */
COMPAT_TYPE(char * *, void *);
#endif
- printf("res = %d\n", __builtin_constant_p(1));
- printf("res = %d\n", __builtin_constant_p(1 + 2));
- printf("res = %d\n", __builtin_constant_p(&constant_p_var));
- printf("res = %d\n", __builtin_constant_p(constant_p_var));
- printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var));
+ printf("res1 = %d\n", __builtin_constant_p(1));
+ printf("res2 = %d\n", __builtin_constant_p(1 + 2));
+ printf("res3 = %d\n", __builtin_constant_p(&constant_p_var));
+ printf("res4 = %d\n", __builtin_constant_p(constant_p_var));
+ printf("res5 = %d\n", __builtin_constant_p(100000 / constant_p_var));
+#ifdef __clang__
+ /* clang doesn't regard this as constant expression */
+ printf("res6 = 1\n");
+#else
+ printf("res6 = %d\n", __builtin_constant_p(i && 0));
+#endif
+ printf("res7 = %d\n", __builtin_constant_p(i && 1));
+#ifdef __clang__
+ /* clang doesn't regard this as constant expression */
+ printf("res8 = 1\n");
+#else
+ printf("res8 = %d\n", __builtin_constant_p(i && 0 ? i : 34));
+#endif
s = 1;
ll = 2;
i = __builtin_choose_expr (1 != 0, ll, s);
@@ -3549,7 +3676,9 @@ void builtin_test(void)
//printf("bera: %p\n", __builtin_extract_return_addr((void*)43));
}
-#ifndef _WIN32
+#ifdef _WIN32
+void weak_test(void) {}
+#else
extern int __attribute__((weak)) weak_f1(void);
extern int __attribute__((weak)) weak_f2(void);
extern int weak_f3(void);
@@ -3568,14 +3697,18 @@ extern int weak_asm_v1 asm("weak_asm_v1x") __attribute
extern int __attribute((weak)) weak_asm_v2 asm("weak_asm_v2x") ;
extern int __attribute((weak)) weak_asm_v3(void) asm("weak_asm_v3x") __attribute((weak));
+#ifndef __clang__
static const size_t dummy = 0;
extern __typeof(dummy) weak_dummy1 __attribute__((weak, alias("dummy")));
extern __typeof(dummy) __attribute__((weak, alias("dummy"))) weak_dummy2;
extern __attribute__((weak, alias("dummy"))) __typeof(dummy) weak_dummy3;
+#endif
int some_lib_func(void);
int dummy_impl_of_slf(void) { return 444; }
+#ifndef __clang__
int some_lib_func(void) __attribute__((weak, alias("dummy_impl_of_slf")));
+#endif
int weak_toolate() __attribute__((weak));
int weak_toolate() { return 0; }
@@ -3599,7 +3732,11 @@ void __attribute__((weak)) weak_test(void)
printf("weak_asm_v1=%d\n",&weak_asm_v1 != NULL);
printf("weak_asm_v2=%d\n",&weak_asm_v2 != NULL);
printf("weak_asm_v3=%d\n",&weak_asm_v3 != NULL);
+#ifdef __clang__
+ printf("some_lib_func=444\n");
+#else
printf("some_lib_func=%d\n", &some_lib_func ? some_lib_func() : 0);
+#endif
}
int __attribute__((weak)) weak_f2() { return 222; }
@@ -3695,6 +3832,7 @@ int fcompare (double a, double b, int code)
case 4: return a > b;
case 5: return a <= b;
}
+ return 0;
}
void math_cmp_test(void)
@@ -3703,6 +3841,7 @@ void math_cmp_test(void)
double one = 1.0;
double two = 2.0;
int comp = 0;
+ int v;
#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part)
/* This asserts that "a op b" is _not_ true, but "a iop b" is true.
@@ -3724,7 +3863,8 @@ void math_cmp_test(void)
if ((a iop b) || comp) \
; \
else \
- bug (a,b,op,iop,5);
+ bug (a,b,op,iop,5); \
+ if (v = !(a op b), !v) bug(a,b,op,iop,7);
/* Equality tests. */
FCMP(nan, nan, ==, !=, 0);
@@ -3793,8 +3933,10 @@ void builtin_frame_address_test(void)
char *fp0 = __builtin_frame_address(0);
printf("str: %s\n", str);
+#ifndef __riscv
bfa1(str-fp0);
#endif
+#endif
}
char via_volatile (char i)
@@ -3804,6 +3946,14 @@ char via_volatile (char i)
return vi;
}
+void volatile_test(void)
+{
+ if (via_volatile (42) != 42)
+ printf (" broken\n");
+ else
+ printf (" ok\n");
+}
+
struct __attribute__((__packed__)) Spacked {
char a;
short b;
@@ -3869,3 +4019,137 @@ int force_get_order(unsigned long s)
{
return __get_order(s);
}
+
+#define pv(m) printf(sizeof (s->m + 0) == 8 ? "%016llx\n" : "%02x\n", s->m)
+
+/* Test failed when using bounds checking */
+void bounds_check1_test (void)
+{
+ struct s {
+ int x;
+ long long y;
+ } _s, *s = &_s;
+ s->x = 10;
+ s->y = 20;
+ pv(x);
+ pv(y);
+}
+
+/* gcc 2.95.3 does not handle correctly CR in strings or after strays */
+#define CORRECT_CR_HANDLING
+
+/* deprecated and no longer supported in gcc 3.3 */
+#ifdef __TINYC__
+# define ACCEPT_CR_IN_STRINGS
+#endif
+
+/* keep this as the last test because GCC messes up line-numbers
+ with the ^L^K^M characters below */
+void whitespace_test(void)
+{
+ char *str;
+
+ #if 1
+ pri\
+ntf("whitspace:\n");
+#endif
+ pf("N=%d\n", 2);
+
+#ifdef CORRECT_CR_HANDLING
+ pri\
+ntf("aaa=%d\n", 3);
+#endif
+
+ pri\
+\
+ntf("min=%d\n", 4);
+
+#ifdef ACCEPT_CR_IN_STRINGS
+ printf("len1=%d\n", strlen("
+"));
+#ifdef CORRECT_CR_HANDLING
+ str = "
+";
+ printf("len1=%d str[0]=%d\n", strlen(str), str[0]);
+#endif
+ printf("len1=%d\n", strlen(" a
+"));
+#else
+ printf("len1=1\nlen1=1 str[0]=10\nlen1=3\n");
+#endif /* ACCEPT_CR_IN_STRINGS */
+
+#ifdef __LINE__
+ printf("__LINE__ defined\n");
+#endif
+
+#if 0
+ /* wrong with GCC */
+ printf("__LINE__=%d __FILE__=%s\n", __LINE__, __FILE__);
+#line 1111
+ printf("__LINE__=%d __FILE__=%s\n", __LINE__, __FILE__);
+#line 2222 "test"
+ printf("__LINE__=%d __FILE__=%s\n", __LINE__, __FILE__);
+#endif
+}
+
+#define RUN(test) puts("---- " #test " ----"), test(), puts("")
+
+int main(int argc, char **argv)
+{
+ RUN(whitespace_test);
+ RUN(macro_test);
+ RUN(recursive_macro_test);
+ RUN(string_test);
+ RUN(expr_test);
+ RUN(scope_test);
+ RUN(scope2_test);
+ RUN(forward_test);
+ RUN(funcptr_test);
+ RUN(if_test);
+ RUN(loop_test);
+ RUN(switch_test);
+ RUN(goto_test);
+ RUN(enum_test);
+ RUN(typedef_test);
+ RUN(struct_test);
+ RUN(array_test);
+ RUN(expr_ptr_test);
+ RUN(bool_test);
+ RUN(optimize_out_test);
+ RUN(expr2_test);
+ RUN(constant_expr_test);
+ RUN(expr_cmp_test);
+ RUN(char_short_test);
+ RUN(init_test);
+ RUN(compound_literal_test);
+ RUN(kr_test);
+ RUN(struct_assign_test);
+ RUN(cast_test);
+ RUN(bitfield_test);
+ RUN(c99_bool_test);
+ RUN(float_test);
+ RUN(longlong_test);
+ RUN(manyarg_test);
+ RUN(stdarg_test);
+ RUN(relocation_test);
+ RUN(old_style_function_test);
+ RUN(alloca_test);
+ RUN(c99_vla_test);
+ RUN(sizeof_test);
+ RUN(typeof_test);
+ RUN(statement_expr_test);
+ RUN(local_label_test);
+ RUN(asm_test);
+ RUN(builtin_test);
+ RUN(weak_test);
+ RUN(global_data_test);
+ RUN(cmp_comparison_test);
+ RUN(math_cmp_test);
+ RUN(callsave_test);
+ RUN(builtin_frame_address_test);
+ RUN(volatile_test);
+ RUN(attrib_test);
+ RUN(bounds_check1_test);
+
+ return 0;
+}
diff --git a/tests/tests2/03_struct.c b/tests/tests2/03_struct.c
index c5d48c5..fd73133 100644
--- a/tests/tests2/03_struct.c
+++ b/tests/tests2/03_struct.c
@@ -1,6 +1,13 @@
-#include <stdio.h>
+extern int printf(const char*, ...);
-struct fred
+struct fred;
+
+void fred$(struct fred* this)
+{
+ printf("~fred()\n");
+}
+
+struct __attribute__((__cleanup__(fred$))) fred
{
int boris;
int natasha;
@@ -8,7 +15,7 @@ struct fred
int main()
{
- struct fred bloggs;
+ struct fred __attribute__((__cleanup__(fred$))) bloggs;
bloggs.boris = 12;
bloggs.natasha = 34;
diff --git a/tests/tests2/03_struct.expect b/tests/tests2/03_struct.expect
index ecbf589..be8df37 100644
--- a/tests/tests2/03_struct.expect
+++ b/tests/tests2/03_struct.expect
@@ -1,6 +1,8 @@
+03_struct.c:14: warning: attribute '__cleanup__' ignored on type
12
34
12
34
56
78
+~fred()
diff --git a/tests/tests2/07_function.c b/tests/tests2/07_function.c
index 0477ce1..006e0a7 100644
--- a/tests/tests2/07_function.c
+++ b/tests/tests2/07_function.c
@@ -15,6 +15,11 @@ void qfunc()
printf("qfunc()\n");
}
+void zfunc()
+{
+ ((void (*)(void))0) ();
+}
+
int main()
{
printf("%d\n", myfunc(3));
diff --git a/tests/tests2/100_c99array-decls.c b/tests/tests2/100_c99array-decls.c
new file mode 100644
index 0000000..46950aa
--- /dev/null
+++ b/tests/tests2/100_c99array-decls.c
@@ -0,0 +1,34 @@
+void foo(int [5]);
+void fooc(int x[const 5]);
+void foos(int x[static 5]);
+void foov(int x[volatile 5]);
+void foor(int x[restrict 5]);
+void fooc(int [const 5]);
+void foos(int [static 5]);
+void foov(int [volatile 5]);
+void foor(int [restrict 5]);
+void fooc(int (* const x));
+void foos(int *x);
+void foov(int * volatile x);
+void foor(int * restrict x);
+void fooc(int x[volatile 5])
+{
+ x[3] = 42;
+#ifdef INVALID
+ x = 0;
+#endif
+}
+void foovm(int x[const *]);
+void foovm(int * const x);
+#ifdef INVALID
+void wrongc(int x[3][const 4]);
+void wrongvm(int x[static *]);
+void foovm(int x[const *])
+{
+ x[2] = 1;
+}
+#endif
+int main()
+{
+ return 0;
+}
diff --git a/tests/tests2/100_c99array-decls.expect b/tests/tests2/100_c99array-decls.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/tests2/100_c99array-decls.expect
diff --git a/tests/tests2/101_cleanup.c b/tests/tests2/101_cleanup.c
new file mode 100644
index 0000000..de5dca2
--- /dev/null
+++ b/tests/tests2/101_cleanup.c
@@ -0,0 +1,227 @@
+extern int printf(const char*, ...);
+static int glob_i = 0;
+
+void incr_glob_i(int *i)
+{
+ glob_i += *i;
+}
+
+#define INCR_GI { \
+ int i __attribute__ ((__cleanup__(incr_glob_i))) = 1; \
+ }
+
+#define INCR_GI0 INCR_GI INCR_GI INCR_GI INCR_GI
+#define INCR_GI1 INCR_GI0 INCR_GI0 INCR_GI0 INCR_GI0
+#define INCR_GI2 INCR_GI1 INCR_GI1 INCR_GI1 INCR_GI1
+#define INCR_GI3 INCR_GI2 INCR_GI2 INCR_GI2 INCR_GI2
+#define INCR_GI4 INCR_GI3 INCR_GI3 INCR_GI3 INCR_GI3
+#define INCR_GI5 INCR_GI4 INCR_GI4 INCR_GI4 INCR_GI4
+#define INCR_GI6 INCR_GI5 INCR_GI5 INCR_GI5 INCR_GI5
+#define INCR_GI7 INCR_GI6 INCR_GI6 INCR_GI6 INCR_GI6
+
+
+void check2(char **hum);
+
+void check(int *j)
+{
+ char * __attribute__ ((cleanup(check2))) stop_that = "wololo";
+ int chk = 0;
+
+ {
+ char * __attribute__ ((cleanup(check2))) stop_that = "plop";
+
+ {
+ non_plopage:
+ printf("---- %d\n", chk);
+ }
+ if (!chk) {
+ chk = 1;
+ goto non_plopage;
+ }
+ }
+
+ {
+ char * __attribute__ ((cleanup(check2))) stop_that = "tata !";
+
+ goto out;
+ stop_that = "titi";
+ }
+ again:
+ chk = 2;
+ {
+ char * __attribute__ ((cleanup(check2))) cascade1 = "1";
+ {
+ char * __attribute__ ((cleanup(check2))) cascade2 = "2";
+ {
+ char * __attribute__ ((cleanup(check2))) cascade3 = "3";
+
+ goto out;
+ cascade3 = "nope";
+ }
+ }
+ }
+ out:
+ if (chk != 2)
+ goto again;
+ {
+ {
+ char * __attribute__ ((cleanup(check2))) out = "last goto out";
+ ++chk;
+ if (chk != 3)
+ goto out;
+ }
+ }
+ return;
+}
+
+void check_oh_i(char *oh_i)
+{
+ printf("c: %c\n", *oh_i);
+}
+
+void goto_hell(double *f)
+{
+ printf("oo: %f\n", *f);
+}
+
+char *test()
+{
+ char *__attribute__ ((cleanup(check2))) str = "I don't think this should be print(but gcc got it wrong too)";
+
+ return str;
+}
+
+void test_ret_subcall(char *that)
+{
+ printf("should be print before\n");
+}
+
+void test_ret()
+{
+ char *__attribute__ ((cleanup(check2))) that = "that";
+ return test_ret_subcall(that);
+}
+
+void test_ret2()
+{
+ char *__attribute__ ((cleanup(check2))) that = "-that";
+ {
+ char *__attribute__ ((cleanup(check2))) that = "this should appear only once";
+ }
+ {
+ char *__attribute__ ((cleanup(check2))) that = "-that2";
+ return;
+ }
+}
+
+void test2(void) {
+ int chk = 0;
+again:
+ if (!chk) {
+ char * __attribute__ ((cleanup(check2))) stop_that = "test2";
+ chk++;
+ goto again;
+ }
+}
+
+int test3(void) {
+ char * __attribute__ ((cleanup(check2))) stop_that = "three";
+ int chk = 0;
+
+ if (chk) {
+ {
+ outside:
+ {
+ char * __attribute__ ((cleanup(check2))) stop_that = "two";
+ printf("---- %d\n", chk);
+ }
+ }
+ }
+ if (!chk)
+ {
+ char * __attribute__ ((cleanup(check2))) stop_that = "one";
+
+ if (!chk) {
+ chk = 1;
+ goto outside;
+ }
+ }
+ return 0;
+}
+
+void cl(int *ip)
+{
+ printf("%d\n", *ip);
+}
+
+void loop_cleanups(void)
+{
+ __attribute__((cleanup(cl))) int l = 1000;
+
+ printf("-- loop 0 --\n");
+ for ( __attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
+ __attribute__((cleanup(cl))) int j = 100;
+ }
+
+ printf("-- loop 1 --\n");
+ for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
+ __attribute__((cleanup(cl))) int j = 200;
+ continue;
+ }
+
+ printf("-- loop 2 --\n");
+ for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
+ __attribute__((cleanup(cl))) int j = 300;
+ break;
+ }
+
+ printf("-- loop 3 --\n");
+ for (int i = 0; i < 2; ++i) {
+ __attribute__((cleanup(cl))) int j = 400;
+ switch (i) {
+ case 0:
+ continue;
+ default:
+ {
+ __attribute__((cleanup(cl))) int jj = 500;
+ break;
+ }
+ }
+ }
+ printf("after break\n");
+}
+
+int main()
+{
+ int i __attribute__ ((__cleanup__(check))) = 0, not_i;
+ int chk = 0;
+ (void)not_i;
+
+ {
+ __attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a';
+ }
+
+ INCR_GI7;
+ printf("glob_i: %d\n", glob_i);
+ naaaaaaaa:
+ if (!chk) {
+ __attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'f';
+ double __attribute__ ((__cleanup__(goto_hell))) f = 2.6;
+
+ chk = 1;
+ goto naaaaaaaa;
+ }
+ i = 105;
+ printf("because what if free was call inside cleanup function %s\n", test());
+ test_ret();
+ test_ret2();
+ test2();
+ test3();
+ loop_cleanups();
+ return i;
+}
+
+void check2(char **hum)
+{
+ printf("str: %s\n", *hum);
+}
diff --git a/tests/tests2/101_cleanup.expect b/tests/tests2/101_cleanup.expect
new file mode 100644
index 0000000..84960cd
--- /dev/null
+++ b/tests/tests2/101_cleanup.expect
@@ -0,0 +1,59 @@
+c: a
+c: o
+glob_i: 65536
+oo: 2.600000
+c: f
+str: I don't think this should be print(but gcc got it wrong too)
+because what if free was call inside cleanup function I don't think this should be print(but gcc got it wrong too)
+should be print before
+str: that
+str: this should appear only once
+str: -that2
+str: -that
+str: test2
+str: one
+---- 1
+str: two
+str: three
+-- loop 0 --
+100
+100
+100
+100
+100
+100
+100
+100
+100
+100
+10
+-- loop 1 --
+200
+200
+200
+200
+200
+200
+200
+200
+200
+200
+10
+-- loop 2 --
+300
+0
+-- loop 3 --
+400
+500
+400
+after break
+1000
+---- 0
+---- 1
+str: plop
+str: tata !
+str: 3
+str: 2
+str: 1
+str: last goto out
+str: wololo
diff --git a/tests/tests2/102_alignas.c b/tests/tests2/102_alignas.c
new file mode 100644
index 0000000..62d3ed2
--- /dev/null
+++ b/tests/tests2/102_alignas.c
@@ -0,0 +1,29 @@
+_Alignas(16) int i1;
+int _Alignas(16) i2;
+void _Alignas(16) *p2;
+_Alignas(16) i3;
+int _Alignas(double) i4;
+int _Alignas(int) i5;
+#if 0
+/* The following are currently wrongly accepted by TCC but really shouldn't. */
+int _Alignas(int _Alignas(16)) i6; //wrong, 'int _Alignas(16)' is no type-name
+typedef int _Alignas(16) int16aligned_t; //wrong, _Alignas invalid on typedef
+int16aligned_t i7;
+#endif
+/* i8 should get an alignment of 16, because unlike _Alignas the
+ corresponding attribute _does_ apply to type-name, though not in
+ some clang versions. */
+int _Alignas(int __attribute__((aligned(16)))) i8;
+extern int printf(const char*, ...);
+#ifdef _MSC_VER
+#define alignof(x) (int)__alignof(x)
+#else
+#define alignof(x) (int)__alignof__(x)
+#endif
+int main()
+{
+ printf("%d %d %d %d\n",
+ alignof(i1) == 16, alignof(i4) == alignof(double),
+ alignof(i5) == alignof(int) , alignof(i8) == 16);
+ return 0;
+}
diff --git a/tests/tests2/102_alignas.expect b/tests/tests2/102_alignas.expect
new file mode 100644
index 0000000..ac6474a
--- /dev/null
+++ b/tests/tests2/102_alignas.expect
@@ -0,0 +1 @@
+1 1 1 1
diff --git a/tests/tests2/103_implicit_memmove.c b/tests/tests2/103_implicit_memmove.c
new file mode 100644
index 0000000..1592fb2
--- /dev/null
+++ b/tests/tests2/103_implicit_memmove.c
@@ -0,0 +1,20 @@
+/* Test that the memmove TCC is emitting for the struct copy
+ and hence implicitely declares can be declared properly also
+ later. */
+struct S { int a,b,c,d, e[1024];};
+int foo (struct S *a, struct S *b)
+{
+ *a = *b;
+ return 0;
+}
+
+void *memmove(void*,const void*,__SIZE_TYPE__);
+void foo2 (struct S *a, struct S *b)
+{
+ memmove(a, b, sizeof *a);
+}
+
+int main()
+{
+ return 0;
+}
diff --git a/tests/tests2/103_implicit_memmove.expect b/tests/tests2/103_implicit_memmove.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/tests2/103_implicit_memmove.expect
diff --git a/tests/tests2/104+_inline.c b/tests/tests2/104+_inline.c
new file mode 100644
index 0000000..1209fd4
--- /dev/null
+++ b/tests/tests2/104+_inline.c
@@ -0,0 +1,54 @@
+
+#define GOT(f) \
+ __attribute__((weak)) void f(void); \
+ printf("%d %s\n", !!f, #f);
+
+int printf(const char*, ...);
+
+void check_exports()
+{
+ // 0
+ GOT(inline_inline_2decl_only)
+ GOT(inline_inline_undeclared)
+ GOT(inline_inline_predeclared)
+ GOT(inline_inline_postdeclared)
+ GOT(inline_inline_prepostdeclared)
+ GOT(inline_inline_undeclared2)
+ GOT(inline_inline_predeclared2)
+ GOT(inline_inline_postdeclared2)
+ GOT(inline_inline_prepostdeclared2)
+
+ // 1
+ GOT(extern_extern_postdeclared)
+ GOT(extern_extern_postdeclared2)
+ GOT(extern_extern_predeclared)
+ GOT(extern_extern_predeclared2)
+ GOT(extern_extern_prepostdeclared)
+ GOT(extern_extern_prepostdeclared2)
+ GOT(extern_extern_undeclared)
+ GOT(extern_extern_undeclared2)
+ GOT(extern_postdeclared)
+ GOT(extern_postdeclared2)
+ GOT(extern_predeclared)
+ GOT(extern_predeclared2)
+ GOT(extern_prepostdeclared)
+ GOT(extern_undeclared)
+ GOT(extern_undeclared2)
+ GOT(inst2_extern_inline_postdeclared)
+ GOT(inst2_extern_inline_predeclared)
+ GOT(inst3_extern_inline_predeclared)
+ GOT(inst_extern_inline_postdeclared)
+ GOT(inst_extern_inline_predeclared)
+ GOT(main)
+ GOT(noinst_extern_inline_func)
+ GOT(noinst_extern_inline_postdeclared)
+ GOT(noinst_extern_inline_postdeclared2)
+ GOT(noinst_extern_inline_undeclared)
+
+ // 0
+ GOT(noinst_static_inline_postdeclared)
+ GOT(noinst2_static_inline_postdeclared)
+ GOT(noinst_static_inline_predeclared)
+ GOT(noinst2_static_inline_predeclared)
+ GOT(static_func)
+}
diff --git a/tests/tests2/104_inline.c b/tests/tests2/104_inline.c
new file mode 100644
index 0000000..766f94a
--- /dev/null
+++ b/tests/tests2/104_inline.c
@@ -0,0 +1,132 @@
+inline void inline_inline_2decl_only(void);
+inline void inline_inline_2decl_only(void);
+
+inline void inline_inline_undeclared(void){}
+
+inline void inline_inline_predeclared(void);
+inline void inline_inline_predeclared(void){}
+
+inline void inline_inline_postdeclared(void){}
+inline void inline_inline_postdeclared(void);
+
+inline void inline_inline_prepostdeclared(void);
+inline void inline_inline_prepostdeclared(void){}
+inline void inline_inline_prepostdeclared(void);
+
+inline void inline_inline_undeclared2(void){}
+
+inline void inline_inline_predeclared2(void);
+inline void inline_inline_predeclared2(void);
+inline void inline_inline_predeclared2(void){}
+
+inline void inline_inline_postdeclared2(void){}
+inline void inline_inline_postdeclared2(void);
+inline void inline_inline_postdeclared2(void);
+
+inline void inline_inline_prepostdeclared2(void);
+inline void inline_inline_prepostdeclared2(void);
+inline void inline_inline_prepostdeclared2(void){}
+inline void inline_inline_prepostdeclared2(void);
+inline void inline_inline_prepostdeclared2(void);
+
+extern void extern_extern_undeclared(void){}
+
+extern void extern_extern_predeclared(void);
+extern void extern_extern_predeclared(void){}
+
+extern void extern_extern_postdeclared(void){}
+extern void extern_extern_postdeclared(void);
+
+extern void extern_extern_prepostdeclared(void);
+extern void extern_extern_prepostdeclared(void){}
+extern void extern_extern_prepostdeclared(void);
+
+extern void extern_extern_undeclared2(void){}
+
+extern void extern_extern_predeclared2(void);
+extern void extern_extern_predeclared2(void);
+extern void extern_extern_predeclared2(void){}
+
+extern void extern_extern_postdeclared2(void){}
+extern void extern_extern_postdeclared2(void);
+extern void extern_extern_postdeclared2(void);
+
+extern void extern_extern_prepostdeclared2(void);
+extern void extern_extern_prepostdeclared2(void);
+extern void extern_extern_prepostdeclared2(void){}
+extern void extern_extern_prepostdeclared2(void);
+extern void extern_extern_prepostdeclared2(void);
+
+void extern_undeclared(void){}
+
+void extern_predeclared(void);
+void extern_predeclared(void){}
+
+void extern_postdeclared(void){}
+void extern_postdeclared(void);
+
+void extern_prepostdeclared(void);
+void extern_prepostdeclared(void){}
+void extern_prepostdeclared(void);
+
+void extern_undeclared2(void){}
+
+void extern_predeclared2(void);
+void extern_predeclared2(void);
+void extern_predeclared2(void){}
+
+void extern_postdeclared2(void){}
+void extern_postdeclared2(void);
+void extern_postdeclared2(void);
+
+
+extern inline void noinst_extern_inline_undeclared(void){}
+
+extern inline void noinst_extern_inline_postdeclared(void){}
+inline void noinst_extern_inline_postdeclared(void);
+
+extern inline void noinst_extern_inline_postdeclared2(void){}
+inline void noinst_extern_inline_postdeclared2(void);
+inline void noinst_extern_inline_postdeclared2(void);
+
+extern inline void inst_extern_inline_postdeclared(void){}
+extern inline void inst_extern_inline_postdeclared(void);
+inline void inst2_extern_inline_postdeclared(void){}
+void inst2_extern_inline_postdeclared(void);
+
+void inst_extern_inline_predeclared(void);
+extern inline void inst_extern_inline_predeclared(void){}
+void inst2_extern_inline_predeclared(void);
+inline void inst2_extern_inline_predeclared(void){}
+extern inline void inst3_extern_inline_predeclared(void);
+inline void inst3_extern_inline_predeclared(void){}
+
+static inline void noinst_static_inline_postdeclared(void){}
+static inline void noinst_static_inline_postdeclared(void);
+static inline void noinst2_static_inline_postdeclared(void){}
+static void noinst2_static_inline_postdeclared(void);
+
+static void noinst_static_inline_predeclared(void);
+static inline void noinst_static_inline_predeclared(void){}
+static void noinst2_static_inline_predeclared(void);
+static inline void noinst2_static_inline_predeclared(void){}
+
+static void static_func(void);
+void static_func(void) { }
+
+inline void noinst_extern_inline_func(void);
+void noinst_extern_inline_func(void) { }
+
+int main()
+{
+ inline_inline_undeclared(); inline_inline_predeclared(); inline_inline_postdeclared();
+ inline_inline_undeclared2(); inline_inline_predeclared2(); inline_inline_postdeclared2();
+ noinst_static_inline_predeclared();
+ noinst2_static_inline_predeclared();
+ noinst_static_inline_predeclared();
+ noinst2_static_inline_predeclared();
+
+ void check_exports();
+ check_exports();
+ return 0;
+}
diff --git a/tests/tests2/104_inline.expect b/tests/tests2/104_inline.expect
new file mode 100644
index 0000000..bdb0994
--- /dev/null
+++ b/tests/tests2/104_inline.expect
@@ -0,0 +1,39 @@
+0 inline_inline_2decl_only
+0 inline_inline_undeclared
+0 inline_inline_predeclared
+0 inline_inline_postdeclared
+0 inline_inline_prepostdeclared
+0 inline_inline_undeclared2
+0 inline_inline_predeclared2
+0 inline_inline_postdeclared2
+0 inline_inline_prepostdeclared2
+1 extern_extern_postdeclared
+1 extern_extern_postdeclared2
+1 extern_extern_predeclared
+1 extern_extern_predeclared2
+1 extern_extern_prepostdeclared
+1 extern_extern_prepostdeclared2
+1 extern_extern_undeclared
+1 extern_extern_undeclared2
+1 extern_postdeclared
+1 extern_postdeclared2
+1 extern_predeclared
+1 extern_predeclared2
+1 extern_prepostdeclared
+1 extern_undeclared
+1 extern_undeclared2
+1 inst2_extern_inline_postdeclared
+1 inst2_extern_inline_predeclared
+1 inst3_extern_inline_predeclared
+1 inst_extern_inline_postdeclared
+1 inst_extern_inline_predeclared
+1 main
+1 noinst_extern_inline_func
+1 noinst_extern_inline_postdeclared
+1 noinst_extern_inline_postdeclared2
+1 noinst_extern_inline_undeclared
+0 noinst_static_inline_postdeclared
+0 noinst2_static_inline_postdeclared
+0 noinst_static_inline_predeclared
+0 noinst2_static_inline_predeclared
+0 static_func
diff --git a/tests/tests2/105_local_extern.c b/tests/tests2/105_local_extern.c
new file mode 100644
index 0000000..a248bb4
--- /dev/null
+++ b/tests/tests2/105_local_extern.c
@@ -0,0 +1,12 @@
+extern int printf(const char *, ...);
+void f(void);
+void bar(void) { void f(void); f(); }
+void foo(void) { extern void f(void); f(); }
+void f(void) { printf("f\n"); }
+
+int main()
+{
+ bar();
+ foo();
+ return 0;
+}
diff --git a/tests/tests2/105_local_extern.expect b/tests/tests2/105_local_extern.expect
new file mode 100644
index 0000000..445ae74
--- /dev/null
+++ b/tests/tests2/105_local_extern.expect
@@ -0,0 +1,2 @@
+f
+f
diff --git a/tests/tests2/106_pthread.c b/tests/tests2/106_pthread.c
new file mode 100644
index 0000000..09308ed
--- /dev/null
+++ b/tests/tests2/106_pthread.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <pthread.h>
+#include <errno.h>
+
+int
+main(void)
+{
+ int ret;
+ pthread_condattr_t attr;
+ pthread_cond_t condition;
+
+ pthread_condattr_init (&attr);
+ pthread_condattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
+ printf ("%s\n", pthread_cond_init (&condition, &attr) ? "fail":"ok");
+ pthread_condattr_destroy (&attr);
+ return 0;
+}
diff --git a/tests/tests2/106_pthread.expect b/tests/tests2/106_pthread.expect
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/tests/tests2/106_pthread.expect
@@ -0,0 +1 @@
+ok
diff --git a/tests/tests2/107_stack_safe.c b/tests/tests2/107_stack_safe.c
new file mode 100644
index 0000000..479c84d
--- /dev/null
+++ b/tests/tests2/107_stack_safe.c
@@ -0,0 +1,13 @@
+extern int printf(const char *, ...);
+
+static void func_ull_ull(unsigned long long l1,unsigned long long l2){
+}
+
+int main()
+{
+ int a,b,c,d;
+ a=1;b=2;c=3;d=4;
+ func_ull_ull((unsigned long long)a/1.0,(unsigned long long)b/1.0);
+ printf("%d %d %d %d",a,b,c,d);
+ return 0;
+}
diff --git a/tests/tests2/107_stack_safe.expect b/tests/tests2/107_stack_safe.expect
new file mode 100644
index 0000000..e9e9cd7
--- /dev/null
+++ b/tests/tests2/107_stack_safe.expect
@@ -0,0 +1 @@
+1 2 3 4 \ No newline at end of file
diff --git a/tests/tests2/108_constructor.c b/tests/tests2/108_constructor.c
new file mode 100644
index 0000000..145d0da
--- /dev/null
+++ b/tests/tests2/108_constructor.c
@@ -0,0 +1,20 @@
+extern int write (int fd, void *buf, int len);
+
+static void __attribute__ ((constructor))
+testc (void)
+{
+ write (1, "constructor\n", 12);
+}
+
+static void __attribute__ ((destructor))
+testd (void)
+{
+ write (1, "destructor\n", 11);
+}
+
+int
+main (void)
+{
+ write (1, "main\n", 5);
+ return 0;
+}
diff --git a/tests/tests2/108_constructor.expect b/tests/tests2/108_constructor.expect
new file mode 100644
index 0000000..167ca51
--- /dev/null
+++ b/tests/tests2/108_constructor.expect
@@ -0,0 +1,3 @@
+constructor
+main
+destructor
diff --git a/tests/tests2/109_float_struct_calling.c b/tests/tests2/109_float_struct_calling.c
new file mode 100644
index 0000000..90fc045
--- /dev/null
+++ b/tests/tests2/109_float_struct_calling.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+/* This test used to fail on x86_64 on linux with sse registers */
+
+struct Point {
+ float x;
+ float y;
+};
+
+struct Rect {
+ struct Point top_left;
+ struct Point size;
+};
+
+float foo(struct Point p, struct Rect r) {
+ return r.size.x;
+}
+
+int main(int argc, char **argv) {
+ struct Point p = {1, 2};
+ struct Rect r = {{3, 4}, {5, 6}};
+ printf("%f\n", foo(p, r));
+ return 0;
+}
diff --git a/tests/tests2/109_float_struct_calling.expect b/tests/tests2/109_float_struct_calling.expect
new file mode 100644
index 0000000..eaa6787
--- /dev/null
+++ b/tests/tests2/109_float_struct_calling.expect
@@ -0,0 +1 @@
+5.000000
diff --git a/tests/tests2/110_average.c b/tests/tests2/110_average.c
new file mode 100644
index 0000000..273b511
--- /dev/null
+++ b/tests/tests2/110_average.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+
+typedef struct
+{
+ double average;
+ int count;
+}
+stats_type;
+
+static void
+testc (stats_type *s, long long data)
+{
+ s->average = (s->average * s->count + data) / (s->count + 1);
+ s->count++;
+}
+
+int main (void)
+{
+ stats_type s;
+
+ s.average = 0;
+ s.count = 0;
+ testc (&s, 10);
+ testc (&s, 20);
+ printf ("%g %d\n", s.average, s.count);
+ return 0;
+}
diff --git a/tests/tests2/110_average.expect b/tests/tests2/110_average.expect
new file mode 100644
index 0000000..4955335
--- /dev/null
+++ b/tests/tests2/110_average.expect
@@ -0,0 +1 @@
+15 2
diff --git a/tests/tests2/111_conversion.c b/tests/tests2/111_conversion.c
new file mode 100644
index 0000000..c0815e1
--- /dev/null
+++ b/tests/tests2/111_conversion.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+union u {
+ unsigned long ul;
+ long double ld;
+};
+
+void
+conv (union u *p)
+{
+ p->ul = (unsigned int) p->ld;
+}
+
+int main (void)
+{
+ union u v;
+
+ v.ld = 42;
+ conv (&v);
+ printf ("%lu\n", v.ul);
+ return 0;
+}
diff --git a/tests/tests2/111_conversion.expect b/tests/tests2/111_conversion.expect
new file mode 100644
index 0000000..d81cc07
--- /dev/null
+++ b/tests/tests2/111_conversion.expect
@@ -0,0 +1 @@
+42
diff --git a/tests/tests2/112_backtrace.c b/tests/tests2/112_backtrace.c
new file mode 100644
index 0000000..8489bd3
--- /dev/null
+++ b/tests/tests2/112_backtrace.c
@@ -0,0 +1,165 @@
+#include <stdio.h>
+
+/* ------------------------------------------------------- */
+#if defined test_backtrace_1
+
+void f3()
+{
+ printf("* f3()\n"), fflush(stdout);
+ *(void**)0 = 0;
+}
+void f2()
+{
+ printf("* f2()\n"), fflush(stdout);
+ f3();
+}
+void f1()
+{
+ printf("* f1()\n"), fflush(stdout);
+ f2();
+}
+int main(int argc, char **argv)
+{
+ printf("* main\n"), fflush(stdout);
+ f1();
+ printf("* exit main\n"), fflush(stdout);
+ return 0;
+}
+
+/* ------------------------------------------------------- */
+#elif defined test_bcheck_1
+
+struct s { int a,b,c,d,e; };
+struct s s[3];
+struct s *ps = s;
+void f1()
+{
+ printf("* f1()\n"), fflush(stdout);
+ ps[3] = ps[2];
+}
+int main(int argc, char **argv)
+{
+ printf("* main\n"), fflush(stdout);
+ f1();
+ printf("* exit main\n"), fflush(stdout);
+ return 0;
+}
+
+/* ------------------------------------------------------- */
+#elif defined test_tcc_backtrace_2
+
+/* test custom backtrace and 'exit()' redirection */
+int tcc_backtrace(const char *fmt, ...);
+void exit(int);
+
+void f2()
+{
+ printf("* f2()\n");
+ printf("* exit f2\n"), fflush(stdout);
+ exit(34);
+}
+void f1()
+{
+ printf("* f1()\n"), fflush(stdout);
+ tcc_backtrace("Hello from %s!", "f1");
+ f2();
+}
+int main(int argc, char **argv)
+{
+ printf("* main\n"), fflush(stdout);
+ f1();
+ printf("* exit main\n"), fflush(stdout);
+ return 0;
+}
+
+/* ------------------------------------------------------- */
+#elif defined test_tcc_backtrace_3
+
+/* this test should be run despite of the exit(34) above */
+int main(int argc, char **argv)
+{
+ printf("* main\n"), fflush(stdout);
+ return 1;
+}
+
+/* ------------------------------------------------------- */
+#else
+#include <stdlib.h>
+#include <string.h>
+char *strdup();
+int main()
+{
+ char pad1[10];
+ char a[10];
+ char pad2[10];
+ char b[10];
+ char pad3[10];
+ memset (pad1, 0, sizeof(pad1));
+ memset (pad2, 0, sizeof(pad2));
+ memset (pad3, 0, sizeof(pad3));
+
+ memset (a, 'a', 10);
+ a[3] = 0;
+ a[9] = 0;
+ memset (b, 'b', 10);
+
+#if defined test_bcheck_100
+ memcpy(&a[1],&b[0],10);
+#elif defined test_bcheck_101
+ memcpy(&a[0],&b[1],10);
+#elif defined test_bcheck_102
+ memcpy(&a[0],&a[3],4);
+#elif defined test_bcheck_103
+ memcpy(&a[3],&a[0],4);
+#elif defined test_bcheck_104
+ memcmp(&b[1],&b[0],10);
+#elif defined test_bcheck_105
+ memcmp(&b[0],&b[1],10);
+#elif defined test_bcheck_106
+ memmove(&b[1],&b[0],10);
+#elif defined test_bcheck_107
+ memmove(&b[0],&b[1],10);
+#elif defined test_bcheck_108
+ memset(&b[1],'b',10);
+#elif defined test_bcheck_109
+ strlen(&b[0]);
+#elif defined test_bcheck_110
+ strcpy(&a[7], &a[0]);
+#elif defined test_bcheck_111
+ strcpy(&a[0], &b[7]);
+#elif defined test_bcheck_112
+ strcpy(&a[0], &a[1]);
+#elif defined test_bcheck_113
+ strcpy(&a[2], &a[0]);
+#elif defined test_bcheck_114
+ strncpy(&a[7], &a[0], 10);
+#elif defined test_bcheck_115
+ strncpy(&a[0], &b[7], 10);
+#elif defined test_bcheck_116
+ strncpy(&a[0], &a[1], 10);
+#elif defined test_bcheck_117
+ strncpy(&a[2], &a[0], 10);
+#elif defined test_bcheck_118
+ strcmp(&b[2], &b[0]);
+#elif defined test_bcheck_119
+ strcmp(&b[0], &b[2]);
+#elif defined test_bcheck_120
+ strncmp(&b[5], &b[0], 10);
+#elif defined test_bcheck_121
+ strncmp(&b[0], &b[5], 10);
+#elif defined test_bcheck_122
+ strcat(&a[7], &a[0]);
+#elif defined test_bcheck_123
+ strcat(&a[0], &b[3]);
+#elif defined test_bcheck_124
+ strcat(&a[0], &a[4]);
+#elif defined test_bcheck_125
+ strcat(&a[3], &a[0]);
+#elif defined test_bcheck_126
+ strchr(&b[0], 'a');
+#elif defined test_bcheck_127
+ free(strdup(&b[0]));
+#endif
+}
+/* ------------------------------------------------------- */
+#endif
diff --git a/tests/tests2/112_backtrace.expect b/tests/tests2/112_backtrace.expect
new file mode 100644
index 0000000..68986c6
--- /dev/null
+++ b/tests/tests2/112_backtrace.expect
@@ -0,0 +1,142 @@
+[test_backtrace_1]
+* main
+* f1()
+* f2()
+* f3()
+112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access
+112_backtrace.c:14: by f2
+112_backtrace.c:19: by f1
+112_backtrace.c:24: by main
+[returns 255]
+
+[test_bcheck_1]
+* main
+* f1()
+112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest
+112_backtrace.c:43: by main
+[returns 255]
+
+[test_tcc_backtrace_2]
+* main
+* f1()
+112_backtrace.c:64: at f1: Hello from f1!
+112_backtrace.c:70: by main
+* f2()
+* exit f2
+[returns 34]
+
+[test_tcc_backtrace_3]
+* main
+[returns 1]
+
+[test_bcheck_100]
+112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest
+[returns 255]
+
+[test_bcheck_101]
+112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src
+[returns 255]
+
+[test_bcheck_102]
+112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy
+[returns 255]
+
+[test_bcheck_103]
+112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy
+[returns 255]
+
+[test_bcheck_104]
+112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1
+[returns 255]
+
+[test_bcheck_105]
+112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2
+[returns 255]
+
+[test_bcheck_106]
+112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest
+[returns 255]
+
+[test_bcheck_107]
+112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src
+[returns 255]
+
+[test_bcheck_108]
+112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset
+[returns 255]
+
+[test_bcheck_109]
+112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen
+[returns 255]
+
+[test_bcheck_110]
+112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest
+[returns 255]
+
+[test_bcheck_111]
+112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src
+[returns 255]
+
+[test_bcheck_112]
+112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy
+[returns 255]
+
+[test_bcheck_113]
+112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy
+[returns 255]
+
+[test_bcheck_114]
+112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest
+[returns 255]
+
+[test_bcheck_115]
+112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src
+[returns 255]
+
+[test_bcheck_116]
+112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy
+[returns 255]
+
+[test_bcheck_117]
+112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy
+[returns 255]
+
+[test_bcheck_118]
+112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1
+[returns 255]
+
+[test_bcheck_119]
+112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2
+[returns 255]
+
+[test_bcheck_120]
+112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1
+[returns 255]
+
+[test_bcheck_121]
+112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2
+[returns 255]
+
+[test_bcheck_122]
+112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
+[returns 255]
+
+[test_bcheck_123]
+112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
+[returns 255]
+
+[test_bcheck_124]
+112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat
+[returns 255]
+
+[test_bcheck_125]
+112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat
+[returns 255]
+
+[test_bcheck_126]
+112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr
+[returns 255]
+
+[test_bcheck_127]
+112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup
+[returns 255]
diff --git a/tests/tests2/113_btdll.c b/tests/tests2/113_btdll.c
new file mode 100644
index 0000000..8ae8981
--- /dev/null
+++ b/tests/tests2/113_btdll.c
@@ -0,0 +1,43 @@
+int tcc_backtrace(const char*, ...);
+#define hello() \
+ tcc_backtrace("hello from %s() / %s:%d",__FUNCTION__,__FILE__,__LINE__)
+
+#ifndef _WIN32
+# define __declspec(n)
+#endif
+
+#if DLL==1
+__declspec(dllexport) int f_1()
+{
+ hello();
+ return 0;
+}
+
+
+#elif DLL==2
+__declspec(dllexport) int f_2()
+{
+ hello();
+ return 0;
+}
+
+
+#else
+
+int f_1();
+int f_2();
+int f_main()
+{
+ hello();
+ return 0;
+}
+
+int main ()
+{
+ f_1();
+ f_2();
+ f_main();
+ return 0;
+}
+
+#endif
diff --git a/tests/tests2/113_btdll.expect b/tests/tests2/113_btdll.expect
new file mode 100644
index 0000000..34de481
--- /dev/null
+++ b/tests/tests2/113_btdll.expect
@@ -0,0 +1,6 @@
+113_btdll.c:12: at f_1: hello from f_1() / 113_btdll.c:12
+113_btdll.c:37: by main
+113_btdll.c:20: at f_2: hello from f_2() / 113_btdll.c:20
+113_btdll.c:38: by main
+113_btdll.c:31: at f_main: hello from f_main() / 113_btdll.c:31
+113_btdll.c:39: by main
diff --git a/tests/tests2/114_bound_signal.c b/tests/tests2/114_bound_signal.c
new file mode 100644
index 0000000..d7d7feb
--- /dev/null
+++ b/tests/tests2/114_bound_signal.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <setjmp.h>
+
+/* See tcc-doc.info */
+#if defined(__TINYC__) && __BOUNDS_CHECKING_ON
+#undef __attribute__
+extern void __bound_checking (int no_check);
+#define BOUNDS_CHECKING_OFF __bound_checking(1)
+#define BOUNDS_CHECKING_ON __bound_checking(-1)
+#define BOUNDS_NO_CHECKING __attribute__((bound_no_checking))
+#else
+#define BOUNDS_CHECKING_OFF
+#define BOUNDS_CHECKING_ON
+#define BOUNDS_NO_CHECKING
+#endif
+
+static volatile int run = 1;
+static int dummy[10];
+static sem_t sem;
+
+static void
+add (void) BOUNDS_NO_CHECKING
+{
+ int i;
+
+ for (i = 0; i < (sizeof(dummy)/sizeof(dummy[0])); i++) {
+ dummy[i]++;
+ }
+ /* Should not be translated into __bound_memset */
+ memset (&dummy[0], 0, sizeof(dummy));
+}
+
+static void *
+high_load (void *unused)
+{
+ while (run) {
+ add();
+ }
+ return NULL;
+}
+
+static void *
+do_signal (void *unused)
+{
+ while (run) {
+ kill (getpid(), SIGUSR1);
+ while (sem_wait(&sem) < 0 && errno == EINTR);
+ }
+ return NULL;
+}
+
+static void signal_handler(int sig) BOUNDS_NO_CHECKING
+{
+ add();
+ sem_post (&sem);
+}
+
+int
+main (void)
+{
+ int i;
+ pthread_t id1, id2;
+ struct sigaction act;
+ sigjmp_buf sj;
+ sigset_t m;
+ time_t end;
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = signal_handler;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ sigaction (SIGUSR1, &act, NULL);
+
+ sem_init (&sem, 1, 0);
+ pthread_create(&id1, NULL, high_load, NULL);
+ pthread_create(&id2, NULL, do_signal, NULL);
+
+ printf ("start\n");
+ /* sleep does not work !!! */
+ end = time(NULL) + 2;
+ while (time(NULL) < end) ;
+ run = 0;
+ printf ("end\n");
+
+ pthread_join(id1, NULL);
+ pthread_join(id2, NULL);
+ sem_destroy (&sem);
+
+ sigemptyset (&m);
+ sigprocmask (SIG_SETMASK, &m, NULL);
+ if (sigsetjmp (sj, 0) == 0)
+ {
+ sigaddset (&m, SIGUSR1);
+ sigprocmask (SIG_SETMASK, &m, NULL);
+ siglongjmp (sj, 1);
+ printf ("failed");
+ return 1;
+ }
+ sigprocmask (SIG_SETMASK, NULL, &m);
+ if (!sigismember (&m, SIGUSR1))
+ printf ("failed");
+ return 0;
+}
diff --git a/tests/tests2/114_bound_signal.expect b/tests/tests2/114_bound_signal.expect
new file mode 100644
index 0000000..5d0fb3b
--- /dev/null
+++ b/tests/tests2/114_bound_signal.expect
@@ -0,0 +1,2 @@
+start
+end
diff --git a/tests/tests2/115_bound_setjmp.c b/tests/tests2/115_bound_setjmp.c
new file mode 100644
index 0000000..c402144
--- /dev/null
+++ b/tests/tests2/115_bound_setjmp.c
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+
+#define TST int i, a[2], b[2]; \
+ for (i = 0; i < 2; i++) a[i] = 0; \
+ for (i = 0; i < 2; i++) b[i] = 0
+
+static jmp_buf jmp;
+
+static void tst1 (void)
+{
+ TST;
+ longjmp(jmp, 1);
+}
+
+static void tst2(void)
+{
+ jmp_buf jmp;
+
+ setjmp (jmp);
+ TST;
+ tst1();
+}
+
+static void tst3 (jmp_buf loc)
+{
+ TST;
+ longjmp(loc, 1);
+}
+
+static void tst4(jmp_buf loc)
+{
+ jmp_buf jmp;
+
+ setjmp (jmp);
+ TST;
+ tst3(loc);
+}
+
+static void tst (void)
+{
+ jmp_buf loc;
+ static int cnt;
+
+ cnt = 0;
+ if (setjmp (jmp) == 0) {
+ TST;
+ tst2();
+ }
+ else {
+ cnt++;
+ }
+ if (setjmp (loc) == 0) {
+ TST;
+ tst4(loc);
+ }
+ else {
+ cnt++;
+ }
+ if (cnt != 2)
+ printf ("incorrect cnt %d\n", cnt);
+}
+
+static jmp_buf buf1;
+static jmp_buf buf2;
+static int *p;
+static int n_x = 6;
+static int g_counter;
+
+static void stack (void)
+{
+ static int counter;
+ static int way_point1;
+ static int way_point2;
+
+ counter = 0;
+ way_point1 = 3;
+ way_point2 = 2;
+ g_counter = 0;
+ if (setjmp (buf1) != 101) {
+ int a[n_x];
+ g_counter++;
+ p = &a[0];
+ if (g_counter < 5)
+ longjmp (buf1, 2);
+ else if (g_counter == 5)
+ longjmp (buf1, 101);
+ else {
+ setjmp (buf2);
+ longjmp (buf1, 101);
+ }
+ }
+
+ way_point1--;
+
+ if (counter == 0) {
+ counter++;
+ {
+ int a[n_x];
+ g_counter++;
+ p = &a[0];
+ if (g_counter < 5)
+ longjmp (buf1, 2);
+ else if (g_counter == 5)
+ longjmp (buf1, 101);
+ else {
+ setjmp (buf2);
+ longjmp (buf1, 101);
+ }
+ }
+ }
+
+ way_point2--;
+
+ if (counter == 1) {
+ counter++;
+ longjmp (buf2, 2);
+ }
+
+ if (!(way_point1 == 0 && way_point2 == 0 &&
+ g_counter == 6 && counter == 2))
+ printf ("Failed %d %d %d %d\n",
+ way_point1, way_point2, g_counter, counter);
+}
+
+static jmp_buf env;
+static int last_value;
+
+static void jump (int val)
+{
+ longjmp (env, val);
+}
+
+static void check (void)
+{
+ int value;
+
+ last_value = -1;
+ value = setjmp (env);
+ if (value != last_value + 1) {
+ printf ("incorrect value %d %d\n",
+ value, last_value + 1);
+ return;
+ }
+ last_value = value;
+ switch (value) {
+ case 0:
+ jump (0);
+ default:
+ if (value < 10)
+ jump (value + 1);
+ }
+}
+
+int
+main (void)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ tst();
+ stack();
+ check();
+ }
+ return 0;
+}
+
+
diff --git a/tests/tests2/115_bound_setjmp.expect b/tests/tests2/115_bound_setjmp.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/tests2/115_bound_setjmp.expect
diff --git a/tests/tests2/116_bound_setjmp2.c b/tests/tests2/116_bound_setjmp2.c
new file mode 100644
index 0000000..151114d
--- /dev/null
+++ b/tests/tests2/116_bound_setjmp2.c
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#if !defined(_WIN32)
+#include <pthread.h>
+#else
+#include <windows.h>
+#endif
+
+#define SIZE 10
+#define COUNT 10
+
+#define TST int i, a[2], b[2]; \
+ for (i = 0; i < 2; i++) a[i] = 0; \
+ for (i = 0; i < 2; i++) b[i] = 0
+
+static int count[SIZE];
+
+static void tst1 (jmp_buf loc)
+{
+ TST;
+ longjmp(loc, 1);
+}
+
+static void tst2(jmp_buf loc)
+{
+ jmp_buf jmp;
+
+ setjmp (jmp);
+ TST;
+ tst1(loc);
+}
+
+static void *tst (void * index)
+{
+ jmp_buf loc;
+ int i = *(int *) index;
+ static int v[SIZE];
+
+ for (v[i] = 0; v[i] < COUNT; v[i]++) {
+ if (setjmp (loc) == 0) {
+ TST;
+ tst2(loc);
+ }
+ else {
+ count[i]++;
+ }
+ i = *(int *) index;
+ }
+ return NULL;
+}
+
+int
+main (void)
+{
+ int i;
+#if !defined(_WIN32)
+ pthread_t id[SIZE];
+#else
+ HANDLE id[SIZE];
+#endif
+ int index[SIZE];
+
+ for (i = 0; i < SIZE; i++) {
+ index[i] = i;
+#if !defined(_WIN32)
+ pthread_create (&id[i], NULL, tst, (void *) &index[i]);
+#else
+ id[i] = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) tst, (void *) &index[i], 0, NULL);
+#endif
+ }
+ for (i = 0; i < SIZE; i++) {
+#if !defined(_WIN32)
+ pthread_join (id[i], NULL);
+#else
+ WaitForSingleObject(id[i], INFINITE);
+#endif
+ }
+ for (i = 0; i < SIZE; i++) {
+ if (count[i] != COUNT)
+ printf ("error: %d %d\n", i, count[i]);
+ }
+ return 0;
+}
diff --git a/tests/tests2/116_bound_setjmp2.expect b/tests/tests2/116_bound_setjmp2.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/tests2/116_bound_setjmp2.expect
diff --git a/tests/tests2/117_gcc_test.c b/tests/tests2/117_gcc_test.c
new file mode 100644
index 0000000..aed62e2
--- /dev/null
+++ b/tests/tests2/117_gcc_test.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+
+void tst_branch(void)
+{
+ goto *&&a;
+ printf ("dummy");
+a: ;
+}
+
+void tst_void_ptr(void *pv, int i)
+{
+ i ? *pv : *pv; // dr106
+}
+
+void tst_shift(void)
+{
+ int i = 1;
+ long l = 1;
+
+ i = i << 32; // illegal. just test
+ l = l << 64; // illegal. just test
+}
+
+#if !defined(_WIN32)
+#include <sys/mman.h>
+
+void tst_const_addr(void)
+{
+ void *addr = mmap ((void *)0x20000000, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+ if (addr != (void *) -1) {
+#if !defined(__riscv)
+ *(int *)0x20000000 += 42;
+#endif
+ munmap (addr, 4096);
+ }
+}
+#endif
+
+struct zero_struct {};
+
+struct zero_struct tst_zero_struct(void)
+{
+ struct zero_struct ret;
+
+ return ret;
+}
+
+struct big_struct { char a[262144]; };
+
+struct big_struct tst_big(struct big_struct tst)
+{
+ return tst;
+}
+
+void tst_adr (int (*fp)(char *, const char *, ...))
+{
+ char buf[10];
+
+ (*fp)(buf, "%.0f", 5.0);
+}
+
+static const char str[] = "abcdefghijklmnopqrstuvwxyz";
+
+void tst_builtin(void)
+{
+ char *p;
+ char tmp[100];
+
+ if (__builtin_offsetof(struct big_struct, a) != 0) __builtin_abort();
+
+ p = __builtin_memcpy (tmp, str, sizeof(str));
+ if (p != tmp) __builtin_abort();
+
+ if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort();
+
+ p = __builtin_memmove(tmp, str, sizeof(str));
+ if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort();
+
+ p = __builtin_memset(tmp, 0, sizeof (tmp));
+ if (p != tmp || tmp[0] != 0 || tmp[99] != 0) __builtin_abort();
+
+ if (__builtin_strlen(str) != sizeof(str) - 1) __builtin_abort();
+
+ p = __builtin_strcpy(tmp, str);
+ if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort();
+
+ p = __builtin_strncpy(tmp, str, sizeof(str));
+ if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort();
+
+ if (__builtin_strcmp (p, str)) __builtin_abort();
+
+ if (__builtin_strncmp (p, str, sizeof(str))) __builtin_abort();
+
+ tmp[0] = '\0';
+ p = __builtin_strcat(tmp, str);
+ if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort();
+
+ if (__builtin_strchr(p, 'z') != &p[25]) __builtin_abort();
+
+ p = __builtin_strdup (str);
+ if (__builtin_memcmp (p, str, sizeof(str))) __builtin_abort();
+ __builtin_free(p);
+
+ p = __builtin_malloc (100);
+ __builtin_memset(p, 0, 100);
+ p = __builtin_realloc (p, 1000);
+ __builtin_memset(p, 0, 1000);
+ __builtin_free(p);
+
+ p = __builtin_calloc(10, 10);
+ __builtin_memset(p, 0, 100);
+ __builtin_free(p);
+
+#if defined(__i386__) || defined(__x86_64__)
+ p = __builtin_alloca(100);
+ __builtin_memset(p, 0, 100);
+#endif
+}
+
+int tst(void)
+{
+ long value = 3;
+ return -value;
+}
+
+void tst_compare(void)
+{
+ /* This failed on risc64 */
+ if (tst() > 0) printf ("error\n");
+}
+
+#pragma pack(1)
+struct S { int d:24; int f:14; } i, j;
+#pragma pack()
+
+void tst_pack (void)
+{
+ i.f = 5; j.f = 5;
+ if (j.f != i.f) printf("error\n");
+}
+
+int
+main (void)
+{
+ struct big_struct big;
+
+ tst_shift();
+ tst_void_ptr(&big.a[0], 0);
+#if !defined(_WIN32)
+ tst_const_addr();
+#endif
+ tst_zero_struct();
+ tst_big(big);
+ tst_adr(&sprintf);
+ tst_builtin();
+ tst_compare();
+ tst_pack();
+}
diff --git a/tests/tests2/117_gcc_test.expect b/tests/tests2/117_gcc_test.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/tests2/117_gcc_test.expect
diff --git a/tests/tests2/11_precedence.c b/tests/tests2/11_precedence.c
index db2049d..845b6bf 100644
--- a/tests/tests2/11_precedence.c
+++ b/tests/tests2/11_precedence.c
@@ -1,4 +1,5 @@
-#include <stdio.h>
+//#include <stdio.h>
+extern int printf(const char *, ...);
int main()
{
diff --git a/tests/tests2/22_floating_point.c b/tests/tests2/22_floating_point.c
index e3491f5..2eb062c 100644
--- a/tests/tests2/22_floating_point.c
+++ b/tests/tests2/22_floating_point.c
@@ -1,6 +1,19 @@
#include <stdio.h>
#include <math.h>
+float fd;
+
+int
+test()
+{
+ // was an internal tcc compiler error with arm64 backend until 2019-11-08
+ if (fd < 5.5) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
int main()
{
// variables
diff --git a/tests/tests2/33_ternary_op.c b/tests/tests2/33_ternary_op.c
index 8579b50..1e6b56d 100644
--- a/tests/tests2/33_ternary_op.c
+++ b/tests/tests2/33_ternary_op.c
@@ -1,4 +1,43 @@
-#include <stdio.h>
+#include <assert.h>
+extern int printf(const char*, ...);
+
+char arr[1];
+static void f (void){}
+void (*fp)(void) = f;
+void call_fp()
+{
+ (fp?f:f)();
+ (fp?fp:fp)();
+ (fp?fp:&f)();
+ (fp?&f:fp)();
+ (fp?&f:&f)();
+ _Generic(0?arr:arr, char*: (void)0);
+ _Generic(0?&arr[0]:arr, char*: (void)0);
+ _Generic(0?arr:&arr[0], char*: (void)0);
+ _Generic(1?arr:arr, char*: (void)0);
+ _Generic(1?&arr[0]:arr, char*: (void)0);
+ _Generic(1?arr:&arr[0], char*: (void)0);
+ _Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0);
+ (fp?&f:f)();
+ (fp?f:&f)();
+ _Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
+
+ /* The following line causes a warning */
+ void *xx = fp?f:1;
+}
+
+struct condstruct {
+ int i;
+};
+
+static int getme(struct condstruct* s, int i)
+{
+ int i1 = (i != 0 ? 0 : s)->i;
+ int i2 = (i == 0 ? s : 0)->i;
+ int i3 = (i != 0 ? (void*)0 : s)->i;
+ int i4 = (i == 0 ? s : (void*)0)->i;
+ return i1 + i2 + i3 + i4;
+}
int main()
{
@@ -9,6 +48,32 @@ int main()
printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3));
}
+ {
+ int c = 0;
+ #define ASSERT(X) assert(X)
+ static struct stru { int x; } a={'A'},b={'B'};
+ static const struct stru2 { int x; } d = { 'D' };
+ ASSERT('A'==(*(1?&a:&b)).x);
+ ASSERT('A'==(1?a:b).x);
+ ASSERT('A'==(c?b:a).x);
+ ASSERT('A'==(0?b:a).x);
+ c=1;
+ ASSERT('A'==(c?a:b).x);
+ ASSERT(sizeof(int) == sizeof(0 ? 'a' : c));
+ ASSERT(sizeof(double) == sizeof(0 ? 'a' : 1.0));
+ ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 'a'));
+ ASSERT(sizeof(float) == sizeof(0 ? 'a' : 1.0f));
+ ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 1.0f));
+ struct condstruct cs = { 38 };
+ printf("%d\n", getme(&cs, 0));
+
+ // the following lines contain type mismatch errors in every ternary expression
+ //printf("comparing double with pointer : size = %d\n", sizeof(0 ? &c : 0.0));
+ //printf("'%c' <> '%c'\n", (0 ? a : d).x, (1 ? a : d).x);
+ //0 ? a : 0.0;
+ }
+
+
return 0;
}
diff --git a/tests/tests2/33_ternary_op.expect b/tests/tests2/33_ternary_op.expect
index 45ea507..497be0e 100644
--- a/tests/tests2/33_ternary_op.expect
+++ b/tests/tests2/33_ternary_op.expect
@@ -1,3 +1,4 @@
+33_ternary_op.c:26: warning: pointer/integer mismatch in conditional expression
0
1
4
@@ -8,3 +9,4 @@
21
24
27
+152
diff --git a/tests/tests2/46_grep.c b/tests/tests2/46_grep.c
index 049dfb1..acda793 100644
--- a/tests/tests2/46_grep.c
+++ b/tests/tests2/46_grep.c
@@ -456,11 +456,13 @@ char *pmatch(char *line, char *pattern)
while (*l && (e = pmatch(l, p)))
l = e; /* Get longest match */
while (*p++ != ENDPAT); /* Skip over pattern */
- while (l >= are) { /* Try to match rest */
+ while (l > are) { /* Try to match rest */
if (e = pmatch(l, p))
return(e);
--l; /* Nope, try earlier */
}
+ if (e = pmatch(l, p))
+ return(e);
return(0); /* Nothing else worked */
default:
diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c
index 0028caf..fd4367a 100644
--- a/tests/tests2/60_errors_and_warnings.c
+++ b/tests/tests2/60_errors_and_warnings.c
@@ -48,4 +48,302 @@ enum rgb3 c = 42;
#elif defined test_74_non_const_init
int i = i++;
+#elif defined test_pointer_assignment
+
+void (*f1)(void);
+void f2(void) {}
+
+struct s1 *ps1;
+struct s2 *ps2;
+
+void *v1, **v2, ***v3;
+
+enum e1 { a = 4 } e10, *e11, *e12;
+enum e2 { b = -4 } e20, *e21;
+enum e3 { c = 5000000000LL } e30;
+
+int *ip;
+unsigned int *up;
+long *lp;
+long long *llp;
+
+char **c1;
+char const **c2;
+unsigned char **u1;
+
+int no_main ()
+{
+ // function
+ f1 = f2;
+ // struct
+ ps1 = ps2;
+ // void*
+ v1 = v3;
+ v2 = v3;
+
+ // enum
+ e11 = e12;
+ e11 = e21;
+ e11 = &e10;
+ ip = &e10;
+ ip = &e20;
+ up = &e10;
+ up = &e20;
+ up = &e30;
+
+ lp = ip;
+ lp = llp;
+
+ // constness
+ c1 = c2;
+ *c1 = *c2;
+ **c1 = **c2;
+
+ // unsigned = signed
+ u1 = c2;
+ *u1 = *c2;
+ **u1 = **c2;
+
+ c2 = c1;
+ *c2 = *c1;
+ **c2 = **c1;
+
+ return 0;
+}
+
+
+#elif defined test_enum_compat
+enum e4;
+enum e5;
+void f3(enum e4 e);
+void f3(enum e5 e);
+
+#elif defined test_enum_compat_2
+enum e6 { E1 = -1, E0 };
+void f3(enum e6);
+void f3(int); // should work as int and e6 are compatible
+void f4(enum e6 e);
+void f4(unsigned e); // should error as unsigned and e6 are incompatible
+
+#elif defined test_ptr_to_str
+void f() { _Generic((int const *[]){0}, int:0); }
+#elif defined test_fnptr_to_str
+void f() { _Generic((int (*(*)(float,char))(double,int)){0}, int:0); }
+#elif defined test_array_to_str
+void f() { _Generic((int(*)[3]){0}, int:0); }
+#elif defined test_duplicate_def_1
+static enum myenum { L = -1 } L;
+#elif defined test_duplicate_def_2
+void foo(void) {
+static enum myenum { L = -1 } L;
+}
+#elif defined test_abstract_decls
+int bar(const char *()); // abstract declarator here is okay
+int bar (const char *(*g)()) // should match this 'g' argument
+{
+ g();
+ return 42;
+}
+int foo(int ()) // abstract decl is wrong in definitions
+{
+ return 0;
+#elif defined test_invalid_1
+void f(char*);
+void g(void) {
+ f((char[]){1, ,});
+}
+#elif defined test_invalid_2
+int ga = 0.42 { 2 };
+#elif defined test_invalid_3
+struct S { int a, b; };
+struct T { struct S x; };
+struct T gt = { 42 a: 1, 43 };
+#elif defined test_invalid_4
+enum E {
+ x = 1 / 0
+};
+#elif defined test_conflicting_types
+int i;
+void foo(void) {
+ int i;
+ {
+ extern double i;
+ i = 42.2;
+ }
+}
+#elif defined test_nested_types
+union u {
+ union u {
+ int i;
+ } m;
+};
+#elif defined test_vla_1
+int X=1;
+
+int main(void) {
+ int t[][][X];
+}
+#elif defined test_invalid_alignas
+/* _Alignas is no type qualifier */
+void * _Alignas(16) p1;
+
+#elif defined test_static_assert
+
+#define ONE 0
+ _Static_assert(ONE == 0, "don't show me this");
+ _Static_assert(ONE == 1, "ONE is not 1");
+
+#elif defined test_static_assert_2
+ _Static_assert(1, "1"" is 1");
+ _Static_assert(0, "0"" is 0");
+
+#elif defined test_static_assert_c2x
+ _Static_assert(1);
+ _Static_assert(0);
+
+#elif defined test_void_array
+ void t[3];
+
+#elif defined test_incomplete_enum_array
+ enum e t[3];
+
+#elif defined test_incomplete_struct_array
+ struct s t[3];
+
+#elif defined test_const_fun_array
+ typedef void f(void);
+ const f t[3];
+
+#elif defined test_incomplete_array_array
+ int t[][3]; // gr: not an error, see below
+
+/******************************************************************/
+#elif defined test_extern_array
+int iii[] = { 1,2,3 };
+extern int iii[];
+int x[];
+int x[2];
+int x[];
+int x[2];
+int x[];
+extern int x[2];
+extern int x[];
+int x[3];
+
+/******************************************************************/
+#elif defined test_func_1 \
+ || defined test_func_2 \
+ || defined test_func_3 \
+ || defined test_func_4 \
+ || defined test_func_5 \
+ || defined test_func_6
+#if defined test_func_1
+int hello(int);
+#elif defined test_func_4
+static int hello(int);
+#endif
+int main () {
+#if defined test_func_6
+ static
+#endif
+ int hello(int);
+ hello(123);
+ return 0;
+}
+int printf(const char*, ...);
+#if defined test_func_3
+static int hello(int a)
+#elif defined test_func_5
+int hello(int a, int b)
+#else
+int hello(int a)
+#endif
+{ printf("%s: a = %d\n", __FUNCTION__, a); return 0; }
+
+/******************************************************************/
+#elif defined test_var_1 \
+ || defined test_var_2 \
+ || defined test_var_3
+#define P(n,v) printf("%-5s: %d ; %d\n", __FUNCTION__, n, v)
+#if defined test_var_1
+int xxx[];
+#endif
+int bar();
+int printf(const char*, ...);
+int main ()
+{
+#if !defined test_var_3
+ int xxx = 2;
+#endif
+ {
+ extern int xxx[
+#if defined test_var_3
+ 2
+#endif
+ ];
+ P(1, xxx[0]);
+ xxx[0] += 2;
+ }
+#if !defined test_var_3
+ P(2, xxx);
+#endif
+ bar(123);
+ return 0;
+}
+int xxx[1] = {1};
+int bar() { P(3, xxx[0]); return 0; }
+
+#elif defined test_var_4
+struct yyy { int y; };
+struct zzz;
+void f1() {
+ extern char *x;
+ extern char **xx;
+ extern struct yyy y;
+ extern struct yyy *yy;
+ extern struct zzz z;
+ extern struct zzz *zz;
+}
+void f2() {
+ extern char *x;
+ extern char **xx;
+ extern struct yyy y;
+ extern struct yyy *yy;
+ extern struct zzz z;
+ extern struct zzz *zz;
+}
+struct yyy y, *yy;
+struct zzz { int z; } z, *zz;
+
+/******************************************************************/
+#elif defined test_long_double_type_for_win32
+
+int main()
+{
+ double *a = 0;
+ long double *b = a;
+ int n = _Generic(*a, double:0, long double:1);
+}
+
+#elif defined test_stray_backslash
+#define x \a
+x
+
+#elif defined test_stray_backslash2
+int printf(const char*, ...);
+int main()
+{
+#define _S(x) #x
+#define S(x) _S(x)
+ printf("%sn\n", S(\\));
+}
+
+/******************************************************************/
+#elif defined test_var_array
+
+static struct var_len { int i; const char str[]; } var_array[] =
+{ { 1, "abcdefghijklmnopqrstuvwxyz" },
+ { 2, "longlonglonglonglong" },
+ { 3, "tst3" } };
+
#endif
diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect
index ed6a690..984e4c1 100644
--- a/tests/tests2/60_errors_and_warnings.expect
+++ b/tests/tests2/60_errors_and_warnings.expect
@@ -20,9 +20,145 @@
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
[test_63_local_enumerator_redefinition]
+[returns 1]
[test_61_undefined_enum]
60_errors_and_warnings.c:46: error: unknown type size
[test_74_non_const_init]
60_errors_and_warnings.c:49: error: initializer element is not constant
+
+[test_pointer_assignment]
+60_errors_and_warnings.c:79: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:82: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:86: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:88: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:91: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:92: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:94: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:95: warning: assignment from incompatible pointer type
+60_errors_and_warnings.c:98: warning: assignment discards qualifiers from pointer target type
+60_errors_and_warnings.c:99: warning: assignment discards qualifiers from pointer target type
+60_errors_and_warnings.c:103: warning: assignment discards qualifiers from pointer target type
+60_errors_and_warnings.c:104: warning: assignment discards qualifiers from pointer target type
+60_errors_and_warnings.c:109: warning: assignment of read-only location
+
+[test_enum_compat]
+60_errors_and_warnings.c:119: error: incompatible types for redefinition of 'f3'
+
+[test_enum_compat_2]
+60_errors_and_warnings.c:126: error: incompatible types for redefinition of 'f4'
+
+[test_ptr_to_str]
+60_errors_and_warnings.c:129: error: type 'const int **' does not match any association
+
+[test_fnptr_to_str]
+60_errors_and_warnings.c:131: error: type 'int (*(*)(float, char))(double, int)' does not match any association
+
+[test_array_to_str]
+60_errors_and_warnings.c:133: error: type 'int (*)[3]' does not match any association
+
+[test_duplicate_def_1]
+60_errors_and_warnings.c:135: error: redefinition of 'L'
+
+[test_duplicate_def_2]
+60_errors_and_warnings.c:138: error: redeclaration of 'L'
+
+[test_abstract_decls]
+60_errors_and_warnings.c:148: error: identifier expected
+
+[test_invalid_1]
+60_errors_and_warnings.c:153: error: identifier expected
+
+[test_invalid_2]
+60_errors_and_warnings.c:156: error: ';' expected (got "{")
+
+[test_invalid_3]
+60_errors_and_warnings.c:160: error: ',' expected (got "a")
+
+[test_invalid_4]
+60_errors_and_warnings.c:164: error: division by zero in constant
+
+[test_conflicting_types]
+60_errors_and_warnings.c:170: error: incompatible types for redefinition of 'i'
+
+[test_nested_types]
+60_errors_and_warnings.c:177: error: struct/union/enum already defined
+
+[test_vla_1]
+60_errors_and_warnings.c:184: error: need explicit inner array size in VLAs
+
+[test_invalid_alignas]
+60_errors_and_warnings.c:188: error: identifier expected
+
+[test_static_assert]
+60_errors_and_warnings.c:194: error: ONE is not 1
+
+[test_static_assert_2]
+60_errors_and_warnings.c:198: error: 0 is 0
+
+[test_static_assert_c2x]
+60_errors_and_warnings.c:202: error: _Static_assert fail
+
+[test_void_array]
+60_errors_and_warnings.c:205: error: declaration of an array of incomplete type elements
+
+[test_incomplete_enum_array]
+60_errors_and_warnings.c:208: error: declaration of an array of incomplete type elements
+
+[test_incomplete_struct_array]
+60_errors_and_warnings.c:211: error: declaration of an array of incomplete type elements
+
+[test_const_fun_array]
+60_errors_and_warnings.c:215: error: declaration of an array of functions
+
+[test_incomplete_array_array]
+
+[test_extern_array]
+60_errors_and_warnings.c:231: error: incompatible types for redefinition of 'x'
+
+[test_func_1]
+hello: a = 123
+
+[test_func_2]
+hello: a = 123
+
+[test_func_3]
+60_errors_and_warnings.c:261: warning: static storage ignored for redefinition of 'hello'
+hello: a = 123
+
+[test_func_4]
+hello: a = 123
+
+[test_func_5]
+60_errors_and_warnings.c:261: error: incompatible types for redefinition of 'hello'
+
+[test_func_6]
+60_errors_and_warnings.c:249: error: function without file scope cannot be static
+
+[test_var_1]
+main : 1 ; 1
+main : 2 ; 2
+bar : 3 ; 3
+
+[test_var_2]
+main : 1 ; 1
+main : 2 ; 2
+bar : 3 ; 3
+
+[test_var_3]
+60_errors_and_warnings.c:293: error: incompatible types for redefinition of 'xxx'
+
+[test_var_4]
+
+[test_long_double_type_for_win32]
+60_errors_and_warnings.c:324: warning: assignment from incompatible pointer type
+
+[test_stray_backslash]
+60_errors_and_warnings.c:330: error: stray '\' in program
+
+[test_stray_backslash2]
+\n
+
+[test_var_array]
+60_errors_and_warnings.c:345: warning: initializer-string for array is too long
diff --git a/tests/tests2/61_integers.c b/tests/tests2/61_integers.c
new file mode 100644
index 0000000..de29b3c
--- /dev/null
+++ b/tests/tests2/61_integers.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+
+/* This was first introduced to test the ARM port */
+
+#define UINT_MAX ((unsigned) -1)
+
+int main()
+{
+ printf("18/21=%u\n", 18/21);
+ printf("18%%21=%u\n", 18%21);
+ printf("41/21=%u\n", 41/21);
+ printf("41%%21=%u\n", 41%21);
+ printf("42/21=%u\n", 42/21);
+ printf("42%%21=%u\n", 42%21);
+ printf("43/21=%u\n", 43/21);
+ printf("43%%21=%u\n", 43%21);
+ printf("126/21=%u\n", 126/21);
+ printf("126%%21=%u\n", 126%21);
+ printf("131/21=%u\n", 131/21);
+ printf("131%%21=%u\n", 131%21);
+ printf("(UINT_MAX/2+3)/2=%u\n", (UINT_MAX/2+3)/2);
+ printf("(UINT_MAX/2+3)%%2=%u\n", (UINT_MAX/2+3)%2);
+
+ printf("18/-21=%u\n", 18/-21);
+ printf("18%%-21=%u\n", 18%-21);
+ printf("41/-21=%u\n", 41/-21);
+ printf("41%%-21=%u\n", 41%-21);
+ printf("42/-21=%u\n", 42/-21);
+ printf("42%%-21=%u\n", 42%-21);
+ printf("43/-21=%u\n", 43/-21);
+ printf("43%%-21=%u\n", 43%-21);
+ printf("126/-21=%u\n", 126/-21);
+ printf("126%%-21=%u\n", 126%-21);
+ printf("131/-21=%u\n", 131/-21);
+ printf("131%%-21=%u\n", 131%-21);
+ printf("(UINT_MAX/2+3)/-2=%u\n", (UINT_MAX/2+3)/-2);
+ printf("(UINT_MAX/2+3)%%-2=%u\n", (UINT_MAX/2+3)%-2);
+
+ printf("-18/21=%u\n", -18/21);
+ printf("-18%%21=%u\n", -18%21);
+ printf("-41/21=%u\n", -41/21);
+ printf("-41%%21=%u\n", -41%21);
+ printf("-42/21=%u\n", -42/21);
+ printf("-42%%21=%u\n", -42%21);
+ printf("-43/21=%u\n", -43/21);
+ printf("-43%%21=%u\n", -43%21);
+ printf("-126/21=%u\n", -126/21);
+ printf("-126%%21=%u\n", -126%21);
+ printf("-131/21=%u\n", -131/21);
+ printf("-131%%21=%u\n", -131%21);
+ printf("-(UINT_MAX/2+3)/2=%u\n", (0-(UINT_MAX/2+3))/2);
+ printf("-(UINT_MAX/2+3)%%2=%u\n", (0-(UINT_MAX/2+3))%2);
+
+ printf("-18/-21=%u\n", -18/-21);
+ printf("-18%%-21=%u\n", -18%-21);
+ printf("-41/-21=%u\n", -41/-21);
+ printf("-41%%-21=%u\n", -41%-21);
+ printf("-42/-21=%u\n", -42/-21);
+ printf("-42%%-21=%u\n", -42%-21);
+ printf("-43/-21=%u\n", -43/-21);
+ printf("-43%%-21=%u\n", -43%-21);
+ printf("-126/-21=%u\n", -126/-21);
+ printf("-126%%-21=%u\n", -126%-21);
+ printf("-131/-21=%u\n", -131/-21);
+ printf("-131%%-21=%u\n", -131%-21);
+ printf("-(UINT_MAX/2+3)/-2=%u\n", (0-(UINT_MAX/2+3))/-2);
+ printf("-(UINT_MAX/2+3)%%-2=%u\n", (0-(UINT_MAX/2+3))%-2);
+
+ return 0;
+}
diff --git a/tests/tests2/61_integers.expect b/tests/tests2/61_integers.expect
new file mode 100644
index 0000000..22c8d1b
--- /dev/null
+++ b/tests/tests2/61_integers.expect
@@ -0,0 +1,56 @@
+18/21=0
+18%21=18
+41/21=1
+41%21=20
+42/21=2
+42%21=0
+43/21=2
+43%21=1
+126/21=6
+126%21=0
+131/21=6
+131%21=5
+(UINT_MAX/2+3)/2=1073741825
+(UINT_MAX/2+3)%2=0
+18/-21=0
+18%-21=18
+41/-21=4294967295
+41%-21=20
+42/-21=4294967294
+42%-21=0
+43/-21=4294967294
+43%-21=1
+126/-21=4294967290
+126%-21=0
+131/-21=4294967290
+131%-21=5
+(UINT_MAX/2+3)/-2=0
+(UINT_MAX/2+3)%-2=2147483650
+-18/21=0
+-18%21=4294967278
+-41/21=4294967295
+-41%21=4294967276
+-42/21=4294967294
+-42%21=0
+-43/21=4294967294
+-43%21=4294967295
+-126/21=4294967290
+-126%21=0
+-131/21=4294967290
+-131%21=4294967291
+-(UINT_MAX/2+3)/2=1073741823
+-(UINT_MAX/2+3)%2=0
+-18/-21=0
+-18%-21=4294967278
+-41/-21=1
+-41%-21=4294967276
+-42/-21=2
+-42%-21=0
+-43/-21=2
+-43%-21=4294967295
+-126/-21=6
+-126%-21=0
+-131/-21=6
+-131%-21=4294967291
+-(UINT_MAX/2+3)/-2=0
+-(UINT_MAX/2+3)%-2=2147483646
diff --git a/tests/tests2/73_arm64.c b/tests/tests2/73_arm64.c
index 8de61b3..855c476 100644
--- a/tests/tests2/73_arm64.c
+++ b/tests/tests2/73_arm64.c
@@ -230,6 +230,17 @@ void ret(void)
printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
}
+void*
+va_arg_with_struct_ptr(va_list ap) {
+ /*
+ * This was a BUG identified with FFTW-3.3.8 on arm64.
+ * The test case only checks it compiles.
+ */
+ struct X { int _x; };
+ struct X *x = va_arg(ap, struct X *);
+ return x;
+}
+
int match(const char **s, const char *f)
{
const char *p = *s;
diff --git a/tests/tests2/81_types.c b/tests/tests2/81_types.c
index fd6d71b..0bc3bae 100644
--- a/tests/tests2/81_types.c
+++ b/tests/tests2/81_types.c
@@ -39,5 +39,17 @@ int f5 (fptr5 fp, fptr1 i)
{
return fp(i);
}
+typedef int intx4[4];
+int f8 (intx4, int);
int f8 (int ([4]), int);
+int f8 (int y[4], int i)
+{
+ return y[i];
+}
+int f9 (int (*)(int), int);
+int f9 (int ((int)), int);
+int f9 (int f(int), int i)
+{
+ return f(i);
+}
int main () { return 0; }
diff --git a/tests/tests2/82_attribs_position.c b/tests/tests2/82_attribs_position.c
index 7c9f987..fd3f2c4 100644
--- a/tests/tests2/82_attribs_position.c
+++ b/tests/tests2/82_attribs_position.c
@@ -16,4 +16,50 @@ void __attribute__((stdcall)) foo (void)
{
}
-int main () { return 0; }
+#define __stdcall __attribute__((stdcall))
+extern int some_stdcall_func (int, int, int) __stdcall;
+__stdcall int __stdcall some_stdcall_func(int foo, int bar, int baz) {
+ //printf("Hello from stdcall: %i %i %i\n", foo, bar, baz);
+ return 43;
+}
+
+/* The actual attribute isn't important, must just be
+ parsable. */
+#define ATTR __attribute__((__noinline__))
+int ATTR actual_function() {
+ return 42;
+}
+
+extern int printf (const char *, ...);
+static int globalvar;
+int main()
+{
+ void *function_pointer = &actual_function;
+ int localvar = 42, i;
+
+ int a = ((ATTR int(*) (void)) function_pointer)();
+ printf("%i\n", a);
+
+ /* In the following we once misparsed 'ATTR *' is a btype
+ and hence the whole type was garbled. */
+ int b = ( (int(ATTR *)(void)) function_pointer)();
+ printf("%i\n", b);
+
+ /* All these should work and leave the stack pointer in its original
+ position. */
+ some_stdcall_func(1, 10, 100);
+ ((int __stdcall (*)(int, int, int))some_stdcall_func) (2, 20, 200);
+ ((int(*__stdcall)(int, int, int))some_stdcall_func) (3, 30, 300);
+ for (i = 0; i < 1024; i++) {
+ globalvar = i;
+ /* This was once misparsed at <= gitrev 325241c0, forgetting
+ the stdcall attribute on the function pointer leading to
+ stack increment being done twice (in callee and caller).
+ This will clobber 'i' and 'localvar' which is how we detect
+ this. */
+ ((int(__stdcall*)(int, int, int))some_stdcall_func) (4, 40, 400);
+ if (localvar != 42 || globalvar != i)
+ printf("error, localvar=%d i=%d globalvar=%d\n", localvar, i, globalvar);
+ }
+ return 0;
+}
diff --git a/tests/tests2/82_attribs_position.expect b/tests/tests2/82_attribs_position.expect
index e69de29..daaac9e 100644
--- a/tests/tests2/82_attribs_position.expect
+++ b/tests/tests2/82_attribs_position.expect
@@ -0,0 +1,2 @@
+42
+42
diff --git a/tests/tests2/85_asm-outside-function.c b/tests/tests2/85_asm-outside-function.c
index dc5639a..3d7434d 100644
--- a/tests/tests2/85_asm-outside-function.c
+++ b/tests/tests2/85_asm-outside-function.c
@@ -1,6 +1,12 @@
+#ifdef __leading_underscore
+# define _ "_"
+#else
+# define _
+#endif
+
extern int printf (const char *, ...);
extern void vide(void);
-__asm__("vide: ret");
+__asm__(_"vide: ret");
int main() {
vide();
diff --git a/tests/tests2/87_dead_code.c b/tests/tests2/87_dead_code.c
index 98d4566..0d5a64c 100644
--- a/tests/tests2/87_dead_code.c
+++ b/tests/tests2/87_dead_code.c
@@ -26,6 +26,36 @@ static void kb_wait_1(void)
timeout--;
} while (timeout);
}
+
+static int global;
+
+static void foo(int i)
+{
+ global+=i;
+ printf ("g=%d\n", global);
+}
+
+static int check(void)
+{
+ printf ("check %d\n", global);
+ return 1;
+}
+
+static void dowhile(void)
+{
+ do {
+ foo(1);
+ if (global == 1) {
+ continue;
+ } else if (global == 2) {
+ continue;
+ }
+ /* The following break shouldn't disable the check() call,
+ as it's reachable by the continues above. */
+ break;
+ } while (check());
+}
+
int main (void)
{
int i = 1;
@@ -118,5 +148,8 @@ enterloop3:
printf ("error4\n");
}
}
+
+ dowhile();
+
return 0;
}
diff --git a/tests/tests2/87_dead_code.expect b/tests/tests2/87_dead_code.expect
index 0b3ec1d..a8c93bd 100644
--- a/tests/tests2/87_dead_code.expect
+++ b/tests/tests2/87_dead_code.expect
@@ -16,3 +16,8 @@ once3
twice3
caseok
caseok2
+g=1
+check 1
+g=2
+check 2
+g=3
diff --git a/tests/tests2/88_codeopt.c b/tests/tests2/88_codeopt.c
index 647626f..2ab4c8a 100644
--- a/tests/tests2/88_codeopt.c
+++ b/tests/tests2/88_codeopt.c
@@ -1,7 +1,7 @@
/* Check some way in where code suppression caused various
miscompilations. */
extern int printf (const char *, ...);
-typedef unsigned long size_t;
+typedef __SIZE_TYPE__ size_t;
size_t _brk_start, _brk_end;
void * extend_brk(size_t size, size_t align)
@@ -51,6 +51,7 @@ _Bool chk(unsigned long addr, unsigned long limit, unsigned long size)
only with certain internal checking added that's not committed). */
if (0)
ret = 0 != (!!(addr > limit - size));
+ return 0;
}
int main()
diff --git a/tests/tests2/90_struct-init.c b/tests/tests2/90_struct-init.c
index d931e23..ade7fad 100644
--- a/tests/tests2/90_struct-init.c
+++ b/tests/tests2/90_struct-init.c
@@ -87,6 +87,13 @@ union UV guv = {{6,5}};
union UV guv2 = {{.b = 7, .a = 8}};
union UV guv3 = {.b = 8, .a = 7};
+struct SSU {
+ int y;
+ struct { int x; };
+};
+struct SSU gssu1 = { .y = 5, .x = 3 };
+struct SSU gssu2 = { 5, 3 };
+
/* Under -fms-extensions also the following is valid:
union UV2 {
struct Anon {u8 a,b;}; // unnamed member, but tagged struct, ...
@@ -166,6 +173,14 @@ void foo (struct W *w, struct pkthdr *phdr_)
int elt = 0x42;
/* Range init, overlapping */
struct T lt2 = { { [1 ... 5] = 9, [6 ... 10] = elt, [4 ... 7] = elt+1 }, 1 };
+ struct SSU lssu1 = { 5, 3 };
+ struct SSU lssu2 = { .y = 5, .x = 3 };
+ /* designated initializers in GNU form */
+#if defined(__GNUC__) || defined(__TINYC__)
+ struct S ls4 = {a: 1, b: 2, c: {3, 4}};
+#else
+ struct S ls4 = {.a = 1, .b = 2, .c = {3, 4}};
+#endif
print(ls);
print(ls2);
print(lt);
@@ -182,7 +197,10 @@ void foo (struct W *w, struct pkthdr *phdr_)
print(lv2);
print(lv3);
print(lt2);
+ print(lssu1);
+ print(lssu2);
print(flow);
+ print(ls4);
}
#endif
@@ -272,6 +290,8 @@ int main()
print(guv.b);
print(guv2);
print(guv3);
+ print(gssu1);
+ print(gssu2);
print(phdr);
foo(&gw, &phdr);
//printf("q: %s\n", q);
diff --git a/tests/tests2/90_struct-init.expect b/tests/tests2/90_struct-init.expect
index e366121..c55cb47 100644
--- a/tests/tests2/90_struct-init.expect
+++ b/tests/tests2/90_struct-init.expect
@@ -17,6 +17,8 @@ guv: 6 5 0 0
guv.b: 5
guv2: 8 7 0 0
guv3: 7 8 0 0
+gssu1: 5 0 0 0 3 0 0 0
+gssu2: 5 0 0 0 3 0 0 0
phdr: 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0
ls: 1 2 3 4
ls2: 1 2 3 4
@@ -34,7 +36,10 @@ lv: 3 4 5 6 68 61 68 61 0 0 0 0 0 0 0 0 0 0 0 0 2d 2e
lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30
lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32
lt2: 0 9 9 9 43 43 43 43 42 42 42 0 0 0 0 0 1
+lssu1: 5 0 0 0 3 0 0 0
+lssu2: 5 0 0 0 3 0 0 0
flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0
+ls4: 1 2 3 4
one
two
three
diff --git a/tests/tests2/92_enum_bitfield.c b/tests/tests2/92_enum_bitfield.c
index bb6dc35..fb8f7a3 100644
--- a/tests/tests2/92_enum_bitfield.c
+++ b/tests/tests2/92_enum_bitfield.c
@@ -45,6 +45,7 @@ int convert_like_real (tree convs)
break;
};
printf("unsigned enum bit-fields broken\n");
+ return 0;
}
int main()
diff --git a/tests/tests2/94_generic.c b/tests/tests2/94_generic.c
index d7fb5fc..6e85c02 100644
--- a/tests/tests2/94_generic.c
+++ b/tests/tests2/94_generic.c
@@ -20,6 +20,12 @@ int b_f()
return 10;
}
+typedef int (*fptr)(int);
+int foo(int i)
+{
+ return i;
+}
+
typedef int int_type1;
#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123);
@@ -60,5 +66,50 @@ int main()
long long: "long long"));
i = _Generic(l, long: 1, int: 2);
printf("%d\n", i);
+ i = _Generic(foo, fptr: 3, int: 4);
+ printf("%d\n", i);
+
+ (void)_Generic((int(*)[2]){0}, int(*)[2]:0, int(*)[4]:0); //shouldn't match twice
+
+ //should accept ({ }) in the controlling expr of _Generic even in const_wanted contexts
+ struct { _Bool x_0: _Generic(({0;}),default:1); } my_x;
+
+ _Generic((__typeof((float const)((float const){42}))*){0}, float*: 0); //casts lose top-level qualifiers
+ int const x = 42; __typeof((__typeof(x))x) *xp = 0; (void)_Generic(xp, int*: 0); //casts lose top-level qualifiers
+
+ //TEST TERNARY:
+ //Same type
+ _Generic( 0?(long*)0:(long*)0, long*: (void)0);
+ //combining of qualifiers
+ _Generic( 0?(long volatile*)0:(long const*)0, long const volatile*: (void)0);
+ //nul-ptr constant selects other type
+ _Generic( 0?(long*)0:0, long*: (void)0);
+ _Generic( 0?(long*)0:(void*)0, long*: (void)0);
+
+ //void ptrs get chosen preferentially; qualifs still combine
+ _Generic( 0?(int volatile*)0: (void const*)1, void volatile const*: (void)0);
+ //like gcc but not clang, don't treat (void* const as the null-ptr constant)
+ _Generic( 0?(int volatile*)0: (void const*)0, void volatile const*: (void)0);
+
+ //ptrs to incomplete types get completed
+ (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
+ (void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
+
+ {
+ /* completion shouldn't affect the type of decl */
+ char **argv;
+ _Generic(argv, char**: (void)0);
+ _Generic(0?(char const*)0:argv[0], char const*: (void)0);
+ _Generic(argv, char**: (void)0);
+ }
+ {
+ extern int (*ar)[];
+ (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
+ (void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
+ (void)(sizeof(struct { int x:_Generic( 0?ar : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
+ (void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : ar, int (*)[4]:+1, int (*)[5]:(void)0); }));
+ (void)(sizeof(struct { int x:_Generic( 0?(int (*)[5])0 : ar, int (*)[5]:+1, int (*)[4]:(void)0); }));
+ }
+
return 0;
}
diff --git a/tests/tests2/94_generic.expect b/tests/tests2/94_generic.expect
index 9aa9275..748d78f 100644
--- a/tests/tests2/94_generic.expect
+++ b/tests/tests2/94_generic.expect
@@ -10,4 +10,5 @@
3
4
long
-1 \ No newline at end of file
+1
+3
diff --git a/tests/tests2/95_bitfields.c b/tests/tests2/95_bitfields.c
index f025c57..4ac38da 100644
--- a/tests/tests2/95_bitfields.c
+++ b/tests/tests2/95_bitfields.c
@@ -78,6 +78,27 @@
}
/* ----------------------------------------------------------------------- */
+#elif TEST == 7
+{
+#ifdef _WIN32
+ typedef long long int ll;
+#else
+ typedef long int ll;
+#endif
+ struct M P __s {
+ ll d : 16;
+ ll b : 16;
+ ll x : 16;
+ ll y : 1;
+ ll z : 2;
+ ll a : 11;
+ ll e : 1;
+ ll f : 1;
+ };
+ TEST_STRUCT(1,2,3,4,5);
+}
+
+/* ----------------------------------------------------------------------- */
#elif defined PACK
#if PACK
@@ -101,6 +122,8 @@ top = 0;
#include SELF
#define TEST 6
#include SELF
+#define TEST 7
+#include SELF
#if PACK
# pragma pack(pop)
diff --git a/tests/tests2/95_bitfields.expect b/tests/tests2/95_bitfields.expect
index 6a8fd9a..215055d 100644
--- a/tests/tests2/95_bitfields.expect
+++ b/tests/tests2/95_bitfields.expect
@@ -34,6 +34,12 @@ bits as set : 00000030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 12
+---- TEST 7 ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 01 00 ffffffff 04 05
+align/size : 8 8
+
---- TEST 1 - PACKED ----
@@ -72,6 +78,12 @@ bits as set : 0030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 10
+---- TEST 7 - PACKED ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 01 00 ffffffff 04 05
+align/size : 1 8
+
---- TEST 1 - WITH ALIGN ----
@@ -110,6 +122,12 @@ bits as set : 00000030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 12
+---- TEST 7 - WITH ALIGN ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 01 00 ffffffff 04 05
+align/size : 8 8
+
---- TEST 1 - PACKED - WITH ALIGN ----
@@ -147,3 +165,9 @@ bits in use : 007000FFFFFFFFFFFFFF
bits as set : 0030002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 10
+
+---- TEST 7 - PACKED - WITH ALIGN ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 01 00 ffffffff 04 05
+align/size : 1 8
diff --git a/tests/tests2/95_bitfields_ms.expect b/tests/tests2/95_bitfields_ms.expect
index 8ccafb7..97c46be 100644
--- a/tests/tests2/95_bitfields_ms.expect
+++ b/tests/tests2/95_bitfields_ms.expect
@@ -34,6 +34,12 @@ bits as set : 000000000000003000002001000000FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 20
+---- TEST 7 - MS-BITFIELDS ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005
+align/size : 8 8
+
---- TEST 1 - MS-BITFIELDS - PACKED ----
@@ -72,6 +78,12 @@ bits as set : 000000003000002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 14
+---- TEST 7 - MS-BITFIELDS - PACKED ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005
+align/size : 1 8
+
---- TEST 1 - MS-BITFIELDS - WITH ALIGN ----
@@ -110,6 +122,12 @@ bits as set : 000000000000003000002001000000FD00000004
values : 01 02 03 04 fffffffd
align/size : 4 20
+---- TEST 7 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005
+align/size : 8 8
+
---- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ----
@@ -147,3 +165,9 @@ bits in use : 00000000700000FFFFFFFFFFFFFF
bits as set : 000000003000002001FD00000004
values : 01 02 03 04 fffffffd
align/size : 1 14
+
+---- TEST 7 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : 3FFFFFFFFFFF0000
+bits as set : 0026000100050000
+values : 0000000000000001 0000000000000000 ffffffffffffffff 0000000000000004 0000000000000005
+align/size : 1 8
diff --git a/tests/tests2/96_nodata_wanted.c b/tests/tests2/96_nodata_wanted.c
index cc211d3..790b431 100644
--- a/tests/tests2/96_nodata_wanted.c
+++ b/tests/tests2/96_nodata_wanted.c
@@ -55,11 +55,10 @@ te0:;
static char ds1 = 0;
ts1:;
if (!SKIP) {
- static void *p = (void*)&main;
- static char cc[] = "static string";
- static double d = 8.0;
-
- static struct __attribute__((packed)) {
+ void *p = (void*)&main;
+ char cc[] = "static string";
+ double d = 8.0;
+ struct __attribute__((packed)) {
unsigned x : 12;
unsigned char y : 7;
unsigned z : 28, a: 4, b: 5;
@@ -81,4 +80,19 @@ te1:;
/*printf("# %d/%d\n", dl, tl);*/
}
+#elif defined test_static_data
+
+#include <stdio.h>
+int main(int argc, char **argv)
+{
+ goto there;
+ if (0) {
+ static int a = 1;
+ printf("hello\n"); /* the "hello\n" string is still suppressed */
+there:
+ printf("a = %d\n", a);
+ }
+ return 0;
+}
+
#endif
diff --git a/tests/tests2/96_nodata_wanted.expect b/tests/tests2/96_nodata_wanted.expect
index 2749109..92dc9c4 100644
--- a/tests/tests2/96_nodata_wanted.expect
+++ b/tests/tests2/96_nodata_wanted.expect
@@ -9,7 +9,7 @@
[test_local_data_noerror]
96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast
-96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short
+96_nodata_wanted.c:25: warning: cast between pointer and integer of different size
[test_data_suppression_off]
data:
@@ -21,3 +21,6 @@ size of data/text:
[test_data_suppression_on]
size of data/text:
zero/zero
+
+[test_static_data]
+a = 1
diff --git a/tests/tests2/98_al_ax_extend.c b/tests/tests2/98_al_ax_extend.c
index 9b4e02f..1cd6585 100644
--- a/tests/tests2/98_al_ax_extend.c
+++ b/tests/tests2/98_al_ax_extend.c
@@ -8,7 +8,7 @@ asm (
"ret;"
);
-#if 1
+#ifndef __leading_underscore
#define us _us
#define ss _ss
#define uc _uc
diff --git a/tests/tests2/99_fastcall.c b/tests/tests2/99_fastcall.c
index ee4b67d..8fbc904 100644
--- a/tests/tests2/99_fastcall.c
+++ b/tests/tests2/99_fastcall.c
@@ -5,7 +5,7 @@
#define __fastcall __attribute((fastcall))
#endif
-#if 1
+#ifndef __leading_underscore
#define SYMBOL(x) _##x
#else
#define SYMBOL(x) x
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 190b2d9..8b169b4 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -3,7 +3,9 @@ include $(TOP)/Makefile
SRC = $(TOPSRC)/tests/tests2
VPATH = $(SRC)
-TESTS = $(patsubst %.c,%.test,$(sort $(notdir $(wildcard $(SRC)/*.c))))
+TESTS = $(patsubst %.c,%.test,\
+ $(sort $(notdir $(wildcard $(SRC)/??_*.c)))\
+ $(sort $(notdir $(wildcard $(SRC)/???_*.c))))
# some tests do not pass on all platforms, remove them for now
SKIP = 34_array_assignment.test # array assignment is not in C standard
@@ -12,7 +14,7 @@ ifeq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
endif
ifdef CONFIG_OSX
SKIP += 40_stdio.test 42_function_pointer.test
- FLAGS += -w
+ SKIP += 113_btdll.test # no shared lib support yet
endif
ifeq ($(ARCH),x86_64)
SKIP += 73_arm64.test
@@ -21,7 +23,17 @@ ifeq (,$(filter i386,$(ARCH)))
SKIP += 98_al_ax_extend.test 99_fastcall.test
endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
- SKIP += 85_asm-outside-function.test
+ SKIP += 85_asm-outside-function.test # x86 asm
+ SKIP += 113_btdll.test # dll support needed
+endif
+ifeq (,$(filter i386 x86_64 arm arm64 riscv64,$(ARCH)))
+ SKIP += 112_backtrace.test
+ SKIP += 114_bound_signal.test
+ SKIP += 115_bound_setjmp.test
+ SKIP += 116_bound_setjmp2.test
+endif
+ifeq (-$(CONFIG_musl)-,-yes-)
+ SKIP += 112_backtrace.test
endif
ifeq (-$(findstring gcc,$(CC))-,--)
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
@@ -29,6 +41,10 @@ endif
ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
SKIP += 95_bitfields%.test # type_align is different on 32bit-non-windows
endif
+ifeq (-$(CONFIG_WIN32)-,-yes-)
+ SKIP += 106_pthread.test # No pthread support
+ SKIP += 114_bound_signal.test # No pthread support
+endif
# Some tests might need arguments
ARGS =
@@ -54,21 +70,47 @@ GEN-ALWAYS =
# using the ms compiler for the really ms-compatible bitfields
95_bitfields_ms.test : GEN = $(GEN-MSC)
+# this test compiles/links two files:
+104_inline.test : FLAGS += $(subst 104,104+,$1)
+104_inline.test : GEN = $(GEN-TCC)
+
+# this test needs pthread
+106_pthread.test: FLAGS += -pthread
+106_pthread.test: NORUN = true
+
+# constructor/destructor
+108_constructor.test: NORUN = true
+
+112_backtrace.test: FLAGS += -dt -b
+112_backtrace.test 113_btdll.test: FILTER += \
+ -e 's;[0-9A-Fa-fx]\{5,\};........;g' \
+ -e 's;0x[0-9A-Fa-f]\{1,\};0x?;g'
+
+# this test creates two DLLs and an EXE
+113_btdll.test: NORUN = true
+113_btdll.test: FLAGS += \
+ -bt $1 -shared -D DLL=1 -o a1$(DLLSUF) && $(TCC) \
+ -bt $1 -shared -D DLL=2 -o a2$(DLLSUF) && $(TCC) \
+ -bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=.
+
+114_bound_signal.test: FLAGS += -b
+115_bound_setjmp.test: FLAGS += -b
+116_bound_setjmp2.test: FLAGS += -b
+
+117_gcc_test.test: FLAGS += $(T2) && $(TCC) -b
+
# Filter source directory in warnings/errors (out-of-tree builds)
-FILTER = 2>&1 | sed 's,$(SRC)/,,g'
-# Filter some always-warning
-ifeq (-$(findstring arm,$(ARCH))-,-arm-)
-FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
-endif
+FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
-all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
+all test tests2.all: $(filter-out $(SKIP),$(TESTS))
+ @$(MAKE) clean --no-print-directory -s
%.test: %.c %.expect
@echo Test: $*...
- @$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3))
+ @$(call T1,$<) $(T3)
-T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS)
-T2 = $(TCC) $(FLAGS) -run $< $(ARGS)
+T1 = $(TCC) $(FLAGS) $(T2) $(ARGS)
+T2 = $(if $(NORUN),$1 -o a.exe && ./a.exe,-run $1)
T3 = $(FILTER) >$*.output 2>&1 || true \
&& diff -Nbu $(filter %.expect,$^) $*.output \
&& rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))
@@ -79,7 +121,7 @@ tests2.%+:
# just run tcc to see the output, e.g. "make tests2.37-"
tests2.%-:
- @$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory
+ @$(MAKE) $(call F1,$*) T3= --no-print-directory
# run single test, e.g. "make tests2.37"
tests2.%:
@@ -95,9 +137,9 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)"
@rm -f *.exe *.obj *.pdb
# using TCC for .expect if -dt in FLAGS
-GEN = $(if $(filter -dt,$(FLAGS)),$(GEN-TCC),$(GEN-CC))
+GEN = $(if $(filter -dt -bt -b,$(FLAGS)),$(GEN-TCC),$(GEN-CC))
GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS)
-GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS)
+GEN-TCC = $(T1)
GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe
MS-CC = cl
@@ -108,5 +150,5 @@ MS-CC = cl
$(sort $(GEN-ALWAYS) $(UPDATE)) : force
force:
-clean:
- rm -f fred.txt *.output a.exe $(GEN-ALWAYS)
+clean :
+ rm -f fred.txt *.output a.exe *.dll *.so *.def $(GEN-ALWAYS)
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index 913b068..e3ec5b7 100755..100644
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -1,189 +1,191 @@
-@rem ------------------------------------------------------
-@rem batch file to build tcc using mingw, msvc or tcc itself
-@rem ------------------------------------------------------
-
-@echo off
-setlocal
-if (%1)==(-clean) goto :cleanup
-set CC=gcc
-set /p VERSION= < ..\VERSION
-set INST=
-set BIN=
-set DOC=no
-set EXES_ONLY=no
-goto :a0
-:a2
-shift
-:a3
-shift
-:a0
-if not (%1)==(-c) goto :a1
-set CC=%~2
-if (%2)==(cl) set CC=@call :cl
-goto :a2
-:a1
-if (%1)==(-t) set T=%2&& goto :a2
-if (%1)==(-v) set VERSION=%~2&& goto :a2
-if (%1)==(-i) set INST=%2&& goto :a2
-if (%1)==(-b) set BIN=%2&& goto :a2
-if (%1)==(-d) set DOC=yes&& goto :a3
-if (%1)==(-x) set EXES_ONLY=yes&& goto :a3
-if (%1)==() goto :p1
-:usage
-echo usage: build-tcc.bat [ options ... ]
-echo options:
-echo -c prog use prog (gcc/tcc/cl) to compile tcc
-echo -c "prog options" use prog with options to compile tcc
-echo -t 32/64 force 32/64 bit default target
-echo -v "version" set tcc version
-echo -i tccdir install tcc into tccdir
-echo -b bindir optionally install binaries into bindir elsewhere
-echo -d create tcc-doc.html too (needs makeinfo)
-echo -x just create the executables
-echo -clean delete all previously produced files and directories
-exit /B 1
-
-@rem ------------------------------------------------------
-@rem sub-routines
-
-:cleanup
-set LOG=echo
-%LOG% removing files:
-for %%f in (*tcc.exe libtcc.dll lib\*.a) do call :del_file %%f
-for %%f in (..\config.h ..\config.texi) do call :del_file %%f
-for %%f in (include\*.h) do @if exist ..\%%f call :del_file %%f
-for %%f in (include\tcclib.h examples\libtcc_test.c) do call :del_file %%f
-for %%f in (*.o *.obj *.def *.pdb *.lib *.exp *.ilk) do call :del_file %%f
-%LOG% removing directories:
-for %%f in (doc libtcc) do call :del_dir %%f
-%LOG% done.
-exit /B 0
-:del_file
-if exist %1 del %1 && %LOG% %1
-exit /B 0
-:del_dir
-if exist %1 rmdir /Q/S %1 && %LOG% %1
-exit /B 0
-
-:cl
-@echo off
-set CMD=cl
-:c0
-set ARG=%1
-set ARG=%ARG:.dll=.lib%
-if (%1)==(-shared) set ARG=-LD
-if (%1)==(-o) shift && set ARG=-Fe%2
-set CMD=%CMD% %ARG%
-shift
-if not (%1)==() goto :c0
-echo on
-%CMD% -O1 -W2 -Zi -MT -GS- -nologo -link -opt:ref,icf
-@exit /B %ERRORLEVEL%
-
-@rem ------------------------------------------------------
-@rem main program
-
-:p1
-if not %T%_==_ goto :p2
-set T=32
-if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64
-if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64
-:p2
-if "%CC:~-3%"=="gcc" set CC=%CC% -Os -s -static
-set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386
-set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
-set P32=i386-win32
-set P64=x86_64-win32
-if %T%==64 goto :t64
-set D=%D32%
-set DX=%D64%
-set PX=%P64%
-goto :p3
-:t64
-set D=%D64%
-set DX=%D32%
-set PX=%P32%
-goto :p3
-
-:p3
-@echo on
-
-:config.h
-echo>..\config.h #define TCC_VERSION "%VERSION%"
-echo>> ..\config.h #ifdef TCC_TARGET_X86_64
-echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-64.a"
-echo>> ..\config.h #else
-echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-32.a"
-echo>> ..\config.h #endif
-
-for %%f in (*tcc.exe *tcc.dll) do @del %%f
-
-:compiler
-%CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL
-@if errorlevel 1 goto :the_end
-%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
-%CC% -o %PX%-tcc.exe ..\tcc.c %DX%
-
-@if (%EXES_ONLY%)==(yes) goto :files-done
-
-if not exist libtcc mkdir libtcc
-if not exist doc mkdir doc
-copy>nul ..\include\*.h include
-copy>nul ..\tcclib.h include
-copy>nul ..\libtcc.h libtcc
-copy>nul ..\tests\libtcc_test.c examples
-copy>nul tcc-win32.txt doc
-
-.\tcc -impdef libtcc.dll -o libtcc\libtcc.def
-@if errorlevel 1 goto :the_end
-
-:libtcc1.a
-@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o
-.\tcc -m32 -c ../lib/libtcc1.c
-.\tcc -m32 -c lib/crt1.c
-.\tcc -m32 -c lib/crt1w.c
-.\tcc -m32 -c lib/wincrt1.c
-.\tcc -m32 -c lib/wincrt1w.c
-.\tcc -m32 -c lib/dllcrt1.c
-.\tcc -m32 -c lib/dllmain.c
-.\tcc -m32 -c lib/chkstk.S
-.\tcc -m32 -w -c ../lib/bcheck.c
-.\tcc -m32 -c ../lib/alloca86.S
-.\tcc -m32 -c ../lib/alloca86-bt.S
-.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o
-@if errorlevel 1 goto :the_end
-.\tcc -m64 -c ../lib/libtcc1.c
-.\tcc -m64 -c lib/crt1.c
-.\tcc -m64 -c lib/crt1w.c
-.\tcc -m64 -c lib/wincrt1.c
-.\tcc -m64 -c lib/wincrt1w.c
-.\tcc -m64 -c lib/dllcrt1.c
-.\tcc -m64 -c lib/dllmain.c
-.\tcc -m64 -c lib/chkstk.S
-.\tcc -m64 -w -c ../lib/bcheck.c
-.\tcc -m64 -c ../lib/alloca86_64.S
-.\tcc -m64 -c ../lib/alloca86_64-bt.S
-.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
-@if errorlevel 1 goto :the_end
-
-:tcc-doc.html
-@if not (%DOC%)==(yes) goto :doc-done
-echo>..\config.texi @set VERSION %VERSION%
-cmd /c makeinfo --html --no-split ../tcc-doc.texi -o doc/tcc-doc.html
-:doc-done
-
-:files-done
-for %%f in (*.o *.def) do @del %%f
-
-:copy-install
-@if (%INST%)==() goto :the_end
-if not exist %INST% mkdir %INST%
-@if (%BIN%)==() set BIN=%INST%
-if not exist %BIN% mkdir %BIN%
-for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f
-@if not exist %INST%\lib mkdir %INST%\lib
-for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f
-for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f
-
-:the_end
-exit /B %ERRORLEVEL%
+@rem ------------------------------------------------------
+@rem batch file to build tcc using mingw, msvc or tcc itself
+@rem ------------------------------------------------------
+
+@echo off
+setlocal
+if (%1)==(-clean) goto :cleanup
+set CC=gcc
+set /p VERSION= < ..\VERSION
+set INST=
+set BIN=
+set DOC=no
+set EXES_ONLY=no
+goto :a0
+:a2
+shift
+:a3
+shift
+:a0
+if not (%1)==(-c) goto :a1
+set CC=%~2
+if (%2)==(cl) set CC=@call :cl
+goto :a2
+:a1
+if (%1)==(-t) set T=%2&& goto :a2
+if (%1)==(-v) set VERSION=%~2&& goto :a2
+if (%1)==(-i) set INST=%2&& goto :a2
+if (%1)==(-b) set BIN=%2&& goto :a2
+if (%1)==(-d) set DOC=yes&& goto :a3
+if (%1)==(-x) set EXES_ONLY=yes&& goto :a3
+if (%1)==() goto :p1
+:usage
+echo usage: build-tcc.bat [ options ... ]
+echo options:
+echo -c prog use prog (gcc/tcc/cl) to compile tcc
+echo -c "prog options" use prog with options to compile tcc
+echo -t 32/64 force 32/64 bit default target
+echo -v "version" set tcc version
+echo -i tccdir install tcc into tccdir
+echo -b bindir optionally install binaries into bindir elsewhere
+echo -d create tcc-doc.html too (needs makeinfo)
+echo -x just create the executables
+echo -clean delete all previously produced files and directories
+exit /B 1
+
+@rem ------------------------------------------------------
+@rem sub-routines
+
+:cleanup
+set LOG=echo
+%LOG% removing files:
+for %%f in (*tcc.exe libtcc.dll lib\*.a) do call :del_file %%f
+for %%f in (..\config.h ..\config.texi) do call :del_file %%f
+for %%f in (include\*.h) do @if exist ..\%%f call :del_file %%f
+for %%f in (include\tcclib.h examples\libtcc_test.c) do call :del_file %%f
+for %%f in (lib\*.o *.o *.obj *.def *.pdb *.lib *.exp *.ilk) do call :del_file %%f
+%LOG% removing directories:
+for %%f in (doc libtcc) do call :del_dir %%f
+%LOG% done.
+exit /B 0
+:del_file
+if exist %1 del %1 && %LOG% %1
+exit /B 0
+:del_dir
+if exist %1 rmdir /Q/S %1 && %LOG% %1
+exit /B 0
+
+:cl
+@echo off
+set CMD=cl
+:c0
+set ARG=%1
+set ARG=%ARG:.dll=.lib%
+if (%1)==(-shared) set ARG=-LD
+if (%1)==(-o) shift && set ARG=-Fe%2
+set CMD=%CMD% %ARG%
+shift
+if not (%1)==() goto :c0
+echo on
+%CMD% -O1 -W2 -Zi -MT -GS- -nologo -link -opt:ref,icf
+@exit /B %ERRORLEVEL%
+
+@rem ------------------------------------------------------
+@rem main program
+
+:p1
+if not %T%_==_ goto :p2
+set T=32
+if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64
+if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64
+:p2
+if "%CC:~-3%"=="gcc" set CC=%CC% -Os -s -static
+set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386
+set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
+set P32=i386-win32
+set P64=x86_64-win32
+if %T%==64 goto :t64
+set D=%D32%
+set DX=%D64%
+set PX=%P64%
+goto :p3
+:t64
+set D=%D64%
+set DX=%D32%
+set PX=%P32%
+goto :p3
+
+:p3
+@echo on
+
+:config.h
+echo>..\config.h #define TCC_VERSION "%VERSION%"
+echo>> ..\config.h #ifdef TCC_TARGET_X86_64
+echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-64.a"
+echo>> ..\config.h #else
+echo>> ..\config.h #define TCC_LIBTCC1 "libtcc1-32.a"
+echo>> ..\config.h #endif
+
+for %%f in (*tcc.exe *tcc.dll) do @del %%f
+
+:compiler
+%CC% -o libtcc.dll -shared ..\libtcc.c %D% -DLIBTCC_AS_DLL
+@if errorlevel 1 goto :the_end
+%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
+%CC% -o %PX%-tcc.exe ..\tcc.c %DX%
+
+@if (%EXES_ONLY%)==(yes) goto :files-done
+
+if not exist libtcc mkdir libtcc
+if not exist doc mkdir doc
+copy>nul ..\include\*.h include
+copy>nul ..\tcclib.h include
+copy>nul ..\libtcc.h libtcc
+copy>nul ..\tests\libtcc_test.c examples
+copy>nul tcc-win32.txt doc
+
+.\tcc -impdef libtcc.dll -o libtcc\libtcc.def
+@if errorlevel 1 goto :the_end
+
+:libtcc1.a
+@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o
+.\tcc -m32 -c ../lib/libtcc1.c
+.\tcc -m32 -c lib/crt1.c
+.\tcc -m32 -c lib/crt1w.c
+.\tcc -m32 -c lib/wincrt1.c
+.\tcc -m32 -c lib/wincrt1w.c
+.\tcc -m32 -c lib/dllcrt1.c
+.\tcc -m32 -c lib/dllmain.c
+.\tcc -m32 -c lib/chkstk.S
+.\tcc -m32 -c ../lib/alloca86.S
+.\tcc -m32 -c ../lib/alloca86-bt.S
+.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o
+@if errorlevel 1 goto :the_end
+.\tcc -m64 -c ../lib/libtcc1.c
+.\tcc -m64 -c lib/crt1.c
+.\tcc -m64 -c lib/crt1w.c
+.\tcc -m64 -c lib/wincrt1.c
+.\tcc -m64 -c lib/wincrt1w.c
+.\tcc -m64 -c lib/dllcrt1.c
+.\tcc -m64 -c lib/dllmain.c
+.\tcc -m64 -c lib/chkstk.S
+.\tcc -m64 -c ../lib/alloca86_64.S
+.\tcc -m64 -c ../lib/alloca86_64-bt.S
+.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
+@if errorlevel 1 goto :the_end
+.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o -g
+.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o
+.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o
+.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o
+
+:tcc-doc.html
+@if not (%DOC%)==(yes) goto :doc-done
+echo>..\config.texi @set VERSION %VERSION%
+cmd /c makeinfo --html --no-split ../tcc-doc.texi -o doc/tcc-doc.html
+:doc-done
+
+:files-done
+for %%f in (*.o *.def) do @del %%f
+
+:copy-install
+@if (%INST%)==() goto :the_end
+if not exist %INST% mkdir %INST%
+@if (%BIN%)==() set BIN=%INST%
+if not exist %BIN% mkdir %BIN%
+for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f
+@if not exist %INST%\lib mkdir %INST%\lib
+for %%f in (lib\*.a lib\*.o lib\*.def) do @copy>nul %%f %INST%\%%f
+for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f
+
+:the_end
+exit /B %ERRORLEVEL%
diff --git a/win32/include/_mingw.h b/win32/include/_mingw.h
index 2fc9798..4ac2651 100644
--- a/win32/include/_mingw.h
+++ b/win32/include/_mingw.h
@@ -41,7 +41,7 @@
#define __MSVCRT__ 1
#undef _MSVCRT_
#define __MINGW_IMPORT extern __declspec(dllimport)
-#define __MINGW_ATTRIB_NORETURN
+#define __MINGW_ATTRIB_NORETURN __declspec(noreturn)
#define __MINGW_ATTRIB_CONST
#define __MINGW_ATTRIB_DEPRECATED
#define __MINGW_ATTRIB_MALLOC
@@ -51,7 +51,7 @@
#define __GNUC_VA_LIST
#define _CRTIMP extern
-#define __CRT_INLINE extern __inline__
+#define __CRT_INLINE static __inline__
#define _CRT_ALIGN(x) __attribute__((aligned(x)))
#define DECLSPEC_ALIGN(x) __attribute__((aligned(x)))
@@ -76,18 +76,12 @@
#define _M_AMD64 100 /* Visual Studio */
#define USE_MINGW_SETJMP_TWO_ARGS
#define mingw_getsp tinyc_getbp
-#define __TRY__
#else
#define __stdcall __attribute__((__stdcall__))
#define _X86_ 1
#define _M_IX86 300 /* Visual Studio */
#define WIN32 1
#define _USE_32BIT_TIME_T
-#ifdef __arm__
-#define __TRY__
-#else
-#define __TRY__ void __try__(void**), *_sehrec[6]; __try__(_sehrec);
-#endif
#endif
/* in stddef.h */
@@ -138,7 +132,7 @@ typedef struct localeinfo_struct _locale_tstruct,*_locale_t;
/* for winapi */
#define _ANONYMOUS_UNION
#define _ANONYMOUS_STRUCT
-#define DECLSPEC_NORETURN
+#define DECLSPEC_NORETURN __declspec(noreturn)
#define DECLARE_STDCALL_P(type) __stdcall type
#define NOSERVICE 1
#define NOMCX 1
diff --git a/win32/include/assert.h b/win32/include/assert.h
index 466d457..b15bb63 100644
--- a/win32/include/assert.h
+++ b/win32/include/assert.h
@@ -54,4 +54,9 @@ extern void __cdecl _assert(const char *, const char *, unsigned);
#endif
+#if (__STDC_VERSION__ >= 201112L) && !defined(static_assert)
+/* C11, section 7.2: The macro static_assert expands to _Static_assert. */
+#define static_assert(exp, str) _Static_assert(exp, str)
+#endif
+
#endif
diff --git a/win32/include/iso646.h b/win32/include/iso646.h
new file mode 100644
index 0000000..02770f6
--- /dev/null
+++ b/win32/include/iso646.h
@@ -0,0 +1,36 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the TinyCC package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+/*
+ * ISO C Standard: 7.9 Alternative spellings <iso646.h>
+ */
+
+#ifndef _ISO646_H_
+#define _ISO646_H_
+
+#define and &&
+#define and_eq &=
+#define bitand &
+#define bitor |
+#define compl ~
+#define not !
+#define not_eq !=
+#define or ||
+#define or_eq |=
+#define xor ^
+#define xor_eq ^=
+
+#endif /* _ISO646_H_ */
+
+
+
+
+
+
+
+
+
+
diff --git a/win32/include/math.h b/win32/include/math.h
index 74add20..c270c57 100644
--- a/win32/include/math.h
+++ b/win32/include/math.h
@@ -198,12 +198,6 @@ extern "C" {
#endif
#ifndef __cplusplus
- __CRT_INLINE long double __cdecl fabsl (long double x)
- {
- long double res;
- __asm__ ("fabs;" : "=t" (res) : "0" (x));
- return res;
- }
#define _hypotl(x,y) ((long double)_hypot((double)(x),(double)(y)))
#define _matherrl _matherr
__CRT_INLINE long double _chgsignl(long double _Number) { return _chgsign((double)(_Number)); }
@@ -213,13 +207,43 @@ extern "C" {
#if !defined (__ia64__)
__CRT_INLINE float __cdecl fabsf (float x)
{
+#ifdef _WIN64
+ *((int *) &x) &= 0x7fffffff;
+ return x;
+#else
float res;
__asm__ ("fabs;" : "=t" (res) : "0" (x));
return res;
+#endif
}
__CRT_INLINE float __cdecl ldexpf (float x, int expn) { return (float) ldexp (x, expn); }
#endif
+#if defined (_WIN32) && !defined(_WIN64)
+ __CRT_INLINE float acosf(float x) { return (float) acos(x); }
+ __CRT_INLINE float asinf(float x) { return (float) asin(x); }
+ __CRT_INLINE float atanf(float x) { return (float) atan(x); }
+ __CRT_INLINE float atan2f(float x, float y) { return (float) atan2(x, y); }
+ __CRT_INLINE float ceilf(float x) { return (float) ceil(x); }
+ __CRT_INLINE float cosf(float x) { return (float) cos(x); }
+ __CRT_INLINE float coshf(float x) { return (float) cosh(x); }
+ __CRT_INLINE float expf(float x) { return (float) exp(x); }
+ __CRT_INLINE float floorf(float x) { return (float) floor(x); }
+ __CRT_INLINE float fmodf(float x, float y) { return (float) fmod(x, y); }
+ __CRT_INLINE float logf(float x) { return (float) log(x); }
+ __CRT_INLINE float logbf(float x) { return (float) logb(x); }
+ __CRT_INLINE float log10f(float x) { return (float) log10(x); }
+ __CRT_INLINE float modff(float x, float *y) {
+ double di, df = modf(x, &di);
+ *y = (float) di; return (float) df;
+ }
+ __CRT_INLINE float powf(float x, float y) { return (float) pow(x, y); }
+ __CRT_INLINE float sinf(float x) { return (float) sin(x); }
+ __CRT_INLINE float sinhf(float x) { return (float) sinh(x); }
+ __CRT_INLINE float sqrtf(float x) { return (float) sqrt(x); }
+ __CRT_INLINE float tanf(float x) { return (float) tan(x); }
+ __CRT_INLINE float tanhf(float x) { return (float) tanh(x); }
+#endif
#else
// cplusplus
__CRT_INLINE long double __cdecl fabsl (long double x)
@@ -366,7 +390,7 @@ extern "C" {
extern double __cdecl logb (double);
extern float __cdecl logbf (float);
extern long double __cdecl logbl (long double);
-
+#ifndef _WIN32
__CRT_INLINE double __cdecl logb (double x)
{
double res;
@@ -390,6 +414,7 @@ extern "C" {
"fstp %%st" : "=t" (res) : "0" (x));
return res;
}
+#endif
extern long double __cdecl modfl (long double, long double*);
@@ -471,7 +496,7 @@ extern "C" {
__asm__ (
"fldl %1\n"
"frndint \n"
- "fstl %0\n" : "=m" (retval) : "m" (x));
+ "fstpl %0\n" : "=m" (retval) : "m" (x));
return retval;
}
@@ -481,18 +506,23 @@ extern "C" {
__asm__ (
"flds %1\n"
"frndint \n"
- "fsts %0\n" : "=m" (retval) : "m" (x));
+ "fstps %0\n" : "=m" (retval) : "m" (x));
return retval;
}
__CRT_INLINE long double __cdecl rintl (long double x)
{
+#ifdef _WIN32
+ // on win32 'long double' is double internally
+ return rint(x);
+#else
long double retval;
__asm__ (
"fldt %1\n"
"frndint \n"
- "fstt %0\n" : "=m" (retval) : "m" (x));
+ "fstpt %0\n" : "=m" (retval) : "m" (x));
return retval;
+#endif
}
/* 7.12.9.5 */
@@ -566,7 +596,7 @@ extern "C" {
__asm__ ("fldcw %0;" : : "m" (tmp_cw));
__asm__ ("fldl %1;"
"frndint;"
- "fstl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */
+ "fstpl %0;" : "=m" (retval) : "m" (_x)); /* round towards zero */
__asm__ ("fldcw %0;" : : "m" (saved_cw) ); /* restore saved control word */
return retval;
}
diff --git a/win32/include/sys/stat.h b/win32/include/sys/stat.h
index 344d4a2..4a95e65 100644
--- a/win32/include/sys/stat.h
+++ b/win32/include/sys/stat.h
@@ -81,9 +81,9 @@ extern "C" {
#else
#define _fstat _fstat64i32
#define _fstati64 _fstat64
-#define _stat _stat64i32
+#define _stat _stat64
#define _stati64 _stat64
-#define _wstat _wstat64i32
+#define _wstat _wstat64
#define _wstati64 _wstat64
#endif
diff --git a/win32/include/uchar.h b/win32/include/uchar.h
new file mode 100755
index 0000000..1a2c029
--- /dev/null
+++ b/win32/include/uchar.h
@@ -0,0 +1,33 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the TinyCC package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#ifndef _INC_UCHAR
+#define _INC_UCHAR
+
+/*
+ * The following defines are only valid when C11 (-std=c11) is used.
+ *
+ * ... a wide character constant prefixed by the letter u or U has type char16_t
+ * or char32_t, respectively, unsigned integer types defined in the <uchar.h>
+ * header.
+ */
+
+#if __STDC_VERSION__ >= 201112L
+/**
+ * __STDC_UTF_16__ The integer constant 1, intended to indicate that
+ * values of type char16_t are UTF-16 encoded.
+ */
+#define __STDC_UTF_16__ 1
+/**
+ * __STDC_UTF_32__ The integer constant 1, intended to indicate that
+ * values of type char32_t are UTF-32 encoded.
+ */
+#define __STDC_UTF_32__ 1
+
+typedef unsigned short char16_t;
+typedef unsigned int char32_t;
+#endif /* __STDC_VERSION__ >= 201112L */
+#endif /* _INC_UCHAR */
diff --git a/win32/include/winapi/qos.h b/win32/include/winapi/qos.h
new file mode 100644
index 0000000..7fa6ad1
--- /dev/null
+++ b/win32/include/winapi/qos.h
@@ -0,0 +1,72 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+#ifndef __QOS_H_
+#define __QOS_H_
+
+typedef ULONG SERVICETYPE;
+
+#define SERVICETYPE_NOTRAFFIC 0x00000000
+#define SERVICETYPE_BESTEFFORT 0x00000001
+#define SERVICETYPE_CONTROLLEDLOAD 0x00000002
+#define SERVICETYPE_GUARANTEED 0x00000003
+
+#define SERVICETYPE_NETWORK_UNAVAILABLE 0x00000004
+#define SERVICETYPE_GENERAL_INFORMATION 0x00000005
+#define SERVICETYPE_NOCHANGE 0x00000006
+#define SERVICETYPE_NONCONFORMING 0x00000009
+#define SERVICETYPE_NETWORK_CONTROL 0x0000000A
+#define SERVICETYPE_QUALITATIVE 0x0000000D
+
+#define SERVICE_BESTEFFORT 0x80010000
+#define SERVICE_CONTROLLEDLOAD 0x80020000
+#define SERVICE_GUARANTEED 0x80040000
+#define SERVICE_QUALITATIVE 0x80200000
+
+#define SERVICE_NO_TRAFFIC_CONTROL 0x81000000
+
+#define SERVICE_NO_QOS_SIGNALING 0x40000000
+
+typedef struct _flowspec {
+ ULONG TokenRate;
+ ULONG TokenBucketSize;
+ ULONG PeakBandwidth;
+ ULONG Latency;
+ ULONG DelayVariation;
+ SERVICETYPE ServiceType;
+ ULONG MaxSduSize;
+ ULONG MinimumPolicedSize;
+} FLOWSPEC,*PFLOWSPEC,*LPFLOWSPEC;
+
+#define QOS_NOT_SPECIFIED 0xFFFFFFFF
+#define POSITIVE_INFINITY_RATE 0xFFFFFFFE
+
+typedef struct {
+ ULONG ObjectType;
+ ULONG ObjectLength;
+} QOS_OBJECT_HDR,*LPQOS_OBJECT_HDR;
+
+#define QOS_GENERAL_ID_BASE 2000
+#define QOS_OBJECT_END_OF_LIST (0x00000001 + QOS_GENERAL_ID_BASE)
+#define QOS_OBJECT_SD_MODE (0x00000002 + QOS_GENERAL_ID_BASE)
+#define QOS_OBJECT_SHAPING_RATE (0x00000003 + QOS_GENERAL_ID_BASE)
+#define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE)
+
+typedef struct _QOS_SD_MODE {
+ QOS_OBJECT_HDR ObjectHdr;
+ ULONG ShapeDiscardMode;
+} QOS_SD_MODE,*LPQOS_SD_MODE;
+
+#define TC_NONCONF_BORROW 0
+#define TC_NONCONF_SHAPE 1
+#define TC_NONCONF_DISCARD 2
+#define TC_NONCONF_BORROW_PLUS 3
+
+typedef struct _QOS_SHAPING_RATE {
+ QOS_OBJECT_HDR ObjectHdr;
+ ULONG ShapingRate;
+} QOS_SHAPING_RATE,*LPQOS_SHAPING_RATE;
+
+#endif
diff --git a/win32/include/winapi/windows.h b/win32/include/winapi/windows.h
index 2660d7f..ff6454a 100644
--- a/win32/include/winapi/windows.h
+++ b/win32/include/winapi/windows.h
@@ -67,7 +67,7 @@
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
-//gr #include <winnls.h>
+#include <winnls.h>
#include <wincon.h>
#include <winver.h>
#include <winreg.h>
diff --git a/win32/include/winapi/winnls.h b/win32/include/winapi/winnls.h
new file mode 100644
index 0000000..296b4cb
--- /dev/null
+++ b/win32/include/winapi/winnls.h
@@ -0,0 +1,778 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+#ifndef _WINNLS_
+#define _WINNLS_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NONLS
+
+#define MAX_LEADBYTES 12
+#define MAX_DEFAULTCHAR 2
+
+#define MB_PRECOMPOSED 0x00000001
+#define MB_COMPOSITE 0x00000002
+#define MB_USEGLYPHCHARS 0x00000004
+#define MB_ERR_INVALID_CHARS 0x00000008
+
+#define WC_COMPOSITECHECK 0x00000200
+#define WC_DISCARDNS 0x00000010
+#define WC_SEPCHARS 0x00000020
+#define WC_DEFAULTCHAR 0x00000040
+#define WC_NO_BEST_FIT_CHARS 0x00000400
+
+#define CT_CTYPE1 0x00000001
+#define CT_CTYPE2 0x00000002
+#define CT_CTYPE3 0x00000004
+
+#define C1_UPPER 0x0001
+#define C1_LOWER 0x0002
+#define C1_DIGIT 0x0004
+#define C1_SPACE 0x0008
+#define C1_PUNCT 0x0010
+#define C1_CNTRL 0x0020
+#define C1_BLANK 0x0040
+#define C1_XDIGIT 0x0080
+#define C1_ALPHA 0x0100
+#define C1_DEFINED 0x0200
+
+#define C2_LEFTTORIGHT 0x0001
+#define C2_RIGHTTOLEFT 0x0002
+
+#define C2_EUROPENUMBER 0x0003
+#define C2_EUROPESEPARATOR 0x0004
+#define C2_EUROPETERMINATOR 0x0005
+#define C2_ARABICNUMBER 0x0006
+#define C2_COMMONSEPARATOR 0x0007
+
+#define C2_BLOCKSEPARATOR 0x0008
+#define C2_SEGMENTSEPARATOR 0x0009
+#define C2_WHITESPACE 0x000A
+#define C2_OTHERNEUTRAL 0x000B
+
+#define C2_NOTAPPLICABLE 0x0000
+
+#define C3_NONSPACING 0x0001
+#define C3_DIACRITIC 0x0002
+#define C3_VOWELMARK 0x0004
+#define C3_SYMBOL 0x0008
+
+#define C3_KATAKANA 0x0010
+#define C3_HIRAGANA 0x0020
+#define C3_HALFWIDTH 0x0040
+#define C3_FULLWIDTH 0x0080
+#define C3_IDEOGRAPH 0x0100
+#define C3_KASHIDA 0x0200
+#define C3_LEXICAL 0x0400
+
+#define C3_ALPHA 0x8000
+
+#define C3_NOTAPPLICABLE 0x0000
+
+#define NORM_IGNORECASE 0x00000001
+#define NORM_IGNORENONSPACE 0x00000002
+#define NORM_IGNORESYMBOLS 0x00000004
+
+#define NORM_IGNOREKANATYPE 0x00010000
+#define NORM_IGNOREWIDTH 0x00020000
+
+#define MAP_FOLDCZONE 0x00000010
+#define MAP_PRECOMPOSED 0x00000020
+#define MAP_COMPOSITE 0x00000040
+#define MAP_FOLDDIGITS 0x00000080
+#define MAP_EXPAND_LIGATURES 0x00002000
+
+#define LCMAP_LOWERCASE 0x00000100
+#define LCMAP_UPPERCASE 0x00000200
+#define LCMAP_SORTKEY 0x00000400
+#define LCMAP_BYTEREV 0x00000800
+
+#define LCMAP_HIRAGANA 0x00100000
+#define LCMAP_KATAKANA 0x00200000
+#define LCMAP_HALFWIDTH 0x00400000
+#define LCMAP_FULLWIDTH 0x00800000
+
+#define LCMAP_LINGUISTIC_CASING 0x01000000
+
+#define LCMAP_SIMPLIFIED_CHINESE 0x02000000
+#define LCMAP_TRADITIONAL_CHINESE 0x04000000
+
+#define LGRPID_INSTALLED 0x00000001
+#define LGRPID_SUPPORTED 0x00000002
+
+#define LCID_INSTALLED 0x00000001
+#define LCID_SUPPORTED 0x00000002
+#define LCID_ALTERNATE_SORTS 0x00000004
+
+#define CP_INSTALLED 0x00000001
+#define CP_SUPPORTED 0x00000002
+
+#define SORT_STRINGSORT 0x00001000
+
+#define CSTR_LESS_THAN 1
+#define CSTR_EQUAL 2
+#define CSTR_GREATER_THAN 3
+
+#define CP_ACP 0
+#define CP_OEMCP 1
+#define CP_MACCP 2
+#define CP_THREAD_ACP 3
+#define CP_SYMBOL 42
+
+#define CP_UTF7 65000
+#define CP_UTF8 65001
+
+#define CTRY_DEFAULT 0
+
+#define CTRY_ALBANIA 355
+#define CTRY_ALGERIA 213
+#define CTRY_ARGENTINA 54
+#define CTRY_ARMENIA 374
+#define CTRY_AUSTRALIA 61
+#define CTRY_AUSTRIA 43
+#define CTRY_AZERBAIJAN 994
+#define CTRY_BAHRAIN 973
+#define CTRY_BELARUS 375
+#define CTRY_BELGIUM 32
+#define CTRY_BELIZE 501
+#define CTRY_BOLIVIA 591
+#define CTRY_BRAZIL 55
+#define CTRY_BRUNEI_DARUSSALAM 673
+#define CTRY_BULGARIA 359
+#define CTRY_CANADA 2
+#define CTRY_CARIBBEAN 1
+#define CTRY_CHILE 56
+#define CTRY_COLOMBIA 57
+#define CTRY_COSTA_RICA 506
+#define CTRY_CROATIA 385
+#define CTRY_CZECH 420
+#define CTRY_DENMARK 45
+#define CTRY_DOMINICAN_REPUBLIC 1
+#define CTRY_ECUADOR 593
+#define CTRY_EGYPT 20
+#define CTRY_EL_SALVADOR 503
+#define CTRY_ESTONIA 372
+#define CTRY_FAEROE_ISLANDS 298
+#define CTRY_FINLAND 358
+#define CTRY_FRANCE 33
+#define CTRY_GEORGIA 995
+#define CTRY_GERMANY 49
+#define CTRY_GREECE 30
+#define CTRY_GUATEMALA 502
+#define CTRY_HONDURAS 504
+#define CTRY_HONG_KONG 852
+#define CTRY_HUNGARY 36
+#define CTRY_ICELAND 354
+#define CTRY_INDIA 91
+#define CTRY_INDONESIA 62
+#define CTRY_IRAN 981
+#define CTRY_IRAQ 964
+#define CTRY_IRELAND 353
+#define CTRY_ISRAEL 972
+#define CTRY_ITALY 39
+#define CTRY_JAMAICA 1
+#define CTRY_JAPAN 81
+#define CTRY_JORDAN 962
+#define CTRY_KAZAKSTAN 7
+#define CTRY_KENYA 254
+#define CTRY_KUWAIT 965
+#define CTRY_KYRGYZSTAN 996
+#define CTRY_LATVIA 371
+#define CTRY_LEBANON 961
+#define CTRY_LIBYA 218
+#define CTRY_LIECHTENSTEIN 41
+#define CTRY_LITHUANIA 370
+#define CTRY_LUXEMBOURG 352
+#define CTRY_MACAU 853
+#define CTRY_MACEDONIA 389
+#define CTRY_MALAYSIA 60
+#define CTRY_MALDIVES 960
+#define CTRY_MEXICO 52
+#define CTRY_MONACO 33
+#define CTRY_MONGOLIA 976
+#define CTRY_MOROCCO 212
+#define CTRY_NETHERLANDS 31
+#define CTRY_NEW_ZEALAND 64
+#define CTRY_NICARAGUA 505
+#define CTRY_NORWAY 47
+#define CTRY_OMAN 968
+#define CTRY_PAKISTAN 92
+#define CTRY_PANAMA 507
+#define CTRY_PARAGUAY 595
+#define CTRY_PERU 51
+#define CTRY_PHILIPPINES 63
+#define CTRY_POLAND 48
+#define CTRY_PORTUGAL 351
+#define CTRY_PRCHINA 86
+#define CTRY_PUERTO_RICO 1
+#define CTRY_QATAR 974
+#define CTRY_ROMANIA 40
+#define CTRY_RUSSIA 7
+#define CTRY_SAUDI_ARABIA 966
+#define CTRY_SERBIA 381
+#define CTRY_SINGAPORE 65
+#define CTRY_SLOVAK 421
+#define CTRY_SLOVENIA 386
+#define CTRY_SOUTH_AFRICA 27
+#define CTRY_SOUTH_KOREA 82
+#define CTRY_SPAIN 34
+#define CTRY_SWEDEN 46
+#define CTRY_SWITZERLAND 41
+#define CTRY_SYRIA 963
+#define CTRY_TAIWAN 886
+#define CTRY_TATARSTAN 7
+#define CTRY_THAILAND 66
+#define CTRY_TRINIDAD_Y_TOBAGO 1
+#define CTRY_TUNISIA 216
+#define CTRY_TURKEY 90
+#define CTRY_UAE 971
+#define CTRY_UKRAINE 380
+#define CTRY_UNITED_KINGDOM 44
+#define CTRY_UNITED_STATES 1
+#define CTRY_URUGUAY 598
+#define CTRY_UZBEKISTAN 7
+#define CTRY_VENEZUELA 58
+#define CTRY_VIET_NAM 84
+#define CTRY_YEMEN 967
+#define CTRY_ZIMBABWE 263
+
+#define LOCALE_NOUSEROVERRIDE 0x80000000
+#define LOCALE_USE_CP_ACP 0x40000000
+#define LOCALE_RETURN_NUMBER 0x20000000
+
+#define LOCALE_ILANGUAGE 0x00000001
+#define LOCALE_SLANGUAGE 0x00000002
+#define LOCALE_SENGLANGUAGE 0x00001001
+#define LOCALE_SABBREVLANGNAME 0x00000003
+#define LOCALE_SNATIVELANGNAME 0x00000004
+
+#define LOCALE_ICOUNTRY 0x00000005
+#define LOCALE_SCOUNTRY 0x00000006
+#define LOCALE_SENGCOUNTRY 0x00001002
+#define LOCALE_SABBREVCTRYNAME 0x00000007
+#define LOCALE_SNATIVECTRYNAME 0x00000008
+
+#define LOCALE_IDEFAULTLANGUAGE 0x00000009
+#define LOCALE_IDEFAULTCOUNTRY 0x0000000A
+#define LOCALE_IDEFAULTCODEPAGE 0x0000000B
+#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004
+#define LOCALE_IDEFAULTMACCODEPAGE 0x00001011
+
+#define LOCALE_SLIST 0x0000000C
+#define LOCALE_IMEASURE 0x0000000D
+
+#define LOCALE_SDECIMAL 0x0000000E
+#define LOCALE_STHOUSAND 0x0000000F
+#define LOCALE_SGROUPING 0x00000010
+#define LOCALE_IDIGITS 0x00000011
+#define LOCALE_ILZERO 0x00000012
+#define LOCALE_INEGNUMBER 0x00001010
+#define LOCALE_SNATIVEDIGITS 0x00000013
+
+#define LOCALE_SCURRENCY 0x00000014
+#define LOCALE_SINTLSYMBOL 0x00000015
+#define LOCALE_SMONDECIMALSEP 0x00000016
+#define LOCALE_SMONTHOUSANDSEP 0x00000017
+#define LOCALE_SMONGROUPING 0x00000018
+#define LOCALE_ICURRDIGITS 0x00000019
+#define LOCALE_IINTLCURRDIGITS 0x0000001A
+#define LOCALE_ICURRENCY 0x0000001B
+#define LOCALE_INEGCURR 0x0000001C
+
+#define LOCALE_SDATE 0x0000001D
+#define LOCALE_STIME 0x0000001E
+#define LOCALE_SSHORTDATE 0x0000001F
+#define LOCALE_SLONGDATE 0x00000020
+#define LOCALE_STIMEFORMAT 0x00001003
+#define LOCALE_IDATE 0x00000021
+#define LOCALE_ILDATE 0x00000022
+#define LOCALE_ITIME 0x00000023
+#define LOCALE_ITIMEMARKPOSN 0x00001005
+#define LOCALE_ICENTURY 0x00000024
+#define LOCALE_ITLZERO 0x00000025
+#define LOCALE_IDAYLZERO 0x00000026
+#define LOCALE_IMONLZERO 0x00000027
+#define LOCALE_S1159 0x00000028
+#define LOCALE_S2359 0x00000029
+
+#define LOCALE_ICALENDARTYPE 0x00001009
+#define LOCALE_IOPTIONALCALENDAR 0x0000100B
+#define LOCALE_IFIRSTDAYOFWEEK 0x0000100C
+#define LOCALE_IFIRSTWEEKOFYEAR 0x0000100D
+
+#define LOCALE_SDAYNAME1 0x0000002A
+#define LOCALE_SDAYNAME2 0x0000002B
+#define LOCALE_SDAYNAME3 0x0000002C
+#define LOCALE_SDAYNAME4 0x0000002D
+#define LOCALE_SDAYNAME5 0x0000002E
+#define LOCALE_SDAYNAME6 0x0000002F
+#define LOCALE_SDAYNAME7 0x00000030
+#define LOCALE_SABBREVDAYNAME1 0x00000031
+#define LOCALE_SABBREVDAYNAME2 0x00000032
+#define LOCALE_SABBREVDAYNAME3 0x00000033
+#define LOCALE_SABBREVDAYNAME4 0x00000034
+#define LOCALE_SABBREVDAYNAME5 0x00000035
+#define LOCALE_SABBREVDAYNAME6 0x00000036
+#define LOCALE_SABBREVDAYNAME7 0x00000037
+#define LOCALE_SMONTHNAME1 0x00000038
+#define LOCALE_SMONTHNAME2 0x00000039
+#define LOCALE_SMONTHNAME3 0x0000003A
+#define LOCALE_SMONTHNAME4 0x0000003B
+#define LOCALE_SMONTHNAME5 0x0000003C
+#define LOCALE_SMONTHNAME6 0x0000003D
+#define LOCALE_SMONTHNAME7 0x0000003E
+#define LOCALE_SMONTHNAME8 0x0000003F
+#define LOCALE_SMONTHNAME9 0x00000040
+#define LOCALE_SMONTHNAME10 0x00000041
+#define LOCALE_SMONTHNAME11 0x00000042
+#define LOCALE_SMONTHNAME12 0x00000043
+#define LOCALE_SMONTHNAME13 0x0000100E
+#define LOCALE_SABBREVMONTHNAME1 0x00000044
+#define LOCALE_SABBREVMONTHNAME2 0x00000045
+#define LOCALE_SABBREVMONTHNAME3 0x00000046
+#define LOCALE_SABBREVMONTHNAME4 0x00000047
+#define LOCALE_SABBREVMONTHNAME5 0x00000048
+#define LOCALE_SABBREVMONTHNAME6 0x00000049
+#define LOCALE_SABBREVMONTHNAME7 0x0000004A
+#define LOCALE_SABBREVMONTHNAME8 0x0000004B
+#define LOCALE_SABBREVMONTHNAME9 0x0000004C
+#define LOCALE_SABBREVMONTHNAME10 0x0000004D
+#define LOCALE_SABBREVMONTHNAME11 0x0000004E
+#define LOCALE_SABBREVMONTHNAME12 0x0000004F
+#define LOCALE_SABBREVMONTHNAME13 0x0000100F
+
+#define LOCALE_SPOSITIVESIGN 0x00000050
+#define LOCALE_SNEGATIVESIGN 0x00000051
+#define LOCALE_IPOSSIGNPOSN 0x00000052
+#define LOCALE_INEGSIGNPOSN 0x00000053
+#define LOCALE_IPOSSYMPRECEDES 0x00000054
+#define LOCALE_IPOSSEPBYSPACE 0x00000055
+#define LOCALE_INEGSYMPRECEDES 0x00000056
+#define LOCALE_INEGSEPBYSPACE 0x00000057
+#define LOCALE_FONTSIGNATURE 0x00000058
+#define LOCALE_SISO639LANGNAME 0x00000059
+#define LOCALE_SISO3166CTRYNAME 0x0000005A
+
+#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x00001012
+#define LOCALE_IPAPERSIZE 0x0000100A
+#define LOCALE_SENGCURRNAME 0x00001007
+#define LOCALE_SNATIVECURRNAME 0x00001008
+#define LOCALE_SYEARMONTH 0x00001006
+#define LOCALE_SSORTNAME 0x00001013
+#define LOCALE_IDIGITSUBSTITUTION 0x00001014
+
+#define TIME_NOMINUTESORSECONDS 0x00000001
+#define TIME_NOSECONDS 0x00000002
+#define TIME_NOTIMEMARKER 0x00000004
+#define TIME_FORCE24HOURFORMAT 0x00000008
+
+#define DATE_SHORTDATE 0x00000001
+#define DATE_LONGDATE 0x00000002
+#define DATE_USE_ALT_CALENDAR 0x00000004
+#define DATE_YEARMONTH 0x00000008
+#define DATE_LTRREADING 0x00000010
+#define DATE_RTLREADING 0x00000020
+
+#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE
+#define CAL_USE_CP_ACP LOCALE_USE_CP_ACP
+#define CAL_RETURN_NUMBER LOCALE_RETURN_NUMBER
+
+#define CAL_ICALINTVALUE 0x00000001
+#define CAL_SCALNAME 0x00000002
+#define CAL_IYEAROFFSETRANGE 0x00000003
+#define CAL_SERASTRING 0x00000004
+#define CAL_SSHORTDATE 0x00000005
+#define CAL_SLONGDATE 0x00000006
+#define CAL_SDAYNAME1 0x00000007
+#define CAL_SDAYNAME2 0x00000008
+#define CAL_SDAYNAME3 0x00000009
+#define CAL_SDAYNAME4 0x0000000a
+#define CAL_SDAYNAME5 0x0000000b
+#define CAL_SDAYNAME6 0x0000000c
+#define CAL_SDAYNAME7 0x0000000d
+#define CAL_SABBREVDAYNAME1 0x0000000e
+#define CAL_SABBREVDAYNAME2 0x0000000f
+#define CAL_SABBREVDAYNAME3 0x00000010
+#define CAL_SABBREVDAYNAME4 0x00000011
+#define CAL_SABBREVDAYNAME5 0x00000012
+#define CAL_SABBREVDAYNAME6 0x00000013
+#define CAL_SABBREVDAYNAME7 0x00000014
+#define CAL_SMONTHNAME1 0x00000015
+#define CAL_SMONTHNAME2 0x00000016
+#define CAL_SMONTHNAME3 0x00000017
+#define CAL_SMONTHNAME4 0x00000018
+#define CAL_SMONTHNAME5 0x00000019
+#define CAL_SMONTHNAME6 0x0000001a
+#define CAL_SMONTHNAME7 0x0000001b
+#define CAL_SMONTHNAME8 0x0000001c
+#define CAL_SMONTHNAME9 0x0000001d
+#define CAL_SMONTHNAME10 0x0000001e
+#define CAL_SMONTHNAME11 0x0000001f
+#define CAL_SMONTHNAME12 0x00000020
+#define CAL_SMONTHNAME13 0x00000021
+#define CAL_SABBREVMONTHNAME1 0x00000022
+#define CAL_SABBREVMONTHNAME2 0x00000023
+#define CAL_SABBREVMONTHNAME3 0x00000024
+#define CAL_SABBREVMONTHNAME4 0x00000025
+#define CAL_SABBREVMONTHNAME5 0x00000026
+#define CAL_SABBREVMONTHNAME6 0x00000027
+#define CAL_SABBREVMONTHNAME7 0x00000028
+#define CAL_SABBREVMONTHNAME8 0x00000029
+#define CAL_SABBREVMONTHNAME9 0x0000002a
+#define CAL_SABBREVMONTHNAME10 0x0000002b
+#define CAL_SABBREVMONTHNAME11 0x0000002c
+#define CAL_SABBREVMONTHNAME12 0x0000002d
+#define CAL_SABBREVMONTHNAME13 0x0000002e
+#define CAL_SYEARMONTH 0x0000002f
+#define CAL_ITWODIGITYEARMAX 0x00000030
+
+#define ENUM_ALL_CALENDARS 0xffffffff
+
+#define CAL_GREGORIAN 1
+#define CAL_GREGORIAN_US 2
+#define CAL_JAPAN 3
+#define CAL_TAIWAN 4
+#define CAL_KOREA 5
+#define CAL_HIJRI 6
+#define CAL_THAI 7
+#define CAL_HEBREW 8
+#define CAL_GREGORIAN_ME_FRENCH 9
+#define CAL_GREGORIAN_ARABIC 10
+#define CAL_GREGORIAN_XLIT_ENGLISH 11
+#define CAL_GREGORIAN_XLIT_FRENCH 12
+
+#define LGRPID_WESTERN_EUROPE 0x0001
+#define LGRPID_CENTRAL_EUROPE 0x0002
+#define LGRPID_BALTIC 0x0003
+#define LGRPID_GREEK 0x0004
+#define LGRPID_CYRILLIC 0x0005
+#define LGRPID_TURKISH 0x0006
+#define LGRPID_JAPANESE 0x0007
+#define LGRPID_KOREAN 0x0008
+#define LGRPID_TRADITIONAL_CHINESE 0x0009
+#define LGRPID_SIMPLIFIED_CHINESE 0x000a
+#define LGRPID_THAI 0x000b
+#define LGRPID_HEBREW 0x000c
+#define LGRPID_ARABIC 0x000d
+#define LGRPID_VIETNAMESE 0x000e
+#define LGRPID_INDIC 0x000f
+#define LGRPID_GEORGIAN 0x0010
+#define LGRPID_ARMENIAN 0x0011
+
+ typedef DWORD LGRPID;
+ typedef DWORD LCTYPE;
+ typedef DWORD CALTYPE;
+ typedef DWORD CALID;
+
+ typedef struct _cpinfo {
+ UINT MaxCharSize;
+ BYTE DefaultChar[MAX_DEFAULTCHAR];
+ BYTE LeadByte[MAX_LEADBYTES];
+ } CPINFO,*LPCPINFO;
+
+ typedef struct _cpinfoexA {
+ UINT MaxCharSize;
+ BYTE DefaultChar[MAX_DEFAULTCHAR];
+ BYTE LeadByte[MAX_LEADBYTES];
+ WCHAR UnicodeDefaultChar;
+ UINT CodePage;
+ CHAR CodePageName[MAX_PATH];
+ } CPINFOEXA,*LPCPINFOEXA;
+
+ typedef struct _cpinfoexW {
+ UINT MaxCharSize;
+ BYTE DefaultChar[MAX_DEFAULTCHAR];
+ BYTE LeadByte[MAX_LEADBYTES];
+ WCHAR UnicodeDefaultChar;
+ UINT CodePage;
+ WCHAR CodePageName[MAX_PATH];
+ } CPINFOEXW,*LPCPINFOEXW;
+
+#ifdef UNICODE
+ typedef CPINFOEXW CPINFOEX;
+ typedef LPCPINFOEXW LPCPINFOEX;
+#else
+ typedef CPINFOEXA CPINFOEX;
+ typedef LPCPINFOEXA LPCPINFOEX;
+#endif
+
+ typedef struct _numberfmtA {
+ UINT NumDigits;
+ UINT LeadingZero;
+ UINT Grouping;
+ LPSTR lpDecimalSep;
+ LPSTR lpThousandSep;
+ UINT NegativeOrder;
+ } NUMBERFMTA,*LPNUMBERFMTA;
+
+ typedef struct _numberfmtW {
+ UINT NumDigits;
+ UINT LeadingZero;
+ UINT Grouping;
+ LPWSTR lpDecimalSep;
+ LPWSTR lpThousandSep;
+ UINT NegativeOrder;
+ } NUMBERFMTW,*LPNUMBERFMTW;
+
+#ifdef UNICODE
+ typedef NUMBERFMTW NUMBERFMT;
+ typedef LPNUMBERFMTW LPNUMBERFMT;
+#else
+ typedef NUMBERFMTA NUMBERFMT;
+ typedef LPNUMBERFMTA LPNUMBERFMT;
+#endif
+
+ typedef struct _currencyfmtA {
+ UINT NumDigits;
+ UINT LeadingZero;
+ UINT Grouping;
+ LPSTR lpDecimalSep;
+ LPSTR lpThousandSep;
+ UINT NegativeOrder;
+ UINT PositiveOrder;
+ LPSTR lpCurrencySymbol;
+ } CURRENCYFMTA,*LPCURRENCYFMTA;
+
+ typedef struct _currencyfmtW {
+ UINT NumDigits;
+ UINT LeadingZero;
+ UINT Grouping;
+ LPWSTR lpDecimalSep;
+ LPWSTR lpThousandSep;
+ UINT NegativeOrder;
+ UINT PositiveOrder;
+ LPWSTR lpCurrencySymbol;
+ } CURRENCYFMTW,*LPCURRENCYFMTW;
+
+#ifdef UNICODE
+ typedef CURRENCYFMTW CURRENCYFMT;
+ typedef LPCURRENCYFMTW LPCURRENCYFMT;
+#else
+ typedef CURRENCYFMTA CURRENCYFMT;
+ typedef LPCURRENCYFMTA LPCURRENCYFMT;
+#endif
+
+ enum SYSNLS_FUNCTION {
+ COMPARE_STRING = 0x0001
+ };
+
+ typedef DWORD NLS_FUNCTION;
+
+ typedef struct _nlsversioninfo{
+ DWORD dwNLSVersionInfoSize;
+ DWORD dwNLSVersion;
+ DWORD dwDefinedVersion;
+ } NLSVERSIONINFO,*LPNLSVERSIONINFO;
+
+ typedef LONG GEOID;
+ typedef DWORD GEOTYPE;
+ typedef DWORD GEOCLASS;
+
+#define GEOID_NOT_AVAILABLE -1
+
+ enum SYSGEOTYPE {
+ GEO_NATION = 0x0001,GEO_LATITUDE = 0x0002,GEO_LONGITUDE = 0x0003,GEO_ISO2 = 0x0004,GEO_ISO3 = 0x0005,GEO_RFC1766 = 0x0006,GEO_LCID = 0x0007,
+ GEO_FRIENDLYNAME= 0x0008,GEO_OFFICIALNAME= 0x0009,GEO_TIMEZONES = 0x000A,GEO_OFFICIALLANGUAGES = 0x000B
+ };
+
+ enum SYSGEOCLASS {
+ GEOCLASS_NATION = 16,GEOCLASS_REGION = 14
+ };
+
+ typedef enum _NORM_FORM {
+ NormalizationOther = 0,
+ NormalizationC = 0x1,
+ NormalizationD = 0x2,
+ NormalizationKC = 0x5,
+ NormalizationKD = 0x6
+} NORM_FORM;
+
+ typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCA)(LGRPID,LPSTR,LPSTR,DWORD,LONG_PTR);
+ typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCA)(LGRPID,LCID,LPSTR,LONG_PTR);
+ typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCA)(LPSTR,LONG_PTR);
+ typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCA)(LPSTR);
+ typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCA)(LPSTR);
+ typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCA)(LPSTR);
+ typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXA)(LPSTR,CALID);
+ typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCA)(LPSTR);
+ typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCA)(LPSTR);
+ typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXA)(LPSTR,CALID);
+ typedef WINBOOL (CALLBACK *LANGUAGEGROUP_ENUMPROCW)(LGRPID,LPWSTR,LPWSTR,DWORD,LONG_PTR);
+ typedef WINBOOL (CALLBACK *LANGGROUPLOCALE_ENUMPROCW)(LGRPID,LCID,LPWSTR,LONG_PTR);
+ typedef WINBOOL (CALLBACK *UILANGUAGE_ENUMPROCW)(LPWSTR,LONG_PTR);
+ typedef WINBOOL (CALLBACK *LOCALE_ENUMPROCW)(LPWSTR);
+ typedef WINBOOL (CALLBACK *CODEPAGE_ENUMPROCW)(LPWSTR);
+ typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR);
+ typedef WINBOOL (CALLBACK *DATEFMT_ENUMPROCEXW)(LPWSTR,CALID);
+ typedef WINBOOL (CALLBACK *TIMEFMT_ENUMPROCW)(LPWSTR);
+ typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCW)(LPWSTR);
+ typedef WINBOOL (CALLBACK *CALINFO_ENUMPROCEXW)(LPWSTR,CALID);
+ typedef WINBOOL (CALLBACK *GEO_ENUMPROC)(GEOID);
+
+#ifdef UNICODE
+#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCW
+#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCW
+#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCW
+#define LOCALE_ENUMPROC LOCALE_ENUMPROCW
+#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCW
+#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCW
+#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXW
+#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCW
+#define CALINFO_ENUMPROC CALINFO_ENUMPROCW
+#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXW
+#else
+#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCA
+#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCA
+#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCA
+#define LOCALE_ENUMPROC LOCALE_ENUMPROCA
+#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCA
+#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCA
+#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXA
+#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCA
+#define CALINFO_ENUMPROC CALINFO_ENUMPROCA
+#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXA
+#endif
+
+#ifdef UNICODE
+#define GetCPInfoEx GetCPInfoExW
+#define CompareString CompareStringW
+#define LCMapString LCMapStringW
+#define GetLocaleInfo GetLocaleInfoW
+#define SetLocaleInfo SetLocaleInfoW
+#define GetCalendarInfo GetCalendarInfoW
+#define SetCalendarInfo SetCalendarInfoW
+#define GetTimeFormat GetTimeFormatW
+#define GetDateFormat GetDateFormatW
+#define GetNumberFormat GetNumberFormatW
+#define GetCurrencyFormat GetCurrencyFormatW
+#define EnumCalendarInfo EnumCalendarInfoW
+#define EnumCalendarInfoEx EnumCalendarInfoExW
+#define EnumTimeFormats EnumTimeFormatsW
+#define EnumDateFormats EnumDateFormatsW
+#define EnumDateFormatsEx EnumDateFormatsExW
+#define GetGeoInfo GetGeoInfoW
+#define GetStringTypeEx GetStringTypeExW
+#define FoldString FoldStringW
+#define EnumSystemLanguageGroups EnumSystemLanguageGroupsW
+#define EnumLanguageGroupLocales EnumLanguageGroupLocalesW
+#define EnumUILanguages EnumUILanguagesW
+#define EnumSystemLocales EnumSystemLocalesW
+#define EnumSystemCodePages EnumSystemCodePagesW
+#else
+#define GetCPInfoEx GetCPInfoExA
+#define CompareString CompareStringA
+#define LCMapString LCMapStringA
+#define GetLocaleInfo GetLocaleInfoA
+#define SetLocaleInfo SetLocaleInfoA
+#define GetCalendarInfo GetCalendarInfoA
+#define SetCalendarInfo SetCalendarInfoA
+#define GetTimeFormat GetTimeFormatA
+#define GetDateFormat GetDateFormatA
+#define GetNumberFormat GetNumberFormatA
+#define GetCurrencyFormat GetCurrencyFormatA
+#define EnumCalendarInfo EnumCalendarInfoA
+#define EnumCalendarInfoEx EnumCalendarInfoExA
+#define EnumTimeFormats EnumTimeFormatsA
+#define EnumDateFormats EnumDateFormatsA
+#define EnumDateFormatsEx EnumDateFormatsExA
+#define GetGeoInfo GetGeoInfoA
+#define GetStringTypeEx GetStringTypeExA
+#define FoldString FoldStringA
+#define EnumSystemLanguageGroups EnumSystemLanguageGroupsA
+#define EnumLanguageGroupLocales EnumLanguageGroupLocalesA
+#define EnumUILanguages EnumUILanguagesA
+#define EnumSystemLocales EnumSystemLocalesA
+#define EnumSystemCodePages EnumSystemCodePagesA
+#endif
+
+ WINBASEAPI WINBOOL WINAPI IsValidCodePage(UINT CodePage);
+ WINBASEAPI UINT WINAPI GetACP(void);
+ WINBASEAPI UINT WINAPI GetOEMCP(void);
+ WINBASEAPI WINBOOL WINAPI GetCPInfo(UINT CodePage,LPCPINFO lpCPInfo);
+ WINBASEAPI WINBOOL WINAPI GetCPInfoExA(UINT CodePage,DWORD dwFlags,LPCPINFOEXA lpCPInfoEx);
+ WINBASEAPI WINBOOL WINAPI GetCPInfoExW(UINT CodePage,DWORD dwFlags,LPCPINFOEXW lpCPInfoEx);
+ WINBASEAPI WINBOOL WINAPI IsDBCSLeadByte(BYTE TestChar);
+ WINBASEAPI WINBOOL WINAPI IsDBCSLeadByteEx(UINT CodePage,BYTE TestChar);
+ WINBASEAPI int WINAPI MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cbMultiByte,LPWSTR lpWideCharStr,int cchWideChar);
+ WINBASEAPI int WINAPI WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cbMultiByte,LPCSTR lpDefaultChar,LPBOOL lpUsedDefaultChar);
+ WINBASEAPI int WINAPI CompareStringA(LCID Locale,DWORD dwCmpFlags,LPCSTR lpString1,int cchCount1,LPCSTR lpString2,int cchCount2);
+ WINBASEAPI int WINAPI CompareStringW(LCID Locale,DWORD dwCmpFlags,LPCWSTR lpString1,int cchCount1,LPCWSTR lpString2,int cchCount2);
+ WINBASEAPI int WINAPI LCMapStringA(LCID Locale,DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest);
+ WINBASEAPI int WINAPI LCMapStringW(LCID Locale,DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest);
+ WINBASEAPI int WINAPI GetLocaleInfoA(LCID Locale,LCTYPE LCType,LPSTR lpLCData,int cchData);
+ WINBASEAPI int WINAPI GetLocaleInfoW(LCID Locale,LCTYPE LCType,LPWSTR lpLCData,int cchData);
+ WINBASEAPI WINBOOL WINAPI SetLocaleInfoA(LCID Locale,LCTYPE LCType,LPCSTR lpLCData);
+ WINBASEAPI WINBOOL WINAPI SetLocaleInfoW(LCID Locale,LCTYPE LCType,LPCWSTR lpLCData);
+ WINBASEAPI int WINAPI GetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPSTR lpCalData,int cchData,LPDWORD lpValue);
+ WINBASEAPI int WINAPI GetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPWSTR lpCalData,int cchData,LPDWORD lpValue);
+ WINBASEAPI WINBOOL WINAPI SetCalendarInfoA(LCID Locale,CALID Calendar,CALTYPE CalType,LPCSTR lpCalData);
+ WINBASEAPI WINBOOL WINAPI SetCalendarInfoW(LCID Locale,CALID Calendar,CALTYPE CalType,LPCWSTR lpCalData);
+ WINBASEAPI int WINAPI GetTimeFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCSTR lpFormat,LPSTR lpTimeStr,int cchTime);
+ WINBASEAPI int WINAPI GetTimeFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpTime,LPCWSTR lpFormat,LPWSTR lpTimeStr,int cchTime);
+ WINBASEAPI int WINAPI GetDateFormatA(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCSTR lpFormat,LPSTR lpDateStr,int cchDate);
+ WINBASEAPI int WINAPI GetDateFormatW(LCID Locale,DWORD dwFlags,CONST SYSTEMTIME *lpDate,LPCWSTR lpFormat,LPWSTR lpDateStr,int cchDate);
+ WINBASEAPI int WINAPI GetNumberFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST NUMBERFMTA *lpFormat,LPSTR lpNumberStr,int cchNumber);
+ WINBASEAPI int WINAPI GetNumberFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST NUMBERFMTW *lpFormat,LPWSTR lpNumberStr,int cchNumber);
+ WINBASEAPI int WINAPI GetCurrencyFormatA(LCID Locale,DWORD dwFlags,LPCSTR lpValue,CONST CURRENCYFMTA *lpFormat,LPSTR lpCurrencyStr,int cchCurrency);
+ WINBASEAPI int WINAPI GetCurrencyFormatW(LCID Locale,DWORD dwFlags,LPCWSTR lpValue,CONST CURRENCYFMTW *lpFormat,LPWSTR lpCurrencyStr,int cchCurrency);
+ WINBASEAPI WINBOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType);
+ WINBASEAPI WINBOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW lpCalInfoEnumProc,LCID Locale,CALID Calendar,CALTYPE CalType);
+ WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType);
+ WINBASEAPI WINBOOL WINAPI EnumCalendarInfoExW(CALINFO_ENUMPROCEXW lpCalInfoEnumProcEx,LCID Locale,CALID Calendar,CALTYPE CalType);
+ WINBASEAPI WINBOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,LCID Locale,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA lpDateFmtEnumProc,LCID Locale,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW lpDateFmtEnumProc,LCID Locale,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,LCID Locale,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI IsValidLanguageGroup(LGRPID LanguageGroup,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI GetNLSVersion(NLS_FUNCTION Function,LCID Locale,LPNLSVERSIONINFO lpVersionInformation);
+ WINBASEAPI WINBOOL WINAPI IsNLSDefinedString(NLS_FUNCTION Function,DWORD dwFlags,LPNLSVERSIONINFO lpVersionInformation,LPCWSTR lpString,INT cchStr);
+ WINBASEAPI WINBOOL WINAPI IsValidLocale(LCID Locale,DWORD dwFlags);
+ WINBASEAPI int WINAPI GetGeoInfoA(GEOID Location,GEOTYPE GeoType,LPSTR lpGeoData,int cchData,LANGID LangId);
+ WINBASEAPI int WINAPI GetGeoInfoW(GEOID Location,GEOTYPE GeoType,LPWSTR lpGeoData,int cchData,LANGID LangId);
+ WINBASEAPI WINBOOL WINAPI EnumSystemGeoID(GEOCLASS GeoClass,GEOID ParentGeoId,GEO_ENUMPROC lpGeoEnumProc);
+ WINBASEAPI GEOID WINAPI GetUserGeoID(GEOCLASS GeoClass);
+ WINBASEAPI WINBOOL WINAPI SetUserGeoID(GEOID GeoId);
+ WINBASEAPI LCID WINAPI ConvertDefaultLocale(LCID Locale);
+ WINBASEAPI LCID WINAPI GetThreadLocale(void);
+ WINBASEAPI WINBOOL WINAPI SetThreadLocale(LCID Locale);
+ WINBASEAPI LANGID WINAPI GetSystemDefaultUILanguage(void);
+ WINBASEAPI LANGID WINAPI GetUserDefaultUILanguage(void);
+ WINBASEAPI LANGID WINAPI GetSystemDefaultLangID(void);
+ WINBASEAPI LANGID WINAPI GetUserDefaultLangID(void);
+ WINBASEAPI LCID WINAPI GetSystemDefaultLCID(void);
+ WINBASEAPI LCID WINAPI GetUserDefaultLCID(void);
+ WINBASEAPI WINBOOL WINAPI GetStringTypeExA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType);
+ WINBASEAPI WINBOOL WINAPI GetStringTypeExW(LCID Locale,DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType);
+ WINBASEAPI WINBOOL WINAPI GetStringTypeA(LCID Locale,DWORD dwInfoType,LPCSTR lpSrcStr,int cchSrc,LPWORD lpCharType);
+ WINBASEAPI WINBOOL WINAPI GetStringTypeW(DWORD dwInfoType,LPCWSTR lpSrcStr,int cchSrc,LPWORD lpCharType);
+ WINBASEAPI int WINAPI FoldStringA(DWORD dwMapFlags,LPCSTR lpSrcStr,int cchSrc,LPSTR lpDestStr,int cchDest);
+ WINBASEAPI int WINAPI FoldStringW(DWORD dwMapFlags,LPCWSTR lpSrcStr,int cchSrc,LPWSTR lpDestStr,int cchDest);
+ WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam);
+ WINBASEAPI WINBOOL WINAPI EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW lpLanguageGroupEnumProc,DWORD dwFlags,LONG_PTR lParam);
+ WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam);
+ WINBASEAPI WINBOOL WINAPI EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW lpLangGroupLocaleEnumProc,LGRPID LanguageGroup,DWORD dwFlags,LONG_PTR lParam);
+ WINBASEAPI WINBOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam);
+ WINBASEAPI WINBOOL WINAPI EnumUILanguagesW(UILANGUAGE_ENUMPROCW lpUILanguageEnumProc,DWORD dwFlags,LONG_PTR lParam);
+ WINBASEAPI WINBOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA lpLocaleEnumProc,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW lpLocaleEnumProc,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA lpCodePageEnumProc,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW lpCodePageEnumProc,DWORD dwFlags);
+ WINBASEAPI WINBOOL WINAPI IsNormalizedString(NORM_FORM NormForm,LPCWSTR lpString,int cwLength);
+ WINBASEAPI int WINAPI NormalizeString(NORM_FORM NormForm,LPCWSTR lpSrcString,int cwSrcLength,LPWSTR lpDstString,int cwDstLength);
+ WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpASCIICharStr,int cchASCIIChar);
+ WINBASEAPI int WINAPI IdnToNameprepUnicode(DWORD dwFlags,LPCWSTR lpUnicodeCharStr,int cchUnicodeChar,LPWSTR lpNameprepCharStr,int cchNameprepChar);
+ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,LPCWSTR lpASCIICharStr,int cchASCIIChar,LPWSTR lpUnicodeCharStr,int cchUnicodeChar);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/win32/include/winapi/winnt.h b/win32/include/winapi/winnt.h
index 4cf685d..8c33404 100644
--- a/win32/include/winapi/winnt.h
+++ b/win32/include/winapi/winnt.h
@@ -1310,7 +1310,7 @@ typedef DWORD LCID;
#define INITIAL_MXCSR 0x1f80
#define INITIAL_FPCSR 0x027f
- typedef DECLSPEC_ALIGN(16) struct _M128A {
+ typedef struct DECLSPEC_ALIGN(16) _M128A {
ULONGLONG Low;
LONGLONG High;
} M128A,*PM128A;
@@ -1336,7 +1336,7 @@ typedef DWORD LCID;
#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32)
- typedef DECLSPEC_ALIGN(16) struct _CONTEXT {
+ typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
@@ -1474,7 +1474,7 @@ typedef DWORD LCID;
#if(defined(_X86_) && !defined(__x86_64))
__CRT_INLINE VOID MemoryBarrier(VOID) {
LONG Barrier;
- __asm__ __volatile__("xchgl %eax,%0 "
+ __asm__ __volatile__("xchgl %%eax,%0 "
:"=r" (Barrier));
}
#define YieldProcessor() __asm__ __volatile__("rep nop ");
@@ -1486,7 +1486,7 @@ typedef DWORD LCID;
#define PF_NON_TEMPORAL_LEVEL_ALL
__CRT_INLINE VOID DbgRaiseAssertionFailure(void) {
- __asm__ __volatile__("int 0x2c ");
+ __asm__ __volatile__("int $0x2c ");
}
PVOID GetCurrentFiber(void);
__CRT_INLINE PVOID GetCurrentFiber(void)
@@ -3150,7 +3150,7 @@ typedef DWORD LCID;
DWORD Type;
} MEMORY_BASIC_INFORMATION32,*PMEMORY_BASIC_INFORMATION32;
- typedef DECLSPEC_ALIGN(16) struct _MEMORY_BASIC_INFORMATION64 {
+ typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 {
ULONGLONG BaseAddress;
ULONGLONG AllocationBase;
DWORD AllocationProtect;
@@ -4949,7 +4949,7 @@ typedef DWORD LCID;
#ifdef _WIN64
typedef struct _SLIST_ENTRY *PSLIST_ENTRY;
- typedef DECLSPEC_ALIGN(16) struct _SLIST_ENTRY {
+ typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY {
PSLIST_ENTRY Next;
} SLIST_ENTRY;
#else
@@ -4961,7 +4961,7 @@ typedef DWORD LCID;
#if defined(_WIN64)
- typedef DECLSPEC_ALIGN(16) struct _SLIST_HEADER {
+ typedef struct DECLSPEC_ALIGN(16) _SLIST_HEADER {
ULONGLONG Alignment;
ULONGLONG Region;
} SLIST_HEADER;
diff --git a/win32/include/winapi/winsock2.h b/win32/include/winapi/winsock2.h
new file mode 100644
index 0000000..365ace6
--- /dev/null
+++ b/win32/include/winapi/winsock2.h
@@ -0,0 +1,1474 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+
+#ifndef _WINSOCK2API_
+#define _WINSOCK2API_
+
+#ifndef INCL_WINSOCK_API_TYPEDEFS
+#define INCL_WINSOCK_API_TYPEDEFS 0
+#endif
+
+#ifndef _INC_WINDOWS
+#include <windows.h>
+#endif
+
+#ifndef MAKEWORD
+#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8))
+#endif
+
+#ifndef WINSOCK_VERSION
+#define WINSOCK_VERSION MAKEWORD(2,2)
+#endif
+
+#ifndef WINSOCK_API_LINKAGE
+#ifdef DECLSPEC_IMPORT
+#define WINSOCK_API_LINKAGE DECLSPEC_IMPORT
+#else
+#define WINSOCK_API_LINKAGE
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _WINSOCK_SOCKET_DEFINED
+#define _WINSOCK_SOCKET_DEFINED
+ typedef unsigned char u_char;
+ typedef unsigned short u_short;
+ typedef unsigned int u_int;
+ typedef unsigned long u_long;
+ __MINGW_EXTENSION typedef unsigned __int64 u_int64;
+ typedef INT_PTR SOCKET;
+#endif
+
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 64
+#endif
+
+ typedef struct fd_set {
+ u_int fd_count;
+ SOCKET fd_array[FD_SETSIZE];
+ } fd_set;
+
+ extern int WINAPI __WSAFDIsSet(SOCKET,fd_set *);
+
+#define FD_CLR(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==fd) { while (__i < ((fd_set *)(set))->fd_count-1) { ((fd_set *)(set))->fd_array[__i] = ((fd_set *)(set))->fd_array[__i+1]; __i++; } ((fd_set *)(set))->fd_count--; break; } } } while(0)
+#define FD_SET(fd,set) do { u_int __i; for(__i = 0;__i < ((fd_set *)(set))->fd_count;__i++) { if (((fd_set *)(set))->fd_array[__i]==(fd)) { break; } } if (__i==((fd_set *)(set))->fd_count) { if (((fd_set *)(set))->fd_count < FD_SETSIZE) { ((fd_set *)(set))->fd_array[__i] = (fd); ((fd_set *)(set))->fd_count++; } } } while(0)
+#define FD_ZERO(set) (((fd_set *)(set))->fd_count=0)
+#define FD_ISSET(fd,set) __WSAFDIsSet((SOCKET)(fd),(fd_set *)(set))
+
+#ifndef _TIMEVAL_DEFINED /* also in winsock[2].h */
+#define _TIMEVAL_DEFINED
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+ };
+
+#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp,uvp,cmp) ((tvp)->tv_sec cmp (uvp)->tv_sec || (tvp)->tv_sec==(uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+#endif /* _TIMEVAL_DEFINED */
+
+#define IOCPARM_MASK 0x7f
+#define IOC_VOID 0x20000000
+#define IOC_OUT 0x40000000
+#define IOC_IN 0x80000000
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+
+#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
+#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
+
+#define FIONREAD _IOR('f',127,u_long)
+#define FIONBIO _IOW('f',126,u_long)
+#define FIOASYNC _IOW('f',125,u_long)
+
+#define SIOCSHIWAT _IOW('s',0,u_long)
+#define SIOCGHIWAT _IOR('s',1,u_long)
+#define SIOCSLOWAT _IOW('s',2,u_long)
+#define SIOCGLOWAT _IOR('s',3,u_long)
+#define SIOCATMARK _IOR('s',7,u_long)
+
+#define h_addr h_addr_list[0]
+
+ struct hostent {
+ char *h_name;
+ char **h_aliases;
+ short h_addrtype;
+ short h_length;
+ char **h_addr_list;
+ };
+
+ struct netent {
+ char *n_name;
+ char **n_aliases;
+ short n_addrtype;
+ u_long n_net;
+ };
+
+ struct servent {
+ char *s_name;
+ char **s_aliases;
+#ifdef _WIN64
+ char *s_proto;
+ short s_port;
+#else
+ short s_port;
+ char *s_proto;
+#endif
+ };
+
+ struct protoent {
+ char *p_name;
+ char **p_aliases;
+ short p_proto;
+ };
+
+#define IPPROTO_IP 0
+#define IPPROTO_HOPOPTS 0
+#define IPPROTO_ICMP 1
+#define IPPROTO_IGMP 2
+#define IPPROTO_GGP 3
+#define IPPROTO_IPV4 4
+#define IPPROTO_TCP 6
+#define IPPROTO_PUP 12
+#define IPPROTO_UDP 17
+#define IPPROTO_IDP 22
+#define IPPROTO_IPV6 41
+#define IPPROTO_ROUTING 43
+#define IPPROTO_FRAGMENT 44
+#define IPPROTO_ESP 50
+#define IPPROTO_AH 51
+#define IPPROTO_ICMPV6 58
+#define IPPROTO_NONE 59
+#define IPPROTO_DSTOPTS 60
+#define IPPROTO_ND 77
+#define IPPROTO_ICLFXBM 78
+
+#define IPPROTO_RAW 255
+#define IPPROTO_MAX 256
+
+#define IPPORT_ECHO 7
+#define IPPORT_DISCARD 9
+#define IPPORT_SYSTAT 11
+#define IPPORT_DAYTIME 13
+#define IPPORT_NETSTAT 15
+#define IPPORT_FTP 21
+#define IPPORT_TELNET 23
+#define IPPORT_SMTP 25
+#define IPPORT_TIMESERVER 37
+#define IPPORT_NAMESERVER 42
+#define IPPORT_WHOIS 43
+#define IPPORT_MTP 57
+
+#define IPPORT_TFTP 69
+#define IPPORT_RJE 77
+#define IPPORT_FINGER 79
+#define IPPORT_TTYLINK 87
+#define IPPORT_SUPDUP 95
+
+#define IPPORT_EXECSERVER 512
+#define IPPORT_LOGINSERVER 513
+#define IPPORT_CMDSERVER 514
+#define IPPORT_EFSSERVER 520
+
+#define IPPORT_BIFFUDP 512
+#define IPPORT_WHOSERVER 513
+#define IPPORT_ROUTESERVER 520
+
+#define IPPORT_RESERVED 1024
+
+#define IMPLINK_IP 155
+#define IMPLINK_LOWEXPER 156
+#define IMPLINK_HIGHEXPER 158
+
+#ifndef s_addr
+
+ struct in_addr {
+ union {
+ struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
+ struct { u_short s_w1,s_w2; } S_un_w;
+ u_long S_addr;
+ } S_un;
+ };
+
+#define s_addr S_un.S_addr
+#define s_host S_un.S_un_b.s_b2
+#define s_net S_un.S_un_b.s_b1
+#define s_imp S_un.S_un_w.s_w2
+#define s_impno S_un.S_un_b.s_b4
+#define s_lh S_un.S_un_b.s_b3
+
+#endif
+
+#define IN_CLASSA(i) (((long)(i) & 0x80000000)==0)
+#define IN_CLASSA_NET 0xff000000
+#define IN_CLASSA_NSHIFT 24
+#define IN_CLASSA_HOST 0x00ffffff
+#define IN_CLASSA_MAX 128
+
+#define IN_CLASSB(i) (((long)(i) & 0xc0000000)==0x80000000)
+#define IN_CLASSB_NET 0xffff0000
+#define IN_CLASSB_NSHIFT 16
+#define IN_CLASSB_HOST 0x0000ffff
+#define IN_CLASSB_MAX 65536
+
+#define IN_CLASSC(i) (((long)(i) & 0xe0000000)==0xc0000000)
+#define IN_CLASSC_NET 0xffffff00
+#define IN_CLASSC_NSHIFT 8
+#define IN_CLASSC_HOST 0x000000ff
+
+#define IN_CLASSD(i) (((long)(i) & 0xf0000000)==0xe0000000)
+#define IN_CLASSD_NET 0xf0000000
+#define IN_CLASSD_NSHIFT 28
+#define IN_CLASSD_HOST 0x0fffffff
+#define IN_MULTICAST(i) IN_CLASSD(i)
+
+#define INADDR_ANY (u_long)0x00000000
+#define INADDR_LOOPBACK 0x7f000001
+#define INADDR_BROADCAST (u_long)0xffffffff
+#define INADDR_NONE 0xffffffff
+
+#define ADDR_ANY INADDR_ANY
+
+ struct sockaddr_in {
+ short sin_family;
+ u_short sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+ };
+
+#define WSADESCRIPTION_LEN 256
+#define WSASYS_STATUS_LEN 128
+
+ typedef struct WSAData {
+ WORD wVersion;
+ WORD wHighVersion;
+#ifdef _WIN64
+ unsigned short iMaxSockets;
+ unsigned short iMaxUdpDg;
+ char *lpVendorInfo;
+ char szDescription[WSADESCRIPTION_LEN+1];
+ char szSystemStatus[WSASYS_STATUS_LEN+1];
+#else
+ char szDescription[WSADESCRIPTION_LEN+1];
+ char szSystemStatus[WSASYS_STATUS_LEN+1];
+ unsigned short iMaxSockets;
+ unsigned short iMaxUdpDg;
+ char *lpVendorInfo;
+#endif
+ } WSADATA,*LPWSADATA;
+
+#define INVALID_SOCKET (SOCKET)(~0)
+#define SOCKET_ERROR (-1)
+
+#define FROM_PROTOCOL_INFO (-1)
+
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+#define SOCK_RAW 3
+#define SOCK_RDM 4
+#define SOCK_SEQPACKET 5
+
+#define SO_DEBUG 0x0001
+#define SO_ACCEPTCONN 0x0002
+#define SO_REUSEADDR 0x0004
+#define SO_KEEPALIVE 0x0008
+#define SO_DONTROUTE 0x0010
+#define SO_BROADCAST 0x0020
+#define SO_USELOOPBACK 0x0040
+#define SO_LINGER 0x0080
+#define SO_OOBINLINE 0x0100
+
+#define SO_DONTLINGER (int)(~SO_LINGER)
+#define SO_EXCLUSIVEADDRUSE ((int)(~SO_REUSEADDR))
+
+#define SO_SNDBUF 0x1001
+#define SO_RCVBUF 0x1002
+#define SO_SNDLOWAT 0x1003
+#define SO_RCVLOWAT 0x1004
+#define SO_SNDTIMEO 0x1005
+#define SO_RCVTIMEO 0x1006
+#define SO_ERROR 0x1007
+#define SO_TYPE 0x1008
+
+#define SO_GROUP_ID 0x2001
+#define SO_GROUP_PRIORITY 0x2002
+#define SO_MAX_MSG_SIZE 0x2003
+#define SO_PROTOCOL_INFOA 0x2004
+#define SO_PROTOCOL_INFOW 0x2005
+#ifdef UNICODE
+#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOW
+#else
+#define SO_PROTOCOL_INFO SO_PROTOCOL_INFOA
+#endif
+#define PVD_CONFIG 0x3001
+#define SO_CONDITIONAL_ACCEPT 0x3002
+
+#define TCP_NODELAY 0x0001
+
+#define AF_UNSPEC 0
+
+#define AF_UNIX 1
+#define AF_INET 2
+#define AF_IMPLINK 3
+#define AF_PUP 4
+#define AF_CHAOS 5
+#define AF_NS 6
+#define AF_IPX AF_NS
+#define AF_ISO 7
+#define AF_OSI AF_ISO
+#define AF_ECMA 8
+#define AF_DATAKIT 9
+#define AF_CCITT 10
+#define AF_SNA 11
+#define AF_DECnet 12
+#define AF_DLI 13
+#define AF_LAT 14
+#define AF_HYLINK 15
+#define AF_APPLETALK 16
+#define AF_NETBIOS 17
+#define AF_VOICEVIEW 18
+#define AF_FIREFOX 19
+#define AF_UNKNOWN1 20
+#define AF_BAN 21
+#define AF_ATM 22
+#define AF_INET6 23
+#define AF_CLUSTER 24
+#define AF_12844 25
+#define AF_IRDA 26
+#define AF_NETDES 28
+#define AF_TCNPROCESS 29
+#define AF_TCNMESSAGE 30
+#define AF_ICLFXBM 31
+
+#define AF_MAX 32
+
+ struct sockaddr {
+ u_short sa_family;
+ char sa_data[14];
+ };
+
+#define _SS_MAXSIZE 128
+#define _SS_ALIGNSIZE (8)
+
+#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short))
+#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE + _SS_ALIGNSIZE))
+
+ struct sockaddr_storage {
+ short ss_family;
+ char __ss_pad1[_SS_PAD1SIZE];
+
+ __MINGW_EXTENSION __int64 __ss_align;
+ char __ss_pad2[_SS_PAD2SIZE];
+
+ };
+
+ struct sockproto {
+ u_short sp_family;
+ u_short sp_protocol;
+ };
+
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_INET AF_INET
+#define PF_IMPLINK AF_IMPLINK
+#define PF_PUP AF_PUP
+#define PF_CHAOS AF_CHAOS
+#define PF_NS AF_NS
+#define PF_IPX AF_IPX
+#define PF_ISO AF_ISO
+#define PF_OSI AF_OSI
+#define PF_ECMA AF_ECMA
+#define PF_DATAKIT AF_DATAKIT
+#define PF_CCITT AF_CCITT
+#define PF_SNA AF_SNA
+#define PF_DECnet AF_DECnet
+#define PF_DLI AF_DLI
+#define PF_LAT AF_LAT
+#define PF_HYLINK AF_HYLINK
+#define PF_APPLETALK AF_APPLETALK
+#define PF_VOICEVIEW AF_VOICEVIEW
+#define PF_FIREFOX AF_FIREFOX
+#define PF_UNKNOWN1 AF_UNKNOWN1
+#define PF_BAN AF_BAN
+#define PF_ATM AF_ATM
+#define PF_INET6 AF_INET6
+
+#define PF_MAX AF_MAX
+
+ struct linger {
+ u_short l_onoff;
+ u_short l_linger;
+ };
+
+#define SOL_SOCKET 0xffff
+
+#define SOMAXCONN 0x7fffffff
+
+#define MSG_OOB 0x1
+#define MSG_PEEK 0x2
+#define MSG_DONTROUTE 0x4
+#define MSG_WAITALL 0x8
+
+#define MSG_PARTIAL 0x8000
+
+#define MSG_INTERRUPT 0x10
+
+#define MSG_MAXIOVLEN 16
+
+#define MAXGETHOSTSTRUCT 1024
+
+#define FD_READ_BIT 0
+#define FD_READ (1 << FD_READ_BIT)
+
+#define FD_WRITE_BIT 1
+#define FD_WRITE (1 << FD_WRITE_BIT)
+
+#define FD_OOB_BIT 2
+#define FD_OOB (1 << FD_OOB_BIT)
+
+#define FD_ACCEPT_BIT 3
+#define FD_ACCEPT (1 << FD_ACCEPT_BIT)
+
+#define FD_CONNECT_BIT 4
+#define FD_CONNECT (1 << FD_CONNECT_BIT)
+
+#define FD_CLOSE_BIT 5
+#define FD_CLOSE (1 << FD_CLOSE_BIT)
+
+#define FD_QOS_BIT 6
+#define FD_QOS (1 << FD_QOS_BIT)
+
+#define FD_GROUP_QOS_BIT 7
+#define FD_GROUP_QOS (1 << FD_GROUP_QOS_BIT)
+
+#define FD_ROUTING_INTERFACE_CHANGE_BIT 8
+#define FD_ROUTING_INTERFACE_CHANGE (1 << FD_ROUTING_INTERFACE_CHANGE_BIT)
+
+#define FD_ADDRESS_LIST_CHANGE_BIT 9
+#define FD_ADDRESS_LIST_CHANGE (1 << FD_ADDRESS_LIST_CHANGE_BIT)
+
+#define FD_MAX_EVENTS 10
+#define FD_ALL_EVENTS ((1 << FD_MAX_EVENTS) - 1)
+
+#ifndef WSABASEERR
+
+#define WSABASEERR 10000
+
+#define WSAEINTR (WSABASEERR+4)
+#define WSAEBADF (WSABASEERR+9)
+#define WSAEACCES (WSABASEERR+13)
+#define WSAEFAULT (WSABASEERR+14)
+#define WSAEINVAL (WSABASEERR+22)
+#define WSAEMFILE (WSABASEERR+24)
+
+#define WSAEWOULDBLOCK (WSABASEERR+35)
+#define WSAEINPROGRESS (WSABASEERR+36)
+#define WSAEALREADY (WSABASEERR+37)
+#define WSAENOTSOCK (WSABASEERR+38)
+#define WSAEDESTADDRREQ (WSABASEERR+39)
+#define WSAEMSGSIZE (WSABASEERR+40)
+#define WSAEPROTOTYPE (WSABASEERR+41)
+#define WSAENOPROTOOPT (WSABASEERR+42)
+#define WSAEPROTONOSUPPORT (WSABASEERR+43)
+#define WSAESOCKTNOSUPPORT (WSABASEERR+44)
+#define WSAEOPNOTSUPP (WSABASEERR+45)
+#define WSAEPFNOSUPPORT (WSABASEERR+46)
+#define WSAEAFNOSUPPORT (WSABASEERR+47)
+#define WSAEADDRINUSE (WSABASEERR+48)
+#define WSAEADDRNOTAVAIL (WSABASEERR+49)
+#define WSAENETDOWN (WSABASEERR+50)
+#define WSAENETUNREACH (WSABASEERR+51)
+#define WSAENETRESET (WSABASEERR+52)
+#define WSAECONNABORTED (WSABASEERR+53)
+#define WSAECONNRESET (WSABASEERR+54)
+#define WSAENOBUFS (WSABASEERR+55)
+#define WSAEISCONN (WSABASEERR+56)
+#define WSAENOTCONN (WSABASEERR+57)
+#define WSAESHUTDOWN (WSABASEERR+58)
+#define WSAETOOMANYREFS (WSABASEERR+59)
+#define WSAETIMEDOUT (WSABASEERR+60)
+#define WSAECONNREFUSED (WSABASEERR+61)
+#define WSAELOOP (WSABASEERR+62)
+#define WSAENAMETOOLONG (WSABASEERR+63)
+#define WSAEHOSTDOWN (WSABASEERR+64)
+#define WSAEHOSTUNREACH (WSABASEERR+65)
+#define WSAENOTEMPTY (WSABASEERR+66)
+#define WSAEPROCLIM (WSABASEERR+67)
+#define WSAEUSERS (WSABASEERR+68)
+#define WSAEDQUOT (WSABASEERR+69)
+#define WSAESTALE (WSABASEERR+70)
+#define WSAEREMOTE (WSABASEERR+71)
+
+#define WSASYSNOTREADY (WSABASEERR+91)
+#define WSAVERNOTSUPPORTED (WSABASEERR+92)
+#define WSANOTINITIALISED (WSABASEERR+93)
+#define WSAEDISCON (WSABASEERR+101)
+#ifndef WSAHOST_NOT_FOUND
+#define WSAHOST_NOT_FOUND (WSABASEERR+1001)
+#endif
+#ifndef WSATRY_AGAIN
+#define WSATRY_AGAIN (WSABASEERR+1002)
+#endif
+#ifndef WSANO_RECOVERY
+#define WSANO_RECOVERY (WSABASEERR+1003)
+#endif
+#ifndef WSANO_DATA
+#define WSANO_DATA (WSABASEERR+1004)
+#endif
+
+#define WSAENOMORE (WSABASEERR+102)
+#define WSAECANCELLED (WSABASEERR+103)
+#define WSAEINVALIDPROCTABLE (WSABASEERR+104)
+#define WSAEINVALIDPROVIDER (WSABASEERR+105)
+#define WSAEPROVIDERFAILEDINIT (WSABASEERR+106)
+#define WSASYSCALLFAILURE (WSABASEERR+107)
+#define WSASERVICE_NOT_FOUND (WSABASEERR+108)
+#define WSATYPE_NOT_FOUND (WSABASEERR+109)
+#define WSA_E_NO_MORE (WSABASEERR+110)
+#define WSA_E_CANCELLED (WSABASEERR+111)
+#define WSAEREFUSED (WSABASEERR+112)
+#ifndef WSA_QOS_RECEIVERS
+#define WSA_QOS_RECEIVERS (WSABASEERR + 1005)
+#endif
+#ifndef WSA_QOS_SENDERS
+#define WSA_QOS_SENDERS (WSABASEERR + 1006)
+#endif
+#ifndef WSA_QOS_NO_SENDERS
+#define WSA_QOS_NO_SENDERS (WSABASEERR + 1007)
+#define WSA_QOS_NO_RECEIVERS (WSABASEERR + 1008)
+#define WSA_QOS_REQUEST_CONFIRMED (WSABASEERR + 1009)
+#define WSA_QOS_ADMISSION_FAILURE (WSABASEERR + 1010)
+#define WSA_QOS_POLICY_FAILURE (WSABASEERR + 1011)
+#define WSA_QOS_BAD_STYLE (WSABASEERR + 1012)
+#define WSA_QOS_BAD_OBJECT (WSABASEERR + 1013)
+#define WSA_QOS_TRAFFIC_CTRL_ERROR (WSABASEERR + 1014)
+#define WSA_QOS_GENERIC_ERROR (WSABASEERR + 1015)
+#define WSA_QOS_ESERVICETYPE (WSABASEERR + 1016)
+#define WSA_QOS_EFLOWSPEC (WSABASEERR + 1017)
+#define WSA_QOS_EPROVSPECBUF (WSABASEERR + 1018)
+#endif
+#ifndef WSA_QOS_EFILTERSTYLE
+#define WSA_QOS_EFILTERSTYLE (WSABASEERR + 1019)
+#endif
+#ifndef WSA_QOS_EFILTERTYPE
+#define WSA_QOS_EFILTERTYPE (WSABASEERR + 1020)
+#endif
+#ifndef WSA_QOS_EFILTERCOUNT
+#define WSA_QOS_EFILTERCOUNT (WSABASEERR + 1021)
+#endif
+#ifndef WSA_QOS_EOBJLENGTH
+#define WSA_QOS_EOBJLENGTH (WSABASEERR + 1022)
+#endif
+#ifndef WSA_QOS_EFLOWCOUNT
+#define WSA_QOS_EFLOWCOUNT (WSABASEERR + 1023)
+#endif
+#ifndef WSA_QOS_EUNKNOWNPSOBJ
+#define WSA_QOS_EUNKNOWNPSOBJ (WSABASEERR + 1024)
+#endif
+#ifndef WSA_QOS_EPOLICYOBJ
+#define WSA_QOS_EPOLICYOBJ (WSABASEERR + 1025)
+#endif
+#ifndef WSA_QOS_EFLOWDESC
+#define WSA_QOS_EFLOWDESC (WSABASEERR + 1026)
+#endif
+#ifndef WSA_QOS_EPSFLOWSPEC
+#define WSA_QOS_EPSFLOWSPEC (WSABASEERR + 1027)
+#endif
+#ifndef WSA_QOS_EPSFILTERSPEC
+#define WSA_QOS_EPSFILTERSPEC (WSABASEERR + 1028)
+#endif
+#ifndef WSA_QOS_ESDMODEOBJ
+#define WSA_QOS_ESDMODEOBJ (WSABASEERR + 1029)
+#endif
+#ifndef WSA_QOS_ESHAPERATEOBJ
+#define WSA_QOS_ESHAPERATEOBJ (WSABASEERR + 1030)
+#endif
+#ifndef WSA_QOS_RESERVED_PETYPE
+#define WSA_QOS_RESERVED_PETYPE (WSABASEERR + 1031)
+#endif
+#endif // WSABASEERR
+
+#define h_errno WSAGetLastError()
+#define HOST_NOT_FOUND WSAHOST_NOT_FOUND
+#define TRY_AGAIN WSATRY_AGAIN
+#define NO_RECOVERY WSANO_RECOVERY
+#define NO_DATA WSANO_DATA
+
+#define WSANO_ADDRESS WSANO_DATA
+#define NO_ADDRESS WSANO_ADDRESS
+
+#if 0
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define ENOTSOCK WSAENOTSOCK
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#define EMSGSIZE WSAEMSGSIZE
+#define EPROTOTYPE WSAEPROTOTYPE
+#define ENOPROTOOPT WSAENOPROTOOPT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EADDRINUSE WSAEADDRINUSE
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define ENETDOWN WSAENETDOWN
+#define ENETUNREACH WSAENETUNREACH
+#define ENETRESET WSAENETRESET
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET WSAECONNRESET
+#define ENOBUFS WSAENOBUFS
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#define ETIMEDOUT WSAETIMEDOUT
+#define ECONNREFUSED WSAECONNREFUSED
+#define ELOOP WSAELOOP
+#define ENAMETOOLONG WSAENAMETOOLONG
+#define EHOSTDOWN WSAEHOSTDOWN
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#define ENOTEMPTY WSAENOTEMPTY
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+#endif
+
+#define WSAAPI WINAPI
+#define WSAEVENT HANDLE
+#define LPWSAEVENT LPHANDLE
+#define WSAOVERLAPPED OVERLAPPED
+ typedef struct _OVERLAPPED *LPWSAOVERLAPPED;
+
+#define WSA_IO_PENDING (ERROR_IO_PENDING)
+#define WSA_IO_INCOMPLETE (ERROR_IO_INCOMPLETE)
+#define WSA_INVALID_HANDLE (ERROR_INVALID_HANDLE)
+#define WSA_INVALID_PARAMETER (ERROR_INVALID_PARAMETER)
+#define WSA_NOT_ENOUGH_MEMORY (ERROR_NOT_ENOUGH_MEMORY)
+#define WSA_OPERATION_ABORTED (ERROR_OPERATION_ABORTED)
+
+#define WSA_INVALID_EVENT ((WSAEVENT)NULL)
+#define WSA_MAXIMUM_WAIT_EVENTS (MAXIMUM_WAIT_OBJECTS)
+#define WSA_WAIT_FAILED (WAIT_FAILED)
+#define WSA_WAIT_EVENT_0 (WAIT_OBJECT_0)
+#define WSA_WAIT_IO_COMPLETION (WAIT_IO_COMPLETION)
+#define WSA_WAIT_TIMEOUT (WAIT_TIMEOUT)
+#define WSA_INFINITE (INFINITE)
+
+ typedef struct _WSABUF {
+ u_long len;
+ char *buf;
+ } WSABUF,*LPWSABUF;
+
+#include <qos.h>
+
+ typedef struct _QualityOfService {
+ FLOWSPEC SendingFlowspec;
+ FLOWSPEC ReceivingFlowspec;
+ WSABUF ProviderSpecific;
+ } QOS,*LPQOS;
+
+#define CF_ACCEPT 0x0000
+#define CF_REJECT 0x0001
+#define CF_DEFER 0x0002
+
+#define SD_RECEIVE 0x00
+#define SD_SEND 0x01
+#define SD_BOTH 0x02
+
+ typedef unsigned int GROUP;
+
+#define SG_UNCONSTRAINED_GROUP 0x01
+#define SG_CONSTRAINED_GROUP 0x02
+
+ typedef struct _WSANETWORKEVENTS {
+ long lNetworkEvents;
+ int iErrorCode[FD_MAX_EVENTS];
+ } WSANETWORKEVENTS,*LPWSANETWORKEVENTS;
+
+#ifndef GUID_DEFINED
+#include <guiddef.h>
+#endif
+
+#define MAX_PROTOCOL_CHAIN 7
+
+#define BASE_PROTOCOL 1
+#define LAYERED_PROTOCOL 0
+
+ typedef struct _WSAPROTOCOLCHAIN {
+ int ChainLen;
+
+ DWORD ChainEntries[MAX_PROTOCOL_CHAIN];
+ } WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN;
+
+#define WSAPROTOCOL_LEN 255
+
+ typedef struct _WSAPROTOCOL_INFOA {
+ DWORD dwServiceFlags1;
+ DWORD dwServiceFlags2;
+ DWORD dwServiceFlags3;
+ DWORD dwServiceFlags4;
+ DWORD dwProviderFlags;
+ GUID ProviderId;
+ DWORD dwCatalogEntryId;
+ WSAPROTOCOLCHAIN ProtocolChain;
+ int iVersion;
+ int iAddressFamily;
+ int iMaxSockAddr;
+ int iMinSockAddr;
+ int iSocketType;
+ int iProtocol;
+ int iProtocolMaxOffset;
+ int iNetworkByteOrder;
+ int iSecurityScheme;
+ DWORD dwMessageSize;
+ DWORD dwProviderReserved;
+ CHAR szProtocol[WSAPROTOCOL_LEN+1];
+ } WSAPROTOCOL_INFOA,*LPWSAPROTOCOL_INFOA;
+ typedef struct _WSAPROTOCOL_INFOW {
+ DWORD dwServiceFlags1;
+ DWORD dwServiceFlags2;
+ DWORD dwServiceFlags3;
+ DWORD dwServiceFlags4;
+ DWORD dwProviderFlags;
+ GUID ProviderId;
+ DWORD dwCatalogEntryId;
+ WSAPROTOCOLCHAIN ProtocolChain;
+ int iVersion;
+ int iAddressFamily;
+ int iMaxSockAddr;
+ int iMinSockAddr;
+ int iSocketType;
+ int iProtocol;
+ int iProtocolMaxOffset;
+ int iNetworkByteOrder;
+ int iSecurityScheme;
+ DWORD dwMessageSize;
+ DWORD dwProviderReserved;
+ WCHAR szProtocol[WSAPROTOCOL_LEN+1];
+ } WSAPROTOCOL_INFOW,*LPWSAPROTOCOL_INFOW;
+#ifdef UNICODE
+ typedef WSAPROTOCOL_INFOW WSAPROTOCOL_INFO;
+ typedef LPWSAPROTOCOL_INFOW LPWSAPROTOCOL_INFO;
+#else
+ typedef WSAPROTOCOL_INFOA WSAPROTOCOL_INFO;
+ typedef LPWSAPROTOCOL_INFOA LPWSAPROTOCOL_INFO;
+#endif
+
+#define PFL_MULTIPLE_PROTO_ENTRIES 0x00000001
+#define PFL_RECOMMENDED_PROTO_ENTRY 0x00000002
+#define PFL_HIDDEN 0x00000004
+#define PFL_MATCHES_PROTOCOL_ZERO 0x00000008
+
+#define XP1_CONNECTIONLESS 0x00000001
+#define XP1_GUARANTEED_DELIVERY 0x00000002
+#define XP1_GUARANTEED_ORDER 0x00000004
+#define XP1_MESSAGE_ORIENTED 0x00000008
+#define XP1_PSEUDO_STREAM 0x00000010
+#define XP1_GRACEFUL_CLOSE 0x00000020
+#define XP1_EXPEDITED_DATA 0x00000040
+#define XP1_CONNECT_DATA 0x00000080
+#define XP1_DISCONNECT_DATA 0x00000100
+#define XP1_SUPPORT_BROADCAST 0x00000200
+#define XP1_SUPPORT_MULTIPOINT 0x00000400
+#define XP1_MULTIPOINT_CONTROL_PLANE 0x00000800
+#define XP1_MULTIPOINT_DATA_PLANE 0x00001000
+#define XP1_QOS_SUPPORTED 0x00002000
+#define XP1_INTERRUPT 0x00004000
+#define XP1_UNI_SEND 0x00008000
+#define XP1_UNI_RECV 0x00010000
+#define XP1_IFS_HANDLES 0x00020000
+#define XP1_PARTIAL_MESSAGE 0x00040000
+
+#define BIGENDIAN 0x0000
+#define LITTLEENDIAN 0x0001
+
+#define SECURITY_PROTOCOL_NONE 0x0000
+
+#define JL_SENDER_ONLY 0x01
+#define JL_RECEIVER_ONLY 0x02
+#define JL_BOTH 0x04
+
+#define WSA_FLAG_OVERLAPPED 0x01
+#define WSA_FLAG_MULTIPOINT_C_ROOT 0x02
+#define WSA_FLAG_MULTIPOINT_C_LEAF 0x04
+#define WSA_FLAG_MULTIPOINT_D_ROOT 0x08
+#define WSA_FLAG_MULTIPOINT_D_LEAF 0x10
+
+#define IOC_UNIX 0x00000000
+#define IOC_WS2 0x08000000
+#define IOC_PROTOCOL 0x10000000
+#define IOC_VENDOR 0x18000000
+
+#define _WSAIO(x,y) (IOC_VOID|(x)|(y))
+#define _WSAIOR(x,y) (IOC_OUT|(x)|(y))
+#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
+#define _WSAIORW(x,y) (IOC_INOUT|(x)|(y))
+
+#define SIO_ASSOCIATE_HANDLE _WSAIOW(IOC_WS2,1)
+#define SIO_ENABLE_CIRCULAR_QUEUEING _WSAIO(IOC_WS2,2)
+#define SIO_FIND_ROUTE _WSAIOR(IOC_WS2,3)
+#define SIO_FLUSH _WSAIO(IOC_WS2,4)
+#define SIO_GET_BROADCAST_ADDRESS _WSAIOR(IOC_WS2,5)
+#define SIO_GET_EXTENSION_FUNCTION_POINTER _WSAIORW(IOC_WS2,6)
+#define SIO_GET_QOS _WSAIORW(IOC_WS2,7)
+#define SIO_GET_GROUP_QOS _WSAIORW(IOC_WS2,8)
+#define SIO_MULTIPOINT_LOOPBACK _WSAIOW(IOC_WS2,9)
+#define SIO_MULTICAST_SCOPE _WSAIOW(IOC_WS2,10)
+#define SIO_SET_QOS _WSAIOW(IOC_WS2,11)
+#define SIO_SET_GROUP_QOS _WSAIOW(IOC_WS2,12)
+#define SIO_TRANSLATE_HANDLE _WSAIORW(IOC_WS2,13)
+#define SIO_ROUTING_INTERFACE_QUERY _WSAIORW(IOC_WS2,20)
+#define SIO_ROUTING_INTERFACE_CHANGE _WSAIOW(IOC_WS2,21)
+#define SIO_ADDRESS_LIST_QUERY _WSAIOR(IOC_WS2,22)
+#define SIO_ADDRESS_LIST_CHANGE _WSAIO(IOC_WS2,23)
+#define SIO_QUERY_TARGET_PNP_HANDLE _WSAIOR(IOC_WS2,24)
+#define SIO_ADDRESS_LIST_SORT _WSAIORW(IOC_WS2,25)
+
+ typedef int (CALLBACK *LPCONDITIONPROC)(LPWSABUF lpCallerId,LPWSABUF lpCallerData,LPQOS lpSQOS,LPQOS lpGQOS,LPWSABUF lpCalleeId,LPWSABUF lpCalleeData,GROUP *g,DWORD_PTR dwCallbackData);
+ typedef void (CALLBACK *LPWSAOVERLAPPED_COMPLETION_ROUTINE)(DWORD dwError,DWORD cbTransferred,LPWSAOVERLAPPED lpOverlapped,DWORD dwFlags);
+
+#define SIO_NSP_NOTIFY_CHANGE _WSAIOW(IOC_WS2,25)
+
+ typedef enum _WSACOMPLETIONTYPE {
+ NSP_NOTIFY_IMMEDIATELY = 0,NSP_NOTIFY_HWND,NSP_NOTIFY_EVENT,NSP_NOTIFY_PORT,NSP_NOTIFY_APC
+ } WSACOMPLETIONTYPE,*PWSACOMPLETIONTYPE,*LPWSACOMPLETIONTYPE;
+
+ typedef struct _WSACOMPLETION {
+ WSACOMPLETIONTYPE Type;
+ union {
+ struct {
+ HWND hWnd;
+ UINT uMsg;
+ WPARAM context;
+ } WindowMessage;
+ struct {
+ LPWSAOVERLAPPED lpOverlapped;
+ } Event;
+ struct {
+ LPWSAOVERLAPPED lpOverlapped;
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpfnCompletionProc;
+ } Apc;
+ struct {
+ LPWSAOVERLAPPED lpOverlapped;
+ HANDLE hPort;
+ ULONG_PTR Key;
+ } Port;
+ } Parameters;
+ } WSACOMPLETION,*PWSACOMPLETION,*LPWSACOMPLETION;
+
+#define TH_NETDEV 0x00000001
+#define TH_TAPI 0x00000002
+
+ typedef struct sockaddr SOCKADDR;
+ typedef struct sockaddr *PSOCKADDR;
+ typedef struct sockaddr *LPSOCKADDR;
+ typedef struct sockaddr_storage SOCKADDR_STORAGE;
+ typedef struct sockaddr_storage *PSOCKADDR_STORAGE;
+ typedef struct sockaddr_storage *LPSOCKADDR_STORAGE;
+
+#ifndef _tagBLOB_DEFINED
+#define _tagBLOB_DEFINED
+#define _BLOB_DEFINED
+#define _LPBLOB_DEFINED
+ typedef struct _BLOB {
+ ULONG cbSize;
+ BYTE *pBlobData;
+ } BLOB,*LPBLOB;
+#endif
+
+#define SERVICE_MULTIPLE (0x00000001)
+
+#define NS_ALL (0)
+
+#define NS_SAP (1)
+#define NS_NDS (2)
+#define NS_PEER_BROWSE (3)
+#define NS_SLP (5)
+#define NS_DHCP (6)
+
+#define NS_TCPIP_LOCAL (10)
+#define NS_TCPIP_HOSTS (11)
+#define NS_DNS (12)
+#define NS_NETBT (13)
+#define NS_WINS (14)
+#define NS_NLA (15)
+
+#define NS_NBP (20)
+
+#define NS_MS (30)
+#define NS_STDA (31)
+#define NS_NTDS (32)
+
+#define NS_X500 (40)
+#define NS_NIS (41)
+#define NS_NISPLUS (42)
+
+#define NS_WRQ (50)
+
+#define NS_NETDES (60)
+
+#define RES_UNUSED_1 (0x00000001)
+#define RES_FLUSH_CACHE (0x00000002)
+#ifndef RES_SERVICE
+#define RES_SERVICE (0x00000004)
+#endif
+
+#define SERVICE_TYPE_VALUE_IPXPORTA "IpxSocket"
+#define SERVICE_TYPE_VALUE_IPXPORTW L"IpxSocket"
+#define SERVICE_TYPE_VALUE_SAPIDA "SapId"
+#define SERVICE_TYPE_VALUE_SAPIDW L"SapId"
+
+#define SERVICE_TYPE_VALUE_TCPPORTA "TcpPort"
+#define SERVICE_TYPE_VALUE_TCPPORTW L"TcpPort"
+
+#define SERVICE_TYPE_VALUE_UDPPORTA "UdpPort"
+#define SERVICE_TYPE_VALUE_UDPPORTW L"UdpPort"
+
+#define SERVICE_TYPE_VALUE_OBJECTIDA "ObjectId"
+#define SERVICE_TYPE_VALUE_OBJECTIDW L"ObjectId"
+
+#ifdef UNICODE
+
+#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDW
+#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTW
+#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTW
+#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDW
+#else
+
+#define SERVICE_TYPE_VALUE_SAPID SERVICE_TYPE_VALUE_SAPIDA
+#define SERVICE_TYPE_VALUE_TCPPORT SERVICE_TYPE_VALUE_TCPPORTA
+#define SERVICE_TYPE_VALUE_UDPPORT SERVICE_TYPE_VALUE_UDPPORTA
+#define SERVICE_TYPE_VALUE_OBJECTID SERVICE_TYPE_VALUE_OBJECTIDA
+#endif
+
+#ifndef __CSADDR_DEFINED__
+#define __CSADDR_DEFINED__
+
+ typedef struct _SOCKET_ADDRESS {
+ LPSOCKADDR lpSockaddr;
+ INT iSockaddrLength;
+ } SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS;
+
+ typedef struct _CSADDR_INFO {
+ SOCKET_ADDRESS LocalAddr;
+ SOCKET_ADDRESS RemoteAddr;
+ INT iSocketType;
+ INT iProtocol;
+ } CSADDR_INFO,*PCSADDR_INFO,*LPCSADDR_INFO;
+#endif
+
+ typedef struct _SOCKET_ADDRESS_LIST {
+ INT iAddressCount;
+ SOCKET_ADDRESS Address[1];
+ } SOCKET_ADDRESS_LIST,*LPSOCKET_ADDRESS_LIST;
+
+ typedef struct _AFPROTOCOLS {
+ INT iAddressFamily;
+ INT iProtocol;
+ } AFPROTOCOLS,*PAFPROTOCOLS,*LPAFPROTOCOLS;
+
+ typedef enum _WSAEcomparator {
+ COMP_EQUAL = 0,COMP_NOTLESS
+ } WSAECOMPARATOR,*PWSAECOMPARATOR,*LPWSAECOMPARATOR;
+
+ typedef struct _WSAVersion {
+ DWORD dwVersion;
+ WSAECOMPARATOR ecHow;
+ } WSAVERSION,*PWSAVERSION,*LPWSAVERSION;
+
+ typedef struct _WSAQuerySetA {
+ DWORD dwSize;
+ LPSTR lpszServiceInstanceName;
+ LPGUID lpServiceClassId;
+ LPWSAVERSION lpVersion;
+ LPSTR lpszComment;
+ DWORD dwNameSpace;
+ LPGUID lpNSProviderId;
+ LPSTR lpszContext;
+ DWORD dwNumberOfProtocols;
+ LPAFPROTOCOLS lpafpProtocols;
+ LPSTR lpszQueryString;
+ DWORD dwNumberOfCsAddrs;
+ LPCSADDR_INFO lpcsaBuffer;
+ DWORD dwOutputFlags;
+ LPBLOB lpBlob;
+ } WSAQUERYSETA,*PWSAQUERYSETA,*LPWSAQUERYSETA;
+
+ typedef struct _WSAQuerySetW {
+ DWORD dwSize;
+ LPWSTR lpszServiceInstanceName;
+ LPGUID lpServiceClassId;
+ LPWSAVERSION lpVersion;
+ LPWSTR lpszComment;
+ DWORD dwNameSpace;
+ LPGUID lpNSProviderId;
+ LPWSTR lpszContext;
+ DWORD dwNumberOfProtocols;
+ LPAFPROTOCOLS lpafpProtocols;
+ LPWSTR lpszQueryString;
+ DWORD dwNumberOfCsAddrs;
+ LPCSADDR_INFO lpcsaBuffer;
+ DWORD dwOutputFlags;
+ LPBLOB lpBlob;
+ } WSAQUERYSETW,*PWSAQUERYSETW,*LPWSAQUERYSETW;
+
+#ifdef UNICODE
+ typedef WSAQUERYSETW WSAQUERYSET;
+ typedef PWSAQUERYSETW PWSAQUERYSET;
+ typedef LPWSAQUERYSETW LPWSAQUERYSET;
+#else
+ typedef WSAQUERYSETA WSAQUERYSET;
+ typedef PWSAQUERYSETA PWSAQUERYSET;
+ typedef LPWSAQUERYSETA LPWSAQUERYSET;
+#endif
+
+#define LUP_DEEP 0x0001
+#define LUP_CONTAINERS 0x0002
+#define LUP_NOCONTAINERS 0x0004
+#define LUP_NEAREST 0x0008
+#define LUP_RETURN_NAME 0x0010
+#define LUP_RETURN_TYPE 0x0020
+#define LUP_RETURN_VERSION 0x0040
+#define LUP_RETURN_COMMENT 0x0080
+#define LUP_RETURN_ADDR 0x0100
+#define LUP_RETURN_BLOB 0x0200
+#define LUP_RETURN_ALIASES 0x0400
+#define LUP_RETURN_QUERY_STRING 0x0800
+#define LUP_RETURN_ALL 0x0FF0
+#define LUP_RES_SERVICE 0x8000
+
+#define LUP_FLUSHCACHE 0x1000
+#define LUP_FLUSHPREVIOUS 0x2000
+
+#define RESULT_IS_ALIAS 0x0001
+#define RESULT_IS_ADDED 0x0010
+#define RESULT_IS_CHANGED 0x0020
+#define RESULT_IS_DELETED 0x0040
+
+ typedef enum _WSAESETSERVICEOP {
+ RNRSERVICE_REGISTER=0,RNRSERVICE_DEREGISTER,RNRSERVICE_DELETE
+ } WSAESETSERVICEOP,*PWSAESETSERVICEOP,*LPWSAESETSERVICEOP;
+
+ typedef struct _WSANSClassInfoA {
+ LPSTR lpszName;
+ DWORD dwNameSpace;
+ DWORD dwValueType;
+ DWORD dwValueSize;
+ LPVOID lpValue;
+ } WSANSCLASSINFOA,*PWSANSCLASSINFOA,*LPWSANSCLASSINFOA;
+
+ typedef struct _WSANSClassInfoW {
+ LPWSTR lpszName;
+ DWORD dwNameSpace;
+ DWORD dwValueType;
+ DWORD dwValueSize;
+ LPVOID lpValue;
+ } WSANSCLASSINFOW,*PWSANSCLASSINFOW,*LPWSANSCLASSINFOW;
+
+#ifdef UNICODE
+ typedef WSANSCLASSINFOW WSANSCLASSINFO;
+ typedef PWSANSCLASSINFOW PWSANSCLASSINFO;
+ typedef LPWSANSCLASSINFOW LPWSANSCLASSINFO;
+#else
+ typedef WSANSCLASSINFOA WSANSCLASSINFO;
+ typedef PWSANSCLASSINFOA PWSANSCLASSINFO;
+ typedef LPWSANSCLASSINFOA LPWSANSCLASSINFO;
+#endif
+
+ typedef struct _WSAServiceClassInfoA {
+ LPGUID lpServiceClassId;
+ LPSTR lpszServiceClassName;
+ DWORD dwCount;
+ LPWSANSCLASSINFOA lpClassInfos;
+ } WSASERVICECLASSINFOA,*PWSASERVICECLASSINFOA,*LPWSASERVICECLASSINFOA;
+
+ typedef struct _WSAServiceClassInfoW {
+ LPGUID lpServiceClassId;
+ LPWSTR lpszServiceClassName;
+ DWORD dwCount;
+ LPWSANSCLASSINFOW lpClassInfos;
+ } WSASERVICECLASSINFOW,*PWSASERVICECLASSINFOW,*LPWSASERVICECLASSINFOW;
+
+#ifdef UNICODE
+ typedef WSASERVICECLASSINFOW WSASERVICECLASSINFO;
+ typedef PWSASERVICECLASSINFOW PWSASERVICECLASSINFO;
+ typedef LPWSASERVICECLASSINFOW LPWSASERVICECLASSINFO;
+#else
+ typedef WSASERVICECLASSINFOA WSASERVICECLASSINFO;
+ typedef PWSASERVICECLASSINFOA PWSASERVICECLASSINFO;
+ typedef LPWSASERVICECLASSINFOA LPWSASERVICECLASSINFO;
+#endif
+
+ typedef struct _WSANAMESPACE_INFOA {
+ GUID NSProviderId;
+ DWORD dwNameSpace;
+ WINBOOL fActive;
+ DWORD dwVersion;
+ LPSTR lpszIdentifier;
+ } WSANAMESPACE_INFOA,*PWSANAMESPACE_INFOA,*LPWSANAMESPACE_INFOA;
+
+ typedef struct _WSANAMESPACE_INFOW {
+ GUID NSProviderId;
+ DWORD dwNameSpace;
+ WINBOOL fActive;
+ DWORD dwVersion;
+ LPWSTR lpszIdentifier;
+ } WSANAMESPACE_INFOW,*PWSANAMESPACE_INFOW,*LPWSANAMESPACE_INFOW;
+
+#ifdef UNICODE
+ typedef WSANAMESPACE_INFOW WSANAMESPACE_INFO;
+ typedef PWSANAMESPACE_INFOW PWSANAMESPACE_INFO;
+ typedef LPWSANAMESPACE_INFOW LPWSANAMESPACE_INFO;
+#else
+ typedef WSANAMESPACE_INFOA WSANAMESPACE_INFO;
+ typedef PWSANAMESPACE_INFOA PWSANAMESPACE_INFO;
+ typedef LPWSANAMESPACE_INFOA LPWSANAMESPACE_INFO;
+#endif
+
+#if INCL_WINSOCK_API_TYPEDEFS
+#ifdef UNICODE
+#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETW
+#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSW
+#define LPFN_WSASOCKET LPFN_WSASOCKETW
+#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGW
+#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSW
+#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINW
+#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTW
+#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSW
+#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOW
+#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSW
+#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW
+#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEW
+#else
+#define LPFN_WSADUPLICATESOCKET LPFN_WSADUPLICATESOCKETA
+#define LPFN_WSAENUMPROTOCOLS LPFN_WSAENUMPROTOCOLSA
+#define LPFN_WSASOCKET LPFN_WSASOCKETA
+#define LPFN_WSAADDRESSTOSTRING LPFN_WSAADDRESSTOSTRINGA
+#define LPFN_WSASTRINGTOADDRESS LPFN_WSASTRINGTOADDRESSA
+#define LPFN_WSALOOKUPSERVICEBEGIN LPFN_WSALOOKUPSERVICEBEGINA
+#define LPFN_WSALOOKUPSERVICENEXT LPFN_WSALOOKUPSERVICENEXTA
+#define LPFN_WSAINSTALLSERVICECLASS LPFN_WSAINSTALLSERVICECLASSA
+#define LPFN_WSAGETSERVICECLASSINFO LPFN_WSAGETSERVICECLASSINFOA
+#define LPFN_WSAENUMNAMESPACEPROVIDERS LPFN_WSAENUMNAMESPACEPROVIDERSA
+#define LPFN_WSAGETSERVICECLASSNAMEBYCLASSID LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA
+#define LPFN_WSASETSERVICE LPFN_WSASETSERVICEA
+#endif
+
+ typedef SOCKET (WSAAPI *LPFN_ACCEPT)(SOCKET s,struct sockaddr *addr,int *addrlen);
+ typedef int (WSAAPI *LPFN_BIND)(SOCKET s,const struct sockaddr *name,int namelen);
+ typedef int (WSAAPI *LPFN_CLOSESOCKET)(SOCKET s);
+ typedef int (WSAAPI *LPFN_CONNECT)(SOCKET s,const struct sockaddr *name,int namelen);
+ typedef int (WSAAPI *LPFN_IOCTLSOCKET)(SOCKET s,long cmd,u_long *argp);
+ typedef int (WSAAPI *LPFN_GETPEERNAME)(SOCKET s,struct sockaddr *name,int *namelen);
+ typedef int (WSAAPI *LPFN_GETSOCKNAME)(SOCKET s,struct sockaddr *name,int *namelen);
+ typedef int (WSAAPI *LPFN_GETSOCKOPT)(SOCKET s,int level,int optname,char *optval,int *optlen);
+ typedef u_long (WSAAPI *LPFN_HTONL)(u_long hostlong);
+ typedef u_short (WSAAPI *LPFN_HTONS)(u_short hostshort);
+ typedef unsigned long (WSAAPI *LPFN_INET_ADDR)(const char *cp);
+ typedef char *(WSAAPI *LPFN_INET_NTOA)(struct in_addr in);
+ typedef int (WSAAPI *LPFN_LISTEN)(SOCKET s,int backlog);
+ typedef u_long (WSAAPI *LPFN_NTOHL)(u_long netlong);
+ typedef u_short (WSAAPI *LPFN_NTOHS)(u_short netshort);
+ typedef int (WSAAPI *LPFN_RECV)(SOCKET s,char *buf,int len,int flags);
+ typedef int (WSAAPI *LPFN_RECVFROM)(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen);
+ typedef int (WSAAPI *LPFN_SELECT)(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout);
+ typedef int (WSAAPI *LPFN_SEND)(SOCKET s,const char *buf,int len,int flags);
+ typedef int (WSAAPI *LPFN_SENDTO)(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen);
+ typedef int (WSAAPI *LPFN_SETSOCKOPT)(SOCKET s,int level,int optname,const char *optval,int optlen);
+ typedef int (WSAAPI *LPFN_SHUTDOWN)(SOCKET s,int how);
+ typedef SOCKET (WSAAPI *LPFN_SOCKET)(int af,int type,int protocol);
+ typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYADDR)(const char *addr,int len,int type);
+ typedef struct hostent *(WSAAPI *LPFN_GETHOSTBYNAME)(const char *name);
+ typedef int (WSAAPI *LPFN_GETHOSTNAME)(char *name,int namelen);
+ typedef struct servent *(WSAAPI *LPFN_GETSERVBYPORT)(int port,const char *proto);
+ typedef struct servent *(WSAAPI *LPFN_GETSERVBYNAME)(const char *name,const char *proto);
+ typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNUMBER)(int number);
+ typedef struct protoent *(WSAAPI *LPFN_GETPROTOBYNAME)(const char *name);
+ typedef int (WSAAPI *LPFN_WSASTARTUP)(WORD wVersionRequested,LPWSADATA lpWSAData);
+ typedef int (WSAAPI *LPFN_WSACLEANUP)(void);
+ typedef void (WSAAPI *LPFN_WSASETLASTERROR)(int iError);
+ typedef int (WSAAPI *LPFN_WSAGETLASTERROR)(void);
+ typedef WINBOOL (WSAAPI *LPFN_WSAISBLOCKING)(void);
+ typedef int (WSAAPI *LPFN_WSAUNHOOKBLOCKINGHOOK)(void);
+ typedef FARPROC (WSAAPI *LPFN_WSASETBLOCKINGHOOK)(FARPROC lpBlockFunc);
+ typedef int (WSAAPI *LPFN_WSACANCELBLOCKINGCALL)(void);
+ typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYNAME)(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen);
+ typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETSERVBYPORT)(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen);
+ typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen);
+ typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETPROTOBYNUMBER)(HWND hWnd,u_int wMsg,int number,char *buf,int buflen);
+ typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYNAME)(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen);
+ typedef HANDLE (WSAAPI *LPFN_WSAASYNCGETHOSTBYADDR)(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen);
+ typedef int (WSAAPI *LPFN_WSACANCELASYNCREQUEST)(HANDLE hAsyncTaskHandle);
+ typedef int (WSAAPI *LPFN_WSAASYNCSELECT)(SOCKET s,HWND hWnd,u_int wMsg,long lEvent);
+ typedef SOCKET (WSAAPI *LPFN_WSAACCEPT)(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData);
+ typedef WINBOOL (WSAAPI *LPFN_WSACLOSEEVENT)(WSAEVENT hEvent);
+ typedef int (WSAAPI *LPFN_WSACONNECT)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
+ typedef WSAEVENT (WSAAPI *LPFN_WSACREATEEVENT)(void);
+ typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETA)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo);
+ typedef int (WSAAPI *LPFN_WSADUPLICATESOCKETW)(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo);
+ typedef int (WSAAPI *LPFN_WSAENUMNETWORKEVENTS)(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);
+ typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSA)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength);
+ typedef int (WSAAPI *LPFN_WSAENUMPROTOCOLSW)(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength);
+ typedef int (WSAAPI *LPFN_WSAEVENTSELECT)(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents);
+ typedef WINBOOL (WSAAPI *LPFN_WSAGETOVERLAPPEDRESULT)(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags);
+ typedef WINBOOL (WSAAPI *LPFN_WSAGETQOSBYNAME)(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS);
+ typedef int (WSAAPI *LPFN_WSAHTONL)(SOCKET s,u_long hostlong,u_long *lpnetlong);
+ typedef int (WSAAPI *LPFN_WSAHTONS)(SOCKET s,u_short hostshort,u_short *lpnetshort);
+ typedef int (WSAAPI *LPFN_WSAIOCTL)(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ typedef SOCKET (WSAAPI *LPFN_WSAJOINLEAF)(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags);
+ typedef int (WSAAPI *LPFN_WSANTOHL)(SOCKET s,u_long netlong,u_long *lphostlong);
+ typedef int (WSAAPI *LPFN_WSANTOHS)(SOCKET s,u_short netshort,u_short *lphostshort);
+ typedef int (WSAAPI *LPFN_WSARECV)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ typedef int (WSAAPI *LPFN_WSARECVDISCONNECT)(SOCKET s,LPWSABUF lpInboundDisconnectData);
+ typedef int (WSAAPI *LPFN_WSARECVFROM)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ typedef WINBOOL (WSAAPI *LPFN_WSARESETEVENT)(WSAEVENT hEvent);
+ typedef int (WSAAPI *LPFN_WSASEND)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ typedef int (WSAAPI *LPFN_WSASENDDISCONNECT)(SOCKET s,LPWSABUF lpOutboundDisconnectData);
+ typedef int (WSAAPI *LPFN_WSASENDTO)(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ typedef WINBOOL (WSAAPI *LPFN_WSASETEVENT)(WSAEVENT hEvent);
+ typedef SOCKET (WSAAPI *LPFN_WSASOCKETA)(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags);
+ typedef SOCKET (WSAAPI *LPFN_WSASOCKETW)(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags);
+ typedef DWORD (WSAAPI *LPFN_WSAWAITFORMULTIPLEEVENTS)(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable);
+ typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGA)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength);
+ typedef INT (WSAAPI *LPFN_WSAADDRESSTOSTRINGW)(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength);
+ typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSA)(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength);
+ typedef INT (WSAAPI *LPFN_WSASTRINGTOADDRESSW)(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength);
+ typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINA)(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup);
+ typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEBEGINW)(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup);
+ typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTA)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults);
+ typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICENEXTW)(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults);
+ typedef INT (WSAAPI *LPFN_WSANSPIOCTL)(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion);
+ typedef INT (WSAAPI *LPFN_WSALOOKUPSERVICEEND)(HANDLE hLookup);
+ typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSA)(LPWSASERVICECLASSINFOA lpServiceClassInfo);
+ typedef INT (WSAAPI *LPFN_WSAINSTALLSERVICECLASSW)(LPWSASERVICECLASSINFOW lpServiceClassInfo);
+ typedef INT (WSAAPI *LPFN_WSAREMOVESERVICECLASS)(LPGUID lpServiceClassId);
+ typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOA)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo);
+ typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSINFOW)(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo);
+ typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSA)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer);
+ typedef INT (WSAAPI *LPFN_WSAENUMNAMESPACEPROVIDERSW)(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer);
+ typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDA)(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength);
+ typedef INT (WSAAPI *LPFN_WSAGETSERVICECLASSNAMEBYCLASSIDW)(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength);
+ typedef INT (WSAAPI *LPFN_WSASETSERVICEA)(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags);
+ typedef INT (WSAAPI *LPFN_WSASETSERVICEW)(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags);
+ typedef INT (WSAAPI *LPFN_WSAPROVIDERCONFIGCHANGE)(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+#endif
+
+#ifdef UNICODE
+#define WSADuplicateSocket WSADuplicateSocketW
+#define WSAEnumProtocols WSAEnumProtocolsW
+#define WSAAddressToString WSAAddressToStringW
+#define WSASocket WSASocketW
+#define WSAStringToAddress WSAStringToAddressW
+#define WSALookupServiceBegin WSALookupServiceBeginW
+#define WSALookupServiceNext WSALookupServiceNextW
+#define WSAInstallServiceClass WSAInstallServiceClassW
+#define WSAGetServiceClassInfo WSAGetServiceClassInfoW
+#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersW
+#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdW
+#define WSASetService WSASetServiceW
+#else
+#define WSADuplicateSocket WSADuplicateSocketA
+#define WSAEnumProtocols WSAEnumProtocolsA
+#define WSASocket WSASocketA
+#define WSAAddressToString WSAAddressToStringA
+#define WSAStringToAddress WSAStringToAddressA
+#define WSALookupServiceBegin WSALookupServiceBeginA
+#define WSALookupServiceNext WSALookupServiceNextA
+#define WSAInstallServiceClass WSAInstallServiceClassA
+#define WSAGetServiceClassInfo WSAGetServiceClassInfoA
+#define WSAEnumNameSpaceProviders WSAEnumNameSpaceProvidersA
+#define WSAGetServiceClassNameByClassId WSAGetServiceClassNameByClassIdA
+#define WSASetService WSASetServiceA
+#endif
+
+ WINSOCK_API_LINKAGE SOCKET WSAAPI accept(SOCKET s,struct sockaddr *addr,int *addrlen);
+ WINSOCK_API_LINKAGE int WSAAPI bind(SOCKET s,const struct sockaddr *name,int namelen);
+ WINSOCK_API_LINKAGE int WSAAPI closesocket(SOCKET s);
+ WINSOCK_API_LINKAGE int WSAAPI connect(SOCKET s,const struct sockaddr *name,int namelen);
+ WINSOCK_API_LINKAGE int WSAAPI ioctlsocket(SOCKET s,long cmd,u_long *argp);
+ WINSOCK_API_LINKAGE int WSAAPI getpeername(SOCKET s,struct sockaddr *name,int *namelen);
+ WINSOCK_API_LINKAGE int WSAAPI getsockname(SOCKET s,struct sockaddr *name,int *namelen);
+ WINSOCK_API_LINKAGE int WSAAPI getsockopt(SOCKET s,int level,int optname,char *optval,int *optlen);
+ WINSOCK_API_LINKAGE u_long WSAAPI htonl(u_long hostlong);
+ WINSOCK_API_LINKAGE u_short WSAAPI htons(u_short hostshort);
+ WINSOCK_API_LINKAGE unsigned long WSAAPI inet_addr(const char *cp);
+ WINSOCK_API_LINKAGE char *WSAAPI inet_ntoa(struct in_addr in);
+ WINSOCK_API_LINKAGE int WSAAPI listen(SOCKET s,int backlog);
+ WINSOCK_API_LINKAGE u_long WSAAPI ntohl(u_long netlong);
+ WINSOCK_API_LINKAGE u_short WSAAPI ntohs(u_short netshort);
+ WINSOCK_API_LINKAGE int WSAAPI recv(SOCKET s,char *buf,int len,int flags);
+ WINSOCK_API_LINKAGE int WSAAPI recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen);
+ WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const struct timeval *timeout);
+ WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags);
+ WINSOCK_API_LINKAGE int WSAAPI sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen);
+ WINSOCK_API_LINKAGE int WSAAPI setsockopt(SOCKET s,int level,int optname,const char *optval,int optlen);
+ WINSOCK_API_LINKAGE int WSAAPI shutdown(SOCKET s,int how);
+ WINSOCK_API_LINKAGE SOCKET WSAAPI socket(int af,int type,int protocol);
+ WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyaddr(const char *addr,int len,int type);
+ WINSOCK_API_LINKAGE struct hostent *WSAAPI gethostbyname(const char *name);
+ WINSOCK_API_LINKAGE int WSAAPI gethostname(char *name,int namelen);
+ WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyport(int port,const char *proto);
+ WINSOCK_API_LINKAGE struct servent *WSAAPI getservbyname(const char *name,const char *proto);
+ WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobynumber(int number);
+ WINSOCK_API_LINKAGE struct protoent *WSAAPI getprotobyname(const char *name);
+ WINSOCK_API_LINKAGE int WSAAPI WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
+ WINSOCK_API_LINKAGE int WSAAPI WSACleanup(void);
+ WINSOCK_API_LINKAGE void WSAAPI WSASetLastError(int iError);
+ WINSOCK_API_LINKAGE int WSAAPI WSAGetLastError(void);
+ WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAIsBlocking(void);
+ WINSOCK_API_LINKAGE int WSAAPI WSAUnhookBlockingHook(void);
+ WINSOCK_API_LINKAGE FARPROC WSAAPI WSASetBlockingHook(FARPROC lpBlockFunc);
+ WINSOCK_API_LINKAGE int WSAAPI WSACancelBlockingCall(void);
+ WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByName(HWND hWnd,u_int wMsg,const char *name,const char *proto,char *buf,int buflen);
+ WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetServByPort(HWND hWnd,u_int wMsg,int port,const char *proto,char *buf,int buflen);
+ WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen);
+ WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetProtoByNumber(HWND hWnd,u_int wMsg,int number,char *buf,int buflen);
+ WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByName(HWND hWnd,u_int wMsg,const char *name,char *buf,int buflen);
+ WINSOCK_API_LINKAGE HANDLE WSAAPI WSAAsyncGetHostByAddr(HWND hWnd,u_int wMsg,const char *addr,int len,int type,char *buf,int buflen);
+ WINSOCK_API_LINKAGE int WSAAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);
+ WINSOCK_API_LINKAGE int WSAAPI WSAAsyncSelect(SOCKET s,HWND hWnd,u_int wMsg,long lEvent);
+ WINSOCK_API_LINKAGE SOCKET WSAAPI WSAAccept(SOCKET s,struct sockaddr *addr,LPINT addrlen,LPCONDITIONPROC lpfnCondition,DWORD_PTR dwCallbackData);
+ WINSOCK_API_LINKAGE WINBOOL WSAAPI WSACloseEvent(WSAEVENT hEvent);
+ WINSOCK_API_LINKAGE int WSAAPI WSAConnect(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
+ WINSOCK_API_LINKAGE WSAEVENT WSAAPI WSACreateEvent(void);
+ WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketA(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOA lpProtocolInfo);
+ WINSOCK_API_LINKAGE int WSAAPI WSADuplicateSocketW(SOCKET s,DWORD dwProcessId,LPWSAPROTOCOL_INFOW lpProtocolInfo);
+ WINSOCK_API_LINKAGE int WSAAPI WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);
+ WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsA(LPINT lpiProtocols,LPWSAPROTOCOL_INFOA lpProtocolBuffer,LPDWORD lpdwBufferLength);
+ WINSOCK_API_LINKAGE int WSAAPI WSAEnumProtocolsW(LPINT lpiProtocols,LPWSAPROTOCOL_INFOW lpProtocolBuffer,LPDWORD lpdwBufferLength);
+ WINSOCK_API_LINKAGE int WSAAPI WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents);
+ WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetOverlappedResult(SOCKET s,LPWSAOVERLAPPED lpOverlapped,LPDWORD lpcbTransfer,WINBOOL fWait,LPDWORD lpdwFlags);
+ WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAGetQOSByName(SOCKET s,LPWSABUF lpQOSName,LPQOS lpQOS);
+ WINSOCK_API_LINKAGE int WSAAPI WSAHtonl(SOCKET s,u_long hostlong,u_long *lpnetlong);
+ WINSOCK_API_LINKAGE int WSAAPI WSAHtons(SOCKET s,u_short hostshort,u_short *lpnetshort);
+ WINSOCK_API_LINKAGE int WSAAPI WSAIoctl(SOCKET s,DWORD dwIoControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ WINSOCK_API_LINKAGE SOCKET WSAAPI WSAJoinLeaf(SOCKET s,const struct sockaddr *name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS,DWORD dwFlags);
+ WINSOCK_API_LINKAGE int WSAAPI WSANtohl(SOCKET s,u_long netlong,u_long *lphostlong);
+ WINSOCK_API_LINKAGE int WSAAPI WSANtohs(SOCKET s,u_short netshort,u_short *lphostshort);
+ WINSOCK_API_LINKAGE int WSAAPI WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ WINSOCK_API_LINKAGE int WSAAPI WSARecvDisconnect(SOCKET s,LPWSABUF lpInboundDisconnectData);
+ WINSOCK_API_LINKAGE int WSAAPI WSARecvFrom(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags,struct sockaddr *lpFrom,LPINT lpFromlen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ WINSOCK_API_LINKAGE WINBOOL WSAAPI WSAResetEvent(WSAEVENT hEvent);
+ WINSOCK_API_LINKAGE int WSAAPI WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ WINSOCK_API_LINKAGE int WSAAPI WSASendDisconnect(SOCKET s,LPWSABUF lpOutboundDisconnectData);
+ WINSOCK_API_LINKAGE int WSAAPI WSASendTo(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,const struct sockaddr *lpTo,int iTolen,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+ WINSOCK_API_LINKAGE WINBOOL WSAAPI WSASetEvent(WSAEVENT hEvent);
+ WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketA(int af,int type,int protocol,LPWSAPROTOCOL_INFOA lpProtocolInfo,GROUP g,DWORD dwFlags);
+ WINSOCK_API_LINKAGE SOCKET WSAAPI WSASocketW(int af,int type,int protocol,LPWSAPROTOCOL_INFOW lpProtocolInfo,GROUP g,DWORD dwFlags);
+ WINSOCK_API_LINKAGE DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,const WSAEVENT *lphEvents,WINBOOL fWaitAll,DWORD dwTimeout,WINBOOL fAlertable);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringA(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSTR lpszAddressString,LPDWORD lpdwAddressStringLength);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAAddressToStringW(LPSOCKADDR lpsaAddress,DWORD dwAddressLength,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPWSTR lpszAddressString,LPDWORD lpdwAddressStringLength);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressA(LPSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOA lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAStringToAddressW(LPWSTR AddressString,INT AddressFamily,LPWSAPROTOCOL_INFOW lpProtocolInfo,LPSOCKADDR lpAddress,LPINT lpAddressLength);
+ WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginA(LPWSAQUERYSETA lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup);
+ WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceBeginW(LPWSAQUERYSETW lpqsRestrictions,DWORD dwControlFlags,LPHANDLE lphLookup);
+ WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextA(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETA lpqsResults);
+ WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceNextW(HANDLE hLookup,DWORD dwControlFlags,LPDWORD lpdwBufferLength,LPWSAQUERYSETW lpqsResults);
+ WINSOCK_API_LINKAGE INT WSAAPI WSANSPIoctl(HANDLE hLookup,DWORD dwControlCode,LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,LPDWORD lpcbBytesReturned,LPWSACOMPLETION lpCompletion);
+ WINSOCK_API_LINKAGE INT WSAAPI WSALookupServiceEnd(HANDLE hLookup);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassA(LPWSASERVICECLASSINFOA lpServiceClassInfo);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAInstallServiceClassW(LPWSASERVICECLASSINFOW lpServiceClassInfo);
+ WINSOCK_API_LINKAGE INT WSAAPI WSARemoveServiceClass(LPGUID lpServiceClassId);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoA(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOA lpServiceClassInfo);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassInfoW(LPGUID lpProviderId,LPGUID lpServiceClassId,LPDWORD lpdwBufSize,LPWSASERVICECLASSINFOW lpServiceClassInfo);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersA(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOA lpnspBuffer);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAEnumNameSpaceProvidersW(LPDWORD lpdwBufferLength,LPWSANAMESPACE_INFOW lpnspBuffer);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdA(LPGUID lpServiceClassId,LPSTR lpszServiceClassName,LPDWORD lpdwBufferLength);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAGetServiceClassNameByClassIdW(LPGUID lpServiceClassId,LPWSTR lpszServiceClassName,LPDWORD lpdwBufferLength);
+ WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceA(LPWSAQUERYSETA lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags);
+ WINSOCK_API_LINKAGE INT WSAAPI WSASetServiceW(LPWSAQUERYSETW lpqsRegInfo,WSAESETSERVICEOP essoperation,DWORD dwControlFlags);
+ WINSOCK_API_LINKAGE INT WSAAPI WSAProviderConfigChange(LPHANDLE lpNotificationHandle,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
+
+ typedef struct sockaddr_in SOCKADDR_IN;
+ typedef struct sockaddr_in *PSOCKADDR_IN;
+ typedef struct sockaddr_in *LPSOCKADDR_IN;
+
+ typedef struct linger LINGER;
+ typedef struct linger *PLINGER;
+ typedef struct linger *LPLINGER;
+
+ typedef struct in_addr IN_ADDR;
+ typedef struct in_addr *PIN_ADDR;
+ typedef struct in_addr *LPIN_ADDR;
+
+ typedef struct fd_set FD_SET;
+ typedef struct fd_set *PFD_SET;
+ typedef struct fd_set *LPFD_SET;
+
+ typedef struct hostent HOSTENT;
+ typedef struct hostent *PHOSTENT;
+ typedef struct hostent *LPHOSTENT;
+
+ typedef struct servent SERVENT;
+ typedef struct servent *PSERVENT;
+ typedef struct servent *LPSERVENT;
+
+ typedef struct protoent PROTOENT;
+ typedef struct protoent *PPROTOENT;
+ typedef struct protoent *LPPROTOENT;
+
+ typedef struct timeval TIMEVAL;
+ typedef struct timeval *PTIMEVAL;
+ typedef struct timeval *LPTIMEVAL;
+
+#define WSAMAKEASYNCREPLY(buflen,error) MAKELONG(buflen,error)
+#define WSAMAKESELECTREPLY(event,error) MAKELONG(event,error)
+#define WSAGETASYNCBUFLEN(lParam) LOWORD(lParam)
+#define WSAGETASYNCERROR(lParam) HIWORD(lParam)
+#define WSAGETSELECTEVENT(lParam) LOWORD(lParam)
+#define WSAGETSELECTERROR(lParam) HIWORD(lParam)
+
+/* #if (_WIN32_WINNT >= 0x0600) */
+#define POLLRDNORM 0x0100
+#define POLLRDBAND 0x0200
+#define POLLIN (POLLRDNORM | POLLRDBAND)
+#define POLLPRI 0x0400
+
+#define POLLWRNORM 0x0010
+#define POLLOUT (POLLWRNORM)
+#define POLLWRBAND 0x0020
+
+#define POLLERR 0x0001
+#define POLLHUP 0x0002
+#define POLLNVAL 0x0004
+
+typedef struct pollfd {
+ SOCKET fd;
+ SHORT events;
+ SHORT revents;
+} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD;
+
+WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout);
+/* #endif // (_WIN32_WINNT >= 0x0600) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef _NEED_POPPACK
+#include <poppack.h>
+#endif
+
+#ifdef IPV6STRICT
+#include <wsipv6ok.h>
+#endif
+
+#ifndef _WINSOCKAPI_
+#define _WINSOCKAPI_
+#endif
+
+#ifdef _INC_WINSOCK_H
+#include <mswsock.h>
+#endif
+
+#endif
diff --git a/win32/include/winapi/ws2ipdef.h b/win32/include/winapi/ws2ipdef.h
new file mode 100644
index 0000000..1f6c1c0
--- /dev/null
+++ b/win32/include/winapi/ws2ipdef.h
@@ -0,0 +1,21 @@
+#ifndef _WS2IPDEF_H
+#define _WS2IPDEF_H
+
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#include <winsock2.h>
+
+struct ip_mreq {
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_interface;
+};
+
+struct ip_mreq_source {
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_sourceaddr;
+ struct in_addr imr_interface;
+};
+
+#endif
diff --git a/win32/include/winapi/ws2tcpip.h b/win32/include/winapi/ws2tcpip.h
new file mode 100644
index 0000000..ac45767
--- /dev/null
+++ b/win32/include/winapi/ws2tcpip.h
@@ -0,0 +1,391 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER within this package.
+ */
+#ifndef _WS2TCPIP_H
+#define _WS2TCPIP_H
+
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#include <ws2ipdef.h>
+
+struct ip_msfilter {
+ struct in_addr imsf_multiaddr;
+ struct in_addr imsf_interface;
+ u_long imsf_fmode;
+ u_long imsf_numsrc;
+ struct in_addr imsf_slist[1];
+};
+
+#define IP_MSFILTER_SIZE(numsrc) (sizeof(struct ip_msfilter)-sizeof(struct in_addr) + (numsrc)*sizeof(struct in_addr))
+
+#define MCAST_INCLUDE 0
+#define MCAST_EXCLUDE 1
+
+#define SIO_GET_INTERFACE_LIST _IOR('t',127,u_long)
+
+#define SIO_GET_INTERFACE_LIST_EX _IOR('t',126,u_long)
+#define SIO_SET_MULTICAST_FILTER _IOW('t',125,u_long)
+#define SIO_GET_MULTICAST_FILTER _IOW('t',124 | IOC_IN,u_long)
+
+#define IP_OPTIONS 1
+#define IP_HDRINCL 2
+#define IP_TOS 3
+#define IP_TTL 4
+#define IP_MULTICAST_IF 9
+#define IP_MULTICAST_TTL 10
+#define IP_MULTICAST_LOOP 11
+#define IP_ADD_MEMBERSHIP 12
+#define IP_DROP_MEMBERSHIP 13
+#define IP_DONTFRAGMENT 14
+#define IP_ADD_SOURCE_MEMBERSHIP 15
+#define IP_DROP_SOURCE_MEMBERSHIP 16
+#define IP_BLOCK_SOURCE 17
+#define IP_UNBLOCK_SOURCE 18
+#define IP_PKTINFO 19
+#define IP_RECEIVE_BROADCAST 22
+
+#define IPV6_HDRINCL 2
+#define IPV6_UNICAST_HOPS 4
+#define IPV6_MULTICAST_IF 9
+#define IPV6_MULTICAST_HOPS 10
+#define IPV6_MULTICAST_LOOP 11
+#define IPV6_ADD_MEMBERSHIP 12
+#define IPV6_DROP_MEMBERSHIP 13
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#define IPV6_PKTINFO 19
+#define IPV6_HOPLIMIT 21
+#define IPV6_PROTECTION_LEVEL 23
+
+#define PROTECTION_LEVEL_UNRESTRICTED 10
+#define PROTECTION_LEVEL_DEFAULT 20
+#define PROTECTION_LEVEL_RESTRICTED 30
+
+#define UDP_NOCHECKSUM 1
+#define UDP_CHECKSUM_COVERAGE 20
+
+#define TCP_EXPEDITED_1122 0x0002
+
+#ifndef s6_addr
+
+struct in6_addr {
+ __MINGW_EXTENSION union {
+ u_char Byte[16];
+ u_short Word[8];
+ } u;
+};
+
+#define in_addr6 in6_addr
+
+#define _S6_un u
+#define _S6_u8 Byte
+#define s6_addr _S6_un._S6_u8
+
+#define s6_bytes u.Byte
+#define s6_words u.Word
+#endif
+
+typedef struct ipv6_mreq {
+ struct in6_addr ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
+} IPV6_MREQ;
+
+struct sockaddr_in6_old {
+ short sin6_family;
+ u_short sin6_port;
+ u_long sin6_flowinfo;
+ struct in6_addr sin6_addr;
+};
+
+struct sockaddr_in6 {
+ short sin6_family;
+ u_short sin6_port;
+ u_long sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ u_long sin6_scope_id;
+};
+
+typedef struct in6_addr IN6_ADDR;
+typedef struct in6_addr *PIN6_ADDR;
+typedef struct in6_addr *LPIN6_ADDR;
+
+typedef struct sockaddr_in6 SOCKADDR_IN6;
+typedef struct sockaddr_in6 *PSOCKADDR_IN6;
+typedef struct sockaddr_in6 *LPSOCKADDR_IN6;
+
+#define SS_PORT(ssp) (((struct sockaddr_in*)(ssp))->sin_port)
+
+#define IN6ADDR_ANY_INIT { 0 }
+#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern const struct in6_addr in6addr_any;
+ extern const struct in6_addr in6addr_loopback;
+
+#ifdef __cplusplus
+}
+#endif
+
+#define WS2TCPIP_INLINE __CRT_INLINE
+
+int IN6_ADDR_EQUAL(const struct in6_addr *,const struct in6_addr *);
+int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *);
+int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *);
+int IN6_IS_ADDR_MULTICAST(const struct in6_addr *);
+int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *);
+int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *);
+int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *);
+int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *);
+int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *);
+int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *);
+int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *);
+int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *);
+int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *);
+int IN6ADDR_ISANY(const struct sockaddr_in6 *);
+int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *);
+void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *);
+void IN6_SET_ADDR_LOOPBACK(struct in6_addr *);
+void IN6ADDR_SETANY(struct sockaddr_in6 *);
+void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *);
+
+#ifndef __CRT__NO_INLINE
+WS2TCPIP_INLINE int IN6_ADDR_EQUAL(const struct in6_addr *a,const struct in6_addr *b) { return (memcmp(a,b,sizeof(struct in6_addr))==0); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0)); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && (a->s6_words[6]==0) && (a->s6_words[7]==0x0100)); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_MULTICAST(const struct in6_addr *a) { return (a->s6_bytes[0]==0xff); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0x80)); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *a) { return ((a->s6_bytes[0]==0xfe) && ((a->s6_bytes[1] & 0xc0)==0xc0)); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0) && !((a->s6_words[6]==0) && (a->s6_addr[14]==0) && ((a->s6_addr[15]==0) || (a->s6_addr[15]==1)))); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==1); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==2); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==5); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==8); }
+WS2TCPIP_INLINE int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_bytes[1] & 0xf)==0xe); }
+WS2TCPIP_INLINE int IN6ADDR_ISANY(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)); }
+WS2TCPIP_INLINE int IN6ADDR_ISLOOPBACK(const struct sockaddr_in6 *a) { return ((a->sin6_family==AF_INET6) && IN6_IS_ADDR_LOOPBACK(&a->sin6_addr)); }
+WS2TCPIP_INLINE void IN6_SET_ADDR_UNSPECIFIED(struct in6_addr *a) { memset(a->s6_bytes,0,sizeof(struct in6_addr)); }
+WS2TCPIP_INLINE void IN6_SET_ADDR_LOOPBACK(struct in6_addr *a) {
+ memset(a->s6_bytes,0,sizeof(struct in6_addr));
+ a->s6_bytes[15] = 1;
+}
+WS2TCPIP_INLINE void IN6ADDR_SETANY(struct sockaddr_in6 *a) {
+ a->sin6_family = AF_INET6;
+ a->sin6_port = 0;
+ a->sin6_flowinfo = 0;
+ IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr);
+ a->sin6_scope_id = 0;
+}
+WS2TCPIP_INLINE void IN6ADDR_SETLOOPBACK(struct sockaddr_in6 *a) {
+ a->sin6_family = AF_INET6;
+ a->sin6_port = 0;
+ a->sin6_flowinfo = 0;
+ IN6_SET_ADDR_LOOPBACK(&a->sin6_addr);
+ a->sin6_scope_id = 0;
+}
+#endif /* !__CRT__NO_INLINE */
+
+typedef union sockaddr_gen {
+ struct sockaddr Address;
+ struct sockaddr_in AddressIn;
+ struct sockaddr_in6_old AddressIn6;
+} sockaddr_gen;
+
+typedef struct _INTERFACE_INFO {
+ u_long iiFlags;
+ sockaddr_gen iiAddress;
+ sockaddr_gen iiBroadcastAddress;
+ sockaddr_gen iiNetmask;
+} INTERFACE_INFO,*LPINTERFACE_INFO;
+
+typedef struct _INTERFACE_INFO_EX {
+ u_long iiFlags;
+ SOCKET_ADDRESS iiAddress;
+ SOCKET_ADDRESS iiBroadcastAddress;
+ SOCKET_ADDRESS iiNetmask;
+} INTERFACE_INFO_EX,*LPINTERFACE_INFO_EX;
+
+#define IFF_UP 0x00000001
+#define IFF_BROADCAST 0x00000002
+#define IFF_LOOPBACK 0x00000004
+#define IFF_POINTTOPOINT 0x00000008
+#define IFF_MULTICAST 0x00000010
+
+typedef struct in_pktinfo {
+ IN_ADDR ipi_addr;
+ UINT ipi_ifindex;
+} IN_PKTINFO;
+
+C_ASSERT(sizeof(IN_PKTINFO)==8);
+
+typedef struct in6_pktinfo {
+ IN6_ADDR ipi6_addr;
+ UINT ipi6_ifindex;
+} IN6_PKTINFO;
+
+C_ASSERT(sizeof(IN6_PKTINFO)==20);
+
+#define EAI_AGAIN WSATRY_AGAIN
+#define EAI_BADFLAGS WSAEINVAL
+#define EAI_FAIL WSANO_RECOVERY
+#define EAI_FAMILY WSAEAFNOSUPPORT
+#define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
+
+#define EAI_NONAME WSAHOST_NOT_FOUND
+#define EAI_SERVICE WSATYPE_NOT_FOUND
+#define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
+
+#define EAI_NODATA EAI_NONAME
+
+typedef struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
+} ADDRINFOA,*PADDRINFOA;
+
+typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ PWSTR ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfoW *ai_next;
+} ADDRINFOW,*PADDRINFOW;
+
+#ifdef UNICODE
+typedef ADDRINFOW ADDRINFOT,*PADDRINFOT;
+#else
+typedef ADDRINFOA ADDRINFOT,*PADDRINFOT;
+#endif
+
+typedef ADDRINFOA ADDRINFO,*LPADDRINFO;
+
+#define AI_PASSIVE 0x1
+#define AI_CANONNAME 0x2
+#define AI_NUMERICHOST 0x4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef UNICODE
+#define GetAddrInfo GetAddrInfoW
+#else
+#define GetAddrInfo GetAddrInfoA
+#endif
+
+ WINSOCK_API_LINKAGE int WSAAPI getaddrinfo(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res);
+ WINSOCK_API_LINKAGE int WSAAPI GetAddrInfoW(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult);
+
+#define GetAddrInfoA getaddrinfo
+
+#if INCL_WINSOCK_API_TYPEDEFS
+ typedef int (WSAAPI *LPFN_GETADDRINFO)(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res);
+ typedef int (WSAAPI *LPFN_GETADDRINFOW)(PCWSTR pNodeName,PCWSTR pServiceName,const ADDRINFOW *pHints,PADDRINFOW *ppResult);
+
+#define LPFN_GETADDRINFOA LPFN_GETADDRINFO
+
+#ifdef UNICODE
+#define LPFN_GETADDRINFOT LPFN_GETADDRINFOW
+#else
+#define LPFN_GETADDRINFOT LPFN_GETADDRINFOA
+#endif
+#endif
+
+#ifdef UNICODE
+#define FreeAddrInfo FreeAddrInfoW
+#else
+#define FreeAddrInfo FreeAddrInfoA
+#endif
+
+ WINSOCK_API_LINKAGE void WSAAPI freeaddrinfo(LPADDRINFO pAddrInfo);
+ WINSOCK_API_LINKAGE void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
+
+#define FreeAddrInfoA freeaddrinfo
+
+#if INCL_WINSOCK_API_TYPEDEFS
+ typedef void (WSAAPI *LPFN_FREEADDRINFO)(struct addrinfo *ai);
+ typedef void (WSAAPI *LPFN_FREEADDRINFOW)(PADDRINFOW pAddrInfo);
+
+#define LPFN_FREEADDRINFOA LPFN_FREEADDRINFO
+
+#ifdef UNICODE
+#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOW
+#else
+#define LPFN_FREEADDRINFOT LPFN_FREEADDRINFOA
+#endif
+#endif
+
+#pragma push_macro("socklen_t")
+#undef socklen_t
+
+ typedef int socklen_t;
+
+#ifdef UNICODE
+#define GetNameInfo GetNameInfoW
+#else
+#define GetNameInfo GetNameInfoA
+#endif
+
+ WINSOCK_API_LINKAGE int WSAAPI getnameinfo(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags);
+ WINSOCK_API_LINKAGE INT WSAAPI GetNameInfoW(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags);
+
+#define GetNameInfoA getnameinfo
+
+#if INCL_WINSOCK_API_TYPEDEFS
+ typedef int (WSAAPI *LPFN_GETNAMEINFO)(const struct sockaddr *sa,socklen_t salen,char *host,DWORD hostlen,char *serv,DWORD servlen,int flags);
+ typedef INT (WSAAPI *LPFN_GETNAMEINFOW)(const SOCKADDR *pSockaddr,socklen_t SockaddrLength,PWCHAR pNodeBuffer,DWORD NodeBufferSize,PWCHAR pServiceBuffer,DWORD ServiceBufferSize,INT Flags);
+
+#define LPFN_GETNAMEINFOA LPFN_GETNAMEINFO
+
+#ifdef UNICODE
+#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOW
+#else
+#define LPFN_GETNAMEINFOT LPFN_GETNAMEINFOA
+#endif
+#endif
+
+#pragma pop_macro("socklen_t")
+
+#ifdef UNICODE
+#define gai_strerror gai_strerrorW
+#else
+#define gai_strerror gai_strerrorA
+#endif
+
+#define GAI_STRERROR_BUFFER_SIZE 1024
+
+char *gai_strerrorA (int);
+WCHAR *gai_strerrorW(int);
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+#define INET_ADDRSTRLEN 22
+#define INET6_ADDRSTRLEN 65
+
+#define NI_NOFQDN 0x01
+#define NI_NUMERICHOST 0x02
+#define NI_NAMEREQD 0x04
+#define NI_NUMERICSERV 0x08
+#define NI_DGRAM 0x10
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/win32/lib/chkstk.S b/win32/lib/chkstk.S
index ec5c07f..6f583a5 100644
--- a/win32/lib/chkstk.S
+++ b/win32/lib/chkstk.S
@@ -1,13 +1,18 @@
/* ---------------------------------------------- */
/* chkstk86.s */
+#ifdef __leading_underscore
+# define _(s) _##s
+#else
+# define _(s) s
+#endif
+
/* ---------------------------------------------- */
#ifndef __x86_64__
/* ---------------------------------------------- */
-.globl __chkstk
-
-__chkstk:
+.globl _(__chkstk)
+_(__chkstk):
xchg (%esp),%ebp /* store ebp, get ret.addr */
push %ebp /* push ret.addr */
lea 4(%esp),%ebp /* setup frame ptr */
@@ -31,9 +36,8 @@ P0:
#else
/* ---------------------------------------------- */
-.globl __chkstk
-
-__chkstk:
+.globl _(__chkstk)
+_(__chkstk):
xchg (%rsp),%rbp /* store ebp, get ret.addr */
push %rbp /* push ret.addr */
lea 8(%rsp),%rbp /* setup frame ptr */
@@ -57,8 +61,8 @@ P0:
/* ---------------------------------------------- */
/* setjmp/longjmp support */
-.globl tinyc_getbp
-tinyc_getbp:
+.globl _(tinyc_getbp)
+_(tinyc_getbp):
mov %rbp,%rax
ret
@@ -67,125 +71,3 @@ tinyc_getbp:
/* ---------------------------------------------- */
-/* ---------------------------------------------- */
-#ifndef __x86_64__
-/* ---------------------------------------------- */
-
-/*
- int _except_handler3(
- PEXCEPTION_RECORD exception_record,
- PEXCEPTION_REGISTRATION registration,
- PCONTEXT context,
- PEXCEPTION_REGISTRATION dispatcher
- );
-
- int __cdecl _XcptFilter(
- unsigned long xcptnum,
- PEXCEPTION_POINTERS pxcptinfoptrs
- );
-
- struct _sehrec {
- void *esp; // 0
- void *exception_pointers; // 1
- void *prev; // 2
- void *handler; // 3
- void *scopetable; // 4
- int trylevel; // 5
- void *ebp // 6
- };
-
- // this is what the assembler code below means:
- __try
- {
- // ...
- }
- __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation()))
- {
- exit(GetExceptionCode());
- }
-*/
-
-.globl _exception_info
-_exception_info:
- mov 1*4-24(%ebp),%eax
- ret
-
-.globl _exception_code
-_exception_code:
- call _exception_info
- mov (%eax),%eax
- mov (%eax),%eax
- ret
-
-seh_filter:
- call _exception_info
- push %eax
- call _exception_code
- push %eax
- call _XcptFilter
- add $ 8,%esp
- ret
-
-seh_except:
- mov 0*4-24(%ebp),%esp
- call _exception_code
- push %eax
- call _exit
-
-// msvcrt wants scopetables aligned and in read-only segment (using .text)
-.align 4
-seh_scopetable:
- .long -1
- .long seh_filter
- .long seh_except
-
-seh_handler:
- jmp _except_handler3
-
-.globl ___try__
-___try__:
-.globl __try__
-__try__:
- push %ebp
- mov 8(%esp),%ebp
-
-// void *esp;
- lea 12(%esp),%eax
- mov %eax,0*4(%ebp)
-
-// void *exception_pointers;
- xor %eax,%eax
- mov %eax,1*4(%ebp)
-
-// void *prev;
- mov %fs:0,%eax
- mov %eax,2*4(%ebp)
-
-// void *handler;
- mov $ seh_handler,%eax
- mov %eax,3*4(%ebp)
-
-// void *scopetable;
- mov $ seh_scopetable,%eax
- mov %eax,4*4(%ebp)
-
-// int trylevel;
- xor %eax,%eax
- mov %eax,5*4(%ebp)
-
-// register new SEH
- lea 2*4(%ebp),%eax
- mov %eax,%fs:0
-
- pop %ebp
- ret
-
-/* ---------------------------------------------- */
-#else
-/* ---------------------------------------------- */
-
-/* SEH on x86-64 not implemented */
-
-/* ---------------------------------------------- */
-#endif
-/* ---------------------------------------------- */
diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c
index 0e04fc0..0686302 100644
--- a/win32/lib/crt1.c
+++ b/win32/lib/crt1.c
@@ -4,6 +4,7 @@
// _UNICODE for tchar.h, UNICODE for API
#include <tchar.h>
+#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
@@ -34,14 +35,29 @@ void __cdecl __set_app_type(int apptype);
unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask);
extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
+#include "crtinit.c"
+
+static int do_main (int argc, _TCHAR * argv[], _TCHAR * env[])
+{
+ int retval;
+ run_ctors(argc, argv, env);
+ retval = _tmain(__argc, __targv, _tenviron);
+ run_dtors();
+ return retval;
+}
+
/* Allow command-line globbing with "int _dowildcard = 1;" in the user source */
int _dowildcard;
+static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)
+{
+ return _XcptFilter(ex->ExceptionRecord->ExceptionCode, ex);
+}
+
void _tstart(void)
{
- __TRY__
_startupinfo start_info = {0};
-
+ SetUnhandledExceptionFilter(catch_sig);
// Sets the current application type
__set_app_type(_CONSOLE_APP);
@@ -52,7 +68,7 @@ void _tstart(void)
#endif
__tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
- exit(_tmain(__argc, __targv, _tenviron));
+ exit(do_main(__argc, __targv, _tenviron));
}
int _runtmain(int argc, /* as tcc passed in */ char **argv)
diff --git a/win32/lib/crtinit.c b/win32/lib/crtinit.c
new file mode 100644
index 0000000..31f087b
--- /dev/null
+++ b/win32/lib/crtinit.c
@@ -0,0 +1,26 @@
+//+---------------------------------------------------------------------------
+
+#ifdef __leading_underscore
+# define _(s) s
+#else
+# define _(s) _##s
+#endif
+
+extern void (*_(_init_array_start)[]) (int argc, _TCHAR **argv, _TCHAR **envp);
+extern void (*_(_init_array_end)[]) (int argc, _TCHAR **argv, _TCHAR **envp);
+extern void (*_(_fini_array_start)[]) (void);
+extern void (*_(_fini_array_end)[]) (void);
+
+static void run_ctors(int argc, _TCHAR **argv, _TCHAR **env)
+{
+ int i = 0;
+ while (&_(_init_array_start)[i] != _(_init_array_end))
+ (*_(_init_array_start)[i++])(argc, argv, env);
+}
+
+static void run_dtors(void)
+{
+ int i = 0;
+ while (&_(_fini_array_end)[i] != _(_fini_array_start))
+ (*_(_fini_array_end)[--i])();
+}
diff --git a/win32/lib/dllcrt1.c b/win32/lib/dllcrt1.c
index ba1dbd0..5a9be82 100644
--- a/win32/lib/dllcrt1.c
+++ b/win32/lib/dllcrt1.c
@@ -1,13 +1,18 @@
//+---------------------------------------------------------------------------
+#include <tchar.h>
#include <windows.h>
+#include "crtinit.c"
BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved);
BOOL WINAPI _dllstart(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
{
- BOOL bRet;
- bRet = DllMain (hDll, dwReason, lpReserved);
- return bRet;
+ BOOL bRet;
+ if (dwReason == DLL_PROCESS_ATTACH) /* ignore DLL_THREAD_ATTACH */
+ run_ctors(0, 0, 0);
+ bRet = DllMain (hDll, dwReason, lpReserved);
+ if (dwReason == DLL_PROCESS_DETACH) /* ignore DLL_THREAD_DETACH */
+ run_dtors();
+ return bRet;
}
-
diff --git a/win32/lib/msvcrt.def b/win32/lib/msvcrt.def
index 742acb8..e8f6ab9 100644
--- a/win32/lib/msvcrt.def
+++ b/win32/lib/msvcrt.def
@@ -1,80 +1,57 @@
LIBRARY msvcrt.dll
EXPORTS
-$I10_OUTPUT
-??0__non_rtti_object@@QAE@ABV0@@Z
-??0__non_rtti_object@@QAE@PBD@Z
+??0__non_rtti_object@@QEAA@AEBV0@@Z
+??0__non_rtti_object@@QEAA@PEBD@Z
??0bad_cast@@AAE@PBQBD@Z
+??0bad_cast@@AEAA@PEBQEBD@Z
??0bad_cast@@QAE@ABQBD@Z
-??0bad_cast@@QAE@ABV0@@Z
-??0bad_cast@@QAE@PBD@Z
-??0bad_typeid@@QAE@ABV0@@Z
-??0bad_typeid@@QAE@PBD@Z
-??0exception@@QAE@ABQBD@Z
-??0exception@@QAE@ABQBDH@Z
-??0exception@@QAE@ABV0@@Z
-??0exception@@QAE@XZ
-??1__non_rtti_object@@UAE@XZ
-??1bad_cast@@UAE@XZ
-??1bad_typeid@@UAE@XZ
-??1exception@@UAE@XZ
-??1type_info@@UAE@XZ
-??2@YAPAXI@Z
-??2@YAPAXIHPBDH@Z
-??3@YAXPAX@Z
-??4__non_rtti_object@@QAEAAV0@ABV0@@Z
-??4bad_cast@@QAEAAV0@ABV0@@Z
-??4bad_typeid@@QAEAAV0@ABV0@@Z
-??4exception@@QAEAAV0@ABV0@@Z
-??8type_info@@QBEHABV0@@Z
-??9type_info@@QBEHABV0@@Z
+??0bad_cast@@QEAA@AEBQEBD@Z
+??0bad_cast@@QEAA@AEBV0@@Z
+??0bad_cast@@QEAA@PEBD@Z
+??0bad_typeid@@QEAA@AEBV0@@Z
+??0bad_typeid@@QEAA@PEBD@Z
+??0exception@@QEAA@AEBQEBD@Z
+??0exception@@QEAA@AEBQEBDH@Z
+??0exception@@QEAA@AEBV0@@Z
+??0exception@@QEAA@XZ
+??1__non_rtti_object@@UEAA@XZ
+??1bad_cast@@UEAA@XZ
+??1bad_typeid@@UEAA@XZ
+??1exception@@UEAA@XZ
+??1type_info@@UEAA@XZ
+??2@YAPEAX_K@Z
+??2@YAPEAX_KHPEBDH@Z
+??3@YAXPEAX@Z
+??4__non_rtti_object@@QEAAAEAV0@AEBV0@@Z
+??4bad_cast@@QEAAAEAV0@AEBV0@@Z
+??4bad_typeid@@QEAAAEAV0@AEBV0@@Z
+??4exception@@QEAAAEAV0@AEBV0@@Z
+??8type_info@@QEBAHAEBV0@@Z
+??9type_info@@QEBAHAEBV0@@Z
??_7__non_rtti_object@@6B@
??_7bad_cast@@6B@
??_7bad_typeid@@6B@
??_7exception@@6B@
-??_E__non_rtti_object@@UAEPAXI@Z
-??_Ebad_cast@@UAEPAXI@Z
-??_Ebad_typeid@@UAEPAXI@Z
-??_Eexception@@UAEPAXI@Z
-??_Fbad_cast@@QAEXXZ
-??_Fbad_typeid@@QAEXXZ
-??_G__non_rtti_object@@UAEPAXI@Z
-??_Gbad_cast@@UAEPAXI@Z
-??_Gbad_typeid@@UAEPAXI@Z
-??_Gexception@@UAEPAXI@Z
-??_U@YAPAXI@Z
-??_U@YAPAXIHPBDH@Z
-??_V@YAXPAX@Z
-?_query_new_handler@@YAP6AHI@ZXZ
+??_Fbad_cast@@QEAAXXZ
+??_Fbad_typeid@@QEAAXXZ
+??_U@YAPEAX_K@Z
+??_U@YAPEAX_KHPEBDH@Z
+??_V@YAXPEAX@Z
+?_query_new_handler@@YAP6AH_K@ZXZ
?_query_new_mode@@YAHXZ
-?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z
+?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z
?_set_new_mode@@YAHH@Z
-?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z
-?before@type_info@@QBEHABV1@@Z
-?name@type_info@@QBEPBDXZ
-?raw_name@type_info@@QBEPBDXZ
+?_set_se_translator@@YAP6AXIPEAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z
+?before@type_info@@QEBAHAEBV1@@Z
+?name@type_info@@QEBAPEBDXZ
+?raw_name@type_info@@QEBAPEBDXZ
?set_new_handler@@YAP6AXXZP6AXXZ@Z
?set_terminate@@YAP6AXXZP6AXXZ@Z
?set_unexpected@@YAP6AXXZP6AXXZ@Z
?terminate@@YAXXZ
?unexpected@@YAXXZ
-?what@exception@@UBEPBDXZ
-_CIacos
-_CIasin
-_CIatan
-_CIatan2
-_CIcos
-_CIcosh
-_CIexp
-_CIfmod
-_CIlog
-_CIlog10
-_CIpow
-_CIsin
-_CIsinh
-_CIsqrt
-_CItan
-_CItanh
+?what@exception@@UEBAPEBDXZ
_CrtCheckMemory
_CrtDbgBreak
_CrtDbgReport
@@ -101,27 +78,33 @@ _CrtSetReportHook
_CrtSetReportHook2
_CrtSetReportMode
_CxxThrowException
-_EH_prolog
_Getdays
_Getmonths
_Gettnames
_HUGE
_Strftime
+_W_Getdays
+_W_Getmonths
+_W_Gettnames
+_Wcsftime
_XcptFilter
+__AdjustPointer
+__C_specific_handler
__CppXcptFilter
-__CxxCallUnwindDelDtor
-__CxxCallUnwindDtor
-__CxxCallUnwindVecDtor
-__CxxDetectRethrow
-__CxxExceptionFilter
__CxxFrameHandler
__CxxFrameHandler2
__CxxFrameHandler3
-__CxxLongjmpUnwind
-__CxxQueryExceptionSize
-__CxxRegisterExceptionObject
-__CxxUnregisterExceptionObject
__DestructExceptionObject
+__ExceptionPtrAssign
+__ExceptionPtrCompare
+__ExceptionPtrCopy
+__ExceptionPtrCopyException
+__ExceptionPtrCreate
+__ExceptionPtrCurrentException
+__ExceptionPtrDestroy
+__ExceptionPtrRethrow
+__ExceptionPtrSwap
+__ExceptionPtrToBool
__RTCastToVoid
__RTDynamicCast
__RTtypeid
@@ -156,57 +139,7 @@ __lc_codepage
__lc_collate_cp
__lc_handle
__lconv_init
-__libm_sse2_acos
-__libm_sse2_acosf
-__libm_sse2_asin
-__libm_sse2_asinf
-__libm_sse2_atan
-__libm_sse2_atan2
-__libm_sse2_atanf
-__libm_sse2_cos
-__libm_sse2_cosf
-__libm_sse2_exp
-__libm_sse2_expf
-__libm_sse2_log
-__libm_sse2_log10
-__libm_sse2_log10f
-__libm_sse2_logf
-__libm_sse2_pow
-__libm_sse2_powf
-__libm_sse2_sin
-__libm_sse2_sinf
-__libm_sse2_tan
-__libm_sse2_tanf
__mb_cur_max
-__p___argc
-__p___argv
-__p___initenv
-__p___mb_cur_max
-__p___wargv
-__p___winitenv
-__p__acmdln
-__p__amblksiz
-__p__commode
-__p__daylight
-__p__dstbias
-__p__environ
-__p__fileinfo
-__p__fmode
-__p__iob
-__p__mbcasemap
-__p__mbctype
-__p__osver
-__p__pctype
-__p__pgmptr
-__p__pwctype
-__p__timezone
-__p__tzname
-__p__wcmdln
-__p__wenviron
-__p__winmajor
-__p__winminor
-__p__winver
-__p__wpgmptr
__pctype_func
__pioinfo
__pwctype_func
@@ -228,25 +161,10 @@ __wcserror_s
__wcsncnt
__wgetmainargs
__winitenv
-_abnormal_termination
_abs64
_access
_access_s
_acmdln
-_adj_fdiv_m16i
-_adj_fdiv_m32
-_adj_fdiv_m32i
-_adj_fdiv_m64
-_adj_fdiv_r
-_adj_fdivr_m16i
-_adj_fdivr_m32
-_adj_fdivr_m32i
-_adj_fdivr_m64
-_adj_fpatan
-_adj_fprem
-_adj_fprem1
-_adj_fptan
-_adjust_fdiv
_aexit_rtn
_aligned_free
_aligned_free_dbg
@@ -285,7 +203,7 @@ _cgetws_s
_chdir
_chdrive
_chgsign
-_chkesp
+_chgsignf
_chmod
_chsize
_chsize_s
@@ -299,6 +217,7 @@ _control87
_controlfp
_controlfp_s
_copysign
+_copysignf
_cprintf
_cprintf_l
_cprintf_p
@@ -308,6 +227,7 @@ _cprintf_s_l
_cputs
_cputws
_creat
+_create_locale
_crtAssertBusy
_crtBreakAlloc
_crtDbgFlag
@@ -344,9 +264,6 @@ _endthreadex
_environ
_eof
_errno
-_except_handler2
-_except_handler3
-_except_handler4_common
_execl
_execle
_execlp
@@ -377,11 +294,12 @@ _findnext
_findnext64
_findnexti64
_finite
+_finitef
_flsbuf
_flushall
_fmode
_fpclass
-_fpieee_flt
+_fpclassf
_fpreset
_fprintf_l
_fprintf_p
@@ -390,6 +308,7 @@ _fprintf_s_l
_fputchar
_fputwchar
_free_dbg
+_free_locale
_freea
_freea_s
_fscanf_l
@@ -404,10 +323,6 @@ _ftime32
_ftime32_s
_ftime64
_ftime64_s
-_ftol
-_ftol2
-_ftol2_sse
-_ftol2_sse_excpt
_fullpath
_fullpath_dbg
_futime
@@ -421,6 +336,7 @@ _fwscanf_l
_fwscanf_s_l
_gcvt
_gcvt_s
+_get_current_locale
_get_doserrno
_get_environ
_get_errno
@@ -443,7 +359,6 @@ _getche
_getcwd
_getdcwd
_getdiskfree
-_getdllprocaddr
_getdrive
_getdrives
_getmaxstdio
@@ -454,27 +369,22 @@ _getw
_getwch
_getwche
_getws
-_global_unwind2
_gmtime32
_gmtime32_s
_gmtime64
_gmtime64_s
-_heapadd
_heapchk
_heapmin
_heapset
-_heapused
_heapwalk
_hypot
+_hypotf
_i64toa
_i64toa_s
_i64tow
_i64tow_s
_initterm
_initterm_e
-_inp
-_inpd
-_inpw
_invalid_parameter
_iob
_isalnum_l
@@ -546,6 +456,7 @@ _ismbslead_l
_ismbstrail
_ismbstrail_l
_isnan
+_isnanf
_isprint_l
_isspace_l
_isupper_l
@@ -572,9 +483,7 @@ _jn
_kbhit
_lfind
_lfind_s
-_loaddll
-_local_unwind2
-_local_unwind4
+_local_unwind
_localtime32
_localtime32_s
_localtime64
@@ -582,7 +491,7 @@ _localtime64_s
_lock
_locking
_logb
-_longjmpex
+_logbf
_lrotl
_lrotr
_lsearch
@@ -746,16 +655,14 @@ _mktemp_s
_mktime32
_mktime64
_msize
-_msize_debug
+_msize_dbg
_nextafter
+_nextafterf
_onexit
_open
_open_osfhandle
_osplatform
_osver
-_outp
-_outpd
-_outpw
_pclose
_pctype
_pgmptr
@@ -782,11 +689,8 @@ _rotl
_rotl64
_rotr
_rotr64
-_safe_fdiv
-_safe_fdivr
-_safe_fprem
-_safe_fprem1
_scalb
+_scalbf
_scanf_l
_scanf_s_l
_scprintf
@@ -797,9 +701,6 @@ _scwprintf_l
_scwprintf_p_l
_searchenv
_searchenv_s
-_seh_longjmp_unwind
-_seh_longjmp_unwind4
-_set_SSE2_enable
_set_controlfp
_set_doserrno
_set_errno
@@ -810,7 +711,7 @@ _set_output_format
_set_sbh_threshold
_seterrormode
_setjmp
-_setjmp3
+_setjmpex
_setmaxstdio
_setmbcp
_setmode
@@ -934,7 +835,6 @@ _umask_s
_ungetch
_ungetwch
_unlink
-_unloaddll
_unlock
_utime
_utime32
@@ -1027,6 +927,7 @@ _wcsnset_s
_wcsrev
_wcsset
_wcsset_s
+_wcstod_l
_wcstoi64
_wcstoi64_l
_wcstol_l
@@ -1146,11 +1047,15 @@ _yn
abort
abs
acos
+acosf
asctime
asctime_s
asin
+asinf
atan
atan2
+atan2f
+atanf
atexit
atof
atoi
@@ -1160,16 +1065,20 @@ bsearch_s
btowc
calloc
ceil
+ceilf
clearerr
clearerr_s
clock
cos
+cosf
cosh
+coshf
ctime
difftime
div
exit
exp
+expf
fabs
fclose
feof
@@ -1181,7 +1090,9 @@ fgets
fgetwc
fgetws
floor
+floorf
fmod
+fmodf
fopen
fopen_s
fprintf
@@ -1246,6 +1157,8 @@ localeconv
localtime
log
log10
+log10f
+logf
longjmp
malloc
mblen
@@ -1266,8 +1179,10 @@ memmove_s
memset
mktime
modf
+modff
perror
pow
+powf
printf
printf_s
putc
@@ -1287,14 +1202,18 @@ rewind
scanf
scanf_s
setbuf
+setjmp
setlocale
setvbuf
signal
sin
+sinf
sinh
+sinhf
sprintf
sprintf_s
sqrt
+sqrtf
srand
sscanf
sscanf_s
@@ -1332,7 +1251,9 @@ swscanf
swscanf_s
system
tan
+tanf
tanh
+tanhf
time
tmpfile
tmpfile_s
diff --git a/win32/lib/wincrt1.c b/win32/lib/wincrt1.c
index ce3a63f..d74a0cf 100644
--- a/win32/lib/wincrt1.c
+++ b/win32/lib/wincrt1.c
@@ -26,11 +26,14 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
typedef struct { int newmode; } _startupinfo;
int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
+#include "crtinit.c"
+
static int go_winmain(TCHAR *arg1)
{
STARTUPINFO si;
_TCHAR *szCmd, *p;
int fShow;
+ int retval;
GetStartupInfo(&si);
if (si.dwFlags & STARTF_USESHOWWINDOW)
@@ -48,13 +51,21 @@ static int go_winmain(TCHAR *arg1)
#if defined __i386__ || defined __x86_64__
_controlfp(0x10000, 0x30000);
#endif
- return _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
+ run_ctors(__argc, __targv, _tenviron);
+ retval = _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
+ run_dtors();
+ return retval;
+}
+
+static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)
+{
+ return _XcptFilter(ex->ExceptionRecord->ExceptionCode, ex);
}
int _twinstart(void)
{
- __TRY__
_startupinfo start_info_con = {0};
+ SetUnhandledExceptionFilter(catch_sig);
__set_app_type(__GUI_APP);
__tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info_con);
exit(go_winmain(__argc > 1 ? __targv[1] : NULL));
diff --git a/win32/lib/ws2_32.def b/win32/lib/ws2_32.def
new file mode 100644
index 0000000..b618266
--- /dev/null
+++ b/win32/lib/ws2_32.def
@@ -0,0 +1,198 @@
+LIBRARY ws2_32.dll
+
+EXPORTS
+FreeAddrInfoEx
+FreeAddrInfoExW
+FreeAddrInfoW
+GetAddrInfoExA
+GetAddrInfoExCancel
+GetAddrInfoExOverlappedResult
+GetAddrInfoExW
+GetAddrInfoW
+GetHostNameW
+GetNameInfoW
+InetNtopW
+InetPtonW
+SetAddrInfoExA
+SetAddrInfoExW
+WEP
+WPUCompleteOverlappedRequest
+WPUGetProviderPathEx
+WSAAccept
+WSAAddressToStringA
+WSAAddressToStringW
+WSAAdvertiseProvider
+WSAAsyncGetHostByAddr
+WSAAsyncGetHostByName
+WSAAsyncGetProtoByName
+WSAAsyncGetProtoByNumber
+WSAAsyncGetServByName
+WSAAsyncGetServByPort
+WSAAsyncSelect
+WSACancelAsyncRequest
+WSACancelBlockingCall
+WSACleanup
+WSACloseEvent
+WSAConnect
+WSAConnectByList
+WSAConnectByNameA
+WSAConnectByNameW
+WSACreateEvent
+WSADuplicateSocketA
+WSADuplicateSocketW
+WSAEnumNameSpaceProvidersA
+WSAEnumNameSpaceProvidersExA
+WSAEnumNameSpaceProvidersExW
+WSAEnumNameSpaceProvidersW
+WSAEnumNetworkEvents
+WSAEnumProtocolsA
+WSAEnumProtocolsW
+WSAEventSelect
+WSAGetLastError
+WSAGetOverlappedResult
+WSAGetQOSByName
+WSAGetServiceClassInfoA
+WSAGetServiceClassInfoW
+WSAGetServiceClassNameByClassIdA
+WSAGetServiceClassNameByClassIdW
+WSAHtonl
+WSAHtons
+WSAInstallServiceClassA
+WSAInstallServiceClassW
+WSAIoctl
+WSAIsBlocking
+WSAJoinLeaf
+WSALookupServiceBeginA
+WSALookupServiceBeginW
+WSALookupServiceEnd
+WSALookupServiceNextA
+WSALookupServiceNextW
+WSANSPIoctl
+WSANtohl
+WSANtohs
+WSAPoll
+WSAProviderCompleteAsyncCall
+WSAProviderConfigChange
+WSARecv
+WSARecvDisconnect
+WSARecvFrom
+WSARemoveServiceClass
+WSAResetEvent
+WSASend
+WSASendDisconnect
+WSASendMsg
+WSASendTo
+WSASetBlockingHook
+WSASetEvent
+WSASetLastError
+WSASetServiceA
+WSASetServiceW
+WSASocketA
+WSASocketW
+WSAStartup
+WSAStringToAddressA
+WSAStringToAddressW
+WSAUnadvertiseProvider
+WSAUnhookBlockingHook
+WSAWaitForMultipleEvents
+WSApSetPostRoutine
+WSCDeinstallProvider
+WSCDeinstallProvider32
+WSCDeinstallProviderEx
+WSCEnableNSProvider
+WSCEnableNSProvider32
+WSCEnumNameSpaceProviders32
+WSCEnumNameSpaceProvidersEx32
+WSCEnumProtocols
+WSCEnumProtocols32
+WSCEnumProtocolsEx
+WSCGetApplicationCategory
+WSCGetApplicationCategoryEx
+WSCGetProviderInfo
+WSCGetProviderInfo32
+WSCGetProviderPath
+WSCGetProviderPath32
+WSCInstallNameSpace
+WSCInstallNameSpace32
+WSCInstallNameSpaceEx
+WSCInstallNameSpaceEx2
+WSCInstallNameSpaceEx32
+WSCInstallProvider
+WSCInstallProvider64_32
+WSCInstallProviderAndChains64_32
+WSCInstallProviderEx
+WSCSetApplicationCategory
+WSCSetApplicationCategoryEx
+WSCSetProviderInfo
+WSCSetProviderInfo32
+WSCUnInstallNameSpace
+WSCUnInstallNameSpace32
+WSCUnInstallNameSpaceEx2
+WSCUpdateProvider
+WSCUpdateProvider32
+WSCUpdateProviderEx
+WSCWriteNameSpaceOrder
+WSCWriteNameSpaceOrder32
+WSCWriteProviderOrder
+WSCWriteProviderOrder32
+WSCWriteProviderOrderEx
+WahCloseApcHelper
+WahCloseHandleHelper
+WahCloseNotificationHandleHelper
+WahCloseSocketHandle
+WahCloseThread
+WahCompleteRequest
+WahCreateHandleContextTable
+WahCreateNotificationHandle
+WahCreateSocketHandle
+WahDestroyHandleContextTable
+WahDisableNonIFSHandleSupport
+WahEnableNonIFSHandleSupport
+WahEnumerateHandleContexts
+WahInsertHandleContext
+WahNotifyAllProcesses
+WahOpenApcHelper
+WahOpenCurrentThread
+WahOpenHandleHelper
+WahOpenNotificationHandleHelper
+WahQueueUserApc
+WahReferenceContextByHandle
+WahRemoveHandleContext
+WahWaitForNotification
+WahWriteLSPEvent
+__WSAFDIsSet
+accept
+bind
+closesocket
+connect
+freeaddrinfo
+getaddrinfo
+gethostbyaddr
+gethostbyname
+gethostname
+getnameinfo
+getpeername
+getprotobyname
+getprotobynumber
+getservbyname
+getservbyport
+getsockname
+getsockopt
+htonl
+htons
+inet_addr
+inet_ntoa
+inet_ntop
+inet_pton
+ioctlsocket
+listen
+ntohl
+ntohs
+recv
+recvfrom
+select
+send
+sendto
+setsockopt
+shutdown
+socket
diff --git a/win32/tcc-win32.txt b/win32/tcc-win32.txt
index ab73007..751a8e0 100644
--- a/win32/tcc-win32.txt
+++ b/win32/tcc-win32.txt
@@ -1,168 +1,168 @@
-
- TinyCC
- ======
-
- This file contains specific information for usage of TinyCC
- under MS-Windows. See tcc-doc.html to have all the features.
-
-
- Installation from the binary ZIP package:
- -----------------------------------------
- Unzip the package to a directory of your choice.
-
-
- Set the system PATH:
- --------------------
- To be able to invoke the compiler from everywhere on your computer by
- just typing "tcc", please add the directory containing tcc.exe to your
- system PATH.
-
-
- Include and library search paths
- --------------------------------
- On windows, the standard "include" and "lib" directories are searched
- relatively from the location of the executables (tcc.exe, libtcc.dll).
-
-
- Examples:
- ---------
- Open a console window (DOS box) and 'cd' to the examples directory.
-
- For the 'Fibonacci' example type:
-
- tcc fib.c
-
- For the 'Hello Windows' GUI example type:
-
- tcc hello_win.c
-
- For the 'Hello DLL' example type
-
- tcc -shared dll.c
- tcc -impdef dll.dll (optional)
- tcc hello_dll.c dll.def
-
-
- Using libtcc as JIT compiler in your program
- --------------------------------------------
- Check out the 'libtcc_test' example:
-
- - Running it from source:
- tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c
-
- - Compiling with TCC:
- tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def
-
- - Compiling with MinGW:
- gcc examples/libtcc_test.c -I libtcc libtcc.dll -o libtcc_test.exe
-
- - Compiling with MSVC:
- lib /def:libtcc\libtcc.def /out:libtcc.lib
- cl /MD examples/libtcc_test.c -I libtcc libtcc.lib
-
-
- Import Definition Files:
- ------------------------
- To link with Windows system DLLs, TCC uses import definition
- files (.def) instead of libraries.
-
- The now built-in 'tiny_impdef' program may be used to make
- additional .def files for any DLL. For example
-
- tcc -impdef [-v] opengl32.dll [-o opengl32.def]
-
- Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at
- the TCC commandline to link a program that uses opengl32.dll.
-
-
- Header Files:
- -------------
- The system header files (except _mingw.h) are from the MinGW
- distribution:
-
- http://www.mingw.org/
-
- From the windows headers, only a minimal set is included. If you need
- more, get MinGW's "w32api" package. Extract the files from "include"
- into your "tcc/include/winapi" directory.
-
-
- Resource Files:
- ---------------
- TCC can link windows resources in coff format as generated by MinGW's
- windres.exe. For example:
-
- windres -O coff app.rc -o appres.o
- tcc app.c appres.o -o app.exe
-
-
- Tiny Libmaker:
- --------------
- The now built-in tiny_libmaker tool by Timovj Lahde can be used as
- 'ar' replacement to make a library from several object files:
-
- tcc -ar [rcsv] library objectfiles ...
-
-
- Compilation from source:
- ------------------------
- * You can use the MinGW and MSYS tools available at
- http://www.mingw.org
- http://www.mingw-w64.org
- http://www.msys2.org
-
- Untar the TCC archive and type in the MSYS shell:
- ./configure [--prefix installpath]
- make
- make install
-
- The default install location is c:\Program Files\tcc
-
- Cygwin can be used too with its mingw cross-compiler installed:
- ./configure --cross-prefix=i686-w64-mingw32-
- (the prefix may vary)
-
- * Alternatively you can compile TCC with just GCC from MinGW using
- > build-tcc.bat (from the win32 directory)
-
- Also MSVC can be used with the "VSTools Developer Command Prompt":
- > build-tcc.bat -c cl
-
- or with an existing tcc (needs to be in a different directory)
- > build-tcc.bat -c some-tcc-dir\tcc.exe
-
- Also you can copy/install everything into another directory:
- > build-tcc.bat -i <dir>
-
- Limitations:
- ------------
- - On the object file level, currently TCC supports only the ELF format,
- not COFF as used by MinGW and MSVC. It is not possible to exchange
- object files or libraries between TCC and these compilers.
-
- However libraries for TCC from objects by TCC can be made using
- tcc -ar lib.a files.o ,,,
-
- - No leading underscore is generated in the ELF symbols.
-
- Documentation and License:
- --------------------------
- TCC is distributed under the GNU Lesser General Public License. (See
- COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)
-
- TinyCC homepage is at:
-
- http://fabrice.bellard.free.fr/tcc/
-
-
- WinAPI Help and 3rd-party tools:
- --------------------------------
- The Windows API documentation (Win95) in a single .hlp file is
- available on the lcc-win32 site as "win32hlp.exe" or from other
- locations as "win32hlp_big.zip".
-
- A nice RAD tool to create windows resources (dialog boxes etc.) is
- "ResEd", available at the RadASM website.
-
-
- --- grischka
+
+ TinyCC
+ ======
+
+ This file contains specific information for usage of TinyCC
+ under MS-Windows. See tcc-doc.html to have all the features.
+
+
+ Installation from the binary ZIP package:
+ -----------------------------------------
+ Unzip the package to a directory of your choice.
+
+
+ Set the system PATH:
+ --------------------
+ To be able to invoke the compiler from everywhere on your computer by
+ just typing "tcc", please add the directory containing tcc.exe to your
+ system PATH.
+
+
+ Include and library search paths
+ --------------------------------
+ On windows, the standard "include" and "lib" directories are searched
+ relatively from the location of the executables (tcc.exe, libtcc.dll).
+
+
+ Examples:
+ ---------
+ Open a console window (DOS box) and 'cd' to the examples directory.
+
+ For the 'Fibonacci' example type:
+
+ tcc fib.c
+
+ For the 'Hello Windows' GUI example type:
+
+ tcc hello_win.c
+
+ For the 'Hello DLL' example type
+
+ tcc -shared dll.c
+ tcc -impdef dll.dll (optional)
+ tcc hello_dll.c dll.def
+
+
+ Using libtcc as JIT compiler in your program
+ --------------------------------------------
+ Check out the 'libtcc_test' example:
+
+ - Running it from source:
+ tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c
+
+ - Compiling with TCC:
+ tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def
+
+ - Compiling with MinGW:
+ gcc examples/libtcc_test.c -I libtcc libtcc.dll -o libtcc_test.exe
+
+ - Compiling with MSVC:
+ lib /def:libtcc\libtcc.def /out:libtcc.lib
+ cl /MD examples/libtcc_test.c -I libtcc libtcc.lib
+
+
+ Import Definition Files:
+ ------------------------
+ To link with Windows system DLLs, TCC uses import definition
+ files (.def) instead of libraries.
+
+ The now built-in 'tiny_impdef' program may be used to make
+ additional .def files for any DLL. For example
+
+ tcc -impdef [-v] opengl32.dll [-o opengl32.def]
+
+ Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at
+ the TCC commandline to link a program that uses opengl32.dll.
+
+
+ Header Files:
+ -------------
+ The system header files (except _mingw.h) are from the MinGW
+ distribution:
+
+ http://www.mingw.org/
+
+ From the windows headers, only a minimal set is included. If you need
+ more, get MinGW's "w32api" package. Extract the files from "include"
+ into your "tcc/include/winapi" directory.
+
+
+ Resource Files:
+ ---------------
+ TCC can link windows resources in coff format as generated by MinGW's
+ windres.exe. For example:
+
+ windres -O coff app.rc -o appres.o
+ tcc app.c appres.o -o app.exe
+
+
+ Tiny Libmaker:
+ --------------
+ The now built-in tiny_libmaker tool by Timovj Lahde can be used as
+ 'ar' replacement to make a library from several object files:
+
+ tcc -ar [rcsv] library objectfiles ...
+
+
+ Compilation from source:
+ ------------------------
+ * You can use the MinGW and MSYS tools available at
+ http://www.mingw.org
+ http://www.mingw-w64.org
+ http://www.msys2.org
+
+ Untar the TCC archive and type in the MSYS shell:
+ ./configure [--prefix installpath]
+ make
+ make install
+
+ The default install location is c:\Program Files\tcc
+
+ Cygwin can be used too with its mingw cross-compiler installed:
+ ./configure --cross-prefix=i686-w64-mingw32-
+ (the prefix may vary)
+
+ * Alternatively you can compile TCC with just GCC from MinGW using
+ > build-tcc.bat (from the win32 directory)
+
+ Also MSVC can be used with the "VSTools Developer Command Prompt":
+ > build-tcc.bat -c cl
+
+ or with an existing tcc (needs to be in a different directory)
+ > build-tcc.bat -c some-tcc-dir\tcc.exe
+
+ Also you can copy/install everything into another directory:
+ > build-tcc.bat -i <dir>
+
+ Limitations:
+ ------------
+ - On the object file level, currently TCC supports only the ELF format,
+ not COFF as used by MinGW and MSVC. It is not possible to exchange
+ object files or libraries between TCC and these compilers.
+
+ However libraries for TCC from objects by TCC can be made using
+ tcc -ar lib.a files.o ,,,
+
+ - No leading underscore is generated in the ELF symbols.
+
+ Documentation and License:
+ --------------------------
+ TCC is distributed under the GNU Lesser General Public License. (See
+ COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)
+
+ TinyCC homepage is at:
+
+ http://fabrice.bellard.free.fr/tcc/
+
+
+ WinAPI Help and 3rd-party tools:
+ --------------------------------
+ The Windows API documentation (Win95) in a single .hlp file is
+ available on the lcc-win32 site as "win32hlp.exe" or from other
+ locations as "win32hlp_big.zip".
+
+ A nice RAD tool to create windows resources (dialog boxes etc.) is
+ "ResEd", available at the RadASM website.
+
+
+ --- grischka
diff --git a/win32/tccwin32.sh b/win32/tccwin32.sh
new file mode 100644
index 0000000..e68f663
--- /dev/null
+++ b/win32/tccwin32.sh
@@ -0,0 +1,8 @@
+R_=$(pwd)
+
+RTCC=$(cd `dirname $0`/../; pwd)
+echo RTCC=$RTCC
+
+$RTCC/i386-win32-tcc -I $RTCC/win32/include -I $RTCC/win32/include/winapi -I $RTCC/include -L $RTCC/win32/lib -L $RTCC $*
+
+cd $R_
diff --git a/win32/tccwin64.sh b/win32/tccwin64.sh
new file mode 100644
index 0000000..671685f
--- /dev/null
+++ b/win32/tccwin64.sh
@@ -0,0 +1,8 @@
+R_=$(pwd)
+
+RTCC=$(cd `dirname $0`/../; pwd)
+echo RTCC=$RTCC
+
+$RTCC/x86_64-win32-tcc -I $RTCC/win32/include -I $RTCC/win32/include/winapi -I $RTCC/include -L $RTCC/win32/lib -L $RTCC $*
+
+cd $R_
diff --git a/win32/tccwin_build.sh b/win32/tccwin_build.sh
new file mode 100644
index 0000000..a076e89
--- /dev/null
+++ b/win32/tccwin_build.sh
@@ -0,0 +1,39 @@
+# please refer to win32/tcc-win32.txt for more detail
+# this script shows:
+# * build tcc (with sys cc) and then tcc itself
+# * to build cross i386-win32-tcc and x86_64-win32-tcc at osx/lnx
+# * to build hello_win.c 32/64 with tccwin*.sh
+
+R_=$(pwd)
+#RTCC=$(cd `dirname $0`; pwd)
+RTCC=$(cd `dirname $0`/../; pwd)
+cd $RTCC
+echo RTCC=$RTCC
+
+make clean
+./configure
+make tcc
+./configure --cc=./tcc
+make tcc
+#make cross
+make cross-i386-win32
+make cross-x86_64-win32
+
+cd $R_
+pwd
+
+echo RTCC=$RTCC
+
+sh $RTCC/win32/tccwin32.sh $RTCC/win32/examples/hello_win.c -o $RTCC/win32/examples/hello_win32.exe
+sh $RTCC/win32/tccwin64.sh $RTCC/win32/examples/hello_win.c -o $RTCC/win32/examples/hello_win64.exe
+ls -al $RTCC/win32/examples/hello_win*.exe
+
+sh $RTCC/win32/tccwin32.sh $RTCC/tcc.c -DTCC_LIBTCC1="\"i386-win32-libtcc1.a\"" -o $RTCC/tcc32.exe
+sh $RTCC/win32/tccwin64.sh $RTCC/tcc.c -DTCC_LIBTCC1="\"x86_64-win32-libtcc1.a\"" -o $RTCC/tcc64.exe
+ls -al $RTCC/tcc*.exe
+
+#sh $RTCC/win32/tccwin32.sh $RTCC/libtcc.c -DTCC_LIBTCC1="\"i386-win32-libtcc1.a\"" -DLIBTCC_AS_DLL -DTCC_TARGET_PE -DTCC_TARGET_I386 -o $RTCC/libtcc32.dll -shared
+#sh $RTCC/win32/tccwin64.sh $RTCC/libtcc.c -DTCC_LIBTCC1="\"x86_64-win32-libtcc1.a\"" -DLIBTCC_AS_DLL -DTCC_TARGET_PE -DTCC_TARGET_X86_64 -shared -o $RTCC/libtcc64.dll
+sh $RTCC/win32/tccwin32.sh $RTCC/libtcc.c -DLIBTCC_AS_DLL -shared -o $RTCC/libtcc32.dll
+sh $RTCC/win32/tccwin64.sh $RTCC/libtcc.c -DLIBTCC_AS_DLL -shared -o $RTCC/libtcc64.dll
+ls -al $RTCC/libtcc*.dll
diff --git a/x86_64-gen.c b/x86_64-gen.c
index e33a38a..e68ef94 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -49,9 +49,9 @@
#define RC_XMM6 0x40000
#define RC_XMM7 0x80000
#define RC_IRET RC_RAX /* function return: integer register */
-#define RC_LRET RC_RDX /* function return: second integer register */
+#define RC_IRE2 RC_RDX /* function return: second integer register */
#define RC_FRET RC_XMM0 /* function return: float register */
-#define RC_QRET RC_XMM1 /* function return: second float register */
+#define RC_FRE2 RC_XMM1 /* function return: second float register */
/* pretty names for the registers */
enum {
@@ -86,9 +86,9 @@ enum {
/* return registers for function */
#define REG_IRET TREG_RAX /* single word int return register */
-#define REG_LRET TREG_RDX /* second word return register (for long long) */
+#define REG_IRE2 TREG_RDX /* second word return register (for long long) */
#define REG_FRET TREG_XMM0 /* float return register */
-#define REG_QRET TREG_XMM1 /* second float return register */
+#define REG_FRE2 TREG_XMM1 /* second float return register */
/* defined if function parameters must be evaluated in reverse order */
#define INVERT_FUNC_PARAMS
@@ -102,9 +102,13 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 16
+/* define if return values need to be extended explicitely
+ at caller side (for interfacing with non-TCC compilers) */
+#define PROMOTE_RET
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
+#define USING_GLOBALS
#include "tcc.h"
#include <assert.h>
@@ -142,6 +146,16 @@ ST_DATA const int reg_classes[NB_REGS] = {
static unsigned long func_sub_sp_offset;
static int func_ret_sub;
+#if defined(CONFIG_TCC_BCHECK)
+static addr_t func_bound_offset;
+static unsigned long func_bound_ind;
+ST_DATA int func_bound_add_epilog;
+#endif
+
+#ifdef TCC_TARGET_PE
+static int func_scratch, func_alloca;
+#endif
+
/* XXX: make it faster ? */
ST_FUNC void g(int c)
{
@@ -206,17 +220,11 @@ ST_FUNC void gsym_addr(int t, int a)
while (t) {
unsigned char *ptr = cur_text_section->data + t;
uint32_t n = read32le(ptr); /* next value */
- write32le(ptr, a - t - 4);
+ write32le(ptr, a < 0 ? -a : a - t - 4);
t = n;
}
}
-void gsym(int t)
-{
- gsym_addr(t, ind);
-}
-
-
static int is64_type(int t)
{
return ((t & VT_BTYPE) == VT_PTR ||
@@ -433,6 +441,9 @@ void load(int r, SValue *sv)
b = 0xbf0f; /* movswl */
} else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
b = 0xb70f; /* movzwl */
+ } else if ((ft & VT_TYPE) == (VT_VOID)) {
+ /* Can happen with zero size structs */
+ return;
} else {
assert(((ft & VT_BTYPE) == VT_INT)
|| ((ft & VT_BTYPE) == VT_LLONG)
@@ -477,22 +488,22 @@ void load(int r, SValue *sv)
orex(1,0,r,0x8d); /* lea xxx(%ebp), r */
gen_modrm(r, VT_LOCAL, sv->sym, fc);
} else if (v == VT_CMP) {
- orex(0,r,0,0);
- if ((fc & ~0x100) != TOK_NE)
- oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */
- else
- oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */
if (fc & 0x100)
{
+ v = vtop->cmp_r;
+ fc &= ~0x100;
/* This was a float compare. If the parity bit is
set the result was unordered, meaning false for everything
except TOK_NE, and true for TOK_NE. */
- fc &= ~0x100;
- o(0x037a + (REX_BASE(r) << 8));
- }
+ orex(0, r, 0, 0xb0 + REG_VALUE(r)); /* mov $0/1,%al */
+ g(v ^ fc ^ (v == TOK_NE));
+ o(0x037a + (REX_BASE(r) << 8));
+ }
orex(0,r,0, 0x0f); /* setxx %br */
o(fc);
o(0xc0 + REG_VALUE(r));
+ orex(0,r,0, 0x0f);
+ o(0xc0b6 + REG_VALUE(r) * 0x900); /* movzbl %al, %eax */
} else if (v == VT_JMP || v == VT_JMPI) {
t = v & 1;
orex(0,r,0,0);
@@ -529,7 +540,7 @@ void load(int r, SValue *sv)
o(0xf024);
o(0xf02444dd); /* fldl -0x10(%rsp) */
} else {
- orex(1,r,v, 0x89);
+ orex(is64_type(ft), r, v, 0x89);
o(0xc0 + REG_VALUE(r) + REG_VALUE(v) * 8); /* mov v, r */
}
}
@@ -603,16 +614,13 @@ void store(int r, SValue *v)
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
gen_modrm64(op64, r, v->r, v->sym, fc);
} else if (fr != r) {
- /* XXX: don't we really come here? */
- abort();
+ orex(1, fr, r, op64);
o(0xc0 + fr + r * 8); /* mov r, fr */
}
} else {
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
gen_modrm(r, v->r, v->sym, fc);
} else if (fr != r) {
- /* XXX: don't we really come here? */
- abort();
o(0xc0 + fr + r * 8); /* mov r, fr */
}
}
@@ -623,20 +631,13 @@ static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
- ((vtop->r & VT_SYM) || (vtop->c.i-4) == (int)(vtop->c.i-4))) {
- /* constant case */
- if (vtop->r & VT_SYM) {
- /* relocation case */
+ ((vtop->r & VT_SYM) && (vtop->c.i-4) == (int)(vtop->c.i-4))) {
+ /* constant symbolic case -> simple relocation */
#ifdef TCC_TARGET_PE
- greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4));
+ greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PC32, (int)(vtop->c.i-4));
#else
- greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4));
+ greloca(cur_text_section, vtop->sym, ind + 1, R_X86_64_PLT32, (int)(vtop->c.i-4));
#endif
- } else {
- /* put an empty PC32 relocation */
- put_elf_reloca(symtab_section, cur_text_section,
- ind + 1, R_X86_64_PC32, 0, (int)(vtop->c.i-4));
- }
oad(0xe8 + is_jmp, 0); /* call/jmp im */
} else {
/* otherwise, indirect call */
@@ -649,86 +650,69 @@ static void gcall_or_jmp(int is_jmp)
}
#if defined(CONFIG_TCC_BCHECK)
-#ifndef TCC_TARGET_PE
-static addr_t func_bound_offset;
-static unsigned long func_bound_ind;
-#endif
-static void gen_static_call(int v)
+static void gen_bounds_call(int v)
{
- Sym *sym = external_global_sym(v, &func_old_type, 0);
+ Sym *sym = external_global_sym(v, &func_old_type);
oad(0xe8, 0);
+#ifdef TCC_TARGET_PE
greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4);
+#else
+ greloca(cur_text_section, sym, ind-4, R_X86_64_PLT32, -4);
+#endif
}
-/* generate a bounded pointer addition */
-ST_FUNC void gen_bounded_ptr_add(void)
-{
- /* save all temporary registers */
- save_regs(0);
-
- /* prepare fast x86_64 function call */
- gv(RC_RAX);
- o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size
- vtop--;
-
- gv(RC_RAX);
- o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr
- vtop--;
-
- /* do a fast function call */
- gen_static_call(TOK___bound_ptr_add);
-
- /* returned pointer is in rax */
- vtop++;
- vtop->r = TREG_RAX | VT_BOUNDED;
-
+#ifdef TCC_TARGET_PE
+# define TREG_FASTCALL_1 TREG_RCX
+#else
+# define TREG_FASTCALL_1 TREG_RDI
+#endif
- /* relocation offset of the bounding function call point */
- vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela)));
+static void gen_bounds_prolog(void)
+{
+ /* leave some room for bound checking code */
+ func_bound_offset = lbounds_section->data_offset;
+ func_bound_ind = ind;
+ func_bound_add_epilog = 0;
+ o(0xb848 + TREG_FASTCALL_1 * 0x100); /*lbound section pointer */
+ gen_le64 (0);
+ oad(0xb8, 0); /* call to function */
}
-/* patch pointer addition in vtop so that pointer dereferencing is
- also tested */
-ST_FUNC void gen_bounded_ptr_deref(void)
+static void gen_bounds_epilog(void)
{
- addr_t func;
- int size, align;
- ElfW(Rela) *rel;
- Sym *sym;
+ addr_t saved_ind;
+ addr_t *bounds_ptr;
+ Sym *sym_data;
+ int offset_modified = func_bound_offset != lbounds_section->data_offset;
- size = 0;
- /* XXX: put that code in generic part of tcc */
- if (!is_float(vtop->type.t)) {
- if (vtop->r & VT_LVAL_BYTE)
- size = 1;
- else if (vtop->r & VT_LVAL_SHORT)
- size = 2;
- }
- if (!size)
- size = type_size(&vtop->type, &align);
- switch(size) {
- case 1: func = TOK___bound_ptr_indir1; break;
- case 2: func = TOK___bound_ptr_indir2; break;
- case 4: func = TOK___bound_ptr_indir4; break;
- case 8: func = TOK___bound_ptr_indir8; break;
- case 12: func = TOK___bound_ptr_indir12; break;
- case 16: func = TOK___bound_ptr_indir16; break;
- default:
- tcc_error("unhandled size when dereferencing bounded pointer");
- func = 0;
- break;
- }
+ if (!offset_modified && !func_bound_add_epilog)
+ return;
+
+ /* add end of table info */
+ bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
+ *bounds_ptr = 0;
- sym = external_global_sym(func, &func_old_type, 0);
- if (!sym->c)
- put_extern_sym(sym, NULL, 0, 0);
+ sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
+ func_bound_offset, lbounds_section->data_offset);
- /* patch relocation */
- /* XXX: find a better solution ? */
+ /* generate bound local allocation */
+ if (offset_modified) {
+ saved_ind = ind;
+ ind = func_bound_ind;
+ greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
+ ind = ind + 10;
+ gen_bounds_call(TOK___bound_local_new);
+ ind = saved_ind;
+ }
- rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i);
- rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
+ /* generate bound check local freeing */
+ o(0x5250); /* save returned value, if any */
+ greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
+ o(0xb848 + TREG_FASTCALL_1 * 0x100); /* mov xxx, %rcx/di */
+ gen_le64 (0);
+ gen_bounds_call(TOK___bound_local_delete);
+ o(0x585a); /* restore returned value, if any */
}
#endif
@@ -749,8 +733,6 @@ static int arg_prepare_reg(int idx) {
return arg_regs[idx];
}
-static int func_scratch, func_alloca;
-
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
@@ -812,6 +794,11 @@ void gfunc_call(int nb_args)
int size, r, args_size, i, d, bt, struct_size;
int arg;
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gbound_args(nb_args);
+#endif
+
args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
arg = nb_args;
@@ -877,19 +864,18 @@ void gfunc_call(int nb_args)
if (is_sse_float(vtop->type.t)) {
if (tcc_state->nosse)
tcc_error("SSE disabled");
- gv(RC_XMM0); /* only use one float register */
if (arg >= REGN) {
+ gv(RC_XMM0);
/* movq %xmm0, j*8(%rsp) */
gen_offs_sp(0xd60f66, 0x100, arg*8);
} else {
- /* movaps %xmm0, %xmmN */
- o(0x280f);
- o(0xc0 + (arg << 3));
+ /* Load directly to xmmN register */
+ gv(RC_XMM0 << arg);
d = arg_prepare_reg(arg);
- /* mov %xmm0, %rxx */
+ /* mov %xmmN, %rxx */
o(0x66);
orex(1,d,0, 0x7e0f);
- o(0xc0 + REG_VALUE(d));
+ o(0xc0 + arg*8 + REG_VALUE(d));
}
} else {
if (bt == VT_STRUCT) {
@@ -911,7 +897,6 @@ void gfunc_call(int nb_args)
vtop--;
}
save_regs(0);
-
/* Copy R10 and R11 into RCX and RDX, respectively */
if (nb_args > 0) {
o(0xd1894c); /* mov %r10, %rcx */
@@ -924,25 +909,12 @@ void gfunc_call(int nb_args)
if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
/* need to add the "func_scratch" area after alloca */
- o(0x0548), gen_le32(func_alloca), func_alloca = ind - 4;
- }
-
- /* other compilers don't clear the upper bits when returning char/short */
- bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
- if (bt == (VT_BYTE | VT_UNSIGNED))
- o(0xc0b60f); /* movzbl %al, %eax */
- else if (bt == VT_BYTE)
- o(0xc0be0f); /* movsbl %al, %eax */
- else if (bt == VT_SHORT)
- o(0x98); /* cwtl */
- else if (bt == (VT_SHORT | VT_UNSIGNED))
- o(0xc0b70f); /* movzbl %al, %eax */
-#if 0 /* handled in gen_cast() */
- else if (bt == VT_INT)
- o(0x9848); /* cltq */
- else if (bt == (VT_INT | VT_UNSIGNED))
- o(0xc089); /* mov %eax,%eax */
+ o(0x48); func_alloca = oad(0x05, func_alloca); /* add $NN, %rax */
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_call(TOK___bound_alloca_nr); /* new region */
#endif
+ }
vtop--;
}
@@ -950,14 +922,15 @@ void gfunc_call(int nb_args)
#define FUNC_PROLOG_SIZE 11
/* generate function prolog of type 't' */
-void gfunc_prolog(CType *func_type)
+void gfunc_prolog(Sym *func_sym)
{
+ CType *func_type = &func_sym->type;
int addr, reg_param_index, bt, size;
Sym *sym;
CType *type;
func_ret_sub = 0;
- func_scratch = 0;
+ func_scratch = 32;
func_alloca = 0;
loc = 0;
@@ -970,8 +943,6 @@ void gfunc_prolog(CType *func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
- func_vt = sym->type;
- func_var = (sym->f.func_type == FUNC_ELLIPSIS);
size = gfunc_arg_size(&func_vt);
if (!using_regs(size)) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
@@ -989,7 +960,8 @@ void gfunc_prolog(CType *func_type)
if (reg_param_index < REGN) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
- sym_push(sym->v & ~SYM_FIELD, type, VT_LLOCAL | VT_LVAL, addr);
+ sym_push(sym->v & ~SYM_FIELD, type,
+ VT_LLOCAL | VT_LVAL, addr);
} else {
if (reg_param_index < REGN) {
/* save arguments passed by register */
@@ -1002,19 +974,24 @@ void gfunc_prolog(CType *func_type)
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
}
- sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
+ sym_push(sym->v & ~SYM_FIELD, type,
+ VT_LOCAL | VT_LVAL, addr);
}
addr += 8;
reg_param_index++;
}
while (reg_param_index < REGN) {
- if (func_type->ref->f.func_type == FUNC_ELLIPSIS) {
+ if (func_var) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
addr += 8;
}
reg_param_index++;
}
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_prolog();
+#endif
}
/* generate function epilog */
@@ -1022,6 +999,15 @@ void gfunc_epilog(void)
{
int v, saved_ind;
+ /* align local size to word & save local variables */
+ func_scratch = (func_scratch + 15) & -16;
+ loc = (loc & -16) - func_scratch;
+
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gen_bounds_epilog();
+#endif
+
o(0xc9); /* leave */
if (func_ret_sub == 0) {
o(0xc3); /* ret */
@@ -1033,12 +1019,10 @@ void gfunc_epilog(void)
saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
- /* align local size to word & save local variables */
- func_scratch = (func_scratch + 15) & -16;
- v = (func_scratch + -loc + 15) & -16;
+ v = -loc;
if (v >= 4096) {
- Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
+ Sym *sym = external_global_sym(TOK___chkstk, &func_old_type);
oad(0xb8, v); /* mov stacksize, %eax */
oad(0xe8, 0); /* call __chkstk, (does the stackframe too) */
greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4);
@@ -1050,11 +1034,7 @@ void gfunc_epilog(void)
}
/* add the "func_scratch" area after each alloca seen */
- while (func_alloca) {
- unsigned char *ptr = cur_text_section->data + func_alloca;
- func_alloca = read32le(ptr);
- write32le(ptr, func_scratch);
- }
+ gsym_addr(func_alloca, -func_scratch);
cur_text_section->data_offset = saved_ind;
pe_add_unwind_data(ind, saved_ind, v);
@@ -1161,7 +1141,16 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p
ret_t = VT_QLONG;
} else {
*reg_count = 1;
- ret_t = (size > 4) ? VT_LLONG : VT_INT;
+ if (size > 4)
+ ret_t = VT_LLONG;
+ else if (size > 2)
+ ret_t = VT_INT;
+ else if (size > 1)
+ ret_t = VT_SHORT;
+ else
+ ret_t = VT_BYTE;
+ if ((ty->t & VT_BTYPE) == VT_STRUCT || (ty->t & VT_UNSIGNED))
+ ret_t |= VT_UNSIGNED;
}
break;
@@ -1237,11 +1226,16 @@ void gfunc_call(int nb_args)
{
X86_64_Mode mode;
CType type;
- int size, align, r, args_size, stack_adjust, i, reg_count;
+ int size, align, r, args_size, stack_adjust, i, reg_count, k;
int nb_reg_args = 0;
int nb_sse_args = 0;
int sse_reg, gen_reg;
- char _onstack[nb_args], *onstack = _onstack;
+ char *onstack = tcc_malloc((nb_args + 1) * sizeof (char));
+
+#ifdef CONFIG_TCC_BCHECK
+ if (tcc_state->do_bounds_check)
+ gbound_args(nb_args);
+#endif
/* calculate the number of integer/float register arguments, remember
arguments to be passed via stack (in onstack[]), and also remember
@@ -1272,7 +1266,7 @@ void gfunc_call(int nb_args)
tcc_error("SSE disabled but floating point arguments passed");
/* fetch cpu flag before generating any code */
- if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP)
+ if ((vtop->r & VT_VALMASK) == VT_CMP)
gv(RC_INT);
/* for struct arguments, we need to call memcpy and the function
@@ -1282,9 +1276,9 @@ void gfunc_call(int nb_args)
sse_reg = nb_sse_args;
args_size = 0;
stack_adjust &= 15;
- for (i = 0; i < nb_args;) {
+ for (i = k = 0; i < nb_args;) {
mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
- if (!onstack[i]) {
+ if (!onstack[i + k]) {
++i;
continue;
}
@@ -1297,7 +1291,7 @@ void gfunc_call(int nb_args)
args_size += 8;
stack_adjust = 0;
}
- if (onstack[i] == 2)
+ if (onstack[i + k] == 2)
stack_adjust = 1;
vrotb(i+1);
@@ -1347,9 +1341,11 @@ void gfunc_call(int nb_args)
vpop();
--nb_args;
- onstack++;
+ k++;
}
+ tcc_free(onstack);
+
/* XXX This should be superfluous. */
save_regs(0); /* save used temporary registers */
@@ -1368,12 +1364,12 @@ void gfunc_call(int nb_args)
sse_reg -= 2;
gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */
if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */
- /* movaps %xmm0, %xmmN */
- o(0x280f);
- o(0xc0 + (sse_reg << 3));
/* movaps %xmm1, %xmmN */
o(0x280f);
o(0xc1 + ((sse_reg+1) << 3));
+ /* movaps %xmm0, %xmmN */
+ o(0x280f);
+ o(0xc0 + (sse_reg << 3));
}
} else {
assert(reg_count == 1);
@@ -1423,7 +1419,6 @@ void gfunc_call(int nb_args)
vtop--;
}
-
#define FUNC_PROLOG_SIZE 11
static void push_arg_reg(int i) {
@@ -1432,8 +1427,9 @@ static void push_arg_reg(int i) {
}
/* generate function prolog of type 't' */
-void gfunc_prolog(CType *func_type)
+void gfunc_prolog(Sym *func_sym)
{
+ CType *func_type = &func_sym->type;
X86_64_Mode mode;
int i, addr, align, size, reg_count;
int param_addr = 0, reg_param_index, sse_param_index;
@@ -1447,7 +1443,7 @@ void gfunc_prolog(CType *func_type)
func_sub_sp_offset = ind;
func_ret_sub = 0;
- if (sym->f.func_type == FUNC_ELLIPSIS) {
+ if (func_var) {
int seen_reg_num, seen_sse_num, seen_stack_size;
seen_reg_num = seen_sse_num = 0;
/* frame pointer and return address */
@@ -1477,16 +1473,23 @@ void gfunc_prolog(CType *func_type)
}
}
- loc -= 16;
- /* movl $0x????????, -0x10(%rbp) */
- o(0xf045c7);
+ loc -= 24;
+ /* movl $0x????????, -0x18(%rbp) */
+ o(0xe845c7);
gen_le32(seen_reg_num * 8);
- /* movl $0x????????, -0xc(%rbp) */
- o(0xf445c7);
+ /* movl $0x????????, -0x14(%rbp) */
+ o(0xec45c7);
gen_le32(seen_sse_num * 16 + 48);
- /* movl $0x????????, -0x8(%rbp) */
- o(0xf845c7);
- gen_le32(seen_stack_size);
+ /* leaq $0x????????, %r11 */
+ o(0x9d8d4c);
+ gen_le32(seen_stack_size);
+ /* movq %r11, -0x10(%rbp) */
+ o(0xf05d894c);
+ /* leaq $-192(%rbp), %r11 */
+ o(0x9d8d4c);
+ gen_le32(-176 - 24);
+ /* movq %r11, -0x8(%rbp) */
+ o(0xf85d894c);
/* save all register passing arguments */
for (i = 0; i < 8; i++) {
@@ -1511,7 +1514,6 @@ void gfunc_prolog(CType *func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
- func_vt = sym->type;
mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, &reg_count);
if (mode == x86_64_mode_memory) {
push_arg_reg(reg_param_index);
@@ -1572,14 +1574,8 @@ void gfunc_prolog(CType *func_type)
}
#ifdef CONFIG_TCC_BCHECK
- /* leave some room for bound checking code */
- if (tcc_state->do_bounds_check) {
- func_bound_offset = lbounds_section->data_offset;
- func_bound_ind = ind;
- oad(0xb8, 0); /* lbound section pointer */
- o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */
- oad(0xb8, 0); /* call to function */
- }
+ if (tcc_state->do_bounds_check)
+ gen_bounds_prolog();
#endif
}
@@ -1589,35 +1585,8 @@ void gfunc_epilog(void)
int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
- if (tcc_state->do_bounds_check
- && func_bound_offset != lbounds_section->data_offset)
- {
- addr_t saved_ind;
- addr_t *bounds_ptr;
- Sym *sym_data;
-
- /* add end of table info */
- bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
- *bounds_ptr = 0;
-
- /* generate bound local allocation */
- sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
- func_bound_offset, lbounds_section->data_offset);
- saved_ind = ind;
- ind = func_bound_ind;
- greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0);
- ind = ind + 5 + 3;
- gen_static_call(TOK___bound_local_new);
- ind = saved_ind;
-
- /* generate bound check local freeing */
- o(0x5250); /* save returned value, if any */
- greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0);
- oad(0xb8, 0); /* mov xxx, %rax */
- o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */
- gen_static_call(TOK___bound_local_delete);
- o(0x585a); /* restore returned value, if any */
- }
+ if (tcc_state->do_bounds_check)
+ gen_bounds_epilog();
#endif
o(0xc9); /* leave */
if (func_ret_sub == 0) {
@@ -1639,6 +1608,12 @@ void gfunc_epilog(void)
#endif /* not PE */
+ST_FUNC void gen_fill_nops(int bytes)
+{
+ while (bytes--)
+ g(0x90);
+}
+
/* generate a jump to a label */
int gjmp(int t)
{
@@ -1658,42 +1633,23 @@ void gjmp_addr(int a)
}
}
-ST_FUNC void gtst_addr(int inv, int a)
+ST_FUNC int gjmp_append(int n, int t)
{
- int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP) {
- inv ^= (vtop--)->c.i;
- a -= ind + 2;
- if (a == (char)a) {
- g(inv - 32);
- g(a);
- } else {
- g(0x0f);
- oad(inv - 16, a - 4);
- }
- } else if ((v & ~1) == VT_JMP) {
- if ((v & 1) != inv) {
- gjmp_addr(a);
- gsym(vtop->c.i);
- } else {
- gsym(vtop->c.i);
- o(0x05eb);
- gjmp_addr(a);
- }
- vtop--;
+ void *p;
+ /* insert vtop->c jump list in t */
+ if (n) {
+ uint32_t n1 = n, n2;
+ while ((n2 = read32le(p = cur_text_section->data + n1)))
+ n1 = n2;
+ write32le(p, t);
+ t = n;
}
+ return t;
}
-/* generate a test. set 'inv' to invert test. Stack entry is popped */
-ST_FUNC int gtst(int inv, int t)
+ST_FUNC int gjmp_cond(int op, int t)
{
- int v = vtop->r & VT_VALMASK;
-
- if (nocode_wanted) {
- ;
- } else if (v == VT_CMP) {
- /* fast case : can jump directly since flags are set */
- if (vtop->c.i & 0x100)
+ if (op & 0x100)
{
/* This was a float compare. If the parity flag is set
the result was unordered. For anything except != this
@@ -1702,9 +1658,10 @@ ST_FUNC int gtst(int inv, int t)
Take care about inverting the test. We need to jump
to our target if the result was unordered and test wasn't NE,
otherwise if unordered we don't want to jump. */
- vtop->c.i &= ~0x100;
- if (inv == (vtop->c.i == TOK_NE))
- o(0x067a); /* jp +6 */
+ int v = vtop->cmp_r;
+ op &= ~0x100;
+ if (op ^ v ^ (v != TOK_NE))
+ o(0x067a); /* jp +6 */
else
{
g(0x0f);
@@ -1712,25 +1669,8 @@ ST_FUNC int gtst(int inv, int t)
}
}
g(0x0f);
- t = gjmp2((vtop->c.i - 16) ^ inv, t);
- } else if (v == VT_JMP || v == VT_JMPI) {
- /* && or || optimization */
- if ((v & 1) == inv) {
- /* insert vtop->c jump list in t */
- uint32_t n1, n = vtop->c.i;
- if (n) {
- while ((n1 = read32le(cur_text_section->data + n)))
- n = n1;
- write32le(cur_text_section->data + n, t);
- t = vtop->c.i;
- }
- } else {
- t = gjmp(t);
- gsym(vtop->c.i);
- }
- }
- vtop--;
- return t;
+ t = gjmp2(op - 16, t);
+ return t;
}
/* generate an integer binary operation */
@@ -1771,10 +1711,8 @@ void gen_opi(int op)
o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8);
}
vtop--;
- if (op >= TOK_ULT && op <= TOK_GT) {
- vtop->r = VT_CMP;
- vtop->c.i = op;
- }
+ if (op >= TOK_ULT && op <= TOK_GT)
+ vset_VT_CMP(op);
break;
case '-':
case TOK_SUBC1: /* sub with carry generation */
@@ -1929,8 +1867,7 @@ void gen_opf(int op)
op = TOK_EQ;
}
vtop--;
- vtop->r = VT_CMP;
- vtop->c.i = op;
+ vset_VT_CMP(op);
} else {
/* no memory reference possible for long double operations */
load(TREG_ST0, vtop);
@@ -1974,6 +1911,7 @@ void gen_opf(int op)
v1.c.i = fc;
load(r, &v1);
fc = 0;
+ vtop->r = r = r | VT_LVAL;
}
if (op == TOK_EQ || op == TOK_NE) {
@@ -2008,8 +1946,8 @@ void gen_opf(int op)
}
vtop--;
- vtop->r = VT_CMP;
- vtop->c.i = op | 0x100;
+ vset_VT_CMP(op | 0x100);
+ vtop->cmp_r = op;
} else {
assert((vtop->type.t & VT_BTYPE) != VT_LDOUBLE);
switch(op) {
@@ -2041,6 +1979,7 @@ void gen_opf(int op)
v1.c.i = fc;
load(r, &v1);
fc = 0;
+ vtop->r = r = r | VT_LVAL;
}
assert(!(vtop[-1].r & VT_LVAL));
@@ -2205,6 +2144,29 @@ void gen_cvt_ftoi(int t)
vtop->r = r;
}
+// Generate sign extension from 32 to 64 bits:
+ST_FUNC void gen_cvt_sxtw(void)
+{
+ int r = gv(RC_INT);
+ /* x86_64 specific: movslq */
+ o(0x6348);
+ o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
+}
+
+/* char/short to int conversion */
+ST_FUNC void gen_cvt_csti(int t)
+{
+ int r, sz, xl, ll;
+ r = gv(RC_INT);
+ sz = !(t & VT_UNSIGNED);
+ xl = (t & VT_BTYPE) == VT_SHORT;
+ ll = (vtop->type.t & VT_BTYPE) == VT_LLONG;
+ orex(ll, r, 0, 0xc0b60f /* mov[sz] %a[xl], %eax */
+ | (sz << 3 | xl) << 8
+ | (REG_VALUE(r) << 3 | REG_VALUE(r)) << 16
+ );
+}
+
/* computed goto support */
void ggoto(void)
{
@@ -2233,22 +2195,31 @@ ST_FUNC void gen_vla_result(int addr) {
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
-#ifdef TCC_TARGET_PE
- /* alloca does more than just adjust %rsp on Windows */
- vpush_global_sym(&func_old_type, TOK_alloca);
- vswap(); /* Move alloca ref past allocation size */
- gfunc_call(1);
-#else
- int r;
- r = gv(RC_INT); /* allocation size */
- /* sub r,%rsp */
- o(0x2b48);
- o(0xe0 | REG_VALUE(r));
- /* We align to 16 bytes rather than align */
- /* and ~15, %rsp */
- o(0xf0e48348);
- vpop();
+ int use_call = 0;
+
+#if defined(CONFIG_TCC_BCHECK)
+ use_call = tcc_state->do_bounds_check;
+#endif
+#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */
+ use_call = 1;
#endif
+ if (use_call)
+ {
+ vpush_global_sym(&func_old_type, TOK_alloca);
+ vswap(); /* Move alloca ref past allocation size */
+ gfunc_call(1);
+ }
+ else {
+ int r;
+ r = gv(RC_INT); /* allocation size */
+ /* sub r,%rsp */
+ o(0x2b48);
+ o(0xe0 | REG_VALUE(r));
+ /* We align to 16 bytes rather than align */
+ /* and ~15, %rsp */
+ o(0xf0e48348);
+ vpop();
+ }
}
diff --git a/x86_64-link.c b/x86_64-link.c
index a96144c..ec67d74 100644
--- a/x86_64-link.c
+++ b/x86_64-link.c
@@ -22,6 +22,7 @@
#include "tcc.h"
+#if !defined(ELF_OBJ_ONLY) || defined(TCC_TARGET_MACHO)
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
@@ -51,8 +52,6 @@ int code_reloc (int reloc_type)
case R_X86_64_JUMP_SLOT:
return 1;
}
-
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@@ -94,10 +93,10 @@ int gotplt_entry_type (int reloc_type)
return ALWAYS_GOTPLT_ENTRY;
}
- tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
+#if !defined(TCC_TARGET_MACHO) || defined TCC_IS_NATIVE
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
@@ -157,18 +156,13 @@ ST_FUNC void relocate_plt(TCCState *s1)
add32le(p + 8, x - 6);
p += 16;
while (p < p_end) {
- add32le(p + 2, x + s1->plt->data - p);
+ add32le(p + 2, x + (s1->plt->data - p));
p += 16;
}
}
}
-
-static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
-
-void relocate_init(Section *sr)
-{
- qrel = (ElfW_Rel *) sr->data;
-}
+#endif
+#endif
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
@@ -179,7 +173,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
switch (type) {
case R_X86_64_64:
if (s1->output_type == TCC_OUTPUT_DLL) {
- esym_index = s1->sym_attrs[sym_index].dyn_index;
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
@@ -199,6 +193,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
if (s1->output_type == TCC_OUTPUT_DLL) {
/* XXX: this logic may depend on TCC's codegen
now TCC uses R_X86_64_32 even for a 64bit pointer */
+ qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
/* Use sign extension! */
qrel->r_addend = (int)read32le(ptr) + val;
@@ -210,7 +205,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_X86_64_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
- esym_index = s1->sym_attrs[sym_index].dyn_index;
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
@@ -243,7 +238,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_X86_64_PC64:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
- esym_index = s1->sym_attrs[sym_index].dyn_index;
+ esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC64);
@@ -264,7 +259,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
add32le(ptr, s1->got->sh_addr - addr +
- s1->sym_attrs[sym_index].got_offset - 4);
+ get_sym_attr(s1, sym_index, 0)->got_offset - 4);
break;
case R_X86_64_GOTPC32:
add32le(ptr, s1->got->sh_addr - addr + rel->r_addend);
@@ -277,11 +272,11 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
break;
case R_X86_64_GOT32:
/* we load the got offset */
- add32le(ptr, s1->sym_attrs[sym_index].got_offset);
+ add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
break;
case R_X86_64_GOT64:
/* we load the got offset */
- add64le(ptr, s1->sym_attrs[sym_index].got_offset);
+ add64le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
break;
case R_X86_64_GOTOFF64:
add64le(ptr, val - s1->got->sh_addr);