summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2018-02-21 23:26:45 +0000
committerThomas Preud'homme <robotux@celest.fr>2018-02-21 23:26:45 +0000
commit1608e08052209fedd11fceef305a08c305dba9c1 (patch)
treedb73a0e818cffa09a5cb04da81561465853cd47d
parent51d8a1f05eac1e8087ef960a9747cb22242f5e07 (diff)
parentf4ab37b20a5b328cd681740fb2eed649d994b8c1 (diff)
merge patched into master
-rw-r--r--Changelog151
-rw-r--r--Makefile539
-rw-r--r--README21
-rw-r--r--RELICENSING1
-rw-r--r--TODO30
-rw-r--r--VERSION2
-rw-r--r--arm-asm.c94
-rw-r--r--arm-gen.c33
-rw-r--r--arm-link.c15
-rw-r--r--arm64-gen.c22
-rw-r--r--arm64-link.c15
-rw-r--r--c67-gen.c17
-rw-r--r--c67-link.c5
-rw-r--r--coff.h2
-rwxr-xr-xconfigure266
-rw-r--r--conftest.c22
-rw-r--r--debian/.git-dpm6
-rw-r--r--debian/patches/0001-Disable-test-not-working-on-i386.patch (renamed from debian/patches/0002-Disable-test-not-working-on-i386.patch)28
-rw-r--r--debian/patches/0001-Update-version-to-reflect-package-version.patch25
-rw-r--r--debian/patches/0002-Disable-stack-protector-in-runtime-library.patch (renamed from debian/patches/0003-Disable-stack-protector-in-runtime-library.patch)18
-rw-r--r--debian/patches/series5
-rw-r--r--elf.h19
-rw-r--r--examples/ex3.c3
-rw-r--r--i386-asm.c58
-rw-r--r--i386-gen.c136
-rw-r--r--i386-link.c21
-rw-r--r--il-gen.c4
-rw-r--r--include/stddef.h8
-rw-r--r--lib/Makefile139
-rw-r--r--lib/alloca-arm.S8
-rw-r--r--lib/alloca86-bt.S2
-rw-r--r--lib/alloca86.S6
-rw-r--r--lib/alloca86_64-bt.S6
-rw-r--r--lib/alloca86_64.S12
-rw-r--r--lib/armeabi.c12
-rw-r--r--lib/armflush.c58
-rw-r--r--lib/bcheck.c24
-rw-r--r--lib/lib-arm64.c12
-rw-r--r--lib/libtcc1.c144
-rw-r--r--lib/va_list.c65
-rw-r--r--libtcc.c800
-rw-r--r--libtcc.h2
-rw-r--r--tcc-doc.html2489
-rw-r--r--tcc-doc.texi62
-rw-r--r--tcc.c470
-rw-r--r--tcc.h521
-rw-r--r--tccasm.c335
-rw-r--r--tccelf.c613
-rw-r--r--tccgen.c3599
-rw-r--r--tccpe.c343
-rw-r--r--tccpp.c820
-rw-r--r--tccrun.c162
-rw-r--r--tcctok.h23
-rw-r--r--tcctools.c546
-rw-r--r--tests/Makefile99
-rw-r--r--tests/abitest.c44
-rw-r--r--tests/asm-c-connect-1.c57
-rw-r--r--tests/asm-c-connect-2.c36
-rw-r--r--tests/asmtest.S20
-rwxr-xr-x[-rw-r--r--]tests/gcctestsuite.sh0
-rw-r--r--tests/libtcc_test.c4
-rw-r--r--tests/pp/13.expect1
-rw-r--r--tests/pp/15.c6
-rw-r--r--tests/pp/15.expect2
-rw-r--r--tests/pp/18.c15
-rw-r--r--tests/pp/18.expect3
-rw-r--r--tests/pp/19.c101
-rw-r--r--tests/pp/19.expect14
-rw-r--r--tests/pp/20.c13
-rw-r--r--tests/pp/20.expect6
-rw-r--r--tests/pp/21.c36
-rw-r--r--tests/pp/21.expect8
-rw-r--r--tests/pp/Makefile21
-rw-r--r--tests/pp/pp-counter.c27
-rw-r--r--tests/pp/pp-counter.expect15
-rw-r--r--tests/tcctest.c226
-rw-r--r--tests/tcctest.py15
-rw-r--r--tests/tests2/17_enum.c43
-rw-r--r--tests/tests2/17_enum.expect1
-rw-r--r--tests/tests2/39_typedef.c18
-rw-r--r--tests/tests2/42_function_pointer.c6
-rw-r--r--tests/tests2/56_btype_excess-1.c1
-rw-r--r--tests/tests2/56_btype_excess-1.expect1
-rw-r--r--tests/tests2/57_btype_excess-2.c1
-rw-r--r--tests/tests2/57_btype_excess-2.expect1
-rw-r--r--tests/tests2/58_function_redefinition.c9
-rw-r--r--tests/tests2/58_function_redefinition.expect1
-rw-r--r--tests/tests2/59_function_array.c1
-rw-r--r--tests/tests2/59_function_array.expect1
-rw-r--r--tests/tests2/60_enum_redefinition.c4
-rw-r--r--tests/tests2/60_enum_redefinition.expect1
-rw-r--r--tests/tests2/60_errors_and_warnings.c51
-rw-r--r--tests/tests2/60_errors_and_warnings.expect28
-rw-r--r--tests/tests2/61_undefined_enum.c1
-rw-r--r--tests/tests2/61_undefined_enum.expect1
-rw-r--r--tests/tests2/62_enumerator_redefinition.c4
-rw-r--r--tests/tests2/62_enumerator_redefinition.expect1
-rw-r--r--tests/tests2/63_local_enumerator_redefinition.c14
-rw-r--r--tests/tests2/74_nocode_wanted.c1
-rw-r--r--tests/tests2/74_nocode_wanted.expect1
-rw-r--r--tests/tests2/81_types.c34
-rw-r--r--tests/tests2/82_attribs_position.c5
-rw-r--r--tests/tests2/84_hex-float.c (renamed from tests/tests2/84-hex-float.c)0
-rw-r--r--tests/tests2/84_hex-float.expect (renamed from tests/tests2/84-hex-float.expect)0
-rw-r--r--tests/tests2/85-asm-outside-function.expect0
-rw-r--r--tests/tests2/85_asm-outside-function.c (renamed from tests/tests2/85-asm-outside-function.c)2
-rw-r--r--tests/tests2/85_asm-outside-function.expect1
-rw-r--r--[-rwxr-xr-x]tests/tests2/86_memory-model.c (renamed from tests/tests2/86-memory-model.c)76
-rw-r--r--[-rwxr-xr-x]tests/tests2/86_memory-model.expect (renamed from tests/tests2/86-memory-model.expect)2
-rw-r--r--tests/tests2/87_dead_code.c2
-rw-r--r--tests/tests2/88_codeopt.c68
-rw-r--r--tests/tests2/88_codeopt.expect2
-rw-r--r--tests/tests2/89_nocode_wanted.c (renamed from tests/tests2/82_nocode_wanted.c)12
-rw-r--r--tests/tests2/89_nocode_wanted.expect (renamed from tests/tests2/82_nocode_wanted.expect)0
-rw-r--r--tests/tests2/90_struct-init.c (renamed from tests/tests2/86-struct-init.c)38
-rw-r--r--tests/tests2/90_struct-init.expect (renamed from tests/tests2/86-struct-init.expect)3
-rw-r--r--tests/tests2/91_ptr_longlong_arith32.c (renamed from tests/tests2/87_ptr_longlong_arith32.c)0
-rw-r--r--tests/tests2/91_ptr_longlong_arith32.expect (renamed from tests/tests2/87_ptr_longlong_arith32.expect)0
-rw-r--r--tests/tests2/92_enum_bitfield.c57
-rw-r--r--tests/tests2/92_enum_bitfield.expect (renamed from tests/tests2/63_local_enumerator_redefinition.expect)0
-rw-r--r--tests/tests2/93_integer_promotion.c71
-rw-r--r--tests/tests2/93_integer_promotion.expect46
-rw-r--r--tests/tests2/94_generic.c64
-rw-r--r--tests/tests2/94_generic.expect13
-rw-r--r--tests/tests2/95_bitfields.c218
-rw-r--r--tests/tests2/95_bitfields.expect149
-rw-r--r--tests/tests2/95_bitfields_ms.c2
-rw-r--r--tests/tests2/95_bitfields_ms.expect149
-rw-r--r--tests/tests2/96_nodata_wanted.c84
-rw-r--r--tests/tests2/96_nodata_wanted.expect23
-rw-r--r--tests/tests2/97_utf8_string_literal.c12
-rw-r--r--tests/tests2/97_utf8_string_literal.expect1
-rw-r--r--tests/tests2/98_al_ax_extend.c41
-rw-r--r--tests/tests2/98_al_ax_extend.expect9
-rw-r--r--tests/tests2/99_fastcall.c276
-rw-r--r--tests/tests2/99_fastcall.expect1
-rw-r--r--tests/tests2/Makefile97
-rwxr-xr-x[-rw-r--r--]win32/build-tcc.bat256
-rw-r--r--win32/examples/dll.c7
-rw-r--r--win32/examples/hello_dll.c17
-rw-r--r--win32/include/_mingw.h17
-rw-r--r--win32/include/assert.h5
-rw-r--r--win32/include/conio.h2
-rw-r--r--win32/include/math.h2
-rw-r--r--win32/include/stdint.h2
-rw-r--r--win32/include/tcc/tcc_libm.h4
-rw-r--r--win32/include/values.h2
-rw-r--r--win32/include/winapi/intrin.h11
-rw-r--r--win32/include/winapi/reason.h80
-rw-r--r--win32/include/winapi/specstrings.h7
-rw-r--r--win32/include/winapi/stralign.h154
-rw-r--r--win32/include/winapi/windef.h2
-rw-r--r--win32/include/winapi/windows.h6
-rw-r--r--win32/include/winapi/winnetwk.h476
-rw-r--r--win32/include/winapi/winnls.h765
-rw-r--r--win32/include/winapi/winnt.h2
-rw-r--r--win32/include/winapi/winreg.h2
-rw-r--r--win32/lib/chkstk.S4
-rw-r--r--win32/lib/crt1.c62
-rw-r--r--win32/lib/crt1w.c3
-rw-r--r--win32/lib/user32.def4
-rw-r--r--win32/lib/wincrt1.c97
-rw-r--r--win32/lib/wincrt1w.c3
-rw-r--r--win32/tcc-win32.txt330
-rw-r--r--win32/tools/tiny_impdef.c249
-rw-r--r--win32/tools/tiny_libmaker.c278
-rw-r--r--win32/vs2015/libtcc.vcxproj190
-rw-r--r--win32/vs2015/tcc.sln41
-rw-r--r--win32/vs2015/tcc.vcxproj173
-rw-r--r--x86_64-asm.h18
-rw-r--r--x86_64-gen.c454
-rw-r--r--x86_64-link.c80
172 files changed, 11352 insertions, 7810 deletions
diff --git a/Changelog b/Changelog
index 7cc19c8..17f5bde 100644
--- a/Changelog
+++ b/Changelog
@@ -1,126 +1,45 @@
Version 0.9.27:
-Licensing:
-
-- TinyCC partly relicensed to MIT license
-
User interface:
+- -x[c|a|n] filetype option (Sergey Korshunoff)
+- -P[1], -dD, -dM preprocessor options (Sergey Korshunoff)
+- -Wl,-(no-)whole-archive linker option (Reuben Thomas)
+- -mms-bitfields option (David Mertens)
+- -include <file> option (Michael Matz)
+- -mno-sse on x86-64 disables use of SSE instructions
+- @listfile support (Vlad Vissoultchev)
+- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
+- CPATH, C_INCLUDE_PATH and LIBRARY_PATH environment variables support
+ (Andrew Aladjev, Urs Janssen)
-- define __STDC_HOSTED__ (Michael Matz, Urs Janssen)
-- added support for CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH (Andrew Aladjev
-and Urs Janssen)
-- added option -norunsrc to control argv[0] with tcc -run (James Lyon)
-- improve --with-libgcc configure help (grischka)
-- improve error message when memory is full (grischka)
-- improve wording about compiler switches in documentation (Thomas Preud'homme)
-- use GNU triplet prefix for cross compiler names (Thomas Preud'homme)
-- ignore unknown linker optimization and as-needed option (Austin English)
+Platforms:
+- new AARCH64 (arm64) target (Edmund Grimley Evans)
+- vastly improved support for ARM hard float calling convention
+ (Thomas Preud'homme, Daniel Glöckner)
+- provide a runtime library for ARM (Thomas Preud'homme)
+- many x86_64 ABI fixes incl. XMM register passing and tests (James Lyon)
+- ABI tests with native compiler using libtcc (James Lyon)
+- UNICODE startup code supports wmain and wWinMain (YX Hao)
+- shared libraries for x86_64 (Michael Matz)
+- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
Features:
+- VLA (variable length array) improved (James Lyon, Pip Cet)
+- import functions by ordinal in .def files on windows (YX Hao)
+- x86/x86_64 assembler much improved (Michael Matz)
+- simple dead code suppression (Edmund Grimley Evans, Michael Matz, grischka)
+- implement round/fmin/fmax etc. math on windows (Avi Halachmi)
+- #pragma once support (Sergey Korshunoff, Vlad Vissoultchev, ...)
+- switch/case code improved (Zdenek Pavlas)
+- ~15% faster by TinyAlloc fast memory allocator (Vlad Vissoultchev)
+- standard conforming (and GCC compatible) struct initialization
+ (Michael Matz)
+- bit-field layout made compatible with GCC (Michael Matz)
+- UTF8 in string literals supported (Zdenek Pavlas)
+_ _Generic(...) supported (Matthias Gatto)
-- added ABI tests with native compiler using libtcc (James Lyon)
-- added CMake build system with support for cross-compilation (James Lyon)
-- improved variable length array support (James Lyon)
-- add the possibility to use noname functions by ordinal (YX Hao)
-- add a install-strip target to install tcc (Thomas Preud'homme)
-- add runtime selection of float ABI on ARM (Thomas Preud'homme)
-- add shared lib support on x86-64 (Michael Matz)
-
-Platforms:
-- support Debian GNU/kfreeBSD 64bit userspace (Thomas Preud'homme)
-- fix GNU/Hurd interpreter path (Thomas Preud'homme)
-- fix configure script for FreeBSD host (Thomas Preud'homme)
-- make tcc -run work reliably on ARM by flushing caches (Thomas Preud'homme)
-- many x86-64 ABI fixes incl. XMM register passing (James Lyon)
-- improve compatibility with mingw's long double (James Lyon)
-- avoid .stabstr section name to be truncated on win32 (Roy)
-- add support for load/store of _Bool value (Thomas Preud'homme)
-- detect instruction with incorrect operands on x86-64 (Thomas Preud'homme)
-- improved relocations on ARM (Thomas Preud'homme)
-- add va_* macro implementation for ARM (Thomas Preud'homme)
-- define __ARM_EABI__, __ARMEL__ and __ARM_PCS_VFP (Thomas Preud'homme)
-- provide a runtime library for ARM (Thomas Preud'homme)
-- vastly improved support for ARM hard float calling convention
-(Thomas Preud'homme, Daniel Glöckner)
-- tcc can uses libtcc1 on ARM (Thomas Preud'homme)
-- use __fixdfdi for all float to integer conversion (grischka)
-- simplify startup code for unix platforms (grischka)
-- improve ELF generated on ARM (Thomas Preud'homme)
-- add support for thumb to ARM relocation (Thomas Preud'homme)
-- fix globbing to match MSVC on Windows (Thomas Preud'homme)
-- deprecate FPA and OABI support for ARM (Thomas Preud'homme)
-- warn about softfloat not being supported on ARM (Thomas Preud'homme)
-
-Bug fixes:
-- many code clean up (Urs Janssen, grischka)
-- fixes of other's patches (grischka, Ramsay Jones, Michael Matz)
-- fix documentation about __TINYC__ (Urs Janssen)
-- improve build of documentation (Urs Janssen)
-- improve build instructions (Jov)
-- switch from texi2html to makeinfo --html to build tcc-doc.html (James Lyon)
-- improve out of tree build (James Lyon)
-- improved passing and returning of struct (James Lyon)
-- fix CMake build on i386 and x86-64 (James Lyon)
-- fix i386 calling convention issue (James Lyon)
-- fix error in Windows build of tests (James Lyon)
-- fix x86-64 long double passing (James Lyon)
-- fix crash with undefined struct (grischka)
-- normalize slashes on win32 to always use backslashes (grischka)
-- use runtime function for float to int conversion on i386 (grischka)
-- improved documentation for include and lib lookup on win32 (grischka)
-- detect redefinition of function (Thomas Preud'homme)
-- detect the use of array of functions (Thomas Preud'homme)
-- detect use of enumerator with wrong enumeration (Thomas Preud'homme)
-- detect redefinition of enumerator or enumeration (Thomas Preud'homme)
-- set the user-defined library search paths first (Vittorio Giovara)
-- detect usage of incomplete types inside struct/union (Amine Najahi)
-- various macro bug fixes (Joseph Poirier)
-- avoid wrong trigger of assert on x86-64 platform (Thomas Preud'homme)
-- fix NaN comparison (Thomas Preud'homme)
-- use libtcc for static linking with runtime library (Thomas Preud'homme)
-- fix negation of 0.0 and -0.0 values (Thomas Preud'homme)
-- fix use of long long as if condition (Thomas Preud'homme)
-- disable bound check if libgcc is used (Thomas Preud'homme)
-- error out when casting to void (grischka)
-- remove circular dependency in Makefile (grischka)
-- stop preventing gcc to do strict aliasing (grischka)
-- fix Windows build of tcc (grischka)
-- build runtime library for arm cross compiler (Thomas Preud'homme)
-- fix installation of arm cross-compiler (Thomas Preud'homme)
-- add basic test for cross-compiler (Thomas Preud'homme)
-- fix failure when generating PE on x86-64 (Archidemon)
-- fix floating point unary minus and plus (Michael Matz)
-- add more tests for signed zero float (Michael Matz)
-- fix precision of double on x86-64 (Vincent Lefevre)
-- fix bound checking of argv with -run switch (Kirill Smelkov)
-- work around a wine cmd bug when building tcc on Windows (Austin English)
-- reenable some bound check tests (grischka)
-- boundtest.c lookup honors VPATH (grischka)
-- diff compared to CC in test[123]b? are now errors (grischka)
-- fix test3 on Windows (grischka)
-- prevent gcc from building (non functional) libtcc.a (grischka)
-- fix warning related to PE file generation on x86-64 (grischka)
-- stop mixing ordinary and implicit rule in Makefile (Iavael)
-- fix integer to double conversion on ARM (Thomas Preud'homme)
-- fix parameter passing of structure < 4 bytes on ARM (Thomas Preud'homme)
-- disable builtin_frame_address test on ARM due to gcc bug (Thomas Preud'homme)
-- fix initialization of struct on ARM (Thomas Preud'homme)
-- fix parameter passing of (unsigned) long long bitfield (Thomas Preud'homme)
-- improve float to integer tests (Thomas Preud'homme)
-- fix relocation of Thumb branch to ARM function (Thomas Preud'homme)
-- fix char wrong compatibility with [un]signed char (Thomas Preud'homme)
-- choose the code to compile based on target in libtcc1 (Thomas Preud'homme)
-- fix various clang warnings (Thomas Preud'homme)
-- don't hardcode tcc in Makefile for tests (Thomas Preud'homme)
-- fix relocation of __bound_init bound checking code (Thomas Preud'homme)
-- accept only one basic type for a given variable (Thomas Preud'homme)
-- fix error when using va_* with tcc using libgcc (Thomas Preud'homme)
-- support GOT32 and PLT32 reloc on the same symbol (Thomas Preud'homme)
-- fix memory leak due to symbol attributes (mingodad)
-- partially fix bound checking of argv and arge (Thomas Preud'homme)
-- fix possible dereference when getting name of symbol (grischka)
-- fix va_list type definition on x86-64 (Daniel Glöckner)
-- reduce number of scan-build false positive (mingodad)
+Licensing:
+- TinyCC partly relicensed to MIT license (See RELICENSING file).
version 0.9.26:
diff --git a/Makefile b/Makefile
index 9527d12..3ae466f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,61 +1,78 @@
+# --------------------------------------------------------------------------
#
# Tiny C Compiler Makefile
#
-TOP ?= .
-include $(TOP)/config.mak
-VPATH = $(TOPSRC)
-CFLAGS += -I$(TOP)
+ifndef TOP
+ TOP = .
+ INCLUDED = no
+endif
-CFLAGS += $(CPPFLAGS)
+include $(TOP)/config.mak
-ifeq (-$(findstring gcc,$(CC))-,-gcc-)
- ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
- CFLAGS += -D_FORTIFY_SOURCE=0
- endif
-else
- ifeq (-$(findstring clang,$(CC))-,-clang-)
- # make clang accept gnuisms in libtcc1.c
- CFLAGS+=-fheinous-gnu-extensions
- endif
+ifeq (-$(CC)-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-gcc-4--)
+ CFLAGS += -D_FORTIFY_SOURCE=0
endif
LIBTCC = libtcc.a
LIBTCC1 = libtcc1.a
LINK_LIBTCC =
LIBS =
+CFLAGS += -I$(TOP)
+CFLAGS += $(CPPFLAGS)
+VPATH = $(TOPSRC)
ifdef CONFIG_WIN32
- LIBTCC = libtcc.dll
+ 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
- ifndef CONFIG_NOLDL
+ ifneq ($(CONFIG_ldl),no)
LIBS+=-ldl
endif
# make libtcc as static or dynamic library?
- ifdef DISABLE_STATIC
- LIBTCC=libtcc.so
- ifndef DISABLE_RPATH
+ ifeq ($(CONFIG_static),no)
+ LIBTCC=libtcc$(DLLSUF)
+ export LD_LIBRARY_PATH := $(CURDIR)/$(TOP)
+ ifneq ($(CONFIG_rpath),no)
LINK_LIBTCC += -Wl,-rpath,"$(libdir)"
- export LD_LIBRARY_PATH := $(CURDIR)/$(TOP)
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
+ endif
endif
-ifeq ($(TARGETOS),Darwin)
- CFLAGS += -Wl,-flat_namespace,-undefined,warning
- export MACOSX_DEPLOYMENT_TARGET:=10.2
+# 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))
+TCC = $(TOP)/tcc$(EXESUF) $(TCCFLAGS)
+ifdef CONFIG_OSX
+ TCCFLAGS += -D_ANSI_SOURCE
endif
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
-LIBS_P= $(LIBS)
+LIBS_P = $(LIBS)
LDFLAGS_P = $(LDFLAGS)
CONFIG_$(ARCH) = yes
NATIVE_DEFINES_$(CONFIG_i386) += -DTCC_TARGET_I386
-NATIVE_DEFINES_$(CONFIG_x86-64) += -DTCC_TARGET_X86_64
+NATIVE_DEFINES_$(CONFIG_x86_64) += -DTCC_TARGET_X86_64
NATIVE_DEFINES_$(CONFIG_WIN32) += -DTCC_TARGET_PE
+NATIVE_DEFINES_$(CONFIG_OSX) += -DTCC_TARGET_MACHO
NATIVE_DEFINES_$(CONFIG_uClibc) += -DTCC_UCLIBC
+NATIVE_DEFINES_$(CONFIG_musl) += -DTCC_MUSL
+NATIVE_DEFINES_$(CONFIG_libgcc) += -DCONFIG_USE_LIBGCC
+NATIVE_DEFINES_$(CONFIG_selinux) += -DHAVE_SELINUX
NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM
NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
@@ -63,269 +80,254 @@ NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
-ifeq ($(TOP),.)
-
-PROGS=tcc$(EXESUF)
-I386_CROSS = i386-tcc$(EXESUF)
-WIN32_CROSS = i386-win32-tcc$(EXESUF)
-WIN64_CROSS = x86_64-win32-tcc$(EXESUF)
-WINCE_CROSS = arm-wince-tcc$(EXESUF)
-X64_CROSS = x86_64-tcc$(EXESUF)
-ARM_FPA_CROSS = arm-fpa-tcc$(EXESUF)
-ARM_FPA_LD_CROSS = arm-fpa-ld-tcc$(EXESUF)
-ARM_VFP_CROSS = arm-vfp-tcc$(EXESUF)
-ARM_EABI_CROSS = arm-eabi-tcc$(EXESUF)
-ARM_EABIHF_CROSS = arm-eabihf-tcc$(EXESUF)
-ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS)
-ARM64_CROSS = arm64-tcc$(EXESUF)
-C67_CROSS = c67-tcc$(EXESUF)
-
-CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
-CORE_FILES += tcc.h config.h libtcc.h tcctok.h
-I386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h
-WIN32_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
-WIN64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h tccpe.c
-WINCE_FILES = $(CORE_FILES) arm-gen.c arm-link.c tccpe.c
-X86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h
-ARM_FILES = $(CORE_FILES) arm-gen.c arm-link.c
-ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
-C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
+ifeq ($(INCLUDED),no)
+# --------------------------------------------------------------------------
+# running top Makefile
-ifdef CONFIG_WIN32
- PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) $(LIBTCC)
- ifeq ($(ARCH),x86-64)
- NATIVE_FILES=$(WIN64_FILES)
- PROGS_CROSS=$(WIN32_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
- LIBTCC1_CROSS=lib/i386-win32/libtcc1.a
- else
- NATIVE_FILES=$(WIN32_FILES)
- PROGS_CROSS=$(WIN64_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
- LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a
- endif
+PROGS = tcc$(EXESUF)
+TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
+TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
-else ifeq ($(ARCH),i386)
-NATIVE_FILES=$(I386_FILES)
-PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
-LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a
+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
+
+PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
+LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
+
+# build cross compilers & libs
+cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
-else ifeq ($(ARCH),x86-64)
-NATIVE_FILES=$(X86_64_FILES)
-PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
-LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a
+# build specific cross compiler & lib
+cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
-else ifeq ($(ARCH),arm)
-NATIVE_FILES=$(ARM_FILES)
-PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS)
+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)
-else ifeq ($(ARCH),arm64)
-NATIVE_FILES=$(ARM64_FILES)
-PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS)
+ifdef CONFIG_cross
+all : cross
endif
-ifeq ($(TARGETOS),Darwin)
- PROGS += tiny_libmaker$(EXESUF)
+# --------------------------------------------
+
+T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
+X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
+
+DEF-i386 = -DTCC_TARGET_I386
+DEF-x86_64 = -DTCC_TARGET_X86_64
+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-c67 = -DTCC_TARGET_C67 -w # disable warnigs
+DEF-arm-fpa = -DTCC_TARGET_ARM
+DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
+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-$(NATIVE_TARGET) = $(NATIVE_DEFINES)
+
+DEFINES += $(DEF-$T) $(DEF-all)
+DEFINES += $(if $(ROOT-$T),-DCONFIG_SYSROOT="\"$(ROOT-$T)\"")
+DEFINES += $(if $(CRT-$T),-DCONFIG_TCC_CRTPREFIX="\"$(CRT-$T)\"")
+DEFINES += $(if $(LIB-$T),-DCONFIG_TCC_LIBPATHS="\"$(LIB-$T)\"")
+DEFINES += $(if $(INC-$T),-DCONFIG_TCC_SYSINCLUDEPATHS="\"$(INC-$T)\"")
+DEFINES += $(DEF-$(or $(findstring win,$T),unx))
+
+ifneq ($(X),)
+ifeq ($(CONFIG_WIN32),yes)
+DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
+DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\""
+else
+DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
+DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
+endif
endif
-TCCLIBS = $(LIBTCC1) $(LIBTCC)
-TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
+# include custom configuration (see make help)
+-include config-extra.mak
-ifdef CONFIG_CROSS
- PROGS += $(PROGS_CROSS)
- TCCLIBS += $(LIBTCC1_CROSS)
+CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
+CORE_FILES += tcc.h config.h libtcc.h tcctok.h
+i386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h
+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)
+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
+c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
+
+# libtcc sources
+LIBTCC_SRC = $(filter-out tcc.c tcctools.c,$(filter %.c,$($T_FILES)))
+
+ifeq ($(ONE_SOURCE),yes)
+LIBTCC_OBJ = $(X)libtcc.o
+LIBTCC_INC = $($T_FILES)
+TCC_FILES = $(X)tcc.o
+tcc.o : DEFINES += -DONE_SOURCE=0
+else
+LIBTCC_OBJ = $(patsubst %.c,$(X)%.o,$(LIBTCC_SRC))
+LIBTCC_INC = $(filter %.h %-gen.c %-link.c,$($T_FILES))
+TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
+$(TCC_FILES) : DEFINES += -DONE_SOURCE=0
endif
-all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
+# target specific object rule
+$(X)%.o : %.c $(LIBTCC_INC)
+ $(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
+
+# additional dependencies
+$(X)tcc.o : tcctools.c
# Host Tiny C Compiler
tcc$(EXESUF): tcc.o $(LIBTCC)
- $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS) $(LINK_LIBTCC)
+ $(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
# Cross Tiny C Compilers
-%-tcc$(EXESUF): tcc.c
- $(CC) -o $@ $< -DONE_SOURCE $(DEFINES) $(CFLAGS) $(LIBS) $(LDFLAGS)
+%-tcc$(EXESUF): FORCE
+ @$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
-# profiling version
-tcc_p$(EXESUF): $(NATIVE_FILES)
- $(CC) -o $@ $< -DONE_SOURCE $(NATIVE_DEFINES) $(CPPFLAGS_P) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
-
-$(I386_CROSS): DEFINES = -DTCC_TARGET_I386 \
- -DCONFIG_TCCDIR="\"$(tccdir)/i386\""
-$(X64_CROSS) : DEFINES = -DTCC_TARGET_X86_64
- -DCONFIG_TCCDIR="\"$(tccdir)/x86_64\""
-$(WIN32_CROSS) : DEFINES = -DTCC_TARGET_I386 -DTCC_TARGET_PE \
- -DCONFIG_TCCDIR="\"$(tccdir)/win32\"" \
- -DCONFIG_TCC_LIBPATHS="\"{B}/lib/32;{B}/lib\""
-$(WIN64_CROSS) : DEFINES = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE \
- -DCONFIG_TCCDIR="\"$(tccdir)/win32\"" \
- -DCONFIG_TCC_LIBPATHS="\"{B}/lib/64;{B}/lib\""
-$(WINCE_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_TARGET_PE
-$(C67_CROSS): DEFINES = -DTCC_TARGET_C67 -w # disable warnigs
-$(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM
-$(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
-$(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP
-$(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP
-$(ARM64_CROSS): DEFINES = -DTCC_TARGET_ARM64
-
-$(I386_CROSS) : $(I386_FILES)
-$(X64_CROSS) : $(X86_64_FILES)
-$(WIN32_CROSS) : $(WIN32_FILES)
-$(WIN64_CROSS) : $(WIN64_FILES)
-$(WINCE_CROSS) : $(WINCE_FILES)
-$(C67_CROSS) : $(C67_FILES)
-$(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES)
-$(ARM64_CROSS): $(ARM64_FILES)
-
-# libtcc generation and test
-ifndef ONE_SOURCE
-LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
-LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES) i386-asm.c,$(NATIVE_FILES))
-else
-LIBTCC_OBJ = libtcc.o
-LIBTCC_INC = $(NATIVE_FILES)
-libtcc.o : NATIVE_DEFINES += -DONE_SOURCE
-endif
+$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
+ $(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
-$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
- $(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CFLAGS)
+# profiling version
+tcc_p$(EXESUF): $($T_FILES)
+ $(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
+# static libtcc library
libtcc.a: $(LIBTCC_OBJ)
$(AR) rcs $@ $^
+# dynamic libtcc library
libtcc.so: $(LIBTCC_OBJ)
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
libtcc.so: CFLAGS+=-fPIC
+libtcc.so: LDFLAGS+=-fPIC
-# windows : libtcc.dll
-libtcc.dll : $(LIBTCC_OBJ) tiny_impdef$(EXESUF)
- $(CC) -shared $(LIBTCC_OBJ) -o $@ $(LDFLAGS)
- ./tiny_impdef $@
+# windows dynamic libtcc library
+libtcc.dll : $(LIBTCC_OBJ)
+ $(CC) -shared -o $@ $^ $(LDFLAGS)
+libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
-libtcc.dll : NATIVE_DEFINES += -DLIBTCC_AS_DLL
+# import file for windows libtcc.dll
+libtcc.def : libtcc.dll tcc$(EXESUF)
+ $(XTCC) -impdef $< -o $@
+XTCC ?= ./tcc$(EXESUF)
-# windows : utilities
-tiny_%$(EXESUF): $(TOPSRC)/win32/tools/tiny_%.c
- $(CC) -o $@ $< $(CFLAGS) $(LDFLAGS) $(NATIVE_DEFINES)
-
-ifneq ($(LIBTCC1),)
# TinyCC runtime libraries
-$(LIBTCC1) : FORCE $(PROGS)
- $(MAKE) -C lib native
-endif
+libtcc1.a : tcc$(EXESUF) FORCE
+ @$(MAKE) -C lib DEFINES='$(DEF-$T)'
-lib/%/libtcc1.a : FORCE $(PROGS_CROSS)
- $(MAKE) -C lib cross TARGET=$*
+# Cross libtcc1.a
+%-libtcc1.a : %-tcc$(EXESUF) FORCE
+ @$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
+.PRECIOUS: %-libtcc1.a
FORCE:
-# install
-INSTALL = install
-INSTALLBIN = install $(STRIP_$(STRIP_BINARIES))
-STRIP_yes = -s
-
-install-strip: install
-install-strip: STRIP_BINARIES = yes
-
-ifndef CONFIG_WIN32
-install:
- mkdir -p "$(bindir)"
- $(INSTALLBIN) -m755 $(PROGS) "$(bindir)"
- mkdir -p "$(tccdir)"
-ifneq ($(LIBTCC1),)
- $(INSTALL) -m644 $(LIBTCC1) "$(tccdir)"
-endif
- mkdir -p "$(tccdir)/include"
- $(INSTALL) -m644 $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
- mkdir -p "$(libdir)"
- $(INSTALL) -m644 $(LIBTCC) "$(libdir)"
- mkdir -p "$(includedir)"
- $(INSTALL) -m644 $(TOPSRC)/libtcc.h "$(includedir)"
-
- mkdir -p "$(mandir)/man1"
- -$(INSTALL) -m644 tcc.1 "$(mandir)/man1"
- mkdir -p "$(infodir)"
- -$(INSTALL) -m644 tcc-doc.info "$(infodir)"
- mkdir -p "$(docdir)"
- -$(INSTALL) -m644 tcc-doc.html "$(docdir)"
-ifdef CONFIG_CROSS
- mkdir -p "$(tccdir)/win32/lib/32"
- mkdir -p "$(tccdir)/win32/lib/64"
- $(INSTALL) -m644 $(TOPSRC)/win32/lib/*.def "$(tccdir)/win32/lib"
- -$(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/win32/lib/32"
- -$(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/win32/lib/64"
- cp -r $(TOPSRC)/include/. "$(tccdir)/win32/include"
- cp -r $(TOPSRC)/win32/include/. "$(tccdir)/win32/include"
-endif
-
-uninstall:
- rm -fv $(foreach P,$(PROGS),"$(bindir)/$P")
- rm -fv "$(libdir)/$(LIBTCC)" "$(includedir)/libtcc.h"
- rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
- rm -fv "$(docdir)/tcc-doc.html"
- rm -rv "$(tccdir)"
-else
-# on windows
-install:
- mkdir -p "$(tccdir)"
- mkdir -p "$(tccdir)/lib"
- mkdir -p "$(tccdir)/include"
- mkdir -p "$(tccdir)/examples"
- mkdir -p "$(tccdir)/doc"
- mkdir -p "$(tccdir)/libtcc"
- $(INSTALLBIN) -m755 $(PROGS) "$(tccdir)"
- $(INSTALL) -m644 libtcc1.a $(TOPSRC)/win32/lib/*.def "$(tccdir)/lib"
- cp -r $(TOPSRC)/win32/include/. "$(tccdir)/include"
- cp -r $(TOPSRC)/win32/examples/. "$(tccdir)/examples"
- cp $(TOPSRC)/tests/libtcc_test.c "$(tccdir)/examples"
- $(INSTALL) -m644 $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
- $(INSTALL) -m644 tcc-doc.html $(TOPSRC)/win32/tcc-win32.txt "$(tccdir)/doc"
- $(INSTALL) -m644 $(TOPSRC)/libtcc.h libtcc.def "$(tccdir)/libtcc"
-ifdef CONFIG_CROSS
- mkdir -p "$(tccdir)/lib/32"
- mkdir -p "$(tccdir)/lib/64"
- -$(INSTALL) -m644 lib/i386-win32/libtcc1.a "$(tccdir)/lib/32"
- -$(INSTALL) -m644 lib/x86_64-win32/libtcc1.a "$(tccdir)/lib/64"
-endif
-
-uninstall:
- rm -rfv "$(tccdir)/"*
-endif
-
+# --------------------------------------------------------------------------
# documentation and man page
tcc-doc.html: tcc-doc.texi
- -makeinfo --no-split --html --number-sections -o $@ $<
+ 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 > $@
+ $(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
tcc-doc.info: tcc-doc.texi
- -makeinfo $<
+ makeinfo $< || true
-# in tests subdir
-test:
- $(MAKE) -C tests
+# --------------------------------------------------------------------------
+# install
-clean:
- rm -f $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.so* *.out *.log \
- lib*.def *.exe *.dll a.out tags TAGS libtcc_test$(EXESUF) tcc$(EXESUF)
- $(MAKE) -C tests $@
- $(MAKE) -C lib $@
+INSTALL = install -m644
+INSTALLBIN = install -m755 $(STRIP_$(CONFIG_strip))
+STRIP_yes = -s
-distclean: clean
- rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
+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)
+IBw = $(call IB,$(wildcard $1),$2)
+IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
+IFw = $(call IF,$(wildcard $1),$2)
+IR = mkdir -p $2 && cp -r $1/. $2
+
+# install progs & libs
+install-unx:
+ $(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
+ $(call IFw,$(LIBTCC1) $(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)")
+ $(call IFw,tcc.1,"$(mandir)/man1")
+ $(call IFw,tcc-doc.info,"$(infodir)")
+ $(call IFw,tcc-doc.html,"$(docdir)")
+ifneq "$(wildcard $(LIBTCC1_W))" ""
+ $(call IFw,$(TOPSRC)/win32/lib/*.def $(LIBTCC1_W),"$(tccdir)/win32/lib")
+ $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/win32/include")
+ $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/win32/include")
+endif
-config.mak:
- @echo "Please run ./configure."
- @exit 1
+# 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 "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
+ @rm -fv "$(docdir)/tcc-doc.html"
+ rm -r "$(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 IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
+ $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
+ $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
+ $(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
+ $(call IFw,$(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)),"$(libdir)")
+ $(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
+ifneq "$(wildcard $(LIBTCC1_U))" ""
+ $(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
+ $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/lib/include")
+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"
+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)"
+
+# --------------------------------------------------------------------------
+# other stuff
TAGFILES = *.[ch] include/*.h lib/*.[chS]
tags : ; ctags $(TAGFILES)
-TAGS : ; etags $(TAGFILES)
+# cannot have both tags and TAGS on windows
+ETAGS : ; etags $(TAGFILES)
# create release tarball from *current* git branch (including tcc-doc.html
# and converting two files to CRLF)
-TCC-VERSION = $(VERSION)
+TCC-VERSION = tcc-$(VERSION)
tar: tcc-doc.html
mkdir $(TCC-VERSION)
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
@@ -337,6 +339,65 @@ tar: tcc-doc.html
rm -rf $(TCC-VERSION)
git reset
-.PHONY: all clean test tar tags TAGS distclean install uninstall FORCE
+config.mak:
+ $(if $(wildcard $@),,@echo "Please run ./configure." && exit 1)
+
+# run all tests
+test:
+ $(MAKE) -C tests
+# run test(s) from tests2 subdir (see make help)
+tests2.%:
+ $(MAKE) -C tests/tests2 $@
+
+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 $@
+
+distclean: clean
+ rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
-endif # ifeq ($(TOP),.)
+.PHONY: all clean test tar tags ETAGS distclean install uninstall FORCE
+
+help:
+ @echo "make"
+ @echo " build native compiler (from separate objects)"
+ @echo ""
+ @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 ""
+ @echo "make cross-TARGET"
+ @echo " build one specific cross compiler for 'TARGET', as in"
+ @echo " $(TCC_X)"
+ @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 0b789b2..3a3f90b 100644
--- a/README
+++ b/README
@@ -28,28 +28,19 @@ Features:
Documentation:
-------------
-1) Installation on a i386/x86_64/arm Linux/OSX/FreeBSD host (for Windows read tcc-win32.txt)
-
-Note: For OSX and FreeBSD, gmake should be used instead of make.
+1) Installation on a i386/x86_64/arm Linux/OSX/FreeBSD host
./configure
make
make test
make install
-Alternatively, out-of-tree builds are supported: you may use different
-directories to hold build objects, kept separate from your source tree:
-
- mkdir _build
- cd _build
- ../configure
- make
- make test
- make install
+ Notes: For OSX and FreeBSD, gmake should be used instead of make.
+ For Windows read tcc-win32.txt.
-Texi2html must be installed to compile the doc.
-By default, tcc is installed in /usr/local/bin.
-./configure --help shows configuration options.
+makeinfo must be installed to compile the doc. By default, tcc is
+installed in /usr/local/bin. ./configure --help shows configuration
+options.
2) Introduction
diff --git a/RELICENSING b/RELICENSING
index a067c04..20841a7 100644
--- a/RELICENSING
+++ b/RELICENSING
@@ -46,6 +46,7 @@
TK ? tcccoff.c c67-gen.c
Urs Janssen YES
waddlesplash YES
+ Christian Jullien YES Windows Cygwin build and tests
------------------------------------------------------------------------------
diff --git a/TODO b/TODO
index e6e5b07..d810088 100644
--- a/TODO
+++ b/TODO
@@ -2,16 +2,9 @@ TODO list:
Bugs:
-- fix macro substitution with nested definitions (ShangHongzhang)
+- i386 fastcall is mostly wrong
- FPU st(0) is left unclean (kwisatz haderach). Incompatible with
optimized gcc/msc code
-
-- constructors
-- cast bug (Peter Wang)
-- define incomplete type if defined several times (Peter Wang).
-- test binutils/gcc compile
-- tci patch + argument.
-- see -lxxx bug (Michael Charity).
- see transparent union pb in /urs/include/sys/socket.h
- precise behaviour of typeof with arrays ? (__put_user macro)
but should suffice for most cases)
@@ -20,17 +13,15 @@ Bugs:
- transform functions to function pointers in function parameters
(net/ipv4/ip_output.c)
- fix function pointer type display
-- check lcc test suite -> fix bitfield binary operations
- check section alignment in C
- fix invalid cast in comparison 'if (v == (int8_t)v)'
- finish varargs.h support (gcc 3.2 testsuite issue)
- fix static functions declared inside block
- fix multiple unions init
-- sizeof, alignof, typeof can still generate code in some cases.
-- Fix the remaining libtcc memory leaks.
- make libtcc fully reentrant (except for the compilation stage itself).
- struct/union/enum definitions in nested scopes (see also Debian bug #770657)
- __STDC_IEC_559__: float f(void) { static float x = 0.0 / 0.0; return x; }
+- memory may be leaked after errors (longjmp).
Portability:
@@ -42,14 +33,10 @@ Portability:
Linking:
-- static linking does not work
-- with "-run" and libtcc, no PLT is used, so branches may be out of
- range and relocations may fail; as a result libtest fails on arm64; see:
- https://lists.gnu.org/archive/html/tinycc-devel/2015-03/msg00111.html
+- static linking (-static) does not work
Bound checking:
-- '-b' bug.
- fix bound exit on RedHat 7.3
- setjmp is not supported properly in bound checking.
- fix bound check code with '&' on local variables (currently done
@@ -61,11 +48,10 @@ Missing features:
- disable-asm and disable-bcheck options
- __builtin_expect()
-- improve '-E' option.
- atexit (Nigel Horne)
-- packed attribute
- C99: add complex types (gcc 3.2 testsuite issue)
- postfix compound literals (see 20010124-1.c)
+- interactive mode / integrated debugger
Optimizations:
@@ -81,9 +67,8 @@ Not critical:
normative example - only relevant when using gotos! -> must add
boolean variable to tell if compound literal was already
initialized).
-- add PowerPC or ARM code generator and improve codegen for RISC (need
+- add PowerPC generator and improve codegen for RISC (need
to suppress VT_LOCAL and use a base register instead).
-- interactive mode / integrated debugger
- fix preprocessor symbol redefinition
- add portable byte code generator and interpreter for other
unsupported architectures.
@@ -108,3 +93,8 @@ Fixed (probably):
- #include_next support for /usr/include/limits ?
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
- win32: add __stdcall, check GetModuleHandle for dlls.
+- macro substitution with nested definitions (ShangHongzhang)
+- with "-run" and libtcc, a PLT is now built.
+- '-E' option was improved
+- packed attribute is now supported
+- ARM and ARM64 code generators have been added.
diff --git a/VERSION b/VERSION
index a2ff443..9a54223 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.9.27 (prerelease)
+0.9.27
diff --git a/arm-asm.c b/arm-asm.c
new file mode 100644
index 0000000..3b5ae66
--- /dev/null
+++ b/arm-asm.c
@@ -0,0 +1,94 @@
+/*************************************************************/
+/*
+ * ARM dummy assembler for TCC
+ *
+ */
+
+#ifdef TARGET_DEFS_ONLY
+
+#define CONFIG_TCC_ASM
+#define NB_ASM_REGS 16
+
+ST_FUNC void g(int c);
+ST_FUNC void gen_le16(int c);
+ST_FUNC void gen_le32(int c);
+
+/*************************************************************/
+#else
+/*************************************************************/
+
+#include "tcc.h"
+
+static void asm_error(void)
+{
+ tcc_error("ARM 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/arm-gen.c b/arm-gen.c
index cf3ea95..f535a09 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -34,8 +34,8 @@
#define NB_REGS 9
#endif
-#ifndef TCC_ARM_VERSION
-# define TCC_ARM_VERSION 5
+#ifndef TCC_CPU_VERSION
+# define TCC_CPU_VERSION 5
#endif
/* a register can belong to several classes. The classes must be
@@ -179,6 +179,7 @@ ST_FUNC void arm_init(struct TCCState *s)
#define func_ldouble_type func_old_type
ST_FUNC void arm_init(struct TCCState *s)
{
+#if 0
#if !defined (TCC_ARM_VFP)
tcc_warning("Support for FPA is deprecated and will be removed in next"
" release");
@@ -187,6 +188,7 @@ ST_FUNC void arm_init(struct TCCState *s)
tcc_warning("Support for OABI is deprecated and will be removed in next"
" release");
#endif
+#endif
}
#endif
@@ -201,7 +203,7 @@ static int regmask(int r) {
/******************************************************/
#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
-char *default_elfinterp(struct TCCState *s)
+const char *default_elfinterp(struct TCCState *s)
{
if (s->float_abi == ARM_HARD_FLOAT)
return "/lib/ld-linux-armhf.so.3";
@@ -214,7 +216,8 @@ void o(uint32_t i)
{
/* this is a good place to start adding big-endian support*/
int ind1;
-
+ if (nocode_wanted)
+ return;
ind1 = ind + 4;
if (!cur_text_section)
tcc_error("compiler error! This happens f.ex. if the compiler\n"
@@ -340,7 +343,7 @@ void stuff_const_harder(uint32_t op, uint32_t v) {
}
}
-ST_FUNC uint32_t encbranch(int pos, int addr, int fail)
+uint32_t encbranch(int pos, int addr, int fail)
{
addr-=pos+8;
addr/=4;
@@ -810,7 +813,7 @@ struct avail_regs {
and the parameter is a single float.
avregs: opaque structure to keep track of available VFP co-processor regs
- align: alignment contraints for the param, as returned by type_size()
+ align: alignment constraints for the param, as returned by type_size()
size: size of the parameter, as returned by type_size() */
int assign_vfpreg(struct avail_regs *avregs, int align, int size)
{
@@ -820,7 +823,7 @@ int assign_vfpreg(struct avail_regs *avregs, int align, int size)
return -1;
if (align >> 3) { /* double alignment */
first_reg = avregs->first_free_reg;
- /* alignment contraint not respected so use next reg and record hole */
+ /* alignment constraint not respected so use next reg and record hole */
if (first_reg & 1)
avregs->avail[avregs->last_hole++] = first_reg++;
} else { /* no special alignment (float or array of float) */
@@ -1218,7 +1221,7 @@ void gfunc_call(int nb_args)
int variadic;
if (float_abi == ARM_HARD_FLOAT) {
- variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
+ variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS);
if (variadic || floats_in_core_regs(&vtop[-nb_args]))
float_abi = ARM_SOFTFP_FLOAT;
}
@@ -1276,7 +1279,7 @@ void gfunc_prolog(CType *func_type)
sym = func_type->ref;
func_vt = sym->type;
- func_var = (func_type->ref->c == FUNC_ELLIPSIS);
+ func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS);
n = nf = 0;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
@@ -1411,6 +1414,8 @@ void gfunc_epilog(void)
int gjmp(int t)
{
int r;
+ if (nocode_wanted)
+ return t;
r=ind;
o(0xE0000000|encbranch(r,t,1));
return r;
@@ -1427,9 +1432,13 @@ int gtst(int inv, int t)
{
int v, r;
uint32_t op;
+
v = vtop->r & VT_VALMASK;
r=ind;
- if (v == VT_CMP) {
+
+ 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);
@@ -1644,7 +1653,7 @@ static int is_zero(int i)
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
- * two operands are guaranted to have the same floating point type */
+ * two operands are guaranteed to have the same floating point type */
void gen_opf(int op)
{
uint32_t x;
@@ -1774,7 +1783,7 @@ static uint32_t is_fconst()
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
- two operands are guaranted to have the same floating point type */
+ two operands are guaranteed to have the same floating point type */
void gen_opf(int op)
{
uint32_t x, r, r2, c1, c2;
diff --git a/arm-link.c b/arm-link.c
index 5e9c698..92a24eb 100644
--- a/arm-link.c
+++ b/arm-link.c
@@ -8,6 +8,7 @@
#define R_JMP_SLOT R_ARM_JUMP_SLOT
#define R_GLOB_DAT R_ARM_GLOB_DAT
#define R_COPY R_ARM_COPY
+#define R_RELATIVE R_ARM_RELATIVE
#define R_NUM R_ARM_NUM
@@ -61,7 +62,7 @@ int code_reloc (int reloc_type)
return -1;
}
-/* Returns an enumerator to describe wether and when the relocation needs a
+/* 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)
@@ -108,7 +109,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
unsigned plt_offset;
/* when building a DLL, GOT entry accesses must be done relative to
- start of GOT (see x86_64 examble above) */
+ start of GOT (see x86_64 example above) */
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_error("DLLs unimplemented!");
@@ -166,7 +167,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
void relocate_init(Section *sr) {}
-void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
+void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
ElfW(Sym) *sym;
int sym_index;
@@ -189,7 +190,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
if (x & 0x800000)
x -= 0x1000000;
x <<= 2;
- blx_avail = (TCC_ARM_VERSION >= 5);
+ blx_avail = (TCC_CPU_VERSION >= 5);
is_thumb = val & 1;
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
@@ -381,6 +382,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
/* Nothing to do. Normally used to indicate a dependency
on a certain symbol (like for exception handling under EABI). */
return;
+ case R_ARM_RELATIVE:
+#ifdef TCC_TARGET_PE
+ add32le(ptr, val - s1->pe_imagebase);
+#endif
+ /* do nothing */
+ return;
default:
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
diff --git a/arm64-gen.c b/arm64-gen.c
index 4b2608a..86b3af7 100644
--- a/arm64-gen.c
+++ b/arm64-gen.c
@@ -95,6 +95,8 @@ static uint32_t fltr(int r)
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);
@@ -247,7 +249,6 @@ static int arm64_type_size(int t)
case VT_BYTE: return 0;
case VT_SHORT: return 1;
case VT_PTR: return 3;
- case VT_ENUM: return 2;
case VT_FUNC: return 3;
case VT_FLOAT: return 2;
case VT_DOUBLE: return 3;
@@ -426,7 +427,7 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend)
// relocation and use only relocations with unlimited range.
int avoid_adrp = 1;
- if (avoid_adrp || (sym->type.t & VT_WEAK)) {
+ 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
@@ -581,7 +582,7 @@ static void arm64_gen_bl_or_b(int b)
{
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
assert(!b && (vtop->r & VT_SYM));
- greloc(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26);
+ greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0);
o(0x94000000); // bl .
}
else
@@ -1191,9 +1192,9 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
return 0;
}
-ST_FUNC void greturn(void)
+ST_FUNC void gfunc_return(CType *func_type)
{
- CType *t = &func_vt;
+ CType *t = func_type;
unsigned long a;
arm64_pcs(0, &t, &a);
@@ -1201,8 +1202,8 @@ ST_FUNC void greturn(void)
case -1:
break;
case 0:
- if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
- int align, size = type_size(&func_vt, &align);
+ if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
+ int align, size = type_size(func_type, &align);
gaddrof();
gv(RC_R(0));
arm64_ldrs(0, size);
@@ -1211,7 +1212,7 @@ ST_FUNC void greturn(void)
gv(RC_IRET);
break;
case 1: {
- CType type = func_vt;
+ CType type = *func_type;
mk_pointer(&type);
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
indir();
@@ -1220,7 +1221,7 @@ ST_FUNC void greturn(void)
break;
}
case 16:
- if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
+ if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
uint32_t j, sz, n = arm64_hfa(&vtop->type, &sz);
gaddrof();
gv(RC_R(0));
@@ -1235,6 +1236,7 @@ ST_FUNC void greturn(void)
default:
assert(0);
}
+ vtop--;
}
ST_FUNC void gfunc_epilog(void)
@@ -1278,6 +1280,8 @@ ST_FUNC void gfunc_epilog(void)
ST_FUNC int gjmp(int t)
{
int r = ind;
+ if (nocode_wanted)
+ return t;
o(t);
return r;
}
diff --git a/arm64-link.c b/arm64-link.c
index dd96ded..59322c5 100644
--- a/arm64-link.c
+++ b/arm64-link.c
@@ -7,6 +7,7 @@
#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
#define R_COPY R_AARCH64_COPY
+#define R_RELATIVE R_AARCH64_RELATIVE
#define R_NUM R_AARCH64_NUM
@@ -50,14 +51,12 @@ int code_reloc (int reloc_type)
return -1;
}
-/* Returns an enumerator to describe wether and when the relocation needs a
+/* 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_AARCH64_ABS32:
- case R_AARCH64_ABS64:
case R_AARCH64_PREL32:
case R_AARCH64_MOVW_UABS_G0_NC:
case R_AARCH64_MOVW_UABS_G1_NC:
@@ -70,6 +69,8 @@ int gotplt_entry_type (int reloc_type)
case R_AARCH64_COPY:
return NO_GOTPLT_ENTRY;
+ case R_AARCH64_ABS32:
+ case R_AARCH64_ABS64:
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
return AUTO_GOTPLT_ENTRY;
@@ -153,7 +154,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
void relocate_init(Section *sr) {}
-void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
+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);
#ifdef DEBUG_RELOC
@@ -239,6 +240,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
#endif
write64le(ptr, val - rel->r_addend);
return;
+ case R_AARCH64_RELATIVE:
+#ifdef TCC_TARGET_PE
+ add32le(ptr, val - s1->pe_imagebase);
+#endif
+ /* do nothing */
+ return;
default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
diff --git a/c67-gen.c b/c67-gen.c
index 28db68b..bcb4b0e 100644
--- a/c67-gen.c
+++ b/c67-gen.c
@@ -182,7 +182,8 @@ FILE *f = NULL;
void C67_g(int c)
{
int ind1;
-
+ if (nocode_wanted)
+ return;
#ifdef ASSEMBLY_LISTING_C67
fprintf(f, " %08X", c);
#endif
@@ -1950,12 +1951,12 @@ void gfunc_prolog(CType * func_type)
CType *type;
sym = func_type->ref;
- func_call = sym->r;
+ func_call = sym->f.func_call;
addr = 8;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
- func_var = (sym->c == FUNC_ELLIPSIS);
+ func_var = (sym->f.func_type == FUNC_ELLIPSIS);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
@@ -2038,6 +2039,8 @@ void gfunc_epilog(void)
int gjmp(int t)
{
int ind1 = ind;
+ if (nocode_wanted)
+ return t;
C67_MVKL(C67_A0, t); //r=reg to load, constant
C67_MVKH(C67_A0, t); //r=reg to load, constant
@@ -2070,7 +2073,9 @@ int gtst(int inv, int t)
int v, *p;
v = vtop->r & VT_VALMASK;
- if (v == VT_CMP) {
+ 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;
@@ -2220,7 +2225,7 @@ void gen_opi(int op)
r = vtop[-1].r;
fr = vtop[0].r;
vtop--;
- C67_MPYI(fr, r); // 32 bit bultiply fr,r,fr
+ C67_MPYI(fr, r); // 32 bit multiply fr,r,fr
C67_NOP(8); // NOP 8 for worst case
break;
case TOK_SHL:
@@ -2277,7 +2282,7 @@ void gen_opi(int op)
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
- two operands are guaranted to have the same floating point type */
+ two operands are guaranteed to have the same floating point type */
/* XXX: need to use ST1 too */
void gen_opf(int op)
{
diff --git a/c67-link.c b/c67-link.c
index ce45269..de72e44 100644
--- a/c67-link.c
+++ b/c67-link.c
@@ -8,6 +8,7 @@
#define R_JMP_SLOT R_C60_JMP_SLOT
#define R_GLOB_DAT R_C60_GLOB_DAT
#define R_COPY R_C60_COPY
+#define R_RELATIVE R_C60_RELATIVE
#define R_NUM R_C60_NUM
@@ -43,7 +44,7 @@ int code_reloc (int reloc_type)
return -1;
}
-/* Returns an enumerator to describe wether and when the relocation needs a
+/* 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)
@@ -96,7 +97,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
void relocate_init(Section *sr) {}
-void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
+void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
switch(type) {
case R_C60_32:
diff --git a/coff.h b/coff.h
index ea871a7..e8e6185 100644
--- a/coff.h
+++ b/coff.h
@@ -22,7 +22,7 @@ struct filehdr {
/*------------------------------------------------------------------------*/
#define F_RELFLG 0x01 /* relocation info stripped from file */
#define F_EXEC 0x02 /* file is executable (no unresolved refs) */
-#define F_LNNO 0x04 /* line nunbers stripped from file */
+#define F_LNNO 0x04 /* line numbers stripped from file */
#define F_LSYMS 0x08 /* local symbols stripped from file */
#define F_GSP10 0x10 /* 34010 version */
#define F_GSP20 0x20 /* 34020 version */
diff --git a/configure b/configure
index 42821ce..1ee3acb 100755
--- a/configure
+++ b/configure
@@ -17,8 +17,6 @@ TMPN="./conftest-$$"
TMPH=$TMPN.h
# default parameters
-build_cross="no"
-use_libgcc="no"
prefix=""
execprefix=""
bindir=""
@@ -32,8 +30,6 @@ cross_prefix=""
cc="gcc"
ar="ar"
strip="strip"
-cygwin="no"
-gprof="no"
bigendian="no"
mingw32="no"
LIBSUF=".a"
@@ -46,23 +42,30 @@ tcc_elfinterp=""
triplet=
tcc_lddir=
confvars=
+suggest="yes"
cpu=
+cpuver=
+gcc_major=0
+gcc_minor=0
# OS specific
targetos=`uname`
case $targetos in
- MINGW*) mingw32=yes;;
- MSYS*) mingw32=yes;;
- DragonFly) noldl=yes;;
- OpenBSD) noldl=yes;;
- FreeBSD) noldl=yes;;
- NetBSD) noldl=yes;;
- *) ;;
+ Darwin)
+ confvars="$confvars OSX"
+ DLLSUF=".dylib"
+ ;;
+ MINGW*|MSYS*|CYGWIN*)
+ mingw32=yes
+ ;;
+ DragonFly|OpenBSD|FreeBSD|NetBSD)
+ confvars="$confvars ldl=no"
+ ;;
+ *)
+ ;;
esac
# find source path
-# XXX: we assume an absolute path is given when launching configure,
-# except in './configure' case.
source_path=${0%configure}
source_path=${source_path%/}
source_path_used="yes"
@@ -122,23 +125,23 @@ for opt do
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
- --enable-gprof) gprof="yes"
+ --enable-cross) confvars="$confvars cross"
;;
- --enable-mingw32) mingw32="yes" ; cross_prefix="i686-pc-mingw32-" ; cpu=x86
+ --disable-static) confvars="$confvars static=no"
;;
- --enable-cygwin) mingw32="yes" ; cygwin="yes" ; cross_prefix="mingw32-" ; cpu=x86
+ --enable-static) confvars="$confvars static"
;;
- --enable-cross) build_cross="yes"
+ --disable-rpath) confvars="$confvars rpath=no"
;;
- --disable-static) disable_static="yes"
+ --strip-binaries) confvars="$confvars strip"
;;
- --disable-rpath) disable_rpath="yes"
+ --with-libgcc) confvars="$confvars libgcc"
;;
- --strip-binaries) strip_binaries="yes"
+ --with-selinux) confvars="$confvars selinux"
;;
- --with-libgcc) use_libgcc="yes"
+ --config-mingw32*) mingw32=$(echo "$opt=yes" | cut -d '=' -f 2)
;;
- --with-selinux) have_selinux="yes"
+ --config-*) confvars="$confvars ${opt#--config-}"; suggest="no"
;;
--help|-h) show_help="yes"
;;
@@ -157,10 +160,10 @@ fi
case "$cpu" in
x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386)
- cpu="x86"
+ cpu="i386"
;;
- x86_64|amd64)
- cpu="x86-64"
+ x86_64|amd64|x86-64)
+ cpu="x86_64"
;;
arm*)
case "$cpu" in
@@ -177,7 +180,7 @@ case "$cpu" in
cpuver=7
;;
esac
- cpu="armv4l"
+ cpu="arm"
;;
aarch64)
cpu="aarch64"
@@ -186,7 +189,7 @@ case "$cpu" in
cpu="alpha"
;;
"Power Macintosh"|ppc|ppc64)
- cpu="powerpc"
+ cpu="ppc"
;;
mips)
cpu="mips"
@@ -195,7 +198,8 @@ case "$cpu" in
cpu="s390"
;;
*)
- cpu="unknown"
+ echo "Unsupported CPU"
+ exit 1
;;
esac
@@ -205,22 +209,18 @@ if test -z "$CFLAGS"; then
fi
if test "$mingw32" = "yes" ; then
- if test x"$tccdir" = x""; then
- tccdir="tcc"
- fi
- if test -z "$prefix" ; then
- prefix="C:/Program Files/${tccdir}"
+ if test "$source_path_used" = "no"; then
+ source_path="."
fi
- if test -z "$sharedir" ; then
- sharedir="${prefix}"
+ if test "$cc" = gcc; then
+ test -z "$LDFLAGS" && LDFLAGS="-static"
fi
- execprefix="$prefix"
- bindir="${prefix}"
- tccdir="${prefix}"
- libdir="${prefix}/lib"
- docdir="${sharedir}/doc"
- mandir="${sharedir}/man"
- infodir="${sharedir}/info"
+ test -z "$prefix" && prefix="C:/Program Files/tcc"
+ test -z "$tccdir" && tccdir="${prefix}"
+ test -z "$bindir" && bindir="${tccdir}"
+ test -z "$docdir" && docdir="${tccdir}/doc"
+ test -z "$libdir" && libdir="${tccdir}/libtcc"
+ confvars="$confvars WIN32"
LIBSUF=".lib"
EXESUF=".exe"
DLLSUF=".dll"
@@ -252,12 +252,11 @@ else
if test x"$tccdir" = x""; then
tccdir="${libdir}/tcc"
fi
+ if test x"$includedir" = x""; then
+ includedir="${prefix}/include"
+ fi
fi # mingw32
-if test x"$includedir" = x""; then
- includedir="${prefix}/include"
-fi
-
if test x"$show_help" = "xyes" ; then
cat << EOF
Usage: configure [options]
@@ -288,17 +287,17 @@ Advanced options (experts only):
--cpu=CPU CPU [$cpu]
--strip-binaries strip symbol tables from 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
- --with-libgcc use libgcc_s.so.1 instead of libtcc1.a in dynamic link
- --enable-mingw32 build windows version on linux with mingw32
- --enable-cygwin build windows version on windows with cygwin
+ --with-libgcc use libgcc_s.so.1 instead of libtcc1.a
--enable-cross build cross compilers
- --with-selinux use mmap for exec mem [needs writable /tmp]
+ --with-selinux use mmap for executable memory (with tcc -run)
--sysincludepaths=... specify system include paths, colon separated
--libpaths=... specify system library paths, colon separated
--crtprefix=... specify locations of crt?.o, colon separated
--elfinterp=... specify elf interpreter
--triplet=... specify system library/include directory triplet
+ --config-uClibc,-musl,-mingw32... enable system specific configurations
EOF
#echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@@ -308,16 +307,16 @@ cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
-CONFTEST=./conftest$EXESUF
-
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
- bigendian="$($CONFTEST bigendian)"
gcc_major="$($CONFTEST version)"
gcc_minor="$($CONFTEST minor)"
- if test "$mingw32" = "no" ; then
+ fi
+ bigendian="$($CONFTEST bigendian)"
+ if test "$mingw32" = "no" ; then
if test -z "$triplet"; then
tt="$($CONFTEST triplet)"
@@ -327,14 +326,14 @@ if test -z "$cross_prefix" ; then
fi
if test -z "$triplet"; then
- if test $cpu = "x86-64" -o $cpu = "aarch64" ; then
+ if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
if test -f "/usr/lib64/crti.o" ; then
tcc_lddir="lib64"
fi
fi
fi
- if test "$cpu" = "armv4l" ; then
+ if test "$cpu" = "arm" ; then
if test "${triplet%eabihf}" != "$triplet" ; then
confvars="$confvars arm_eabihf"
elif test "${triplet%eabi}" != "$triplet" ; then
@@ -345,58 +344,63 @@ if test -z "$cross_prefix" ; then
fi
fi
- if test -f "/lib/ld-uClibc.so.0" ; then
- confvars="$confvars uClibc"
+ if test "$suggest" = "yes"; then
+ if test -f "/lib/ld-uClibc.so.0" ; then
+ echo "Perhaps you want ./configure --config-uClibc"
+ fi
+ if test -f "/lib/ld-musl-$cpu.so.1"; then
+ echo "Perhaps you want ./configure --config-musl"
+ fi
fi
-
- fi
fi
else
# if cross compiling, cannot launch a program, so make a static guess
case $cpu in
- powerpc|mips|s390) bigendian=yes;;
+ ppc|mips|s390) bigendian=yes;;
esac
fi
+if test "$bigendian" = "yes" ; then
+ confvars="$confvars BIGENDIAN"
+fi
+
# a final configuration tuning
-$cc -v --help > cc_help.txt 2>&1
-W_OPTIONS="declaration-after-statement"
-for i in $W_OPTIONS; do
- O_PRESENT="$(grep -- -W$i cc_help.txt)"
- if test -n "$O_PRESENT"; then CFLAGS="$CFLAGS -W$i"; fi
-done
-W_OPTIONS="deprecated-declarations strict-aliasing pointer-sign sign-compare unused-result uninitialized"
-for i in $W_OPTIONS; do
- O_PRESENT="$(grep -- -W$i cc_help.txt)"
- if test -n "$O_PRESENT"; then CFLAGS="$CFLAGS -Wno-$i"; fi
-done
-F_OPTIONS="strict-aliasing"
-for i in $F_OPTIONS; do
- O_PRESENT="$(grep -- -f$i cc_help.txt)"
- if test -n "$O_PRESENT"; then CFLAGS="$CFLAGS -fno-$i"; fi
-done
-rm -f cc_help.txt
+if ! echo "$cc" | grep -q "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
+ OPT1="$OPT1 -fheinous-gnu-extensions"
+ OPT2="$OPT2 -Wstring-plus-int"
+ fi
+ $cc $OPT1 $OPT2 -o a.out -c -xc - < /dev/null > cc_msg.txt 2>&1
+ for o in $OPT1; do # enable these options
+ if ! grep -q -- $o cc_msg.txt; then CFLAGS="$CFLAGS $o"; fi
+ done
+ for o in $OPT2; do # disable these options
+ if ! grep -q -- $o cc_msg.txt; then CFLAGS="$CFLAGS -Wno-${o#-W*}"; fi
+ done
+ # cat cc_msg.txt
+ # echo $CFLAGS
+ rm -f cc_msg.txt a.out
+fi
-fcho() { if test -n "$2"; then echo "$1$2"; else echo "$1-"; fi }
+fcho() { if test -n "$2"; then echo "$1$2"; fi }
-echo "Binary directory $bindir"
-echo "TinyCC directory $tccdir"
-echo "Library directory $libdir"
-echo "Include directory $includedir"
-echo "Manual directory $mandir"
-echo "Info directory $infodir"
-echo "Doc directory $docdir"
+fcho "Binary directory " "$bindir"
+fcho "TinyCC directory " "$tccdir"
+fcho "Library directory " "$libdir"
+fcho "Include directory " "$includedir"
+fcho "Manual directory " "$mandir"
+fcho "Info directory " "$infodir"
+fcho "Doc directory " "$docdir"
fcho "Target root prefix " "$sysroot"
echo "Source path $source_path"
-echo "C compiler $cc"
+echo "C compiler $cc ($gcc_major.$gcc_minor)"
echo "Target OS $targetos"
echo "CPU $cpu"
-echo "Big Endian $bigendian"
-echo "Profiling $gprof"
-echo "Cross compilers $build_cross"
-echo "Use libgcc $use_libgcc"
fcho "Triplet " "$triplet"
-
+fcho "Config " "${confvars# }"
echo "Creating config.mak and config.h"
cat >config.mak <<EOF
@@ -428,12 +432,19 @@ print_inc() {
echo "#endif" >> $TMPH
fi
}
+
print_mak() {
if test -n "$2"; then
echo "NATIVE_DEFINES+=-D$1=\"\\\"$2\\\"\"" >> config.mak
fi
}
+print_mak_int() {
+ if test -n "$2"; then
+ echo "NATIVE_DEFINES+=-D$1=$2" >> config.mak
+ fi
+}
+
echo "/* Automatically generated by configure - do not modify */" > $TMPH
print_inc CONFIG_SYSROOT "$sysroot"
@@ -444,77 +455,22 @@ print_mak CONFIG_TCC_CRTPREFIX "$tcc_crtprefix"
print_mak CONFIG_TCC_ELFINTERP "$tcc_elfinterp"
print_mak CONFIG_LDDIR "$tcc_lddir"
print_mak CONFIG_TRIPLET "$triplet"
+print_mak_int TCC_CPU_VERSION "$cpuver"
-echo "#define GCC_MAJOR $gcc_major" >> $TMPH
-echo "#define GCC_MINOR $gcc_minor" >> $TMPH
-
-if test "$cpu" = "x86" ; then
- echo "ARCH=i386" >> config.mak
-elif test "$cpu" = "x86-64" ; then
- echo "ARCH=x86-64" >> config.mak
-elif test "$cpu" = "armv4l" ; then
- echo "ARCH=arm" >> config.mak
- echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH
-elif test "$cpu" = "aarch64" ; then
+if test "$cpu" = "aarch64" ; then
echo "ARCH=arm64" >> config.mak
-elif test "$cpu" = "powerpc" ; then
- echo "ARCH=ppc" >> config.mak
-elif test "$cpu" = "mips" ; then
- echo "ARCH=mips" >> config.mak
-elif test "$cpu" = "s390" ; then
- echo "ARCH=s390" >> config.mak
-elif test "$cpu" = "alpha" ; then
- echo "ARCH=alpha" >> config.mak
else
- echo "Unsupported CPU"
- exit 1
+ echo "ARCH=$cpu" >> config.mak
fi
-
echo "TARGETOS=$targetos" >> config.mak
for v in $confvars ; do
- echo "CONFIG_$v=yes" >> config.mak
+ if test "${v%=*}" = "$v"; then
+ echo "CONFIG_$v=yes" >> config.mak
+ else
+ echo "CONFIG_$v" >> config.mak
+ fi
done
-if test "$noldl" = "yes" ; then
- echo "CONFIG_NOLDL=yes" >> config.mak
-fi
-if test "$mingw32" = "yes" ; then
- echo "CONFIG_WIN32=yes" >> config.mak
-fi
-if test "$cygwin" = "yes" ; then
- echo "#ifndef _WIN32" >> $TMPH
- echo "# define _WIN32" >> $TMPH
- echo "#endif" >> $TMPH
- echo "AR=ar" >> config.mak
-fi
-if test "$bigendian" = "yes" ; then
- echo "WORDS_BIGENDIAN=yes" >> config.mak
- echo "#define WORDS_BIGENDIAN 1" >> $TMPH
-fi
-if test "$gprof" = "yes" ; then
- echo "TARGET_GPROF=yes" >> config.mak
- echo "#define HAVE_GPROF 1" >> $TMPH
-fi
-if test "$build_cross" = "yes" ; then
- echo "CONFIG_CROSS=yes" >> config.mak
-fi
-if test "$disable_static" = "yes" ; then
- echo "DISABLE_STATIC=yes" >> config.mak
-fi
-if test "$disable_rpath" = "yes" ; then
- echo "DISABLE_RPATH=yes" >> config.mak
-fi
-if test "$strip_binaries" = "yes" ; then
- echo "STRIP_BINARIES=yes" >> config.mak
-fi
-if test "$use_libgcc" = "yes" ; then
- echo "#define CONFIG_USE_LIBGCC" >> $TMPH
- echo "CONFIG_USE_LIBGCC=yes" >> config.mak
-fi
-if test "$have_selinux" = "yes" ; then
- echo "#define HAVE_SELINUX" >> $TMPH
- echo "HAVE_SELINUX=yes" >> config.mak
-fi
version=`head $source_path/VERSION`
echo "VERSION = $version" >> config.mak
diff --git a/conftest.c b/conftest.c
index fa07a1b..2824cc8 100644
--- a/conftest.c
+++ b/conftest.c
@@ -1,9 +1,9 @@
#include <stdio.h>
/* Define architecture */
-#if defined(__i386__)
+#if defined(__i386__) || defined _M_IX86
# define TRIPLET_ARCH "i386"
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined _M_AMD64
# define TRIPLET_ARCH "x86_64"
#elif defined(__arm__)
# define TRIPLET_ARCH "arm"
@@ -18,6 +18,8 @@
# define TRIPLET_OS "linux"
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
# define TRIPLET_OS "kfreebsd"
+#elif defined _WIN32
+# define TRIPLET_OS "win32"
#elif !defined (__GNU__)
# define TRIPLET_OS "unknown"
#endif
@@ -33,7 +35,9 @@
# define TRIPLET_ABI "gnu"
#endif
-#ifdef __GNU__
+#if defined _WIN32
+# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS
+#elif defined __GNU__
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI
#else
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI
@@ -59,6 +63,13 @@ int main(int argc, char *argv[])
case 'v':
printf("%d\n", __GNUC__);
break;
+#elif defined __TINYC__
+ case 'v':
+ puts("0");
+ break;
+ case 'm':
+ printf("%d\n", __TINYC__);
+ break;
#else
case 'm':
case 'v':
@@ -68,9 +79,8 @@ int main(int argc, char *argv[])
case 't':
puts(TRIPLET);
break;
- case -1:
- /* to test -Wno-unused-result */
- fread(NULL, 1, 1, NULL);
+
+ default:
break;
}
return 0;
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 2640cb3..699a551 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,7 +1,7 @@
# see git-dpm(1) from git-dpm package
-506de045eee57bad9eea1cf50cbe62088f3a5113
-506de045eee57bad9eea1cf50cbe62088f3a5113
-3f2e65a51523fbb98a44b71c29ae3a3fcc13854b
+f4ab37b20a5b328cd681740fb2eed649d994b8c1
+f4ab37b20a5b328cd681740fb2eed649d994b8c1
+e2ccf3981d78dfeb390d22c74625b60310100abb
e2ccf3981d78dfeb390d22c74625b60310100abb
tcc_0.9.27.orig.tar.bz2
3bab3acd404ea92ba18e0c261d9d8cb2f366a8a5
diff --git a/debian/patches/0002-Disable-test-not-working-on-i386.patch b/debian/patches/0001-Disable-test-not-working-on-i386.patch
index 8e52339..2c41791 100644
--- a/debian/patches/0002-Disable-test-not-working-on-i386.patch
+++ b/debian/patches/0001-Disable-test-not-working-on-i386.patch
@@ -1,4 +1,4 @@
-From ef905272c2027276a00c1a8d0950c2f46eade78e Mon Sep 17 00:00:00 2001
+From 557d51707f31b75321fc25d80e5bf249895d171c Mon Sep 17 00:00:00 2001
From: Thomas Preud'homme <robotux@celest.fr>
Date: Sun, 17 Feb 2013 23:39:08 +0100
Subject: Disable test not working on i386
@@ -9,16 +9,16 @@ disable the test on such platform while upstream fixes it.
Origin: vendor
Forwarded: no
-Last-Update: 2016-12-17
+Last-Update: 2018-02-21
---
tests/tcctest.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/tcctest.c b/tests/tcctest.c
-index 0f714822..23fa9f9d 100644
+index 57670bea..3e0ae8bc 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
-@@ -3140,6 +3140,7 @@ void override_func2 (void)
+@@ -3184,6 +3184,7 @@ void override_func2 (void)
printf ("asmc: override2\n");
}
@@ -26,21 +26,21 @@ index 0f714822..23fa9f9d 100644
/* This checks a construct used by the linux kernel to encode
references to strings by PC relative references. */
extern int bug_table[] __attribute__((section("__bug_table")));
-@@ -3161,6 +3162,7 @@ char * get_asm_string (void)
+@@ -3205,6 +3206,7 @@ char * get_asm_string (void)
char * str = ((char*)bug_table) + bug_table[1];
return str;
}
+#endif
- unsigned int set;
-
-@@ -3319,7 +3321,9 @@ void asm_test(void)
- if (!somebool)
- printf("asmbool: failed\n");
- #endif
+ /* This checks another constructs with local labels. */
+ extern unsigned char alld_stuff[];
+@@ -3460,7 +3462,9 @@ void asm_test(void)
+ the global one, not the local decl from this function. */
+ asm volatile(".weak override_func3\n.set override_func3, base_func");
+ override_func3();
+#ifndef __i386__
printf("asmstr: %s\n", get_asm_string());
+#endif
- val = 43;
- fancy_copy (&val, &val2);
- printf ("fancycpy(%d)=%d\n", val, val2);
+ asm_local_label_diff();
+ asm_local_statics();
+ #endif
diff --git a/debian/patches/0001-Update-version-to-reflect-package-version.patch b/debian/patches/0001-Update-version-to-reflect-package-version.patch
deleted file mode 100644
index ddd7d87..0000000
--- a/debian/patches/0001-Update-version-to-reflect-package-version.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 2d2938674c0a51bc96830beb608b25d556f58a68 Mon Sep 17 00:00:00 2001
-From: Thomas Preud'homme <robotux@celest.fr>
-Date: Sun, 17 Feb 2013 23:39:08 +0100
-Subject: Update version to reflect package version
-
-There is plan upstream to make a TinyCC release in the comming month or
-two. The code is thus much closer to the one that will be in the 0.9.27
-release than the one in the 0.9.26 release. The Debian package version
-reflects that and this patch changes the upstream version so that the
-version output by tcc -v matches the one of the Debian package.
-
-Origin: vendor
-Forwarded: no
-Last-Update: 2016-12-17
----
- VERSION | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/VERSION b/VERSION
-index 46e7a712..a2ff443c 100644
---- a/VERSION
-+++ b/VERSION
-@@ -1 +1 @@
--0.9.26
-+0.9.27 (prerelease)
diff --git a/debian/patches/0003-Disable-stack-protector-in-runtime-library.patch b/debian/patches/0002-Disable-stack-protector-in-runtime-library.patch
index ec5be2c..243bc23 100644
--- a/debian/patches/0003-Disable-stack-protector-in-runtime-library.patch
+++ b/debian/patches/0002-Disable-stack-protector-in-runtime-library.patch
@@ -1,4 +1,4 @@
-From 506de045eee57bad9eea1cf50cbe62088f3a5113 Mon Sep 17 00:00:00 2001
+From f4ab37b20a5b328cd681740fb2eed649d994b8c1 Mon Sep 17 00:00:00 2001
From: Thomas Preud'homme <robotux@celest.fr>
Date: Sun, 17 Feb 2013 23:39:08 +0100
Subject: Disable stack protector in runtime library
@@ -9,20 +9,20 @@ when libtcc1.a is build with -fstack-protector.
Origin: vendor
Forwarded: no
-Last-Update: 2016-12-18
+Last-Update: 2018-02-21
---
lib/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/Makefile b/lib/Makefile
-index e61437ef..79891d4e 100644
+index 0c1ec54d..385ffae4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
-@@ -44,6 +44,7 @@ ARM_O = libtcc1.o armeabi.o alloca-arm.o
- ARM64_O = lib-arm64.o
- WIN32_O = crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
+@@ -20,6 +20,7 @@ XCFG = $(or $(findstring -win,$T),-unx)
+ # in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
+ arm-libtcc1-usegcc ?= no
+CFLAGS:=$(filter-out -fstack-protector%,$(CFLAGS))
- # build TCC runtime library to contain PIC code, so it can be linked
- # into shared libraries
- PICFLAGS = -fPIC
+ ifeq "$($(T)-libtcc1-usegcc)" "yes"
+ XCC = $(CC)
+ XAR = $(AR)
diff --git a/debian/patches/series b/debian/patches/series
index 5a76d00..43899e0 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,2 @@
-0001-Update-version-to-reflect-package-version.patch
-0002-Disable-test-not-working-on-i386.patch
-0003-Disable-stack-protector-in-runtime-library.patch
+0001-Disable-test-not-working-on-i386.patch
+0002-Disable-stack-protector-in-runtime-library.patch
diff --git a/elf.h b/elf.h
index d761747..9fed6eb 100644
--- a/elf.h
+++ b/elf.h
@@ -221,7 +221,7 @@ typedef struct
#define EM_68HC12 53 /* Motorola M68HC12 */
#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
#define EM_PCP 55 /* Siemens PCP */
-#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
+#define EM_NCPU 56 /* Sony nCPU embedded RISC */
#define EM_NDR1 57 /* Denso NDR1 microprocessor */
#define EM_STARCORE 58 /* Motorola Start*Core processor */
#define EM_ME16 59 /* Toyota ME16 processor */
@@ -232,7 +232,7 @@ typedef struct
#define EM_FX66 66 /* Siemens FX66 microcontroller */
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
-#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
+#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
@@ -342,7 +342,7 @@ typedef struct
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
-#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */
#define SHT_NUM 19 /* Number of defined types. */
#define SHT_LOOS 0x60000000 /* Start OS-specific. */
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
@@ -376,6 +376,7 @@ typedef struct
required */
#define SHF_GROUP (1 << 9) /* Section is member of a group. */
#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
+#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
#define SHF_ORDERED (1 << 30) /* Special ordering requirement
@@ -816,7 +817,7 @@ typedef struct
#define DF_1_EDITED 0x00200000 /* Object is modified after built. */
#define DF_1_NORELOC 0x00400000
#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
-#define DF_1_GLOBAUDIT 0x01000000 /* Global auditin required. */
+#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
/* Flags for the feature selection in DT_FEATURE_1. */
@@ -870,7 +871,7 @@ typedef struct
#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
-/* Auxialiary version information. */
+/* Auxiliary version information. */
typedef struct
{
@@ -1312,7 +1313,7 @@ typedef struct
#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
-#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
+#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */
#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */
@@ -1775,9 +1776,9 @@ typedef Elf32_Addr Elf32_Conflict;
#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
-/* Additional section indeces. */
+/* Additional section indices. */
-#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tentatively declared
symbols in ANSI C. */
#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
@@ -1956,7 +1957,7 @@ typedef Elf32_Addr Elf32_Conflict;
/* Legal values for sh_type field of Elf64_Shdr. */
-/* These two are primerily concerned with ECOFF debugging info. */
+/* These two are primarily concerned with ECOFF debugging info. */
#define SHT_ALPHA_DEBUG 0x70000001
#define SHT_ALPHA_REGINFO 0x70000002
diff --git a/examples/ex3.c b/examples/ex3.c
index 7c466ad..5556a4b 100644
--- a/examples/ex3.c
+++ b/examples/ex3.c
@@ -1,5 +1,4 @@
-#include <stdlib.h>
-#include <stdio.h>
+#include <tcclib.h>
int fib(n)
{
diff --git a/i386-asm.c b/i386-asm.c
index 5011af5..55c95af 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -42,6 +42,7 @@
#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i))
#define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */
+#define OPC_48 0x200 /* Always has REX prefix */
#ifdef TCC_TARGET_X86_64
# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
@@ -220,11 +221,11 @@ static const uint8_t segment_prefixes[] = {
static const ASMInstr asm_instrs[] = {
#define ALT(x) x
/* This removes a 0x0f in the second byte */
-#define O(o) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))
+#define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o)))
/* This constructs instr_type from opcode, type and group. */
#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0))
#define DEF_ASM_OP0(name, opcode)
-#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0 },
+#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } },
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }},
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }},
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }},
@@ -277,7 +278,7 @@ static inline int get_reg_shift(TCCState *s1)
}
#ifdef TCC_TARGET_X86_64
-static int asm_parse_numeric_reg(int t, int *type)
+static int asm_parse_numeric_reg(int t, unsigned int *type)
{
int reg = -1;
if (t >= TOK_IDENT && t < tok_ident) {
@@ -316,7 +317,7 @@ static int asm_parse_numeric_reg(int t, int *type)
}
#endif
-static int asm_parse_reg(int *type)
+static int asm_parse_reg(unsigned int *type)
{
int reg = 0;
*type = 0;
@@ -452,7 +453,7 @@ static void parse_operand(TCCState *s1, Operand *op)
op->e.pcrel = 0;
}
if (tok == '(') {
- int type = 0;
+ unsigned int type = 0;
next();
if (tok != ',') {
op->reg = asm_parse_reg(&type);
@@ -499,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe)
static void gen_disp32(ExprValue *pe)
{
Sym *sym = pe->sym;
- if (sym && sym->r == cur_text_section->sh_num) {
+ ElfSym *esym = elfsym(sym);
+ if (esym && esym->st_shndx == cur_text_section->sh_num) {
/* same section: we can output an absolute value. Note
that the TCC compiler behaves differently here because
it always outputs a relocation to ease (future) code
elimination in the linker */
- gen_le32(pe->v + sym->jnext - ind - 4);
+ gen_le32(pe->v + esym->st_value - ind - 4);
} else {
if (sym && sym->type.t == VT_VOID) {
sym->type.t = VT_FUNC;
@@ -725,6 +727,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
s = 0; /* avoid warning */
+again:
/* optimize matching by using a lookup table (no hashing is needed
!) */
for(pa = asm_instrs; pa->sym != 0; pa++) {
@@ -755,8 +758,9 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
continue;
/* cmovxx is a test opcode but accepts multiple sizes.
- TCC doesn't accept the suffixed mnemonic, instead we
- simply force size autodetection always. */
+ The suffixes aren't encoded in the table, instead we
+ simply force size autodetection always and deal with suffixed
+ variants below when we don't find e.g. "cmovzl". */
if (pa->instr_type & OPC_WLX)
s = NBWLX - 1;
} else if (pa->instr_type & OPC_B) {
@@ -785,7 +789,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
should only be done if we really have an >32bit imm64, and that
is hardcoded. Ignore it here. */
if (pa->opcode == 0xb0 && ops[0].type != OP_IM64
- && ops[1].type == OP_REG64
+ && (ops[1].type & OP_REG) == OP_REG64
&& !(pa->instr_type & OPC_0F))
continue;
#endif
@@ -842,8 +846,16 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
tcc_error("bad operand with opcode '%s'",
get_tok_str(opcode, NULL));
} else {
- tcc_error("unknown opcode '%s'",
- get_tok_str(opcode, NULL));
+ /* Special case for cmovcc, we accept size suffixes but ignore
+ them, but we don't want them to blow up our tables. */
+ TokenSym *ts = table_ident[opcode - TOK_IDENT];
+ if (ts->len >= 6
+ && strchr("wlq", ts->str[ts->len-1])
+ && !memcmp(ts->str, "cmov", 4)) {
+ opcode = tok_alloc(ts->str, ts->len-1)->tok;
+ goto again;
+ }
+ tcc_error("unknown opcode '%s'", ts->str);
}
}
/* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
@@ -901,14 +913,16 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
g(0x66);
#ifdef TCC_TARGET_X86_64
rex64 = 0;
- if (s == 3 || (alltypes & OP_REG64)) {
+ if (pa->instr_type & OPC_48)
+ rex64 = 1;
+ else if (s == 3 || (alltypes & OP_REG64)) {
/* generate REX prefix */
int default64 = 0;
for(i = 0; i < nb_ops; i++) {
- if (op_type[i] == OP_REG64) {
+ if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) {
/* If only 64bit regs are accepted in one operand
this is a default64 instruction without need for
- REX prefixes. */
+ REX prefixes, except for movabs(0xb8). */
default64 = 1;
break;
}
@@ -1014,16 +1028,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
if (pa->instr_type & OPC_B)
v += s >= 1;
if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) {
- Sym *sym;
+ ElfSym *esym;
int jmp_disp;
/* see if we can really generate the jump with a byte offset */
- sym = ops[0].e.sym;
- if (!sym)
- goto no_short_jump;
- if (sym->r != cur_text_section->sh_num)
+ esym = elfsym(ops[0].e.sym);
+ if (!esym || esym->st_shndx != cur_text_section->sh_num)
goto no_short_jump;
- jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff);
+ jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff);
if (jmp_disp == (int8_t)jmp_disp) {
/* OK to generate jump */
ops[0].e.sym = 0;
@@ -1470,7 +1482,7 @@ ST_FUNC void subst_asm_operand(CString *add_str,
if (r & VT_SYM) {
const char *name = get_tok_str(sv->sym->v, NULL);
if (sv->sym->v >= SYM_FIRST_ANOM) {
- /* In case of anonymuous symbols ("L.42", used
+ /* In case of anonymous symbols ("L.42", used
for static data labels) we can't find them
in the C symbol table when later looking up
this name. So enter them now into the asm label
@@ -1685,7 +1697,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
int reg;
TokenSym *ts;
#ifdef TCC_TARGET_X86_64
- int type;
+ unsigned int type;
#endif
if (!strcmp(str, "memory") ||
diff --git a/i386-gen.c b/i386-gen.c
index a8c6f4a..b9c3599 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -23,6 +23,7 @@
/* number of available registers */
#define NB_REGS 5
#define NB_ASM_REGS 8
+#define CONFIG_TCC_ASM
/* a register can belong to several classes. The classes must be
sorted from more general to more precise (see gv2() code which does
@@ -70,16 +71,13 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
-
-#define psym oad
-
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#include "tcc.h"
/* define to 1/0 to [not] have EBX as 4th register */
-#define USE_EBX 1
+#define USE_EBX 0
ST_DATA const int reg_classes[NB_REGS] = {
/* eax */ RC_INT | RC_EAX,
@@ -100,6 +98,8 @@ static unsigned long func_bound_ind;
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);
@@ -145,41 +145,37 @@ ST_FUNC void gsym(int t)
gsym_addr(t, ind);
}
-/* psym is used to put an instruction with a data field which is a
- reference to a symbol. It is in fact the same as oad ! */
-#define psym oad
-
/* instruction + 4 bytes data. Return the address of the data */
-ST_FUNC int oad(int c, int s)
+static int oad(int c, int s)
{
- int ind1;
-
+ int t;
+ if (nocode_wanted)
+ return s;
o(c);
- ind1 = ind + 4;
- if (ind1 > cur_text_section->data_allocated)
- section_realloc(cur_text_section, ind1);
- write32le(cur_text_section->data + ind, s);
- s = ind;
- ind = ind1;
- return s;
+ t = ind;
+ gen_le32(s);
+ return t;
}
+/* generate jmp to a label */
+#define gjmp2(instr,lbl) oad(instr,lbl)
+
/* output constant with relocation if 'r & VT_SYM' is true */
-ST_FUNC void gen_addr32(int r, Sym *sym, long c)
+ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_32);
gen_le32(c);
}
-ST_FUNC void gen_addrpc32(int r, Sym *sym, long c)
+ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_PC32);
gen_le32(c - 4);
}
-/* generate a modrm reference. 'op_reg' contains the addtionnal 3
+/* generate a modrm reference. 'op_reg' contains the additional 3
opcode bits */
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
{
@@ -214,7 +210,7 @@ ST_FUNC void load(int r, SValue *sv)
#endif
fr = sv->r;
- ft = sv->type.t;
+ ft = sv->type.t & ~VT_DEFSIGN;
fc = sv->c.i;
ft &= ~(VT_VOLATILE | VT_CONSTANT);
@@ -334,6 +330,7 @@ static void gadd_sp(int val)
}
}
+#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_PE
static void gen_static_call(int v)
{
Sym *sym;
@@ -342,24 +339,24 @@ static void gen_static_call(int v)
oad(0xe8, -4);
greloc(cur_text_section, sym, ind-4, R_386_PC32);
}
+#endif
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
- if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
- int rt;
- /* constant case */
- if (vtop->r & VT_SYM) {
- /* relocation case */
- greloc(cur_text_section, vtop->sym,
- ind + 1, R_386_PC32);
- } else {
- /* put an empty PC32 relocation */
- put_elf_reloc(symtab_section, cur_text_section,
- ind + 1, R_386_PC32, 0);
- }
+ if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
+ /* constant and relocation case */
+ greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32);
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
+ } else {
+ /* otherwise, indirect call */
+ r = gv(RC_INT);
+ 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 */
@@ -384,11 +381,6 @@ static void gcall_or_jmp(int is_jmp)
default:
break;
}
- } else {
- /* otherwise, indirect call */
- r = gv(RC_INT);
- o(0xff); /* call/jmp *r */
- o(0xd0 + r + (is_jmp << 4));
}
}
@@ -401,21 +393,21 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int
{
#ifdef TCC_TARGET_PE
int size, align;
-
*ret_align = 1; // Never have to re-align return values for x86
*regsize = 4;
size = type_size(vt, &align);
- if (size > 8) {
+ if (size > 8 || (size & (size - 1)))
return 0;
- } else if (size > 4) {
- ret->ref = NULL;
+ if (size == 8)
ret->t = VT_LLONG;
- return 1;
- } else {
- ret->ref = NULL;
+ else if (size == 4)
ret->t = VT_INT;
- return 1;
- }
+ else if (size == 2)
+ ret->t = VT_SHORT;
+ else
+ ret->t = VT_BYTE;
+ ret->ref = NULL;
+ return 1;
#else
*ret_align = 1; // Never have to re-align return values for x86
return 0;
@@ -479,7 +471,7 @@ ST_FUNC void gfunc_call(int nb_args)
}
save_regs(0); /* save used temporary registers */
func_sym = vtop->type.ref;
- func_call = func_sym->a.func_call;
+ func_call = func_sym->f.func_call;
/* fast call case */
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
func_call == FUNC_FASTCALLW) {
@@ -506,7 +498,7 @@ ST_FUNC void gfunc_call(int nb_args)
#endif
gcall_or_jmp(0);
- if (args_size && func_call != FUNC_STDCALL)
+ if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
gadd_sp(args_size);
vtop--;
}
@@ -527,7 +519,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
CType *type;
sym = func_type->ref;
- func_call = sym->a.func_call;
+ func_call = sym->f.func_call;
addr = 8;
loc = 0;
func_vc = 0;
@@ -549,10 +541,11 @@ ST_FUNC 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->c == FUNC_ELLIPSIS);
+ 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) && (size > 8)) {
+ if (((func_vt.t & VT_BTYPE) == VT_STRUCT)
+ && (size > 8 || (size & (size - 1)))) {
#else
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
#endif
@@ -587,8 +580,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
param_index++;
}
func_ret_sub = 0;
- /* pascal type call ? */
- if (func_call == FUNC_STDCALL)
+ /* pascal type call or fastcall ? */
+ if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW)
func_ret_sub = addr - 8;
#ifndef TCC_TARGET_PE
else if (func_vc)
@@ -641,7 +634,15 @@ ST_FUNC void gfunc_epilog(void)
o(0x585a); /* restore returned value, if any */
}
#endif
- o(0x5b * USE_EBX); /* pop ebx */
+
+ /* align local size to word & save local variables */
+ v = (-loc + 3) & -4;
+
+#if USE_EBX
+ o(0x8b);
+ gen_modrm(TREG_EBX, VT_LOCAL, NULL, -(v+4));
+#endif
+
o(0xc9); /* leave */
if (func_ret_sub == 0) {
o(0xc3); /* ret */
@@ -650,9 +651,6 @@ ST_FUNC void gfunc_epilog(void)
g(func_ret_sub);
g(func_ret_sub >> 8);
}
- /* align local size to word & save local variables */
-
- v = (-loc + 3) & -4;
saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
#ifdef TCC_TARGET_PE
@@ -676,7 +674,7 @@ ST_FUNC void gfunc_epilog(void)
/* generate a jump to a label */
ST_FUNC int gjmp(int t)
{
- return psym(0xe9, t);
+ return gjmp2(0xe9, t);
}
/* generate a jump to a fixed address */
@@ -722,10 +720,12 @@ ST_FUNC void gtst_addr(int inv, int a)
ST_FUNC int gtst(int inv, int t)
{
int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP) {
+ if (nocode_wanted) {
+ ;
+ } else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
g(0x0f);
- t = psym((vtop->c.i - 16) ^ inv, t);
+ t = gjmp2((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
@@ -887,7 +887,7 @@ ST_FUNC void gen_opi(int op)
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
- two operands are guaranted to have the same floating point type */
+ two operands are guaranteed to have the same floating point type */
/* XXX: need to use ST1 too */
ST_FUNC void gen_opf(int op)
{
@@ -1035,15 +1035,6 @@ ST_FUNC void gen_cvt_itof(int t)
/* convert fp to int 't' type */
ST_FUNC void gen_cvt_ftoi(int t)
{
-#if 1
- gv(RC_FLOAT);
- save_reg(TREG_EAX);
- save_reg(TREG_EDX);
- gen_static_call(TOK___tcc_cvt_ftol);
- vtop->r = TREG_EAX; /* mark reg as used */
- if (t == VT_LLONG)
- vtop->r2 = TREG_EDX;
-#else
int bt = vtop->type.t & VT_BTYPE;
if (bt == VT_FLOAT)
vpush_global_sym(&func_old_type, TOK___fixsfdi);
@@ -1056,7 +1047,6 @@ ST_FUNC void gen_cvt_ftoi(int t)
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = REG_LRET;
-#endif
}
/* convert from one floating point type to another */
diff --git a/i386-link.c b/i386-link.c
index c098172..aea3c21 100644
--- a/i386-link.c
+++ b/i386-link.c
@@ -8,6 +8,7 @@
#define R_JMP_SLOT R_386_JMP_SLOT
#define R_GLOB_DAT R_386_GLOB_DAT
#define R_COPY R_386_COPY
+#define R_RELATIVE R_386_RELATIVE
#define R_NUM R_386_NUM
@@ -48,7 +49,7 @@ int code_reloc (int reloc_type)
return -1;
}
-/* Returns an enumerator to describe wether and when the relocation needs a
+/* 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)
@@ -56,12 +57,17 @@ int gotplt_entry_type (int reloc_type)
switch (reloc_type) {
case R_386_RELATIVE:
case R_386_16:
- case R_386_32:
case R_386_GLOB_DAT:
case R_386_JMP_SLOT:
case R_386_COPY:
return NO_GOTPLT_ENTRY;
+ case R_386_32:
+ /* This relocations shouldn't normally need GOT or PLT
+ slots if it weren't for simplicity in the code generator.
+ See our caller for comments. */
+ return AUTO_GOTPLT_ENTRY;
+
case R_386_PC16:
case R_386_PC32:
return AUTO_GOTPLT_ENTRY;
@@ -93,7 +99,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
else
modrm = 0x25;
- /* empty PLT: create PLT0 entry that pushes the library indentifier
+ /* empty PLT: create PLT0 entry that pushes the library identifier
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
(GOT + 2 * PTR_SIZE) */
if (plt->data_offset == 0) {
@@ -154,7 +160,7 @@ void relocate_init(Section *sr)
qrel = (ElfW_Rel *) sr->data;
}
-void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
+void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
int sym_index, esym_index;
@@ -220,12 +226,15 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
write16le(ptr, read16le(ptr) + val - addr);
return;
case R_386_RELATIVE:
+#ifdef TCC_TARGET_PE
+ add32le(ptr, val - s1->pe_imagebase);
+#endif
/* do nothing */
return;
case R_386_COPY:
- /* This reloction must copy initialized data from the library
+ /* This relocation must copy initialized data from the library
to the program .bss segment. Currently made like for ARM
- (to remove noise of defaukt case). Is this true?
+ (to remove noise of default case). Is this true?
*/
return;
default:
diff --git a/il-gen.c b/il-gen.c
index cf3aff5..bb670cc 100644
--- a/il-gen.c
+++ b/il-gen.c
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#error this code has bit-rotted since 2003
+
/* number of available registers */
#define NB_REGS 3
@@ -600,7 +602,7 @@ void gen_opi(int op)
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
- two operands are guaranted to have the same floating point type */
+ two operands are guaranteed to have the same floating point type */
void gen_opf(int op)
{
/* same as integer */
diff --git a/include/stddef.h b/include/stddef.h
index 791ba31..694d503 100644
--- a/include/stddef.h
+++ b/include/stddef.h
@@ -13,12 +13,20 @@ typedef __SIZE_TYPE__ uintptr_t;
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
+#ifdef __LP64__
+typedef signed long int int64_t;
+#else
typedef signed long long int int64_t;
+#endif
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
+#ifdef __LP64__
+typedef unsigned long int uint64_t;
+#else
typedef unsigned long long int uint64_t;
#endif
+#endif
#ifndef NULL
#define NULL ((void*)0)
diff --git a/lib/Makefile b/lib/Makefile
index 79891d4..385ffae 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,109 +5,70 @@
TOP = ..
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
-ifndef TARGET
- # we're building the native libtcc1.a
- ifdef CONFIG_WIN32
- ifeq ($(ARCH),x86-64)
- TARGET = x86_64-win32
- else
- TARGET = i386-win32
- endif
- # using tcc
- else ifeq ($(ARCH),i386)
- TARGET = i386
- XCC = $(CC) # using gcc
- else ifeq ($(ARCH),x86-64)
- TARGET = x86_64
- XCC = $(CC) # using gcc
- else ifeq ($(ARCH),arm)
- TARGET = arm
- XCC = $(CC) # using gcc
- else ifeq ($(ARCH),arm64)
- TARGET = arm64
- endif
- BCHECK_O = bcheck.o
-endif
-
-DIR = $(TARGET)
+XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
+XCC = $(XTCC)
+XAR = $(XTCC) -ar
+XFLAGS-unx = -B$(TOPSRC)
+XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
+XFLAGS = $(XFLAGS$(XCFG))
+XCFG = $(or $(findstring -win,$T),-unx)
-native : ../libtcc1.a
-cross : $(DIR)/libtcc1.a
-
-native : TCC = $(TOP)/tcc$(EXESUF)
-cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF)
-
-I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
-X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BCHECK_O)
-ARM_O = libtcc1.o armeabi.o alloca-arm.o
-ARM64_O = lib-arm64.o
-WIN32_O = crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
+# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
+arm-libtcc1-usegcc ?= no
CFLAGS:=$(filter-out -fstack-protector%,$(CFLAGS))
-# build TCC runtime library to contain PIC code, so it can be linked
-# into shared libraries
-PICFLAGS = -fPIC
-
-ifeq "$(TARGET)" "i386-win32"
- OBJ = $(addprefix $(DIR)/,$(I386_O) $(WIN32_O))
- TGT = -DTCC_TARGET_I386 -DTCC_TARGET_PE
- XCC = $(TCC) -B$(TOPSRC)/win32 -I$(TOPSRC)/include
- XAR = $(DIR)/tiny_libmaker$(EXESUF)
- XFLAGS = $(TGT)
-else ifeq "$(TARGET)" "x86_64-win32"
- OBJ = $(addprefix $(DIR)/,$(X86_64_O) $(WIN32_O))
- TGT = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
- XCC = $(TCC) -B$(TOPSRC)/win32 -I$(TOPSRC)/include
- XAR = $(DIR)/tiny_libmaker$(EXESUF)
- XFLAGS = $(TGT)
-else ifeq "$(TARGET)" "i386"
- OBJ = $(addprefix $(DIR)/,$(I386_O))
- TGT = -DTCC_TARGET_I386
- XCC ?= $(TCC) -B$(TOPSRC)
-else ifeq "$(TARGET)" "x86_64"
- OBJ = $(addprefix $(DIR)/,$(X86_64_O))
- TGT = -DTCC_TARGET_X86_64
- XCC ?= $(TCC) -B$(TOPSRC)
-else ifeq "$(TARGET)" "arm"
- OBJ = $(addprefix $(DIR)/,$(ARM_O))
- TGT = -DTCC_TARGET_ARM
- XCC ?= $(TCC) -B$(TOPSRC)
-else ifeq "$(TARGET)" "arm64"
- OBJ = $(addprefix $(DIR)/,$(ARM64_O))
- TGT = -DTCC_TARGET_ARM64
- XCC ?= $(TCC) -B$(TOPSRC)
-else
- $(error libtcc1.a not supported on target '$(TARGET)')
+ifeq "$($(T)-libtcc1-usegcc)" "yes"
+ XCC = $(CC)
+ XAR = $(AR)
+ XFLAGS = $(CFLAGS) -fPIC
endif
-XFLAGS ?= $(CFLAGS) $(PICFLAGS) $(TGT)
+# only for native compiler
+$(X)BCHECK_O = bcheck.o
-ifeq ($(TARGETOS),Darwin)
- XAR = $(DIR)/tiny_libmaker$(EXESUF)
- XFLAGS += -D_ANSI_SOURCE
+ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
BCHECK_O =
endif
-ifdef XAR
-AR = $(XAR)
+ifdef CONFIG_OSX
+ XFLAGS += -D_ANSI_SOURCE
endif
-$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR)
- $(AR) rcs $@ $(OBJ)
-$(DIR)/%.o : %.c
- $(XCC) -c $< -o $@ $(XFLAGS)
-$(DIR)/%.o : %.S
+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
+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-arm-wince = $(ARM_O) $(WIN_O)
+
+$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
+ $(XAR) rcs $@ $^
+
+$(X)%.o : %.c
$(XCC) -c $< -o $@ $(XFLAGS)
-# windows : utilities
-$(DIR)/tiny_%$(EXESUF) : $(TOPSRC)/win32/tools/tiny_%.c
- $(CC) -o $@ $< $(CFLAGS) $(LDFLAGS) $(TGT)
-$(OBJ) $(XAR) : $(DIR)/exists
+$(X)%.o : %.S
+ $(XCC) -c $< -o $@ $(XFLAGS)
-%/exists :
- mkdir -p $(DIR)
- @echo $@ > $@
+$(X)crt1w.o : crt1.c
+$(X)wincrt1w.o : wincrt1.c
clean :
- rm -rf i386-win32 x86_64-win32 i386 x86_64 arm arm64
+ rm -f *.a *.o $(BIN)
diff --git a/lib/alloca-arm.S b/lib/alloca-arm.S
index 9deae63..68556e3 100644
--- a/lib/alloca-arm.S
+++ b/lib/alloca-arm.S
@@ -3,9 +3,15 @@
.global alloca
.type alloca, %function
alloca:
+#ifdef __TINYC__
+ .int 0xe060d00d
+ .int 0xe3cdd007
+ .int 0xe1a0000d
+ .int 0xe1a0f00e
+#else
rsb sp, r0, sp
bic sp, sp, #7
mov r0, sp
mov pc, lr
+#endif
.size alloca, .-alloca
- .section .note.GNU-stack,"",%progbits
diff --git a/lib/alloca86-bt.S b/lib/alloca86-bt.S
index 5215505..4f95cf1 100644
--- a/lib/alloca86-bt.S
+++ b/lib/alloca86-bt.S
@@ -11,7 +11,7 @@ __bound_alloca:
and $-4,%eax
jz p6
-#ifdef TCC_TARGET_PE
+#ifdef _WIN32
p4:
cmp $4096,%eax
jbe p5
diff --git a/lib/alloca86.S b/lib/alloca86.S
index a17e07f..bb7a2c2 100644
--- a/lib/alloca86.S
+++ b/lib/alloca86.S
@@ -10,7 +10,7 @@ alloca:
and $-4,%eax
jz p3
-#ifdef TCC_TARGET_PE
+#ifdef _WIN32
p1:
cmp $4096,%eax
jbe p2
@@ -28,8 +28,4 @@ p3:
push %edx
ret
-/* mark stack as nonexecutable */
-#if defined __ELF__ && defined __linux__
- .section .note.GNU-stack,"",@progbits
-#endif
/* ---------------------------------------------- */
diff --git a/lib/alloca86_64-bt.S b/lib/alloca86_64-bt.S
index 1f196bb..4cbad90 100644
--- a/lib/alloca86_64-bt.S
+++ b/lib/alloca86_64-bt.S
@@ -4,7 +4,7 @@
.globl __bound_alloca
__bound_alloca:
-#ifdef TCC_TARGET_PE
+#ifdef _WIN32
# bound checking is not implemented
pop %rdx
mov %rcx,%rax
@@ -53,8 +53,4 @@ p3:
ret
#endif
-/* mark stack as nonexecutable */
-#if defined __ELF__ && defined __linux__
- .section .note.GNU-stack,"",@progbits
-#endif
/* ---------------------------------------------- */
diff --git a/lib/alloca86_64.S b/lib/alloca86_64.S
index 4a74104..ae3c97d 100644
--- a/lib/alloca86_64.S
+++ b/lib/alloca86_64.S
@@ -5,7 +5,7 @@
alloca:
pop %rdx
-#ifdef TCC_TARGET_PE
+#ifdef _WIN32
mov %rcx,%rax
#else
mov %rdi,%rax
@@ -14,7 +14,7 @@ alloca:
and $-16,%rax
jz p3
-#ifdef TCC_TARGET_PE
+#ifdef _WIN32
p1:
cmp $4096,%rax
jbe p2
@@ -27,16 +27,8 @@ p2:
sub %rax,%rsp
mov %rsp,%rax
-#ifdef TCC_TARGET_PE
- add $32,%rax
-#endif
-
p3:
push %rdx
ret
-/* mark stack as nonexecutable */
-#if defined __ELF__ && defined __linux__
- .section .note.GNU-stack,"",@progbits
-#endif
/* ---------------------------------------------- */
diff --git a/lib/armeabi.c b/lib/armeabi.c
index b12d164..a59640d 100644
--- a/lib/armeabi.c
+++ b/lib/armeabi.c
@@ -19,7 +19,19 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
+#ifdef __TINYC__
+#define INT_MIN (-2147483647 - 1)
+#define INT_MAX 2147483647
+#define UINT_MAX 0xffffffff
+#define LONG_MIN (-2147483647L - 1)
+#define LONG_MAX 2147483647L
+#define ULONG_MAX 0xffffffffUL
+#define LLONG_MAX 9223372036854775807LL
+#define LLONG_MIN (-9223372036854775807LL - 1)
+#define ULLONG_MAX 0xffffffffffffffffULL
+#else
#include <limits.h>
+#endif
/* We rely on the little endianness and EABI calling convention for this to
work */
diff --git a/lib/armflush.c b/lib/armflush.c
new file mode 100644
index 0000000..eae3260
--- /dev/null
+++ b/lib/armflush.c
@@ -0,0 +1,58 @@
+/* armflush.c - flush the instruction cache
+
+ __clear_cache is used in tccrun.c, It is a built-in
+ intrinsic with gcc. However tcc in order to compile
+ itself needs this function */
+
+#ifdef __TINYC__
+
+/* syscall wrapper */
+unsigned syscall(unsigned syscall_nr, ...);
+
+/* arm-tcc supports only fake asm currently */
+__asm__(
+ ".global syscall\n"
+ "syscall:\n"
+ ".int 0xe92d4080\n" // push {r7, lr}
+ ".int 0xe1a07000\n" // mov r7, r0
+ ".int 0xe1a00001\n" // mov r0, r1
+ ".int 0xe1a01002\n" // mov r1, r2
+ ".int 0xe1a02003\n" // mov r2, r3
+ ".int 0xef000000\n" // svc 0x00000000
+ ".int 0xe8bd8080\n" // pop {r7, pc}
+ );
+
+/* from unistd.h: */
+#if defined(__thumb__) || defined(__ARM_EABI__)
+# define __NR_SYSCALL_BASE 0x0
+#else
+# define __NR_SYSCALL_BASE 0x900000
+#endif
+#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
+#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+
+#else
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+
+#endif
+
+/* Flushing for tccrun */
+void __clear_cache(void *beginning, void *end)
+{
+/* __ARM_NR_cacheflush is kernel private and should not be used in user space.
+ * However, there is no ARM asm parser in tcc so we use it for now */
+#if 1
+ syscall(__ARM_NR_cacheflush, beginning, end, 0);
+#else
+ __asm__ ("push {r7}\n\t"
+ "mov r7, #0xf0002\n\t"
+ "mov r2, #0\n\t"
+ "swi 0\n\t"
+ "pop {r7}\n\t"
+ "ret");
+#endif
+}
diff --git a/lib/bcheck.c b/lib/bcheck.c
index d3b9955..90f0ad2 100644
--- a/lib/bcheck.c
+++ b/lib/bcheck.c
@@ -21,10 +21,15 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
-#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) \
- && !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+
+#if !defined(__FreeBSD__) \
+ && !defined(__FreeBSD_kernel__) \
+ && !defined(__DragonFly__) \
+ && !defined(__OpenBSD__) \
+ && !defined(__NetBSD__)
#include <malloc.h>
#endif
+
#if !defined(_WIN32)
#include <unistd.h>
#endif
@@ -45,11 +50,14 @@
#define CONFIG_TCC_MALLOC_HOOKS
#define HAVE_MEMALIGN
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
- || defined(__DragonFly__) || defined(__dietlibc__) \
- || defined(__UCLIBC__) || defined(__OpenBSD__) || defined(__NetBSD__) \
- || defined(_WIN32) || defined(TCC_UCLIBC)
-#warning Bound checking does not support malloc (etc.) in this environment.
+#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
@@ -236,7 +244,7 @@ BOUND_PTR_INDIR(16)
#if defined(__GNUC__) && (__GNUC__ >= 6)
/*
- * At least gcc 6.2 complains when __builtin_frame_address is used whith
+ * At least gcc 6.2 complains when __builtin_frame_address is used with
* nonzero argument.
*/
#pragma GCC diagnostic push
diff --git a/lib/lib-arm64.c b/lib/lib-arm64.c
index 42d5936..b8fd9e8 100644
--- a/lib/lib-arm64.c
+++ b/lib/lib-arm64.c
@@ -9,8 +9,20 @@
* without any warranty.
*/
+#ifdef __TINYC__
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned uint32_t;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+void *memcpy(void*,void*,__SIZE_TYPE__);
+#else
#include <stdint.h>
#include <string.h>
+#endif
void __clear_cache(void *beg, void *end)
{
diff --git a/lib/libtcc1.c b/lib/libtcc1.c
index c3ff7fe..0e46618 100644
--- a/lib/libtcc1.c
+++ b/lib/libtcc1.c
@@ -107,10 +107,10 @@ union float_long {
};
/* XXX: we don't support several builtin supports for now */
-#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
+#if !defined __x86_64__ && !defined __arm__
/* XXX: use gcc/tcc intrinsic ? */
-#if defined(TCC_TARGET_I386)
+#if defined __i386__
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
: "=r" ((USItype) (sh)), \
@@ -478,18 +478,6 @@ long long __ashldi3(long long a, int b)
#endif
}
-long long __tcc_cvt_ftol(long double x)
-{
- unsigned c0, c1;
- long long ret;
- __asm__ __volatile__ ("fnstcw %0" : "=m" (c0));
- c1 = c0 | 0x0C00;
- __asm__ __volatile__ ("fldcw %0" : : "m" (c1));
- __asm__ __volatile__ ("fistpll %0" : "=m" (ret));
- __asm__ __volatile__ ("fldcw %0" : : "m" (c0));
- return ret;
-}
-
#endif /* !__x86_64__ */
/* XXX: fix tcc's code generator to do this instead */
@@ -562,6 +550,13 @@ unsigned long long __fixunssfdi (float a1)
return 0;
}
+long long __fixsfdi (float a1)
+{
+ long long ret; int s;
+ ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
+ return s ? ret : -ret;
+}
+
unsigned long long __fixunsdfdi (double a1)
{
register union double_long dl1;
@@ -587,6 +582,14 @@ unsigned long long __fixunsdfdi (double a1)
return 0;
}
+long long __fixdfdi (double a1)
+{
+ long long ret; int s;
+ ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
+ return s ? ret : -ret;
+}
+
+#ifndef __arm__
unsigned long long __fixunsxfdi (long double a1)
{
register union ldouble_long dl1;
@@ -610,121 +613,10 @@ unsigned long long __fixunsxfdi (long double a1)
return 0;
}
-long long __fixsfdi (float a1)
-{
- long long ret; int s;
- ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
- return s ? ret : -ret;
-}
-
-long long __fixdfdi (double a1)
-{
- long long ret; int s;
- ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
- return s ? ret : -ret;
-}
-
long long __fixxfdi (long double a1)
{
long long ret; int s;
ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1);
return s ? ret : -ret;
}
-
-#if defined(TCC_TARGET_X86_64) && !defined(_WIN64)
-
-#ifndef __TINYC__
-# include <stdlib.h>
-# include <stdio.h>
-# include <string.h>
-# undef __va_start
-# undef __va_arg
-# undef __va_copy
-# undef __va_end
-#else
-/* 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);
-#endif
-
-/* This should be in sync with our include/stdarg.h */
-enum __va_arg_type {
- __va_gen_reg, __va_float_reg, __va_stack
-};
-
-/* GCC compatible definition of va_list. */
-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;
-
-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,
- int size, int align)
-{
- size = (size + 7) & ~7;
- align = (align + 7) & ~7;
- switch (arg_type) {
- case __va_gen_reg:
- if (ap->gp_offset + size <= 48) {
- ap->gp_offset += size;
- return ap->reg_save_area + ap->gp_offset - size;
- }
- goto use_overflow_area;
-
- case __va_float_reg:
- if (ap->fp_offset < 128 + 48) {
- ap->fp_offset += 16;
- return ap->reg_save_area + ap->fp_offset - 16;
- }
- size = 8;
- goto use_overflow_area;
-
- case __va_stack:
- use_overflow_area:
- ap->overflow_arg_area += size;
- ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
- return ap->overflow_arg_area - size;
-
- default: /* should never happen */
- abort();
- }
-}
-#endif /* __x86_64__ */
-
-#ifdef TCC_TARGET_ARM
-#define _GNU_SOURCE
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <stdio.h>
-
-/* Flushing for tccrun */
-void __clear_cache(void *beginning, void *end)
-{
-/* __ARM_NR_cacheflush is kernel private and should not be used in user space.
- * However, there is no ARM asm parser in tcc so we use it for now */
-#if 1
- syscall(__ARM_NR_cacheflush, beginning, end, 0);
-#else
- __asm__ ("push {r7}\n\t"
- "mov r7, #0xf0002\n\t"
- "mov r2, #0\n\t"
- "swi 0\n\t"
- "pop {r7}\n\t"
- "ret");
-#endif
-}
-#endif /* arm */
+#endif /* !ARM */
diff --git a/lib/va_list.c b/lib/va_list.c
new file mode 100644
index 0000000..8749f46
--- /dev/null
+++ b/lib/va_list.c
@@ -0,0 +1,65 @@
+/* va_list.c - tinycc support for va_list on X86_64 */
+
+#if defined __x86_64__
+
+/* Avoid include files, they may not be available when cross compiling */
+extern void *memset(void *s, int c, __SIZE_TYPE__ n);
+extern void abort(void);
+
+/* This should be in sync with our include/stdarg.h */
+enum __va_arg_type {
+ __va_gen_reg, __va_float_reg, __va_stack
+};
+
+/* GCC compatible definition of va_list. */
+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;
+
+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,
+ int size, int align)
+{
+ size = (size + 7) & ~7;
+ align = (align + 7) & ~7;
+ switch (arg_type) {
+ case __va_gen_reg:
+ if (ap->gp_offset + size <= 48) {
+ ap->gp_offset += size;
+ return ap->reg_save_area + ap->gp_offset - size;
+ }
+ goto use_overflow_area;
+
+ case __va_float_reg:
+ if (ap->fp_offset < 128 + 48) {
+ ap->fp_offset += 16;
+ return ap->reg_save_area + ap->fp_offset - 16;
+ }
+ size = 8;
+ goto use_overflow_area;
+
+ case __va_stack:
+ use_overflow_area:
+ ap->overflow_arg_area += size;
+ ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
+ return ap->overflow_arg_area - size;
+
+ default: /* should never happen */
+ abort();
+ }
+}
+#endif
diff --git a/libtcc.c b/libtcc.c
index 68c3f9d..1e9dd97 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -32,9 +32,11 @@ ST_DATA int tcc_ext = 1;
/* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state;
+static int nb_states;
+
/********************************************************/
-#ifdef ONE_SOURCE
+#if ONE_SOURCE
#include "tccpp.c"
#include "tccgen.c"
#include "tccelf.c"
@@ -42,10 +44,12 @@ ST_DATA struct TCCState *tcc_state;
#ifdef TCC_TARGET_I386
#include "i386-gen.c"
#include "i386-link.c"
+#include "i386-asm.c"
#endif
#ifdef TCC_TARGET_ARM
#include "arm-gen.c"
#include "arm-link.c"
+#include "arm-asm.c"
#endif
#ifdef TCC_TARGET_ARM64
#include "arm64-gen.c"
@@ -54,19 +58,15 @@ ST_DATA struct TCCState *tcc_state;
#ifdef TCC_TARGET_C67
#include "c67-gen.c"
#include "c67-link.c"
+#include "tcccoff.c"
#endif
#ifdef TCC_TARGET_X86_64
#include "x86_64-gen.c"
#include "x86_64-link.c"
+#include "i386-asm.c"
#endif
#ifdef CONFIG_TCC_ASM
#include "tccasm.c"
-#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
-#include "i386-asm.c"
-#endif
-#endif
-#ifdef TCC_TARGET_COFF
-#include "tcccoff.c"
#endif
#ifdef TCC_TARGET_PE
#include "tccpe.c"
@@ -104,10 +104,8 @@ static void tcc_set_lib_path_w32(TCCState *s)
char path[1024], *p;
GetModuleFileNameA(tcc_module, path, sizeof path);
p = tcc_basename(normalize_slashes(strlwr(path)));
- if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
- p -= 5;
- else if (p > path)
- p--;
+ if (p > path)
+ --p;
*p = 0;
tcc_set_lib_path(s, path);
}
@@ -133,7 +131,7 @@ BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
/********************************************************/
/* copy a string and truncate it. */
-PUB_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
+ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
{
char *q, *q_end;
int c;
@@ -153,7 +151,7 @@ PUB_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
}
/* strcat and truncate. */
-PUB_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
+ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
{
int len;
len = strlen(buf);
@@ -162,7 +160,7 @@ PUB_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
return buf;
}
-PUB_FUNC char *pstrncpy(char *out, const char *in, size_t num)
+ST_FUNC char *pstrncpy(char *out, const char *in, size_t num)
{
memcpy(out, in, num);
out[num] = '\0';
@@ -237,7 +235,7 @@ PUB_FUNC char *tcc_strdup(const char *str)
return ptr;
}
-PUB_FUNC void tcc_memstats(int bench)
+PUB_FUNC void tcc_memcheck(void)
{
}
@@ -245,94 +243,96 @@ PUB_FUNC void tcc_memstats(int bench)
#define MEM_DEBUG_MAGIC1 0xFEEDDEB1
#define MEM_DEBUG_MAGIC2 0xFEEDDEB2
-#define MEM_DEBUG_FILE_LEN 15
+#define MEM_DEBUG_MAGIC3 0xFEEDDEB3
+#define MEM_DEBUG_FILE_LEN 40
+#define MEM_DEBUG_CHECK3(header) \
+ ((mem_debug_header_t*)((char*)header + header->size))->magic3
+#define MEM_USER_PTR(header) \
+ ((char *)header + offsetof(mem_debug_header_t, magic3))
+#define MEM_HEADER_PTR(ptr) \
+ (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3))
struct mem_debug_header {
- size_t magic1;
- size_t size;
+ unsigned magic1;
+ unsigned size;
struct mem_debug_header *prev;
struct mem_debug_header *next;
- size_t line_num;
- char file_name[MEM_DEBUG_FILE_LEN + 1];
- size_t magic2;
+ int line_num;
+ char file_name[MEM_DEBUG_FILE_LEN + 1];
+ unsigned magic2;
+ ALIGNED(16) unsigned magic3;
};
typedef struct mem_debug_header mem_debug_header_t;
static mem_debug_header_t *mem_debug_chain;
-static size_t mem_cur_size;
-static size_t mem_max_size;
+static unsigned mem_cur_size;
+static unsigned mem_max_size;
+
+static mem_debug_header_t *malloc_check(void *ptr, const char *msg)
+{
+ mem_debug_header_t * header = MEM_HEADER_PTR(ptr);
+ if (header->magic1 != MEM_DEBUG_MAGIC1 ||
+ header->magic2 != MEM_DEBUG_MAGIC2 ||
+ MEM_DEBUG_CHECK3(header) != MEM_DEBUG_MAGIC3 ||
+ header->size == (unsigned)-1) {
+ fprintf(stderr, "%s check failed\n", msg);
+ if (header->magic1 == MEM_DEBUG_MAGIC1)
+ fprintf(stderr, "%s:%u: block allocated here.\n",
+ header->file_name, header->line_num);
+ exit(1);
+ }
+ return header;
+}
PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
{
- void *ptr;
int ofs;
-
mem_debug_header_t *header;
- ptr = malloc(sizeof(mem_debug_header_t) + size);
- if (!ptr)
+ header = malloc(sizeof(mem_debug_header_t) + size);
+ if (!header)
tcc_error("memory full (malloc)");
- mem_cur_size += size;
- if (mem_cur_size > mem_max_size)
- mem_max_size = mem_cur_size;
-
- header = (mem_debug_header_t *)ptr;
-
header->magic1 = MEM_DEBUG_MAGIC1;
header->magic2 = MEM_DEBUG_MAGIC2;
header->size = size;
+ MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
header->line_num = line;
-
ofs = strlen(file) - MEM_DEBUG_FILE_LEN;
strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);
header->file_name[MEM_DEBUG_FILE_LEN] = 0;
header->next = mem_debug_chain;
header->prev = NULL;
-
if (header->next)
header->next->prev = header;
-
mem_debug_chain = header;
- ptr = (char *)ptr + sizeof(mem_debug_header_t);
- return ptr;
+ mem_cur_size += size;
+ if (mem_cur_size > mem_max_size)
+ mem_max_size = mem_cur_size;
+
+ return MEM_USER_PTR(header);
}
PUB_FUNC void tcc_free_debug(void *ptr)
{
mem_debug_header_t *header;
-
if (!ptr)
return;
-
- ptr = (char *)ptr - sizeof(mem_debug_header_t);
- header = (mem_debug_header_t *)ptr;
- if (header->magic1 != MEM_DEBUG_MAGIC1 ||
- header->magic2 != MEM_DEBUG_MAGIC2 ||
- header->size == (size_t)-1 )
- {
- tcc_error("tcc_free check failed");
- }
-
+ header = malloc_check(ptr, "tcc_free");
mem_cur_size -= header->size;
- header->size = (size_t)-1;
-
+ header->size = (unsigned)-1;
if (header->next)
header->next->prev = header->prev;
-
if (header->prev)
header->prev->next = header->next;
-
if (header == mem_debug_chain)
mem_debug_chain = header->next;
-
- free(ptr);
+ free(header);
}
-
PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line)
{
void *ptr;
@@ -345,52 +345,26 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
{
mem_debug_header_t *header;
int mem_debug_chain_update = 0;
-
- if (!ptr) {
- ptr = tcc_malloc_debug(size, file, line);
- return ptr;
- }
-
- ptr = (char *)ptr - sizeof(mem_debug_header_t);
- header = (mem_debug_header_t *)ptr;
- if (header->magic1 != MEM_DEBUG_MAGIC1 ||
- header->magic2 != MEM_DEBUG_MAGIC2 ||
- header->size == (size_t)-1 )
- {
- check_error:
- tcc_error("tcc_realloc check failed");
- }
-
- mem_debug_chain_update = (header == mem_debug_chain);
-
- mem_cur_size -= header->size;
- ptr = realloc(ptr, sizeof(mem_debug_header_t) + size);
if (!ptr)
+ return tcc_malloc_debug(size, file, line);
+ header = malloc_check(ptr, "tcc_realloc");
+ mem_cur_size -= header->size;
+ mem_debug_chain_update = (header == mem_debug_chain);
+ header = realloc(header, sizeof(mem_debug_header_t) + size);
+ if (!header)
tcc_error("memory full (realloc)");
-
- header = (mem_debug_header_t *)ptr;
- if (header->magic1 != MEM_DEBUG_MAGIC1 ||
- header->magic2 != MEM_DEBUG_MAGIC2)
- {
- goto check_error;
- }
-
- mem_cur_size += size;
- if (mem_cur_size > mem_max_size)
- mem_max_size = mem_cur_size;
-
header->size = size;
+ MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
if (header->next)
header->next->prev = header;
-
if (header->prev)
header->prev->next = header;
-
if (mem_debug_chain_update)
mem_debug_chain = header;
-
- ptr = (char *)ptr + sizeof(mem_debug_header_t);
- return ptr;
+ mem_cur_size += size;
+ if (mem_cur_size > mem_max_size)
+ mem_max_size = mem_cur_size;
+ return MEM_USER_PTR(header);
}
PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
@@ -401,29 +375,23 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
return ptr;
}
-PUB_FUNC void tcc_memstats(int bench)
+PUB_FUNC void tcc_memcheck(void)
{
if (mem_cur_size) {
mem_debug_header_t *header = mem_debug_chain;
-
fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",
mem_cur_size, mem_max_size);
-
while (header) {
fprintf(stderr, "%s:%u: error: %u bytes leaked\n",
header->file_name, header->line_num, header->size);
header = header->next;
}
+#if MEM_DEBUG-0 == 2
+ exit(2);
+#endif
}
- else if (bench)
- fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size);
}
-
-#undef MEM_DEBUG_MAGIC1
-#undef MEM_DEBUG_MAGIC2
-#undef MEM_DEBUG_FILE_LEN
-
-#endif
+#endif /* MEM_DEBUG */
#define free(p) use_tcc_free(p)
#define malloc(s) use_tcc_malloc(s)
@@ -432,13 +400,13 @@ PUB_FUNC void tcc_memstats(int bench)
/********************************************************/
/* dynarrays */
-ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
+ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data)
{
int nb, nb_alloc;
void **pp;
nb = *nb_ptr;
- pp = *ptab;
+ pp = *(void ***)ptab;
/* every power of two we double array size */
if ((nb & (nb - 1)) == 0) {
if (!nb)
@@ -446,7 +414,7 @@ ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
else
nb_alloc = nb * 2;
pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
- *ptab = pp;
+ *(void***)ptab = pp;
}
pp[nb++] = data;
*nb_ptr = nb;
@@ -462,7 +430,7 @@ ST_FUNC void dynarray_reset(void *pp, int *n)
*(void**)pp = NULL;
}
-static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in)
+static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in)
{
const char *p;
do {
@@ -470,7 +438,7 @@ static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char
CString str;
cstr_new(&str);
- for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) {
+ for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) {
if (c == '{' && p[1] && p[2] == '}') {
c = p[1], p += 2;
if (c == 'B')
@@ -518,7 +486,7 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
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 (f->line_num > 0) {
+ if (s1->error_set_jmp_enabled) {
strcat_printf(buf, sizeof(buf), "%s:%d: ",
f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
} else {
@@ -536,8 +504,10 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
if (!s1->error_func) {
/* default case: stderr */
- if (s1->ppfp) /* print a newline during tcc -E */
- fprintf(s1->ppfp, "\n"), fflush(s1->ppfp);
+ if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
+ /* print a newline during tcc -E */
+ printf("\n"), fflush(stdout);
+ fflush(stdout); /* flush -v output */
fprintf(stderr, "%s\n", buf);
fflush(stderr); /* print error/warning now (win32) */
} else {
@@ -608,14 +578,13 @@ 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;
bf->fd = -1;
bf->prev = file;
file = bf;
+ tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
}
ST_FUNC void tcc_close(void)
@@ -625,6 +594,8 @@ ST_FUNC void tcc_close(void)
close(bf->fd);
total_lines += bf->line_num;
}
+ if (bf->true_filename != bf->filename)
+ tcc_free(bf->true_filename);
file = bf->prev;
tcc_free(bf);
}
@@ -641,44 +612,51 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
(int)(s1->include_stack_ptr - s1->include_stack), "", filename);
if (fd < 0)
return -1;
-
tcc_open_bf(s1, filename, 0);
+#ifdef _WIN32
+ normalize_slashes(file->filename);
+#endif
file->fd = fd;
return fd;
}
-/* compile the C file opened in 'file'. Return non zero if errors. */
+/* compile the file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1)
{
Sym *define_start;
+ int filetype, is_asm;
- preprocess_start(s1);
define_start = define_stack;
+ filetype = s1->filetype;
+ is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP;
+ tccelf_begin_file(s1);
if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1;
- tccgen_start(s1);
-#ifdef INC_DEBUG
- printf("%s: **** new file\n", file->filename);
+ preprocess_start(s1, is_asm);
+ if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
+ tcc_preprocess(s1);
+ } else if (is_asm) {
+#ifdef CONFIG_TCC_ASM
+ tcc_assemble(s1, filetype == AFF_TYPE_ASMPP);
+#else
+ tcc_error_noabort("asm not supported");
#endif
- ch = file->buf_ptr[0];
- tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
- parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
- next();
- decl(VT_CONST);
- if (tok != TOK_EOF)
- expect("declaration");
- /* reset define stack, but keep -D and built-ins */
- free_defines(define_start);
- tccgen_end(s1);
+ } else {
+ tccgen_compile(s1);
+ }
}
s1->error_set_jmp_enabled = 0;
+ 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);
+ tccelf_end_file(s1);
return s1->nb_errors != 0 ? -1 : 0;
}
@@ -711,10 +689,8 @@ LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *valu
memcpy(file->buffer + len1 + 1, value, len2);
/* parse with define parser */
- ch = file->buf_ptr[0];
next_nomacro();
parse_define();
-
tcc_close();
}
@@ -735,6 +711,8 @@ static void tcc_cleanup(void)
{
if (NULL == tcc_state)
return;
+ while (file)
+ tcc_close();
tccpp_delete(tcc_state);
tcc_state = NULL;
/* free sym_pools */
@@ -753,11 +731,12 @@ LIBTCCAPI TCCState *tcc_new(void)
if (!s)
return NULL;
tcc_state = s;
+ ++nb_states;
s->alacarte_link = 1;
s->nocommon = 1;
s->warn_implicit_function_declaration = 1;
- s->ms_bitfields = 0;
+ s->ms_extensions = 1;
#ifdef CHAR_IS_UNSIGNED
s->char_is_unsigned = 1;
@@ -765,9 +744,6 @@ LIBTCCAPI TCCState *tcc_new(void)
#ifdef TCC_TARGET_I386
s->seg_size = 32;
#endif
-#ifdef TCC_IS_NATIVE
- s->runtime_main = "main";
-#endif
/* enable this if you want symbols with leading underscore on windows: */
#if 0 /* def TCC_TARGET_PE */
s->leading_underscore = 1;
@@ -786,6 +762,7 @@ LIBTCCAPI TCCState *tcc_new(void)
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;
@@ -827,6 +804,8 @@ LIBTCCAPI TCCState *tcc_new(void)
#endif
#elif defined(TCC_TARGET_ARM64)
tcc_define_symbol(s, "__aarch64__", NULL);
+#elif defined TCC_TARGET_C67
+ tcc_define_symbol(s, "__C67__", NULL);
#endif
#ifdef TCC_TARGET_PE
@@ -850,30 +829,30 @@ LIBTCCAPI TCCState *tcc_new(void)
# if defined(__FreeBSD_kernel__)
tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
# endif
-#endif
# if defined(__NetBSD__)
tcc_define_symbol(s, "__NetBSD__", "__NetBSD__");
# endif
# if defined(__OpenBSD__)
tcc_define_symbol(s, "__OpenBSD__", "__OpenBSD__");
# endif
+#endif
/* TinyCC & gcc defines */
-#if defined(TCC_TARGET_PE) && defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
+ /* 32bit systems. */
+ tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
+ tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
+ tcc_define_symbol(s, "__ILP32__", NULL);
+#elif LONG_SIZE == 4
/* 64bit Windows. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
tcc_define_symbol(s, "__LLP64__", NULL);
-#elif defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
+#else
/* Other 64bit systems. */
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
tcc_define_symbol(s, "__LP64__", NULL);
-#else
- /* Other 32bit systems. */
- tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
- tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
- tcc_define_symbol(s, "__ILP32__", NULL);
#endif
#ifdef TCC_TARGET_PE
@@ -902,18 +881,19 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
"name proto __asm__ (#alias) __THROW");
# endif
-#endif /* ndef TCC_TARGET_PE */
-
+# 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 */
return s;
}
LIBTCCAPI void tcc_delete(TCCState *s1)
{
- int bench = s1->do_bench;
-
tcc_cleanup();
/* free sections */
@@ -927,6 +907,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
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);
@@ -938,6 +919,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->files, &s1->nb_files);
dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
+ dynarray_reset(&s1->argv, &s1->argc);
#ifdef TCC_IS_NATIVE
/* free runtime memory */
@@ -945,7 +927,8 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
#endif
tcc_free(s1);
- tcc_memstats(bench);
+ if (0 == --nb_states)
+ tcc_memcheck();
}
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
@@ -987,7 +970,7 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
# endif
#else
/* paths for crt objects */
- tcc_split_path(s, (void ***)&s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
+ tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
/* add libc crt1/crti objects */
if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
!s->nostdlib) {
@@ -1001,38 +984,19 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
{
- tcc_split_path(s, (void ***)&s->include_paths, &s->nb_include_paths, pathname);
+ tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname);
return 0;
}
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
{
- tcc_split_path(s, (void ***)&s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
+ tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
return 0;
}
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
{
- int ret, filetype;
-
- filetype = flags & 0x0F;
- if (filetype == 0) {
- /* use a file extension to detect a filetype */
- const char *ext = tcc_fileextension(filename);
- if (ext[0]) {
- ext++;
- if (!strcmp(ext, "S"))
- filetype = AFF_TYPE_ASMPP;
- else if (!strcmp(ext, "s"))
- filetype = AFF_TYPE_ASM;
- else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
- filetype = AFF_TYPE_C;
- else
- filetype = AFF_TYPE_BIN;
- } else {
- filetype = AFF_TYPE_C;
- }
- }
+ int ret;
/* open the file */
ret = tcc_open(s1, filename);
@@ -1043,29 +1007,10 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
}
/* update target deps */
- dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps,
+ dynarray_add(&s1->target_deps, &s1->nb_target_deps,
tcc_strdup(filename));
- parse_flags = 0;
- /* if .S file, define __ASSEMBLER__ like gcc does */
- if (filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP) {
- tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
- parse_flags = PARSE_FLAG_ASM_FILE;
- }
-
- if (flags & AFF_PREPROCESS) {
- ret = tcc_preprocess(s1);
- } else if (filetype == AFF_TYPE_C) {
- ret = tcc_compile(s1);
-#ifdef CONFIG_TCC_ASM
- } else if (filetype == AFF_TYPE_ASMPP) {
- /* non preprocessed assembler */
- ret = tcc_assemble(s1, 1);
- } else if (filetype == AFF_TYPE_ASM) {
- /* preprocessed assembler */
- ret = tcc_assemble(s1, 0);
-#endif
- } else {
+ if (flags & AFF_TYPE_BIN) {
ElfW(Ehdr) ehdr;
int fd, obj_type;
@@ -1073,8 +1018,10 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
obj_type = tcc_object_type(fd, &ehdr);
lseek(fd, 0, SEEK_SET);
- /* do not display line number if error */
- file->line_num = 0;
+#ifdef TCC_TARGET_MACHO
+ if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib"))
+ obj_type = AFF_BINTYPE_DYN;
+#endif
switch (obj_type) {
case AFF_BINTYPE_REL:
@@ -1113,6 +1060,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
tcc_error_noabort("unrecognized file type");
break;
}
+ } else {
+ ret = tcc_compile(s1);
}
tcc_close();
return ret;
@@ -1120,15 +1069,32 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
{
- if (s->output_type == TCC_OUTPUT_PREPROCESS)
- return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS | s->filetype);
- else
- return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | s->filetype);
+ int filetype = s->filetype;
+ int flags = AFF_PRINT_ERROR;
+ if (filetype == 0) {
+ /* use a file extension to detect a filetype */
+ const char *ext = tcc_fileextension(filename);
+ if (ext[0]) {
+ ext++;
+ if (!strcmp(ext, "S"))
+ filetype = AFF_TYPE_ASMPP;
+ else if (!strcmp(ext, "s"))
+ filetype = AFF_TYPE_ASM;
+ else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
+ filetype = AFF_TYPE_C;
+ else
+ flags |= AFF_TYPE_BIN;
+ } else {
+ filetype = AFF_TYPE_C;
+ }
+ s->filetype = filetype;
+ }
+ return tcc_add_file_internal(s, filename, flags);
}
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
{
- tcc_split_path(s, (void ***)&s->library_paths, &s->nb_library_paths, pathname);
+ tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname);
return 0;
}
@@ -1146,7 +1112,6 @@ static int tcc_add_library_internal(TCCState *s, const char *fmt,
return -1;
}
-#ifndef TCC_TARGET_PE
/* 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)
@@ -1154,7 +1119,6 @@ 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)
{
@@ -1167,9 +1131,12 @@ ST_FUNC int tcc_add_crt(TCCState *s, const char *filename)
/* the library name is the same as the argument of the '-l' option */
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
{
-#ifdef TCC_TARGET_PE
+#if defined TCC_TARGET_PE
const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL };
const char **pp = s->static_link ? libs + 4 : libs;
+#elif defined TCC_TARGET_MACHO
+ const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL };
+ const char **pp = s->static_link ? libs + 1 : libs;
#else
const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
const char **pp = s->static_link ? libs + 1 : libs;
@@ -1187,11 +1154,11 @@ PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname)
{
int ret = tcc_add_library(s, libname);
if (ret < 0)
- tcc_error_noabort("library 'lib%s' not found", libname);
+ tcc_error_noabort("library '%s' not found", libname);
return ret;
}
-/* habdle #pragma comment(lib,) */
+/* handle #pragma comment(lib,) */
ST_FUNC void tcc_add_pragma_libs(TCCState *s1)
{
int i;
@@ -1228,14 +1195,6 @@ typedef struct FlagDef {
const char *name;
} FlagDef;
-static const FlagDef warning_defs[] = {
- { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
- { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
- { offsetof(TCCState, warn_error), 0, "error" },
- { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
- "implicit-function-declaration" },
-};
-
static int no_flag(const char **pp)
{
const char *p = *pp;
@@ -1245,73 +1204,35 @@ static int no_flag(const char **pp)
return 1;
}
-ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
- const char *name, int value)
+ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name)
{
- int i;
+ int value, ret;
const FlagDef *p;
const char *r;
+ value = 1;
r = name;
if (no_flag(&r))
- value = !value;
-
- for(i = 0, p = flags; i < nb_flags; i++, p++) {
- if (!strcmp(r, p->name))
- goto found;
- }
- return -1;
- found:
- if (p->flags & FD_INVERT)
- value = !value;
- *(int *)((uint8_t *)s + p->offset) = value;
- return 0;
-}
-
-/* set/reset a warning */
-static int tcc_set_warning(TCCState *s, const char *warning_name, int value)
-{
- int i;
- const FlagDef *p;
+ value = 0;
- if (!strcmp(warning_name, "all")) {
- for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
- if (p->flags & WD_ALL)
- *(int *)((uint8_t *)s + p->offset) = 1;
+ for (ret = -1, p = flags; p->name; ++p) {
+ if (ret) {
+ if (strcmp(r, p->name))
+ continue;
+ } else {
+ if (0 == (p->flags & WD_ALL))
+ continue;
+ }
+ if (p->offset) {
+ *(int*)((char *)s + p->offset) =
+ p->flags & FD_INVERT ? !value : value;
+ if (ret)
+ return 0;
+ } else {
+ ret = 0;
}
- return 0;
- } else {
- return set_flag(s, warning_defs, countof(warning_defs),
- warning_name, value);
}
-}
-
-static const FlagDef flag_defs[] = {
- { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
- { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
- { offsetof(TCCState, nocommon), FD_INVERT, "common" },
- { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
- { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
- { offsetof(TCCState, old_struct_init_code), 0, "old-struct-init-code" },
- { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
-};
-
-/* set/reset a flag */
-static int tcc_set_flag(TCCState *s, const char *flag_name, int value)
-{
- return set_flag(s, flag_defs, countof(flag_defs),
- flag_name, value);
-}
-
-static const FlagDef m_defs[] = {
-#ifdef TCC_TARGET_X86_64
- { offsetof(TCCState, nosse), FD_INVERT, "sse" },
-#endif
- { 0, 0, " no flag" },
-};
-static int tcc_set_m_flag(TCCState *s, const char *flag_name, int value)
-{
- return set_flag(s, m_defs, countof(m_defs), flag_name, value);
+ return ret;
}
static int strstart(const char *val, const char **str)
@@ -1348,7 +1269,7 @@ static int link_option(const char *str, const char *val, const char **ptr)
if (*str == '-')
str++;
- /* then str & val should match (potentialy up to '=') */
+ /* then str & val should match (potentially up to '=') */
p = str;
q = val;
@@ -1373,6 +1294,8 @@ static int link_option(const char *str, const char *val, const char **ptr)
if (*p != ',' && *p != '=')
return 0;
p++;
+ } else if (*p) {
+ return 0;
}
*ptr = p;
return ret;
@@ -1386,11 +1309,15 @@ static const char *skip_linker_arg(const char **str)
return s2;
}
-static char *copy_linker_arg(const char *p)
+static void copy_linker_arg(char **pp, const char *s, int sep)
{
- const char *q = p;
+ const char *q = s;
+ char *p = *pp;
+ int l = 0;
+ if (p && sep)
+ p[l = strlen(p)] = sep, ++l;
skip_linker_arg(&q);
- return pstrncpy(tcc_malloc(q - p + 1), p, q - p);
+ pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s);
}
/* set linker options */
@@ -1408,19 +1335,19 @@ static int tcc_set_linker(TCCState *s, const char *option)
} else if (link_option(option, "nostdlib", &p)) {
s->nostdlib = 1;
} else if (link_option(option, "fini=", &p)) {
- s->fini_symbol = copy_linker_arg(p);
+ copy_linker_arg(&s->fini_symbol, p, 0);
ignoring = 1;
} else if (link_option(option, "image-base=", &p)
|| link_option(option, "Ttext=", &p)) {
s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
} else if (link_option(option, "init=", &p)) {
- s->init_symbol = copy_linker_arg(p);
+ copy_linker_arg(&s->init_symbol, p, 0);
ignoring = 1;
} else if (link_option(option, "oformat=", &p)) {
#if defined(TCC_TARGET_PE)
if (strstart("pe-", &p)) {
-#elif defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#elif PTR_SIZE == 8
if (strstart("elf64-", &p)) {
#else
if (strstart("elf32-", &p)) {
@@ -1439,13 +1366,19 @@ static int tcc_set_linker(TCCState *s, const char *option)
ignoring = 1;
} else if (link_option(option, "O", &p)) {
ignoring = 1;
+ } else if (link_option(option, "export-all-symbols", &p)) {
+ s->rdynamic = 1;
} else if (link_option(option, "rpath=", &p)) {
- s->rpath = copy_linker_arg(p);
+ copy_linker_arg(&s->rpath, p, ':');
+ } else if (link_option(option, "enable-new-dtags", &p)) {
+ s->enable_new_dtags = 1;
} else if (link_option(option, "section-alignment=", &p)) {
s->section_align = strtoul(p, &end, 16);
} else if (link_option(option, "soname=", &p)) {
- s->soname = copy_linker_arg(p);
+ copy_linker_arg(&s->soname, p, 0);
#ifdef TCC_TARGET_PE
+ } else if (link_option(option, "large-address-aware", &p)) {
+ s->pe_characteristics |= 0x20;
} else if (link_option(option, "file-alignment=", &p)) {
s->pe_file_align = strtoul(p, &end, 16);
} else if (link_option(option, "stack=", &p)) {
@@ -1456,7 +1389,7 @@ static int tcc_set_linker(TCCState *s, const char *option)
s->pe_subsystem = 1;
} else if (!strcmp(p, "console")) {
s->pe_subsystem = 3;
- } else if (!strcmp(p, "gui")) {
+ } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) {
s->pe_subsystem = 2;
} else if (!strcmp(p, "posix")) {
s->pe_subsystem = 7;
@@ -1500,6 +1433,8 @@ typedef struct TCCOption {
enum {
TCC_OPTION_HELP,
+ TCC_OPTION_HELP2,
+ TCC_OPTION_v,
TCC_OPTION_I,
TCC_OPTION_D,
TCC_OPTION_U,
@@ -1514,7 +1449,6 @@ enum {
TCC_OPTION_c,
TCC_OPTION_dumpversion,
TCC_OPTION_d,
- TCC_OPTION_float_abi,
TCC_OPTION_static,
TCC_OPTION_std,
TCC_OPTION_shared,
@@ -1527,7 +1461,7 @@ enum {
TCC_OPTION_Wp,
TCC_OPTION_W,
TCC_OPTION_O,
- TCC_OPTION_mms_bitfields,
+ TCC_OPTION_mfloat_abi,
TCC_OPTION_m,
TCC_OPTION_f,
TCC_OPTION_isystem,
@@ -1541,13 +1475,14 @@ enum {
TCC_OPTION_pedantic,
TCC_OPTION_pthread,
TCC_OPTION_run,
- TCC_OPTION_v,
TCC_OPTION_w,
TCC_OPTION_pipe,
TCC_OPTION_E,
TCC_OPTION_MD,
TCC_OPTION_MF,
- TCC_OPTION_x
+ TCC_OPTION_x,
+ TCC_OPTION_ar,
+ TCC_OPTION_impdef
};
#define TCC_OPTION_HAS_ARG 0x0001
@@ -1557,6 +1492,8 @@ static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
{ "-help", TCC_OPTION_HELP, 0 },
{ "?", TCC_OPTION_HELP, 0 },
+ { "hh", TCC_OPTION_HELP2, 0 },
+ { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
@@ -1575,9 +1512,6 @@ static const TCCOption tcc_options[] = {
{ "c", TCC_OPTION_c, 0 },
{ "dumpversion", TCC_OPTION_dumpversion, 0},
{ "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
-#ifdef TCC_TARGET_ARM
- { "mfloat-abi", TCC_OPTION_float_abi, TCC_OPTION_HAS_ARG },
-#endif
{ "static", TCC_OPTION_static, 0 },
{ "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "shared", TCC_OPTION_shared, 0 },
@@ -1595,25 +1529,58 @@ static const TCCOption tcc_options[] = {
{ "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
- { "mms-bitfields", TCC_OPTION_mms_bitfields, 0}, /* must go before option 'm' */
- { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
+#ifdef TCC_TARGET_ARM
+ { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG },
+#endif
+ { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
- { "iwithprefix", TCC_OPTION_iwithprefix, TCC_OPTION_HAS_ARG },
{ "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG },
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
- { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "w", TCC_OPTION_w, 0 },
{ "pipe", TCC_OPTION_pipe, 0},
{ "E", TCC_OPTION_E, 0},
{ "MD", TCC_OPTION_MD, 0},
{ "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
{ "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
+ { "ar", TCC_OPTION_ar, 0},
+#ifdef TCC_TARGET_PE
+ { "impdef", TCC_OPTION_impdef, 0},
+#endif
{ NULL, 0, 0 },
};
+static const FlagDef options_W[] = {
+ { 0, 0, "all" },
+ { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
+ { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
+ { offsetof(TCCState, warn_error), 0, "error" },
+ { offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" },
+ { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
+ "implicit-function-declaration" },
+ { 0, 0, NULL }
+};
+
+static const FlagDef options_f[] = {
+ { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
+ { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
+ { offsetof(TCCState, nocommon), FD_INVERT, "common" },
+ { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
+ { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
+ { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
+ { 0, 0, NULL }
+};
+
+static const FlagDef options_m[] = {
+ { offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" },
+#ifdef TCC_TARGET_X86_64
+ { offsetof(TCCState, nosse), FD_INVERT, "sse" },
+#endif
+ { 0, 0, NULL }
+};
+
static void parse_option_D(TCCState *s1, const char *optarg)
{
char *sym = tcc_strdup(optarg);
@@ -1628,56 +1595,105 @@ 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((void ***)&s->files, &s->nb_files, f);
+ dynarray_add(&s->files, &s->nb_files, f);
+}
+
+static int args_parser_make_argv(const char *r, int *argc, char ***argv)
+{
+ int ret = 0, q, c;
+ CString str;
+ for(;;) {
+ while (c = (unsigned char)*r, c && c <= ' ')
+ ++r;
+ if (c == 0)
+ break;
+ q = 0;
+ cstr_new(&str);
+ while (c = (unsigned char)*r, c) {
+ ++r;
+ if (c == '\\' && (*r == '"' || *r == '\\')) {
+ c = *r++;
+ } else if (c == '"') {
+ q = !q;
+ continue;
+ } else if (q == 0 && c <= ' ') {
+ break;
+ }
+ cstr_ccat(&str, c);
+ }
+ cstr_ccat(&str, 0);
+ //printf("<%s>\n", str.data), fflush(stdout);
+ dynarray_add(argv, argc, tcc_strdup(str.data));
+ cstr_free(&str);
+ ++ret;
+ }
+ return ret;
}
/* read list file */
-static void args_parser_listfile(TCCState *s, const char *filename)
+static void args_parser_listfile(TCCState *s,
+ const char *filename, int optind, int *pargc, char ***pargv)
{
- int fd;
+ int fd, i;
size_t len;
char *p;
+ int argc = 0;
+ char **argv = NULL;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
- tcc_error("file '%s' not found", filename);
+ tcc_error("listfile '%s' not found", filename);
len = lseek(fd, 0, SEEK_END);
p = tcc_malloc(len + 1), p[len] = 0;
lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd);
- tcc_set_options(s, p);
+
+ for (i = 0; i < *pargc; ++i)
+ if (i == optind)
+ args_parser_make_argv(p, &argc, &argv);
+ else
+ dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
+
tcc_free(p);
+ dynarray_reset(&s->argv, &s->argc);
+ *pargc = s->argc = argc, *pargv = s->argv = argv;
}
-PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
+PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
{
const TCCOption *popt;
const char *optarg, *r;
- int optind = 0;
- int run = 0;
- int x;
+ const char *run = NULL;
int last_o = -1;
+ int x;
CString linker_arg; /* collect -Wl options */
- char buf[1024];
+ int tool = 0, arg_start = 0, noaction = optind;
+ char **argv = *pargv;
+ int argc = *pargc;
cstr_new(&linker_arg);
while (optind < argc) {
-
- r = argv[optind++];
-
-reparse:
+ r = argv[optind];
if (r[0] == '@' && r[1] != '\0') {
- args_parser_listfile(s, r + 1);
+ args_parser_listfile(s, r + 1, optind, &argc, &argv);
continue;
}
-
+ optind++;
+ if (tool) {
+ if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
+ ++s->verbose;
+ continue;
+ }
+reparse:
if (r[0] != '-' || r[1] == '\0') {
- args_parser_add_file(s, r, s->filetype);
+ if (r[0] != '@') /* allow "tcc file(s) -run @ args ..." */
+ args_parser_add_file(s, r, s->filetype);
if (run) {
- optind--;
- /* argv[0] will be this file */
+ tcc_set_options(s, run);
+ arg_start = optind - 1;
break;
}
continue;
@@ -1706,7 +1722,9 @@ reparse:
switch(popt->index) {
case TCC_OPTION_HELP:
- return 0;
+ return OPT_HELP;
+ case TCC_OPTION_HELP2:
+ return OPT_HELP2;
case TCC_OPTION_I:
tcc_add_include_path(s, optarg);
break;
@@ -1724,7 +1742,7 @@ reparse:
tcc_set_lib_path(s, optarg);
break;
case TCC_OPTION_l:
- args_parser_add_file(s, optarg, AFF_TYPE_LIBWH - s->alacarte_link);
+ args_parser_add_file(s, optarg, AFF_TYPE_LIB);
s->nb_libraries++;
break;
case TCC_OPTION_pthread:
@@ -1760,21 +1778,13 @@ reparse:
s->dflag = 3;
else if (*optarg == 'M')
s->dflag = 7;
+ else if (*optarg == 't')
+ s->dflag = 16;
+ else if (isnum(*optarg))
+ g_debug = atoi(optarg);
else
goto unsupported_option;
break;
-#ifdef TCC_TARGET_ARM
- case TCC_OPTION_float_abi:
- /* tcc doesn't support soft float yet */
- if (!strcmp(optarg, "softfp")) {
- s->float_abi = ARM_SOFTFP_FLOAT;
- tcc_undefine_symbol(s, "__ARM_PCS_VFP");
- } else if (!strcmp(optarg, "hard"))
- s->float_abi = ARM_HARD_FLOAT;
- else
- tcc_error("unsupported float abi '%s'", optarg);
- break;
-#endif
case TCC_OPTION_static:
s->static_link = 1;
break;
@@ -1788,12 +1798,6 @@ reparse:
case TCC_OPTION_soname:
s->soname = tcc_strdup(optarg);
break;
- case TCC_OPTION_m:
- if (!strcmp(optarg, "32") || !strcmp(optarg, "64"))
- s->option_m = tcc_strdup(optarg);
- else if (tcc_set_m_flag(s, optarg, 1) < 0)
- goto unsupported_option;
- break;
case TCC_OPTION_o:
if (s->outfile) {
tcc_warning("multiple -o option");
@@ -1809,12 +1813,8 @@ reparse:
case TCC_OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
- case TCC_OPTION_iwithprefix:
- snprintf(buf, sizeof buf, "{B}/%s", optarg);
- tcc_add_sysinclude_path(s, buf);
- break;
case TCC_OPTION_include:
- dynarray_add((void ***)&s->cmd_include_files,
+ dynarray_add(&s->cmd_include_files,
&s->nb_cmd_include_files, tcc_strdup(optarg));
break;
case TCC_OPTION_nostdinc:
@@ -1823,26 +1823,44 @@ reparse:
case TCC_OPTION_nostdlib:
s->nostdlib = 1;
break;
- case TCC_OPTION_print_search_dirs:
- s->print_search_dirs = 1;
- break;
case TCC_OPTION_run:
#ifndef TCC_IS_NATIVE
tcc_error("-run is not available in a cross compiler");
#endif
- tcc_set_options(s, optarg);
- run = 1;
+ run = optarg;
x = TCC_OUTPUT_MEMORY;
goto set_output_type;
case TCC_OPTION_v:
do ++s->verbose; while (*optarg++ == 'v');
+ ++noaction;
break;
case TCC_OPTION_f:
- if (tcc_set_flag(s, optarg, 1) < 0)
+ if (set_flag(s, options_f, optarg) < 0)
goto unsupported_option;
break;
+#ifdef TCC_TARGET_ARM
+ case TCC_OPTION_mfloat_abi:
+ /* tcc doesn't support soft float yet */
+ if (!strcmp(optarg, "softfp")) {
+ s->float_abi = ARM_SOFTFP_FLOAT;
+ tcc_undefine_symbol(s, "__ARM_PCS_VFP");
+ } else if (!strcmp(optarg, "hard"))
+ s->float_abi = ARM_HARD_FLOAT;
+ else
+ tcc_error("unsupported float abi '%s'", optarg);
+ break;
+#endif
+ case TCC_OPTION_m:
+ if (set_flag(s, options_m, optarg) < 0) {
+ if (x = atoi(optarg), x != 32 && x != 64)
+ goto unsupported_option;
+ if (PTR_SIZE != x/8)
+ return x;
+ ++noaction;
+ }
+ break;
case TCC_OPTION_W:
- if (tcc_set_warning(s, optarg, 1) < 0)
+ if (set_flag(s, options_W, optarg) < 0)
goto unsupported_option;
break;
case TCC_OPTION_w:
@@ -1890,8 +1908,19 @@ reparse:
case TCC_OPTION_O:
last_o = atoi(optarg);
break;
- case TCC_OPTION_mms_bitfields:
- s->ms_bitfields = 1;
+ case TCC_OPTION_print_search_dirs:
+ x = OPT_PRINT_DIRS;
+ goto extra_action;
+ case TCC_OPTION_impdef:
+ x = OPT_IMPDEF;
+ goto extra_action;
+ case TCC_OPTION_ar:
+ x = OPT_AR;
+ extra_action:
+ arg_start = optind - 1;
+ if (arg_start != noaction)
+ tcc_error("cannot parse %s here", r);
+ tool = x;
break;
case TCC_OPTION_traditional:
case TCC_OPTION_pedantic:
@@ -1906,53 +1935,32 @@ unsupported_option:
break;
}
}
-
if (last_o > 0)
tcc_define_symbol(s, "__OPTIMIZE__", NULL);
-
if (linker_arg.size) {
r = linker_arg.data;
goto arg_err;
}
-
- return optind;
+ *pargc = argc - arg_start;
+ *pargv = argv + arg_start;
+ if (tool)
+ return tool;
+ if (optind != noaction)
+ return 0;
+ if (s->verbose == 2)
+ return OPT_PRINT_DIRS;
+ if (s->verbose)
+ return OPT_V;
+ return OPT_HELP;
}
-LIBTCCAPI int tcc_set_options(TCCState *s, const char *r)
+LIBTCCAPI void tcc_set_options(TCCState *s, const char *r)
{
- char **argv;
- int argc;
- int ret, q, c;
- CString str;
-
- argc = 0, argv = NULL;
- for(;;) {
- while (c = (unsigned char)*r, c && c <= ' ')
- ++r;
- if (c == 0)
- break;
- q = 0;
- cstr_new(&str);
- while (c = (unsigned char)*r, c) {
- ++r;
- if (c == '\\' && (*r == '"' || *r == '\\')) {
- c = *r++;
- } else if (c == '"') {
- q = !q;
- continue;
- } else if (q == 0 && c <= ' ') {
- break;
- }
- cstr_ccat(&str, c);
- }
- cstr_ccat(&str, 0);
- //printf("<%s>\n", str.data), fflush(stdout);
- dynarray_add((void ***)&argv, &argc, tcc_strdup(str.data));
- cstr_free(&str);
- }
- ret = tcc_parse_args(s, argc, argv);
+ char **argv = NULL;
+ int argc = 0;
+ args_parser_make_argv(r, &argc, &argv);
+ tcc_parse_args(s, &argc, &argv, 0);
dynarray_reset(&argv, &argc);
- return ret;
}
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
@@ -1961,27 +1969,13 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
total_time = 1;
if (total_bytes < 1)
total_bytes = 1;
- fprintf(stderr, "%d idents, %d lines, %d bytes, %0.3f s, %u lines/s, %0.1f MB/s\n",
+ 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,
(double)total_time/1000,
(unsigned)total_lines*1000/total_time,
(double)total_bytes/1000/total_time);
-}
-
-PUB_FUNC void tcc_set_environment(TCCState *s)
-{
- char * path;
-
- path = getenv("C_INCLUDE_PATH");
- if(path != NULL) {
- tcc_add_include_path(s, path);
- }
- path = getenv("CPATH");
- if(path != NULL) {
- tcc_add_include_path(s, path);
- }
- path = getenv("LIBRARY_PATH");
- if(path != NULL) {
- tcc_add_library_path(s, path);
- }
+#ifdef MEM_DEBUG
+ fprintf(stderr, "* %d bytes memory used\n", mem_max_size);
+#endif
}
diff --git a/libtcc.h b/libtcc.h
index 799ffd8..a1b31e3 100644
--- a/libtcc.h
+++ b/libtcc.h
@@ -27,7 +27,7 @@ LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
void (*error_func)(void *opaque, const char *msg));
/* set options as from command line (multiple supported) */
-LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
+LIBTCCAPI void tcc_set_options(TCCState *s, const char *str);
/*****************************/
/* preprocessor */
diff --git a/tcc-doc.html b/tcc-doc.html
new file mode 100644
index 0000000..c88d27a
--- /dev/null
+++ b/tcc-doc.html
@@ -0,0 +1,2489 @@
+<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 9f136ed..5e718a2 100644
--- a/tcc-doc.texi
+++ b/tcc-doc.texi
@@ -176,29 +176,15 @@ In a script, it gives the following header:
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
@end example
-@item -mms-bitfields
-Use an algorithm for bitfield alignment consistent with MSVC. Default is
-gcc's algorithm.
-
-@item -mfloat-abi (ARM only)
-Select the float ABI. Possible values: @code{softfp} and @code{hard}
-
-@item -dumpversion
-Print only the compiler version and nothing else.
-
@item -v
Display TCC version.
@item -vv
-Show included files. As sole argument, print search dirs (as below).
+Show included files. As sole argument, print search dirs. -vvv shows tries too.
@item -bench
Display compilation statistics.
-@item -print-search-dirs
-Print the configured installation directory and a list of library
-and include directories tcc will search.
-
@end table
Preprocessor options:
@@ -220,6 +206,10 @@ also be defined: @option{-DF(a)=a+1}
@item -Usym
Undefine preprocessor symbol @samp{sym}.
+
+@item -E
+Preprocess only, to stdout or file (with -o).
+
@end table
Compilation flags:
@@ -317,6 +307,10 @@ Generate an object file combining all input files.
@item -Wl,-rpath=path
Put custom search path for dynamic libraries into executable.
+@item -Wl,--enable-new-dtags
+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.
+
@item -Wl,--oformat=fmt
Use @var{fmt} as output format. The supported output formats are:
@table @code
@@ -337,6 +331,9 @@ Modify executable layout.
@item -Wl,-Bsymbolic
Set DT_SYMBOLIC tag.
+@item -Wl,-(no-)whole-archive
+Turn on/off linking of all objects in archives.
+
@end table
Debugger options:
@@ -370,6 +367,31 @@ Generate makefile fragment with dependencies.
@item -MF depfile
Use @file{depfile} as output for -MD.
+@item -print-search-dirs
+Print the configured installation directory and a list of library
+and include directories tcc will search.
+
+@item -dumpversion
+Print version.
+
+@end table
+
+Target specific options:
+
+@table @option
+@item -mms-bitfields
+Use an algorithm for bitfield alignment consistent with MSVC. Default is
+gcc's algorithm.
+
+@item -mfloat-abi (ARM only)
+Select the float ABI. Possible values: @code{softfp} and @code{hard}
+
+@item -mno-sse
+Do not use sse registers on x86_64
+
+@item -m32, -m64
+Pass command line to the i386/x86_64 cross compiler.
+
@end table
Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are
@@ -647,7 +669,7 @@ are supported.
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
assembler supports a gas-like syntax (GNU assembler). You can
-desactivate assembler support if you want a smaller TinyCC executable
+deactivate assembler support if you want a smaller TinyCC executable
(the C compiler does not rely on the assembler).
TinyCC Assembler is used to handle files with @file{.S} (C
@@ -1024,7 +1046,7 @@ All symbols are stored in hashed symbol stacks. Each symbol stack
contains @code{Sym} structures.
@code{Sym.v} contains the symbol name (remember
-an idenfier is also a token, so a string is never necessary to store
+an identifier is also a token, so a string is never necessary to store
it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually
the register in which the corresponding variable is stored. @code{Sym.c} is
usually a constant associated to the symbol like its address for normal
@@ -1067,7 +1089,7 @@ global stack.
@section Sections
-The generated code and datas are written in sections. The structure
+The generated code and data are written in sections. The structure
@code{Section} contains all the necessary information for a given
section. @code{new_section()} creates a new section. ELF file semantics
is assumed for each section.
@@ -1254,13 +1276,13 @@ should generate a function prolog/epilog.
@item gen_opi(op)
must generate the binary integer operation @var{op} on the two top
-entries of the stack which are guaranted to contain integer types.
+entries of the stack which are guaranteed to contain integer types.
The result value should be put on the stack.
@item gen_opf(op)
same as @code{gen_opi()} for floating point operations. The two top
-entries of the stack are guaranted to contain floating point values of
+entries of the stack are guaranteed to contain floating point values of
same types.
@item gen_cvt_itof()
diff --git a/tcc.c b/tcc.c
index cbef5d3..cd887d1 100644
--- a/tcc.c
+++ b/tcc.c
@@ -18,205 +18,193 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifdef ONE_SOURCE
-#include "libtcc.c"
-#else
#include "tcc.h"
+#if ONE_SOURCE
+# include "libtcc.c"
#endif
+#include "tcctools.c"
-static void print_paths(const char *msg, char **paths, int nb_paths)
-{
- int i;
- printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
- for(i = 0; i < nb_paths; i++)
- printf(" %s\n", paths[i]);
-}
+static const char help[] =
+ "Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n"
+ "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"
+ "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"
+ "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"
+ " -Wl,-opt[=val] set linker option (see tcc -hh)\n"
+ "Debugger options:\n"
+ " -g generate runtime debug info\n"
+#ifdef CONFIG_TCC_BCHECK
+ " -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"
+#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"
+ "Tools:\n"
+ " create library : tcc -ar [rcsv] lib.a files\n"
+#ifdef TCC_TARGET_PE
+ " create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n"
+#endif
+ ;
-static void display_info(TCCState *s, int what)
-{
- switch (what) {
- case 0:
- printf("tcc version %s ("
+static const char help2[] =
+ "Tiny C Compiler "TCC_VERSION" - More Options\n"
+ "Special options:\n"
+ " -P -P1 with -E: no/alternative #line output\n"
+ " -dD -dM with -E: output #define directives\n"
+ " -pthread same as -D_REENTRANT and -lpthread\n"
+ " -On same as -D__OPTIMIZE__ for n > 0\n"
+ " -Wp,-opt same as -opt\n"
+ " -include file include 'file' above each input file\n"
+ " -isystem dir add 'dir' to system include path\n"
+ " -static link to static libraries (not recommended)\n"
+ " -dumpversion print version\n"
+ " -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"
+ "-W... warnings:\n"
+ " all turn on some (*) warnings\n"
+ " error stop after first warning\n"
+ " unsupported warn about ignored options, pragmas, etc.\n"
+ " write-strings strings are const\n"
+ " implicit-function-declaration warn for missing prototype (*)\n"
+ "-f[no-]... flags:\n"
+ " unsigned-char default char is unsigned\n"
+ " signed-char default char is signed\n"
+ " common use common section instead of bss\n"
+ " leading-underscore decorate extern symbols\n"
+ " ms-extensions allow anonymous struct in struct\n"
+ " dollars-in-identifiers allow '$' in C symbols\n"
+ "-m... target specific options:\n"
+ " ms-bitfields use MSVC bitfield layout\n"
+#ifdef TCC_TARGET_ARM
+ " float-abi hard/softfp on arm\n"
+#endif
+#ifdef TCC_TARGET_X86_64
+ " no-sse disable floats on x86_64\n"
+#endif
+ "-Wl,... linker options:\n"
+ " -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"
+ " -image-base= -Ttext= set base address of executable\n"
+ " -section-alignment= set section alignment in executable\n"
+#ifdef TCC_TARGET_PE
+ " -file-alignment= set PE file alignment\n"
+ " -stack= set PE stack reserve\n"
+ " -large-address-aware set related PE option\n"
+ " -subsystem=[console/windows] set PE subsystem\n"
+ " -oformat=[pe-* binary] set executable output format\n"
+ "Predefined macros:\n"
+ " tcc -E -dM - < nul\n"
+#else
+ " -rpath= set dynamic library search path\n"
+ " -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n"
+ " -soname= set DT_SONAME elf tag\n"
+ " -Bsymbolic set DT_SYMBOLIC elf tag\n"
+ " -oformat=[elf32/64-* binary] set executable output format\n"
+ " -init= -fini= -as-needed -O (ignored)\n"
+ "Predefined macros:\n"
+ " tcc -E -dM - < /dev/null\n"
+#endif
+ "See also the manual for more details.\n"
+ ;
+
+static const char version[] =
+ "tcc version "TCC_VERSION" ("
#ifdef TCC_TARGET_I386
"i386"
#elif defined TCC_TARGET_X86_64
- "x86-64"
+ "x86_64"
#elif defined TCC_TARGET_C67
"C67"
#elif defined TCC_TARGET_ARM
"ARM"
-# ifdef TCC_ARM_HARDFLOAT
- " Hard Float"
-# endif
#elif defined TCC_TARGET_ARM64
"AArch64"
-# ifdef TCC_ARM_HARDFLOAT
+#endif
+#ifdef TCC_ARM_HARDFLOAT
" Hard Float"
-# endif
#endif
#ifdef TCC_TARGET_PE
" Windows"
-#elif defined(__APPLE__)
- /* Current Apple OS name as of 2016 */
- " macOS"
+#elif defined(TCC_TARGET_MACHO)
+ " Darwin"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
" FreeBSD"
-#elif defined(__DragonFly__)
- " DragonFly BSD"
-#elif defined(__NetBSD__)
- " NetBSD"
-#elif defined(__OpenBSD__)
- " OpenBSD"
-#elif defined(__linux__)
- " Linux"
#else
- " Unidentified system"
-#endif
- ")\n", TCC_VERSION);
- break;
- case 1:
- printf("install: %s\n", s->tcc_lib_path);
- /* print_paths("programs", NULL, 0); */
- print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
- print_paths("libraries", s->library_paths, s->nb_library_paths);
-#ifndef TCC_TARGET_PE
- print_paths("crt", s->crt_paths, s->nb_crt_paths);
- printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
+ " Linux"
#endif
- break;
- }
-}
+ ")\n"
+ ;
-static void help(void)
+static void print_dirs(const char *msg, char **paths, int nb_paths)
{
- printf("Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n"
- "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 man page)\n"
- " -mms-bitfields use bitfield alignment consistent with MSVC\n"
- " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
- " -w disable all warnings\n"
- " -v show version\n"
- " -vv show included files (as sole argument: show search paths)\n"
- " -dumpversion\n"
- " -bench show compilation statistics\n"
- " -xc -xa specify type of the next infile\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"
- " -P[1] no / alternative #line output with -E\n"
- " -dD -dM output #define directives with -E\n"
- "Linker options:\n"
- " -Ldir add library path 'dir'\n"
- " -llib link with dynamic or static library 'lib'\n"
- " -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n"
- " -r generate (relocatable) object file\n"
- " -rdynamic export all global symbols to dynamic linker\n"
- " -shared generate a shared library\n"
- " -soname set name for shared library to be used at runtime\n"
- " -static static linking\n"
- " -Wl,-opt[=val] set linker option (see manual)\n"
- "Debugger options:\n"
- " -g generate runtime debug info\n"
-#ifdef CONFIG_TCC_BCHECK
- " -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"
-#endif
- "Misc options:\n"
- " -nostdinc do not use standard system include paths\n"
- " -nostdlib do not link with standard crt and libraries\n"
- " -Bdir use 'dir' as tcc internal library and include path\n"
- " -MD generate target dependencies for make\n"
- " -MF depfile put generated dependencies here\n"
- );
+ int i;
+ printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
+ for(i = 0; i < nb_paths; i++)
+ printf(" %s\n", paths[i]);
}
-/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
-#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
-#ifdef _WIN32
-#include <process.h>
-static int execvp_win32(const char *prog, char **argv)
+static void print_search_dirs(TCCState *s)
{
- int ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
- if (-1 == ret)
- return ret;
- cwait(&ret, ret, WAIT_CHILD);
- exit(ret);
-}
-#define execvp execvp_win32
-#endif
-static void exec_other_tcc(TCCState *s, char **argv, const char *optarg)
-{
- char child_path[4096], *child_name; const char *target;
- switch (atoi(optarg)) {
-#ifdef TCC_TARGET_I386
- case 32: break;
- case 64: target = "x86_64";
-#else
- case 64: break;
- case 32: target = "i386";
-#endif
- pstrcpy(child_path, sizeof child_path - 40, argv[0]);
- child_name = tcc_basename(child_path);
- strcpy(child_name, target);
-#ifdef TCC_TARGET_PE
- strcat(child_name, "-win32");
+ printf("install: %s\n", s->tcc_lib_path);
+ /* 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);
+ 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
- strcat(child_name, "-tcc");
- if (strcmp(argv[0], child_path)) {
- if (s->verbose > 0)
- printf("tcc: using '%s'\n", child_name), fflush(stdout);
- execvp(argv[0] = child_path, argv);
- }
- tcc_error("'%s' not found", child_name);
- case 0: /* ignore -march etc. */
- break;
- default:
- tcc_warning("unsupported option \"-m%s\"", optarg);
- }
}
-#else
-#define exec_other_tcc(s, argv, optarg)
-#endif
-static void gen_makedeps(TCCState *s, const char *target, const char *filename)
+static void set_environment(TCCState *s)
{
- FILE *depout;
- char buf[1024], *ext;
- int i;
+ char * path;
- if (!filename) {
- /* compute filename automatically
- * dir/file.o -> dir/file.d */
- pstrcpy(buf, sizeof(buf), target);
- ext = tcc_fileextension(buf);
- pstrcpy(ext, sizeof(buf) - (ext-buf), ".d");
- filename = buf;
+ path = getenv("C_INCLUDE_PATH");
+ if(path != NULL) {
+ tcc_add_sysinclude_path(s, path);
+ }
+ path = getenv("CPATH");
+ if(path != NULL) {
+ tcc_add_include_path(s, path);
+ }
+ path = getenv("LIBRARY_PATH");
+ if(path != NULL) {
+ tcc_add_library_path(s, path);
}
-
- if (s->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, "\n");
- fclose(depout);
}
static char *default_outputfile(TCCState *s, const char *first_file)
@@ -227,7 +215,7 @@ static char *default_outputfile(TCCState *s, const char *first_file)
if (first_file && strcmp(first_file, "-"))
name = tcc_basename(first_file);
- pstrcpy(buf, sizeof(buf), name);
+ snprintf(buf, sizeof(buf), "%s", name);
ext = tcc_fileextension(buf);
#ifdef TCC_TARGET_PE
if (s->output_type == TCC_OUTPUT_DLL)
@@ -241,7 +229,6 @@ static char *default_outputfile(TCCState *s, const char *first_file)
strcpy(ext, ".o");
else
strcpy(buf, "a.out");
-
return tcc_strdup(buf);
}
@@ -256,112 +243,129 @@ static unsigned getclock_ms(void)
#endif
}
-int main(int argc, char **argv)
+int main(int argc0, char **argv0)
{
TCCState *s;
- int ret, optind, i;
+ int ret, opt, n = 0, t = 0;
unsigned start_time = 0;
- const char *first_file = NULL;
+ const char *first_file;
+ int argc; char **argv;
+ FILE *ppfp = stdout;
+redo:
+ argc = argc0, argv = argv0;
s = tcc_new();
+ opt = tcc_parse_args(s, &argc, &argv, 1);
- optind = tcc_parse_args(s, argc - 1, argv + 1);
-
- tcc_set_environment(s);
-
- if (optind == 0) {
- help();
- return 1;
- }
-
- if (s->option_m)
- exec_other_tcc(s, argv, s->option_m);
+ if ((n | t) == 0) {
+ if (opt == OPT_HELP)
+ return printf(help), 1;
+ if (opt == OPT_HELP2)
+ return printf(help2), 1;
+ if (opt == OPT_M32 || opt == OPT_M64)
+ tcc_tool_cross(s, argv, opt); /* never returns */
+ if (s->verbose)
+ printf(version);
+ if (opt == OPT_AR)
+ return tcc_tool_ar(s, argc, argv);
+#ifdef TCC_TARGET_PE
+ if (opt == OPT_IMPDEF)
+ return tcc_tool_impdef(s, argc, argv);
+#endif
+ if (opt == OPT_V)
+ return 0;
+ if (opt == OPT_PRINT_DIRS) {
+ /* initialize search dirs */
+ set_environment(s);
+ tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+ print_search_dirs(s);
+ return 0;
+ }
- if (s->verbose)
- display_info(s, 0);
+ n = s->nb_files;
+ if (n == 0)
+ tcc_error("no input files\n");
- if (s->nb_files == 0) {
- if (optind == 1) {
- if (s->print_search_dirs || s->verbose == 2) {
- tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
- display_info(s, 1);
- return 1;
+ if (s->output_type == TCC_OUTPUT_PREPROCESS) {
+ if (s->outfile) {
+ ppfp = fopen(s->outfile, "w");
+ if (!ppfp)
+ tcc_error("could not write '%s'", s->outfile);
}
- if (s->verbose)
- return 1;
+ } 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)
+ tcc_error("cannot specify output file with -c many files");
+ } else {
+ if (s->option_pthread)
+ tcc_set_options(s, "-lpthread");
}
- tcc_error("no input files\n");
- }
- /* check -c consistency : only single file handled. XXX: checks file type */
- if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
- if (s->nb_libraries != 0)
- tcc_error("cannot specify libraries with -c");
- /* accepts only a single input file */
- if (s->nb_files != 1)
- tcc_error("cannot specify multiple files with -c");
+ if (s->do_bench)
+ start_time = getclock_ms();
}
+ set_environment(s);
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type);
+ s->ppfp = ppfp;
- if (s->output_type == TCC_OUTPUT_PREPROCESS) {
- if (!s->outfile) {
- s->ppfp = stdout;
- } else {
- s->ppfp = fopen(s->outfile, "w");
- if (!s->ppfp)
- tcc_error("could not write '%s'", s->outfile);
- }
- } else if (s->output_type != TCC_OUTPUT_OBJ) {
- if (s->option_pthread)
- tcc_set_options(s, "-lpthread");
- }
-
- if (s->do_bench)
- start_time = getclock_ms();
+ 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;
/* compile or add each files or library */
- for(i = ret = 0; i < s->nb_files && ret == 0; i++) {
- struct filespec *f = s->files[i];
- if (f->type >= AFF_TYPE_LIB) {
- s->alacarte_link = f->type == AFF_TYPE_LIB;
+ for (first_file = NULL, ret = 0;;) {
+ struct filespec *f = s->files[s->nb_files - n];
+ s->filetype = f->type;
+ s->alacarte_link = f->alacarte;
+ if (f->type == AFF_TYPE_LIB) {
if (tcc_add_library_err(s, f->name) < 0)
ret = 1;
} else {
if (1 == s->verbose)
printf("-> %s\n", f->name);
- s->filetype = f->type;
- if (tcc_add_file(s, f->name) < 0)
- ret = 1;
if (!first_file)
first_file = f->name;
+ if (tcc_add_file(s, f->name) < 0)
+ ret = 1;
}
- s->filetype = AFF_TYPE_NONE;
+ s->filetype = 0;
s->alacarte_link = 1;
+ if (--n == 0 || ret
+ || (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
+ break;
}
- if (s->output_type == TCC_OUTPUT_PREPROCESS) {
- if (s->outfile)
- fclose(s->ppfp);
-
+ if (s->run_test) {
+ t = 0;
+ } else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
+ ;
} else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE
- ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
+ ret = tcc_run(s, argc, argv);
#endif
} else {
if (!s->outfile)
s->outfile = default_outputfile(s, first_file);
- ret = !!tcc_output_file(s, s->outfile);
- if (s->gen_deps && !ret)
+ if (tcc_output_file(s, s->outfile))
+ ret = 1;
+ else if (s->gen_deps)
gen_makedeps(s, s->outfile, s->deps_outfile);
}
}
- if (s->do_bench)
+ if (s->do_bench && (n | t | ret) == 0)
tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s);
+ if (ret == 0 && n)
+ goto redo; /* compile more files with -c */
+ if (t)
+ goto redo; /* run more tests with -dt -run */
+ if (ppfp && ppfp != stdout)
+ fclose(ppfp);
return ret;
}
diff --git a/tcc.h b/tcc.h
index 9b65e6d..cd67973 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1,6 +1,6 @@
/*
* TCC - Tiny C Compiler
- *
+ *
* Copyright (c) 2001-2004 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
@@ -41,10 +41,11 @@
# include <dlfcn.h>
# endif
/* XXX: need to define this to use them in non ISOC99 context */
- extern float strtof (const char *__nptr, char **__endptr);
- extern long double strtold (const char *__nptr, char **__endptr);
+extern float strtof (const char *__nptr, char **__endptr);
+extern long double strtold (const char *__nptr, char **__endptr);
+#endif
-#else /* on _WIN32: */
+#ifdef _WIN32
# include <windows.h>
# include <io.h> /* open, close etc. */
# include <direct.h> /* getcwd */
@@ -52,7 +53,6 @@
# include <stdint.h>
# endif
# define inline __inline
-# define inp next_inp /* inp is an intrinsic on msvc */
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# ifndef __GNUC__
@@ -65,12 +65,14 @@
# define LIBTCCAPI __declspec(dllexport)
# define PUB_FUNC LIBTCCAPI
# endif
+# define inp next_inp /* inp is an intrinsic on msvc/mingw */
# ifdef _MSC_VER
# pragma warning (disable : 4244) // conversion from 'uint64_t' to 'int', possible loss of data
# pragma warning (disable : 4267) // conversion from 'size_t' to 'int', possible loss of data
# pragma warning (disable : 4996) // The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
# 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
# endif
# undef CONFIG_TCC_STATIC
#endif
@@ -79,28 +81,32 @@
# define O_BINARY 0
#endif
-#ifdef __GNUC__
-# define NORETURN __attribute__ ((noreturn))
-#elif defined _MSC_VER
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+#endif
+
+#ifndef countof
+#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
+#endif
+
+#ifdef _MSC_VER
# define NORETURN __declspec(noreturn)
+# define ALIGNED(x) __declspec(align(x))
#else
-# define NORETURN
+# define NORETURN __attribute__((noreturn))
+# define ALIGNED(x) __attribute__((aligned(x)))
#endif
#ifdef _WIN32
# define IS_DIRSEP(c) (c == '/' || c == '\\')
# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2])))
# define PATHCMP stricmp
+# define PATHSEP ";"
#else
# define IS_DIRSEP(c) (c == '/')
# define IS_ABSPATH(p) IS_DIRSEP(p[0])
# define PATHCMP strcmp
-#endif
-
-#ifdef TCC_TARGET_PE
-#define PATHSEP ';'
-#else
-#define PATHSEP ':'
+# define PATHSEP ":"
#endif
/* -------------------------------------------- */
@@ -118,33 +124,29 @@
/* target selection */
/* #define TCC_TARGET_I386 *//* i386 code generator */
+/* #define TCC_TARGET_X86_64 *//* x86-64 code generator */
/* #define TCC_TARGET_ARM *//* ARMv4 code generator */
/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */
/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */
-/* #define TCC_TARGET_X86_64 *//* x86-64 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)
-#define TCC_TARGET_I386
-#endif
-
-#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
- !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
- !defined(CONFIG_USE_LIBGCC)
-#define CONFIG_TCC_BCHECK /* enable bound checking code */
-#endif
-
-/* define it to include assembler support */
-#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64) && \
- !defined(TCC_TARGET_C67)
-#define CONFIG_TCC_ASM
-#endif
-
-/* object format selection */
-#if defined(TCC_TARGET_C67)
-#define TCC_TARGET_COFF
+# if defined __x86_64__ || defined _AMD64_
+# define TCC_TARGET_X86_64
+# elif defined __arm__
+# define TCC_TARGET_ARM
+# define TCC_ARM_EABI
+# define TCC_ARM_HARDFLOAT
+# elif defined __aarch64__
+# define TCC_TARGET_ARM64
+# else
+# define TCC_TARGET_I386
+# endif
+# ifdef _WIN32
+# define TCC_TARGET_PE 1
+# endif
#endif
/* only native compiler supports -run */
@@ -162,6 +164,10 @@
#if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT
# define CONFIG_TCC_BACKTRACE
+# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) \
+ && !defined TCC_UCLIBC && !defined TCC_MUSL
+# define CONFIG_TCC_BCHECK /* enable bound checking code */
+# endif
#endif
/* ------------ path configuration ------------ */
@@ -170,7 +176,7 @@
# define CONFIG_SYSROOT ""
#endif
#ifndef CONFIG_TCCDIR
-# define CONFIG_TCCDIR "."
+# define CONFIG_TCCDIR "/usr/local/lib/tcc"
#endif
#ifndef CONFIG_LDDIR
# define CONFIG_LDDIR "lib"
@@ -193,7 +199,7 @@
/* system include paths */
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
# ifdef TCC_TARGET_PE
-# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include;{B}/include/winapi"
+# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi"
# else
# define CONFIG_TCC_SYSINCLUDEPATHS \
"{B}/include" \
@@ -235,11 +241,23 @@
# elif defined(TCC_UCLIBC)
# define CONFIG_TCC_ELFINTERP "/lib/ld-uClibc.so.0" /* is there a uClibc for x86_64 ? */
# elif defined TCC_TARGET_ARM64
-# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1"
+# if defined(TCC_MUSL)
+# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-aarch64.so.1"
+# else
+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-aarch64.so.1"
+# endif
# elif defined(TCC_TARGET_X86_64)
-# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
+# if defined(TCC_MUSL)
+# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1"
+# else
+# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
+# endif
# elif !defined(TCC_ARM_EABI)
-# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
+# if defined(TCC_MUSL)
+# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
+# else
+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
+# endif
# endif
#endif
@@ -250,13 +268,15 @@
# define DEFAULT_ELFINTERP(s) default_elfinterp(s)
#endif
-/* target specific subdir for libtcc1.a */
-#ifndef TCC_ARCH_DIR
-# define TCC_ARCH_DIR ""
+/* (target specific) libtcc1.a */
+#ifndef TCC_LIBTCC1
+# define TCC_LIBTCC1 "libtcc1.a"
#endif
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
+#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
#define TCC_LIBGCC USE_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1"
+#endif
/* -------------------------------------------- */
@@ -264,23 +284,29 @@
#include "elf.h"
#include "stab.h"
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
-# define ELFCLASSW ELFCLASS64
-# define ElfW(type) Elf##64##_##type
-# define ELFW(type) ELF##64##_##type
-# define ElfW_Rel ElfW(Rela)
-# define SHT_RELX SHT_RELA
-# define REL_SECTION_FMT ".rela%s"
+/* -------------------------------------------- */
+
+#ifndef PUB_FUNC /* functions used by tcc.c but not in libtcc.h */
+# define PUB_FUNC
+#endif
+
+#ifndef ONE_SOURCE
+# define ONE_SOURCE 1
+#endif
+
+#if ONE_SOURCE
+#define ST_INLN static inline
+#define ST_FUNC static
+#define ST_DATA static
#else
-# define ELFCLASSW ELFCLASS32
-# define ElfW(type) Elf##32##_##type
-# define ELFW(type) ELF##32##_##type
-# define ElfW_Rel ElfW(Rel)
-# define SHT_RELX SHT_REL
-# define REL_SECTION_FMT ".rel%s"
+#define ST_INLN
+#define ST_FUNC
+#define ST_DATA extern
+#endif
+
+#ifdef TCC_PROFILE /* profile all functions */
+# define static
#endif
-/* target address type */
-#define addr_t ElfW(Addr)
/* -------------------------------------------- */
/* include the target specific definitions */
@@ -297,12 +323,14 @@
#ifdef TCC_TARGET_ARM
# include "arm-gen.c"
# include "arm-link.c"
+# include "arm-asm.c"
#endif
#ifdef TCC_TARGET_ARM64
# include "arm64-gen.c"
# include "arm64-link.c"
#endif
#ifdef TCC_TARGET_C67
+# define TCC_TARGET_COFF
# include "coff.h"
# include "c67-gen.c"
# include "c67-link.c"
@@ -311,6 +339,33 @@
/* -------------------------------------------- */
+#if PTR_SIZE == 8
+# define ELFCLASSW ELFCLASS64
+# define ElfW(type) Elf##64##_##type
+# define ELFW(type) ELF##64##_##type
+# define ElfW_Rel ElfW(Rela)
+# define SHT_RELX SHT_RELA
+# define REL_SECTION_FMT ".rela%s"
+#else
+# define ELFCLASSW ELFCLASS32
+# define ElfW(type) Elf##32##_##type
+# define ELFW(type) ELF##32##_##type
+# define ElfW_Rel ElfW(Rel)
+# define SHT_RELX SHT_REL
+# define REL_SECTION_FMT ".rel%s"
+#endif
+/* target address type */
+#define addr_t ElfW(Addr)
+#define ElfSym ElfW(Sym)
+
+#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
+# define LONG_SIZE 8
+#else
+# define LONG_SIZE 4
+#endif
+
+/* -------------------------------------------- */
+
#define INCLUDE_STACK_SIZE 32
#define IFDEF_STACK_SIZE 64
#define VSTACK_SIZE 256
@@ -376,63 +431,64 @@ typedef struct SValue {
result of unary() for an identifier. */
} SValue;
-struct Attribute {
+/* symbol attributes */
+struct SymAttr {
+ unsigned short
+ aligned : 5, /* alignment as log2+1 (0 == unspecified) */
+ packed : 1,
+ weak : 1,
+ visibility : 2,
+ dllexport : 1,
+ dllimport : 1,
+ unused : 5;
+};
+
+/* function attributes or temporary attributes for parsing */
+struct FuncAttr {
unsigned
- func_call : 3, /* calling convention (0..5), see below */
- aligned : 5, /* alignment as log2+1 (0 == unspecified) */
- packed : 1,
- func_export : 1,
- func_import : 1,
- func_args : 5,
- func_proto : 1,
- mode : 4,
- weak : 1,
- visibility : 2,
- unsigned_enum : 1,
- fill : 7; // 7 bits left to fit well in union below
+ func_call : 3, /* calling convention (0..5), see below */
+ func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
+ func_args : 8; /* PE __stdcall args */
};
/* GNUC attribute definition */
typedef struct AttributeDef {
- struct Attribute a;
+ struct SymAttr a;
+ struct FuncAttr f;
struct Section *section;
- int alias_target; /* token */
- int asm_label; /* associated asm label */
+ 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 */
- union {
- int asm_label; /* associated asm label */
- int scope; /* scope level for locals */
- };
+ int v; /* symbol token */
+ unsigned short r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
+ struct SymAttr a; /* symbol attributes */
union {
- long r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
- struct Attribute a;
+ struct {
+ int c; /* associated number or Elf symbol index */
+ union {
+ int sym_scope; /* scope level for locals */
+ int jnext; /* next jump label */
+ struct FuncAttr f; /* function attributes */
+ int auxtype; /* bitfield access type */
+ };
+ };
+ long long enum_val; /* enum constant if IS_ENUM_VAL */
+ int *d; /* define token stream */
};
- union {
- long c; /* associated number */
- int *d; /* define token stream */
- };
- CType type; /* associated type */
+ CType type; /* associated type */
union {
struct Sym *next; /* next related symbol (for fields and anoms) */
- long jnext; /* next jump label */
+ int asm_label; /* associated asm label */
};
struct Sym *prev; /* prev symbol in stack */
struct Sym *prev_tok; /* previous symbol for this token */
} Sym;
/* section definition */
-/* XXX: use directly ELF structure for parameters ? */
-/* special flag to indicate that the section should not be linked to
- the other ones */
-#define SHF_PRIVATE 0x80000000
-
-/* special flag, too */
-#define SECTION_ABS ((void *)1)
-
typedef struct Section {
unsigned long data_offset; /* current data offset */
unsigned char *data; /* section data */
@@ -467,12 +523,12 @@ typedef struct DLLReference {
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
-/* stored in 'Sym.c' field */
+/* stored in 'Sym->f.func_type' field */
#define FUNC_NEW 1 /* ansi function prototype */
#define FUNC_OLD 2 /* old function prototype */
#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
-/* stored in 'Sym.r' field */
+/* stored in 'Sym->f.func_call' field */
#define FUNC_CDECL 0 /* standard c call */
#define FUNC_STDCALL 1 /* pascal c call */
#define FUNC_FASTCALL1 2 /* first param in %eax */
@@ -507,6 +563,7 @@ typedef struct BufferedFile {
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
int include_next_index; /* next search path */
char filename[1024]; /* filename */
+ char *true_filename; /* filename not modified by # line directive */
unsigned char unget[4];
unsigned char buffer[1]; /* extra size for CH_EOB char */
} BufferedFile;
@@ -514,21 +571,14 @@ typedef struct BufferedFile {
#define CH_EOB '\\' /* end of buffer or '\0' char in file */
#define CH_EOF (-1) /* end of file */
-/* parsing state (used to save parser state to reparse part of the
- source several times) */
-typedef struct ParseState {
- const int *macro_ptr;
- int line_num;
- int tok;
- CValue tokc;
-} ParseState;
-
/* used to record tokens */
typedef struct TokenString {
int *str;
int len;
+ int lastlen;
int allocated_len;
int last_line_num;
+ int save_line_num;
/* used to chain token-strings with begin/end_macro() */
struct TokenString *prev;
const int *prev_ptr;
@@ -562,7 +612,7 @@ typedef struct ExprValue {
#define MAX_ASM_OPERANDS 30
typedef struct ASMOperand {
- int id; /* GCC 3 optionnal identifier (0 if number only supported */
+ int id; /* GCC 3 optional identifier (0 if number only supported */
char *constraint;
char asm_str[16]; /* computed asm string for operand */
SValue *vt; /* C value of the expression */
@@ -601,6 +651,7 @@ struct TCCState {
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;
@@ -610,10 +661,8 @@ struct TCCState {
/* C language options */
int char_is_unsigned;
int leading_underscore;
- int ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
- int old_struct_init_code; /* use old algorithm to init array in struct when there is no '{' used.
- Liuux 2.4.26 can't find initrd when compiled with a new algorithm */
- int dollars_in_identifiers; /* allows '$' char in indentifiers */
+ 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 */
/* warning switches */
@@ -622,6 +671,7 @@ struct TCCState {
int warn_error;
int warn_none;
int warn_implicit_function_declaration;
+ int warn_gcc_compat;
/* compile with debug symbol (and use them if error during execution) */
int do_debug;
@@ -632,6 +682,7 @@ struct TCCState {
#ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/
#endif
+ int run_test; /* nth test to run with -dt -run */
addr_t text_addr; /* address of text section */
int has_text_addr;
@@ -640,7 +691,7 @@ struct TCCState {
char *init_symbol; /* symbols to call at load-time (not used currently) */
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
-
+
#ifdef TCC_TARGET_I386
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
#endif
@@ -683,7 +734,8 @@ struct TCCState {
enum {
LINE_MACRO_OUTPUT_FORMAT_GCC,
LINE_MACRO_OUTPUT_FORMAT_NONE,
- LINE_MACRO_OUTPUT_FORMAT_STD
+ LINE_MACRO_OUTPUT_FORMAT_STD,
+ LINE_MACRO_OUTPUT_FORMAT_P10 = 11
} Pflag; /* -P switch */
char dflag; /* -dX value */
@@ -729,19 +781,19 @@ struct TCCState {
Section *dynsymtab_section;
/* exported dynamic symbol section */
Section *dynsym;
- /* copy of the gobal symtab_section variable */
+ /* copy of the global symtab_section variable */
Section *symtab;
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
struct sym_attr *sym_attrs;
int nb_sym_attrs;
- /* tiny assembler state */
- Sym *asm_labels;
#ifdef TCC_TARGET_PE
/* PE info */
int pe_subsystem;
+ unsigned pe_characteristics;
unsigned pe_file_align;
unsigned pe_stack_size;
+ addr_t pe_imagebase;
# ifdef TCC_TARGET_X86_64
Section *uw_pdata;
int uw_sym;
@@ -761,17 +813,19 @@ struct TCCState {
int nb_libraries; /* number of libs thereof */
int filetype;
char *outfile; /* output filename */
- char *option_m; /* only -m32/-m64 handled */
- int print_search_dirs; /* option */
int option_r; /* option -r */
int 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, name[1];
+ char type;
+ char alacarte;
+ char name[1];
};
/* The current value can be: */
@@ -782,7 +836,6 @@ struct filespec {
#define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */
#define VT_JMP 0x0034 /* value is the consequence of jmp true (even) */
#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */
-#define VT_REF 0x0040 /* value is pointer to structure rather than address */
#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
@@ -798,53 +851,57 @@ struct filespec {
/* types */
#define VT_BTYPE 0x000f /* mask for basic type */
-#define VT_INT 0 /* integer type */
+#define VT_VOID 0 /* void 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_INT 3 /* integer type */
+#define VT_LLONG 4 /* 64 bit integer */
+#define VT_PTR 5 /* pointer */
#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_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */
-#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */
+#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */
+#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */
+
#define VT_UNSIGNED 0x0010 /* unsigned type */
-#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
-#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_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
+#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */
+#define VT_ARRAY 0x0040 /* array type (also has VT_PTR) */
+#define VT_BITFIELD 0x0080 /* bitfield modifier */
+#define VT_CONSTANT 0x0100 /* const modifier */
+#define VT_VOLATILE 0x0200 /* volatile modifier */
+#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */
+#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */
/* storage */
-#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 /* weak symbol */
-#define VT_TLS 0x00040000 /* thread-local storage */
-#define VT_VIS_SHIFT 19 /* shift for symbol visibility, overlapping
- bitfield values, because bitfields never
- have linkage and hence never have
- visibility. */
-#define VT_VIS_SIZE 2 /* We have four visibilities. */
-#define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT)
-
-#define VT_STRUCT_SHIFT 19 /* shift for bitfield shift values (max: 32 - 2*6) */
+#define VT_EXTERN 0x00001000 /* extern definition */
+#define VT_STATIC 0x00002000 /* static variable */
+#define VT_TYPEDEF 0x00004000 /* typedef definition */
+#define VT_INLINE 0x00008000 /* inline definition */
+/* 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 BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
+#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
+#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT)
+#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */
+#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
+
+#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM)
+#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL)
+#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
/* type mask (except storage) */
-#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK | VT_VIS_MASK)
-#define VT_TYPE (~(VT_STORAGE))
+#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
+#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
+
+/* symbol was created by tccasm.c first */
+#define VT_ASM (VT_VOID | VT_UNSIGNED)
+#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
/* token values */
@@ -886,6 +943,7 @@ struct filespec {
#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 */
@@ -899,12 +957,14 @@ struct filespec {
#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 0xce /* A '##' in the right position to mean pasting */
+#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 */
-
-/* assignement operators : normal operator or 0x80 */
+
+/* assignment operators : normal operator or 0x80 */
#define TOK_A_MOD 0xa5
#define TOK_A_AND 0xa6
#define TOK_A_MUL 0xaa
@@ -916,18 +976,10 @@ struct filespec {
#define TOK_A_SHL 0x81
#define TOK_A_SAR 0x82
-#ifndef offsetof
-#define offsetof(type, field) ((size_t) &((type *)0)->field)
-#endif
-
-#ifndef countof
-#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
-#endif
-
#define TOK_EOF (-1) /* end of file */
#define TOK_LINEFEED 10 /* line feed */
-/* all identificators and strings have token above that */
+/* all identifiers and strings have token above that */
#define TOK_IDENT 256
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
@@ -1025,26 +1077,6 @@ enum tcc_token {
/* keywords: tok >= TOK_IDENT && tok < TOK_UIDENT */
#define TOK_UIDENT TOK_DEFINE
-/* -------------------------------------------- */
-
-#ifndef PUB_FUNC /* functions used by tcc.c but not in libtcc.h */
-# define PUB_FUNC
-#endif
-
-#ifdef ONE_SOURCE
-#define ST_INLN static inline
-#define ST_FUNC static
-#define ST_DATA static
-#else
-#define ST_INLN
-#define ST_FUNC
-#define ST_DATA extern
-#endif
-
-#ifdef TCC_PROFILE /* profile all functions */
-# define static
-#endif
-
/* ------------ libtcc.c ------------ */
/* use GNU C extensions */
@@ -1055,9 +1087,9 @@ ST_DATA int tcc_ext;
ST_DATA struct TCCState *tcc_state;
/* public functions currently used by the tcc main function */
-PUB_FUNC char *pstrcpy(char *buf, int buf_size, const char *s);
-PUB_FUNC char *pstrcat(char *buf, int buf_size, const char *s);
-PUB_FUNC char *pstrncpy(char *out, const char *in, size_t num);
+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 *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);
@@ -1085,13 +1117,13 @@ 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_memstats(int bench);
+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, ...);
/* other utilities */
-ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data);
+ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
ST_FUNC void dynarray_reset(void *pp, int *n);
ST_INLN void cstr_ccat(CString *cstr, int ch);
ST_FUNC void cstr_cat(CString *cstr, const char *str, int len);
@@ -1101,13 +1133,13 @@ ST_FUNC void cstr_free(CString *cstr);
ST_FUNC void cstr_reset(CString *cstr);
ST_INLN void sym_free(Sym *sym);
-ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);
+ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c);
ST_FUNC Sym *sym_find2(Sym *s, int v);
-ST_FUNC Sym *sym_push(int v, CType *type, int r, long c);
+ST_FUNC Sym *sym_push(int v, CType *type, int r, int c);
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
ST_INLN Sym *struct_find(int v);
ST_INLN Sym *sym_find(int v);
-ST_FUNC Sym *global_identifier_push(int v, int t, long c);
+ST_FUNC Sym *global_identifier_push(int v, int t, int c);
ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
ST_FUNC int tcc_open(TCCState *s1, const char *filename);
@@ -1117,15 +1149,13 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
/* 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_PREPROCESS 0x40 /* preprocess file */
-/* combined with: */
+#define AFF_TYPE_BIN 0x40 /* file to add is binary */
+/* 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_BIN 4
-#define AFF_TYPE_LIB 5
-#define AFF_TYPE_LIBWH 6
+#define AFF_TYPE_LIB 4
/* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1
#define AFF_BINTYPE_DYN 2
@@ -1134,21 +1164,25 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
-
-#ifndef TCC_TARGET_PE
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
-#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);
-PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv);
-PUB_FUNC void tcc_set_environment(TCCState *s);
+PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind);
#ifdef _WIN32
ST_FUNC char *normalize_slashes(char *path);
#endif
+/* tcc_parse_args return codes: */
+#define OPT_HELP 1
+#define OPT_HELP2 2
+#define OPT_V 3
+#define OPT_PRINT_DIRS 4
+#define OPT_AR 5
+#define OPT_IMPDEF 6
+#define OPT_M32 32
+#define OPT_M64 64
+
/* ------------ tccpp.c ------------ */
ST_DATA struct BufferedFile *file;
@@ -1189,9 +1223,7 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len);
ST_FUNC const char *get_tok_str(int v, CValue *cv);
ST_FUNC void begin_macro(TokenString *str, int alloc);
ST_FUNC void end_macro(void);
-ST_FUNC void set_idnum(int c, int val);
-ST_FUNC void save_parse_state(ParseState *s);
-ST_FUNC void restore_parse_state(ParseState *s);
+ST_FUNC int set_idnum(int c, int val);
ST_INLN void tok_str_new(TokenString *s);
ST_FUNC TokenString *tok_str_alloc(void);
ST_FUNC void tok_str_free(TokenString *s);
@@ -1204,20 +1236,21 @@ ST_INLN Sym *define_find(int v);
ST_FUNC void free_defines(Sym *b);
ST_FUNC Sym *label_find(int v);
ST_FUNC Sym *label_push(Sym **ptop, int v, int flags);
-ST_FUNC void label_pop(Sym **ptop, Sym *slast);
+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);
+ST_FUNC void preprocess_start(TCCState *s1, int is_asm);
+ST_FUNC void preprocess_end(TCCState *s1);
ST_FUNC void tccpp_new(TCCState *s);
ST_FUNC void tccpp_delete(TCCState *s);
ST_FUNC int tcc_preprocess(TCCState *s1);
ST_FUNC void skip(int c);
ST_FUNC NORETURN void expect(const char *msg);
-/* space exlcuding newline */
+/* space excluding newline */
static inline int is_space(int ch) {
return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r';
}
@@ -1259,19 +1292,26 @@ 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_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_start(TCCState *s1);
-ST_FUNC void tccgen_end(TCCState *s1);
+ST_FUNC int tccgen_compile(TCCState *s1);
ST_FUNC void free_inline_functions(TCCState *s);
ST_FUNC void check_vstack(void);
ST_INLN int is_float(int t);
ST_FUNC int ieee_finite(double d);
ST_FUNC void test_lvalue(void);
-ST_FUNC void swap(int *p, int *q);
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 void vset(CType *type, int r, long v);
+ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vswap(void);
ST_FUNC void vpush_global_sym(CType *type, int v);
ST_FUNC void vrote(SValue *e, int n);
@@ -1304,7 +1344,6 @@ ST_FUNC void expr_prod(void);
ST_FUNC void expr_sum(void);
ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void);
-ST_FUNC void decl(int l);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size);
#endif
@@ -1329,6 +1368,7 @@ typedef struct {
} 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 */
@@ -1340,24 +1380,29 @@ 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, *strtab_section;
+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);
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);
ST_FUNC void *section_ptr_add(Section *sec, addr_t size);
ST_FUNC void section_reserve(Section *sec, unsigned long size);
ST_FUNC Section *find_section(TCCState *s1, const char *name);
ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
-ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore);
+ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore);
ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size);
+#if PTR_SIZE == 4
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
+#endif
ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend);
ST_FUNC int put_elf_str(Section *s, const char *sym);
@@ -1372,11 +1417,10 @@ ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigne
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 relocate_common_syms(void);
+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 void tcc_add_linker_symbols(TCCState *s1);
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);
@@ -1403,7 +1447,7 @@ ST_FUNC int handle_eob(void);
/* ------------ xxx-link.c ------------ */
-/* Wether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
+/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
that unknown relocation don't create a GOT or PLT entry */
enum gotplt_entry {
NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */
@@ -1416,7 +1460,7 @@ ST_FUNC int code_reloc (int reloc_type);
ST_FUNC int gotplt_entry_type (int reloc_type);
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, char *ptr, addr_t addr, addr_t val);
+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);
/* ------------ xxx-gen.c ------------ */
@@ -1458,13 +1502,13 @@ static inline uint16_t read16le(unsigned char *p) {
return p[0] | (uint16_t)p[1] << 8;
}
static inline void write16le(unsigned char *p, uint16_t x) {
- p[0] = x & 255, p[1] = x >> 8 & 255;
+ p[0] = x & 255; p[1] = x >> 8 & 255;
}
static inline uint32_t read32le(unsigned char *p) {
return read16le(p) | (uint32_t)read16le(p + 2) << 16;
}
static inline void write32le(unsigned char *p, uint32_t x) {
- write16le(p, x), write16le(p + 2, x >> 16);
+ write16le(p, x); write16le(p + 2, x >> 16);
}
static inline void add32le(unsigned char *p, int32_t x) {
write32le(p, read32le(p) + x);
@@ -1473,7 +1517,7 @@ static inline uint64_t read64le(unsigned char *p) {
return read32le(p) | (uint64_t)read32le(p + 4) << 32;
}
static inline void write64le(unsigned char *p, uint64_t x) {
- write32le(p, x), write32le(p + 4, x >> 32);
+ write32le(p, x); write32le(p + 4, x >> 32);
}
static inline void add64le(unsigned char *p, int64_t x) {
write64le(p, read64le(p) + x);
@@ -1482,11 +1526,10 @@ static inline void add64le(unsigned char *p, int64_t x) {
/* ------------ i386-gen.c ------------ */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC void g(int c);
-ST_FUNC int oad(int c, int s);
ST_FUNC void gen_le16(int c);
ST_FUNC void gen_le32(int c);
-ST_FUNC void gen_addr32(int r, Sym *sym, long c);
-ST_FUNC void gen_addrpc32(int r, Sym *sym, long 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
@@ -1498,15 +1541,17 @@ ST_FUNC void gen_bounded_ptr_deref(void);
#ifdef TCC_TARGET_X86_64
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
ST_FUNC void gen_opl(int op);
+#ifdef TCC_TARGET_PE
+ST_FUNC void gen_vla_result(int addr);
+#endif
#endif
/* ------------ arm-gen.c ------------ */
#ifdef TCC_TARGET_ARM
#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
-ST_FUNC char *default_elfinterp(struct TCCState *s);
+PUB_FUNC const char *default_elfinterp(struct TCCState *s);
#endif
ST_FUNC void arm_init(struct TCCState *s);
-ST_FUNC uint32_t encbranch(int pos, int addr, int fail);
ST_FUNC void gen_cvt_itof1(int t);
#endif
@@ -1514,7 +1559,7 @@ ST_FUNC void gen_cvt_itof1(int t);
#ifdef TCC_TARGET_ARM64
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_opl(int op);
-ST_FUNC void greturn(void);
+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);
@@ -1558,17 +1603,19 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str);
ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd);
ST_FUNC int pe_output_file(TCCState * s1, const char *filename);
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value);
-#ifndef TCC_TARGET_ARM
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2);
#endif
#ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif
+PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
/* symbol properties stored in Elf32_Sym->st_other */
# define ST_PE_EXPORT 0x10
# define ST_PE_IMPORT 0x20
# define ST_PE_STDCALL 0x40
#endif
+#define ST_ASM_SET 0x04
/* ------------ tccrun.c ----------------- */
#ifdef TCC_IS_NATIVE
@@ -1592,9 +1639,19 @@ ST_FUNC void tcc_set_num_callers(int n);
ST_FUNC void tcc_run_free(TCCState *s1);
#endif
+/* ------------ tcctools.c ----------------- */
+#if 0 /* included in tcc.c */
+ST_FUNC int tcc_tool_ar(TCCState *s, int argc, char **argv);
+#ifdef TCC_TARGET_PE
+ST_FUNC int tcc_tool_impdef(TCCState *s, int argc, char **argv);
+#endif
+ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option);
+ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename);
+#endif
+
/********************************************************/
#undef ST_DATA
-#ifdef ONE_SOURCE
+#if ONE_SOURCE
#define ST_DATA static
#else
#define ST_DATA
diff --git a/tccasm.c b/tccasm.c
index 7e9c6e6..c035c8b 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -31,55 +31,59 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
return ts->tok;
}
-ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
-static int tcc_assemble_internal(TCCState *s1, int do_preprocess);
-static Sym sym_dot;
+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);
+
+static Sym *asm_label_find(int v)
+{
+ Sym *sym = sym_find(v);
+ while (sym && sym->sym_scope)
+ sym = sym->prev_tok;
+ return sym;
+}
+
+static Sym *asm_label_push(int v)
+{
+ /* 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;
+ return sym;
+}
/* Return a symbol we can use inside the assembler, having name NAME.
- The assembler symbol table is different from the C symbol table
- (and the Sym members are used differently). But we must be able
- to look up file-global C symbols from inside the assembler, e.g.
- for global asm blocks to be able to refer to defined C symbols.
-
- This routine gives back either an existing asm-internal
- symbol, or a new one. In the latter case the new asm-internal
- symbol is initialized with info from the C symbol table.
-
- If CSYM is non-null we take symbol info from it, otherwise
- we look up NAME in the C symbol table and use that. */
+ Symbols from asm and C source share a namespace. If we generate
+ an asm symbol it's also a (file-global) C symbol, but it's
+ either not accessible by name (like "L.123"), or its type information
+ is such that it's not usable without a proper C declaration.
+
+ Sometimes we need symbols accessible by name from asm, which
+ are anonymous in C, in this case CSYM can be used to transfer
+ all information from that symbol to the (possibly newly created)
+ asm symbol. */
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
{
- Sym *sym = label_find(name);
+ Sym *sym = asm_label_find(name);
if (!sym) {
- sym = label_push(&tcc_state->asm_labels, name, 0);
- sym->type.t = VT_VOID | VT_EXTERN;
- if (!csym) {
- csym = sym_find(name);
- /* We might be called for an asm block from inside a C routine
- and so might have local decls on the identifier stack. Search
- for the first global one. */
- while (csym && csym->scope)
- csym = csym->prev_tok;
- }
- /* Now, if we have a defined global symbol copy over
- section and offset. */
- if (csym &&
- ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
- csym->c) {
- ElfW(Sym) *esym;
- esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
- sym->c = csym->c;
- sym->r = esym->st_shndx;
- sym->jnext = esym->st_value;
- /* XXX can't yet store st_size anywhere. */
- sym->type.t &= ~VT_EXTERN;
- /* Mark that this asm symbol doesn't need to be fed back. */
- sym->type.t |= VT_IMPORT;
- }
+ sym = asm_label_push(name);
+ if (csym)
+ sym->c = csym->c;
}
return sym;
}
+static Sym* asm_section_sym(TCCState *s1, Section *sec)
+{
+ char buf[100];
+ int label = tok_alloc(buf,
+ snprintf(buf, sizeof buf, "L.%s", sec->name)
+ )->tok;
+ Sym *sym = asm_label_find(label);
+ return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
+}
+
/* We do not use the C expression parser to handle symbols. Maybe the
C expression parser could be tweaked to do so. */
@@ -87,29 +91,28 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
{
Sym *sym;
int op, label;
- unsigned long n;
+ uint64_t n;
const char *p;
switch(tok) {
case TOK_PPNUM:
p = tokc.str.data;
- n = strtoul(p, (char **)&p, 0);
+ n = strtoull(p, (char **)&p, 0);
if (*p == 'b' || *p == 'f') {
/* backward or forward label */
label = asm_get_local_label_name(s1, n);
- sym = label_find(label);
+ sym = asm_label_find(label);
if (*p == 'b') {
/* backward : find the last corresponding defined label */
- if (sym && sym->r == 0)
+ 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);
} else {
/* forward */
- if (!sym || sym->r) {
+ if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
/* if the last label is defined, then define a new one */
- sym = label_push(&s1->asm_labels, label, 0);
- sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
+ sym = asm_label_push(label);
}
}
pe->v = 0;
@@ -153,21 +156,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
skip(')');
break;
case '.':
- pe->v = 0;
- pe->sym = &sym_dot;
- pe->pcrel = 0;
- sym_dot.type.t = VT_VOID | VT_STATIC;
- sym_dot.r = cur_text_section->sh_num;
- sym_dot.jnext = ind;
+ pe->v = ind;
+ pe->sym = asm_section_sym(s1, cur_text_section);
+ pe->pcrel = 0;
next();
break;
default:
if (tok >= TOK_IDENT) {
+ ElfSym *esym;
/* label case : if the label was not found, add one */
sym = get_asm_sym(tok, NULL);
- if (sym->r == SHN_ABS) {
+ esym = elfsym(sym);
+ if (esym && esym->st_shndx == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
- pe->v = sym->jnext;
+ pe->v = esym->st_value;
pe->sym = NULL;
pe->pcrel = 0;
} else {
@@ -281,20 +283,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
} else if (pe->sym == e2.sym) {
/* OK */
pe->sym = NULL; /* same symbols can be subtracted to NULL */
- } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
- /* we also accept defined symbols in the same section */
- pe->v += pe->sym->jnext - e2.sym->jnext;
- pe->sym = NULL;
- } else if (e2.sym->r == cur_text_section->sh_num) {
- /* When subtracting a defined symbol in current section
- this actually makes the value PC-relative. */
- pe->v -= e2.sym->jnext - ind - 4;
- pe->pcrel = 1;
- e2.sym = NULL;
- } else {
- cannot_relocate:
- tcc_error("invalid operation with label");
- }
+ } else {
+ ElfSym *esym1, *esym2;
+ esym1 = elfsym(pe->sym);
+ esym2 = elfsym(e2.sym);
+ if (esym1 && esym1->st_shndx == esym2->st_shndx
+ && esym1->st_shndx != SHN_UNDEF) {
+ /* we also accept defined symbols in the same section */
+ pe->v += esym1->st_value - esym2->st_value;
+ pe->sym = NULL;
+ } else if (esym2->st_shndx == cur_text_section->sh_num) {
+ /* When subtracting a defined symbol in current section
+ this actually makes the value PC-relative. */
+ pe->v -= esym2->st_value - ind - 4;
+ pe->pcrel = 1;
+ e2.sym = NULL;
+ } else {
+cannot_relocate:
+ tcc_error("invalid operation with label");
+ }
+ }
}
}
}
@@ -355,38 +363,38 @@ ST_FUNC int asm_int_expr(TCCState *s1)
return e.v;
}
-/* NOTE: the same name space as C labels is used to avoid using too
- much memory when storing labels in TokenStrings */
static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
+ ElfSym *esym;
- sym = label_find(label);
+ sym = asm_label_find(label);
if (sym) {
+ esym = elfsym(sym);
/* A VT_EXTERN symbol, even if it has a section is considered
overridable. This is how we "define" .set targets. Real
definitions won't have VT_EXTERN set. */
- if (sym->r && !(sym->type.t & VT_EXTERN)) {
+ if (esym && esym->st_shndx != SHN_UNDEF) {
/* the label is already defined */
- if (!is_local) {
- tcc_error("assembler label '%s' already defined",
- get_tok_str(label, NULL));
- } else {
- /* redefinition of local labels is possible */
+ if (IS_ASM_SYM(sym)
+ && (is_local == 1 || (sym->type.t & VT_EXTERN)))
goto new_label;
- }
+ if (!(sym->type.t & VT_EXTERN))
+ tcc_error("assembler label '%s' already defined",
+ get_tok_str(label, NULL));
}
} else {
new_label:
- sym = label_push(&s1->asm_labels, label, 0);
- /* If we need a symbol to hold a value, mark it as
- tentative only (for .set). If this is for a real label
- we'll remove VT_EXTERN. */
- sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
+ sym = asm_label_push(label);
}
- sym->r = sh_num;
- sym->jnext = value;
+ if (!sym->c)
+ put_extern_sym2(sym, SHN_UNDEF, 0, 0, 0);
+ esym = elfsym(sym);
+ esym->st_shndx = sh_num;
+ esym->st_value = value;
+ if (is_local != 2)
+ sym->type.t &= ~VT_EXTERN;
return sym;
}
@@ -401,35 +409,17 @@ static Sym* set_symbol(TCCState *s1, int label)
{
long n;
ExprValue e;
+ Sym *sym;
+ ElfSym *esym;
next();
asm_expr(s1, &e);
n = e.v;
- if (e.sym)
- n += e.sym->jnext;
- return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
-}
-
-static void asm_free_labels(TCCState *st)
-{
- Sym *s, *s1;
- Section *sec;
-
- for(s = st->asm_labels; s != NULL; s = s1) {
- s1 = s->prev;
- /* define symbol value in object file */
- s->type.t &= ~VT_EXTERN;
- if (s->r && !(s->type.t & VT_IMPORT)) {
- if (s->r == SHN_ABS)
- sec = SECTION_ABS;
- else
- sec = st->sections[s->r];
- put_extern_sym2(s, sec, s->jnext, 0, 0);
- }
- /* remove label */
- table_ident[s->v - TOK_IDENT]->sym_label = NULL;
- sym_free(s);
- }
- st->asm_labels = NULL;
+ esym = elfsym(e.sym);
+ if (esym)
+ n += esym->st_value;
+ sym = asm_new_label1(s1, label, 2, esym ? esym->st_shndx : SHN_ABS, n);
+ elfsym(sym)->st_other |= ST_ASM_SET;
+ return sym;
}
static void use_section1(TCCState *s1, Section *sec)
@@ -462,7 +452,7 @@ static void pop_section(TCCState *s1)
use_section1(s1, prev);
}
-static void asm_parse_directive(TCCState *s1)
+static void asm_parse_directive(TCCState *s1, int global)
{
int n, offset, v, size, tok1;
Section *sec;
@@ -628,40 +618,39 @@ static void asm_parse_directive(TCCState *s1)
{
int repeat;
TokenString *init_str;
- ParseState saved_parse_state = {0};
next();
repeat = asm_int_expr(s1);
init_str = tok_str_alloc();
- next();
- while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
+ while (next(), tok != TOK_ASMDIR_endr) {
+ if (tok == CH_EOF)
+ tcc_error("we at end of file, .endr not found");
tok_str_add_tok(init_str);
- next();
}
- if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
- next();
tok_str_add(init_str, -1);
tok_str_add(init_str, 0);
- save_parse_state(&saved_parse_state);
begin_macro(init_str, 1);
while (repeat-- > 0) {
- tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS));
+ tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS),
+ global);
macro_ptr = init_str->str;
}
end_macro();
- restore_parse_state(&saved_parse_state);
+ next();
break;
}
case TOK_ASMDIR_org:
{
unsigned long n;
ExprValue e;
+ ElfSym *esym;
next();
asm_expr(s1, &e);
n = e.v;
- if (e.sym) {
- if (e.sym->r != cur_text_section->sh_num)
+ esym = elfsym(e.sym);
+ if (esym) {
+ if (esym->st_shndx != cur_text_section->sh_num)
expect("constant or same-section symbol");
- n += e.sym->jnext;
+ n += esym->st_value;
}
if (n < ind)
tcc_error("attempt to .org backwards");
@@ -686,15 +675,15 @@ static void asm_parse_directive(TCCState *s1)
tok1 = tok;
do {
Sym *sym;
-
next();
sym = get_asm_sym(tok, NULL);
if (tok1 != TOK_ASMDIR_hidden)
sym->type.t &= ~VT_STATIC;
if (tok1 == TOK_ASMDIR_weak)
- sym->type.t |= VT_WEAK;
+ sym->a.weak = 1;
else if (tok1 == TOK_ASMDIR_hidden)
- sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
+ sym->a.visibility = STV_HIDDEN;
+ update_storage(sym);
next();
} while (tok == ',');
break;
@@ -785,7 +774,7 @@ static void asm_parse_directive(TCCState *s1)
Sym *sym;
next();
- sym = label_find(tok);
+ sym = asm_label_find(tok);
if (!sym) {
tcc_error("label not found: %s", get_tok_str(tok, NULL));
}
@@ -913,22 +902,21 @@ static void asm_parse_directive(TCCState *s1)
/* assemble a file */
-static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
+static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
{
int opcode;
+ int saved_parse_flags = parse_flags;
- /* XXX: undefine C labels */
-
- ch = file->buf_ptr[0];
- tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
- set_idnum('.', IS_ID);
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
- next();
for(;;) {
+ 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 == '#') {
@@ -936,9 +924,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
while (tok != TOK_LINEFEED)
next();
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
- asm_parse_directive(s1);
+ asm_parse_directive(s1, global);
} else if (tok == TOK_PPNUM) {
- Sym *sym;
const char *p;
int n;
p = tokc.str.data;
@@ -946,9 +933,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
if (*p != '\0')
expect("':'");
/* new local label */
- sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
- /* Remove the marker for tentative definitions. */
- sym->type.t &= ~VT_EXTERN;
+ asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
next();
skip(':');
goto redo;
@@ -957,19 +942,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
opcode = tok;
next();
if (tok == ':') {
- /* handle "extern void vide(void); __asm__("vide: ret");" as
- "__asm__("globl vide\nvide: ret");" */
- Sym *sym = sym_find(opcode);
- if (sym && (sym->type.t & VT_EXTERN) && nocode_wanted) {
- sym = label_find(opcode);
- if (!sym) {
- sym = label_push(&s1->asm_labels, opcode, 0);
- sym->type.t = VT_VOID | VT_EXTERN;
- }
- }
/* new label */
- sym = asm_new_label(s1, opcode, 0);
- sym->type.t &= ~VT_EXTERN;
+ asm_new_label(s1, opcode, 0);
next();
goto redo;
} else if (tok == '=') {
@@ -980,44 +954,27 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
}
}
/* end of line */
- if (tok != ';' && tok != TOK_LINEFEED){
+ if (tok != ';' && tok != TOK_LINEFEED)
expect("end of line");
- }
parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
- next();
}
- asm_free_labels(s1);
-
+ parse_flags = saved_parse_flags;
return 0;
}
/* Assemble the current file */
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
{
- Sym *define_start;
int ret;
-
- preprocess_start(s1);
-
+ tcc_debug_start(s1);
/* default section is text */
cur_text_section = text_section;
ind = cur_text_section->data_offset;
-
- define_start = define_stack;
-
- /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
- symbols can be safely used */
- put_elf_sym(symtab_section, 0, 0,
- ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
- SHN_ABS, file->filename);
-
- ret = tcc_assemble_internal(s1, do_preprocess);
-
+ nocode_wanted = 0;
+ ret = tcc_assemble_internal(s1, do_preprocess, 1);
cur_text_section->data_offset = ind;
-
- free_defines(define_start);
-
+ tcc_debug_end(s1);
return ret;
}
@@ -1027,23 +984,18 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
/* assemble the string 'str' in the current C compilation unit without
C preprocessing. NOTE: str is modified by modifying the '\0' at the
end */
-static void tcc_assemble_inline(TCCState *s1, char *str, int len)
+static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
{
- int saved_parse_flags;
- const int *saved_macro_ptr;
-
- saved_parse_flags = parse_flags;
- saved_macro_ptr = macro_ptr;
+ const int *saved_macro_ptr = macro_ptr;
+ int dotid = set_idnum('.', IS_ID);
tcc_open_bf(s1, ":asm:", len);
memcpy(file->buffer, str, len);
-
macro_ptr = NULL;
- tcc_assemble_internal(s1, 0);
+ tcc_assemble_internal(s1, 0, global);
tcc_close();
- parse_flags = saved_parse_flags;
- set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
+ set_idnum('.', dotid);
macro_ptr = saved_macro_ptr;
}
@@ -1089,7 +1041,6 @@ ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands,
}
static void subst_asm_operands(ASMOperand *operands, int nb_operands,
- int nb_outputs,
CString *out_str, CString *in_str)
{
int c, index, modifier;
@@ -1258,7 +1209,7 @@ ST_FUNC void asm_instr(void)
printf("asm: \"%s\"\n", (char *)astr.data);
#endif
if (must_subst) {
- subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
+ subst_asm_operands(operands, nb_operands, &astr1, &astr);
cstr_free(&astr);
} else {
astr1 = astr;
@@ -1272,7 +1223,7 @@ ST_FUNC void asm_instr(void)
clobber_regs, out_reg);
/* assemble the string with tcc internal assembler */
- tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
+ tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
/* restore the current C token */
next();
@@ -1294,7 +1245,10 @@ ST_FUNC void asm_instr(void)
ST_FUNC void asm_global_instr(void)
{
CString astr;
+ int saved_nocode_wanted = nocode_wanted;
+ /* Global asm blocks are always emitted. */
+ nocode_wanted = 0;
next();
parse_asm_str(&astr);
skip(')');
@@ -1310,7 +1264,7 @@ ST_FUNC void asm_global_instr(void)
ind = cur_text_section->data_offset;
/* assemble the string with tcc internal assembler */
- tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
+ tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 1);
cur_text_section->data_offset = ind;
@@ -1318,5 +1272,6 @@ ST_FUNC void asm_global_instr(void)
next();
cstr_free(&astr);
+ nocode_wanted = saved_nocode_wanted;
}
#endif /* CONFIG_TCC_ASM */
diff --git a/tccelf.c b/tccelf.c
index 003797c..70d47e1 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -27,6 +27,7 @@
/* 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 */
@@ -37,34 +38,40 @@ 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, *strtab_section;
+ST_DATA Section *symtab_section;
/* debug sections */
ST_DATA Section *stab_section, *stabstr_section;
/* XXX: avoid static variable */
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
+/* special flag to indicate that the section should not be linked to the other ones */
+#define SHF_PRIVATE 0x80000000
+/* section is dynsymtab_section */
+#define SHF_DYNSYM 0x40000000
+
/* ------------------------------------------------------------------------- */
ST_FUNC void tccelf_new(TCCState *s)
{
/* no section zero */
- dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
+ dynarray_add(&s->sections, &s->nb_sections, NULL);
/* create standard sections */
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
+ common_section->sh_num = SHN_COMMON;
/* symbols are always generated for linking stage */
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
".strtab",
".hashtab", SHF_PRIVATE);
- strtab_section = symtab_section->link;
s->symtab = symtab_section;
/* private symbol table for dynamic symbols */
- s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
+ s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM,
".dynstrtab",
".dynhashtab", SHF_PRIVATE);
get_sym_attr(s, 0, 1);
@@ -125,6 +132,61 @@ ST_FUNC void tccelf_delete(TCCState *s1)
/* free loaded dlls array */
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
tcc_free(s1->sym_attrs);
+
+ symtab_section = NULL; /* for tccrun.c:rt_printline() */
+}
+
+/* save section data state */
+ST_FUNC void tccelf_begin_file(TCCState *s1)
+{
+ Section *s; int i;
+ for (i = 1; i < s1->nb_sections; i++) {
+ s = s1->sections[i];
+ s->sh_offset = s->data_offset;
+ }
+ /* disable symbol hashing during compilation */
+ s = s1->symtab, s->reloc = s->hash, s->hash = NULL;
+#if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE
+ s1->uw_sym = 0;
+#endif
+}
+
+/* At the end of compilation, convert any UNDEF syms to global, and merge
+ with previously existing symbols */
+ST_FUNC void tccelf_end_file(TCCState *s1)
+{
+ Section *s = s1->symtab;
+ int first_sym, nb_syms, *tr, i;
+
+ first_sym = s->sh_offset / sizeof (ElfSym);
+ nb_syms = s->data_offset / sizeof (ElfSym) - first_sym;
+ s->data_offset = s->sh_offset;
+ s->link->data_offset = s->link->sh_offset;
+ s->hash = s->reloc, s->reloc = NULL;
+ tr = tcc_mallocz(nb_syms * sizeof *tr);
+
+ for (i = 0; i < nb_syms; ++i) {
+ ElfSym *sym = (ElfSym*)s->data + first_sym + i;
+ if (sym->st_shndx == SHN_UNDEF
+ && 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);
+ }
+ /* now update relocations */
+ for (i = 1; i < s1->nb_sections; i++) {
+ Section *sr = s1->sections[i];
+ if (sr->sh_type == SHT_RELX && sr->link == s) {
+ ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset);
+ ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset);
+ for (; rel < rel_end; ++rel) {
+ int n = ELFW(R_SYM)(rel->r_info) - first_sym;
+ //if (n < 0) tcc_error("internal: invalid symbol index in relocation");
+ rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info));
+ }
+ }
+ }
+ tcc_free(tr);
}
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
@@ -148,15 +210,15 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
sec->sh_addralign = 1;
break;
default:
- sec->sh_addralign = PTR_SIZE; /* gcc/pcc default aligment */
+ sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */
break;
}
if (sh_flags & SHF_PRIVATE) {
- dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
+ dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec);
} else {
sec->sh_num = s1->nb_sections;
- dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
+ dynarray_add(&s1->sections, &s1->nb_sections, sec);
}
return sec;
@@ -208,17 +270,27 @@ ST_FUNC void section_realloc(Section *sec, unsigned long new_size)
sec->data_allocated = size;
}
-/* reserve at least 'size' bytes in section 'sec' from
- sec->data_offset. */
-ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
+/* reserve at least 'size' bytes aligned per 'align' in section
+ 'sec' from current offset, and return the aligned offset */
+ST_FUNC size_t section_add(Section *sec, addr_t size, int align)
{
size_t offset, offset1;
- offset = sec->data_offset;
+ offset = (sec->data_offset + align - 1) & -align;
offset1 = offset + size;
- if (offset1 > sec->data_allocated)
+ if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated)
section_realloc(sec, offset1);
sec->data_offset = offset1;
+ if (align > sec->sh_addralign)
+ sec->sh_addralign = align;
+ return offset;
+}
+
+/* reserve at least 'size' bytes in section 'sec' from
+ sec->data_offset. */
+ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
+{
+ size_t offset = section_add(sec, size, 1);
return sec->data + offset;
}
@@ -256,7 +328,7 @@ ST_FUNC int put_elf_str(Section *s, const char *sym)
len = strlen(sym) + 1;
offset = s->data_offset;
ptr = section_ptr_add(s, len);
- memcpy(ptr, sym, len);
+ memmove(ptr, sym, len);
return offset;
}
@@ -286,6 +358,9 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets)
strtab = s->link->data;
nb_syms = s->data_offset / sizeof(ElfW(Sym));
+ if (!nb_buckets)
+ nb_buckets = ((int*)s->hash->data)[0];
+
s->hash->data_offset = 0;
ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
ptr[0] = nb_buckets;
@@ -319,7 +394,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
Section *hs;
sym = section_ptr_add(s, sizeof(ElfW(Sym)));
- if (name)
+ if (name && name[0])
name_offset = put_elf_str(s->link, name);
else
name_offset = 0;
@@ -336,11 +411,11 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
int *ptr, *base;
ptr = section_ptr_add(hs, sizeof(int));
base = (int *)hs->data;
- /* only add global or weak symbols */
+ /* only add global or weak symbols. */
if (ELFW(ST_BIND)(info) != STB_LOCAL) {
/* add another hashing entry */
nbuckets = base[0];
- h = elf_hash((unsigned char *) name) % nbuckets;
+ h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets;
*ptr = base[2 + h];
base[2 + h] = sym_index;
base[1]++;
@@ -357,8 +432,6 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
return sym_index;
}
-/* find global ELF symbol 'name' and return its index. Return 0 if not
- found. */
ST_FUNC int find_elf_sym(Section *s, const char *name)
{
ElfW(Sym) *sym;
@@ -425,17 +498,15 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
sym_type = ELFW(ST_TYPE)(info);
sym_vis = ELFW(ST_VISIBILITY)(other);
- sym_index = find_elf_sym(s, name);
- esym = &((ElfW(Sym) *)s->data)[sym_index];
- if (sym_index && esym->st_value == value && esym->st_size == size
- && esym->st_info == info && esym->st_other == other
- && esym->st_shndx == shndx)
- return sym_index;
-
if (sym_bind != STB_LOCAL) {
/* we search global or weak symbols */
+ sym_index = find_elf_sym(s, name);
if (!sym_index)
goto do_def;
+ esym = &((ElfW(Sym) *)s->data)[sym_index];
+ if (esym->st_value == value && esym->st_size == size && esym->st_info == info
+ && esym->st_other == other && esym->st_shndx == shndx)
+ return sym_index;
if (esym->st_shndx != SHN_UNDEF) {
esym_bind = ELFW(ST_BIND)(esym->st_info);
/* propagate the most constraining visibility */
@@ -471,8 +542,12 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
goto do_patch;
} else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) {
/* data symbol keeps precedence over common/bss */
- } else if (s == tcc_state->dynsymtab_section) {
+ } else if (s->sh_flags & SHF_DYNSYM) {
/* we accept that two DLL define the same symbol */
+ } else if (esym->st_other & ST_ASM_SET) {
+ /* If the existing symbol came from an asm .set
+ we can override. */
+ goto do_patch;
} else {
#if 0
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
@@ -666,7 +741,8 @@ static void sort_syms(TCCState *s1, Section *s)
p++;
}
/* save the number of local symbols in section header */
- s->sh_info = q - new_syms;
+ if( s->sh_size ) /* this 'if' makes IDA happy */
+ s->sh_info = q - new_syms;
/* then second pass for non local symbols */
p = (ElfW(Sym) *)s->data;
@@ -698,26 +774,6 @@ static void sort_syms(TCCState *s1, Section *s)
tcc_free(old_to_new_syms);
}
-/* relocate common symbols in the .bss section */
-ST_FUNC void relocate_common_syms(void)
-{
- ElfW(Sym) *sym;
- unsigned long offset, align;
-
- for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
- if (sym->st_shndx == SHN_COMMON) {
- /* align symbol */
- align = sym->st_value;
- offset = bss_section->data_offset;
- offset = (offset + align - 1) & -align;
- sym->st_value = offset;
- sym->st_shndx = bss_section->sh_num;
- offset += sym->st_size;
- bss_section->data_offset = offset;
- }
- }
-}
-
/* relocate symbol table, resolve undefined symbols if do_resolve is
true and output error if undefined symbol. */
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
@@ -729,7 +785,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
for_each_elem(symtab, 1, sym, ElfW(Sym)) {
sh_num = sym->st_shndx;
if (sh_num == SHN_UNDEF) {
- name = (char *) strtab_section->data + sym->st_name;
+ name = (char *) s1->symtab->link->data + sym->st_name;
/* Use ld.so to resolve symbol for us (for tcc -run) */
if (do_resolve) {
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
@@ -787,7 +843,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
tgt += rel->r_addend;
#endif
addr = s->sh_addr + rel->r_offset;
- relocate(s1, rel, type, ptr, addr, tgt);
+ relocate(s1, rel, type, ptr, addr, tgt);
}
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC)
@@ -819,6 +875,12 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
switch(type) {
#if defined(TCC_TARGET_I386)
case R_386_32:
+ if (!get_sym_attr(s1, sym_index, 0)->dyn_index
+ && ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) {
+ /* don't fixup unresolved (weak) symbols */
+ rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE);
+ break;
+ }
#elif defined(TCC_TARGET_X86_64)
case R_X86_64_32:
case R_X86_64_32S:
@@ -862,7 +924,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,
- int reloc_type, unsigned long size,
+ unsigned long size,
int info, int sym_index)
{
int need_plt_entry;
@@ -898,11 +960,30 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
name = (char *) symtab_section->link->data + sym->st_name;
if (s1->dynsym) {
- if (0 == attr->dyn_index)
- attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size,
- info, 0, sym->st_shndx, name);
- put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
- attr->dyn_index);
+ if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
+ /* Hack alarm. We don't want to emit dynamic symbols
+ and symbol based relocs for STB_LOCAL symbols, but rather
+ want to resolve them directly. At this point the symbol
+ values aren't final yet, so we must defer this. We will later
+ have to create a RELATIVE reloc anyway, so we misuse the
+ relocation slot to smuggle the symbol reference until
+ fill_local_got_entries. Not that the sym_index is
+ relative to symtab_section, not s1->dynsym! Nevertheless
+ we use s1->dyn_sym so that if this is the first call
+ that got->reloc is correctly created. Also note that
+ RELATIVE relocs are not normally created for the .got,
+ so the types serves as a marker for later (and is retained
+ also for the final output, which is okay because then the
+ got is just normal data). */
+ put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE,
+ 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);
+ put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
+ attr->dyn_index);
+ }
} else {
put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type,
sym_index);
@@ -956,47 +1037,57 @@ ST_FUNC void build_got_entries(TCCState *s1)
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (gotplt_entry == NO_GOTPLT_ENTRY) {
-#ifdef TCC_TARGET_I386
- if (type == R_386_32 && sym->st_shndx == SHN_UNDEF) {
- /* the i386 generator uses the plt address for function
- pointers into .so. This may break pointer equality
- but helps to keep it simple */
- char *name = (char *)symtab_section->link->data + sym->st_name;
- int index = find_elf_sym(s1->dynsymtab_section, name);
- ElfW(Sym) *esym = (ElfW(Sym) *)s1->dynsymtab_section->data + index;
- if (index
- && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC
- || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE
- && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
- goto jmp_slot;
- }
-#endif
continue;
}
- /* Automatically create PLT/GOT [entry] it is an undefined reference
- (resolved at runtime), or the symbol is absolute, probably created
- by tcc_add_symbol, and thus on 64-bit targets might be too far
- from application code */
+ /* Automatically create PLT/GOT [entry] if it is an undefined
+ reference (resolved at runtime), or the symbol is absolute,
+ probably created by tcc_add_symbol, and thus on 64-bit
+ targets might be too far from application code. */
if (gotplt_entry == AUTO_GOTPLT_ENTRY) {
if (sym->st_shndx == SHN_UNDEF) {
+ ElfW(Sym) *esym;
+ int dynindex;
if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT)
continue;
- } else if (!(sym->st_shndx == SHN_ABS && PTR_SIZE == 8))
+ /* Relocations for UNDEF symbols would normally need
+ to be transferred into the executable or shared object.
+ If that were done AUTO_GOTPLT_ENTRY wouldn't exist.
+ But TCC doesn't do that (at least for exes), so we
+ need to resolve all such relocs locally. And that
+ means PLT slots for functions in DLLs and COPY relocs for
+ data symbols. COPY relocs were generated in
+ bind_exe_dynsyms (and the symbol adjusted to be defined),
+ and for functions we were generated a dynamic symbol
+ of function type. */
+ if (s1->dynsym) {
+ /* dynsym isn't set for -run :-/ */
+ dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index;
+ esym = (ElfW(Sym) *)s1->dynsym->data + dynindex;
+ if (dynindex
+ && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC
+ || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE
+ && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
+ goto jmp_slot;
+ }
+ } else if (!(sym->st_shndx == SHN_ABS
+#ifndef TCC_TARGET_ARM
+ && PTR_SIZE == 8
+#endif
+ ))
continue;
}
#ifdef TCC_TARGET_X86_64
- if (type == R_X86_64_PLT32 &&
- ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) {
+ if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) &&
+ (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
+ ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)) {
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
continue;
}
#endif
if (code_reloc(type)) {
-#ifdef TCC_TARGET_I386
jmp_slot:
-#endif
reloc_type = R_JMP_SLOT;
} else
reloc_type = R_GLOB_DAT;
@@ -1007,7 +1098,7 @@ ST_FUNC void build_got_entries(TCCState *s1)
if (gotplt_entry == BUILD_GOT_ONLY)
continue;
- attr = put_got_entry(s1, reloc_type, type, sym->st_size, sym->st_info,
+ attr = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
sym_index);
if (reloc_type == R_JMP_SLOT)
@@ -1058,7 +1149,7 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
static int tcc_add_support(TCCState *s1, const char *filename)
{
char buf[1024];
- snprintf(buf, sizeof(buf), "%s/"TCC_ARCH_DIR"%s", s1->tcc_lib_path, filename);
+ snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename);
return tcc_add_file(s1, buf);
}
@@ -1101,12 +1192,15 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
/* add libc */
if (!s1->nostdlib) {
tcc_add_library_err(s1, "c");
-#ifdef CONFIG_USE_LIBGCC
+#ifdef TCC_LIBGCC
if (!s1->static_link) {
- tcc_add_file(s1, TCC_LIBGCC);
+ if (TCC_LIBGCC[0] == '/')
+ tcc_add_file(s1, TCC_LIBGCC);
+ else
+ tcc_add_dll(s1, TCC_LIBGCC, 0);
}
#endif
- tcc_add_support(s1, "libtcc1.a");
+ tcc_add_support(s1, TCC_LIBTCC1);
/* add crt end if not memory output */
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_crt(s1, "crtn.o");
@@ -1116,7 +1210,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
/* add various standard linker symbols (must be done after the
sections are filled (for example after allocating common
symbols)) */
-ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
+static void tcc_add_linker_symbols(TCCState *s1)
{
char buf[1024];
int i;
@@ -1175,6 +1269,24 @@ ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
}
}
+ST_FUNC void resolve_common_syms(TCCState *s1)
+{
+ ElfW(Sym) *sym;
+
+ /* Allocate common symbols in BSS. */
+ for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
+ if (sym->st_shndx == SHN_COMMON) {
+ /* symbol alignment is in st_value for SHN_COMMONs */
+ sym->st_value = section_add(bss_section, sym->st_size,
+ sym->st_value);
+ sym->st_shndx = bss_section->sh_num;
+ }
+ }
+
+ /* Now assign linker provided symbols their value. */
+ tcc_add_linker_symbols(s1);
+}
+
static void tcc_output_binary(TCCState *s1, FILE *f,
const int *sec_order)
{
@@ -1197,14 +1309,6 @@ static void tcc_output_binary(TCCState *s1, FILE *f,
}
}
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-#define HAVE_PHDR 1
-#define EXTRA_RELITEMS 14
-#else
-#define HAVE_PHDR 1
-#define EXTRA_RELITEMS 9
-#endif
-
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
{
int sym_index = ELFW(R_SYM) (rel->r_info);
@@ -1250,6 +1354,30 @@ ST_FUNC void fill_got(TCCState *s1)
}
}
+/* See put_got_entry for a description. This is the second stage
+ where GOT references to local defined symbols are rewritten. */
+static void fill_local_got_entries(TCCState *s1)
+{
+ ElfW_Rel *rel;
+ 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);
+ ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
+ struct sym_attr *attr = get_sym_attr(s1, sym_index, 0);
+ unsigned offset = attr->got_offset;
+ if (offset != rel->r_offset - s1->got->sh_addr)
+ tcc_error_noabort("huh");
+ rel->r_info = ELFW(R_INFO)(0, R_RELATIVE);
+#if SHT_RELX == SHT_RELA
+ rel->r_addend = sym->st_value;
+#else
+ /* All our REL architectures also happen to be 32bit LE. */
+ write32le(s1->got->data + offset, sym->st_value);
+#endif
+ }
+ }
+}
+
/* Bind symbols of executable: resolve undefined symbols from exported symbols
in shared libraries and export non local defined symbols to shared libraries
if -rdynamic switch was given on command line */
@@ -1278,9 +1406,12 @@ static void bind_exe_dynsyms(TCCState *s1)
* of the function wanted by the caller of dlsym instead of
* the address of the function that would return that
* address */
- put_elf_sym(s1->dynsym, 0, esym->st_size,
- ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
- name);
+ int dynindex
+ = put_elf_sym(s1->dynsym, 0, esym->st_size,
+ ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
+ name);
+ int index = sym - (ElfW(Sym) *) symtab_section->data;
+ get_sym_attr(s1, index, 1)->dyn_index = dynindex;
} else if (type == STT_OBJECT) {
unsigned long offset;
ElfW(Sym) *dynsym;
@@ -1345,13 +1476,12 @@ static void bind_libs_dynsyms(TCCState *s1)
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) {
name = (char *) s1->dynsymtab_section->link->data + esym->st_name;
sym_index = find_elf_sym(symtab_section, name);
- /* XXX: avoid adding a symbol if already present because of
- -rdynamic ? */
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if (sym_index && sym->st_shndx != SHN_UNDEF)
- set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
- 0, sym->st_shndx, name);
- else if (esym->st_shndx == SHN_UNDEF) {
+ if (sym_index && sym->st_shndx != SHN_UNDEF
+ && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
+ set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
+ sym->st_info, 0, sym->st_shndx, name);
+ } else if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("undefined dynamic symbol '%s'", name);
@@ -1383,40 +1513,43 @@ static void export_global_syms(TCCState *s1)
/* Allocate strings for section names and decide if an unallocated section
should be output.
NOTE: the strsec section comes last, so its size is also correct ! */
-static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
+static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
{
int i;
Section *s;
+ int textrel = 0;
/* Allocate strings for section names */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
- s->sh_name = put_elf_str(strsec, s->name);
/* when generating a DLL, we include relocations but we may
patch them */
if (file_type == TCC_OUTPUT_DLL &&
s->sh_type == SHT_RELX &&
- !(s->sh_flags & SHF_ALLOC)) {
- /* gr: avoid bogus relocs for empty (debug) sections */
- if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)
- prepare_dynamic_rel(s1, s);
- else if (s1->do_debug)
- s->sh_size = s->data_offset;
+ !(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 ||
file_type == TCC_OUTPUT_OBJ ||
(s->sh_flags & SHF_ALLOC) ||
- i == (s1->nb_sections - 1)) {
+ i == (s1->nb_sections - 1)) {
/* we output all sections if debug or object file */
s->sh_size = s->data_offset;
}
+ if (s->sh_size || (s->sh_flags & SHF_ALLOC))
+ s->sh_name = put_elf_str(strsec, s->name);
}
+ strsec->sh_size = strsec->data_offset;
+ return textrel;
}
/* Info to be copied in dynamic section */
struct dyn_inf {
Section *dynamic;
Section *dynstr;
- unsigned long dyn_rel_off;
+ unsigned long data_offset;
addr_t rel_addr;
addr_t rel_size;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -1472,7 +1605,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
the program header table itself if needed. These are done later as
they require section layout to be done first. */
if (interp)
- ph += 1 + HAVE_PHDR;
+ ph += 2;
/* dynamic relocation table information, for .dynamic section */
dyninf->rel_addr = dyninf->rel_size = 0;
@@ -1614,19 +1747,14 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
if (interp) {
ph = &phdr[0];
- if (HAVE_PHDR)
- {
- int len = phnum * sizeof(ElfW(Phdr));
-
- ph->p_type = PT_PHDR;
- ph->p_offset = sizeof(ElfW(Ehdr));
- ph->p_vaddr = interp->sh_addr - len;
- ph->p_paddr = ph->p_vaddr;
- ph->p_filesz = ph->p_memsz = len;
- ph->p_flags = PF_R | PF_X;
- ph->p_align = 4; /* interp->sh_addralign; */
- ph++;
- }
+ ph->p_type = PT_PHDR;
+ ph->p_offset = sizeof(ElfW(Ehdr));
+ ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr));
+ ph->p_vaddr = interp->sh_addr - ph->p_filesz;
+ ph->p_paddr = ph->p_vaddr;
+ ph->p_flags = PF_R | PF_X;
+ ph->p_align = 4; /* interp->sh_addralign; */
+ ph++;
ph->p_type = PT_INTERP;
ph->p_offset = interp->sh_offset;
@@ -1657,18 +1785,15 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
sections */
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
{
- Section *dynamic;
-
- dynamic = dyninf->dynamic;
+ Section *dynamic = dyninf->dynamic;
/* put dynamic section entries */
- dynamic->data_offset = dyninf->dyn_rel_off;
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr);
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset);
put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
put_dt(dynamic, DT_RELA, dyninf->rel_addr);
put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
@@ -1707,7 +1832,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];
-#ifdef TCC_TARGET_I386
+#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 */
@@ -1762,7 +1887,8 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
ehdr.e_ident[4] = ELFCLASSW;
ehdr.e_ident[5] = ELFDATA2LSB;
ehdr.e_ident[6] = EV_CURRENT;
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
+ /* FIXME: should set only for freebsd _target_, but we exclude only PE target */
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
#endif
#ifdef TCC_TARGET_ARM
@@ -1883,33 +2009,75 @@ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum,
return 0;
}
+/* 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)
+{
+ int i, nnew, l, *backmap;
+ Section **snew, *s;
+ ElfW(Sym) *sym;
+
+ snew = tcc_malloc(s1->nb_sections * sizeof(snew[0]));
+ backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0]));
+ for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) {
+ s = s1->sections[sec_order[i]];
+ if (!i || s->sh_name) {
+ backmap[sec_order[i]] = nnew;
+ snew[nnew] = s;
+ ++nnew;
+ } else {
+ backmap[sec_order[i]] = 0;
+ snew[--l] = s;
+ }
+ }
+ for (i = 0; i < nnew; i++) {
+ s = snew[i];
+ if (s) {
+ s->sh_num = i;
+ if (s->sh_type == SHT_RELX)
+ s->sh_info = backmap[s->sh_info];
+ }
+ }
+
+ for_each_elem(symtab_section, 1, sym, ElfW(Sym))
+ if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
+ sym->st_shndx = backmap[sym->st_shndx];
+ if( !s1->static_link ) {
+ for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
+ if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
+ sym->st_shndx = backmap[sym->st_shndx];
+ }
+ for (i = 0; i < s1->nb_sections; i++)
+ sec_order[i] = i;
+ tcc_free(s1->sections);
+ s1->sections = snew;
+ s1->nb_sections = nnew;
+ tcc_free(backmap);
+}
+
/* 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;
- struct dyn_inf dyninf;
+ struct dyn_inf dyninf = {0};
ElfW(Phdr) *phdr;
ElfW(Sym) *sym;
Section *strsec, *interp, *dynamic, *dynstr;
+ int textrel;
file_type = s1->output_type;
s1->nb_errors = 0;
-
- /* if linking, also link in runtime libraries (libc, libgcc, etc.) */
- if (file_type != TCC_OUTPUT_OBJ) {
- tcc_add_runtime(s1);
- }
-
+ ret = -1;
phdr = NULL;
sec_order = NULL;
interp = dynamic = dynstr = NULL; /* avoid warning */
- dyninf.dyn_rel_off = 0; /* avoid warning */
+ textrel = 0;
if (file_type != TCC_OUTPUT_OBJ) {
- relocate_common_syms();
-
- tcc_add_linker_symbols(s1);
+ /* if linking, also link in runtime libraries (libc, libgcc, etc.) */
+ tcc_add_runtime(s1);
+ resolve_common_syms(s1);
if (!s1->static_link) {
if (file_type == TCC_OUTPUT_EXE) {
@@ -1941,51 +2109,69 @@ static int elf_output_file(TCCState *s1, const char *filename)
if (file_type == TCC_OUTPUT_EXE) {
bind_exe_dynsyms(s1);
-
- if (s1->nb_errors) {
- ret = -1;
+ if (s1->nb_errors)
goto the_end;
- }
-
bind_libs_dynsyms(s1);
- } else /* shared library case: simply export all global symbols */
+ } else {
+ /* shared library case: simply export all global symbols */
export_global_syms(s1);
+ }
+ }
+ build_got_entries(s1);
+ }
- build_got_entries(s1);
+ /* we add a section for symbols */
+ strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
+ put_elf_str(strsec, "");
- /* add a list of needed dlls */
- for(i = 0; i < s1->nb_loaded_dlls; i++) {
- DLLReference *dllref = s1->loaded_dlls[i];
- if (dllref->level == 0)
- put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
- }
+ /* Allocate strings for section names */
+ textrel = alloc_sec_names(s1, file_type, strsec);
- if (s1->rpath)
- put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath));
+ if (dynamic) {
+ /* add a list of needed dlls */
+ for(i = 0; i < s1->nb_loaded_dlls; i++) {
+ DLLReference *dllref = s1->loaded_dlls[i];
+ if (dllref->level == 0)
+ put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
+ }
+ if (s1->rpath)
+ put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
+ put_elf_str(dynstr, s1->rpath));
+
+ if (file_type == TCC_OUTPUT_DLL) {
+ if (s1->soname)
+ 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 (file_type == TCC_OUTPUT_DLL) {
- if (s1->soname)
- put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
+ if (textrel)
put_dt(dynamic, DT_TEXTREL, 0);
- }
+ }
- if (s1->symbolic)
- put_dt(dynamic, DT_SYMBOLIC, 0);
+ if (s1->symbolic)
+ put_dt(dynamic, DT_SYMBOLIC, 0);
- /* add necessary space for other entries */
- dyninf.dyn_rel_off = dynamic->data_offset;
- dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS;
- } else {
- /* still need to build got entries in case of static link */
- build_got_entries(s1);
- }
+ dyninf.dynamic = dynamic;
+ dyninf.dynstr = dynstr;
+ /* remember offset and reserve space for 2nd call below */
+ dyninf.data_offset = dynamic->data_offset;
+ fill_dynamic(s1, &dyninf);
+ dynamic->sh_size = dynamic->data_offset;
+ dynstr->sh_size = dynstr->data_offset;
}
- /* we add a section for symbols */
- strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
- put_elf_str(strsec, "");
+ /* compute number of program headers */
+ if (file_type == TCC_OUTPUT_OBJ)
+ phnum = 0;
+ else if (file_type == TCC_OUTPUT_DLL)
+ phnum = 3;
+ else if (s1->static_link)
+ phnum = 2;
+ else
+ phnum = 5;
+
+ /* allocate program segment headers */
+ phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
/* compute number of sections */
shnum = s1->nb_sections;
@@ -1994,41 +2180,16 @@ static int elf_output_file(TCCState *s1, const char *filename)
sec_order = tcc_malloc(sizeof(int) * shnum);
sec_order[0] = 0;
- /* compute number of program headers */
- switch(file_type) {
- default:
- case TCC_OUTPUT_OBJ:
- phnum = 0;
- break;
- case TCC_OUTPUT_EXE:
- if (!s1->static_link)
- phnum = 4 + HAVE_PHDR;
- else
- phnum = 2;
- break;
- case TCC_OUTPUT_DLL:
- phnum = 3;
- break;
- }
-
- /* Allocate strings for section names */
- alloc_sec_names(s1, file_type, strsec);
-
- /* allocate program segment headers */
- phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
-
/* compute section to program header mapping */
file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf,
sec_order);
/* Fill remaining program header and finalize relocation related to dynamic
linking. */
- if (phnum > 0) {
+ if (file_type != TCC_OUTPUT_OBJ) {
fill_unloadable_phdr(phdr, phnum, interp, dynamic);
if (dynamic) {
- dyninf.dynamic = dynamic;
- dyninf.dynstr = dynstr;
-
+ dynamic->data_offset = dyninf.data_offset;
fill_dynamic(s1, &dyninf);
/* put in GOT the dynamic section address and relocate PLT */
@@ -2045,22 +2206,24 @@ static int elf_output_file(TCCState *s1, const char *filename)
}
}
}
- }
- /* if building executable or DLL, then relocate each section
- except the GOT which is already relocated */
- if (file_type != TCC_OUTPUT_OBJ) {
+ /* if building executable or DLL, then relocate each section
+ except the GOT which is already relocated */
ret = final_sections_reloc(s1);
if (ret)
goto the_end;
- }
+ tidy_section_headers(s1, sec_order);
- /* Perform relocation to GOT or PLT entries */
- if (file_type == TCC_OUTPUT_EXE && s1->static_link)
- fill_got(s1);
+ /* Perform relocation to GOT or PLT entries */
+ if (file_type == TCC_OUTPUT_EXE && s1->static_link)
+ fill_got(s1);
+ else if (s1->got)
+ fill_local_got_entries(s1);
+ }
/* Create the ELF file with name 'filename' */
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
+ s1->nb_sections = shnum;
the_end:
tcc_free(sec_order);
tcc_free(phdr);
@@ -2122,7 +2285,7 @@ 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;
+ int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed;
unsigned char *strsec, *strtab;
int *old_to_new_syms;
char *sh_name, *name;
@@ -2160,6 +2323,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
symtab = NULL;
strtab = NULL;
nb_syms = 0;
+ seencompressed = 0;
for(i = 1; i < ehdr.e_shnum; i++) {
sh = &shdr[i];
if (sh->sh_type == SHT_SYMTAB) {
@@ -2177,6 +2341,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
sh = &shdr[sh->sh_link];
strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
}
+ if (sh->sh_flags & SHF_COMPRESSED)
+ seencompressed = 1;
}
/* now examine each section and try to merge its content with the
@@ -2200,6 +2366,12 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
strcmp(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))))
+ continue;
if (sh->sh_addralign < 1)
sh->sh_addralign = 1;
/* find corresponding section, if any */
@@ -2587,7 +2759,7 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
dllref->level = level;
strcpy(dllref->name, soname);
- dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+ dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
/* add dynamic symbols in dynsym_section */
for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
@@ -2750,12 +2922,13 @@ static int ld_next(TCCState *s1, char *name, int name_size)
static int ld_add_file(TCCState *s1, const char filename[])
{
- int ret;
-
- ret = tcc_add_file_internal(s1, filename, AFF_TYPE_BIN);
- if (ret)
- ret = tcc_add_dll(s1, filename, 0);
- return ret;
+ if (filename[0] == '/') {
+ if (CONFIG_SYSROOT[0] == '\0'
+ && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0)
+ return 0;
+ filename = tcc_basename(filename);
+ }
+ return tcc_add_dll(s1, filename, 0);
}
static inline int new_undef_syms(void)
@@ -2817,9 +2990,9 @@ static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
goto lib_parse_error;
if (group) {
/* Add the filename *and* the libname to avoid future conversions */
- dynarray_add((void ***) &libs, &nblibs, tcc_strdup(filename));
+ dynarray_add(&libs, &nblibs, tcc_strdup(filename));
if (libname[0] != '\0')
- dynarray_add((void ***) &libs, &nblibs, tcc_strdup(libname));
+ dynarray_add(&libs, &nblibs, tcc_strdup(libname));
}
}
}
diff --git a/tccgen.c b/tccgen.c
index f6c7700..e0b744e 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -50,15 +50,18 @@ ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack p
ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
ST_DATA int const_wanted; /* true if constant wanted */
-ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
+ST_DATA int nocode_wanted; /* no code generation wanted */
+#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */
+#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */
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 */
ST_DATA const char *funcname;
+ST_DATA int g_debug;
-ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
+ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type;
ST_DATA struct switch_t {
struct case_t {
@@ -69,30 +72,32 @@ ST_DATA struct switch_t {
} *cur_switch; /* current switch */
/* ------------------------------------------------------------------------- */
+
static void gen_cast(CType *type);
+static void gen_cast_s(int t);
static inline CType *pointed_type(CType *type);
static int is_compatible_types(CType *type1, CType *type2);
static int parse_btype(CType *type, AttributeDef *ad);
-static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
+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_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
-static int decl0(int l, int is_for_loop_init);
+static void decl(int l);
+static int decl0(int l, int is_for_loop_init, Sym *);
static void expr_eq(void);
-static void expr_lor_const(void);
-static void unary_type(CType *type);
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_parameter_types(CType *type1, CType *type2);
-static void expr_type(CType *type);
+static int is_compatible_unqualified_types(CType *type1, CType *type2);
static inline int64_t expr_const64(void);
-ST_FUNC void vpush64(int ty, unsigned long long v);
-ST_FUNC void vpush(CType *type);
-ST_FUNC int gvtst(int inv, int t);
-ST_FUNC int is_btype_size(int bt);
+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 skip_or_save_block(TokenString **str);
+static void gv_dup(void);
ST_INLN int is_float(int t)
{
@@ -111,6 +116,12 @@ ST_FUNC int ieee_finite(double d)
return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
}
+/* compiling intel long double natively */
+#if (defined __i386__ || defined __x86_64__) \
+ && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
+# define TCC_IS_NATIVE_387
+#endif
+
ST_FUNC void test_lvalue(void)
{
if (!(vtop->r & VT_LVAL))
@@ -139,26 +150,9 @@ void pv (const char *lbl, int a, int b)
#endif
/* ------------------------------------------------------------------------- */
-ST_FUNC void tccgen_start(TCCState *s1)
+/* start of translation unit info */
+ST_FUNC void tcc_debug_start(TCCState *s1)
{
- cur_text_section = NULL;
- funcname = "";
- anon_sym = SYM_FIRST_ANOM;
- section_sym = 0;
- nocode_wanted = 1;
-
- /* define some often used types */
- int_type.t = VT_INT;
- char_pointer_type.t = VT_BYTE;
- mk_pointer(&char_pointer_type);
-#if PTR_SIZE == 4
- size_type.t = VT_INT;
-#else
- size_type.t = VT_LLONG;
-#endif
- func_old_type.t = VT_FUNC;
- func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
-
if (s1->do_debug) {
char buf[512];
@@ -175,70 +169,184 @@ ST_FUNC void tccgen_start(TCCState *s1)
text_section->data_offset, text_section, section_sym);
put_stabs_r(file->filename, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
+ last_ind = 0;
+ last_line_num = 0;
}
+
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
symbols can be safely used */
put_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
SHN_ABS, file->filename);
+}
+
+/* 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,
+ text_section->data_offset, text_section, section_sym);
+
+}
+
+/* generate line number info */
+ST_FUNC void tcc_debug_line(TCCState *s1)
+{
+ if (!s1->do_debug)
+ 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;
+ }
+}
+
+/* put function symbol */
+ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym)
+{
+ char buf[512];
+
+ if (!s1->do_debug)
+ return;
+
+ /* 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;
+}
+
+/* put function size */
+ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
+{
+ if (!s1->do_debug)
+ return;
+ put_stabn(N_FUN, 0, 0, size);
+}
+
+/* ------------------------------------------------------------------------- */
+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;
+
+ /* define some often used types */
+ int_type.t = VT_INT;
+ char_pointer_type.t = VT_BYTE;
+ 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;
+
+ tcc_debug_start(s1);
#ifdef TCC_TARGET_ARM
arm_init(s1);
#endif
-}
-ST_FUNC void tccgen_end(TCCState *s1)
-{
+#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);
gen_inline_functions(s1);
check_vstack();
/* end of translation unit info */
- if (s1->do_debug) {
- put_stabs_r(NULL, N_SO, 0, 0,
- text_section->data_offset, text_section, section_sym);
+ tcc_debug_end(s1);
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+ST_FUNC ElfSym *elfsym(Sym *s)
+{
+ if (!s || !s->c)
+ return NULL;
+ return &((ElfSym *)symtab_section->data)[s->c];
+}
+
+/* apply storage attributes to Elf symbol */
+ST_FUNC void update_storage(Sym *sym)
+{
+ ElfSym *esym;
+ int sym_bind, old_sym_bind;
+
+ esym = elfsym(sym);
+ if (!esym)
+ return;
+
+ if (sym->a.visibility)
+ esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
+ | sym->a.visibility;
+
+ if (sym->type.t & VT_STATIC)
+ sym_bind = STB_LOCAL;
+ else if (sym->a.weak)
+ sym_bind = STB_WEAK;
+ else
+ sym_bind = STB_GLOBAL;
+ old_sym_bind = ELFW(ST_BIND)(esym->st_info);
+ if (sym_bind != old_sym_bind) {
+ esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info));
}
+
+#ifdef TCC_TARGET_PE
+ if (sym->a.dllimport)
+ esym->st_other |= ST_PE_IMPORT;
+ if (sym->a.dllexport)
+ esym->st_other |= ST_PE_EXPORT;
+#endif
+
+#if 0
+ printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n",
+ get_tok_str(sym->v, NULL),
+ sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g',
+ sym->a.visibility,
+ sym->a.dllexport,
+ sym->a.dllimport
+ );
+#endif
}
/* ------------------------------------------------------------------------- */
/* update sym->c so that it points to an external symbol in section
'section' with value 'value' */
-ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
+ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
addr_t value, unsigned long size,
int can_add_underscore)
{
- int sym_type, sym_bind, sh_num, info, other;
- ElfW(Sym) *esym;
+ int sym_type, sym_bind, info, other, t;
+ ElfSym *esym;
const char *name;
char buf1[256];
-
#ifdef CONFIG_TCC_BCHECK
char buf[32];
#endif
- if (section == NULL)
- sh_num = SHN_UNDEF;
- else if (section == SECTION_ABS)
- sh_num = SHN_ABS;
- else
- sh_num = section->sh_num;
-
- if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
- sym_type = STT_FUNC;
- } else if ((sym->type.t & VT_BTYPE) == VT_VOID) {
- sym_type = STT_NOTYPE;
- } else {
- sym_type = STT_OBJECT;
- }
-
- if (sym->type.t & VT_STATIC)
- sym_bind = STB_LOCAL;
- else {
- if (sym->type.t & VT_WEAK)
- sym_bind = STB_WEAK;
- else
- sym_bind = STB_GLOBAL;
- }
-
if (!sym->c) {
name = get_tok_str(sym->v, NULL);
#ifdef CONFIG_TCC_BCHECK
@@ -268,53 +376,53 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
}
}
#endif
+ t = sym->type.t;
+ if ((t & VT_BTYPE) == VT_FUNC) {
+ sym_type = STT_FUNC;
+ } else if ((t & VT_BTYPE) == VT_VOID) {
+ sym_type = STT_NOTYPE;
+ } else {
+ sym_type = STT_OBJECT;
+ }
+ if (t & VT_STATIC)
+ sym_bind = STB_LOCAL;
+ else
+ sym_bind = STB_GLOBAL;
other = 0;
-
#ifdef TCC_TARGET_PE
- if (sym->type.t & VT_EXPORT)
- other |= ST_PE_EXPORT;
if (sym_type == STT_FUNC && sym->type.ref) {
Sym *ref = sym->type.ref;
- if (ref->a.func_export)
- other |= ST_PE_EXPORT;
- if (ref->a.func_call == FUNC_STDCALL && can_add_underscore) {
- sprintf(buf1, "_%s@%d", name, ref->a.func_args * PTR_SIZE);
+ if (ref->f.func_call == FUNC_STDCALL && can_add_underscore) {
+ sprintf(buf1, "_%s@%d", name, ref->f.func_args * PTR_SIZE);
name = buf1;
other |= ST_PE_STDCALL;
can_add_underscore = 0;
}
- } else {
- if (find_elf_sym(tcc_state->dynsymtab_section, name))
- other |= ST_PE_IMPORT;
- if (sym->type.t & VT_IMPORT)
- other |= ST_PE_IMPORT;
}
-#else
- if (! (sym->type.t & VT_STATIC))
- other = (sym->type.t & VT_VIS_MASK) >> VT_VIS_SHIFT;
#endif
if (tcc_state->leading_underscore && can_add_underscore) {
buf1[0] = '_';
pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
name = buf1;
}
- if (sym->asm_label) {
+ if (sym->asm_label)
name = get_tok_str(sym->asm_label, NULL);
- }
info = ELFW(ST_INFO)(sym_bind, sym_type);
- sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name);
+ sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name);
} else {
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+ esym = elfsym(sym);
esym->st_value = value;
esym->st_size = size;
esym->st_shndx = sh_num;
}
+ update_storage(sym);
}
ST_FUNC void put_extern_sym(Sym *sym, Section *section,
addr_t value, unsigned long size)
{
- put_extern_sym2(sym, section, value, size, 1);
+ int sh_num = section ? section->sh_num : SHN_UNDEF;
+ put_extern_sym2(sym, sh_num, value, size, 1);
}
/* add a new relocation entry to symbol 'sym' in section 's' */
@@ -322,19 +430,26 @@ ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type,
addr_t addend)
{
int c = 0;
+
+ if (nocode_wanted && s == cur_text_section)
+ return;
+
if (sym) {
if (0 == sym->c)
put_extern_sym(sym, NULL, 0, 0);
c = sym->c;
}
+
/* now we can add ELF relocation info */
put_elf_reloca(symtab_section, s, offset, type, c, addend);
}
+#if PTR_SIZE == 4
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type)
{
greloca(s, sym, offset, type, 0);
}
+#endif
/* ------------------------------------------------------------------------- */
/* symbol allocator */
@@ -383,20 +498,15 @@ ST_INLN void sym_free(Sym *sym)
}
/* push, without hashing */
-ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c)
+ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c)
{
Sym *s;
s = sym_malloc();
- s->scope = 0;
+ memset(s, 0, sizeof *s);
s->v = v;
s->type.t = t;
- s->type.ref = NULL;
-#ifdef _WIN64
- s->d = NULL;
-#endif
s->c = c;
- s->next = NULL;
/* add in stack */
s->prev = *ps;
*ps = s;
@@ -436,7 +546,7 @@ ST_INLN Sym *sym_find(int v)
}
/* push a given symbol on the symbol stack */
-ST_FUNC Sym *sym_push(int v, CType *type, int r, long c)
+ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
{
Sym *s, **ps;
TokenSym *ts;
@@ -459,8 +569,8 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, long c)
ps = &ts->sym_identifier;
s->prev_tok = *ps;
*ps = s;
- s->scope = local_scope;
- if (s->prev_tok && s->prev_tok->scope == s->scope)
+ s->sym_scope = local_scope;
+ if (s->prev_tok && s->prev_tok->sym_scope == s->sym_scope)
tcc_error("redeclaration of '%s'",
get_tok_str(v & ~SYM_STRUCT, NULL));
}
@@ -468,7 +578,7 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, long c)
}
/* push a global identifier */
-ST_FUNC Sym *global_identifier_push(int v, int t, long c)
+ST_FUNC Sym *global_identifier_push(int v, int t, int c)
{
Sym *s, **ps;
s = sym_push2(&global_stack, v, t, c);
@@ -477,9 +587,9 @@ ST_FUNC Sym *global_identifier_push(int v, int t, long c)
ps = &table_ident[v - TOK_IDENT]->sym_identifier;
/* modify the top most local identifier, so that
sym_identifier will point to 's' when popped */
- while (*ps != NULL)
+ while (*ps != NULL && (*ps)->sym_scope)
ps = &(*ps)->prev_tok;
- s->prev_tok = NULL;
+ s->prev_tok = *ps;
*ps = s;
}
return s;
@@ -515,51 +625,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
*ptop = b;
}
-static void weaken_symbol(Sym *sym)
-{
- sym->type.t |= VT_WEAK;
- if (sym->c > 0) {
- int esym_type;
- ElfW(Sym) *esym;
-
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
- esym_type = ELFW(ST_TYPE)(esym->st_info);
- esym->st_info = ELFW(ST_INFO)(STB_WEAK, esym_type);
- }
-}
-
-static void apply_visibility(Sym *sym, CType *type)
-{
- int vis = sym->type.t & VT_VIS_MASK;
- int vis2 = type->t & VT_VIS_MASK;
- if (vis == (STV_DEFAULT << VT_VIS_SHIFT))
- vis = vis2;
- else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT))
- ;
- else
- vis = (vis < vis2) ? vis : vis2;
- sym->type.t &= ~VT_VIS_MASK;
- sym->type.t |= vis;
-
- if (sym->c > 0) {
- ElfW(Sym) *esym;
-
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
- vis >>= VT_VIS_SHIFT;
- esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis;
- }
-}
-
/* ------------------------------------------------------------------------- */
-ST_FUNC void swap(int *p, int *q)
-{
- int t;
- t = *p;
- *p = *q;
- *q = t;
-}
-
static void vsetc(CType *type, int r, CValue *vc)
{
int v;
@@ -568,12 +635,23 @@ static void vsetc(CType *type, int r, CValue *vc)
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. */
- if (vtop >= vstack) {
+ because it would complicate the code generator.
+
+ Don't do this when nocode_wanted. vtop might come from
+ !nocode_wanted regions (see 88_codeopt.c) and transforming
+ it to a register without actually generating code is wrong
+ 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.
+
+ 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);
}
+
vtop++;
vtop->type = *type;
vtop->r = r;
@@ -582,11 +660,42 @@ static void vsetc(CType *type, int r, CValue *vc)
vtop->sym = NULL;
}
+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);
+ }
+ tmp = vtop[0];
+ vtop[0] = vtop[-1];
+ vtop[-1] = tmp;
+}
+
+/* pop stack value */
+ST_FUNC void vpop(void)
+{
+ int v;
+ v = vtop->r & VT_VALMASK;
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+ /* for x86, we need to pop the FP stack */
+ if (v == TREG_ST0) {
+ o(0xd8dd); /* fstp %st(0) */
+ } else
+#endif
+ if (v == VT_JMP || v == VT_JMPI) {
+ /* need to put correct jump if && or || without test */
+ gsym(vtop->c.i);
+ }
+ vtop--;
+}
+
/* push constant of type "type" with useless value */
ST_FUNC void vpush(CType *type)
{
- CValue cval;
- vsetc(type, VT_CONST, &cval);
+ vset(type, VT_CONST, 0);
}
/* push integer constant */
@@ -622,6 +731,71 @@ static inline void vpushll(long long v)
vpush64(VT_LLONG, v);
}
+ST_FUNC void vset(CType *type, int r, int v)
+{
+ CValue cval;
+
+ cval.i = v;
+ vsetc(type, r, &cval);
+}
+
+static void vseti(int r, int v)
+{
+ CType type;
+ type.t = VT_INT;
+ type.ref = NULL;
+ vset(&type, r, v);
+}
+
+ST_FUNC void vpushv(SValue *v)
+{
+ if (vtop >= vstack + (VSTACK_SIZE - 1))
+ tcc_error("memory full (vstack)");
+ vtop++;
+ *vtop = *v;
+}
+
+static void vdup(void)
+{
+ vpushv(vtop);
+}
+
+/* rotate n first stack elements to the bottom
+ I1 ... In -> I2 ... In I1 [top is right]
+*/
+ST_FUNC void vrotb(int n)
+{
+ int i;
+ SValue tmp;
+
+ tmp = vtop[-n + 1];
+ for(i=-n+1;i!=0;i++)
+ vtop[i] = vtop[i+1];
+ vtop[0] = tmp;
+}
+
+/* rotate the n elements before entry e towards the top
+ I1 ... In ... -> In I1 ... I(n-1) ... [top is right]
+ */
+ST_FUNC void vrote(SValue *e, int n)
+{
+ int i;
+ SValue tmp;
+
+ tmp = *e;
+ for(i = 0;i < n - 1; i++)
+ e[-i] = e[-i - 1];
+ e[-n + 1] = tmp;
+}
+
+/* rotate n first stack elements to the top
+ I1 ... In -> In I1 ... I(n-1) [top is right]
+ */
+ST_FUNC void vrott(int n)
+{
+ vrote(vtop, n);
+}
+
/* push a symbol value of TYPE */
static inline void vpushsym(CType *type, Sym *sym)
{
@@ -662,92 +836,118 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
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;
+ update_storage(s);
}
return s;
}
-/* define a new external reference to a symbol 'v' */
-static Sym *external_sym(int v, CType *type, int r)
+/* Merge some type attributes. */
+static void patch_type(Sym *sym, CType *type)
{
- Sym *s;
+ if (!(type->t & VT_EXTERN)) {
+ if (!(sym->type.t & VT_EXTERN))
+ tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
+ sym->type.t &= ~VT_EXTERN;
+ }
- s = sym_find(v);
- if (!s) {
- /* push forward reference */
- s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
- s->type.t |= VT_EXTERN;
- } 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;
- } else if (!is_compatible_types(&s->type, type)) {
- tcc_error("incompatible types for redefinition of '%s'",
- get_tok_str(v, NULL));
+ if (IS_ASM_SYM(sym)) {
+ /* stay static if both are static */
+ sym->type.t = type->t & (sym->type.t | ~VT_STATIC);
+ sym->type.ref = type->ref;
}
- /* Merge some storage attributes. */
- if (type->t & VT_WEAK)
- weaken_symbol(s);
- if (type->t & VT_VIS_MASK)
- apply_visibility(s, type);
+ if (!is_compatible_types(&sym->type, type)) {
+ tcc_error("incompatible types for redefinition of '%s'",
+ get_tok_str(sym->v, NULL));
- return s;
-}
+ } 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))
+ tcc_warning("static storage ignored for redefinition of '%s'",
+ get_tok_str(sym->v, NULL));
-/* 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));
-}
-
-ST_FUNC void vset(CType *type, int r, long v)
-{
- CValue cval;
+ if (0 == (type->t & VT_EXTERN)) {
+ /* 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.ref = type->ref;
+ }
- cval.i = v;
- vsetc(type, r, &cval);
+ } 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));
+ }
+ if ((type->t ^ sym->type.t) & VT_STATIC)
+ tcc_warning("storage mismatch for redefinition of '%s'",
+ get_tok_str(sym->v, NULL));
+ }
}
-static void vseti(int r, int v)
-{
- CType type;
- type.t = VT_INT;
- type.ref = 0;
- vset(&type, r, v);
-}
-ST_FUNC void vswap(void)
+/* Merge some storage attributes. */
+static void patch_storage(Sym *sym, AttributeDef *ad, CType *type)
{
- SValue tmp;
- /* 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. */
- if (vtop >= vstack) {
- int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP || (v & ~1) == VT_JMP)
- gv(RC_INT);
- }
- tmp = vtop[0];
- vtop[0] = vtop[-1];
- vtop[-1] = tmp;
+ if (type)
+ patch_type(sym, type);
-/* XXX: +2% overall speed possible with optimized memswap
- *
- * memswap(&vtop[0], &vtop[1], sizeof *vtop);
- */
+#ifdef TCC_TARGET_PE
+ 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;
+ if (ad->asm_label)
+ sym->asm_label = ad->asm_label;
+ update_storage(sym);
}
-ST_FUNC void vpushv(SValue *v)
+/* define a new external reference to a symbol 'v' */
+static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
{
- if (vtop >= vstack + (VSTACK_SIZE - 1))
- tcc_error("memory full (vstack)");
- vtop++;
- *vtop = *v;
+ Sym *s;
+ s = sym_find(v);
+ if (!s) {
+ /* push forward reference */
+ s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
+ s->type.t |= VT_EXTERN;
+ s->a = ad->a;
+ s->sym_scope = 0;
+ } 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);
+ }
+ return s;
}
-static void vdup(void)
+/* push a reference to global symbol v */
+ST_FUNC void vpush_global_sym(CType *type, int v)
{
- vpushv(vtop);
+ vpushsym(type, external_global_sym(v, type, 0));
}
/* save registers up to (vtop - n) stack entry */
@@ -774,6 +974,8 @@ ST_FUNC void save_reg_upstack(int r, int n)
if ((r &= VT_VALMASK) >= VT_CONST)
return;
+ if (nocode_wanted)
+ return;
/* modify all stack values */
saved = 0;
@@ -789,7 +991,7 @@ ST_FUNC void save_reg_upstack(int r, int n)
type = &p->type;
if ((p->r & VT_LVAL) ||
(!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
type = &char_pointer_type;
#else
type = &int_type;
@@ -806,7 +1008,7 @@ ST_FUNC void save_reg_upstack(int r, int n)
o(0xd8dd); /* fstp %st(0) */
}
#endif
-#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
/* special long long case */
if ((type->t & VT_BTYPE) == VT_LLONG) {
sv.c.i += 4;
@@ -865,6 +1067,8 @@ ST_FUNC int get_reg(int rc)
/* find a free register */
for(r=0;r<NB_REGS;r++) {
if (reg_classes[r] & rc) {
+ if (nocode_wanted)
+ return r;
for(p=vstack;p<=vtop;p++) {
if ((p->r & VT_VALMASK) == r ||
(p->r2 & VT_VALMASK) == r)
@@ -913,8 +1117,6 @@ static void move_reg(int r, int s, int t)
/* get address of vtop (vtop MUST BE an lvalue) */
ST_FUNC void gaddrof(void)
{
- if (vtop->r & VT_REF && !nocode_wanted)
- gv(RC_INT);
vtop->r &= ~VT_LVAL;
/* tricky: if saved lvalue, then we can go back to lvalue */
if ((vtop->r & VT_VALMASK) == VT_LLOCAL)
@@ -951,80 +1153,156 @@ static void gbound(void)
}
#endif
+static void incr_bf_adr(int o)
+{
+ vtop->type = char_pointer_type;
+ gaddrof();
+ vpushi(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);
+}
+
+/* single-byte load mode for packed or otherwise unaligned bitfields */
+static void load_packed_bf(CType *type, int bit_pos, int bit_size)
+{
+ int n, o, bits;
+ save_reg_upstack(vtop->r, 1);
+ vpush64(type->t & VT_BTYPE, 0); // B X
+ bits = 0, o = bit_pos >> 3, bit_pos &= 7;
+ do {
+ vswap(); // X B
+ incr_bf_adr(o);
+ vdup(); // X B B
+ n = 8 - bit_pos;
+ if (n > bit_size)
+ n = bit_size;
+ if (bit_pos)
+ vpushi(bit_pos), gen_op(TOK_SHR), bit_pos = 0; // X B Y
+ if (n < 8)
+ vpushi((1 << n) - 1), gen_op('&');
+ gen_cast(type);
+ if (bits)
+ vpushi(bits), gen_op(TOK_SHL);
+ vrotb(3); // B Y X
+ gen_op('|'); // B X
+ bits += n, bit_size -= n, o = 1;
+ } while (bit_size);
+ vswap(), vpop();
+ if (!(type->t & VT_UNSIGNED)) {
+ n = ((type->t & VT_BTYPE) == VT_LLONG ? 64 : 32) - bits;
+ vpushi(n), gen_op(TOK_SHL);
+ vpushi(n), gen_op(TOK_SAR);
+ }
+}
+
+/* single-byte store mode for packed or otherwise unaligned bitfields */
+static void store_packed_bf(int bit_pos, int bit_size)
+{
+ int bits, n, o, m, c;
+
+ c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+ vswap(); // X B
+ save_reg_upstack(vtop->r, 1);
+ bits = 0, o = bit_pos >> 3, bit_pos &= 7;
+ do {
+ incr_bf_adr(o); // X B
+ vswap(); //B X
+ c ? vdup() : gv_dup(); // B V X
+ vrott(3); // X B V
+ if (bits)
+ vpushi(bits), gen_op(TOK_SHR);
+ if (bit_pos)
+ vpushi(bit_pos), gen_op(TOK_SHL);
+ n = 8 - bit_pos;
+ if (n > bit_size)
+ n = bit_size;
+ if (n < 8) {
+ m = ((1 << n) - 1) << bit_pos;
+ vpushi(m), gen_op('&'); // X B V1
+ vpushv(vtop-1); // X B V1 B
+ vpushi(m & 0x80 ? ~m & 0x7f : ~m);
+ gen_op('&'); // X B V1 B1
+ gen_op('|'); // X B V2
+ }
+ vdup(), vtop[-1] = vtop[-2]; // X B B V2
+ vstore(), vpop(); // X B
+ bits += n, bit_size -= n, bit_pos = 0, o = 1;
+ } while (bit_size);
+ vpop(), vpop();
+}
+
+static int adjust_bf(SValue *sv, int bit_pos, int bit_size)
+{
+ int t;
+ if (0 == sv->type.ref)
+ 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);
+ }
+ return t;
+}
+
/* store vtop a register belonging to class 'rc'. lvalues are
converted to values. Cannot be used if cannot be converted to
register value (such as structures). */
ST_FUNC int gv(int rc)
{
- int r, bit_pos, bit_size, size, align, i;
- int rc2;
+ int r, bit_pos, bit_size, size, align, rc2;
/* NOTE: get_reg can modify vstack[] */
if (vtop->type.t & VT_BITFIELD) {
CType type;
- int bits = 32;
- bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
- bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+
+ bit_pos = BIT_POS(vtop->type.t);
+ bit_size = BIT_SIZE(vtop->type.t);
/* remove bit field info to avoid loops */
- vtop->type.t &= ~VT_BITFIELD & ((1 << VT_STRUCT_SHIFT) - 1);
- /* cast to int to propagate signedness in following ops */
- if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
- type.t = VT_LLONG;
- bits = 64;
- } else
- type.t = VT_INT;
- if((vtop->type.t & VT_UNSIGNED) ||
- (vtop->type.t & VT_BTYPE) == VT_BOOL)
+ vtop->type.t &= ~VT_STRUCT_MASK;
+
+ type.ref = NULL;
+ type.t = vtop->type.t & VT_UNSIGNED;
+ if ((vtop->type.t & VT_BTYPE) == VT_BOOL)
type.t |= VT_UNSIGNED;
- gen_cast(&type);
- /* generate shifts */
- vpushi(bits - (bit_pos + bit_size));
- gen_op(TOK_SHL);
- vpushi(bits - bit_size);
- /* NOTE: transformed to SHR if unsigned */
- gen_op(TOK_SAR);
+
+ r = adjust_bf(vtop, bit_pos, bit_size);
+
+ if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
+ type.t |= VT_LLONG;
+ else
+ type.t |= VT_INT;
+
+ if (r == VT_STRUCT) {
+ load_packed_bf(&type, bit_pos, bit_size);
+ } else {
+ int bits = (type.t & VT_BTYPE) == VT_LLONG ? 64 : 32;
+ /* cast to int to propagate signedness in following ops */
+ gen_cast(&type);
+ /* generate shifts */
+ vpushi(bits - (bit_pos + bit_size));
+ gen_op(TOK_SHL);
+ vpushi(bits - bit_size);
+ /* NOTE: transformed to SHR if unsigned */
+ gen_op(TOK_SAR);
+ }
r = gv(rc);
} else {
if (is_float(vtop->type.t) &&
(vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
- Sym *sym;
- int *ptr;
unsigned long offset;
-#if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP)
- CValue check;
-#endif
-
- /* XXX: unify with initializers handling ? */
/* CPUs usually cannot use float constants, so we store them
generically in data segment */
size = type_size(&vtop->type, &align);
- offset = (data_section->data_offset + align - 1) & -align;
- data_section->data_offset = offset;
- /* XXX: not portable yet */
-#if defined(__i386__) || defined(__x86_64__)
- /* Zero pad x87 tenbyte long doubles */
- if (size == LDOUBLE_SIZE) {
- vtop->c.tab[2] &= 0xffff;
-#if LDOUBLE_SIZE == 16
- vtop->c.tab[3] = 0;
-#endif
- }
-#endif
- ptr = section_ptr_add(data_section, size);
- size = size >> 2;
-#if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP)
- check.d = 1;
- if(check.tab[0])
- for(i=0;i<size;i++)
- ptr[i] = vtop->c.tab[size-1-i];
- else
-#endif
- for(i=0;i<size;i++)
- ptr[i] = vtop->c.tab[i];
- sym = get_sym_ref(&vtop->type, data_section, offset, size << 2);
- vtop->r |= VT_LVAL | VT_SYM;
- vtop->sym = sym;
- vtop->c.i = 0;
+ if (NODATA_WANTED)
+ size = 0, align = 1;
+ offset = section_add(data_section, size, align);
+ vpush_ref(&vtop->type, data_section, offset, size);
+ vswap();
+ init_putv(&vtop->type, data_section, offset);
+ vtop->r |= VT_LVAL;
}
#ifdef CONFIG_TCC_BCHECK
if (vtop->r & VT_MUSTBOUND)
@@ -1041,7 +1319,6 @@ ST_FUNC int gv(int rc)
rc2 = RC_QRET;
#endif
#endif
-
/* need to reload if:
- constant
- lvalue (need to dereference pointer)
@@ -1049,7 +1326,7 @@ ST_FUNC int gv(int rc)
if (r >= VT_CONST
|| (vtop->r & VT_LVAL)
|| !(reg_classes[r] & rc)
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#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
@@ -1058,7 +1335,7 @@ ST_FUNC int gv(int rc)
)
{
r = get_reg(rc);
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#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
@@ -1070,7 +1347,7 @@ ST_FUNC int gv(int rc)
original_type = vtop->type.t;
/* two register type load : expand to two words
temporarily */
-#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* load constant */
ll = vtop->c.i;
@@ -1125,13 +1402,7 @@ ST_FUNC int gv(int rc)
t = vtop->type.t;
t1 = t;
/* compute memory access type */
- if (vtop->r & VT_REF)
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
- t = VT_PTR;
-#else
- t = VT_INT;
-#endif
- else if (vtop->r & VT_LVAL_BYTE)
+ if (vtop->r & VT_LVAL_BYTE)
t = VT_BYTE;
else if (vtop->r & VT_LVAL_SHORT)
t = VT_SHORT;
@@ -1212,7 +1483,7 @@ static int reg_fret(int t)
return REG_FRET;
}
-#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
/* expand 64bit on stack in two ints */
static void lexpand(void)
{
@@ -1263,7 +1534,7 @@ ST_FUNC void lexpand_nr(void)
}
#endif
-#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
+#if PTR_SIZE == 4
/* build a long long from two ints */
static void lbuild(int t)
{
@@ -1274,60 +1545,6 @@ static void lbuild(int t)
}
#endif
-/* rotate n first stack elements to the bottom
- I1 ... In -> I2 ... In I1 [top is right]
-*/
-ST_FUNC void vrotb(int n)
-{
- int i;
- SValue tmp;
-
- tmp = vtop[-n + 1];
- for(i=-n+1;i!=0;i++)
- vtop[i] = vtop[i+1];
- vtop[0] = tmp;
-}
-
-/* rotate the n elements before entry e towards the top
- I1 ... In ... -> In I1 ... I(n-1) ... [top is right]
- */
-ST_FUNC void vrote(SValue *e, int n)
-{
- int i;
- SValue tmp;
-
- tmp = *e;
- for(i = 0;i < n - 1; i++)
- e[-i] = e[-i - 1];
- e[-n + 1] = tmp;
-}
-
-/* rotate n first stack elements to the top
- I1 ... In -> In I1 ... I(n-1) [top is right]
- */
-ST_FUNC void vrott(int n)
-{
- vrote(vtop, n);
-}
-
-/* pop stack value */
-ST_FUNC void vpop(void)
-{
- int v;
- v = vtop->r & VT_VALMASK;
-#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
- /* for x86, we need to pop the FP stack */
- if (v == TREG_ST0 && !nocode_wanted) {
- o(0xd8dd); /* fstp %st(0) */
- } else
-#endif
- if (v == VT_JMP || v == VT_JMPI) {
- /* need to put correct jump if && or || without test */
- gsym(vtop->c.i);
- }
- vtop--;
-}
-
/* convert stack entry to register and duplicate its value in another
register */
static void gv_dup(void)
@@ -1336,8 +1553,12 @@ static void gv_dup(void)
SValue sv;
t = vtop->type.t;
-#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
+#if PTR_SIZE == 4
if ((t & VT_BTYPE) == VT_LLONG) {
+ if (t & VT_BITFIELD) {
+ gv(RC_INT);
+ t = vtop->type.t;
+ }
lexpand();
gv_dup();
vswap();
@@ -1398,7 +1619,7 @@ ST_FUNC int gvtst(int inv, int t)
return gtst(inv, t);
}
-#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
/* generate CPU independent (unsigned) long long operations */
static void gen_opl(int op)
{
@@ -1512,7 +1733,7 @@ static void gen_opl(int op)
c = (int)vtop->c.i;
/* constant: simpler */
/* NOTE: all comments are for SHL. the other cases are
- done by swaping words */
+ done by swapping words */
vpop();
if (op != TOK_SHL)
vswap();
@@ -1597,25 +1818,15 @@ static void gen_opl(int op)
a = 0;
b = 0;
gen_op(op1);
- if (op1 != TOK_NE) {
+ if (op == TOK_NE) {
+ b = gvtst(0, 0);
+ } else {
a = gvtst(1, 0);
- }
- if (op != TOK_EQ) {
- /* generate non equal test */
- /* XXX: NOT PORTABLE yet */
- if (a == 0) {
+ if (op != TOK_EQ) {
+ /* generate non equal test */
+ vpushi(TOK_NE);
+ vtop->r = VT_CMP;
b = gvtst(0, 0);
- } else {
-#if defined(TCC_TARGET_I386)
- b = psym(0x850f, 0);
-#elif defined(TCC_TARGET_ARM)
- b = ind;
- o(0x1A000000 | encbranch(ind, 0, 1));
-#elif defined(TCC_TARGET_C67) || defined(TCC_TARGET_ARM64)
- tcc_error("not implemented");
-#else
-#error not supported
-#endif
}
}
/* compare low. Always unsigned */
@@ -1739,8 +1950,8 @@ static void gen_opic(int op)
vtop--;
} else if (!const_wanted &&
c2 && ((l2 == 0 && (op == '&' || op == '*')) ||
- (l2 == -1 && op == '|') ||
- (l2 == 0xffffffff && t2 != VT_LLONG && op == '|') ||
+ (op == '|' &&
+ (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))) ||
(l2 == 1 && (op == '%' || op == TOK_UMOD)))) {
/* treat (x & 0), (x * 0), (x | -1) and (x % 1) as constant */
if (l2 == 1)
@@ -1754,7 +1965,7 @@ static void gen_opic(int op)
op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) &&
l2 == 0) ||
(op == '&' &&
- l2 == -1))) {
+ (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))))) {
/* filter out NOP operations like x*1, x-0, x&-1... */
vtop--;
} else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
@@ -1789,23 +2000,12 @@ static void gen_opic(int op)
vtop->c.i = l2;
} else {
general_case:
- if (!nocode_wanted) {
/* call low level op generator */
if (t1 == VT_LLONG || t2 == VT_LLONG ||
(PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR)))
gen_opl(op);
else
gen_opi(op);
- } else {
- vtop--;
- /* Ensure vtop isn't marked VT_CONST in case something
- up our callchain is interested in const-ness of the
- expression. Also make it a non-LVAL if it was,
- so that further code can't accidentally generate
- a deref (happen only for buggy uses of e.g.
- gv() under nocode_wanted). */
- vtop->r &= ~(VT_VALMASK | VT_LVAL);
- }
}
}
}
@@ -1815,6 +2015,10 @@ static void gen_opif(int op)
{
int c1, c2;
SValue *v1, *v2;
+#if defined _MSC_VER && defined _AMD64_
+ /* avoid bad optimization with f1 -= f2 for f1:-0.0, f2:0.0 */
+ volatile
+#endif
long double f1, f2;
v1 = vtop - 1;
@@ -1866,11 +2070,7 @@ static void gen_opif(int op)
vtop--;
} else {
general_case:
- if (!nocode_wanted) {
- gen_opf(op);
- } else {
- vtop--;
- }
+ gen_opf(op);
}
}
@@ -1978,11 +2178,11 @@ redo:
goto redo;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
/* at least one operand is a pointer */
- /* relationnal op: must be both pointers */
+ /* 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 defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
t = VT_LLONG | VT_UNSIGNED;
#else
t = VT_INT | VT_UNSIGNED;
@@ -2002,12 +2202,7 @@ redo:
}
vrott(3);
gen_opic(op);
- /* set to integer type */
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
- vtop->type.t = VT_LLONG;
-#else
- vtop->type.t = VT_INT;
-#endif
+ vtop->type.t = ptrdiff_type.t;
vswap();
gen_op(TOK_PDIV);
} else {
@@ -2017,12 +2212,12 @@ redo:
/* Put pointer as first operand */
if (bt2 == VT_PTR) {
vswap();
- swap(&t1, &t2);
+ t = t1, t1 = t2, t2 = t;
}
#if PTR_SIZE == 4
if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG)
/* XXX: truncate here because gen_opl can't handle ptr + long long */
- gen_cast(&int_type);
+ gen_cast_s(VT_INT);
#endif
type1 = vtop[-1].type;
type1.t &= ~VT_ARRAY;
@@ -2032,7 +2227,7 @@ redo:
u = pointed_size(&vtop[-1].type);
if (u < 0)
tcc_error("unknown array element size");
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
vpushll(u);
#else
/* XXX: cast to int ? (long long case) */
@@ -2091,23 +2286,28 @@ redo:
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)) == (t | VT_UNSIGNED))
+ 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;
+ 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_LLONG | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
+ 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;
+ 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_INT | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
+ 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;
std_op:
/* XXX: currently, some unsigned operations are explicit, so
@@ -2130,6 +2330,7 @@ redo:
}
vswap();
type1.t = t;
+ type1.ref = NULL;
gen_cast(&type1);
vswap();
/* special case for shifts and long long: we keep the shift as
@@ -2142,14 +2343,14 @@ redo:
else
gen_opic(op);
if (op >= TOK_ULT && op <= TOK_GT) {
- /* relationnal op: the result is an int */
+ /* relational op: the result is an int */
vtop->type.t = VT_INT;
} else {
vtop->type.t = t;
}
}
// Make sure that we have converted to an rvalue:
- if (vtop->r & VT_LVAL && !nocode_wanted)
+ if (vtop->r & VT_LVAL)
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
}
@@ -2216,6 +2417,11 @@ static void gen_cvt_ftoi1(int t)
static void force_charshort_cast(int t)
{
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)
@@ -2242,6 +2448,14 @@ static void force_charshort_cast(int t)
}
/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */
+static void gen_cast_s(int t)
+{
+ CType type;
+ type.t = t;
+ type.ref = NULL;
+ gen_cast(&type);
+}
+
static void gen_cast(CType *type)
{
int sbt, dbt, sf, df, c, p;
@@ -2255,7 +2469,7 @@ static void gen_cast(CType *type)
}
/* bitfields first get cast to ints */
- if (vtop->type.t & VT_BITFIELD && !nocode_wanted) {
+ if (vtop->type.t & VT_BITFIELD) {
gv(RC_INT);
}
@@ -2267,6 +2481,9 @@ static void gen_cast(CType *type)
df = is_float(dbt);
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;
+#endif
if (c) {
/* constant case: we can do it now */
/* XXX: in ISOC, cannot do it if error in convert */
@@ -2303,7 +2520,7 @@ static void gen_cast(CType *type)
;
else if (sbt & VT_UNSIGNED)
vtop->c.i = (uint32_t)vtop->c.i;
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
else if (sbt == VT_PTR)
;
#endif
@@ -2315,7 +2532,7 @@ static void gen_cast(CType *type)
;
else if (dbt == VT_BOOL)
vtop->c.i = (vtop->c.i != 0);
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
else if (dbt == VT_PTR)
;
#endif
@@ -2331,7 +2548,7 @@ static void gen_cast(CType *type)
} else if (p && dbt == VT_BOOL) {
vtop->r = VT_CONST;
vtop->c.i = 1;
- } else if (!nocode_wanted) {
+ } else {
/* non constant case: generate code */
if (sf && df) {
/* convert from fp to fp */
@@ -2357,7 +2574,7 @@ static void gen_cast(CType *type)
gen_cast(type);
}
}
-#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
} else if ((dbt & VT_BTYPE) == VT_LLONG) {
if ((sbt & VT_BTYPE) != VT_LLONG) {
/* scalar to long long */
@@ -2371,7 +2588,7 @@ static void gen_cast(CType *type)
if (sbt == VT_PTR) {
/* cast from pointer to int before we apply
shift operation, which pointers don't support*/
- gen_cast(&int_type);
+ gen_cast_s(VT_INT);
}
gv_dup();
vpushi(31);
@@ -2415,7 +2632,7 @@ static void gen_cast(CType *type)
tcc_warning("nonportable conversion from pointer to char/short");
}
force_charshort_cast(dbt);
-#if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 4
} else if ((dbt & VT_BTYPE) == VT_INT) {
/* scalar to int */
if ((sbt & VT_BTYPE) == VT_LLONG) {
@@ -2465,6 +2682,8 @@ 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) {
+ return -1; /* incomplete enum */
} else if (bt == VT_LDOUBLE) {
*a = LDOUBLE_ALIGN;
return LDOUBLE_SIZE;
@@ -2494,10 +2713,6 @@ ST_FUNC int type_size(CType *type, int *a)
} else if (bt == VT_QLONG || bt == VT_QFLOAT) {
*a = 8;
return 16;
- } else if (bt == VT_ENUM) {
- *a = 4;
- /* Enums might be incomplete, so don't just return '4' here. */
- return type->ref->c;
} else {
/* char, void, function, _Bool */
*a = 1;
@@ -2540,7 +2755,7 @@ ST_FUNC void mk_pointer(CType *type)
{
Sym *s;
s = sym_push(SYM_FIELD, type, 0, -1);
- type->t = VT_PTR | (type->t & ~VT_TYPE);
+ type->t = VT_PTR | (type->t & VT_STORAGE);
type->ref = s;
}
@@ -2554,17 +2769,17 @@ static int is_compatible_func(CType *type1, CType *type2)
if (!is_compatible_types(&s1->type, &s2->type))
return 0;
/* check func_call */
- if (s1->a.func_call != s2->a.func_call)
+ if (s1->f.func_call != s2->f.func_call)
return 0;
/* XXX: not complete */
- if (s1->c == FUNC_OLD || s2->c == FUNC_OLD)
+ if (s1->f.func_type == FUNC_OLD || s2->f.func_type == FUNC_OLD)
return 1;
- if (s1->c != s2->c)
+ if (s1->f.func_type != s2->f.func_type)
return 0;
while (s1 != NULL) {
if (s2 == NULL)
return 0;
- if (!is_compatible_parameter_types(&s1->type, &s2->type))
+ if (!is_compatible_unqualified_types(&s1->type, &s2->type))
return 0;
s1 = s1->next;
s2 = s2->next;
@@ -2590,26 +2805,12 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
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;
}
- /* An enum is compatible with (unsigned) int. Ideally we would
- store the enums signedness in type->ref.a.<some_bit> and
- only accept unsigned enums with unsigned int and vice versa.
- But one of our callers (gen_assign_cast) always strips VT_UNSIGNED
- from pointer target types, so we can't add it here either. */
- if ((t1 & VT_BTYPE) == VT_ENUM) {
- t1 = VT_INT;
- if (type1->ref->a.unsigned_enum)
- t1 |= VT_UNSIGNED;
- }
- if ((t2 & VT_BTYPE) == VT_ENUM) {
- t2 = VT_INT;
- if (type2->ref->a.unsigned_enum)
- t2 |= VT_UNSIGNED;
- }
/* XXX: bitfields ? */
if (t1 != t2)
return 0;
@@ -2638,7 +2839,7 @@ static int is_compatible_types(CType *type1, CType *type2)
/* return true if type1 and type2 are the same (ignoring qualifiers).
*/
-static int is_compatible_parameter_types(CType *type1, CType *type2)
+static int is_compatible_unqualified_types(CType *type1, CType *type2)
{
return compare_types(type1,type2,1);
}
@@ -2655,17 +2856,33 @@ static void type_to_str(char *buf, int buf_size,
char buf1[256];
const char *tstr;
- t = type->t & VT_TYPE;
+ t = type->t;
bt = t & VT_BTYPE;
buf[0] = '\0';
- if (t & VT_CONSTANT)
- pstrcat(buf, buf_size, "const ");
+
+ 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_DEFSIGN | VT_UNSIGNED)) == (VT_DEFSIGN | VT_UNSIGNED))
- pstrcat(buf, buf_size, "unsigned ");
- else if (t & VT_DEFSIGN)
- pstrcat(buf, buf_size, "signed ");
+ 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";
@@ -2681,13 +2898,16 @@ static void type_to_str(char *buf, int buf_size,
goto add_tstr;
case VT_INT:
tstr = "int";
- goto add_tstr;
- case VT_LONG:
- tstr = "long";
- goto add_tstr;
+ goto maybe_long;
case VT_LLONG:
tstr = "long long";
- goto add_tstr;
+ 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;
@@ -2699,12 +2919,11 @@ static void type_to_str(char *buf, int buf_size,
add_tstr:
pstrcat(buf, buf_size, tstr);
break;
- case VT_ENUM:
case VT_STRUCT:
- if (bt == VT_STRUCT)
- tstr = "struct ";
- else
- tstr = "enum ";
+ 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)
@@ -2729,7 +2948,7 @@ static void type_to_str(char *buf, int buf_size,
case VT_PTR:
s = type->ref;
if (t & VT_ARRAY) {
- snprintf(buf1, sizeof(buf1), "%s[%ld]", varstr ? varstr : "", s->c);
+ snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c);
type_to_str(buf, buf_size, &s->type, buf1);
goto no_var;
}
@@ -2754,7 +2973,7 @@ static void type_to_str(char *buf, int buf_size,
casts if needed. */
static void gen_assign_cast(CType *dt)
{
- CType *st, *type1, *type2, tmp_type1, tmp_type2;
+ CType *st, *type1, *type2;
char buf1[256], buf2[256];
int dbt, sbt;
@@ -2789,7 +3008,7 @@ static void gen_assign_cast(CType *dt)
goto type_ok;
}
type1 = pointed_type(dt);
- /* a function is implicitely a function pointer */
+ /* 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))
@@ -2803,21 +3022,16 @@ static void gen_assign_cast(CType *dt)
(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 */
- tmp_type1 = *type1;
- tmp_type2 = *type2;
- tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
- tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
- if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
+ if (!is_compatible_unqualified_types(type1, type2)) {
/* 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 ((tmp_type1.t & (VT_DEFSIGN | VT_UNSIGNED)) !=
- (tmp_type2.t & (VT_DEFSIGN | VT_UNSIGNED)) &&
- (tmp_type1.t & VT_BTYPE) == (tmp_type2.t & VT_BTYPE))
- ;
- else
+ 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");
}
}
@@ -2839,11 +3053,7 @@ static void gen_assign_cast(CType *dt)
break;
case VT_STRUCT:
case_VT_STRUCT:
- tmp_type1 = *dt;
- tmp_type2 = *st;
- tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
- tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
- if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
+ if (!is_compatible_unqualified_types(dt, st)) {
error:
type_to_str(buf1, sizeof(buf1), st, NULL);
type_to_str(buf2, sizeof(buf2), dt, NULL);
@@ -2868,8 +3078,7 @@ ST_FUNC void vstore(void)
&& !(vtop->type.t & VT_BITFIELD)) {
/* optimize char/short casts */
delayed_cast = VT_MUSTCAST;
- vtop->type.t = (ft & VT_TYPE & ~VT_BITFIELD &
- ((1 << VT_STRUCT_SHIFT) - 1));
+ vtop->type.t = ft & VT_TYPE;
/* XXX: factorize */
if (ft & VT_CONSTANT)
tcc_warning("assignment of read-only location");
@@ -2883,7 +3092,6 @@ ST_FUNC void vstore(void)
/* if structure, only generate pointer */
/* structure assignment : generate memcpy */
/* XXX: optimize if small size */
- if (!nocode_wanted) {
size = type_size(&vtop->type, &align);
/* destination */
@@ -2910,10 +3118,7 @@ ST_FUNC void vstore(void)
/* type size */
vpushi(size);
gfunc_call(3);
- } else {
- vswap();
- vpop();
- }
+
/* leave source on stack */
} else if (ft & VT_BITFIELD) {
/* bitfield store handling */
@@ -2921,47 +3126,52 @@ ST_FUNC void vstore(void)
/* save lvalue as expression result (example: s.b = s.a = n;) */
vdup(), vtop[-1] = vtop[-2];
- bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f;
- bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+ bit_pos = BIT_POS(ft);
+ bit_size = BIT_SIZE(ft);
/* remove bit field info to avoid loops */
- vtop[-1].type.t = ft & ~VT_BITFIELD & ((1 << VT_STRUCT_SHIFT) - 1);
+ vtop[-1].type.t = ft & ~VT_STRUCT_MASK;
- if((ft & VT_BTYPE) == VT_BOOL) {
+ if ((ft & VT_BTYPE) == VT_BOOL) {
gen_cast(&vtop[-1].type);
vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
}
- /* duplicate destination */
- vdup();
- vtop[-1] = vtop[-2];
-
- /* mask and shift source */
- if((ft & VT_BTYPE) != VT_BOOL) {
- if((ft & VT_BTYPE) == VT_LLONG) {
- vpushll((1ULL << bit_size) - 1ULL);
- } else {
- vpushi((1 << bit_size) - 1);
+ r = adjust_bf(vtop - 1, bit_pos, bit_size);
+ 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) {
+ /* mask source */
+ if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG)
+ vpushll(mask);
+ else
+ vpushi((unsigned)mask);
+ gen_op('&');
}
+ /* shift source */
+ vpushi(bit_pos);
+ gen_op(TOK_SHL);
+ vswap();
+ /* duplicate destination */
+ vdup();
+ vrott(3);
+ /* load destination, mask and or with source */
+ if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
+ vpushll(~(mask << bit_pos));
+ else
+ vpushi(~((unsigned)mask << bit_pos));
gen_op('&');
+ gen_op('|');
+ /* store result */
+ vstore();
+ /* ... and discard */
+ vpop();
}
- vpushi(bit_pos);
- gen_op(TOK_SHL);
- /* load destination, mask and or with source */
- vswap();
- if((ft & VT_BTYPE) == VT_LLONG) {
- vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos));
- } else {
- vpushi(~(((1 << bit_size) - 1) << bit_pos));
- }
- gen_op('&');
- gen_op('|');
- /* store result */
- vstore();
- /* ... and discard */
- vpop();
-
+ } else if (dbt == VT_VOID) {
+ --vtop;
} else {
- if (!nocode_wanted) {
#ifdef CONFIG_TCC_BCHECK
/* bound check case */
if (vtop[-1].r & VT_MUSTBOUND) {
@@ -2986,7 +3196,7 @@ ST_FUNC void vstore(void)
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
SValue sv;
t = get_reg(RC_INT);
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
sv.type.t = VT_PTR;
#else
sv.type.t = VT_INT;
@@ -2997,7 +3207,7 @@ ST_FUNC void vstore(void)
vtop[-1].r = t | VT_LVAL;
}
/* two word case handling : store second register at word + 4 (or +8 for x86-64) */
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_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
@@ -3020,7 +3230,7 @@ ST_FUNC void vstore(void)
} else {
store(r, vtop - 1);
}
- }
+
vswap();
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
vtop->r |= delayed_cast;
@@ -3033,10 +3243,7 @@ ST_FUNC void inc(int post, int c)
test_lvalue();
vdup(); /* save lvalue */
if (post) {
- if (!nocode_wanted)
- gv_dup(); /* duplicate value */
- else
- vdup(); /* duplicate value */
+ gv_dup(); /* duplicate value */
vrotb(3);
vrotb(3);
}
@@ -3080,20 +3287,15 @@ static int exact_log2p1(int i)
return ret;
}
-/* Parse GNUC __attribute__ extension. Currently, the following
- extensions are recognized:
- - aligned(n) : set data/function alignment.
- - packed : force data alignment to 1
- - section(x) : generate data/code in this section.
- - unused : currently ignored, but may be used someday.
- - regparm(n) : pass function parameters in registers (i386 only)
- */
+/* Parse __attribute__((...)) GNUC extension. */
static void parse_attribute(AttributeDef *ad)
{
int t, n;
CString astr;
- while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) {
+redo:
+ if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2)
+ return;
next();
skip('(');
skip('(');
@@ -3174,12 +3376,12 @@ static void parse_attribute(AttributeDef *ad)
case TOK_CDECL1:
case TOK_CDECL2:
case TOK_CDECL3:
- ad->a.func_call = FUNC_CDECL;
+ ad->f.func_call = FUNC_CDECL;
break;
case TOK_STDCALL1:
case TOK_STDCALL2:
case TOK_STDCALL3:
- ad->a.func_call = FUNC_STDCALL;
+ ad->f.func_call = FUNC_STDCALL;
break;
#ifdef TCC_TARGET_I386
case TOK_REGPARM1:
@@ -3191,30 +3393,30 @@ static void parse_attribute(AttributeDef *ad)
else if (n < 0)
n = 0;
if (n > 0)
- ad->a.func_call = FUNC_FASTCALL1 + n - 1;
+ ad->f.func_call = FUNC_FASTCALL1 + n - 1;
skip(')');
break;
case TOK_FASTCALL1:
case TOK_FASTCALL2:
case TOK_FASTCALL3:
- ad->a.func_call = FUNC_FASTCALLW;
+ ad->f.func_call = FUNC_FASTCALLW;
break;
#endif
case TOK_MODE:
skip('(');
switch(tok) {
case TOK_MODE_DI:
- ad->a.mode = VT_LLONG + 1;
+ ad->attr_mode = VT_LLONG + 1;
break;
case TOK_MODE_QI:
- ad->a.mode = VT_BYTE + 1;
+ ad->attr_mode = VT_BYTE + 1;
break;
case TOK_MODE_HI:
- ad->a.mode = VT_SHORT + 1;
+ ad->attr_mode = VT_SHORT + 1;
break;
case TOK_MODE_SI:
case TOK_MODE_word:
- ad->a.mode = VT_INT + 1;
+ ad->attr_mode = VT_INT + 1;
break;
default:
tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL));
@@ -3224,10 +3426,10 @@ static void parse_attribute(AttributeDef *ad)
skip(')');
break;
case TOK_DLLEXPORT:
- ad->a.func_export = 1;
+ ad->a.dllexport = 1;
break;
case TOK_DLLIMPORT:
- ad->a.func_import = 1;
+ ad->a.dllimport = 1;
break;
default:
if (tcc_state->warn_unsupported)
@@ -3251,7 +3453,7 @@ static void parse_attribute(AttributeDef *ad)
}
skip(')');
skip(')');
- }
+ goto redo;
}
static Sym * find_field (CType *type, int v)
@@ -3286,98 +3488,115 @@ static void struct_add_offset (Sym *s, int offset)
static void struct_layout(CType *type, AttributeDef *ad)
{
- int align, maxalign, offset, c, bit_pos, bt, prevbt, prev_bit_size;
+ int size, align, maxalign, offset, c, bit_pos, bit_size;
+ int packed, a, bt, prevbt, prev_bit_size;
int pcc = !tcc_state->ms_bitfields;
+ int pragma_pack = *tcc_state->pack_stack_ptr;
Sym *f;
- if (ad->a.aligned)
- maxalign = 1 << (ad->a.aligned - 1);
- else
- maxalign = 1;
+
+ maxalign = 1;
offset = 0;
c = 0;
bit_pos = 0;
prevbt = VT_STRUCT; /* make it never match */
prev_bit_size = 0;
+
+//#define BF_DEBUG
+
for (f = type->ref->next; f; f = f->next) {
- int typealign, bit_size;
- int size = type_size(&f->type, &typealign);
- if (f->type.t & VT_BITFIELD)
- bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
- else
- bit_size = -1;
- if (bit_size == 0 && pcc) {
- /* Zero-width bit-fields in PCC mode aren't affected
- by any packing (attribute or pragma). */
- align = typealign;
- } else if (f->r > 1) {
- align = f->r;
- } else if (ad->a.packed || f->r == 1) {
- align = 1;
- /* Packed fields or packed records don't let the base type
- influence the records type alignment. */
- typealign = 1;
- } else {
- align = typealign;
- }
- if (type->ref->type.t != TOK_STRUCT) {
+ if (f->type.t & VT_BITFIELD)
+ bit_size = BIT_SIZE(f->type.t);
+ else
+ bit_size = -1;
+ size = type_size(&f->type, &align);
+ a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0;
+ packed = 0;
+
+ if (pcc && bit_size == 0) {
+ /* in pcc mode, packing does not affect zero-width bitfields */
+
+ } else {
+ /* in pcc mode, attribute packed overrides if set. */
+ if (pcc && (f->a.packed || ad->a.packed))
+ align = packed = 1;
+
+ /* pragma pack overrides align if lesser and packs bitfields always */
+ if (pragma_pack) {
+ packed = 1;
+ if (pragma_pack < align)
+ align = pragma_pack;
+ /* in pcc mode pragma pack also overrides individual align */
+ if (pcc && pragma_pack < a)
+ a = 0;
+ }
+ }
+ /* some individual align was specified */
+ if (a)
+ align = a;
+
+ if (type->ref->type.t == VT_UNION) {
if (pcc && bit_size >= 0)
- size = (bit_size + 7) >> 3;
- /* Bit position is already zero from our caller. */
+ size = (bit_size + 7) >> 3;
offset = 0;
if (size > c)
- c = size;
+ c = size;
+
} else if (bit_size < 0) {
- int addbytes = pcc ? (bit_pos + 7) >> 3 : 0;
- prevbt = VT_STRUCT;
- prev_bit_size = 0;
- c = (c + addbytes + align - 1) & -align;
+ if (pcc)
+ c += (bit_pos + 7) >> 3;
+ c = (c + align - 1) & -align;
offset = c;
if (size > 0)
- c += size;
+ c += size;
bit_pos = 0;
+ prevbt = VT_STRUCT;
+ prev_bit_size = 0;
+
} else {
/* A bit-field. Layout is more complicated. There are two
- options TCC implements: PCC compatible and MS compatible
- (PCC compatible is what GCC uses for almost all targets).
- In PCC layout the overall size of the struct (in c) is
- _excluding_ the current run of bit-fields (that is,
- there's at least additional bit_pos bits after c). In
- MS layout c does include the current run of bit-fields.
-
- This matters for calculating the natural alignment buckets
- in PCC mode. */
-
- /* 'align' will be used to influence records alignment,
- so it's the max of specified and type alignment, except
- in certain cases that depend on the mode. */
- if (align < typealign)
- align = typealign;
- if (pcc) {
- /* In PCC layout a non-packed bit-field is placed adjacent
- to the preceding bit-fields, except if it would overflow
- its container (depending on base type) or it's a zero-width
- bit-field. Packed non-zero-width bit-fields always are
- placed adjacent. */
- int ofs = (c * 8 + bit_pos) % (typealign * 8);
- int ofs2 = ofs + bit_size + (typealign * 8) - 1;
- if (bit_size == 0 ||
- (typealign != 1 &&
- (ofs2 / (typealign * 8)) > (size/typealign))) {
- c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign;
+ options: PCC (GCC) compatible and MS compatible */
+ if (pcc) {
+ /* In PCC layout a bit-field is placed adjacent to the
+ preceding bit-fields, except if:
+ - it has zero-width
+ - an individual alignment was given
+ - it would overflow its base type container and
+ there is no packing */
+ if (bit_size == 0) {
+ new_field:
+ c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align;
bit_pos = 0;
- }
- offset = c;
+ } else if (f->a.aligned) {
+ goto new_field;
+ } else if (!packed) {
+ int a8 = align * 8;
+ int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8;
+ if (ofs > size / align)
+ goto new_field;
+ }
+
+ /* in pcc mode, long long bitfields have type int if they fit */
+ if (size == 8 && bit_size <= 32)
+ f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4;
+
+ while (bit_pos >= align * 8)
+ c += align, bit_pos -= align * 8;
+ offset = c;
+
/* In PCC layout named bit-fields influence the alignment
of the containing struct using the base types alignment,
- except for packed fields (which here have correct
- align/typealign). */
- if ((f->v & SYM_FIRST_ANOM))
- align = 1;
+ except for packed fields (which here have correct align). */
+ if (f->v & SYM_FIRST_ANOM
+ // && bit_size // ??? gcc on ARM/rpi does that
+ )
+ align = 1;
+
} else {
bt = f->type.t & VT_BTYPE;
- if ((bit_pos + bit_size > size * 8) ||
- (bit_size > 0) == (bt != prevbt)) {
- c = (c + typealign - 1) & -typealign;
+ if ((bit_pos + bit_size > size * 8)
+ || (bit_size > 0) == (bt != prevbt)
+ ) {
+ c = (c + align - 1) & -align;
offset = c;
bit_pos = 0;
/* In MS bitfield mode a bit-field run always uses
@@ -3385,34 +3604,33 @@ static void struct_layout(CType *type, AttributeDef *ad)
To start a new run it's also required that this
or the last bit-field had non-zero width. */
if (bit_size || prev_bit_size)
- c += size;
+ c += size;
}
/* In MS layout the records alignment is normally
influenced by the field, except for a zero-width
field at the start of a run (but by further zero-width
fields it is again). */
if (bit_size == 0 && prevbt != bt)
- align = 1;
+ align = 1;
prevbt = bt;
- prev_bit_size = bit_size;
+ prev_bit_size = bit_size;
}
+
f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
| (bit_pos << VT_STRUCT_SHIFT);
bit_pos += bit_size;
- if (pcc && bit_pos >= size * 8) {
- c += size;
- bit_pos -= size * 8;
- }
}
if (align > maxalign)
- maxalign = align;
-#if 0
- printf("set field %s offset=%d c=%d",
- get_tok_str(f->v & ~SYM_FIELD, NULL), offset, c);
+ maxalign = align;
+
+#ifdef BF_DEBUG
+ printf("set field %s offset %-2d size %-2d align %-2d",
+ get_tok_str(f->v & ~SYM_FIELD, NULL), offset, size, align);
if (f->type.t & VT_BITFIELD) {
- printf(" pos=%d size=%d",
- (f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
- (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
+ printf(" pos %-2d bits %-2d",
+ BIT_POS(f->type.t),
+ BIT_SIZE(f->type.t)
+ );
}
printf("\n");
#endif
@@ -3454,26 +3672,105 @@ static void struct_layout(CType *type, AttributeDef *ad)
f->r = 0;
}
+
+ if (pcc)
+ c += (bit_pos + 7) >> 3;
+
/* store size and alignment */
- type->ref->c = (c + (pcc ? (bit_pos + 7) >> 3 : 0)
- + maxalign - 1) & -maxalign;
- type->ref->r = maxalign;
+ a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1;
+ if (a < maxalign)
+ a = maxalign;
+ type->ref->r = a;
+ if (pragma_pack && pragma_pack < maxalign && 0 == pcc) {
+ /* can happen if individual align for some member was given. In
+ this case MSVC ignores maxalign when aligning the size */
+ a = pragma_pack;
+ if (a < bt)
+ a = bt;
+ }
+ c = (c + a - 1) & -a;
+ type->ref->c = c;
+
+#ifdef BF_DEBUG
+ printf("struct size %-2d align %-2d\n\n", c, a), fflush(stdout);
+#endif
+
+ /* check whether we can access bitfields by their type */
+ for (f = type->ref->next; f; f = f->next) {
+ int s, px, cx, c0;
+ CType t;
+
+ if (0 == (f->type.t & VT_BITFIELD))
+ continue;
+ f->type.ref = f;
+ f->auxtype = -1;
+ bit_size = BIT_SIZE(f->type.t);
+ if (bit_size == 0)
+ continue;
+ bit_pos = BIT_POS(f->type.t);
+ size = type_size(&f->type, &align);
+ if (bit_pos + bit_size <= size * 8 && f->c + size <= c)
+ continue;
+
+ /* try to access the field using a different type */
+ c0 = -1, s = align = 1;
+ for (;;) {
+ px = f->c * 8 + bit_pos;
+ cx = (px >> 3) & -align;
+ px = px - (cx << 3);
+ if (c0 == cx)
+ break;
+ s = (px + bit_size + 7) >> 3;
+ if (s > 4) {
+ t.t = VT_LLONG;
+ } else if (s > 2) {
+ t.t = VT_INT;
+ } else if (s > 1) {
+ t.t = VT_SHORT;
+ } else {
+ t.t = VT_BYTE;
+ }
+ s = type_size(&t, &align);
+ c0 = cx;
+ }
+
+ if (px + bit_size <= s * 8 && cx + s <= c) {
+ /* update offset and bit position */
+ f->c = cx;
+ bit_pos = px;
+ f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
+ | (bit_pos << VT_STRUCT_SHIFT);
+ if (s != size)
+ f->auxtype = t.t;
+#ifdef BF_DEBUG
+ printf("FIX field %s offset %-2d size %-2d align %-2d "
+ "pos %-2d bits %-2d\n",
+ get_tok_str(f->v & ~SYM_FIELD, NULL),
+ cx, s, align, px, bit_size);
+#endif
+ } else {
+ /* fall back to load/store single-byte wise */
+ f->auxtype = VT_STRUCT;
+#ifdef BF_DEBUG
+ printf("FIX field %s : load byte-wise\n",
+ get_tok_str(f->v & ~SYM_FIELD, NULL));
+#endif
+ }
+ }
}
-/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
-static void struct_decl(CType *type, AttributeDef *ad, int u)
+/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */
+static void struct_decl(CType *type, int u)
{
- int a, v, size, align, flexible, alignoverride;
- long c;
+ int v, c, size, align, flexible;
int bit_size, bsize, bt;
Sym *s, *ss, **ps;
- AttributeDef ad1;
+ AttributeDef ad, ad1;
CType type1, btype;
- a = tok; /* save decl type */
+ memset(&ad, 0, sizeof ad);
next();
- if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
- parse_attribute(ad);
+ parse_attribute(&ad);
if (tok != '{') {
v = tok;
next();
@@ -3481,37 +3778,40 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
if (v < TOK_IDENT)
expect("struct/union/enum name");
s = struct_find(v);
- if (s && (s->scope == local_scope || (tok != '{' && tok != ';'))) {
- if (s->type.t != a)
- tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
- goto do_decl;
+ if (s && (s->sym_scope == local_scope || tok != '{')) {
+ if (u == s->type.t)
+ goto do_decl;
+ if (u == VT_ENUM && IS_ENUM(s->type.t))
+ goto do_decl;
+ tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
}
} else {
v = anon_sym++;
}
/* Record the original enum/struct/union token. */
- type1.t = a;
+ type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u;
type1.ref = NULL;
/* we put an undefined size for struct/union */
s = sym_push(v | SYM_STRUCT, &type1, 0, -1);
s->r = 0; /* default alignment is zero as gcc */
- /* put struct/union/enum name in type */
- do_decl:
- type->t = u;
+do_decl:
+ type->t = s->type.t;
type->ref = s;
-
+
if (tok == '{') {
next();
if (s->c != -1)
tcc_error("struct/union/enum already defined");
/* cannot be empty */
- c = 0;
/* non empty enums are not allowed */
- if (a == TOK_ENUM) {
- int seen_neg = 0;
- int seen_wide = 0;
+ ps = &s->next;
+ if (u == VT_ENUM) {
+ long long ll = 0, pl = 0, nl = 0;
+ CType t;
+ t.ref = s;
+ /* enum symbols have static storage */
+ t.t = VT_INT|VT_STATIC|VT_ENUM_VAL;
for(;;) {
- CType *t = &int_type;
v = tok;
if (v < TOK_UIDENT)
expect("identifier");
@@ -3522,38 +3822,49 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
next();
if (tok == '=') {
next();
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
- c = expr_const64();
-#else
- /* We really want to support long long enums
- on i386 as well, but the Sym structure only
- holds a 'long' for associated constants,
- and enlarging it would bump its size (no
- available padding). So punt for now. */
- c = expr_const();
-#endif
+ ll = expr_const64();
}
- if (c < 0)
- seen_neg = 1;
- if (c != (int)c && (unsigned long)c != (unsigned int)c)
- seen_wide = 1, t = &size_type;
- /* enum symbols have static storage */
- ss = sym_push(v, t, VT_CONST, c);
- ss->type.t |= VT_STATIC;
+ ss = sym_push(v, &t, VT_CONST, 0);
+ ss->enum_val = ll;
+ *ps = ss, ps = &ss->next;
+ if (ll < nl)
+ nl = ll;
+ if (ll > pl)
+ pl = ll;
if (tok != ',')
break;
next();
- c++;
+ ll++;
/* NOTE: we accept a trailing comma */
if (tok == '}')
break;
}
- if (!seen_neg)
- s->a.unsigned_enum = 1;
- s->c = type_size(seen_wide ? &size_type : &int_type, &align);
skip('}');
+ /* set integral type of the enum */
+ t.t = VT_INT;
+ if (nl >= 0) {
+ if (pl != (unsigned)pl)
+ t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
+ t.t |= VT_UNSIGNED;
+ } else if (pl != (int)pl || nl != (int)nl)
+ t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
+ s->type.t = type->t = t.t | VT_ENUM;
+ s->c = 0;
+ /* set type for enum members */
+ for (ss = s->next; ss; ss = ss->next) {
+ ll = ss->enum_val;
+ if (ll == (int)ll) /* default is int if it fits */
+ continue;
+ if (t.t & VT_UNSIGNED) {
+ ss->type.t |= VT_UNSIGNED;
+ if (ll == (unsigned)ll)
+ continue;
+ }
+ ss->type.t = (ss->type.t & ~VT_BTYPE)
+ | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG);
+ }
} else {
- ps = &s->next;
+ c = 0;
flexible = 0;
while (tok != '}') {
if (!parse_btype(&btype, &ad1)) {
@@ -3568,7 +3879,8 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
v = 0;
type1 = btype;
if (tok != ':') {
- type_decl(&type1, &ad1, &v, TYPE_DIRECT | TYPE_ABSTRACT);
+ if (tok != ';')
+ type_decl(&type1, &ad1, &v, TYPE_DIRECT);
if (v == 0) {
if ((type1.t & VT_BTYPE) != VT_STRUCT)
expect("identifier");
@@ -3581,14 +3893,14 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
}
}
if (type_size(&type1, &align) < 0) {
- if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY) && c)
+ if ((u == VT_STRUCT) && (type1.t & VT_ARRAY) && c)
flexible = 1;
else
tcc_error("field '%s' has incomplete type",
get_tok_str(v, NULL));
}
if ((type1.t & VT_BTYPE) == VT_FUNC ||
- (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE)))
+ (type1.t & VT_STORAGE))
tcc_error("invalid type for '%s'",
get_tok_str(v, NULL));
}
@@ -3602,41 +3914,31 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
if (v && bit_size == 0)
tcc_error("zero width for bit-field '%s'",
get_tok_str(v, NULL));
- if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
- parse_attribute(&ad1);
+ parse_attribute(&ad1);
}
size = type_size(&type1, &align);
- /* Only remember non-default alignment. */
- alignoverride = 0;
- if (ad1.a.aligned) {
- int speca = 1 << (ad1.a.aligned - 1);
- alignoverride = speca;
- } else if (ad1.a.packed || ad->a.packed) {
- alignoverride = 1;
- } else if (*tcc_state->pack_stack_ptr) {
- if (align > *tcc_state->pack_stack_ptr)
- alignoverride = *tcc_state->pack_stack_ptr;
- }
if (bit_size >= 0) {
bt = type1.t & VT_BTYPE;
if (bt != VT_INT &&
bt != VT_BYTE &&
bt != VT_SHORT &&
bt != VT_BOOL &&
- bt != VT_ENUM &&
bt != VT_LLONG)
tcc_error("bitfields must have scalar type");
bsize = size * 8;
if (bit_size > bsize) {
tcc_error("width of '%s' exceeds its type",
get_tok_str(v, NULL));
- } else if (bit_size == bsize) {
+ } else if (bit_size == bsize
+ && !ad.a.packed && !ad1.a.packed) {
/* no need for bit fields */
;
+ } else if (bit_size == 64) {
+ tcc_error("field width 64 not implemented");
} else {
- type1.t |= VT_BITFIELD |
- (0 << VT_STRUCT_SHIFT) |
- (bit_size << (VT_STRUCT_SHIFT + 6));
+ type1.t = (type1.t & ~VT_STRUCT_MASK)
+ | VT_BITFIELD
+ | (bit_size << (VT_STRUCT_SHIFT + 6));
}
}
if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
@@ -3652,7 +3954,8 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
v = anon_sym++;
}
if (v) {
- ss = sym_push(v | SYM_FIELD, &type1, alignoverride, 0);
+ ss = sym_push(v | SYM_FIELD, &type1, 0, 0);
+ ss->a = ad1.a;
*ps = ss;
ps = &ss->next;
}
@@ -3663,17 +3966,22 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
skip(';');
}
skip('}');
- if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
- parse_attribute(ad);
- struct_layout(type, ad);
+ parse_attribute(&ad);
+ struct_layout(type, &ad);
}
}
}
-/* return 1 if basic type is a type size (short, long, long long) */
-ST_FUNC int is_btype_size(int bt)
+static void sym_to_attr(AttributeDef *ad, Sym *s)
{
- return bt == VT_SHORT || bt == VT_LONG || bt == VT_LLONG;
+ 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;
}
/* Add type qualifiers to a type. If the type is an array then the qualifiers
@@ -3692,15 +4000,17 @@ static void parse_btype_qualify(CType *type, int qualifiers)
*/
static int parse_btype(CType *type, AttributeDef *ad)
{
- int t, u, bt_size, complete, type_found, typespec_found;
+ int t, u, bt, st, type_found, typespec_found, g;
Sym *s;
CType type1;
memset(ad, 0, sizeof(AttributeDef));
- complete = 0;
type_found = 0;
typespec_found = 0;
- t = 0;
+ t = VT_INT;
+ bt = st = -1;
+ type->ref = NULL;
+
while(1) {
switch(tok) {
case TOK_EXTENSION:
@@ -3714,12 +4024,17 @@ static int parse_btype(CType *type, AttributeDef *ad)
basic_type:
next();
basic_type1:
- if (complete)
- tcc_error("too many basic types");
- t |= u;
- bt_size = is_btype_size (u & VT_BTYPE);
- if (u == VT_INT || (!bt_size && !(t & VT_TYPEDEF)))
- complete = 1;
+ if (u == VT_SHORT || u == VT_LONG) {
+ if (st != -1 || (bt != -1 && bt != VT_INT))
+ tmbt: tcc_error("too many basic types");
+ st = u;
+ } else {
+ if (bt != -1 || (st != -1 && u != VT_INT))
+ goto tmbt;
+ bt = u;
+ }
+ if (u != VT_INT)
+ t = (t & ~(VT_BTYPE|VT_LONG)) | u;
typespec_found = 1;
break;
case TOK_VOID:
@@ -3732,17 +4047,15 @@ static int parse_btype(CType *type, AttributeDef *ad)
u = VT_INT;
goto basic_type;
case TOK_LONG:
- next();
if ((t & VT_BTYPE) == VT_DOUBLE) {
-#ifndef TCC_TARGET_PE
- t = (t & ~VT_BTYPE) | VT_LDOUBLE;
-#endif
- } else if ((t & VT_BTYPE) == VT_LONG) {
- t = (t & ~VT_BTYPE) | VT_LLONG;
+ t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
+ } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) {
+ t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG;
} else {
u = VT_LONG;
- goto basic_type1;
+ goto basic_type;
}
+ next();
break;
#ifdef TCC_TARGET_ARM64
case TOK_UINT128:
@@ -3758,27 +4071,25 @@ static int parse_btype(CType *type, AttributeDef *ad)
u = VT_FLOAT;
goto basic_type;
case TOK_DOUBLE:
- next();
- if ((t & VT_BTYPE) == VT_LONG) {
-#ifdef TCC_TARGET_PE
- t = (t & ~VT_BTYPE) | VT_DOUBLE;
-#else
- t = (t & ~VT_BTYPE) | VT_LDOUBLE;
-#endif
+ if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) {
+ t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE;
} else {
u = VT_DOUBLE;
- goto basic_type1;
+ goto basic_type;
}
+ next();
break;
case TOK_ENUM:
- struct_decl(&type1, ad, VT_ENUM);
+ struct_decl(&type1, VT_ENUM);
basic_type2:
u = type1.t;
type->ref = type1.ref;
goto basic_type1;
case TOK_STRUCT:
+ struct_decl(&type1, VT_STRUCT);
+ goto basic_type2;
case TOK_UNION:
- struct_decl(&type1, ad, VT_STRUCT);
+ struct_decl(&type1, VT_UNION);
goto basic_type2;
/* type modifiers */
@@ -3803,9 +4114,9 @@ static int parse_btype(CType *type, AttributeDef *ad)
case TOK_SIGNED3:
if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED))
tcc_error("signed and unsigned modifier");
- typespec_found = 1;
t |= VT_DEFSIGN;
next();
+ typespec_found = 1;
break;
case TOK_REGISTER:
case TOK_AUTO:
@@ -3824,15 +4135,18 @@ static int parse_btype(CType *type, AttributeDef *ad)
/* storage */
case TOK_EXTERN:
- t |= VT_EXTERN;
- next();
- break;
+ g = VT_EXTERN;
+ goto storage;
case TOK_STATIC:
- t |= VT_STATIC;
- next();
- break;
+ g = VT_STATIC;
+ goto storage;
case TOK_TYPEDEF:
- t |= VT_TYPEDEF;
+ g = VT_TYPEDEF;
+ goto storage;
+ storage:
+ if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g)
+ tcc_error("multiple storage classes");
+ t |= g;
next();
break;
case TOK_INLINE1:
@@ -3846,9 +4160,9 @@ static int parse_btype(CType *type, AttributeDef *ad)
case TOK_ATTRIBUTE1:
case TOK_ATTRIBUTE2:
parse_attribute(ad);
- if (ad->a.mode) {
- u = ad->a.mode -1;
- t = (t & ~VT_BTYPE) | u;
+ if (ad->attr_mode) {
+ u = ad->attr_mode -1;
+ t = (t & ~(VT_BTYPE|VT_LONG)) | u;
}
break;
/* GNUC typeof */
@@ -3859,6 +4173,8 @@ static int parse_btype(CType *type, AttributeDef *ad)
parse_expr_type(&type1);
/* remove all storage modifiers except typedef */
type1.t &= ~(VT_STORAGE&~VT_TYPEDEF);
+ if (type1.ref)
+ sym_to_attr(ad, type1.ref);
goto basic_type2;
default:
if (typespec_found)
@@ -3866,24 +4182,18 @@ static int parse_btype(CType *type, AttributeDef *ad)
s = sym_find(tok);
if (!s || !(s->type.t & VT_TYPEDEF))
goto the_end;
-
- type->t = ((s->type.t & ~VT_TYPEDEF) |
- (t & ~(VT_CONSTANT | VT_VOLATILE)));
+ t &= ~(VT_BTYPE|VT_LONG);
+ u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u;
+ type->t = (s->type.t & ~VT_TYPEDEF) | u;
type->ref = s->type.ref;
- if (t & (VT_CONSTANT | VT_VOLATILE))
- parse_btype_qualify(type, t & (VT_CONSTANT | VT_VOLATILE));
+ if (t)
+ parse_btype_qualify(type, t);
t = type->t;
-
- if (s->r) {
- /* get attributes from typedef */
- if (0 == ad->a.aligned)
- ad->a.aligned = s->a.aligned;
- if (0 == ad->a.func_call)
- ad->a.func_call = s->a.func_call;
- ad->a.packed |= s->a.packed;
- }
+ /* get attributes from typedef */
+ sym_to_attr(ad, s);
next();
typespec_found = 1;
+ st = bt = -2;
break;
}
type_found = 1;
@@ -3893,14 +4203,13 @@ the_end:
if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE)
t |= VT_UNSIGNED;
}
-
- /* long is never used as type */
- if ((t & VT_BTYPE) == VT_LONG)
-#if (!defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64) || \
- defined TCC_TARGET_PE
- t = (t & ~VT_BTYPE) | VT_INT;
-#else
- t = (t & ~VT_BTYPE) | VT_LLONG;
+ /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */
+ bt = t & (VT_BTYPE|VT_LONG);
+ if (bt == VT_LONG)
+ t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT;
+#ifdef TCC_TARGET_PE
+ if (bt == VT_LDOUBLE)
+ t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE;
#endif
type->t = t;
return type_found;
@@ -3943,7 +4252,7 @@ static int asm_label_instr(void)
return v;
}
-static void post_type(CType *type, AttributeDef *ad, int storage)
+static int post_type(CType *type, AttributeDef *ad, int storage, int td)
{
int n, l, t1, arg_size, align;
Sym **plast, *s, *first;
@@ -3951,25 +4260,25 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
CType pt;
if (tok == '(') {
- /* function declaration */
+ /* function type, or recursive declarator (return if so) */
next();
- l = 0;
+ if (td && !(td & TYPE_ABSTRACT))
+ return 0;
+ if (tok == ')')
+ l = 0;
+ else if (parse_btype(&pt, &ad1))
+ l = FUNC_NEW;
+ else if (td)
+ return 0;
+ else
+ l = FUNC_OLD;
first = NULL;
plast = &first;
arg_size = 0;
- if (tok != ')') {
+ if (l) {
for(;;) {
/* read param name and compute offset */
if (l != FUNC_OLD) {
- if (!parse_btype(&pt, &ad1)) {
- if (l) {
- tcc_error("invalid type");
- } else {
- l = FUNC_OLD;
- goto old_proto;
- }
- }
- l = FUNC_NEW;
if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')')
break;
type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT);
@@ -3977,11 +4286,10 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
tcc_error("parameter declared as void");
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
} else {
- old_proto:
n = tok;
if (n < TOK_UIDENT)
expect("identifier");
- pt.t = VT_INT;
+ pt.t = VT_VOID; /* invalid type */
next();
}
convert_parameter_type(&pt);
@@ -3996,10 +4304,11 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
next();
break;
}
+ if (l == FUNC_NEW && !parse_btype(&pt, &ad1))
+ tcc_error("invalid type");
}
- }
- /* if no parameters, then old type prototype */
- if (l == 0)
+ } else
+ /* if no parameters, then old type prototype */
l = FUNC_OLD;
skip(')');
/* NOTE: const is ignored in returned type as it has a special
@@ -4011,12 +4320,14 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
if (tok == '[') {
next();
skip(']'); /* only handle simple "[]" */
- type->t |= VT_PTR;
+ mk_pointer(type);
}
/* we push a anonymous symbol which will contain the function prototype */
- ad->a.func_args = arg_size;
- s = sym_push(SYM_FIELD, type, 0, l);
+ ad->f.func_args = arg_size;
+ ad->f.func_type = l;
+ s = sym_push(SYM_FIELD, type, 0, 0);
s->a = ad->a;
+ s->f = ad->f;
s->next = first;
type->t = VT_FUNC;
type->ref = s;
@@ -4051,7 +4362,7 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
}
skip(']');
/* parse next post type */
- post_type(type, ad, storage);
+ post_type(type, ad, storage, 0);
if (type->t == VT_FUNC)
tcc_error("declaration of an array of functions");
t1 |= type->t & VT_VLA;
@@ -4077,20 +4388,26 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR;
type->ref = s;
}
+ return 1;
}
-/* Parse a type declaration (except basic type), and return the type
+/* Parse a type declarator (except basic type), and return the type
in 'type'. 'td' is a bitmask indicating which kind of type decl is
expected. 'type' should contain the basic type. 'ad' is the
attribute definition of the basic type. It can be modified by
- type_decl().
- */
-static void type_decl(CType *type, AttributeDef *ad, int *v, int td)
+ type_decl(). If this (possibly abstract) declarator is a pointer chain
+ it returns the innermost pointed to type (equals *type, but is a different
+ pointer), otherwise returns type itself, that's used for recursive calls. */
+static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
{
- Sym *s;
- CType type1, *type2;
+ CType *post, *ret;
int qualifiers, storage;
+ /* recursive type, remove storage bits first, apply them later again */
+ storage = type->t & VT_STORAGE;
+ type->t &= ~VT_STORAGE;
+ post = ret = type;
+
while (tok == '*') {
qualifiers = 0;
redo:
@@ -4118,50 +4435,36 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td)
}
mk_pointer(type);
type->t |= qualifiers;
+ if (ret == type)
+ /* innermost pointed to type is the one for the first derivation */
+ ret = pointed_type(type);
}
-
- /* recursive type */
- /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
- type1.t = 0; /* XXX: same as int */
+
if (tok == '(') {
- next();
- /* XXX: this is not correct to modify 'ad' at this point, but
- the syntax is not clear */
- if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
- parse_attribute(ad);
- type_decl(&type1, ad, v, td);
- skip(')');
+ /* This is possibly a parameter type list for abstract declarators
+ ('int ()'), use post_type for testing this. */
+ if (!post_type(type, ad, 0, td)) {
+ /* It's not, so it's a nested declarator, and the post operations
+ apply to the innermost pointed to type (if any). */
+ /* XXX: this is not correct to modify 'ad' at this point, but
+ the syntax is not clear */
+ parse_attribute(ad);
+ post = type_decl(type, ad, v, td);
+ skip(')');
+ }
+ } else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
+ /* type identifier */
+ *v = tok;
+ next();
} else {
- /* type identifier */
- if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
- *v = tok;
- next();
- } else {
- if (!(td & TYPE_ABSTRACT))
- expect("identifier");
- *v = 0;
- }
+ if (!(td & TYPE_ABSTRACT))
+ expect("identifier");
+ *v = 0;
}
- storage = type->t & VT_STORAGE;
- type->t &= ~VT_STORAGE;
- post_type(type, ad, storage);
+ post_type(post, ad, storage, 0);
+ parse_attribute(ad);
type->t |= storage;
- if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
- parse_attribute(ad);
-
- if (!type1.t)
- return;
- /* append type at the end of type1 */
- type2 = &type1;
- for(;;) {
- s = type2->ref;
- type2 = &s->type;
- if (!type2->t) {
- *type2 = *type;
- break;
- }
- }
- *type = type1;
+ return ret;
}
/* compute the lvalue VT_LVAL_xxx needed to match type t. */
@@ -4189,7 +4492,7 @@ ST_FUNC void indir(void)
return;
expect("pointer");
}
- if ((vtop->r & VT_LVAL) && !nocode_wanted)
+ if (vtop->r & VT_LVAL)
gv(RC_INT);
vtop->type = *pointed_type(&vtop->type);
/* Arrays and functions are never lvalues */
@@ -4210,13 +4513,12 @@ static void gfunc_param_typed(Sym *func, Sym *arg)
int func_type;
CType type;
- func_type = func->c;
+ func_type = func->f.func_type;
if (func_type == FUNC_OLD ||
(func_type == FUNC_ELLIPSIS && arg == NULL)) {
/* default casting : only need to convert float to double */
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) {
- type.t = VT_DOUBLE;
- gen_cast(&type);
+ gen_cast_s(VT_DOUBLE);
} else if (vtop->type.t & VT_BITFIELD) {
type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
type.ref = vtop->type.ref;
@@ -4231,6 +4533,16 @@ static void gfunc_param_typed(Sym *func, Sym *arg)
}
}
+/* parse an expression and return its type without any side effect. */
+static void expr_type(CType *type, void (*expr_fn)(void))
+{
+ nocode_wanted++;
+ expr_fn();
+ *type = vtop->type;
+ vpop();
+ nocode_wanted--;
+}
+
/* parse an expression of the form '(type)' or '(expr)' and return its
type */
static void parse_expr_type(CType *type)
@@ -4242,7 +4554,7 @@ static void parse_expr_type(CType *type)
if (parse_btype(type, &ad)) {
type_decl(type, &ad, &n, TYPE_ABSTRACT);
} else {
- expr_type(type);
+ expr_type(type, gexpr);
}
skip(')');
}
@@ -4258,12 +4570,25 @@ static void parse_type(CType *type)
type_decl(type, &ad, &n, TYPE_ABSTRACT);
}
-static void vpush_tokc(int t)
+static void parse_builtin_params(int nc, const char *args)
{
- CType type;
- type.t = t;
- type.ref = 0;
- vsetc(&type, VT_CONST, &tokc);
+ char c, sep = '(';
+ CType t;
+ if (nc)
+ nocode_wanted++;
+ next();
+ while ((c = *args++)) {
+ skip(sep);
+ sep = ',';
+ switch (c) {
+ case 'e': expr_eq(); continue;
+ case 't': parse_type(&t); vpush(&t); continue;
+ default: tcc_error("internal error"); break;
+ }
+ }
+ skip(')');
+ if (nc)
+ nocode_wanted--;
}
ST_FUNC void unary(void)
@@ -4275,6 +4600,7 @@ ST_FUNC void unary(void)
sizeof_caller = in_sizeof;
in_sizeof = 0;
+ type.ref = NULL;
/* XXX: GCC 2.95.3 does not generate a table although it should be
better here */
tok_next:
@@ -4282,36 +4608,43 @@ ST_FUNC void unary(void)
case TOK_EXTENSION:
next();
goto tok_next;
+ case TOK_LCHAR:
+#ifdef TCC_TARGET_PE
+ t = VT_SHORT|VT_UNSIGNED;
+ goto push_tokc;
+#endif
case TOK_CINT:
case TOK_CCHAR:
- case TOK_LCHAR:
- vpushi(tokc.i);
+ t = VT_INT;
+ push_tokc:
+ type.t = t;
+ vsetc(&type, VT_CONST, &tokc);
next();
break;
case TOK_CUINT:
- vpush_tokc(VT_INT | VT_UNSIGNED);
- next();
- break;
+ t = VT_INT | VT_UNSIGNED;
+ goto push_tokc;
case TOK_CLLONG:
- vpush_tokc(VT_LLONG);
- next();
- break;
+ t = VT_LLONG;
+ goto push_tokc;
case TOK_CULLONG:
- vpush_tokc(VT_LLONG | VT_UNSIGNED);
- next();
- break;
+ t = VT_LLONG | VT_UNSIGNED;
+ goto push_tokc;
case TOK_CFLOAT:
- vpush_tokc(VT_FLOAT);
- next();
- break;
+ t = VT_FLOAT;
+ goto push_tokc;
case TOK_CDOUBLE:
- vpush_tokc(VT_DOUBLE);
- next();
- break;
+ t = VT_DOUBLE;
+ goto push_tokc;
case TOK_CLDOUBLE:
- vpush_tokc(VT_LDOUBLE);
- next();
- break;
+ t = VT_LDOUBLE;
+ goto push_tokc;
+ case TOK_CLONG:
+ t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG;
+ goto push_tokc;
+ case TOK_CULONG:
+ t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED;
+ goto push_tokc;
case TOK___FUNCTION__:
if (!gnu_ext)
goto tok_identifier;
@@ -4328,8 +4661,10 @@ ST_FUNC void unary(void)
type.t |= VT_ARRAY;
type.ref->c = len;
vpush_ref(&type, data_section, data_section->data_offset, len);
- ptr = section_ptr_add(data_section, len);
- memcpy(ptr, funcname, len);
+ if (!NODATA_WANTED) {
+ ptr = section_ptr_add(data_section, len);
+ memcpy(ptr, funcname, len);
+ }
next();
}
break;
@@ -4343,6 +4678,8 @@ ST_FUNC void unary(void)
case TOK_STR:
/* string parsing */
t = VT_BYTE;
+ if (tcc_state->char_is_unsigned)
+ t = VT_BYTE | VT_UNSIGNED;
str_init:
if (tcc_state->warn_write_strings)
t |= VT_CONSTANT;
@@ -4379,14 +4716,18 @@ ST_FUNC void unary(void)
gen_cast(&type);
}
} else if (tok == '{') {
+ int saved_nocode_wanted = nocode_wanted;
if (const_wanted)
tcc_error("expected constant");
/* save all registers */
- if (!nocode_wanted)
- save_regs(0);
+ save_regs(0);
/* statement expression : we do not accept break/continue
- inside as GCC does */
+ inside as GCC does. We do retain the nocode_wanted state,
+ 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);
+ nocode_wanted = saved_nocode_wanted;
skip(')');
} else {
gexpr();
@@ -4407,7 +4748,7 @@ ST_FUNC void unary(void)
there and in function calls. */
/* arrays can also be used although they are not lvalues */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
- !(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_LLOCAL))
+ !(vtop->type.t & VT_ARRAY))
test_lvalue();
mk_pointer(&vtop->type);
gaddrof();
@@ -4416,9 +4757,7 @@ ST_FUNC void unary(void)
next();
unary();
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- CType boolean;
- boolean.t = VT_BOOL;
- gen_cast(&boolean);
+ gen_cast_s(VT_BOOL);
vtop->c.i = !vtop->c.i;
} else if ((vtop->r & VT_VALMASK) == VT_CMP)
vtop->c.i ^= 1;
@@ -4452,8 +4791,11 @@ ST_FUNC void unary(void)
t = tok;
next();
in_sizeof++;
- unary_type(&type); // Perform a in_sizeof = 0;
+ expr_type(&type, unary); /* Perform a in_sizeof = 0; */
+ s = vtop[1].sym; /* hack: accessing previous vtop */
size = type_size(&type, &align);
+ if (s && s->a.aligned)
+ align = 1 << (s->a.aligned - 1);
if (t == TOK_SIZEOF) {
if (!(type.t & VT_VLA)) {
if (size < 0)
@@ -4469,86 +4811,56 @@ ST_FUNC void unary(void)
break;
case TOK_builtin_expect:
- {
- /* __builtin_expect is a no-op for now */
- int saved_nocode_wanted;
- next();
- skip('(');
- expr_eq();
- skip(',');
- saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
- expr_lor_const();
- vpop();
- nocode_wanted = saved_nocode_wanted;
- skip(')');
- }
+ /* __builtin_expect is a no-op for now */
+ parse_builtin_params(0, "ee");
+ vpop();
break;
case TOK_builtin_types_compatible_p:
- {
- CType type1, type2;
- next();
- skip('(');
- parse_type(&type1);
- skip(',');
- parse_type(&type2);
- skip(')');
- type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
- type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
- vpushi(is_compatible_types(&type1, &type2));
- }
+ parse_builtin_params(0, "tt");
+ vtop[-1].type.t &= ~(VT_CONSTANT | VT_VOLATILE);
+ vtop[0].type.t &= ~(VT_CONSTANT | VT_VOLATILE);
+ n = is_compatible_types(&vtop[-1].type, &vtop[0].type);
+ vtop -= 2;
+ vpushi(n);
break;
case TOK_builtin_choose_expr:
{
- int saved_nocode_wanted;
int64_t c;
next();
skip('(');
c = expr_const64();
skip(',');
if (!c) {
- saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
+ nocode_wanted++;
}
expr_eq();
if (!c) {
vpop();
- nocode_wanted = saved_nocode_wanted;
+ nocode_wanted--;
}
skip(',');
if (c) {
- saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
+ nocode_wanted++;
}
expr_eq();
if (c) {
vpop();
- nocode_wanted = saved_nocode_wanted;
+ nocode_wanted--;
}
skip(')');
}
break;
case TOK_builtin_constant_p:
- {
- int saved_nocode_wanted, res;
- next();
- skip('(');
- saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
- gexpr();
- res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
- vpop();
- nocode_wanted = saved_nocode_wanted;
- skip(')');
- vpushi(res);
- }
+ parse_builtin_params(1, "e");
+ n = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+ vtop--;
+ vpushi(n);
break;
case TOK_builtin_frame_address:
case TOK_builtin_return_address:
{
int tok1 = tok;
int level;
- CType type;
next();
skip('(');
if (tok != TOK_CINT) {
@@ -4579,45 +4891,30 @@ ST_FUNC void unary(void)
#ifdef TCC_TARGET_X86_64
#ifdef TCC_TARGET_PE
case TOK_builtin_va_start:
- {
- next();
- skip('(');
- expr_eq();
- skip(',');
- expr_eq();
- skip(')');
- if ((vtop->r & VT_VALMASK) != VT_LOCAL)
- tcc_error("__builtin_va_start expects a local variable");
- vtop->r &= ~(VT_LVAL | VT_REF);
- vtop->type = char_pointer_type;
- vtop->c.i += 8;
- vstore();
- }
+ 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");
+ vtop->r = r;
+ vtop->type = char_pointer_type;
+ vtop->c.i += 8;
+ vstore();
break;
#else
case TOK_builtin_va_arg_types:
- {
- CType type;
- next();
- skip('(');
- parse_type(&type);
- skip(')');
- vpushi(classify_x86_64_va_arg(&type));
- }
+ parse_builtin_params(0, "t");
+ vpushi(classify_x86_64_va_arg(&vtop->type));
+ vswap();
+ vpop();
break;
#endif
#endif
#ifdef TCC_TARGET_ARM64
case TOK___va_start: {
- if (nocode_wanted)
- tcc_error("statement in global scope");
- next();
- skip('(');
- expr_eq();
- skip(',');
- expr_eq();
- skip(')');
+ parse_builtin_params(0, "ee");
//xx check types
gen_va_start();
vpushi(0);
@@ -4625,27 +4922,16 @@ ST_FUNC void unary(void)
break;
}
case TOK___va_arg: {
- CType type;
- if (nocode_wanted)
- tcc_error("statement in global scope");
- next();
- skip('(');
- expr_eq();
- skip(',');
- parse_type(&type);
- skip(')');
+ parse_builtin_params(0, "et");
+ type = vtop->type;
+ vpop();
//xx check types
gen_va_arg(&type);
vtop->type = type;
break;
}
case TOK___arm64_clear_cache: {
- next();
- skip('(');
- expr_eq();
- skip(',');
- expr_eq();
- skip(')');
+ parse_builtin_params(0, "ee");
gen_clear_cache();
vpushi(0);
vtop->type.t = VT_VOID;
@@ -4669,11 +4955,11 @@ ST_FUNC void unary(void)
subtract(-0, x). */
vpush(&vtop->type);
if (t == VT_FLOAT)
- vtop->c.f = -0.0f;
+ vtop->c.f = -1.0 * 0.0;
else if (t == VT_DOUBLE)
- vtop->c.d = -0.0;
+ vtop->c.d = -1.0 * 0.0;
else
- vtop->c.ld = -0.0;
+ vtop->c.ld = -1.0 * 0.0;
} else
vpushi(0);
vswap();
@@ -4701,7 +4987,68 @@ ST_FUNC void unary(void)
vpushsym(&s->type, s);
next();
break;
-
+
+ case TOK_GENERIC:
+ {
+ CType controlling_type;
+ int has_default = 0;
+ int has_match = 0;
+ int learn = 0;
+ TokenString *str = NULL;
+
+ next();
+ skip('(');
+ expr_type(&controlling_type, expr_eq);
+ controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY);
+ for (;;) {
+ learn = 0;
+ skip(',');
+ if (tok == TOK_DEFAULT) {
+ if (has_default)
+ tcc_error("too many 'default'");
+ has_default = 1;
+ if (!has_match)
+ learn = 1;
+ next();
+ } else {
+ AttributeDef ad_tmp;
+ int itmp;
+ CType cur_type;
+ parse_btype(&cur_type, &ad_tmp);
+ type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
+ if (compare_types(&controlling_type, &cur_type, 0)) {
+ if (has_match) {
+ tcc_error("type match twice");
+ }
+ has_match = 1;
+ learn = 1;
+ }
+ }
+ skip(':');
+ if (learn) {
+ if (str)
+ tok_str_free(str);
+ skip_or_save_block(&str);
+ } else {
+ skip_or_save_block(NULL);
+ }
+ if (tok == ')')
+ break;
+ }
+ if (!str) {
+ char buf[60];
+ type_to_str(buf, sizeof buf, &controlling_type, NULL);
+ tcc_error("type '%s' does not match any association", buf);
+ }
+ begin_macro(str, 1);
+ next();
+ expr_eq();
+ if (tok != TOK_EOF)
+ expect(",");
+ end_macro();
+ next();
+ break;
+ }
// special qnan , snan and infinity values
case TOK___NAN__:
vpush64(VT_DOUBLE, 0x7ff8000000000000ULL);
@@ -4723,7 +5070,7 @@ ST_FUNC void unary(void)
if (t < TOK_UIDENT)
expect("identifier");
s = sym_find(t);
- if (!s) {
+ if (!s || IS_ASM_SYM(s)) {
const char *name = get_tok_str(t, NULL);
if (tok != '(')
tcc_error("'%s' undeclared", name);
@@ -4739,30 +5086,23 @@ ST_FUNC void unary(void)
tcc_warning("implicit declaration of function '%s'", name);
s = external_global_sym(t, &func_old_type, 0);
}
- if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) ==
- (VT_STATIC | VT_INLINE | VT_FUNC)) {
- /* if referencing an inline function, then we generate a
- symbol to it if not already done. It will have the
- effect to generate code for it at the end of the
- compilation unit. Inline function as always
- generated in the text section. */
- if (!s->c && !nocode_wanted)
- put_extern_sym(s, text_section, 0, 0);
- r = VT_SYM | VT_CONST;
- } else {
- r = s->r;
- /* A symbol that has a register is a local register variable,
- which starts out as VT_LOCAL value. */
- if ((r & VT_VALMASK) < VT_CONST)
- r = (r & ~VT_VALMASK) | VT_LOCAL;
- }
+
+ r = s->r;
+ /* A symbol that has a register is a local register variable,
+ which starts out as VT_LOCAL value. */
+ if ((r & VT_VALMASK) < VT_CONST)
+ r = (r & ~VT_VALMASK) | VT_LOCAL;
+
vset(&s->type, r, s->c);
/* Point to s as backpointer (even without r&VT_SYM).
Will be used by at least the x86 inline asm parser for
regvars. */
vtop->sym = s;
- if (vtop->r & VT_SYM) {
+
+ if (r & VT_SYM) {
vtop->c.i = 0;
+ } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) {
+ vtop->c.i = s->enum_val;
}
break;
}
@@ -4837,11 +5177,11 @@ ST_FUNC void unary(void)
s = vtop->type.ref;
next();
sa = s->next; /* first parameter */
- nb_args = 0;
+ nb_args = regsize = 0;
ret.r2 = VT_CONST;
/* compute first implicit argument if a structure is returned */
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
- variadic = (s->c == FUNC_ELLIPSIS);
+ variadic = (s->f.func_type == FUNC_ELLIPSIS);
ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
&ret_align, &regsize);
if (!ret_nregs) {
@@ -4906,11 +5246,7 @@ ST_FUNC void unary(void)
if (sa)
tcc_error("too few arguments to function");
skip(')');
- if (!nocode_wanted) {
- gfunc_call(nb_args);
- } else {
- vtop -= (nb_args + 1);
- }
+ gfunc_call(nb_args);
/* return value */
for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) {
@@ -5043,26 +5379,6 @@ static void expr_or(void)
}
}
-/* XXX: fix this mess */
-static void expr_land_const(void)
-{
- expr_or();
- while (tok == TOK_LAND) {
- next();
- expr_or();
- gen_op(TOK_LAND);
- }
-}
-static void expr_lor_const(void)
-{
- expr_land_const();
- while (tok == TOK_LOR) {
- next();
- expr_land_const();
- gen_op(TOK_LOR);
- }
-}
-
static void expr_land(void)
{
expr_or();
@@ -5070,23 +5386,20 @@ static void expr_land(void)
int t = 0;
for(;;) {
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- CType ctb;
- ctb.t = VT_BOOL;
- gen_cast(&ctb);
+ gen_cast_s(VT_BOOL);
if (vtop->c.i) {
vpop();
} else {
- int saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
+ nocode_wanted++;
while (tok == TOK_LAND) {
next();
expr_or();
vpop();
}
+ nocode_wanted--;
if (t)
gsym(t);
- nocode_wanted = saved_nocode_wanted;
- gen_cast(&int_type);
+ gen_cast_s(VT_INT);
break;
}
} else {
@@ -5114,23 +5427,20 @@ static void expr_lor(void)
int t = 0;
for(;;) {
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
- CType ctb;
- ctb.t = VT_BOOL;
- gen_cast(&ctb);
+ gen_cast_s(VT_BOOL);
if (!vtop->c.i) {
vpop();
} else {
- int saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
+ nocode_wanted++;
while (tok == TOK_LOR) {
next();
expr_land();
vpop();
}
+ nocode_wanted--;
if (t)
gsym(t);
- nocode_wanted = saved_nocode_wanted;
- gen_cast(&int_type);
+ gen_cast_s(VT_INT);
break;
}
} else {
@@ -5158,12 +5468,9 @@ static int condition_3way(void)
{
int c = -1;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST &&
- (!(vtop->r & VT_SYM) ||
- !(vtop->sym->type.t & VT_WEAK))) {
- CType boolean;
- boolean.t = VT_BOOL;
+ (!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) {
vdup();
- gen_cast(&boolean);
+ gen_cast_s(VT_BOOL);
c = vtop->c.i;
vpop();
}
@@ -5172,8 +5479,7 @@ static int condition_3way(void)
static void expr_cond(void)
{
- int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv;
- int c;
+ int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g;
SValue sv;
CType type, type1, type2;
@@ -5181,81 +5487,67 @@ static void expr_cond(void)
if (tok == '?') {
next();
c = condition_3way();
- if (c >= 0) {
- int saved_nocode_wanted = nocode_wanted;
- if (c) {
- if (tok != ':' || !gnu_ext) {
- vpop();
- gexpr();
- }
- skip(':');
- nocode_wanted = 1;
- expr_cond();
- vpop();
- nocode_wanted = saved_nocode_wanted;
- } else {
- vpop();
- if (tok != ':' || !gnu_ext) {
- nocode_wanted = 1;
- gexpr();
- vpop();
- nocode_wanted = saved_nocode_wanted;
- }
- skip(':');
- expr_cond();
- }
- }
- else {
- /* XXX This doesn't handle nocode_wanted correctly at all.
- It unconditionally calls gv/gvtst and friends. That's
- the case for many of the expr_ routines. Currently
- that should generate only useless code, but depending
- on other operand handling this might also generate
- pointer derefs for lvalue conversions whose result
- is useless, but nevertheless can lead to segfault.
-
- Somewhen we need to overhaul the whole nocode_wanted
- handling. */
- if (vtop != vstack) {
- /* needed to avoid having different registers saved in
- each branch */
- if (is_float(vtop->type.t)) {
- rc = RC_FLOAT;
+ g = (tok == ':' && gnu_ext);
+ 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
+ if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+ rc = RC_ST0;
}
- else
- rc = RC_INT;
- gv(rc);
- save_regs(1);
- }
- if (tok == ':' && gnu_ext) {
+#endif
+ } else
+ rc = RC_INT;
+ gv(rc);
+ save_regs(1);
+ if (g)
gv_dup();
- tt = gvtst(1, 0);
- } else {
- tt = gvtst(1, 0);
+ tt = gvtst(1, 0);
+
+ } else {
+ if (!g)
+ vpop();
+ tt = 0;
+ }
+
+ if (1) {
+ 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(':');
- u = gjmp(0);
+
+ u = 0;
+ if (c < 0)
+ u = gjmp(0);
gsym(tt);
+
+ if (c == 0)
+ nocode_wanted--;
+ if (c == 1)
+ nocode_wanted++;
expr_cond();
- type2 = vtop->type;
+ 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 {
@@ -5263,10 +5555,14 @@ static void expr_cond(void)
}
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
/* cast to biggest op */
- type.t = VT_LLONG;
+ 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_LLONG | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
+ 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
@@ -5290,24 +5586,27 @@ static void expr_cond(void)
type.t = VT_VOID;
} else {
/* integer operations */
- type.t = VT_INT;
+ 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_INT | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
+ 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;
}
/* 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;
/* now we convert second operand */
- gen_cast(&type);
- if (islv) {
- mk_pointer(&vtop->type);
- gaddrof();
+ if (c != 1) {
+ gen_cast(&type);
+ if (islv) {
+ mk_pointer(&vtop->type);
+ gaddrof();
+ } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
+ gaddrof();
}
- else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
- gaddrof();
+
rc = RC_INT;
if (is_float(type.t)) {
rc = RC_FLOAT;
@@ -5319,29 +5618,36 @@ static void expr_cond(void)
} 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_IRET;
}
-
- r2 = gv(rc);
+
+ tt = r2 = 0;
+ if (c < 0) {
+ r2 = gv(rc);
+ tt = gjmp(0);
+ }
+ gsym(u);
+
/* this is horrible, but we must also convert first
operand */
- tt = gjmp(0);
- gsym(u);
- /* put again first value and cast it */
- *vtop = sv;
- gen_cast(&type);
- if (islv) {
- mk_pointer(&vtop->type);
- gaddrof();
+ 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();
}
- else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
- gaddrof();
- r1 = gv(rc);
- move_reg(r2, r1, type.t);
- vtop->r = r2;
- gsym(tt);
- if (islv)
- indir();
}
}
}
@@ -5380,41 +5686,14 @@ ST_FUNC void gexpr(void)
}
}
-/* parse an expression and return its type without any side effect. */
-static void expr_type(CType *type)
-{
- int saved_nocode_wanted;
-
- saved_nocode_wanted = nocode_wanted;
- nocode_wanted = 1;
- gexpr();
- *type = vtop->type;
- vpop();
- nocode_wanted = saved_nocode_wanted;
-}
-
-/* parse a unary expression and return its type without any side
- effect. */
-static void unary_type(CType *type)
-{
- int a;
-
- a = nocode_wanted;
- nocode_wanted = 1;
- unary();
- *type = vtop->type;
- vpop();
- nocode_wanted = a;
-}
-
/* parse a constant expression and return value in vtop. */
static void expr_const1(void)
{
- int a;
- a = const_wanted;
- const_wanted = 1;
+ const_wanted++;
+ nocode_wanted++;
expr_cond();
- const_wanted = a;
+ nocode_wanted--;
+ const_wanted--;
}
/* parse an integer constant and return its value. */
@@ -5454,7 +5733,6 @@ static int is_label(void)
last_tok = tok;
next();
if (tok == ':') {
- next();
return last_tok;
} else {
unget_tok(last_tok);
@@ -5462,24 +5740,71 @@ static int is_label(void)
}
}
-static void label_or_decl(int l)
-{
- int last_tok;
+#ifndef TCC_TARGET_ARM64
+static void gfunc_return(CType *func_type)
+{
+ if ((func_type->t & VT_BTYPE) == VT_STRUCT) {
+ CType type, ret_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 returning structure, must copy it to implicit
+ first pointer arg location */
+ type = *func_type;
+ mk_pointer(&type);
+ vset(&type, VT_LOCAL | VT_LVAL, func_vc);
+ indir();
+ vswap();
+ /* copy structure value to pointer */
+ vstore();
+ } else {
+ /* returning structure packed into registers */
+ int r, size, addr, align;
+ size = type_size(func_type,&align);
+ if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
+ (vtop->c.i & (ret_align-1)))
+ && (align & (ret_align-1))) {
+ loc = (loc - size) & -ret_align;
+ addr = loc;
+ type = *func_type;
+ vset(&type, VT_LOCAL | VT_LVAL, addr);
+ vswap();
+ vstore();
+ vpop();
+ 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;
- /* fast test first */
- if (tok >= TOK_UIDENT)
- {
- /* no need to save tokc because tok is an identifier */
- last_tok = tok;
- next();
- if (tok == ':') {
- unget_tok(last_tok);
- return;
- }
- unget_tok(last_tok);
- }
- decl(l);
+ if (ret_nregs == 1)
+ gv(r);
+ else {
+ for (;;) {
+ vdup();
+ gv(r);
+ 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;
+ vtop->c.i += regsize;
+ }
+ }
+ }
+ } else if (is_float(func_type->t)) {
+ gv(rc_fret(func_type->t));
+ } else {
+ gv(RC_IRET);
+ }
+ vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
}
+#endif
static int case_cmp(const void *pa, const void *pb)
{
@@ -5554,12 +5879,8 @@ static void block(int *bsym, int *csym, int is_expr)
Sym *s;
/* generate line number info */
- if (tcc_state->do_debug &&
- (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 (tcc_state->do_debug)
+ tcc_debug_line(tcc_state);
if (is_expr) {
/* default return value is (void) */
@@ -5575,19 +5896,22 @@ static void block(int *bsym, int *csym, int is_expr)
gexpr();
skip(')');
cond = condition_3way();
- if (cond == 0)
- nocode_wanted |= 2;
- a = gvtst(1, 0);
+ 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();
- if (cond == 1)
- nocode_wanted |= 2;
d = gjmp(0);
gsym(a);
+ if (cond == 1)
+ nocode_wanted |= 0x20000000;
block(bsym, csym, 0);
gsym(d); /* patch else jmp */
if (cond != 0)
@@ -5596,7 +5920,7 @@ static void block(int *bsym, int *csym, int is_expr)
gsym(a);
} else if (tok == TOK_WHILE) {
int saved_nocode_wanted;
- nocode_wanted &= ~2;
+ nocode_wanted &= ~0x20000000;
next();
d = ind;
vla_sp_restore();
@@ -5610,8 +5934,7 @@ static void block(int *bsym, int *csym, int is_expr)
block(&a, &b, 0);
nocode_wanted = saved_nocode_wanted;
--local_scope;
- if(!nocode_wanted)
- gjmp_addr(d);
+ gjmp_addr(d);
gsym(a);
gsym_addr(b, d);
} else if (tok == '{') {
@@ -5641,7 +5964,10 @@ static void block(int *bsym, int *csym, int is_expr)
}
}
while (tok != '}') {
- label_or_decl(VT_LOCAL);
+ if ((a = is_label()))
+ unget_tok(a);
+ else
+ decl(VT_LOCAL);
if (tok != '}') {
if (is_expr)
vpop();
@@ -5649,7 +5975,7 @@ static void block(int *bsym, int *csym, int is_expr)
}
}
/* pop locally defined labels */
- label_pop(&local_label_stack, llabel);
+ 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),
@@ -5674,77 +6000,16 @@ static void block(int *bsym, int *csym, int is_expr)
if (tok != ';') {
gexpr();
gen_assign_cast(&func_vt);
-#ifdef TCC_TARGET_ARM64
- // Perhaps it would be better to use this for all backends:
- greturn();
-#else
- if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
- CType type, ret_type;
- int ret_align, ret_nregs, regsize;
- ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
- &ret_align, &regsize);
- if (0 == ret_nregs) {
- /* if returning structure, must copy it to implicit
- first pointer arg location */
- type = func_vt;
- mk_pointer(&type);
- vset(&type, VT_LOCAL | VT_LVAL, func_vc);
- indir();
- vswap();
- /* copy structure value to pointer */
- vstore();
- } else {
- /* returning structure packed into registers */
- int r, size, addr, align;
- size = type_size(&func_vt,&align);
- if ((vtop->r != (VT_LOCAL | VT_LVAL) ||
- (vtop->c.i & (ret_align-1)))
- && (align & (ret_align-1))) {
- loc = (loc - size) & -ret_align;
- addr = loc;
- type = func_vt;
- vset(&type, VT_LOCAL | VT_LVAL, addr);
- vswap();
- vstore();
- vpop();
- 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;
-
- if (ret_nregs == 1)
- gv(r);
- else {
- for (;;) {
- vdup();
- gv(r);
- 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;
- vtop->c.i += regsize;
- }
- }
- }
- } else if (is_float(func_vt.t)) {
- gv(rc_fret(func_vt.t));
- } else {
- gv(RC_IRET);
- }
-#endif
- vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
+ if ((func_vt.t & VT_BTYPE) == VT_VOID)
+ vtop--;
+ else
+ gfunc_return(&func_vt);
}
skip(';');
/* jump unless last stmt in top-level block */
if (tok != '}' || local_scope != 1)
rsym = gjmp(rsym);
- nocode_wanted |= 2;
+ nocode_wanted |= 0x20000000;
} else if (tok == TOK_BREAK) {
/* compute jump */
if (!bsym)
@@ -5752,7 +6017,7 @@ static void block(int *bsym, int *csym, int is_expr)
*bsym = gjmp(*bsym);
next();
skip(';');
- nocode_wanted |= 2;
+ nocode_wanted |= 0x20000000;
} else if (tok == TOK_CONTINUE) {
/* compute jump */
if (!csym)
@@ -5764,14 +6029,14 @@ static void block(int *bsym, int *csym, int is_expr)
} else if (tok == TOK_FOR) {
int e;
int saved_nocode_wanted;
- nocode_wanted &= ~2;
+ nocode_wanted &= ~0x20000000;
next();
skip('(');
s = local_stack;
++local_scope;
if (tok != ';') {
/* c99 for-loop init decl? */
- if (!decl0(VT_LOCAL, 1)) {
+ if (!decl0(VT_LOCAL, 1, NULL)) {
/* no, regular for-loop init expr */
gexpr();
vpop();
@@ -5801,8 +6066,7 @@ static void block(int *bsym, int *csym, int is_expr)
saved_nocode_wanted = nocode_wanted;
block(&a, &b, 0);
nocode_wanted = saved_nocode_wanted;
- if(!nocode_wanted)
- gjmp_addr(c);
+ gjmp_addr(c);
gsym(a);
gsym_addr(b, c);
--local_scope;
@@ -5811,7 +6075,7 @@ static void block(int *bsym, int *csym, int is_expr)
} else
if (tok == TOK_DO) {
int saved_nocode_wanted;
- nocode_wanted &= ~2;
+ nocode_wanted &= ~0x20000000;
next();
a = 0;
b = 0;
@@ -5823,11 +6087,8 @@ static void block(int *bsym, int *csym, int is_expr)
skip('(');
gsym(b);
gexpr();
- if (!nocode_wanted) {
- c = gvtst(0, 0);
- gsym_addr(c, d);
- } else
- vtop--;
+ c = gvtst(0, 0);
+ gsym_addr(c, d);
nocode_wanted = saved_nocode_wanted;
skip(')');
gsym(a);
@@ -5852,21 +6113,19 @@ static void block(int *bsym, int *csym, int is_expr)
a = gjmp(a); /* add implicit break */
/* case lookup */
gsym(b);
- if (!nocode_wanted) {
- 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);
- vpop();
- if (sw.def_sym)
- gjmp_addr(sw.def_sym);
- }
+ 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);
+ vpop();
+ if (sw.def_sym)
+ gjmp_addr(sw.def_sym);
dynarray_reset(&sw.p, &sw.n);
cur_switch = saved;
/* break label */
@@ -5876,7 +6135,7 @@ static void block(int *bsym, int *csym, int is_expr)
struct case_t *cr = tcc_malloc(sizeof(struct case_t));
if (!cur_switch)
expect("switch");
- nocode_wanted &= ~2;
+ nocode_wanted &= ~0x20000000;
next();
cr->v1 = cr->v2 = expr_const64();
if (gnu_ext && tok == TOK_DOTS) {
@@ -5886,7 +6145,7 @@ static void block(int *bsym, int *csym, int is_expr)
tcc_warning("empty case range");
}
cr->sym = ind;
- dynarray_add((void***) &cur_switch->p, &cur_switch->n, cr);
+ dynarray_add(&cur_switch->p, &cur_switch->n, cr);
skip(':');
is_expr = 0;
goto block_after_label;
@@ -5910,10 +6169,7 @@ static void block(int *bsym, int *csym, int is_expr)
gexpr();
if ((vtop->type.t & VT_BTYPE) != VT_PTR)
expect("pointer");
- if (!nocode_wanted)
- ggoto();
- else
- vtop--;
+ ggoto();
} else if (tok >= TOK_UIDENT) {
s = label_find(tok);
/* put forward definition if needed */
@@ -5924,9 +6180,7 @@ static void block(int *bsym, int *csym, int is_expr)
s->r = LABEL_FORWARD;
}
vla_sp_restore_root();
- if (nocode_wanted)
- ;
- else if (s->r & LABEL_FORWARD)
+ if (s->r & LABEL_FORWARD)
s->jnext = gjmp(s->jnext);
else
gjmp_addr(s->jnext);
@@ -5941,6 +6195,7 @@ static void block(int *bsym, int *csym, int is_expr)
b = is_label();
if (b) {
/* label case */
+ next();
s = label_find(b);
if (s) {
if (s->r == LABEL_DEFINED)
@@ -5954,7 +6209,7 @@ static void block(int *bsym, int *csym, int is_expr)
vla_sp_restore();
/* we accept this, but it is a mistake */
block_after_label:
- nocode_wanted &= ~2;
+ nocode_wanted &= ~0x20000000;
if (tok == '}') {
tcc_warning("deprecated use of label at end of compound statement");
} else {
@@ -5978,6 +6233,44 @@ static void block(int *bsym, int *csym, int is_expr)
}
}
+/* This skips over a stream of tokens containing balanced {} and ()
+ pairs, stopping at outer ',' ';' and '}' (or matching '}' if we started
+ with a '{'). If STR then allocates and stores the skipped tokens
+ in *STR. This doesn't check if () and {} are nested correctly,
+ i.e. "({)}" is accepted. */
+static void skip_or_save_block(TokenString **str)
+{
+ int braces = tok == '{';
+ int level = 0;
+ if (str)
+ *str = tok_str_alloc();
+
+ while ((level > 0 || (tok != '}' && tok != ',' && tok != ';' && tok != ')'))) {
+ int t;
+ if (tok == TOK_EOF) {
+ if (str || level > 0)
+ tcc_error("unexpected end of file");
+ else
+ break;
+ }
+ if (str)
+ tok_str_add_tok(*str);
+ t = tok;
+ next();
+ if (t == '{' || t == '(') {
+ level++;
+ } else if (t == '}' || t == ')') {
+ level--;
+ if (level == 0 && braces && t == '}')
+ break;
+ }
+ }
+ if (str) {
+ tok_str_add(*str, -1);
+ tok_str_add(*str, 0);
+ }
+}
+
#define EXPR_CONST 1
#define EXPR_ANY 2
@@ -5991,8 +6284,15 @@ static void parse_init_elem(int expr_type)
global_expr = 1;
expr_const1();
global_expr = saved_global_expr;
- /* NOTE: symbols are accepted */
- if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
+ /* 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))
+#ifdef TCC_TARGET_PE
+ || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport)
+#endif
+ )
tcc_error("initializer element is not constant");
break;
case EXPR_ANY:
@@ -6001,83 +6301,86 @@ static void parse_init_elem(int expr_type)
}
}
+/* put zeros for variable based init */
+static void init_putz(Section *sec, unsigned long c, int size)
+{
+ if (sec) {
+ /* nothing to do because globals are already set to zero */
+ } else {
+ vpush_global_sym(&func_old_type, TOK_memset);
+ vseti(VT_LOCAL, c);
+#ifdef TCC_TARGET_ARM
+ vpushs(size);
+ vpushi(0);
+#else
+ vpushi(0);
+ vpushs(size);
+#endif
+ gfunc_call(3);
+ }
+}
+
/* t is the array or struct type. c is the array or struct
address. cur_field is the pointer to the current
- value, for arrays the 'c' member contains the current start
- index and the 'r' contains the end index (in case of range init).
- 'size_only' is true if only size info is needed (only used
- in arrays) */
-static void decl_designator(CType *type, Section *sec, unsigned long c,
- Sym **cur_field, int size_only)
+ 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
+ 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 *s, *f;
- int notfirst, index, index_last, align, l, nb_elems, elem_size;
- CType type1;
+ int index, index_last, align, l, nb_elems, elem_size;
+ unsigned long corig = c;
- notfirst = 0;
elem_size = 0;
nb_elems = 1;
if (gnu_ext && (l = is_label()) != 0)
goto struct_field;
- while (tok == '[' || tok == '.') {
+ /* NOTE: we only support ranges for last designator */
+ while (nb_elems == 1 && (tok == '[' || tok == '.')) {
if (tok == '[') {
if (!(type->t & VT_ARRAY))
expect("array type");
- s = type->ref;
next();
- index = expr_const();
- if (index < 0 || (s->c >= 0 && index >= s->c))
- tcc_error("invalid index");
+ index = index_last = expr_const();
if (tok == TOK_DOTS && gnu_ext) {
next();
index_last = expr_const();
- if (index_last < 0 ||
- (s->c >= 0 && index_last >= s->c) ||
- index_last < index)
- tcc_error("invalid index");
- } else {
- index_last = index;
}
skip(']');
- if (!notfirst) {
- (*cur_field)->c = index;
- (*cur_field)->r = index_last;
- }
+ s = type->ref;
+ if (index < 0 || (s->c >= 0 && index_last >= s->c) ||
+ index_last < index)
+ tcc_error("invalid index");
+ if (cur_field)
+ (*cur_field)->c = index_last;
type = pointed_type(type);
elem_size = type_size(type, &align);
c += index * elem_size;
- /* NOTE: we only support ranges for last designator */
nb_elems = index_last - index + 1;
- if (nb_elems != 1) {
- notfirst = 1;
- break;
- }
} else {
next();
l = tok;
- next();
struct_field:
+ next();
if ((type->t & VT_BTYPE) != VT_STRUCT)
expect("struct/union type");
f = find_field(type, l);
if (!f)
expect("field");
- if (!notfirst)
+ if (cur_field)
*cur_field = f;
- /* XXX: fix this mess by using explicit storage field */
- type1 = f->type;
- type1.t |= (type->t & ~VT_TYPE);
- type = &type1;
+ type = &f->type;
c += f->c;
}
- notfirst = 1;
+ cur_field = NULL;
}
- if (notfirst) {
+ if (!cur_field) {
if (tok == '=') {
next();
- } else {
- if (!gnu_ext)
- expect("=");
+ } else if (!gnu_ext) {
+ expect("=");
}
} else {
if (type->t & VT_ARRAY) {
@@ -6088,15 +6391,18 @@ static void decl_designator(CType *type, Section *sec, unsigned long c,
c += index * type_size(type, &align);
} else {
f = *cur_field;
+ while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD))
+ *cur_field = f = f->next;
if (!f)
tcc_error("too many field init");
- /* XXX: fix this mess by using explicit storage field */
- type1 = f->type;
- type1.t |= (type->t & ~VT_TYPE);
- type = &type1;
+ type = &f->type;
c += f->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)
+ init_putz(sec, corig + al, c - corig - al);
decl_initializer(type, sec, c, 0, size_only);
/* XXX: make it more general */
@@ -6113,7 +6419,7 @@ static void decl_designator(CType *type, Section *sec, unsigned long c,
vstore();
}
vpop();
- } else {
+ } else if (!NODATA_WANTED) {
c_end = c + nb_elems * elem_size;
if (c_end > sec->data_allocated)
section_realloc(sec, c_end);
@@ -6125,14 +6431,17 @@ static void decl_designator(CType *type, Section *sec, unsigned long c,
}
}
}
+ c += nb_elems * type_size(type, &align);
+ if (c - corig > al)
+ al = c - corig;
+ return al;
}
/* store a value or an expression directly in global data or in local array */
static void init_putv(CType *type, Section *sec, unsigned long c)
{
- int bt, bit_pos, bit_size;
+ int bt;
void *ptr;
- unsigned long long bit_mask;
CType dtype;
dtype = *type;
@@ -6144,24 +6453,29 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
/* XXX: generate error if incorrect relocation */
gen_assign_cast(&dtype);
bt = type->t & VT_BTYPE;
- size = type_size(type, &align);
- if (c + size > sec->data_allocated) {
- section_realloc(sec, c + size);
+
+ if ((vtop->r & VT_SYM)
+ && bt != VT_PTR
+ && bt != VT_FUNC
+ && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT)
+ || (type->t & VT_BITFIELD))
+ && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM)
+ )
+ tcc_error("initializer element is not computable at load time");
+
+ if (NODATA_WANTED) {
+ vtop--;
+ return;
}
+
+ size = type_size(type, &align);
+ section_reserve(sec, c + size);
ptr = sec->data + c;
+
/* XXX: make code faster ? */
- if (!(type->t & VT_BITFIELD)) {
- bit_pos = 0;
- bit_size = PTR_SIZE * 8;
- bit_mask = -1LL;
- } else {
- bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
- bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
- bit_mask = (1LL << bit_size) - 1;
- }
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
vtop->sym->v >= SYM_FIRST_ANOM &&
- /* XXX This rejects compount literals like
+ /* XXX This rejects compound literals like
'(void *){ptr}'. The problem is that '&sym' is
represented the same way, which would be ruled out
by the SYM_FIRST_ANOM check above, but also '"string"'
@@ -6174,9 +6488,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
(vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */
Section *ssec;
- ElfW(Sym) *esym;
+ ElfSym *esym;
ElfW_Rel *rel;
- esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c];
+ esym = elfsym(vtop->sym);
ssec = tcc_state->sections[esym->st_shndx];
memmove (ptr, ssec->data + esym->st_value, size);
if (ssec->reloc) {
@@ -6202,7 +6516,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
c + rel->r_offset - esym->st_value,
ELFW(R_TYPE)(rel->r_info),
ELFW(R_SYM)(rel->r_info),
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+#if PTR_SIZE == 8
rel->r_addend
#else
0
@@ -6211,54 +6525,71 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
}
}
} else {
- if ((vtop->r & VT_SYM) &&
- (bt == VT_BYTE ||
- bt == VT_SHORT ||
- bt == VT_DOUBLE ||
- bt == VT_LDOUBLE ||
-#if PTR_SIZE == 8
- (bt == VT_LLONG && bit_size != 64) ||
- bt == VT_INT
-#else
- bt == VT_LLONG ||
- (bt == VT_INT && bit_size != 32)
-#endif
- ))
- tcc_error("initializer element is not computable at load time");
- switch(bt) {
+ if (type->t & VT_BITFIELD) {
+ int bit_pos, bit_size, bits, n;
+ unsigned char *p, v, m;
+ bit_pos = BIT_POS(vtop->type.t);
+ bit_size = BIT_SIZE(vtop->type.t);
+ p = (unsigned char*)ptr + (bit_pos >> 3);
+ bit_pos &= 7, bits = 0;
+ while (bit_size) {
+ n = 8 - bit_pos;
+ if (n > bit_size)
+ n = bit_size;
+ v = vtop->c.i >> bits << bit_pos;
+ m = ((1 << n) - 1) << bit_pos;
+ *p = (*p & ~m) | (v & m);
+ bits += n, bit_size -= n, bit_pos = 0, ++p;
+ }
+ } else
+ switch(bt) {
/* XXX: when cross-compiling we assume that each type has the
same representation on host and target, which is likely to
be wrong in the case of long double */
case VT_BOOL:
- vtop->c.i = (vtop->c.i != 0);
+ vtop->c.i = vtop->c.i != 0;
case VT_BYTE:
- *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+ *(char *)ptr |= vtop->c.i;
break;
case VT_SHORT:
- *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+ *(short *)ptr |= vtop->c.i;
+ break;
+ case VT_FLOAT:
+ *(float*)ptr = vtop->c.f;
break;
case VT_DOUBLE:
*(double *)ptr = vtop->c.d;
break;
case VT_LDOUBLE:
+#if defined TCC_IS_NATIVE_387
+ if (sizeof (long double) >= 10) /* zero pad ten-byte LD */
+ memcpy(ptr, &vtop->c.ld, 10);
+#ifdef __TINYC__
+ else if (sizeof (long double) == sizeof (double))
+ __asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld));
+#endif
+ else if (vtop->c.ld == 0.0)
+ ;
+ else
+#endif
if (sizeof(long double) == LDOUBLE_SIZE)
- *(long double *)ptr = vtop->c.ld;
- else if (sizeof(double) == LDOUBLE_SIZE)
- *(double *)ptr = vtop->c.ld;
- else
+ *(long double*)ptr = vtop->c.ld;
+ else if (sizeof(double) == LDOUBLE_SIZE)
+ *(double *)ptr = (double)vtop->c.ld;
+ else
tcc_error("can't cross compile long double constants");
break;
#if PTR_SIZE != 8
case VT_LLONG:
- *(long long *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+ *(long long *)ptr |= vtop->c.i;
break;
#else
case VT_LLONG:
#endif
case VT_PTR:
{
- addr_t val = (vtop->c.i & bit_mask) << bit_pos;
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+ addr_t val = vtop->c.i;
+#if PTR_SIZE == 8
if (vtop->r & VT_SYM)
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
else
@@ -6272,8 +6603,8 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
}
default:
{
- int val = (vtop->c.i & bit_mask) << bit_pos;
-#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
+ int val = vtop->c.i;
+#if PTR_SIZE == 8
if (vtop->r & VT_SYM)
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
else
@@ -6296,25 +6627,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
}
}
-/* put zeros for variable based init */
-static void init_putz(Section *sec, unsigned long c, int size)
-{
- if (sec) {
- /* nothing to do because globals are already set to zero */
- } else {
- vpush_global_sym(&func_old_type, TOK_memset);
- vseti(VT_LOCAL, c);
-#ifdef TCC_TARGET_ARM
- vpushs(size);
- vpushi(0);
-#else
- vpushi(0);
- vpushs(size);
-#endif
- gfunc_call(3);
- }
-}
-
/* '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
@@ -6323,7 +6635,7 @@ static void init_putz(Section *sec, unsigned long c, int size)
static void decl_initializer(CType *type, Section *sec, unsigned long c,
int first, int size_only)
{
- int index, array_length, n, no_oblock, nb, parlevel, parlevel1, i;
+ int len, n, no_oblock, nb, i;
int size1, align1;
int have_elem;
Sym *s, *f;
@@ -6348,12 +6660,11 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
/* Use i_c_parameter_t, to strip toplevel qualifiers.
The source type might have VT_CONSTANT set, which is
of course assignable to non-const elements. */
- is_compatible_parameter_types(type, &vtop->type)) {
+ is_compatible_unqualified_types(type, &vtop->type)) {
init_putv(type, sec, c);
} else if (type->t & VT_ARRAY) {
s = type->ref;
n = s->c;
- array_length = 0;
t1 = pointed_type(type);
size1 = type_size(t1, &align1);
@@ -6376,6 +6687,7 @@ 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)) {
+ len = 0;
while (tok == TOK_STR || tok == TOK_LSTR) {
int cstr_len, ch;
@@ -6386,8 +6698,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
cstr_len = tokc.str.size / sizeof(nwchar_t);
cstr_len--;
nb = cstr_len;
- if (n >= 0 && nb > (n - array_length))
- nb = n - array_length;
+ 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");
@@ -6395,7 +6707,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
string in global variable, we handle it
specifically */
if (sec && tok == TOK_STR && size1 == 1) {
- memcpy(sec->data + c + array_length, tokc.str.data, nb);
+ if (!NODATA_WANTED)
+ memcpy(sec->data + c + len, tokc.str.data, nb);
} else {
for(i=0;i<nb;i++) {
if (tok == TOK_STR)
@@ -6403,75 +6716,61 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
else
ch = ((nwchar_t *)tokc.str.data)[i];
vpushi(ch);
- init_putv(t1, sec, c + (array_length + i) * size1);
+ init_putv(t1, sec, c + (len + i) * size1);
}
}
}
- array_length += nb;
+ len += nb;
next();
}
/* only add trailing zero if enough storage (no
warning in this case since it is standard) */
- if (n < 0 || array_length < n) {
+ if (n < 0 || len < n) {
if (!size_only) {
vpushi(0);
- init_putv(t1, sec, c + (array_length * size1));
+ init_putv(t1, sec, c + (len * size1));
}
- array_length++;
+ len++;
}
+ len *= size1;
} else {
indexsym.c = 0;
- indexsym.r = 0;
f = &indexsym;
do_init_list:
+ len = 0;
while (tok != '}' || have_elem) {
- decl_designator(type, sec, c, &f, size_only);
+ len = decl_designator(type, sec, c, &f, size_only, len);
have_elem = 0;
- index = f->c;
- /* must put zero in holes (note that doing it that way
- ensures that it even works with designators) */
- if (!size_only && array_length < index) {
- init_putz(sec, c + array_length * size1,
- (index - array_length) * size1);
- }
- if (type->t & VT_ARRAY) {
- index = indexsym.c = ++indexsym.r;
- } else {
- index = index + type_size(&f->type, &align1);
- if (s->type.t == TOK_UNION)
- f = NULL;
- else
- f = f->next;
- }
- if (index > array_length)
- array_length = index;
-
if (type->t & VT_ARRAY) {
+ ++indexsym.c;
/* special test for multi dimensional arrays (may not
be strictly correct if designators are used at the
same time) */
- if (no_oblock && index >= n)
+ if (no_oblock && len >= n*size1)
break;
} else {
+ if (s->type.t == VT_UNION)
+ f = NULL;
+ else
+ f = f->next;
if (no_oblock && f == NULL)
break;
}
+
if (tok == '}')
break;
skip(',');
}
}
/* put zeros at the end */
- if (!size_only && array_length < n) {
- init_putz(sec, c + array_length * size1,
- (n - array_length) * size1);
- }
+ if (!size_only && len < n*size1)
+ init_putz(sec, c + len, n*size1 - len);
if (!no_oblock)
skip('}');
/* patch type size if needed, which happens only for array types */
if (n < 0)
- s->c = array_length;
+ s->c = size1 == 1 ? len : ((len + size1 - 1)/size1);
} else if ((type->t & VT_BTYPE) == VT_STRUCT) {
size1 = 1;
no_oblock = 1;
@@ -6481,7 +6780,6 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
}
s = type->ref;
f = s->next;
- array_length = 0;
n = s->c;
goto do_init_list;
} else if (tok == '{') {
@@ -6496,25 +6794,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
But GNU C supports it, so we need to recurse even into
subfields of structs and arrays when size_only is set. */
/* just skip expression */
- parlevel = parlevel1 = 0;
- while ((parlevel > 0 || parlevel1 > 0 ||
- (tok != '}' && tok != ',')) && tok != -1) {
- if (tok == '(')
- parlevel++;
- else if (tok == ')') {
- if (parlevel == 0 && parlevel1 == 0)
- break;
- parlevel--;
- }
- else if (tok == '{')
- parlevel1++;
- else if (tok == '}') {
- if (parlevel == 0 && parlevel1 == 0)
- break;
- parlevel1--;
- }
- next();
- }
+ skip_or_save_block(NULL);
} else {
if (!have_elem) {
/* This should happen only when we haven't parsed
@@ -6538,12 +6818,19 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
int has_init, int v, int scope)
{
- int size, align, addr, data_offset;
- int level;
- ParseState saved_parse_state = {0};
+ int size, align, addr;
TokenString *init_str = NULL;
+
Section *sec;
Sym *flexible_array;
+ Sym *sym = NULL;
+ int saved_nocode_wanted = nocode_wanted;
+#ifdef CONFIG_TCC_BCHECK
+ int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
+#endif
+
+ if (type->t & VT_STATIC)
+ nocode_wanted |= NODATA_WANTED ? 0x40000000 : 0x80000000;
flexible_array = NULL;
if ((type->t & VT_BTYPE) == VT_STRUCT) {
@@ -6567,37 +6854,21 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (!has_init)
tcc_error("unknown type size");
/* get all init string */
- init_str = tok_str_alloc();
if (has_init == 2) {
+ init_str = tok_str_alloc();
/* only get strings */
while (tok == TOK_STR || tok == TOK_LSTR) {
tok_str_add_tok(init_str);
next();
}
+ tok_str_add(init_str, -1);
+ tok_str_add(init_str, 0);
} else {
- level = 0;
- while (level > 0 || (tok != ',' && tok != ';')) {
- if (tok < 0)
- tcc_error("unexpected end of file in initializer");
- tok_str_add_tok(init_str);
- if (tok == '{')
- level++;
- else if (tok == '}') {
- level--;
- if (level <= 0) {
- next();
- break;
- }
- }
- next();
- }
+ skip_or_save_block(&init_str);
}
- tok_str_add(init_str, -1);
- tok_str_add(init_str, 0);
-
- /* compute size */
- save_parse_state(&saved_parse_state);
+ unget_tok(0);
+ /* compute size */
begin_macro(init_str, 1);
next();
decl_initializer(type, NULL, 0, 1, 1);
@@ -6624,10 +6895,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
} else if (ad->a.packed) {
align = 1;
}
+
+ if (NODATA_WANTED)
+ size = 0, align = 1;
+
if ((r & VT_VALMASK) == VT_LOCAL) {
sec = NULL;
#ifdef CONFIG_TCC_BCHECK
- if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
+ if (bcheck && (type->t & VT_ARRAY)) {
loc--;
}
#endif
@@ -6637,7 +6912,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* handles bounds */
/* XXX: currently, since we do only one pass, we cannot track
'&' operators, so we add only arrays */
- if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
+ if (bcheck && (type->t & VT_ARRAY)) {
addr_t *bounds_ptr;
/* add padding between regions */
loc--;
@@ -6656,42 +6931,21 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
r = (r & ~VT_VALMASK) | reg;
}
#endif
- sym_push(v, type, r, addr);
+ sym = sym_push(v, type, r, addr);
+ sym->a = ad->a;
} else {
/* push local reference */
vset(type, r, addr);
}
} else {
- Sym *sym;
-
- sym = NULL;
if (v && scope == VT_CONST) {
/* see if the symbol was already defined */
sym = sym_find(v);
if (sym) {
- if (!is_compatible_types(&sym->type, type))
- tcc_error("incompatible types for redefinition of '%s'",
- get_tok_str(v, NULL));
- if (sym->type.t & VT_EXTERN) {
- /* if the variable is extern, it was not allocated */
- sym->type.t &= ~VT_EXTERN;
- /* set array size if it was omitted in extern
- declaration */
- if ((sym->type.t & VT_ARRAY) &&
- sym->type.ref->c < 0 &&
- type->ref->c >= 0)
- sym->type.ref->c = type->ref->c;
- } else {
- /* we accept several definitions of the same
- global variable. this is tricky, because we
- must play with the SHN_COMMON type of the symbol */
- /* XXX: should check if the variable was already
- initialized. It is incorrect to initialized it
- twice */
- /* no init data, we won't add more to the symbol */
- if (!has_init)
- goto no_alloc;
- }
+ patch_storage(sym, ad, type);
+ /* we accept several definitions of the same global variable. */
+ if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
+ goto no_alloc;
}
}
@@ -6703,62 +6957,43 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
else if (tcc_state->nocommon)
sec = bss_section;
}
+
if (sec) {
- data_offset = sec->data_offset;
- data_offset = (data_offset + align - 1) & -align;
- addr = data_offset;
- /* very important to increment global pointer at this time
- because initializers themselves can create new initializers */
- data_offset += size;
+ addr = section_add(sec, size, align);
#ifdef CONFIG_TCC_BCHECK
/* add padding if bound check */
- if (tcc_state->do_bounds_check)
- data_offset++;
+ if (bcheck)
+ section_add(sec, 1, 1);
#endif
- sec->data_offset = data_offset;
- /* allocate section space to put the data */
- if (sec->sh_type != SHT_NOBITS &&
- data_offset > sec->data_allocated)
- section_realloc(sec, data_offset);
- /* align section if needed */
- if (align > sec->sh_addralign)
- sec->sh_addralign = align;
} else {
- addr = 0; /* avoid warning */
+ addr = align; /* SHN_COMMON is special, symbol value is align */
+ sec = common_section;
}
if (v) {
- if (scope != VT_CONST || !sym) {
+ if (!sym) {
sym = sym_push(v, type, r | VT_SYM, 0);
- sym->asm_label = ad->asm_label;
+ patch_storage(sym, ad, NULL);
}
+ /* Local statics have a scope until now (for
+ warnings), remove it here. */
+ sym->sym_scope = 0;
/* update symbol definition */
- if (sec) {
- put_extern_sym(sym, sec, addr, size);
- } else {
- ElfW(Sym) *esym;
- /* put a common area */
- put_extern_sym(sym, NULL, align, size);
- /* XXX: find a nicer way */
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
- esym->st_shndx = SHN_COMMON;
- }
+ put_extern_sym(sym, sec, addr, size);
} else {
/* push global reference */
sym = get_sym_ref(type, sec, addr, size);
vpushsym(type, sym);
+ vtop->r |= r;
}
- /* patch symbol weakness */
- if (type->t & VT_WEAK)
- weaken_symbol(sym);
- apply_visibility(sym, type);
+
#ifdef CONFIG_TCC_BCHECK
/* handles bounds now because the symbol must be defined
before for the relocation */
- if (tcc_state->do_bounds_check) {
+ if (bcheck) {
addr_t *bounds_ptr;
- greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR);
+ greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0);
/* then add global bound info */
bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t));
bounds_ptr[0] = 0; /* relocated */
@@ -6766,9 +7001,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
}
#endif
}
+
if (type->t & VT_VLA) {
int a;
+ if (NODATA_WANTED)
+ goto no_alloc;
+
/* save current stack pointer */
if (vlas_in_scope == 0) {
if (vla_sp_root_loc == -1)
@@ -6778,9 +7017,15 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
vla_runtime_type_size(type, &a);
gen_vla_alloc(type, a);
+#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
+ /* on _WIN64, because of the function args scratch area, the
+ result of alloca differs from RSP and is returned in RAX. */
+ gen_vla_result(addr), addr = (loc -= PTR_SIZE);
+#endif
gen_vla_sp_save(addr);
vla_sp_loc = addr;
vlas_in_scope++;
+
} else if (has_init) {
size_t oldreloc_offset = 0;
if (sec && sec->reloc)
@@ -6793,85 +7038,21 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (flexible_array)
flexible_array->type.ref->c = -1;
}
- no_alloc: ;
+
+ no_alloc:
/* restore parse state if needed */
if (init_str) {
end_macro();
- restore_parse_state(&saved_parse_state);
+ next();
}
-}
-static void put_func_debug(Sym *sym)
-{
- char buf[512];
-
- /* 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;
-}
-
-/* parse an old style function declaration list */
-/* XXX: check multiple parameter */
-static void func_decl_list(Sym *func_sym)
-{
- AttributeDef ad;
- int v;
- Sym *s;
- CType btype, type;
-
- /* parse each declaration */
- while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF &&
- tok != TOK_ASM1 && tok != TOK_ASM2 && tok != TOK_ASM3) {
- if (!parse_btype(&btype, &ad))
- expect("declaration list");
- if (((btype.t & VT_BTYPE) == VT_ENUM ||
- (btype.t & VT_BTYPE) == VT_STRUCT) &&
- tok == ';') {
- /* we accept no variable after */
- } else {
- for(;;) {
- type = btype;
- type_decl(&type, &ad, &v, TYPE_DIRECT);
- /* find parameter in function parameter list */
- s = func_sym->next;
- while (s != NULL) {
- if ((s->v & ~SYM_FIELD) == v)
- goto found;
- s = s->next;
- }
- tcc_error("declaration for parameter '%s' but no such parameter",
- get_tok_str(v, NULL));
- found:
- /* check that no storage specifier except 'register' was given */
- if (type.t & VT_STORAGE)
- tcc_error("storage class specified for '%s'", get_tok_str(v, NULL));
- convert_parameter_type(&type);
- /* we can add the type (NOTE: it could be local to the function) */
- s->type = type;
- /* accept other parameters */
- if (tok == ',')
- next();
- else
- break;
- }
- }
- skip(';');
- }
+ nocode_wanted = saved_nocode_wanted;
}
/* parse a function defined by symbol 'sym' and generate its code in
'cur_text_section' */
static void gen_function(Sym *sym)
{
- int saved_nocode_wanted = nocode_wanted;
-
nocode_wanted = 0;
ind = cur_text_section->data_offset;
/* NOTE: we patch the symbol size later */
@@ -6882,42 +7063,33 @@ static void gen_function(Sym *sym)
vla_sp_loc = -1;
vla_sp_root_loc = -1;
/* put debug symbol */
- if (tcc_state->do_debug)
- put_func_debug(sym);
-
+ 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);
local_scope = 0;
-
rsym = 0;
block(NULL, NULL, 0);
+ nocode_wanted = 0;
gsym(rsym);
gfunc_epilog();
cur_text_section->data_offset = ind;
- label_pop(&global_label_stack, NULL);
+ label_pop(&global_label_stack, NULL, 0);
/* reset local stack */
local_scope = 0;
sym_pop(&local_stack, NULL, 0);
/* end of function */
/* patch symbol size */
- ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size =
- ind - func_ind;
- /* patch symbol weakness (this definition overrules any prototype) */
- if (sym->type.t & VT_WEAK)
- weaken_symbol(sym);
- apply_visibility(sym, &sym->type);
- if (tcc_state->do_debug) {
- put_stabn(N_FUN, 0, 0, ind - func_ind);
- }
+ elfsym(sym)->st_size = ind - func_ind;
+ tcc_debug_funcend(tcc_state, ind - func_ind);
/* It's better to crash than to generate wrong code */
cur_text_section = NULL;
funcname = ""; /* for safety */
func_vt.t = VT_VOID; /* for safety */
func_var = 0; /* for safety */
ind = 0; /* for safety */
- nocode_wanted = saved_nocode_wanted;
+ nocode_wanted = 0x80000000;
check_vstack();
}
@@ -6929,7 +7101,7 @@ static void gen_inline_functions(TCCState *s)
ln = file->line_num;
/* iterate while inline function are referenced */
- for(;;) {
+ do {
inline_generated = 0;
for (i = 0; i < s->nb_inline_fns; ++i) {
fn = s->inline_fns[i];
@@ -6940,7 +7112,6 @@ static void gen_inline_functions(TCCState *s)
fn->sym = NULL;
if (file)
pstrcpy(file->filename, sizeof file->filename, fn->filename);
- sym->r = VT_SYM | VT_CONST;
sym->type.t &= ~VT_INLINE;
begin_macro(fn->func_str, 1);
@@ -6952,9 +7123,7 @@ static void gen_inline_functions(TCCState *s)
inline_generated = 1;
}
}
- if (!inline_generated)
- break;
- }
+ } while (inline_generated);
file->line_num = ln;
}
@@ -6970,8 +7139,9 @@ ST_FUNC void free_inline_functions(TCCState *s)
dynarray_reset(&s->inline_fns, &s->nb_inline_fns);
}
-/* 'l' is VT_LOCAL or VT_CONST to define default storage type */
-static int decl0(int l, int is_for_loop_init)
+/* 'l' is VT_LOCAL or VT_CONST to define default storage type, or VT_CMP
+ if parsing old style parameter decl list (and FUNC_SYM is set then) */
+static int decl0(int l, int is_for_loop_init, Sym *func_sym)
{
int v, has_init, r;
CType type, btype;
@@ -6982,34 +7152,40 @@ static int decl0(int l, int is_for_loop_init)
if (!parse_btype(&btype, &ad)) {
if (is_for_loop_init)
return 0;
- /* skip redundant ';' */
- /* XXX: find more elegant solution */
- if (tok == ';') {
+ /* skip redundant ';' if not in old parameter decl scope */
+ if (tok == ';' && l != VT_CMP) {
next();
continue;
}
- if (l == VT_CONST &&
- (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
+ if (l != VT_CONST)
+ break;
+ if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) {
/* global asm block */
asm_global_instr();
continue;
}
- /* special test for old K&R protos without explicit int
- type. Only accepted when defining global data */
- if (l == VT_LOCAL || tok < TOK_UIDENT)
+ if (tok >= TOK_UIDENT) {
+ /* special test for old K&R protos without explicit int
+ type. Only accepted when defining global data */
+ btype.t = VT_INT;
+ } else {
+ if (tok != TOK_EOF)
+ expect("declaration");
break;
- btype.t = VT_INT;
+ }
}
- if (((btype.t & VT_BTYPE) == VT_ENUM ||
- (btype.t & VT_BTYPE) == VT_STRUCT) &&
- tok == ';') {
+ if (tok == ';') {
if ((btype.t & VT_BTYPE) == VT_STRUCT) {
int v = btype.ref->v;
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM)
tcc_warning("unnamed struct/union that defines no instances");
+ next();
+ continue;
}
- next();
- continue;
+ if (IS_ENUM(btype.t)) {
+ next();
+ continue;
+ }
}
while (1) { /* iterate thru each declaration */
type = btype;
@@ -7025,7 +7201,7 @@ static int decl0(int l, int is_for_loop_init)
#if 0
{
char buf[500];
- type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL));
+ type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL));
printf("type = '%s'\n", buf);
}
#endif
@@ -7036,8 +7212,8 @@ static int decl0(int l, int is_for_loop_init)
/* if old style function prototype, we accept a
declaration list */
sym = type.ref;
- if (sym->c == FUNC_OLD)
- func_decl_list(sym);
+ if (sym->f.func_type == FUNC_OLD && l == VT_CONST)
+ decl0(VT_CMP, 0, sym);
}
if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
@@ -7048,80 +7224,48 @@ static int decl0(int l, int is_for_loop_init)
expect(";");
}
- if (ad.a.weak)
- type.t |= VT_WEAK;
#ifdef TCC_TARGET_PE
- if (ad.a.func_import)
- type.t |= VT_IMPORT;
- if (ad.a.func_export)
- type.t |= VT_EXPORT;
+ 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_BTYPE) == VT_FUNC)
+ ad.a.dllimport = 0;
+ else
+ type.t |= VT_EXTERN;
+ }
+ }
#endif
- type.t |= ad.a.visibility << VT_VIS_SHIFT;
-
if (tok == '{') {
- if (l == VT_LOCAL)
+ if (l != VT_CONST)
tcc_error("cannot use local functions");
if ((type.t & VT_BTYPE) != VT_FUNC)
expect("function definition");
- /* reject abstract declarators in function definition */
+ /* reject abstract declarators in function definition
+ make old style params without decl have int type */
sym = type.ref;
- while ((sym = sym->next) != NULL)
+ while ((sym = sym->next) != NULL) {
if (!(sym->v & ~SYM_FIELD))
- expect("identifier");
+ 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;
-
- sym = sym_find(v);
- if (sym) {
- Sym *ref;
- if ((sym->type.t & VT_BTYPE) != VT_FUNC)
- goto func_error1;
-
- ref = sym->type.ref;
- if (0 == ref->a.func_proto)
- tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
-
- /* use func_call from prototype if not defined */
- if (ref->a.func_call != FUNC_CDECL
- && type.ref->a.func_call == FUNC_CDECL)
- type.ref->a.func_call = ref->a.func_call;
-
- /* use export from prototype */
- if (ref->a.func_export)
- type.ref->a.func_export = 1;
-
- /* use static from prototype */
- if (sym->type.t & VT_STATIC)
- type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
-
- /* If the definition has no visibility use the
- one from prototype. */
- if (! (type.t & VT_VIS_MASK))
- type.t |= sym->type.t & VT_VIS_MASK;
-
- if (!is_compatible_types(&sym->type, &type)) {
- func_error1:
- tcc_error("incompatible types for redefinition of '%s'",
- get_tok_str(v, NULL));
- }
- type.ref->a.func_proto = 0;
- /* if symbol is already defined, then put complete type */
- sym->type = type;
- } else {
- /* put function symbol */
- sym = global_identifier_push(v, type.t, 0);
- sym->type.ref = type.ref;
- }
+
+ /* put function symbol */
+ sym = external_global_sym(v, &type, 0);
+ type.t &= ~VT_EXTERN;
+ patch_storage(sym, &ad, &type);
/* 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)) {
- int block_level;
struct InlineFunc *fn;
const char *filename;
@@ -7129,43 +7273,39 @@ static int decl0(int l, int is_for_loop_init)
fn = tcc_malloc(sizeof *fn + strlen(filename));
strcpy(fn->filename, filename);
fn->sym = sym;
- fn->func_str = tok_str_alloc();
-
- block_level = 0;
- for(;;) {
- int t;
- if (tok == TOK_EOF)
- tcc_error("unexpected end of file");
- tok_str_add_tok(fn->func_str);
- t = tok;
- next();
- if (t == '{') {
- block_level++;
- } else if (t == '}') {
- block_level--;
- if (block_level == 0)
- break;
- }
- }
- tok_str_add(fn->func_str, -1);
- tok_str_add(fn->func_str, 0);
- dynarray_add((void ***)&tcc_state->inline_fns, &tcc_state->nb_inline_fns, fn);
-
+ skip_or_save_block(&fn->func_str);
+ dynarray_add(&tcc_state->inline_fns,
+ &tcc_state->nb_inline_fns, fn);
} else {
/* compute text section */
cur_text_section = ad.section;
if (!cur_text_section)
cur_text_section = text_section;
- sym->r = VT_SYM | VT_CONST;
gen_function(sym);
}
break;
} else {
- if (btype.t & VT_TYPEDEF) {
+ if (l == VT_CMP) {
+ /* find parameter in function parameter list */
+ for (sym = func_sym->next; sym; sym = sym->next)
+ if ((sym->v & ~SYM_FIELD) == v)
+ goto found;
+ tcc_error("declaration for parameter '%s' but no such parameter",
+ get_tok_str(v, NULL));
+found:
+ if (type.t & VT_STORAGE) /* 'register' is okay */
+ tcc_error("storage class specified for '%s'",
+ get_tok_str(v, NULL));
+ if (sym->type.t != VT_VOID)
+ tcc_error("redefinition of parameter '%s'",
+ get_tok_str(v, NULL));
+ convert_parameter_type(&type);
+ sym->type = type;
+ } else if (type.t & VT_TYPEDEF) {
/* save typedefed type */
/* XXX: test storage specifiers ? */
sym = sym_find(v);
- if (sym && sym->scope == local_scope) {
+ if (sym && sym->sym_scope == local_scope) {
if (!is_compatible_types(&sym->type, &type)
|| !(sym->type.t & VT_TYPEDEF))
tcc_error("incompatible redefinition of '%s'",
@@ -7175,14 +7315,13 @@ static int decl0(int l, int is_for_loop_init)
sym = sym_push(v, &type, 0, 0);
}
sym->a = ad.a;
- sym->type.t |= VT_TYPEDEF;
+ sym->f = ad.f;
} else {
r = 0;
if ((type.t & VT_BTYPE) == VT_FUNC) {
/* external function definition */
/* specific case for func_call attribute */
- ad.a.func_proto = 1;
- type.ref->a = ad.a;
+ type.ref->f = ad.f;
} else if (!(type.t & VT_ARRAY)) {
/* not lvalue if array */
r |= lvalue_type(type.t);
@@ -7190,36 +7329,38 @@ static int decl0(int l, int is_for_loop_init)
has_init = (tok == '=');
if (has_init && (type.t & VT_VLA))
tcc_error("variable length array cannot be initialized");
- if ((btype.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) ||
+ 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)) {
/* external variable or function */
/* NOTE: as GCC, uninitialized global static
arrays of null size are considered as
extern */
- sym = external_sym(v, &type, r);
- sym->asm_label = ad.asm_label;
-
+ type.t |= VT_EXTERN;
+ sym = external_sym(v, &type, r, &ad);
if (ad.alias_target) {
- Section tsec;
- ElfW(Sym) *esym;
+ ElfSym *esym;
Sym *alias_target;
-
alias_target = sym_find(ad.alias_target);
- if (!alias_target || !alias_target->c)
+ esym = elfsym(alias_target);
+ if (!esym)
tcc_error("unsupported forward __alias__ attribute");
- esym = &((ElfW(Sym) *)symtab_section->data)[alias_target->c];
- tsec.sh_num = esym->st_shndx;
- put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0);
+ /* 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 {
- type.t |= (btype.t & VT_STATIC); /* Retain "static". */
if (type.t & VT_STATIC)
r |= VT_CONST;
else
r |= l;
if (has_init)
next();
+ else if (l == VT_CONST)
+ /* uninitialized global variables may be overridden */
+ type.t |= VT_EXTERN;
decl_initializer_alloc(&type, &ad, r, has_init, v, l);
}
}
@@ -7237,9 +7378,9 @@ static int decl0(int l, int is_for_loop_init)
return 0;
}
-ST_FUNC void decl(int l)
+static void decl(int l)
{
- decl0(l, 0);
+ decl0(l, 0, NULL);
}
/* ------------------------------------------------------------------------- */
diff --git a/tccpe.c b/tccpe.c
index e2101bb..a7266c9 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -26,14 +26,12 @@
#ifndef _WIN32
#define stricmp strcasecmp
#define strnicmp strncasecmp
-#endif
-
-#ifndef MAX_PATH
-#define MAX_PATH 260
+#include <sys/stat.h> /* chmod() */
#endif
#ifdef TCC_TARGET_X86_64
# define ADDR3264 ULONGLONG
+# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64
# define REL_TYPE_DIRECT R_X86_64_64
# define R_XXX_THUNKFIX R_X86_64_PC32
# define R_XXX_RELATIVE R_X86_64_RELATIVE
@@ -42,6 +40,7 @@
#elif defined TCC_TARGET_ARM
# define ADDR3264 DWORD
+# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
# define REL_TYPE_DIRECT R_ARM_ABS32
# define R_XXX_THUNKFIX R_ARM_ABS32
# define R_XXX_RELATIVE R_ARM_RELATIVE
@@ -50,6 +49,7 @@
#elif defined TCC_TARGET_I386
# define ADDR3264 DWORD
+# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
# define REL_TYPE_DIRECT R_386_32
# define R_XXX_THUNKFIX R_386_32
# define R_XXX_RELATIVE R_386_RELATIVE
@@ -58,22 +58,6 @@
#endif
-#if 0
-#ifdef _WIN32
-void dbg_printf (const char *fmt, ...)
-{
- char buffer[4000];
- va_list arg;
- int x;
- va_start(arg, fmt);
- x = vsprintf (buffer, fmt, arg);
- strcpy(buffer+x, "\n");
- OutputDebugString(buffer);
-}
-#endif
-#endif
-
-/* ----------------------------------------------------------- */
#ifndef IMAGE_NT_SIGNATURE
/* ----------------------------------------------------------- */
/* definitions below are from winnt.h */
@@ -245,14 +229,19 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_REL_BASED_MIPS_JMPADDR 5
#define IMAGE_REL_BASED_SECTION 6
#define IMAGE_REL_BASED_REL32 7
+#define IMAGE_REL_BASED_DIR64 10
#pragma pack(pop)
/* ----------------------------------------------------------- */
#endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */
-#pragma pack(push, 1)
+#ifndef IMAGE_REL_BASED_DIR64
+# define IMAGE_REL_BASED_DIR64 10
+#endif
+
+#pragma pack(push, 1)
struct pe_header
{
IMAGE_DOS_HEADER doshdr;
@@ -285,7 +274,6 @@ struct pe_rsrc_reloc {
DWORD size;
WORD type;
};
-
#pragma pack(pop)
/* ------------------------------------------------------------- */
@@ -358,6 +346,7 @@ struct pe_info {
int type;
DWORD sizeofheaders;
ADDR3264 imagebase;
+ const char *start_symbol;
DWORD start_addr;
DWORD imp_offs;
DWORD imp_size;
@@ -384,7 +373,7 @@ struct pe_info {
static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym)
{
- const char *name = symtab_section->link->data + sym->st_name;
+ const char *name = (char*)symtab_section->link->data + sym->st_name;
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL))
return name + 1;
return name;
@@ -395,9 +384,11 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
char buffer[200];
const char *s, *p;
int sym_index = 0, n = 0;
+ int a, err = 0;
do {
s = pe_export_name(s1, sym);
+ a = 0;
if (n) {
/* second try: */
if (sym->st_other & ST_PE_STDCALL) {
@@ -408,19 +399,24 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
strcpy(buffer, s+1)[p-s-1] = 0;
} else if (s[0] != '_') { /* try non-ansi function */
buffer[0] = '_', strcpy(buffer + 1, s);
- } else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */
- strcpy(buffer, s + 6);
- } else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */
- strcpy(buffer, s + 6);
+ } else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */
+ strcpy(buffer, s + 6), a = 1;
+ } else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */
+ strcpy(buffer, s + 6), a = 1;
} else {
- break;
+ continue;
}
s = buffer;
}
sym_index = find_elf_sym(s1->dynsymtab_section, s);
// printf("find (%d) %d %s\n", n, sym_index, s);
+ if (sym_index
+ && ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT
+ && 0 == (sym->st_other & ST_PE_IMPORT)
+ && 0 == a
+ ) err = -1, sym_index = 0;
} while (0 == sym_index && ++n < 2);
- return sym_index;
+ return n == 2 ? err : sym_index;
}
/*----------------------------------------------------------------------------*/
@@ -638,7 +634,6 @@ static int pe_write(struct pe_info *pe)
switch (si->cls) {
case sec_text:
pe_header.opthdr.BaseOfCode = addr;
- pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr;
break;
case sec_data:
@@ -691,11 +686,16 @@ static int pe_write(struct pe_info *pe)
psh->PointerToRawData = file_offset;
file_offset = pe_file_align(pe, file_offset + si->data_size);
psh->SizeOfRawData = file_offset - psh->PointerToRawData;
+ if (si->cls == sec_text)
+ pe_header.opthdr.SizeOfCode += psh->SizeOfRawData;
+ else
+ pe_header.opthdr.SizeOfInitializedData += psh->SizeOfRawData;
}
}
//pe_header.filehdr.TimeDateStamp = time(NULL);
pe_header.filehdr.NumberOfSections = pe->sec_count;
+ pe_header.opthdr.AddressOfEntryPoint = pe->start_addr;
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
pe_header.opthdr.ImageBase = pe->imagebase;
pe_header.opthdr.Subsystem = pe->subsystem;
@@ -703,6 +703,7 @@ static int pe_write(struct pe_info *pe)
pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size;
if (PE_DLL == pe->type)
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);
@@ -723,6 +724,9 @@ static int pe_write(struct pe_info *pe)
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);
+#ifndef _WIN32
+ chmod(pe->filename, 0777);
+#endif
if (2 == pe->s1->verbose)
printf("-------------------------------\n");
@@ -752,7 +756,7 @@ static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
}
p = tcc_mallocz(sizeof *p);
p->dll_index = dll_index;
- dynarray_add((void***)&pe->imp_info, &pe->imp_count, p);
+ dynarray_add(&pe->imp_info, &pe->imp_count, p);
found_dll:
i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index);
@@ -760,11 +764,21 @@ found_dll:
return p->symbols[i];
s = tcc_mallocz(sizeof *s);
- dynarray_add((void***)&p->symbols, &p->sym_count, s);
+ dynarray_add(&p->symbols, &p->sym_count, s);
s->sym_index = sym_index;
return s;
}
+void pe_free_imports(struct pe_info *pe)
+{
+ int i;
+ for (i = 0; i < pe->imp_count; ++i) {
+ struct pe_import_info *p = pe->imp_info[i];
+ dynarray_reset(&p->symbols, &p->sym_count);
+ }
+ dynarray_reset(&pe->imp_info, &pe->imp_count);
+}
+
/*----------------------------------------------------------------------------*/
static void pe_build_imports(struct pe_info *pe)
{
@@ -816,7 +830,7 @@ static void pe_build_imports(struct pe_info *pe)
int sym_index = p->symbols[k]->sym_index;
ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index;
- const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
+ const char *name = (char*)pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
int ordinal;
org_sym->st_value = thk_ptr;
@@ -856,9 +870,7 @@ static void pe_build_imports(struct pe_info *pe)
ent_ptr += sizeof (ADDR3264);
}
dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR);
- dynarray_reset(&p->symbols, &p->sym_count);
}
- dynarray_reset(&pe->imp_info, &pe->imp_count);
}
/* ------------------------------------------------------------- */
@@ -886,7 +898,7 @@ static void pe_build_exports(struct pe_info *pe)
struct pe_sort_sym **sorted, *p;
FILE *op;
- char buf[MAX_PATH];
+ char buf[260];
const char *dllname;
const char *name;
@@ -903,7 +915,7 @@ static void pe_build_exports(struct pe_info *pe)
p = tcc_malloc(sizeof *p);
p->index = sym_index;
p->name = name;
- dynarray_add((void***)&sorted, &sym_count, p);
+ dynarray_add(&sorted, &sym_count, p);
}
#if 0
if (sym->st_other & ST_PE_EXPORT)
@@ -942,20 +954,20 @@ static void pe_build_exports(struct pe_info *pe)
/* automatically write exports to <output-filename>.def */
pstrcpy(buf, sizeof buf, pe->filename);
strcpy(tcc_fileextension(buf), ".def");
- op = fopen(buf, "w");
+ op = fopen(buf, "wb");
if (NULL == op) {
tcc_error_noabort("could not create '%s': %s", buf, strerror(errno));
} else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose)
- printf("<- %s (%d symbols)\n", buf, sym_count);
+ printf("<- %s (%d symbol%s)\n", buf, sym_count, &"s"[sym_count < 2]);
}
#endif
for (ord = 0; ord < sym_count; ++ord)
{
p = sorted[ord], sym_index = p->index, name = p->name;
- /* insert actual address later in pe_relocate_rva */
+ /* insert actual address later in relocate_section() */
put_elf_reloc(symtab_section, pe->thunk,
func_o, R_XXX_RELATIVE, sym_index);
*(DWORD*)(pe->thunk->data + name_o)
@@ -1000,7 +1012,7 @@ static void pe_build_reloc (struct pe_info *pe)
}
if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */
WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD));
- *wp = addr | IMAGE_REL_BASED_HIGHLOW<<12;
+ *wp = addr | PE_IMAGE_REL<<12;
++count;
continue;
}
@@ -1169,26 +1181,6 @@ static int pe_assign_addresses (struct pe_info *pe)
return 0;
}
-/* ------------------------------------------------------------- */
-static void pe_relocate_rva (struct pe_info *pe, Section *s)
-{
- Section *sr = s->reloc;
- ElfW_Rel *rel, *rel_end;
- rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
- for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
- if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) {
- int sym_index = ELFW(R_SYM)(rel->r_info);
- DWORD addr = s->sh_addr;
- if (sym_index) {
- ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
- addr = sym->st_value;
- }
- // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
- *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
- }
- }
-}
-
/*----------------------------------------------------------------------------*/
static int pe_isafunc(int sym_index)
@@ -1220,12 +1212,12 @@ static int pe_check_symbols(struct pe_info *pe)
sym = (ElfW(Sym) *)symtab_section->data + sym_index;
if (sym->st_shndx == SHN_UNDEF) {
- const char *name = symtab_section->link->data + sym->st_name;
+ const char *name = (char*)symtab_section->link->data + sym->st_name;
unsigned type = ELFW(ST_TYPE)(sym->st_info);
int imp_sym = pe_find_import(pe->s1, sym);
struct import_symbol *is;
- if (0 == imp_sym)
+ if (imp_sym <= 0)
goto not_found;
if (type == STT_NOTYPE) {
@@ -1296,7 +1288,11 @@ static int pe_check_symbols(struct pe_info *pe)
}
not_found:
- tcc_error_noabort("undefined symbol '%s'", name);
+ if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
+ /* STB_WEAK undefined symbols are accepted */
+ continue;
+ tcc_error_noabort("undefined symbol '%s'%s", name,
+ imp_sym < 0 ? ", missing __declspec(dllimport)?":"");
ret = -1;
} else if (pe->s1->rdynamic
@@ -1312,7 +1308,7 @@ static int pe_check_symbols(struct pe_info *pe)
#ifdef PE_PRINT_SECTIONS
static void pe_print_section(FILE * f, Section * s)
{
- /* just if you'r curious */
+ /* just if you're curious */
BYTE *p, *e, b;
int i, n, l, m;
p = s->data;
@@ -1450,26 +1446,15 @@ static void pe_print_sections(TCCState *s1, const char *fname)
/* ------------------------------------------------------------- */
/* helper function for load/store to insert one more indirection */
-#ifndef TCC_TARGET_ARM
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
{
- Sym *sym;
- ElfW(Sym) *esym;
int r2;
-
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
return sv;
- sym = sv->sym;
- if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN)
+ if (!sv->sym->a.dllimport)
return sv;
- if (!sym->c)
- put_extern_sym(sym, NULL, 0, 0);
- esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
- if (!(esym->st_other & ST_PE_IMPORT))
- return sv;
-
- // printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
-
+ // printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
memset(v2, 0, sizeof *v2);
v2->type.t = VT_PTR;
v2->r = VT_CONST | VT_SYM | VT_LVAL;
@@ -1478,14 +1463,12 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
r2 = get_reg(RC_INT);
load(r2, v2);
v2->r = r2;
-
if ((uint32_t)sv->c.i) {
vpushv(v2);
vpushi(sv->c.i);
gen_opi('+');
*v2 = *vtop--;
}
-
v2->type.t = sv->type.t;
v2->r |= sv->r & VT_LVAL;
return v2;
@@ -1514,7 +1497,7 @@ static int add_dllref(TCCState *s1, const char *dllname)
return i + 1;
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname));
strcpy(dllref->name, dllname);
- dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+ dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
return s1->nb_loaded_dlls;
}
@@ -1526,6 +1509,101 @@ static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
return len == read(fd, buffer, len);
}
+/* ------------------------------------------------------------- */
+
+PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
+{
+ int l, i, n, n0, ret;
+ char *p;
+ int fd;
+
+ IMAGE_SECTION_HEADER ish;
+ IMAGE_EXPORT_DIRECTORY ied;
+ IMAGE_DOS_HEADER dh;
+ IMAGE_FILE_HEADER ih;
+ DWORD sig, ref, addr, ptr, namep;
+
+ int pef_hdroffset, opt_hdroffset, sec_hdroffset;
+
+ n = n0 = 0;
+ p = NULL;
+ ret = -1;
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ goto the_end_1;
+ ret = 1;
+ if (!read_mem(fd, 0, &dh, sizeof dh))
+ goto the_end;
+ if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
+ goto the_end;
+ if (sig != 0x00004550)
+ goto the_end;
+ pef_hdroffset = dh.e_lfanew + sizeof sig;
+ if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
+ goto the_end;
+ opt_hdroffset = pef_hdroffset + sizeof ih;
+ if (ih.Machine == 0x014C) {
+ IMAGE_OPTIONAL_HEADER32 oh;
+ sec_hdroffset = opt_hdroffset + sizeof oh;
+ if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
+ goto the_end;
+ if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
+ goto the_end_0;
+ addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ } else if (ih.Machine == 0x8664) {
+ IMAGE_OPTIONAL_HEADER64 oh;
+ sec_hdroffset = opt_hdroffset + sizeof oh;
+ if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
+ goto the_end;
+ if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
+ goto the_end_0;
+ addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ } else
+ goto the_end;
+
+ //printf("addr: %08x\n", addr);
+ for (i = 0; i < ih.NumberOfSections; ++i) {
+ if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
+ goto the_end;
+ //printf("vaddr: %08x\n", ish.VirtualAddress);
+ if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
+ goto found;
+ }
+ goto the_end_0;
+
+found:
+ ref = ish.VirtualAddress - ish.PointerToRawData;
+ if (!read_mem(fd, addr - ref, &ied, sizeof ied))
+ goto the_end;
+
+ namep = ied.AddressOfNames - ref;
+ for (i = 0; i < ied.NumberOfNames; ++i) {
+ if (!read_mem(fd, namep, &ptr, sizeof ptr))
+ goto the_end;
+ namep += sizeof ptr;
+ for (l = 0;;) {
+ if (n+1 >= n0)
+ p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256);
+ if (!read_mem(fd, ptr - ref + l++, p + n, 1)) {
+ tcc_free(p), p = NULL;
+ goto the_end;
+ }
+ if (p[n++] == 0)
+ break;
+ }
+ }
+ if (p)
+ p[n] = 0;
+the_end_0:
+ ret = 0;
+the_end:
+ close(fd);
+the_end_1:
+ *pp = p;
+ return ret;
+}
+
/* -------------------------------------------------------------
* This is for compiled windows resources in 'coff' format
* as generated by 'windres.exe -O coff ...'.
@@ -1535,7 +1613,7 @@ static int pe_load_res(TCCState *s1, int fd)
{
struct pe_rsrc_header hdr;
Section *rsrc_section;
- int i, ret = -1;
+ int i, ret = -1, sym_index;
BYTE *ptr;
unsigned offs;
@@ -1544,7 +1622,7 @@ static int pe_load_res(TCCState *s1, int fd)
if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE
|| hdr.filehdr.NumberOfSections != 1
- || strcmp(hdr.sectionhdr.Name, ".rsrc") != 0)
+ || strcmp((char*)hdr.sectionhdr.Name, ".rsrc") != 0)
goto quit;
rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
@@ -1553,8 +1631,8 @@ static int pe_load_res(TCCState *s1, int fd)
if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData))
goto quit;
offs = hdr.sectionhdr.PointerToRelocations;
- for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
- {
+ sym_index = put_elf_sym(symtab_section, 0, 0, 0, 0, rsrc_section->sh_num, ".rsrc");
+ for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) {
struct pe_rsrc_reloc rel;
if (!read_mem(fd, offs, &rel, sizeof rel))
goto quit;
@@ -1562,7 +1640,7 @@ static int pe_load_res(TCCState *s1, int fd)
if (rel.type != RSRC_RELTYPE)
goto quit;
put_elf_reloc(symtab_section, rsrc_section,
- rel.offset, R_XXX_RELATIVE, 0);
+ rel.offset, R_XXX_RELATIVE, sym_index);
offs += sizeof rel;
}
ret = 0;
@@ -1643,20 +1721,20 @@ quit:
}
/* ------------------------------------------------------------- */
-#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
-#include "win32/tools/tiny_impdef.c"
-
-static int pe_load_dll(TCCState *s1, const char *dllname, int fd)
+static int pe_load_dll(TCCState *s1, const char *filename)
{
char *p, *q;
- int index;
- p = get_export_names(fd);
- if (!p)
+ int index, ret;
+
+ ret = tcc_get_dllexports(filename, &p);
+ if (ret) {
return -1;
- index = add_dllref(s1, dllname);
- for (q = p; *q; q += 1 + strlen(q))
- pe_putimport(s1, index, q, 0);
- tcc_free(p);
+ } else if (p) {
+ index = add_dllref(s1, tcc_basename(filename));
+ for (q = p; *q; q += 1 + strlen(q))
+ pe_putimport(s1, index, q, 0);
+ tcc_free(p);
+ }
return 0;
}
@@ -1670,7 +1748,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int 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))
- ret = pe_load_dll(s1, tcc_basename(filename), fd);
+ ret = pe_load_dll(s1, filename);
return ret;
}
@@ -1681,9 +1759,9 @@ static unsigned pe_add_uwwind_info(TCCState *s1)
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(tcc_state, ".pdata");
s1->uw_pdata->sh_addralign = 4;
- s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
}
-
+ if (0 == s1->uw_sym)
+ s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_base");
if (0 == s1->uw_offs) {
/* As our functions all have the same stackframe, we use one entry for all */
static const unsigned char uw_info[] = {
@@ -1732,7 +1810,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
/* put relocations on it */
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
- put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym);
+ put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
}
#endif
/* ------------------------------------------------------------- */
@@ -1746,62 +1824,71 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{
const char *start_symbol;
int pe_type = 0;
+ int unicode_entry = 0;
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
pe_type = PE_GUI;
else
+ if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) {
+ pe_type = PE_GUI;
+ unicode_entry = PE_GUI;
+ }
+ 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
+ else {
pe_type = PE_EXE;
+ if (find_elf_sym(symtab_section, "wmain"))
+ unicode_entry = PE_EXE;
+ }
start_symbol =
TCC_OUTPUT_MEMORY == s1->output_type
- ? PE_GUI == pe_type ? "__runwinmain" : "_main"
+ ? PE_GUI == pe_type ? (unicode_entry ? "__runwwinmain" : "__runwinmain")
+ : (unicode_entry ? "__runwmain" : "__runmain")
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
- : PE_GUI == pe_type ? "__winstart" : "__start"
+ : PE_GUI == pe_type ? (unicode_entry ? "__wwinstart": "__winstart")
+ : (unicode_entry ? "__wstart" : "__start")
;
if (!s1->leading_underscore || strchr(start_symbol, '@'))
++start_symbol;
/* grab the startup code from libtcc1 */
- if (TCC_OUTPUT_MEMORY != s1->output_type || PE_GUI == pe_type)
- set_elf_sym(symtab_section,
- 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- SHN_UNDEF, start_symbol);
+#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);
if (0 == s1->nostdlib) {
static const char *libs[] = {
- "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
+ TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
for (pp = libs; 0 != (p = *pp); ++pp) {
if (0 == *p) {
if (PE_DLL != pe_type && PE_GUI != pe_type)
break;
- } else if (tcc_add_library_err(s1, p) < 0) {
- break;
+ } else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
+ continue;
+ } else {
+ tcc_add_library_err(s1, p);
}
}
}
- if (TCC_OUTPUT_MEMORY == s1->output_type) {
+ if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN;
-#ifdef TCC_IS_NATIVE
- s1->runtime_main = start_symbol;
-#endif
- } else {
- pe->start_addr = (DWORD)(uintptr_t)tcc_get_symbol_err(s1, start_symbol);
- }
-
pe->type = pe_type;
+ pe->start_symbol = start_symbol;
}
static void pe_set_options(TCCState * s1, struct pe_info *pe)
@@ -1863,8 +1950,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
tcc_add_bcheck(s1);
pe_add_runtime(s1, &pe);
- relocate_common_syms(); /* assign bss adresses */
- tcc_add_linker_symbols(s1);
+ resolve_common_syms(s1);
pe_set_options(s1, &pe);
ret = pe_check_symbols(&pe);
@@ -1873,13 +1959,16 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
else if (filename) {
pe_assign_addresses(&pe);
relocate_syms(s1, s1->symtab, 0);
+ s1->pe_imagebase = pe.imagebase;
for (i = 1; i < s1->nb_sections; ++i) {
Section *s = s1->sections[i];
if (s->reloc) {
relocate_section(s1, s);
- pe_relocate_rva(&pe, s);
}
}
+ pe.start_addr = (DWORD)
+ ((uintptr_t)tcc_get_symbol_err(s1, pe.start_symbol)
+ - pe.imagebase);
if (s1->nb_errors)
ret = -1;
else
@@ -1889,9 +1978,15 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;
pe_build_imports(&pe);
+ s1->runtime_main = pe.start_symbol;
+#ifdef TCC_TARGET_X86_64
+ s1->uw_pdata = find_section(s1, ".pdata");
+#endif
#endif
}
+ pe_free_imports(&pe);
+
#ifdef PE_PRINT_SECTIONS
pe_print_sections(s1, "tcc.log");
#endif
diff --git a/tccpp.c b/tccpp.c
index 6659812..76f9e42 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -43,10 +43,13 @@ ST_DATA TokenSym **table_ident;
static TokenSym *hash_ident[TOK_HASH_SIZE];
static char token_buf[STRING_MAX_SIZE + 1];
static CString cstr_buf;
+static CString macro_equal_buf;
static TokenString tokstr_buf;
static unsigned char isidnum_table[256 - CH_EOF];
static int pp_debug_tok, pp_debug_symv;
static int pp_once;
+static int pp_expr;
+static int pp_counter;
static void tok_print(const char *msg, const int *str);
static struct TinyAlloc *toksym_alloc;
@@ -86,7 +89,7 @@ static const unsigned char tok_two_chars[] =
'^','=', TOK_A_XOR,
'|','=', TOK_A_OR,
'-','>', TOK_ARROW,
- '.','.', 0xa8, // C++ token ?
+ '.','.', TOK_TWODOTS,
'#','#', TOK_TWOSHARPS,
0
};
@@ -126,7 +129,7 @@ ST_FUNC void expect(const char *msg)
#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)
#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__)
#define TAL_DEBUG_PARAMS , const char *file, int line
-#define TAL_DEBUG_FILE_LEN 15
+#define TAL_DEBUG_FILE_LEN 40
#endif
#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */
@@ -137,22 +140,22 @@ ST_FUNC void expect(const char *msg)
#define CSTR_TAL_LIMIT 1024
typedef struct TinyAlloc {
- size_t limit;
- size_t size;
+ unsigned limit;
+ unsigned size;
uint8_t *buffer;
uint8_t *p;
- size_t nb_allocs;
+ unsigned nb_allocs;
struct TinyAlloc *next, *top;
#ifdef TAL_INFO
- size_t nb_peak;
- size_t nb_total;
- size_t nb_missed;
+ unsigned nb_peak;
+ unsigned nb_total;
+ unsigned nb_missed;
uint8_t *peak_p;
#endif
} TinyAlloc;
typedef struct tal_header_t {
- size_t size;
+ unsigned size;
#ifdef TAL_DEBUG
int line_num; /* negative line_num used for double free check */
char file_name[TAL_DEBUG_FILE_LEN + 1];
@@ -161,7 +164,7 @@ typedef struct tal_header_t {
/* ------------------------------------------------------------------------- */
-ST_FUNC TinyAlloc *tal_new(TinyAlloc **pal, size_t limit, size_t size)
+static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size)
{
TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc));
al->p = al->buffer = tcc_malloc(size);
@@ -171,7 +174,7 @@ ST_FUNC TinyAlloc *tal_new(TinyAlloc **pal, size_t limit, size_t size)
return al;
}
-ST_FUNC void tal_delete(TinyAlloc *al)
+static void tal_delete(TinyAlloc *al)
{
TinyAlloc *next;
@@ -186,17 +189,20 @@ tail_call:
#ifdef TAL_DEBUG
if (al->nb_allocs > 0) {
uint8_t *p;
- fprintf(stderr, "TAL_DEBUG: mem leak %d chunks (limit= %d)\n",
+ fprintf(stderr, "TAL_DEBUG: memory leak %d chunk(s) (limit= %d)\n",
al->nb_allocs, al->limit);
p = al->buffer;
while (p < al->p) {
tal_header_t *header = (tal_header_t *)p;
if (header->line_num > 0) {
- fprintf(stderr, " file %s, line %u: %u bytes\n",
+ fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n",
header->file_name, header->line_num, header->size);
}
p += header->size + sizeof(tal_header_t);
}
+#if MEM_DEBUG-0 == 2
+ exit(2);
+#endif
}
#endif
next = al->next;
@@ -206,7 +212,7 @@ tail_call:
goto tail_call;
}
-ST_FUNC void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS)
+static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS)
{
if (!p)
return;
@@ -215,10 +221,10 @@ tail_call:
#ifdef TAL_DEBUG
tal_header_t *header = (((tal_header_t *)p) - 1);
if (header->line_num < 0) {
- fprintf(stderr, "TAL_DEBUG: file %s, line %u double frees chunk from\n",
+ fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n",
file, line);
- fprintf(stderr, " file %s, line %u: %u bytes\n",
- header->file_name, -header->line_num, header->size);
+ fprintf(stderr, "%s:%d: %d bytes\n",
+ header->file_name, (int)-header->line_num, (int)header->size);
} else
header->line_num = -header->line_num;
#endif
@@ -233,12 +239,12 @@ tail_call:
tcc_free(p);
}
-ST_FUNC void *tal_realloc_impl(TinyAlloc **pal, void *p, size_t size TAL_DEBUG_PARAMS)
+static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS)
{
tal_header_t *header;
void *ret;
int is_own;
- size_t adj_size = (size + 3) & -4;
+ unsigned adj_size = (size + 3) & -4;
TinyAlloc *al = *pal;
tail_call:
@@ -475,6 +481,8 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
switch(v) {
case TOK_CINT:
case TOK_CUINT:
+ case TOK_CLONG:
+ case TOK_CULONG:
case TOK_CLLONG:
case TOK_CULLONG:
/* XXX: not quite exact, but only useful for testing */
@@ -526,7 +534,6 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
break;
/* above tokens have value, the ones below don't */
-
case TOK_LT:
v = '<';
goto addv;
@@ -539,6 +546,8 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
return strcpy(p, "<<=");
case TOK_A_SAR:
return strcpy(p, ">>=");
+ case TOK_EOF:
+ return strcpy(p, "<eof>");
default:
if (v < TOK_IDENT) {
/* search in two bytes table */
@@ -582,7 +591,7 @@ ST_FUNC int handle_eob(void)
/* only tries to read if really end of buffer */
if (bf->buf_ptr >= bf->buf_end) {
- if (bf->fd != -1) {
+ if (bf->fd >= 0) {
#if defined(PARSE_DEBUG)
len = 1;
#else
@@ -814,9 +823,11 @@ ST_FUNC uint8_t *parse_comment(uint8_t *p)
return p;
}
-ST_FUNC void set_idnum(int c, int val)
+ST_FUNC int set_idnum(int c, int val)
{
+ int prev = isidnum_table[c - CH_EOF];
isidnum_table[c - CH_EOF] = val;
+ return prev;
}
#define cinp minp
@@ -993,30 +1004,7 @@ _default:
file->buf_ptr = p;
}
-/* ParseState handling */
-
-/* XXX: currently, no include file info is stored. Thus, we cannot display
- accurate messages if the function or data definition spans multiple
- files */
-
-/* save current parse state in 's' */
-ST_FUNC void save_parse_state(ParseState *s)
-{
- s->line_num = file->line_num;
- s->macro_ptr = macro_ptr;
- s->tok = tok;
- s->tokc = tokc;
-}
-
-/* restore parse state from 's' */
-ST_FUNC void restore_parse_state(ParseState *s)
-{
- file->line_num = s->line_num;
- macro_ptr = s->macro_ptr;
- tok = s->tok;
- tokc = s->tokc;
-}
-
+#if 0
/* return the number of additional 'ints' necessary to store the
token */
static inline int tok_size(const int *p)
@@ -1035,6 +1023,9 @@ static inline int tok_size(const int *p)
case TOK_PPNUM:
case TOK_PPSTR:
return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2);
+ case TOK_CLONG:
+ case TOK_CULONG:
+ return 1 + LONG_SIZE / 4;
case TOK_CDOUBLE:
case TOK_CLLONG:
case TOK_CULLONG:
@@ -1045,13 +1036,13 @@ static inline int tok_size(const int *p)
return 1 + 0;
}
}
+#endif
/* token string handling */
-
ST_INLN void tok_str_new(TokenString *s)
{
s->str = NULL;
- s->len = 0;
+ s->len = s->lastlen = 0;
s->allocated_len = 0;
s->last_line_num = -1;
}
@@ -1117,6 +1108,7 @@ ST_FUNC void begin_macro(TokenString *str, int alloc)
str->alloc = alloc;
str->prev = macro_stack;
str->prev_ptr = macro_ptr;
+ str->save_line_num = file->line_num;
macro_ptr = str->str;
macro_stack = str;
}
@@ -1126,6 +1118,7 @@ ST_FUNC void end_macro(void)
TokenString *str = macro_stack;
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 {
@@ -1137,7 +1130,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
{
int len, *str;
- len = s->len;
+ len = s->lastlen = s->len;
str = s->str;
/* allocate space for worst case */
@@ -1151,6 +1144,10 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
case TOK_LCHAR:
case TOK_CFLOAT:
case TOK_LINENUM:
+#if LONG_SIZE == 4
+ case TOK_CLONG:
+ case TOK_CULONG:
+#endif
str[len++] = cv->tab[0];
break;
case TOK_PPNUM:
@@ -1171,6 +1168,10 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
case TOK_CDOUBLE:
case TOK_CLLONG:
case TOK_CULLONG:
+#if LONG_SIZE == 8
+ case TOK_CLONG:
+ case TOK_CULONG:
+#endif
#if LDOUBLE_SIZE == 8
case TOK_CLDOUBLE:
#endif
@@ -1221,14 +1222,24 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
tab = cv->tab;
switch(*t = *p++) {
+#if LONG_SIZE == 4
+ case TOK_CLONG:
+#endif
case TOK_CINT:
- case TOK_CUINT:
case TOK_CCHAR:
case TOK_LCHAR:
- case TOK_CFLOAT:
case TOK_LINENUM:
- tab[0] = *p++;
+ cv->i = *p++;
break;
+#if LONG_SIZE == 4
+ case TOK_CULONG:
+#endif
+ case TOK_CUINT:
+ cv->i = (unsigned)*p++;
+ break;
+ case TOK_CFLOAT:
+ tab[0] = *p++;
+ break;
case TOK_STR:
case TOK_LSTR:
case TOK_PPNUM:
@@ -1240,6 +1251,10 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
case TOK_CDOUBLE:
case TOK_CLLONG:
case TOK_CULLONG:
+#if LONG_SIZE == 8
+ case TOK_CLONG:
+ case TOK_CULONG:
+#endif
n = 2;
goto copy;
case TOK_CLDOUBLE:
@@ -1263,35 +1278,21 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
*pp = p;
}
-/* Calling this function is expensive, but it is not possible
- to read a token string backwards. */
-static int tok_last(const int *str0, const int *str1)
-{
- const int *str = str0;
- int tok = 0;
- CValue cval;
-
- while (str < str1)
- TOK_GET(&tok, &str, &cval);
- return tok;
-}
-
static int macro_is_equal(const int *a, const int *b)
{
CValue cv;
int t;
- static CString localbuf;
if (!a || !b)
return 1;
while (*a && *b) {
- /* first time preallocate static localbuf, next time only reset position to start */
- cstr_reset(&localbuf);
+ /* first time preallocate macro_equal_buf, next time only reset position to start */
+ cstr_reset(&macro_equal_buf);
TOK_GET(&t, &a, &cv);
- cstr_cat(&localbuf, get_tok_str(t, &cv), 0);
+ cstr_cat(&macro_equal_buf, get_tok_str(t, &cv), 0);
TOK_GET(&t, &b, &cv);
- if (strcmp(localbuf.data, get_tok_str(t, &cv)))
+ if (strcmp(macro_equal_buf.data, get_tok_str(t, &cv)))
return 0;
}
return !(*a || *b);
@@ -1339,7 +1340,8 @@ ST_FUNC void free_defines(Sym *b)
sym_free(top);
}
- /* restore remaining (-D or predefined) symbols */
+ /* 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) {
@@ -1379,7 +1381,7 @@ ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)
/* pop labels until element last is reached. Look if any labels are
undefined. Define symbols if '&&label' was used. */
-ST_FUNC void label_pop(Sym **ptop, Sym *slast)
+ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
{
Sym *s, *s1;
for(s = *ptop; s != slast; s = s1) {
@@ -1398,9 +1400,26 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast)
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
- sym_free(s);
+ if (!keep)
+ sym_free(s);
}
- *ptop = slast;
+ if (!keep)
+ *ptop = slast;
+}
+
+/* fake the nth "#if defined test_..." for tcc -dt -run */
+static void maybe_run_test(TCCState *s)
+{
+ const char *p;
+ if (s->include_stack_ptr != s->include_stack)
+ return;
+ p = get_tok_str(tok, NULL);
+ if (0 != memcmp(p, "test_", 5))
+ return;
+ if (0 != --s->run_test)
+ return;
+ fprintf(s->ppfp, "\n[%s]\n" + !(s->dflag & 32), p), fflush(s->ppfp);
+ define_push(tok, MACRO_OBJ, NULL, NULL);
}
/* eval an expression for #if/#elif */
@@ -1410,6 +1429,7 @@ static int expr_preprocess(void)
TokenString *str;
str = tok_str_alloc();
+ pp_expr = 1;
while (tok != TOK_LINEFEED && tok != TOK_EOF) {
next(); /* do macro subst */
if (tok == TOK_DEFINED) {
@@ -1417,9 +1437,16 @@ static int expr_preprocess(void)
t = tok;
if (t == '(')
next_nomacro();
+ if (tok < TOK_IDENT)
+ expect("identifier");
+ if (tcc_state->run_test)
+ maybe_run_test(tcc_state);
c = define_find(tok) != 0;
- if (t == '(')
+ if (t == '(') {
next_nomacro();
+ if (tok != ')')
+ expect("')'");
+ }
tok = TOK_CINT;
tokc.i = c;
} else if (tok >= TOK_IDENT) {
@@ -1429,6 +1456,7 @@ static int expr_preprocess(void)
}
tok_str_add_tok(str);
}
+ pp_expr = 0;
tok_str_add(str, -1); /* simulate end of file */
tok_str_add(str, 0);
/* now evaluate C constant expression */
@@ -1448,7 +1476,7 @@ ST_FUNC void parse_define(void)
int saved_parse_flags = parse_flags;
v = tok;
- if (v < TOK_IDENT)
+ if (v < TOK_IDENT || v == TOK_DEFINED)
tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc));
/* XXX: should check if same macro (ANSI) */
first = NULL;
@@ -1461,7 +1489,7 @@ ST_FUNC void parse_define(void)
/* '(' must be just after macro definition for MACRO_FUNC */
next_nomacro_spc();
if (tok == '(') {
- set_idnum('.', 0);
+ int dotid = set_idnum('.', 0);
next_nomacro();
ps = &first;
if (tok != ')') for (;;) {
@@ -1489,6 +1517,7 @@ ST_FUNC void parse_define(void)
}
next_nomacro_spc();
t = MACRO_FUNC;
+ set_idnum('.', dotid);
}
tokstr_buf.len = 0;
@@ -1499,7 +1528,6 @@ ST_FUNC void parse_define(void)
ID character in asm mode). But '#' should be retained instead of
regarded as line comment leader, so still don't set ASM_FILE
in parse_flags. */
- set_idnum('.', (saved_parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
while (tok != TOK_LINEFEED && tok != TOK_EOF) {
/* remove spaces around ## and after '#' */
if (TOK_TWOSHARPS == tok) {
@@ -1563,7 +1591,7 @@ static CachedInclude *search_cached_include(TCCState *s1, const char *filename,
e = tcc_malloc(sizeof(CachedInclude) + strlen(filename));
strcpy(e->filename, filename);
e->ifndef_macro = e->once = 0;
- dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e);
+ dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e);
/* add in hash table */
e->hash_next = s1->cached_includes_hash[h];
s1->cached_includes_hash[h] = s1->nb_cached_includes;
@@ -1607,7 +1635,7 @@ static void pragma_parse(TCCState *s1)
} else if (tok == TOK_once) {
search_cached_include(s1, file->filename, 1)->once = pp_once;
- } else if (s1->ppfp) {
+ } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
/* tcc -E: keep pragmas below unchanged */
unget_tok(' ');
unget_tok(TOK_PRAGMA);
@@ -1652,24 +1680,28 @@ static void pragma_parse(TCCState *s1)
goto pragma_err;
} else if (tok == TOK_comment) {
- char *file;
+ char *p; int t;
next();
skip('(');
- if (tok != TOK_lib)
- goto pragma_warn;
+ t = tok;
next();
skip(',');
if (tok != TOK_STR)
goto pragma_err;
- file = tcc_strdup((char *)tokc.str.data);
- dynarray_add((void ***)&s1->pragma_libs, &s1->nb_pragma_libs, file);
+ p = tcc_strdup((char *)tokc.str.data);
next();
if (tok != ')')
goto pragma_err;
- } else {
-pragma_warn:
- if (s1->warn_unsupported)
- tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc));
+ if (t == TOK_lib) {
+ dynarray_add(&s1->pragma_libs, &s1->nb_pragma_libs, p);
+ } else {
+ if (t == TOK_option)
+ tcc_set_options(s1, p);
+ tcc_free(p);
+ }
+
+ } else if (s1->warn_unsupported) {
+ tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc));
}
return;
@@ -1787,7 +1819,8 @@ ST_FUNC void preprocess(int is_bof)
/* search in file's dir if "header.h" */
if (c != '\"')
continue;
- path = file->filename;
+ /* https://savannah.nongnu.org/bugs/index.php?50847 */
+ path = file->true_filename;
pstrncpy(buf1, path, tcc_basename(path) - path);
} else {
@@ -1817,7 +1850,7 @@ ST_FUNC void preprocess(int is_bof)
printf("%s: including %s\n", file->prev->filename, file->filename);
#endif
/* update target deps */
- dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps,
+ dynarray_add(&s1->target_deps, &s1->nb_target_deps,
tcc_strdup(buf1));
/* push current file in stack */
++s1->include_stack_ptr;
@@ -1917,9 +1950,11 @@ include_done:
_line_num:
next();
if (tok != TOK_LINEFEED) {
- if (tok == TOK_STR)
+ 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);
- else if (parse_flags & PARSE_FLAG_ASM_FILE)
+ } else if (parse_flags & PARSE_FLAG_ASM_FILE)
break;
else
goto _line_err;
@@ -2068,13 +2103,79 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long
tcc_warning("unknown escape sequence: \'\\x%x\'", c);
break;
}
+ } else if (is_long && c >= 0x80) {
+ /* assume we are processing UTF-8 sequence */
+ /* reference: The Unicode Standard, Version 10.0, ch3.9 */
+
+ int cont; /* count of continuation bytes */
+ int skip; /* how many bytes should skip when error occurred */
+ int i;
+
+ /* decode leading byte */
+ if (c < 0xC2) {
+ skip = 1; goto invalid_utf8_sequence;
+ } else if (c <= 0xDF) {
+ cont = 1; n = c & 0x1f;
+ } else if (c <= 0xEF) {
+ cont = 2; n = c & 0xf;
+ } else if (c <= 0xF4) {
+ cont = 3; n = c & 0x7;
+ } else {
+ skip = 1; goto invalid_utf8_sequence;
+ }
+
+ /* decode continuation bytes */
+ for (i = 1; i <= cont; i++) {
+ int l = 0x80, h = 0xBF;
+
+ /* adjust limit for second byte */
+ if (i == 1) {
+ switch (c) {
+ case 0xE0: l = 0xA0; break;
+ case 0xED: h = 0x9F; break;
+ case 0xF0: l = 0x90; break;
+ case 0xF4: h = 0x8F; break;
+ }
+ }
+
+ if (p[i] < l || p[i] > h) {
+ skip = i; goto invalid_utf8_sequence;
+ }
+
+ n = (n << 6) | (p[i] & 0x3f);
+ }
+
+ /* advance pointer */
+ p += 1 + cont;
+ c = n;
+ goto add_char_nonext;
+
+ /* error handling */
+ invalid_utf8_sequence:
+ tcc_warning("ill-formed UTF-8 subsequence starting with: \'\\x%x\'", c);
+ c = 0xFFFD;
+ p += skip;
+ goto add_char_nonext;
+
}
p++;
add_char_nonext:
if (!is_long)
cstr_ccat(outstr, c);
- else
+ else {
+#ifdef TCC_TARGET_PE
+ /* store as UTF-16 */
+ if (c < 0x10000) {
+ cstr_wccat(outstr, c);
+ } else {
+ c -= 0x10000;
+ cstr_wccat(outstr, (c >> 10) + 0xD800);
+ cstr_wccat(outstr, (c & 0x3FF) + 0xDC00);
+ }
+#else
cstr_wccat(outstr, c);
+#endif
+ }
}
/* add a trailing '\0' */
if (!is_long)
@@ -2103,23 +2204,24 @@ static void parse_string(const char *s, int len)
tcc_free(p);
if (sep == '\'') {
- int char_size;
+ int char_size, i, n, c;
/* XXX: make it portable */
if (!is_long)
- char_size = 1;
+ tok = TOK_CCHAR, char_size = 1;
else
- char_size = sizeof(nwchar_t);
- if (tokcstr.size <= char_size)
+ tok = TOK_LCHAR, char_size = sizeof(nwchar_t);
+ n = tokcstr.size / char_size - 1;
+ if (n < 1)
tcc_error("empty character constant");
- if (tokcstr.size > 2 * char_size)
+ if (n > 1)
tcc_warning("multi-character character constant");
- if (!is_long) {
- tokc.i = *(int8_t *)tokcstr.data;
- tok = TOK_CCHAR;
- } else {
- tokc.i = *(nwchar_t *)tokcstr.data;
- tok = TOK_LCHAR;
+ for (c = i = 0; i < n; ++i) {
+ if (is_long)
+ c = ((nwchar_t *)tokcstr.data)[i];
+ else
+ c = (c << 8) | ((char *)tokcstr.data)[i];
}
+ tokc.i = c;
} else {
tokc.str.size = tokcstr.size;
tokc.str.data = tokcstr.data;
@@ -2353,7 +2455,7 @@ static void parse_number(const char *p)
}
} else {
unsigned long long n, n1;
- int lcount, ucount, must_64bit;
+ int lcount, ucount, ov = 0;
const char *p1;
/* integer number */
@@ -2380,14 +2482,13 @@ static void parse_number(const char *p)
n1 = n;
n = n * b + t;
/* detect overflow */
- /* XXX: this test is not reliable */
- if (n < n1)
- tcc_error("integer constant overflow");
+ if (n1 >= 0x1000000000000000ULL && n / b != n1)
+ ov = 1;
}
/* Determine the characteristics (unsigned and/or 64bit) the type of
the constant must have according to the constant suffix(es) */
- lcount = ucount = must_64bit = 0;
+ lcount = ucount = 0;
p1 = p;
for(;;) {
t = toup(ch);
@@ -2397,10 +2498,6 @@ static void parse_number(const char *p)
if (lcount && *(p - 1) != ch)
tcc_error("incorrect integer suffix: %s", p1);
lcount++;
-#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
- if (lcount == 2)
-#endif
- must_64bit = 1;
ch = *p++;
} else if (t == 'U') {
if (ucount >= 1)
@@ -2412,29 +2509,36 @@ static void parse_number(const char *p)
}
}
- /* Whether 64 bits are needed to hold the constant's value */
- if (n & 0xffffffff00000000LL || must_64bit) {
- tok = TOK_CLLONG;
- n1 = n >> 32;
- } else {
- tok = TOK_CINT;
- n1 = n;
+ /* Determine if it needs 64 bits and/or unsigned in order to fit */
+ if (ucount == 0 && b == 10) {
+ if (lcount <= (LONG_SIZE == 4)) {
+ if (n >= 0x80000000U)
+ lcount = (LONG_SIZE == 4) + 1;
+ }
+ if (n >= 0x8000000000000000ULL)
+ ov = 1, ucount = 1;
+ } else {
+ if (lcount <= (LONG_SIZE == 4)) {
+ if (n >= 0x100000000ULL)
+ lcount = (LONG_SIZE == 4) + 1;
+ else if (n >= 0x80000000U)
+ ucount = 1;
+ }
+ if (n >= 0x8000000000000000ULL)
+ ucount = 1;
}
- /* Whether type must be unsigned to hold the constant's value */
- if (ucount || ((n1 >> 31) && (b != 10))) {
- if (tok == TOK_CLLONG)
- tok = TOK_CULLONG;
- else
- tok = TOK_CUINT;
- /* If decimal and no unsigned suffix, bump to 64 bits or throw error */
- } else if (n1 >> 31) {
- if (tok == TOK_CINT)
- tok = TOK_CLLONG;
- else
- tcc_error("integer constant overflow");
- }
+ if (ov)
+ tcc_warning("integer constant overflow");
+ tok = TOK_CINT;
+ if (lcount) {
+ tok = TOK_CLONG;
+ if (lcount == 2)
+ tok = TOK_CLLONG;
+ }
+ if (ucount)
+ ++tok; /* TOK_CU... */
tokc.i = n;
}
if (ch)
@@ -2524,6 +2628,8 @@ static inline void next_nomacro1(void)
tcc_close();
s1->include_stack_ptr--;
p = file->buf_ptr;
+ if (p == file->buffer)
+ tok_flags = TOK_FLAG_BOF|TOK_FLAG_BOL;
goto redo_no_start;
}
}
@@ -2611,7 +2717,7 @@ maybe_newline:
} else {
/* slower case */
cstr_reset(&tokcstr);
- cstr_cat(&tokcstr, p1, len);
+ cstr_cat(&tokcstr, (char *) p1, len);
p--;
PEEKC(c, p);
parse_ident_slow:
@@ -2857,7 +2963,7 @@ maybe_newline:
keep_tok_flags:
file->buf_ptr = p;
#if defined(PARSE_DEBUG)
- printf("token = %s\n", get_tok_str(tok, &tokc));
+ printf("token = %d %s\n", tok, get_tok_str(tok, &tokc));
#endif
}
@@ -2878,6 +2984,7 @@ static void next_nomacro_spc(void)
} else {
next_nomacro1();
}
+ //printf("token = %s\n", get_tok_str(tok, &tokc));
}
ST_FUNC void next_nomacro(void)
@@ -2891,8 +2998,7 @@ ST_FUNC void next_nomacro(void)
static void macro_subst(
TokenString *tok_str,
Sym **nested_list,
- const int *macro_str,
- int can_read_stream
+ const int *macro_str
);
/* substitute arguments in replacement lists in macro_str by the values in
@@ -2923,7 +3029,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
cstr_ccat(&cstr, '\"');
st = s->d;
spc = 0;
- while (*st) {
+ while (*st >= 0) {
TOK_GET(&t, &st, &cval);
if (t != TOK_PLCHLDR
&& t != TOK_NOSUBST
@@ -2963,7 +3069,7 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
/* special case for var arg macros : ## eats the ','
if empty VA_ARGS variable. */
if (t1 == TOK_PPJOIN && t0 == ',' && gnu_ext && s->type.t) {
- if (*st == 0) {
+ if (*st <= 0) {
/* suppress ',' '##' */
str.len -= 2;
} else {
@@ -2971,23 +3077,31 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
str.len--;
goto add_var;
}
- } else {
- for(;;) {
- int t1;
- TOK_GET(&t1, &st, &cval);
- if (!t1)
- break;
- tok_str_add2(&str, t1, &cval);
- }
}
-
} else {
add_var:
- /* NOTE: the stream cannot be read when macro
- substituing an argument */
- macro_subst(&str, nested_list, st, 0);
+ if (!s->next) {
+ /* Expand arguments tokens and store them. In most
+ cases we could also re-expand each argument if
+ used multiple times, but not if the argument
+ contains the __COUNTER__ macro. */
+ TokenString str2;
+ sym_push2(&s->next, s->v, s->type.t, 0);
+ tok_str_new(&str2);
+ macro_subst(&str2, nested_list, st);
+ tok_str_add(&str2, 0);
+ s->next->d = str2.str;
+ }
+ st = s->next->d;
+ }
+ for(;;) {
+ int t2;
+ TOK_GET(&t2, &st, &cval);
+ if (t2 <= 0)
+ break;
+ tok_str_add2(&str, t2, &cval);
}
- if (str.len == l0) /* exanded to empty string */
+ if (str.len == l0) /* expanded to empty string */
tok_str_add(&str, TOK_PLCHLDR);
} else {
tok_str_add(&str, t);
@@ -3007,9 +3121,103 @@ static char const ab_month_name[12][4] =
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
+static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
+{
+ CString cstr;
+ int n, ret = 1;
+
+ cstr_new(&cstr);
+ if (t1 != TOK_PLCHLDR)
+ cstr_cat(&cstr, get_tok_str(t1, v1), -1);
+ n = cstr.size;
+ if (t2 != TOK_PLCHLDR)
+ cstr_cat(&cstr, get_tok_str(t2, v2), -1);
+ cstr_ccat(&cstr, '\0');
+
+ tcc_open_bf(tcc_state, ":paste:", cstr.size);
+ memcpy(file->buffer, cstr.data, cstr.size);
+ tok_flags = 0;
+ for (;;) {
+ next_nomacro1();
+ if (0 == *file->buf_ptr)
+ break;
+ 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);
+ ret = 0;
+ break;
+ }
+ tcc_close();
+ //printf("paste <%s>\n", (char*)cstr.data);
+ cstr_free(&cstr);
+ return ret;
+}
+
+/* handle the '##' operator. Return NULL if no '##' seen. Otherwise
+ return the resulting string (which must be freed). */
+static inline int *macro_twosharps(const int *ptr0)
+{
+ int t;
+ CValue cval;
+ TokenString macro_str1;
+ int start_of_nosubsts = -1;
+ const int *ptr;
+
+ /* we search the first '##' */
+ for (ptr = ptr0;;) {
+ TOK_GET(&t, &ptr, &cval);
+ if (t == TOK_PPJOIN)
+ break;
+ if (t == 0)
+ return NULL;
+ }
+
+ tok_str_new(&macro_str1);
+
+ //tok_print(" $$$", ptr0);
+ for (ptr = ptr0;;) {
+ TOK_GET(&t, &ptr, &cval);
+ if (t == 0)
+ break;
+ if (t == TOK_PPJOIN)
+ continue;
+ while (*ptr == TOK_PPJOIN) {
+ int t1; CValue cv1;
+ /* given 'a##b', remove nosubsts preceding 'a' */
+ if (start_of_nosubsts >= 0)
+ macro_str1.len = start_of_nosubsts;
+ /* given 'a##b', remove nosubsts preceding 'b' */
+ while ((t1 = *++ptr) == TOK_NOSUBST)
+ ;
+ if (t1 && t1 != TOK_PPJOIN) {
+ TOK_GET(&t1, &ptr, &cv1);
+ if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) {
+ if (paste_tokens(t, &cval, t1, &cv1)) {
+ t = tok, cval = tokc;
+ } else {
+ tok_str_add2(&macro_str1, t, &cval);
+ t = t1, cval = cv1;
+ }
+ }
+ }
+ }
+ if (t == TOK_NOSUBST) {
+ if (start_of_nosubsts < 0)
+ start_of_nosubsts = macro_str1.len;
+ } else {
+ start_of_nosubsts = -1;
+ }
+ tok_str_add2(&macro_str1, t, &cval);
+ }
+ tok_str_add(&macro_str1, 0);
+ //tok_print(" ###", macro_str1.str);
+ return macro_str1.str;
+}
+
/* peek or read [ws_str == NULL] next token from function macro call,
walking up macro levels up to the file if necessary */
-static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *ws_str)
+static int next_argstream(Sym **nested_list, TokenString *ws_str)
{
int t;
const int *p;
@@ -3019,10 +3227,10 @@ static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *w
if (macro_ptr) {
p = macro_ptr, t = *p;
if (ws_str) {
- while (is_space(t) || TOK_LINEFEED == t)
+ while (is_space(t) || TOK_LINEFEED == t || TOK_PLCHLDR == t)
tok_str_add(ws_str, t), t = *++p;
}
- if (t == 0 && can_read_stream) {
+ if (t == 0) {
end_macro();
/* also, end of scope for nested defined symbol */
sa = *nested_list;
@@ -3050,6 +3258,8 @@ static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *w
break;
ch = ' ';
}
+ if (ch == '\n')
+ file->line_num++;
if (!(ch == '\f' || ch == '\v' || ch == '\r'))
tok_str_add(ws_str, ch);
cinp();
@@ -3072,21 +3282,21 @@ static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *w
static int macro_subst_tok(
TokenString *tok_str,
Sym **nested_list,
- Sym *s,
- int can_read_stream)
+ Sym *s)
{
Sym *args, *sa, *sa1;
- int parlevel, *mstr, t, t1, spc;
+ int parlevel, t, t1, spc;
TokenString str;
char *cstrval;
CValue cval;
CString cstr;
char buf[32];
-
+
/* if symbol is a macro, prepare substitution */
/* special macros */
- if (tok == TOK___LINE__) {
- snprintf(buf, sizeof(buf), "%d", file->line_num);
+ if (tok == TOK___LINE__ || tok == TOK___COUNTER__) {
+ t = tok == TOK___LINE__ ? file->line_num : pp_counter++;
+ snprintf(buf, sizeof(buf), "%d", t);
cstrval = buf;
t1 = TOK_PPNUM;
goto add_cstr1;
@@ -3116,10 +3326,11 @@ static int macro_subst_tok(
cval.str.data = cstr.data;
tok_str_add2(tok_str, t1, &cval);
cstr_free(&cstr);
- } else {
+ } else if (s->d) {
int saved_parse_flags = parse_flags;
+ int *joined_str = NULL;
+ int *mstr = s->d;
- mstr = s->d;
if (s->type.t == MACRO_FUNC) {
/* whitespace between macro name and argument list */
TokenString ws_str;
@@ -3130,7 +3341,7 @@ static int macro_subst_tok(
| PARSE_FLAG_ACCEPT_STRAYS;
/* get next token from argument stream */
- t = next_argstream(nested_list, can_read_stream, &ws_str);
+ t = next_argstream(nested_list, &ws_str);
if (t != '(') {
/* not a macro substitution after all, restore the
* macro token plus all whitespace we've read.
@@ -3148,7 +3359,9 @@ static int macro_subst_tok(
} else {
tok_str_free_str(ws_str.str);
}
- next_nomacro(); /* eat '(' */
+ do {
+ next_nomacro(); /* eat '(' */
+ } while (tok == TOK_PLCHLDR);
/* argument macro */
args = NULL;
@@ -3156,7 +3369,7 @@ static int macro_subst_tok(
/* NOTE: empty args are allowed, except if no args */
for(;;) {
do {
- next_argstream(nested_list, can_read_stream, NULL);
+ next_argstream(nested_list, NULL);
} while (is_space(tok) || TOK_LINEFEED == tok);
empty_arg:
/* handle '()' case */
@@ -3181,11 +3394,12 @@ static int macro_subst_tok(
tok = ' ';
if (!check_space(tok, &spc))
tok_str_add2(&str, tok, &tokc);
- next_argstream(nested_list, can_read_stream, NULL);
+ next_argstream(nested_list, NULL);
}
if (parlevel)
expect(")");
str.len -= spc;
+ tok_str_add(&str, -1);
tok_str_add(&str, 0);
sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
sa1->d = str.str;
@@ -3214,6 +3428,10 @@ static int macro_subst_tok(
while (sa) {
sa1 = sa->prev;
tok_str_free_str(sa->d);
+ if (sa->next) {
+ tok_str_free_str(sa->next->d);
+ sym_free(sa->next);
+ }
sym_free(sa);
sa = sa1;
}
@@ -3221,141 +3439,39 @@ static int macro_subst_tok(
sym_push2(nested_list, s->v, 0, 0);
parse_flags = saved_parse_flags;
- macro_subst(tok_str, nested_list, mstr, can_read_stream | 2);
+ joined_str = macro_twosharps(mstr);
+ macro_subst(tok_str, nested_list, joined_str ? joined_str : mstr);
/* pop nested defined symbol */
sa1 = *nested_list;
*nested_list = sa1->prev;
sym_free(sa1);
+ if (joined_str)
+ tok_str_free_str(joined_str);
if (mstr != s->d)
tok_str_free_str(mstr);
}
return 0;
}
-static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
-{
- CString cstr;
- int n, ret = 1;
-
- cstr_new(&cstr);
- if (t1 != TOK_PLCHLDR)
- cstr_cat(&cstr, get_tok_str(t1, v1), -1);
- n = cstr.size;
- if (t2 != TOK_PLCHLDR)
- cstr_cat(&cstr, get_tok_str(t2, v2), -1);
- cstr_ccat(&cstr, '\0');
-
- tcc_open_bf(tcc_state, ":paste:", cstr.size);
- memcpy(file->buffer, cstr.data, cstr.size);
- for (;;) {
- next_nomacro1();
- if (0 == *file->buf_ptr)
- break;
- 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);
- ret = 0;
- break;
- }
- tcc_close();
- //printf("paste <%s>\n", (char*)cstr.data);
- cstr_free(&cstr);
- return ret;
-}
-
-/* handle the '##' operator. Return NULL if no '##' seen. Otherwise
- return the resulting string (which must be freed). */
-static inline int *macro_twosharps(const int *ptr0)
-{
- int t;
- CValue cval;
- TokenString macro_str1;
- int start_of_nosubsts = -1;
- const int *ptr;
-
- /* we search the first '##' */
- for (ptr = ptr0;;) {
- TOK_GET(&t, &ptr, &cval);
- if (t == TOK_PPJOIN)
- break;
- if (t == 0)
- return NULL;
- }
-
- tok_str_new(&macro_str1);
-
- //tok_print(" $$$", ptr0);
- for (ptr = ptr0;;) {
- TOK_GET(&t, &ptr, &cval);
- if (t == 0)
- break;
- if (t == TOK_PPJOIN)
- continue;
- while (*ptr == TOK_PPJOIN) {
- int t1; CValue cv1;
- /* given 'a##b', remove nosubsts preceding 'a' */
- if (start_of_nosubsts >= 0)
- macro_str1.len = start_of_nosubsts;
- /* given 'a##b', remove nosubsts preceding 'b' */
- while ((t1 = *++ptr) == TOK_NOSUBST)
- ;
- if (t1 && t1 != TOK_PPJOIN) {
- TOK_GET(&t1, &ptr, &cv1);
- if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) {
- if (paste_tokens(t, &cval, t1, &cv1)) {
- t = tok, cval = tokc;
- } else {
- tok_str_add2(&macro_str1, t, &cval);
- t = t1, cval = cv1;
- }
- }
- }
- }
- if (t == TOK_NOSUBST) {
- if (start_of_nosubsts < 0)
- start_of_nosubsts = macro_str1.len;
- } else {
- start_of_nosubsts = -1;
- }
- tok_str_add2(&macro_str1, t, &cval);
- }
- tok_str_add(&macro_str1, 0);
- //tok_print(" ###", macro_str1.str);
- return macro_str1.str;
-}
-
/* do macro substitution of macro_str and add result to
(tok_str,tok_len). 'nested_list' is the list of all macros we got
inside to avoid recursing. */
static void macro_subst(
TokenString *tok_str,
Sym **nested_list,
- const int *macro_str,
- int can_read_stream
+ const int *macro_str
)
{
Sym *s;
- const int *ptr;
int t, spc, nosubst;
CValue cval;
- int *macro_str1 = NULL;
- /* first scan for '##' operator handling */
- ptr = macro_str;
spc = nosubst = 0;
- /* first scan for '##' operator handling */
- if (can_read_stream) {
- macro_str1 = macro_twosharps(ptr);
- if (macro_str1)
- ptr = macro_str1;
- }
-
while (1) {
- TOK_GET(&t, &ptr, &cval);
- if (t == 0)
+ TOK_GET(&t, &macro_str, &cval);
+ if (t <= 0)
break;
if (t >= TOK_IDENT && 0 == nosubst) {
@@ -3372,41 +3488,41 @@ static void macro_subst(
{
TokenString str;
- str.str = (int*)ptr;
+ str.str = (int*)macro_str;
begin_macro(&str, 2);
tok = t;
- macro_subst_tok(tok_str, nested_list, s, can_read_stream);
+ macro_subst_tok(tok_str, nested_list, s);
if (str.alloc == 3) {
/* already finished by reading function macro arguments */
break;
}
- ptr = macro_ptr;
+ macro_str = macro_ptr;
end_macro ();
}
-
- spc = (tok_str->len &&
- is_space(tok_last(tok_str->str,
- tok_str->str + tok_str->len)));
-
+ 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);
- nosubst = 0;
+
+ if (nosubst) {
+ if (nosubst > 1 && (spc || (++nosubst == 3 && t == '(')))
+ continue;
+ nosubst = 0;
+ }
if (t == TOK_NOSUBST)
nosubst = 1;
}
+ /* GCC supports 'defined' as result of a macro substitution */
+ if (t == TOK_DEFINED && pp_expr)
+ nosubst = 2;
}
- if (macro_str1)
- tok_str_free_str(macro_str1);
-
}
/* return next token with macro substitution */
@@ -3434,7 +3550,7 @@ ST_FUNC void next(void)
if (s) {
Sym *nested_list = NULL;
tokstr_buf.len = 0;
- macro_subst_tok(&tokstr_buf, &nested_list, s, 1);
+ macro_subst_tok(&tokstr_buf, &nested_list, s);
tok_str_add(&tokstr_buf, 0);
begin_macro(&tokstr_buf, 2);
goto redo;
@@ -3462,41 +3578,57 @@ ST_INLN void unget_tok(int last_tok)
tok = last_tok;
}
-ST_FUNC void preprocess_start(TCCState *s1)
+ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
{
- char *buf;
+ CString cstr;
+ int i;
+
s1->include_stack_ptr = s1->include_stack;
- /* XXX: move that before to avoid having to initialize
- file->ifdef_stack_ptr ? */
s1->ifdef_stack_ptr = s1->ifdef_stack;
file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
+ pp_expr = 0;
+ 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('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
- buf = tcc_malloc(3 + strlen(file->filename));
- sprintf(buf, "\"%s\"", file->filename);
- tcc_undefine_symbol(s1, "__BASE_FILE__");
- tcc_define_symbol(s1, "__BASE_FILE__", buf);
- tcc_free(buf);
- if (s1->nb_cmd_include_files) {
- CString cstr;
- int i;
- cstr_new(&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);
- }
+ 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) {
*s1->include_stack_ptr++ = file;
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;
+}
+
+/* cleanup from error/setjmp */
+ST_FUNC void preprocess_end(TCCState *s1)
+{
+ while (macro_stack)
+ end_macro();
+ macro_ptr = NULL;
}
ST_FUNC void tccpp_new(TCCState *s)
@@ -3506,6 +3638,7 @@ ST_FUNC void tccpp_new(TCCState *s)
/* 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++)
@@ -3550,11 +3683,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
/* free -D and compiler defines */
free_defines(NULL);
- /* cleanup from error/setjmp */
- while (macro_stack)
- end_macro();
- macro_ptr = NULL;
-
/* free tokens */
n = tok_ident - TOK_IDENT;
for(i = 0; i < n; i++)
@@ -3565,6 +3693,7 @@ ST_FUNC void tccpp_delete(TCCState *s)
/* free static buffers */
cstr_free(&tokcstr);
cstr_free(&cstr_buf);
+ cstr_free(&macro_equal_buf);
tok_str_free_str(tokstr_buf.str);
/* free allocators */
@@ -3582,19 +3711,16 @@ ST_FUNC void tccpp_delete(TCCState *s)
static void tok_print(const char *msg, const int *str)
{
FILE *fp;
- int t;
+ int t, s = 0;
CValue cval;
fp = tcc_state->ppfp;
- if (!fp || !tcc_state->dflag)
- fp = stdout;
-
- fprintf(fp, "%s ", msg);
+ fprintf(fp, "%s", msg);
while (str) {
TOK_GET(&t, &str, &cval);
if (!t)
break;
- fprintf(fp,"%s", get_tok_str(t, &cval));
+ fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1;
}
fprintf(fp, "\n");
}
@@ -3689,6 +3815,7 @@ static int pp_need_space(int a, int b)
: '+' == a ? TOK_INC == b || '+' == b
: '-' == a ? TOK_DEC == b || '-' == b
: a >= TOK_IDENT ? b >= TOK_IDENT
+ : a == TOK_PPNUM ? b >= TOK_IDENT
: 0;
}
@@ -3706,29 +3833,23 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
BufferedFile **iptr;
int token_seen, spcs, level;
const char *p;
- Sym *define_start;
+ char white[400];
- preprocess_start(s1);
- ch = file->buf_ptr[0];
- tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_PREPROCESS
| (parse_flags & PARSE_FLAG_ASM_FILE)
| PARSE_FLAG_LINEFEED
| PARSE_FLAG_SPACES
| PARSE_FLAG_ACCEPT_STRAYS
;
- define_start = define_stack;
-
/* Credits to Fabrice Bellard's initial revision to demonstrate its
capability to compile and run itself, provided all numbers are
given as decimals. tcc -E -P10 will do. */
- if (s1->Pflag == 1 + 10)
+ 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);
- free_defines(define_start);
return 0;
#endif
@@ -3739,48 +3860,43 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
token_seen = TOK_LINEFEED, spcs = 0;
pp_line(s1, file, 0);
-
for (;;) {
iptr = s1->include_stack_ptr;
next();
if (tok == TOK_EOF)
break;
+
level = s1->include_stack_ptr - iptr;
if (level) {
if (level > 0)
pp_line(s1, *iptr, 0);
pp_line(s1, file, level);
}
-
- if (s1->dflag) {
+ if (s1->dflag & 7) {
pp_debug_defines(s1);
if (s1->dflag & 4)
continue;
}
- if (token_seen == TOK_LINEFEED) {
- if (tok == ' ') {
- ++spcs;
- continue;
- }
- if (tok == TOK_LINEFEED) {
- spcs = 0;
- continue;
- }
- pp_line(s1, file, 0);
+ if (is_space(tok)) {
+ if (spcs < sizeof white - 1)
+ white[spcs++] = tok;
+ continue;
} else if (tok == TOK_LINEFEED) {
+ spcs = 0;
+ if (token_seen == TOK_LINEFEED)
+ continue;
++file->line_ref;
- } else {
- spcs = pp_need_space(token_seen, tok);
+ } else if (token_seen == TOK_LINEFEED) {
+ pp_line(s1, file, 0);
+ } else if (spcs == 0 && pp_need_space(token_seen, tok)) {
+ white[spcs++] = ' ';
}
- while (spcs)
- fputs(" ", s1->ppfp), --spcs;
+ white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0;
fputs(p = get_tok_str(tok, &tokc), s1->ppfp);
- token_seen = pp_check_he0xE(tok, p);;
+ token_seen = pp_check_he0xE(tok, p);
}
- /* reset define stack, but keep -D and built-ins */
- free_defines(define_start);
return 0;
}
diff --git a/tccrun.c b/tccrun.c
index 7eb47fc..9360164 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -45,60 +45,51 @@ static void set_exception_handler(void);
#endif
static void set_pages_executable(void *ptr, unsigned long length);
-static int tcc_relocate_ex(TCCState *s1, void *ptr);
+static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
#ifdef _WIN64
static void *win64_add_function_table(TCCState *s1);
static void win64_del_function_table(void *);
#endif
-// #define HAVE_SELINUX
-
/* ------------------------------------------------------------- */
/* Do all relocations (needed before using tcc_get_symbol())
Returns -1 on error. */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
{
- int size; void *mem;
+ int size;
+ addr_t ptr_diff = 0;
if (TCC_RELOCATE_AUTO != ptr)
- return tcc_relocate_ex(s1, ptr);
+ return tcc_relocate_ex(s1, ptr, 0);
- size = tcc_relocate_ex(s1, NULL);
+ size = tcc_relocate_ex(s1, NULL, 0);
if (size < 0)
return -1;
#ifdef HAVE_SELINUX
- { /* Use mmap instead of malloc for Selinux. Ref:
- http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
-
- char tmpfname[] = "/tmp/.tccrunXXXXXX";
- int fd = mkstemp (tmpfname);
- void *wr_mem;
-
- unlink (tmpfname);
- ftruncate (fd, size);
-
- wr_mem = mmap (NULL, size, PROT_READ|PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (wr_mem == MAP_FAILED)
- tcc_error("/tmp not writeable");
- mem = mmap (NULL, size, PROT_READ|PROT_EXEC,
- MAP_SHARED, fd, 0);
- if (mem == MAP_FAILED)
- tcc_error("/tmp not executable");
-
- tcc_relocate_ex(s1, wr_mem);
- dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
- dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, wr_mem);
- dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, mem);
- }
+{
+ /* Using mmap instead of malloc */
+ void *prx;
+ char tmpfname[] = "/tmp/.tccrunXXXXXX";
+ int fd = mkstemp(tmpfname);
+ unlink(tmpfname);
+ ftruncate(fd, size);
+
+ ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED || prx == MAP_FAILED)
+ tcc_error("tccrun: could not map memory");
+ 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;
+}
#else
- mem = tcc_malloc(size);
- tcc_relocate_ex(s1, mem); /* no more errors expected */
- dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, mem);
+ ptr = tcc_malloc(size);
#endif
+ tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
+ dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
return 0;
}
@@ -108,13 +99,13 @@ ST_FUNC void tcc_run_free(TCCState *s1)
for (i = 0; i < s1->nb_runtime_mem; ++i) {
#ifdef HAVE_SELINUX
- int size = (int)(addr_t)s1->runtime_mem[i];
- munmap(s1->runtime_mem[++i], size);
- munmap(s1->runtime_mem[++i], size);
+ unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
+ munmap(s1->runtime_mem[i++], size);
+ munmap(s1->runtime_mem[i], size);
#else
-# ifdef _WIN64
+#ifdef _WIN64
win64_del_function_table(*(void**)s1->runtime_mem[i]);
-# endif
+#endif
tcc_free(s1->runtime_mem[i]);
#endif
}
@@ -126,6 +117,9 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
int (*prog_main)(int, char **);
+ s1->runtime_main = "main";
+ if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
+ return 0;
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1;
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
@@ -174,14 +168,19 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
return (*prog_main)(argc, argv);
}
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
+ #define RUN_SECTION_ALIGNMENT 63
+#else
+ #define RUN_SECTION_ALIGNMENT 15
+#endif
+
/* relocate code. Return -1 on error, required size if ptr is NULL,
otherwise copy code into buffer passed by the caller */
-static int tcc_relocate_ex(TCCState *s1, void *ptr)
+static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
{
Section *s;
- unsigned long offset, length;
+ unsigned offset, length, fill, i, k;
addr_t mem;
- int i;
if (NULL == ptr) {
s1->nb_errors = 0;
@@ -189,8 +188,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
pe_output_file(s1, NULL);
#else
tcc_add_runtime(s1);
- relocate_common_syms();
- tcc_add_linker_symbols(s1);
+ resolve_common_syms(s1);
build_got_entries(s1);
#endif
if (s1->nb_errors)
@@ -198,16 +196,38 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
}
offset = 0, mem = (addr_t)ptr;
+ fill = -mem & RUN_SECTION_ALIGNMENT;
#ifdef _WIN64
offset += sizeof (void*);
#endif
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (0 == (s->sh_flags & SHF_ALLOC))
- continue;
- offset = (offset + 15) & ~15;
- s->sh_addr = mem ? mem + offset : 0;
- offset += s->data_offset;
+ for (k = 0; k < 2; ++k) {
+ 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;
+#if 0
+ if (mem)
+ printf("%-16s +%02lx %p %04x\n",
+ s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
+#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 */
@@ -216,7 +236,11 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
return -1;
if (0 == mem)
- return offset;
+ return offset + RUN_SECTION_ALIGNMENT;
+
+#ifdef TCC_TARGET_PE
+ s1->pe_imagebase = mem;
+#endif
/* relocate each section */
for(i = 1; i < s1->nb_sections; i++) {
@@ -226,25 +250,27 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
}
relocate_plt(s1);
-#ifdef _WIN64
- *(void**)ptr = win64_add_function_table(s1);
-#endif
-
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
- // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length);
ptr = (void*)s->sh_addr;
+ if (s->sh_flags & SHF_EXECINSTR)
+ ptr = (char*)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(ptr, length);
+ set_pages_executable((char*)ptr + ptr_diff, length);
}
+
+#ifdef _WIN64
+ *(void**)mem = win64_add_function_table(s1);
+#endif
+
return 0;
}
@@ -257,19 +283,21 @@ static void set_pages_executable(void *ptr, unsigned long length)
unsigned long old_protect;
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
#else
-#ifndef PAGESIZE
-# define PAGESIZE 4096
-#endif
+ void __clear_cache(void *beginning, void *end);
+# ifndef HAVE_SELINUX
addr_t start, end;
+# ifndef PAGESIZE
+# define PAGESIZE 4096
+# endif
start = (addr_t)ptr & ~(PAGESIZE - 1);
end = (addr_t)ptr + length;
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
tcc_error("mprotect failed: did you mean to configure --with-selinux?");
-#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
- { extern void __clear_cache(void *beginning, void *end);
- __clear_cache(ptr, (char *)ptr + length); }
-#endif
+# endif
+# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
+ __clear_cache(ptr, (char *)ptr + length);
+# endif
#endif
}
@@ -282,11 +310,11 @@ static void *win64_add_function_table(TCCState *s1)
RtlAddFunctionTable(
(RUNTIME_FUNCTION*)p,
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
- text_section->sh_addr
+ s1->pe_imagebase
);
s1->uw_pdata = NULL;
}
- return p;;
+ return p;
}
static void win64_del_function_table(void *p)
@@ -415,7 +443,7 @@ no_stabs:
if (wanted_pc >= sym->st_value &&
wanted_pc < sym->st_value + sym->st_size) {
pstrcpy(last_func_name, sizeof(last_func_name),
- (char *) strtab_section->data + sym->st_name);
+ (char *) symtab_section->link->data + sym->st_name);
func_addr = sym->st_value;
goto found;
}
diff --git a/tcctok.h b/tcctok.h
index 775b338..317f64c 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -36,7 +36,9 @@
DEF(TOK_RESTRICT2, "__restrict")
DEF(TOK_RESTRICT3, "__restrict__")
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
-
+
+ DEF(TOK_GENERIC, "_Generic")
+
DEF(TOK_FLOAT, "float")
DEF(TOK_DOUBLE, "double")
DEF(TOK_BOOL, "_Bool")
@@ -85,6 +87,7 @@
DEF(TOK___TIME__, "__TIME__")
DEF(TOK___FUNCTION__, "__FUNCTION__")
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
+ DEF(TOK___COUNTER__, "__COUNTER__")
/* special identifiers */
DEF(TOK___FUNC__, "__func__")
@@ -117,6 +120,8 @@
DEF(TOK_FASTCALL1, "fastcall")
DEF(TOK_FASTCALL2, "__fastcall")
DEF(TOK_FASTCALL3, "__fastcall__")
+ DEF(TOK_REGPARM1, "regparm")
+ DEF(TOK_REGPARM2, "__regparm__")
DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__")
@@ -131,23 +136,19 @@
DEF(TOK_NORETURN2, "__noreturn__")
DEF(TOK_VISIBILITY1, "visibility")
DEF(TOK_VISIBILITY2, "__visibility__")
+
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_choose_expr, "__builtin_choose_expr")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
DEF(TOK_builtin_return_address, "__builtin_return_address")
DEF(TOK_builtin_expect, "__builtin_expect")
-#ifdef TCC_TARGET_X86_64
-#ifdef TCC_TARGET_PE
+ /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
+#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_start, "__builtin_va_start")
-#else
+#elif defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
-#endif
-#endif
- DEF(TOK_REGPARM1, "regparm")
- DEF(TOK_REGPARM2, "__regparm__")
-
-#ifdef TCC_TARGET_ARM64
+#elif defined TCC_TARGET_ARM64
DEF(TOK___va_start, "__va_start")
DEF(TOK___va_arg, "__va_arg")
#endif
@@ -164,6 +165,7 @@
DEF(TOK_push_macro, "push_macro")
DEF(TOK_pop_macro, "pop_macro")
DEF(TOK_once, "once")
+ DEF(TOK_option, "option")
/* builtin functions or variables */
#ifndef TCC_ARM_EABI
@@ -243,7 +245,6 @@
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
DEF(TOK___fixxfdi, "__fixxfdi")
- DEF(TOK___tcc_cvt_ftol, "__tcc_cvt_ftol")
#endif
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
diff --git a/tcctools.c b/tcctools.c
new file mode 100644
index 0000000..1d4424e
--- /dev/null
+++ b/tcctools.c
@@ -0,0 +1,546 @@
+/* -------------------------------------------------------------- */
+/*
+ * TCC - Tiny C Compiler
+ *
+ * tcctools.c - extra tools and and -m32/64 support
+ *
+ */
+
+/* -------------------------------------------------------------- */
+/*
+ * This program is for making libtcc1.a without ar
+ * tiny_libmaker - tiny elf lib maker
+ * usage: tiny_libmaker [lib] files...
+ * Copyright (c) 2007 Timppa
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "tcc.h"
+
+//#define ARMAG "!<arch>\n"
+#define ARFMAG "`\n"
+
+typedef struct {
+ char ar_name[16];
+ char ar_date[12];
+ char ar_uid[6];
+ char ar_gid[6];
+ char ar_mode[8];
+ char ar_size[10];
+ char ar_fmag[2];
+} ArHdr;
+
+static unsigned long le2belong(unsigned long ul) {
+ return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
+ ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
+}
+
+/* Returns 1 if s contains any of the chars of list, else 0 */
+static int contains_any(const char *s, const char *list) {
+ const char *l;
+ for (; *s; s++) {
+ for (l = list; *l; l++) {
+ if (*s == *l)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int ar_usage(int ret) {
+ fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n");
+ fprintf(stderr, "create library ([abdioptxN] not supported).\n");
+ return ret;
+}
+
+ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
+{
+ static ArHdr arhdr = {
+ "/ ",
+ " ",
+ "0 ",
+ "0 ",
+ "0 ",
+ " ",
+ ARFMAG
+ };
+
+ static ArHdr arhdro = {
+ " ",
+ " ",
+ "0 ",
+ "0 ",
+ "0 ",
+ " ",
+ ARFMAG
+ };
+
+ FILE *fi, *fh = NULL, *fo = NULL;
+ ElfW(Ehdr) *ehdr;
+ ElfW(Shdr) *shdr;
+ ElfW(Sym) *sym;
+ int i, fsize, i_lib, i_obj;
+ char *buf, *shstr, *symtab = NULL, *strtab = NULL;
+ int symtabsize = 0;//, strtabsize = 0;
+ char *anames = NULL;
+ int *afpos = NULL;
+ int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
+ char tfile[260], stmp[20];
+ char *file, *name;
+ int ret = 2;
+ const char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored.
+ int verbose = 0;
+
+ i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
+ for (i = 1; i < argc; i++) {
+ const char *a = argv[i];
+ if (*a == '-' && strstr(a, "."))
+ ret = 1; // -x.y is always invalid (same as gnu ar)
+ if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument
+ if (contains_any(a, ops_conflict))
+ ret = 1;
+ if (strstr(a, "v"))
+ verbose = 1;
+ } else { // lib or obj files: don't abort - keep validating all args.
+ if (!i_lib) // first file is the lib
+ i_lib = i;
+ else if (!i_obj) // second file is the first obj
+ i_obj = i;
+ }
+ }
+
+ if (!i_obj) // i_obj implies also i_lib. we require both.
+ ret = 1;
+
+ if (ret == 1)
+ return ar_usage(ret);
+
+ if ((fh = fopen(argv[i_lib], "wb")) == NULL)
+ {
+ fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]);
+ goto the_end;
+ }
+
+ sprintf(tfile, "%s.tmp", argv[i_lib]);
+ if ((fo = fopen(tfile, "wb+")) == NULL)
+ {
+ fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile);
+ goto the_end;
+ }
+
+ funcmax = 250;
+ afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
+ memcpy(&arhdro.ar_mode, "100666", 6);
+
+ // i_obj = first input object file
+ while (i_obj < argc)
+ {
+ if (*argv[i_obj] == '-') { // by now, all options start with '-'
+ i_obj++;
+ continue;
+ }
+ if ((fi = fopen(argv[i_obj], "rb")) == NULL) {
+ fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]);
+ goto the_end;
+ }
+ if (verbose)
+ printf("a - %s\n", argv[i_obj]);
+
+ fseek(fi, 0, SEEK_END);
+ fsize = ftell(fi);
+ fseek(fi, 0, SEEK_SET);
+ buf = tcc_malloc(fsize + 1);
+ fread(buf, fsize, 1, fi);
+ fclose(fi);
+
+ // elf header
+ ehdr = (ElfW(Ehdr) *)buf;
+ if (ehdr->e_ident[4] != ELFCLASSW)
+ {
+ fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]);
+ goto the_end;
+ }
+
+ shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
+ shstr = (char *)(buf + shdr->sh_offset);
+ for (i = 0; i < ehdr->e_shnum; i++)
+ {
+ shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
+ if (!shdr->sh_offset)
+ continue;
+ if (shdr->sh_type == SHT_SYMTAB)
+ {
+ symtab = (char *)(buf + shdr->sh_offset);
+ symtabsize = shdr->sh_size;
+ }
+ if (shdr->sh_type == SHT_STRTAB)
+ {
+ if (!strcmp(shstr + shdr->sh_name, ".strtab"))
+ {
+ strtab = (char *)(buf + shdr->sh_offset);
+ //strtabsize = shdr->sh_size;
+ }
+ }
+ }
+
+ if (symtab && symtabsize)
+ {
+ int nsym = symtabsize / sizeof(ElfW(Sym));
+ //printf("symtab: info size shndx name\n");
+ for (i = 1; i < nsym; i++)
+ {
+ sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
+ if (sym->st_shndx &&
+ (sym->st_info == 0x10
+ || sym->st_info == 0x11
+ || sym->st_info == 0x12
+ )) {
+ //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
+ istrlen = strlen(strtab + sym->st_name)+1;
+ anames = tcc_realloc(anames, strpos+istrlen);
+ strcpy(anames + strpos, strtab + sym->st_name);
+ strpos += istrlen;
+ if (++funccnt >= funcmax) {
+ funcmax += 250;
+ afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more
+ }
+ afpos[funccnt] = fpos;
+ }
+ }
+ }
+
+ file = argv[i_obj];
+ for (name = strchr(file, 0);
+ name > file && name[-1] != '/' && name[-1] != '\\';
+ --name);
+ istrlen = strlen(name);
+ if (istrlen >= sizeof(arhdro.ar_name))
+ istrlen = sizeof(arhdro.ar_name) - 1;
+ memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
+ memcpy(arhdro.ar_name, name, istrlen);
+ arhdro.ar_name[istrlen] = '/';
+ sprintf(stmp, "%-10d", fsize);
+ memcpy(&arhdro.ar_size, stmp, 10);
+ fwrite(&arhdro, sizeof(arhdro), 1, fo);
+ fwrite(buf, fsize, 1, fo);
+ tcc_free(buf);
+ i_obj++;
+ fpos += (fsize + sizeof(arhdro));
+ }
+ hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
+ fpos = 0;
+ if ((hofs & 1)) // align
+ hofs++, fpos = 1;
+ // write header
+ fwrite("!<arch>\n", 8, 1, fh);
+ sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)));
+ memcpy(&arhdr.ar_size, stmp, 10);
+ fwrite(&arhdr, sizeof(arhdr), 1, fh);
+ afpos[0] = le2belong(funccnt);
+ for (i=1; i<=funccnt; i++)
+ afpos[i] = le2belong(afpos[i] + hofs);
+ fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
+ fwrite(anames, strpos, 1, fh);
+ if (fpos)
+ fwrite("", 1, 1, fh);
+ // write objects
+ fseek(fo, 0, SEEK_END);
+ fsize = ftell(fo);
+ fseek(fo, 0, SEEK_SET);
+ buf = tcc_malloc(fsize + 1);
+ fread(buf, fsize, 1, fo);
+ fwrite(buf, fsize, 1, fh);
+ tcc_free(buf);
+ ret = 0;
+the_end:
+ if (anames)
+ tcc_free(anames);
+ if (afpos)
+ tcc_free(afpos);
+ if (fh)
+ fclose(fh);
+ if (fo)
+ fclose(fo), remove(tfile);
+ return ret;
+}
+
+/* -------------------------------------------------------------- */
+/*
+ * tiny_impdef creates an export definition file (.def) from a dll
+ * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
+ *
+ * Copyright (c) 2005,2007 grischka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef TCC_TARGET_PE
+
+ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv)
+{
+ int ret, v, i;
+ char infile[260];
+ char outfile[260];
+
+ const char *file;
+ char *p, *q;
+ FILE *fp, *op;
+
+#ifdef _WIN32
+ char path[260];
+#endif
+
+ infile[0] = outfile[0] = 0;
+ fp = op = NULL;
+ ret = 1;
+ p = NULL;
+ v = 0;
+
+ for (i = 1; i < argc; ++i) {
+ const char *a = argv[i];
+ if ('-' == a[0]) {
+ if (0 == strcmp(a, "-v")) {
+ v = 1;
+ } else if (0 == strcmp(a, "-o")) {
+ if (++i == argc)
+ goto usage;
+ strcpy(outfile, argv[i]);
+ } else
+ goto usage;
+ } else if (0 == infile[0])
+ strcpy(infile, a);
+ else
+ goto usage;
+ }
+
+ if (0 == infile[0]) {
+usage:
+ fprintf(stderr,
+ "usage: tcc -impdef library.dll [-v] [-o outputfile]\n"
+ "create export definition file (.def) from dll\n"
+ );
+ goto the_end;
+ }
+
+ if (0 == outfile[0]) {
+ strcpy(outfile, tcc_basename(infile));
+ q = strrchr(outfile, '.');
+ if (NULL == q)
+ q = strchr(outfile, 0);
+ strcpy(q, ".def");
+ }
+
+ file = infile;
+#ifdef _WIN32
+ if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL))
+ file = path;
+#endif
+ ret = tcc_get_dllexports(file, &p);
+ if (ret || !p) {
+ fprintf(stderr, "tcc: impdef: %s '%s'\n",
+ ret == -1 ? "can't find file" :
+ ret == 1 ? "can't read symbols" :
+ ret == 0 ? "no symbols found in" :
+ "unknown file type", file);
+ ret = 1;
+ goto the_end;
+ }
+
+ if (v)
+ printf("-> %s\n", file);
+
+ op = fopen(outfile, "wb");
+ if (NULL == op) {
+ fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
+ goto the_end;
+ }
+
+ fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file));
+ for (q = p, i = 0; *q; ++i) {
+ fprintf(op, "%s\n", q);
+ q += strlen(q) + 1;
+ }
+
+ if (v)
+ printf("<- %s (%d symbol%s)\n", outfile, i, &"s"[i<2]);
+
+ ret = 0;
+
+the_end:
+ /* cannot free memory received from tcc_get_dllexports
+ if it came from a dll */
+ /* if (p)
+ tcc_free(p); */
+ if (fp)
+ fclose(fp);
+ if (op)
+ fclose(op);
+ return ret;
+}
+
+#endif /* TCC_TARGET_PE */
+
+/* -------------------------------------------------------------- */
+/*
+ * TCC - Tiny C Compiler
+ *
+ * Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
+
+#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
+
+ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
+{
+ tcc_error("-m%d not implemented.", option);
+}
+
+#else
+#ifdef _WIN32
+#include <process.h>
+
+static char *str_replace(const char *str, const char *p, const char *r)
+{
+ const char *s, *s0;
+ char *d, *d0;
+ int sl, pl, rl;
+
+ sl = strlen(str);
+ pl = strlen(p);
+ rl = strlen(r);
+ for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) {
+ for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) {
+ if (d) {
+ memcpy(d, s0, sl = s - s0), d += sl;
+ memcpy(d, r, rl), d += rl;
+ } else
+ sl += rl - pl;
+ }
+ if (d) {
+ strcpy(d, s0);
+ return d0;
+ }
+ }
+}
+
+static int execvp_win32(const char *prog, char **argv)
+{
+ int ret; char **p;
+ /* replace all " by \" */
+ for (p = argv; *p; ++p)
+ if (strchr(*p, '"'))
+ *p = str_replace(*p, "\"", "\\\"");
+ ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
+ if (-1 == ret)
+ return ret;
+ _cwait(&ret, ret, WAIT_CHILD);
+ exit(ret);
+}
+#define execvp execvp_win32
+#endif /* _WIN32 */
+
+ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
+{
+ char program[4096];
+ char *a0 = argv[0];
+ int prefix = tcc_basename(a0) - a0;
+
+ snprintf(program, sizeof program,
+ "%.*s%s"
+#ifdef TCC_TARGET_PE
+ "-win32"
+#endif
+ "-tcc"
+#ifdef _WIN32
+ ".exe"
+#endif
+ , prefix, a0, target == 64 ? "x86_64" : "i386");
+
+ if (strcmp(a0, program))
+ execvp(argv[0] = program, argv);
+ tcc_error("could not run '%s'", program);
+}
+
+#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */
+/* -------------------------------------------------------------- */
+/* enable commandline wildcard expansion (tcc -o x.exe *.c) */
+
+#ifdef _WIN32
+int _CRT_glob = 1;
+#ifndef _CRT_glob
+int _dowildcard = 1;
+#endif
+#endif
+
+/* -------------------------------------------------------------- */
+/* generate xxx.d file */
+
+ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
+{
+ FILE *depout;
+ char buf[1024];
+ int i;
+
+ if (!filename) {
+ /* compute filename automatically: dir/file.o -> dir/file.d */
+ snprintf(buf, sizeof buf, "%.*s.d",
+ (int)(tcc_fileextension(target) - target), target);
+ filename = buf;
+ }
+
+ if (s->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, "\n");
+ fclose(depout);
+}
+
+/* -------------------------------------------------------------- */
diff --git a/tests/Makefile b/tests/Makefile
index a86e8a2..5f6777d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -5,7 +5,7 @@
TOP = ..
include $(TOP)/Makefile
VPATH = $(TOPSRC)/tests $(TOPSRC) $(TOP)
-CFLAGS = -I$(TOPSRC) -I$(TOP)
+CFLAGS := $(filter-out -W% -g% -O%,$(CFLAGS)) -I$(TOPSRC) $(LDFLAGS)
# what tests to run
TESTS = \
@@ -13,9 +13,12 @@ TESTS = \
hello-run \
libtest \
test3 \
+ memtest \
dlltest \
abitest \
+ asm-c-connect-test \
vla_test-run \
+ cross-test \
tests2-dir \
pp-dir
@@ -32,46 +35,39 @@ endif
ifdef CONFIG_WIN32
TESTS := $(filter-out $(BTESTS),$(TESTS))
endif
-ifeq ($(TARGETOS),Darwin)
- TESTS := $(filter-out hello-exe test3 $(BTESTS),$(TESTS))
+ifdef CONFIG_OSX # -run only
+ TESTS := hello-run libtest tests2-dir pp-dir
endif
-ifeq (,$(filter arm64 i386 x86-64,$(ARCH)))
+ifeq (,$(filter arm64 i386 x86_64,$(ARCH)))
TESTS := $(filter-out vla_test-run,$(TESTS))
endif
ifeq ($(CONFIG_arm_eabi),yes)
TESTS := $(filter-out test3,$(TESTS))
endif
-ifeq (,$(filter i386 x86-64,$(ARCH)))
- TESTS := $(filter-out dlltest,$(TESTS))
+ifeq (,$(filter i386 x86_64,$(ARCH)))
+ TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
endif
-
-# run local version of tcc with local libraries and includes
-TCCFLAGS = -B$(TOP) -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP)
-ifdef CONFIG_WIN32
- TCCFLAGS = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP) -L$(TOP)
- PATH := $(CURDIR)/$(TOP):$(PATH) # for libtcc_test to find libtcc.dll
+ifndef CONFIG_cross
+ TESTS := $(filter-out cross-%,$(TESTS))
endif
-TCC = $(TOP)/tcc $(TCCFLAGS)
-RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS)
-
-ifeq ($(TARGETOS),Darwin)
- CFLAGS += -Wl,-flat_namespace,-undefined,warning
- TCCFLAGS += -D_ANSI_SOURCE
- export MACOSX_DEPLOYMENT_TARGET:=10.2
+ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
+ PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
endif
+RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
+DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
all test : clean-s $(TESTS)
hello-exe: ../examples/ex1.c
@echo ------------ $@ ------------
- $(TCC) $< -o hello$(EXESUF) || ($(TOP)/tcc -vv; exit 1) && ./hello$(EXESUF)
+ $(TCC) $< -o hello$(EXESUF) && ./hello$(EXESUF) || $(DUMPTCC)
hello-run: ../examples/ex1.c
@echo ------------ $@ ------------
- $(TCC) -run $<
+ $(TCC) -run $< || $(DUMPTCC)
libtest: libtcc_test$(EXESUF)
@echo ------------ $@ ------------
@@ -133,18 +129,24 @@ test4: tcctest.c test.ref
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@echo ------------ $@ ------------
- $(TCC) -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL ../libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
- $(TCC) $(NATIVE_DEFINES) ../tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
- ./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run ../examples/ex1.c
+ $(TCC) $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
+ $(TCC) $(NATIVE_DEFINES) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
+ ./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
ifndef CONFIG_WIN32
@echo ------------ $@ with PIC ------------
- $(CC) $(CFLAGS) -fPIC -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c ../libtcc.c
+ $(CC) $(CFLAGS) -fPIC $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
$(TCC) libtcc.o $(LIBS) -shared -o libtcc2$(DLLSUF)
- $(TCC) $(NATIVE_DEFINES) ../tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
- ./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run ../examples/ex1.c
+ $(TCC) $(NATIVE_DEFINES) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
+ ./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
endif
@rm tcc2$(EXESUF) libtcc2$(DLLSUF)
+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
+
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14
@@ -180,7 +182,7 @@ speedtest: ex2 ex3
weaktest: tcctest.c test.ref
$(TCC) -c $< -o weaktest.tcc.o
- $(CC) -c $< -o weaktest.gcc.o -I. $(CFLAGS)
+ $(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
objdump -t weaktest.gcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.gcc.o.txt
diff weaktest.gcc.o.txt weaktest.tcc.o.txt && echo "Weak Auto Test OK"
@@ -208,7 +210,7 @@ abitest-cc$(EXESUF): abitest.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
abitest-tcc$(EXESUF): abitest.c libtcc.c
- $(TCC) -o $@ $^ $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS)
+ $(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS)
ABITESTS := abitest-cc$(EXESUF)
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
@@ -229,6 +231,35 @@ vla_test-run: vla_test$(EXESUF)
@echo ------------ $@ ------------
./vla_test$(EXESUF)
+asm-c-connect$(EXESUF): asm-c-connect-1.c asm-c-connect-2.c
+ $(TCC) -o $@ $^
+
+asm-c-connect-%.o: asm-c-connect-%.c
+ $(TCC) -c -o $@ $<
+
+asm-c-connect-sep$(EXESUF): asm-c-connect-1.o asm-c-connect-2.o
+ $(TCC) -o $@ $^
+
+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"
+
+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"
+
# targets for development
%.bin: %.c tcc
$(TCC) -g -o $@ $<
@@ -246,10 +277,12 @@ cache: tcc_g
# clean
clean:
- rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc \
-*-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234] ex? tcc_g
- $(MAKE) -C tests2 $@
- $(MAKE) -C pp $@
+ 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
+ @$(MAKE) -C tests2 $@
+ @$(MAKE) -C pp $@
# silent clean, used before running tests
clean-s:
diff --git a/tests/abitest.c b/tests/abitest.c
index 896e97b..4a192bd 100644
--- a/tests/abitest.c
+++ b/tests/abitest.c
@@ -425,7 +425,7 @@ static int two_member_union_test(void) {
}
/*
- * Win64 calling convetntion test.
+ * Win64 calling convention test.
*/
typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
@@ -558,6 +558,36 @@ static int stdarg_test(void) {
return run_callback(src, stdarg_test_callback);
}
+typedef struct {long long a, b;} stdarg_many_test_struct_type;
+typedef void (*stdarg_many_test_function_type) (int, int, int, int, int,
+ stdarg_many_test_struct_type,
+ int, int, ...);
+
+static int stdarg_many_test_callback(void *ptr)
+{
+ stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr;
+ int x;
+ stdarg_many_test_struct_type l = {10, 11};
+ f(1, 2, 3, 4, 5, l, 6, 7, &x, 44);
+ return x == 44 ? 0 : -1;
+}
+
+static int stdarg_many_test(void)
+{
+ const char *src =
+ "#include <stdarg.h>\n"
+ "typedef struct {long long a, b;} stdarg_many_test_struct_type;\n"
+ "void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n"
+ " va_list ap;\n"
+ " int *p;\n"
+ " va_start (ap, g);\n"
+ " p = va_arg(ap, int*);\n"
+ " *p = va_arg(ap, int);\n"
+ " va_end (ap);\n"
+ "}\n";
+ return run_callback(src, stdarg_many_test_callback);
+}
+
/*
* Test Win32 stdarg handling, since the calling convention will pass a pointer
* to the struct and the stdarg pointer must point to that pointer initially.
@@ -637,10 +667,13 @@ int main(int argc, char **argv) {
RUN_TEST(ret_longdouble_test);
RUN_TEST(ret_2float_test);
RUN_TEST(ret_2double_test);
- /* RUN_TEST(ret_8plus2double_test); currently broken on x86_64 */
- /* RUN_TEST(ret_6plus2longlong_test); currently broken on x86_64 */
- /* RUN_TEST(ret_mixed_test); currently broken on x86_64 */
- /* RUN_TEST(ret_mixed2_test); currently broken on x86_64 */
+ RUN_TEST(ret_8plus2double_test);
+ RUN_TEST(ret_6plus2longlong_test);
+#if !defined __x86_64__ || defined _WIN32
+ /* currently broken on x86_64 linux */
+ RUN_TEST(ret_mixed_test);
+ RUN_TEST(ret_mixed2_test);
+#endif
RUN_TEST(ret_mixed3_test);
RUN_TEST(reg_pack_test);
RUN_TEST(reg_pack_longlong_test);
@@ -651,6 +684,7 @@ int main(int argc, char **argv) {
RUN_TEST(many_struct_test_2);
RUN_TEST(many_struct_test_3);
RUN_TEST(stdarg_test);
+ RUN_TEST(stdarg_many_test);
RUN_TEST(stdarg_struct_test);
RUN_TEST(arg_align_test);
return retval;
diff --git a/tests/asm-c-connect-1.c b/tests/asm-c-connect-1.c
new file mode 100644
index 0000000..8a28d78
--- /dev/null
+++ b/tests/asm-c-connect-1.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+
+#if defined _WIN32 && !defined __TINYC__
+# define _ "_"
+#else
+# define _
+#endif
+
+static int x1_c(void)
+{
+ printf(" x1");
+ return 1;
+}
+
+asm(".text;"_"x1: call "_"x1_c; ret");
+
+void callx4(void);
+void callx5_again(void);
+
+void x6()
+{
+ printf(" x6-1");
+}
+
+int main(int argc, char *argv[])
+{
+ printf("*");
+ asm("call "_"x1");
+ asm("call "_"x2");
+ asm("call "_"x3");
+ callx4();
+ asm("call "_"x5");
+ callx5_again();
+ x6();
+ printf(" *\n");
+ return 0;
+}
+
+static
+int x2(void)
+{
+ printf(" x2");
+ return 2;
+}
+
+extern int x3(void);
+
+void x4(void)
+{
+ printf(" x4");
+}
+
+void x5(void);
+void x5(void)
+{
+ printf(" x5");
+}
diff --git a/tests/asm-c-connect-2.c b/tests/asm-c-connect-2.c
new file mode 100644
index 0000000..3440b40
--- /dev/null
+++ b/tests/asm-c-connect-2.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+
+#if defined _WIN32 && !defined __TINYC__
+# define _ "_"
+#else
+# define _
+#endif
+
+int x3(void)
+{
+ printf(" x3");
+ return 3;
+}
+
+/* That callx4 is defined globally (as if ".globl callx4")
+ is a TCC extension. GCC doesn't behave like this. */
+void callx4(void);
+__asm__(_"callx4: call "_"x4; ret;"
+#ifndef __TINYC__
+ " .global "_"callx4"
+#endif
+);
+
+extern void x5(void);
+
+void callx5_again(void);
+void callx5_again(void)
+{
+ x5();
+ asm("call "_"x6");
+}
+
+static void x6()
+{
+ printf(" x6-2");
+}
diff --git a/tests/asmtest.S b/tests/asmtest.S
index 280aeaf..e9c0e32 100644
--- a/tests/asmtest.S
+++ b/tests/asmtest.S
@@ -114,12 +114,21 @@ notl %r15d
movzb 0x1000, %eax
movzb 0x1000, %ax
+ mov $0x12345678,%eax
+
#ifdef __x86_64__
movzb 0x1000, %rax
movzbq 0x1000, %rbx
movsbq 0x1000, %rdx
movzwq 0x1000, %rdi
movswq 0x1000, %rdx
+ movslq %eax, %rcx
+ mov $0x12345678,%rax
+ mov $0x12345678,%rdx
+ mov $0x12345678,%r10
+ mov $0x123456789abcdef0,%rax
+ mov $0x123456789abcdef0,%rcx
+ mov $0x123456789abcdef0,%r11
#endif
#ifdef __i386__
@@ -546,6 +555,7 @@ invlpg 0x1000
cmpxchg8b 0x1002
#ifdef __x86_64__
cmpxchg16b (%rax)
+cmpxchg16b (%r10,%r11)
#endif
fcmovb %st(5), %st
@@ -567,9 +577,13 @@ fucomip %st(5), %st
cmovs 0x1000, %eax
cmovns %edx, %edi
cmovne %ax, %si
+ cmovbw %ax, %di
+ cmovnbel %edx, %ecx
#ifdef __x86_64__
bswapq %rsi
+ bswapq %r10
cmovz %rdi,%rbx
+ cmovpeq %rsi, %rdx
#endif
int $3
@@ -675,7 +689,9 @@ int $0x10
prefetchw (%rdi)
clflush 0x1000(%rax,%rcx)
fxsaveq (%rdx)
+ fxsaveq (%r11)
fxrstorq (%rcx)
+ fxrstorq (%r10)
#endif
@@ -751,6 +767,9 @@ int $0x10
sidtq 0x1000
swapgs
+
+ str %rdx
+ str %r9
#endif
lmsw 0x1000
@@ -879,6 +898,7 @@ overrideme:
#ifdef __x86_64__
movq %rcx, %mm1
movq %rdx, %xmm2
+ movq %r13, %xmm3
/* movq mem64->xmm is encoded as f30f7e by GAS, but as
660f6e by tcc (which really is a movd and would need
a REX.W prefix to be movq). */
diff --git a/tests/gcctestsuite.sh b/tests/gcctestsuite.sh
index f3cc538..f3cc538 100644..100755
--- a/tests/gcctestsuite.sh
+++ b/tests/gcctestsuite.sh
diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c
index be5db61..480d314 100644
--- a/tests/libtcc_test.c
+++ b/tests/libtcc_test.c
@@ -15,11 +15,15 @@ int add(int a, int b)
return a + b;
}
+/* this strinc is referenced by the generated code */
const char hello[] = "Hello World!";
char my_program[] =
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
"extern int add(int a, int b);\n"
+"#ifdef _WIN32\n" /* dynamically linked data needs 'dllimport' */
+" __attribute__((dllimport))\n"
+"#endif\n"
"extern const char hello[];\n"
"int fib(int n)\n"
"{\n"
diff --git a/tests/pp/13.expect b/tests/pp/13.expect
index 6eb2bec..c7a3230 100644
--- a/tests/pp/13.expect
+++ b/tests/pp/13.expect
@@ -1,3 +1,2 @@
-# `modelist' label. Each video mode record looks like:
.text
endtext:
diff --git a/tests/pp/15.c b/tests/pp/15.c
index d989bee..cf13f9a 100644
--- a/tests/pp/15.c
+++ b/tests/pp/15.c
@@ -12,7 +12,7 @@ return n(A)n(++)n(+)n(+)n(B);
return n(0x1E)n(-1);
// unlike gcc but correct
-XXX: return n(x)+n(x)-n(1)+n(1)-2;
+// XXX: return n(x)+n(x)-n(1)+n(1)-2;
-// unlile gcc, but cannot appear in valid C
-XXX: return n(x)n(x)n(1)n(2)n(x);
+// unlike gcc, but cannot appear in valid C
+// XXX: return n(x)n(x)n(1)n(2)n(x);
diff --git a/tests/pp/15.expect b/tests/pp/15.expect
index f652240..b4f885e 100644
--- a/tests/pp/15.expect
+++ b/tests/pp/15.expect
@@ -3,5 +3,3 @@ return A+++B;
return A+ ++B;
return A+++ +B;
return 0x1E -1;
-XXX: return x+x-1 +1 -2;
-XXX: return x x 1 2 x;
diff --git a/tests/pp/18.c b/tests/pp/18.c
new file mode 100644
index 0000000..0961426
--- /dev/null
+++ b/tests/pp/18.c
@@ -0,0 +1,15 @@
+#define M_RETI_ARG27(x,y,z,aa, ...) aa
+#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
+#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 0, useless)
+#define M_EMPTYI_DETECT(...) 0, 1,
+#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ () )
+#define EX
+#define empty(x)
+#define fnlike(x) yeah x
+/* If the following macro is called with empty arg (X183), the use
+ of 'x' between fnlike and '(' doesn't hinder the recognition of this
+ being a further fnlike macro invocation. */
+#define usefnlike(x) fnlike x (x)
+X181 M_EMPTYI_P_C1()
+X182 M_EMPTYI_P_C1(x)
+X183 usefnlike()
diff --git a/tests/pp/18.expect b/tests/pp/18.expect
new file mode 100644
index 0000000..447a9b2
--- /dev/null
+++ b/tests/pp/18.expect
@@ -0,0 +1,3 @@
+X181 1
+X182 0
+X183 yeah
diff --git a/tests/pp/19.c b/tests/pp/19.c
new file mode 100644
index 0000000..aa91abe
--- /dev/null
+++ b/tests/pp/19.c
@@ -0,0 +1,101 @@
+#define M_C2I(a, ...) a ## __VA_ARGS__
+#define M_C(a, ...) M_C2I(a, __VA_ARGS__)
+#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__
+#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__)
+
+#define M_RETI_ARG2(a, b, ...) b
+#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
+#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa
+#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
+
+#define M_TOBOOLI_0 1, 0,
+#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless)
+
+#define M_IFI_0(true_macro, ...) __VA_ARGS__
+#define M_IFI_1(true_macro, ...) true_macro
+#define M_IF(c) M_C(M_IFI_, M_BOOL(c))
+
+#define M_FLAT(...) __VA_ARGS__
+#define M_INVI_0 1
+#define M_INVI_1 0
+#define M_INV(x) M_C(M_INVI_, x)
+
+#define M_ANDI_00 0
+#define M_ANDI_01 0
+#define M_ANDI_10 0
+#define M_ANDI_11 1
+#define M_AND(x,y) M_C3(M_ANDI_, x, y)
+
+#define M_ORI_00 0
+#define M_ORI_01 1
+#define M_ORI_10 1
+#define M_ORI_11 1
+#define M_OR(x,y) M_C3(M_ORI_, x, y)
+
+#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless)
+
+#define M_EMPTYI_DETECT(...) 0, 1,
+#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ())
+#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__)
+#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () )
+#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__))))
+#define M_APPLY_FUNC2B(func, arg1, arg2) \
+ M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2))
+#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \
+ M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \
+ M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \
+ M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \
+ M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \
+ M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \
+ M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \
+ M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \
+ M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \
+ M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z)
+#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , )
+#define M_INIT_INIT(a) ,a,
+
+#define M_GET_METHOD(method, method_default, ...) \
+ M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,)
+
+#define M_TEST_METHOD_P(method, oplist) \
+ M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist))
+
+#define TRUE 1
+#define TEST1(n) \
+ M_IF(n)(ok,nok)
+#define TEST2(op) \
+ M_TEST_METHOD_P(INIT, op)
+#define TEST3(op) \
+ M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok)
+#define TEST4(op) \
+ TEST1(TEST2(op))
+#define KO(a) ((void)1)
+
+/* This checks that the various expansions that ultimately lead to
+ something like 'KO(arg,arg)', where 'KO' comes from a macro
+ expansion reducing from a large macro chain do not are regarded
+ as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO',
+ but X95 must not consume the (a,b) arguments outside the M_IF()
+ invocation to reduce the 'KO' macro to an invocation. Instead
+ X95 should reduce via M_IF(KO)(a,b) to 'a'.
+
+ The other lines here are variations on this scheme, with X1 to
+ X6 coming from the bug report at
+ http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */
+X92 M_IF(KO)
+X93 M_GET_METHOD(INIT, 0, INIT(KO))
+X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))
+X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b)
+X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))
+X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok)
+X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
+X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
+// test begins
+X1 TEST1(TRUE) // ==> expect ok, get ok
+// First test with a token which is not a macro
+X2 TEST2((INIT(ok))) // ==> expect 1, get 1
+X3 TEST3((INIT(ok))) // ==> expect ok, get ok
+// Then test with a token which is a macro, but should not be expanded.
+X4 TEST2((INIT(KO))) // ==> expect 1, get 1
+X5 TEST4(INIT(KO))
+X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args"
diff --git a/tests/pp/19.expect b/tests/pp/19.expect
new file mode 100644
index 0000000..08c0858
--- /dev/null
+++ b/tests/pp/19.expect
@@ -0,0 +1,14 @@
+X92 M_IFI_1
+X93 KO
+X94 KO
+X95 a
+X96 M_IFI_1
+X97 ok
+X98 (1)(ok, nok)
+X99 ok
+X1 ok
+X2 1
+X3 ok
+X4 1
+X5 nok
+X6 ok
diff --git a/tests/pp/20.c b/tests/pp/20.c
new file mode 100644
index 0000000..7944d62
--- /dev/null
+++ b/tests/pp/20.c
@@ -0,0 +1,13 @@
+/* Various things I encountered while hacking the pre processor */
+#define wrap(x) x
+#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__)
+#define pr_warn(x,y) pr_warning(x,y)
+#define net_ratelimited_function(function, ...) function(__VA_ARGS__)
+X1 net_ratelimited_function(pr_warn, "pipapo", bla);
+X2 net_ratelimited_function(wrap(pr_warn), "bla", foo);
+#define two m n
+#define chain4(a,b,c,d) a ## b ## c ## d
+X2 chain4(two,o,p,q)
+X3 chain4(o,two,p,q)
+X4 chain4(o,p,two,q)
+X5 chain4(o,p,q,two)
diff --git a/tests/pp/20.expect b/tests/pp/20.expect
new file mode 100644
index 0000000..d19405d
--- /dev/null
+++ b/tests/pp/20.expect
@@ -0,0 +1,6 @@
+X1 printk(KERN_WARNING "pipapo",bla);
+X2 printk(KERN_WARNING "bla",foo);
+X2 twoopq
+X3 otwopq
+X4 optwoq
+X5 opqtwo
diff --git a/tests/pp/21.c b/tests/pp/21.c
new file mode 100644
index 0000000..1316226
--- /dev/null
+++ b/tests/pp/21.c
@@ -0,0 +1,36 @@
+/* accept 'defined' as result of substitution */
+
+----- 1 ------
+#define AAA 2
+#define BBB
+#define CCC (defined ( AAA ) && AAA > 1 && !defined BBB)
+#if !CCC
+OK
+#else
+NOT OK
+#endif
+
+----- 2 ------
+#undef BBB
+#if CCC
+OK
+#else
+NOT OK
+#endif
+
+----- 3 ------
+#define DEFINED defined
+#define DDD (DEFINED ( AAA ) && AAA > 1 && !DEFINED BBB)
+#if (DDD)
+OK
+#else
+NOT OK
+#endif
+
+----- 4 ------
+#undef AAA
+#if !(DDD)
+OK
+#else
+NOT OK
+#endif
diff --git a/tests/pp/21.expect b/tests/pp/21.expect
new file mode 100644
index 0000000..5a1376b
--- /dev/null
+++ b/tests/pp/21.expect
@@ -0,0 +1,8 @@
+----- 1 ------
+OK
+----- 2 ------
+OK
+----- 3 ------
+OK
+----- 4 ------
+OK
diff --git a/tests/pp/Makefile b/tests/pp/Makefile
index 4a77035..687aa52 100644
--- a/tests/pp/Makefile
+++ b/tests/pp/Makefile
@@ -3,36 +3,35 @@
#
TOP = ../..
-include $(TOP)/config.mak
+include $(TOP)/Makefile
SRC = $(TOPSRC)/tests/pp
VPATH = $(SRC)
-TCC = ../../tcc
files = $(patsubst %.$1,%.test,$(notdir $(wildcard $(SRC)/*.$1)))
TESTS = $(call files,c) $(call files,S)
all test : $(sort $(TESTS))
-DIFF_OPTS = -Nu -b -B -I "^\#"
+DIFF_OPTS = -Nu -b -B
+
+# Filter source directory in warnings/errors (out-of-tree builds)
+FILTER = 2>&1 | sed 's,$(SRC)/,,g'
%.test: %.c %.expect
@echo PPTest $* ...
- -@$(TCC) -E -P $< >$*.output 2>&1 ; \
+ -@$(TCC) -E -P $< $(FILTER) >$*.output 2>&1 ; \
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
&& rm -f $*.output
%.test: %.S %.expect
@echo PPTest $* ...
- -@$(TCC) -E -P $< >$*.output 2>&1 ; \
+ -@$(TCC) -E -P $< $(FILTER) >$*.output 2>&1 ; \
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
&& rm -f $*.output
# automatically generate .expect files with gcc:
-%.expect: %.c
- gcc -E -P $< >$*.expect 2>&1
-
-%.expect: %.S
- gcc -E -P $< >$*.expect 2>&1
+%.expect: # %.c
+ gcc -E -P $*.[cS] >$*.expect 2>&1
# tell make not to delete
.PRECIOUS: %.expect
@@ -41,7 +40,7 @@ clean:
rm -f *.output
02.test : DIFF_OPTS += -w
-15.test : DIFF_OPTS += -I"^XXX:"
+# 15.test : DIFF_OPTS += -I"^XXX:"
# diff options:
# -b ighore space changes
diff --git a/tests/pp/pp-counter.c b/tests/pp/pp-counter.c
new file mode 100644
index 0000000..3978e1a
--- /dev/null
+++ b/tests/pp/pp-counter.c
@@ -0,0 +1,27 @@
+X1 __COUNTER__
+X2 __COUNTER__
+#if __COUNTER__
+X3 __COUNTER__
+#endif
+#define pass(x) x
+#define a x __COUNTER__ y
+#define a2 pass(__COUNTER__)
+#define f(c) c __COUNTER__
+#define apply(d) d d __COUNTER__ x2 f(d) y2 __COUNTER__
+#define _paste(a,b) a ## b
+#define paste(a,b) _paste(a,b)
+#define _paste3(a,b,c) a ## b ## c
+#define doublepaste(a,b) _paste3(a,b,b)
+#define str(x) #x
+X4 a
+X5 f(a)
+X6 f(b)
+X7 f(__COUNTER__)
+X8 apply(a)
+X9 apply(f(a))
+X10 apply(__COUNTER__)
+X11 apply(a2)
+X12 str(__COUNTER__)
+X13 paste(x,__COUNTER__)
+X14 _paste(x,__COUNTER__)
+X15 doublepaste(x,__COUNTER__)
diff --git a/tests/pp/pp-counter.expect b/tests/pp/pp-counter.expect
new file mode 100644
index 0000000..02fc535
--- /dev/null
+++ b/tests/pp/pp-counter.expect
@@ -0,0 +1,15 @@
+X1 0
+X2 1
+X3 3
+X4 x 4 y
+X5 x 5 y 6
+X6 b 7
+X7 8 9
+X8 x 10 y x 10 y 11 x2 x 10 y 12 y2 13
+X9 x 14 y 15 x 14 y 15 16 x2 x 14 y 15 17 y2 18
+X10 19 19 20 x2 19 21 y2 22
+X11 23 23 24 x2 23 25 y2 26
+X12 "__COUNTER__"
+X13 x27
+X14 x__COUNTER__
+X15 x2828
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 23fa9f9..3e0ae8b 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -176,6 +176,11 @@ static int onetwothree = 123;
#define B3 4
#endif
+#ifdef __TINYC__
+/* We try to handle this syntax. Make at least sure it doesn't segfault. */
+char invalid_function_def()[] {}
+#endif
+
#define __INT64_C(c) c ## LL
#define INT64_MIN (-__INT64_C(9223372036854775807)-1)
@@ -379,7 +384,7 @@ void macro_test(void)
MF_s("hi");
MF_t("hi");
- /* test macro substituion inside args (should not eat stream) */
+ /* test macro substitution inside args (should not eat stream) */
printf("qq=%d\n", qq(qq)(2));
/* test zero argument case. NOTE: gcc 2.95.x does not accept a
@@ -399,7 +404,7 @@ comment
substituted */
TEST2();
- /* And again when the name and parenthes are separated by a
+ /* And again when the name and parentheses are separated by a
comment. */
TEST2 /* the comment */ ();
@@ -1045,8 +1050,8 @@ int pad1;
but __alignof__ returns the wrong result (4) because we
can't store the alignment yet when specified on symbols
directly (it's stored in the type so we'd need to make
- a copy of it).
-struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
+ a copy of it). -- FIXED */
+struct aligntest7 altest7[2] __attribute__((aligned(16)));
struct aligntest8
{
@@ -1156,8 +1161,8 @@ void struct_test()
sizeof(altest5), __alignof__(altest5));
printf("altest6 sizeof=%d alignof=%d\n",
sizeof(altest6), __alignof__(altest6));
- /*printf("altest7 sizeof=%d alignof=%d\n",
- sizeof(altest7), __alignof__(altest7));*/
+ printf("altest7 sizeof=%d alignof=%d\n",
+ sizeof(altest7), __alignof__(altest7));
/* empty structures (GCC extension) */
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
@@ -1404,6 +1409,15 @@ void optimize_out(void)
if (defined_function() && 0)
refer_to_undefined();
+ if (0) {
+ (void)sizeof( ({
+ do { } while (0);
+ 0;
+ }) );
+ undefined_function();
+ }
+
+ /* Leave the "if(1)return; printf()" in this order and last in the function */
if (1)
return;
printf ("oor:%d\n", undefined_function());
@@ -1738,6 +1752,8 @@ arrtype2 sinit22 = {5,6,7};
int sinit23[2] = { "astring" ? sizeof("astring") : -1,
&sinit23 ? 42 : -1 };
+extern int external_inited = 42;
+
void init_test(void)
{
int linit1 = 2;
@@ -2028,13 +2044,6 @@ void bitfield_test(void)
else
printf("st1.f2 != -1\n");
-#ifndef __i386__
- /* on i386 we don't correctly support long long bit-fields.
- The bitfields can straddle long long boundaries (at least with
- GCC bitfield layout) and code generation isn't prepared for this
- (would have to work with two words in that case). */
- /* bit sizes below must be bigger than 32 since GCC doesn't allow
- long-long bitfields whose size is not bigger than int */
struct sbf2 {
long long f1 : 45;
long long : 2;
@@ -2047,7 +2056,7 @@ void bitfield_test(void)
st2.f3 = a;
st2.f2++;
printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3);
-#endif
+
#if 0
Disabled for now until further clarification re GCC compatibility
struct sbf3 {
@@ -2060,6 +2069,26 @@ void bitfield_test(void)
} st3;
printf("sizeof(st3) = %d\n", sizeof(st3));
#endif
+
+ struct sbf4 {
+ int x : 31;
+ char y : 2;
+ } st4;
+ st4.y = 1;
+ printf("st4.y == %d\n", st4.y);
+ struct sbf5 {
+ int a;
+ char b;
+ int x : 12, y : 4, : 0, : 4, z : 3;
+ char c;
+ } st5 = { 1, 2, 3, 4, -3, 6 };
+ printf("st5 = %d %d %d %d %d %d\n", st5.a, st5.b, st5.x, st5.y, st5.z, st5.c);
+ struct sbf6 {
+ short x : 12;
+ unsigned char y : 2;
+ } st6;
+ st6.y = 1;
+ printf("st6.y == %d\n", st6.y);
}
#ifdef __x86_64__
@@ -2658,6 +2687,9 @@ int reltab[3] = { 1, 2, 3 };
int *rel1 = &reltab[1];
int *rel2 = &reltab[2];
+#ifdef _WIN64
+void relocation_test(void) {}
+#else
void getmyaddress(void)
{
printf("in getmyaddress\n");
@@ -2686,6 +2718,7 @@ void relocation_test(void)
printf("pa_symbol=0x%lx\n", __pa_symbol() >> 63);
#endif
}
+#endif
void old_style_f(a,b,c)
int a, b;
@@ -2866,6 +2899,11 @@ struct hlist_head {
struct hlist_node *first, *last;
};
+void consume_ulong (unsigned long i)
+{
+ i = 0;
+}
+
void statement_expr_test(void)
{
int a, i;
@@ -2921,6 +2959,9 @@ void statement_expr_test(void)
});
printf ("stmtexpr: %d %d %d\n", t, b, c);
printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last);
+
+ /* Test that we can give out addresses of local labels. */
+ consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
}
void local_label_test(void)
@@ -3076,7 +3117,7 @@ static __inline__ unsigned long long inc64(unsigned long long a)
unsigned long long res;
#ifdef __x86_64__
/* Using the A constraint is wrong, and increments are tested
- elsewere. */
+ elsewhere. */
res = a + 1;
#else
__asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a));
@@ -3118,10 +3159,13 @@ void other_constraints_test(void)
{
unsigned long ret;
int var;
+#ifndef _WIN64
__asm__ volatile ("mov %P1,%0" : "=r" (ret) : "p" (&var));
printf ("oc1: %d\n", ret == (unsigned long)&var);
+#endif
}
+#ifndef _WIN32
/* Test global asm blocks playing with aliases. */
void base_func(void)
{
@@ -3164,6 +3208,36 @@ char * get_asm_string (void)
}
#endif
+/* This checks another constructs with local labels. */
+extern unsigned char alld_stuff[];
+asm(".data\n"
+ ".byte 41\n"
+ "alld_stuff:\n"
+ "661:\n"
+ ".byte 42\n"
+ "662:\n"
+ ".pushsection .data.ignore\n"
+ ".long 661b - .\n" /* This reference to 661 generates an external sym
+ which shouldn't somehow overwrite the offset that's
+ already determined for it. */
+ ".popsection\n"
+ ".byte 662b - 661b\n" /* So that this value is undeniably 1. */);
+
+void asm_local_label_diff (void)
+{
+ printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
+}
+
+/* This checks that static local variables are available from assembler. */
+void asm_local_statics (void)
+{
+ static int localint = 41;
+ asm("incl %0" : "+m" (localint));
+ printf ("asm_local_statics: %d\n", localint);
+}
+#endif
+
+static
unsigned int set;
void fancy_copy (unsigned *in, unsigned *out)
@@ -3176,7 +3250,7 @@ void fancy_copy2 (unsigned *in, unsigned *out)
asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory");
}
-#ifdef __x86_64__
+#if defined __x86_64__ && !defined _WIN64
void clobber_r12(void)
{
asm volatile("mov $1, %%r12" ::: "r12");
@@ -3185,7 +3259,7 @@ void clobber_r12(void)
void test_high_clobbers(void)
{
-#ifdef __x86_64__
+#if defined __x86_64__ && !defined _WIN64
register long val asm("r12");
long val2;
/* This tests if asm clobbers correctly save/restore callee saved
@@ -3251,6 +3325,84 @@ void trace_console(long len, long len2)
}
#endif
}
+
+void test_asm_dead_code(void)
+{
+ long rdi;
+ /* Try to make sure that xdi contains a zero, and hence will
+ lead to a segfault if the next asm is evaluated without
+ arguments being set up. */
+ asm volatile ("" : "=D" (rdi) : "0" (0));
+ (void)sizeof (({
+ int var;
+ /* This shouldn't trigger a segfault, either the argument
+ registers need to be set up and the asm emitted despite
+ this being in an unevaluated context, or both the argument
+ setup _and_ the asm emission need to be suppressed. The latter
+ is better. Disabling asm code gen when suppression is on
+ also fixes the above trace_console bug, but that came earlier
+ than asm suppression. */
+ asm volatile ("movl $0,(%0)" : : "D" (&var) : "memory");
+ var;
+ }));
+}
+
+void test_asm_call(void)
+{
+#if defined __x86_64__ && !defined _WIN64
+ static char str[] = "PATH";
+ char *s;
+ /* This tests if a reference to an undefined symbol from an asm
+ block, which isn't otherwise referenced in this file, is correctly
+ regarded as global symbol, so that it's resolved by other object files
+ or libraries. We chose getenv here, which isn't used anywhere else
+ in this file. (If we used e.g. printf, which is used we already
+ would have a global symbol entry, not triggering the bug which is
+ 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__))
+ "call getenv@plt;"
+#else
+ "call getenv;"
+#endif
+ "pop %%rdi; pop %%rdi"
+ : "=a" (s) : "r" (str));
+ printf("asmd: %s\n", s);
+#endif
+}
+
+#if defined __x86_64__
+# define RX "(%rip)"
+#else
+# define RX
+#endif
+
+void asm_dot_test(void)
+{
+ int x;
+ for (x = 1;; ++x) {
+ int r = x;
+ switch (x) {
+ case 1:
+ asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0");
+ case 2:
+ asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0");
+ case 3:
+ asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4");
+ asm(".text; mov X"RX",%eax; jmp p0");
+ case 4:
+ asm(".data; X=.; .int 789; Y=.; .int 999");
+ asm(".text; mov X"RX",%eax; X=Y; jmp p0");
+ case 0:
+ asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
+ }
+ if (r == x)
+ break;
+ printf("asm_dot_test %d: %d\n", x, r);
+ }
+}
+
void asm_test(void)
{
char buf[128];
@@ -3303,12 +3455,19 @@ void asm_test(void)
printf("set=0x%x\n", set);
val = 0x01020304;
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
+#ifndef _WIN32
override_func1();
override_func2();
/* The base_func ref from the following inline asm should find
the global one, not the local decl from this function. */
asm volatile(".weak override_func3\n.set override_func3, base_func");
override_func3();
+#ifndef __i386__
+ printf("asmstr: %s\n", get_asm_string());
+#endif
+ asm_local_label_diff();
+ asm_local_statics();
+#endif
/* Check that we can also load structs of appropriate layout
into registers. */
asm volatile("" : "=r" (asmret) : "0"(s2));
@@ -3321,9 +3480,6 @@ void asm_test(void)
if (!somebool)
printf("asmbool: failed\n");
#endif
-#ifndef __i386__
- printf("asmstr: %s\n", get_asm_string());
-#endif
val = 43;
fancy_copy (&val, &val2);
printf ("fancycpy(%d)=%d\n", val, val2);
@@ -3334,6 +3490,9 @@ void asm_test(void)
printf ("regvar=%x\n", regvar);
test_high_clobbers();
trace_console(8, 8);
+ test_asm_dead_code();
+ test_asm_call();
+ asm_dot_test();
return;
label1:
goto label2;
@@ -3391,7 +3550,7 @@ void builtin_test(void)
i = sizeof (__builtin_choose_expr (0, ll, s));
printf("bce: %d\n", i);
- printf("bera: %p\n", __builtin_extract_return_addr((void*)43));
+ //printf("bera: %p\n", __builtin_extract_return_addr((void*)43));
}
#ifndef _WIN32
@@ -3661,8 +3820,6 @@ typedef struct __attribute__((__packed__)) {
int c;
} Spacked2;
Spacked2 spacked2;
-/* This doesn't work for now. Requires adjusting field offsets/sizes
- after parsing the struct members. */
typedef struct Spacked3_s {
char a;
short b;
@@ -3681,10 +3838,12 @@ typedef struct gate_struct64 gate_desc;
gate_desc a_gate_desc;
void attrib_test(void)
{
+#ifndef _WIN32
printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc));
+#endif
}
extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
strange_attrib_placement (void);
@@ -3693,3 +3852,24 @@ void * __attribute__((__unused__)) get_void_ptr (void *a)
{
return a;
}
+
+/* This part checks for a bug in TOK_GET (used for inline expansion),
+ where the large long long constant left the the high bits set for
+ the integer constant token. */
+static inline
+int __get_order(unsigned long long size)
+{
+ int order;
+ size -= 0xffff880000000000ULL; // this const left high bits set in the token
+ {
+ struct S { int i : 1; } s; // constructed for this '1'
+ }
+ order = size;
+ return order;
+}
+
+/* This just forces the above inline function to be actually emitted. */
+int force_get_order(unsigned long s)
+{
+ return __get_order(s);
+}
diff --git a/tests/tcctest.py b/tests/tcctest.py
deleted file mode 100644
index 817250f..0000000
--- a/tests/tcctest.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import subprocess
-import sys
-import difflib
-
-def main():
- reference = subprocess.check_output([sys.argv[1]])
- compare = subprocess.check_output(sys.argv[2:])
- failed = False
- for line in difflib.unified_diff(reference.split('\n'), compare.split('\n'), fromfile='cc', tofile='tcc', lineterm=''):
- failed = True
- print line
- sys.exit(1 if failed else 0)
-
-if __name__ == '__main__':
- main()
diff --git a/tests/tests2/17_enum.c b/tests/tests2/17_enum.c
index 0853c42..e2bc736 100644
--- a/tests/tests2/17_enum.c
+++ b/tests/tests2/17_enum.c
@@ -12,9 +12,49 @@ enum fred
h
};
+/* All following uses of enum efoo should compile
+ without warning. While forward enums aren't ISO C,
+ it's accepted by GCC also in strict mode, and only warned
+ about with -pedantic. This happens in the real world. */
+/* Strict ISO C doesn't allow this kind of forward declaration of
+ enums, but GCC accepts it (and gives only pedantic warning), and
+ it occurs in the wild. */
+enum efoo;
+struct Sforward_use {
+ int (*fmember) (enum efoo x);
+};
+
+extern enum efoo it_real_fn(void);
+enum efoo {
+ ONE,
+ TWO,
+};
+struct S2 {
+ enum efoo (*f2) (void);
+};
+void should_compile(struct S2 *s)
+{
+ s->f2 = it_real_fn;
+}
+
+enum efoo it_real_fn(void)
+{
+ return TWO;
+}
+
+static unsigned int deref_uintptr(unsigned int *p)
+{
+ return *p;
+}
+
+enum Epositive {
+ epos_one, epos_two
+};
+
int main()
{
enum fred frod;
+ enum Epositive epos = epos_two;
printf("%d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h);
/* printf("%d\n", frod); */
@@ -23,6 +63,9 @@ int main()
frod = e;
printf("%d\n", frod);
+ /* Following should compile without warning. */
+ printf ("enum to int: %u\n", deref_uintptr(&epos));
+
return 0;
}
diff --git a/tests/tests2/17_enum.expect b/tests/tests2/17_enum.expect
index 0c4e153..d453a61 100644
--- a/tests/tests2/17_enum.expect
+++ b/tests/tests2/17_enum.expect
@@ -1,3 +1,4 @@
0 1 2 3 54 73 74 75
12
54
+enum to int: 1
diff --git a/tests/tests2/39_typedef.c b/tests/tests2/39_typedef.c
index 3878b9c..da73f71 100644
--- a/tests/tests2/39_typedef.c
+++ b/tests/tests2/39_typedef.c
@@ -44,4 +44,22 @@ extern const int cb[1][2][3];
extern B b;
extern int b[1][2][3];
+/* Funny but valid function declaration. */
+typedef int functype (int);
+extern functype func;
+int func(int i)
+{
+ return i + 1;
+}
+
+/* Even funnier function decl and definition using typeof. */
+int set_anon_super(void);
+int set_anon_super(void)
+{
+ return 42;
+}
+typedef int sas_type (void);
+extern typeof(set_anon_super) set_anon_super;
+extern sas_type set_anon_super;
+
/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/
diff --git a/tests/tests2/42_function_pointer.c b/tests/tests2/42_function_pointer.c
index 49c331b..697bd79 100644
--- a/tests/tests2/42_function_pointer.c
+++ b/tests/tests2/42_function_pointer.c
@@ -8,9 +8,13 @@ int fred(int p)
int (*f)(int) = &fred;
+/* To test what this is supposed to test the destination function
+ (fprint here) must not be called directly anywhere in the test. */
+int (*fprintfptr)(FILE *, const char *, ...) = &fprintf;
+
int main()
{
- printf("%d\n", (*f)(24));
+ fprintfptr(stdout, "%d\n", (*f)(24));
return 0;
}
diff --git a/tests/tests2/56_btype_excess-1.c b/tests/tests2/56_btype_excess-1.c
deleted file mode 100644
index 06eabe7..0000000
--- a/tests/tests2/56_btype_excess-1.c
+++ /dev/null
@@ -1 +0,0 @@
-struct A {} int i;
diff --git a/tests/tests2/56_btype_excess-1.expect b/tests/tests2/56_btype_excess-1.expect
deleted file mode 100644
index 4e6d2d7..0000000
--- a/tests/tests2/56_btype_excess-1.expect
+++ /dev/null
@@ -1 +0,0 @@
-56_btype_excess-1.c:1: error: too many basic types
diff --git a/tests/tests2/57_btype_excess-2.c b/tests/tests2/57_btype_excess-2.c
deleted file mode 100644
index ab95c3e..0000000
--- a/tests/tests2/57_btype_excess-2.c
+++ /dev/null
@@ -1 +0,0 @@
-char int i;
diff --git a/tests/tests2/57_btype_excess-2.expect b/tests/tests2/57_btype_excess-2.expect
deleted file mode 100644
index c12ef81..0000000
--- a/tests/tests2/57_btype_excess-2.expect
+++ /dev/null
@@ -1 +0,0 @@
-57_btype_excess-2.c:1: error: too many basic types
diff --git a/tests/tests2/58_function_redefinition.c b/tests/tests2/58_function_redefinition.c
deleted file mode 100644
index 33f16ee..0000000
--- a/tests/tests2/58_function_redefinition.c
+++ /dev/null
@@ -1,9 +0,0 @@
-int f(void)
-{
- return 0;
-}
-
-int f(void)
-{
- return 1;
-}
diff --git a/tests/tests2/58_function_redefinition.expect b/tests/tests2/58_function_redefinition.expect
deleted file mode 100644
index a95a3f0..0000000
--- a/tests/tests2/58_function_redefinition.expect
+++ /dev/null
@@ -1 +0,0 @@
-58_function_redefinition.c:7: error: redefinition of 'f'
diff --git a/tests/tests2/59_function_array.c b/tests/tests2/59_function_array.c
deleted file mode 100644
index 9fcc12d..0000000
--- a/tests/tests2/59_function_array.c
+++ /dev/null
@@ -1 +0,0 @@
-int (*fct)[42](int x);
diff --git a/tests/tests2/59_function_array.expect b/tests/tests2/59_function_array.expect
deleted file mode 100644
index bf62c6e..0000000
--- a/tests/tests2/59_function_array.expect
+++ /dev/null
@@ -1 +0,0 @@
-59_function_array.c:1: error: declaration of an array of functions
diff --git a/tests/tests2/60_enum_redefinition.c b/tests/tests2/60_enum_redefinition.c
deleted file mode 100644
index 2601560..0000000
--- a/tests/tests2/60_enum_redefinition.c
+++ /dev/null
@@ -1,4 +0,0 @@
-enum color {RED, GREEN, BLUE};
-enum color {R, G, B};
-
-enum color c;
diff --git a/tests/tests2/60_enum_redefinition.expect b/tests/tests2/60_enum_redefinition.expect
deleted file mode 100644
index 5cb41bc..0000000
--- a/tests/tests2/60_enum_redefinition.expect
+++ /dev/null
@@ -1 +0,0 @@
-60_enum_redefinition.c:2: error: struct/union/enum already defined
diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c
new file mode 100644
index 0000000..0028caf
--- /dev/null
+++ b/tests/tests2/60_errors_and_warnings.c
@@ -0,0 +1,51 @@
+#if defined test_56_btype_excess_1
+struct A {} int i;
+
+#elif defined test_57_btype_excess_2
+char int i;
+
+#elif defined test_58_function_redefinition
+int f(void) { return 0; }
+int f(void) { return 1; }
+
+#elif defined test_global_redefinition
+int xxx = 1;
+int xxx;
+int xxx = 2;
+
+#elif defined test_59_function_array
+int (*fct)[42](int x);
+
+#elif defined test_60_enum_redefinition
+enum color { RED, GREEN, BLUE };
+enum color { R, G, B };
+enum color c;
+
+#elif defined test_62_enumerator_redefinition
+enum color { RED, GREEN, BLUE };
+enum rgb { RED, G, B};
+enum color c = RED;
+
+#elif defined test_63_local_enumerator_redefinition
+enum {
+ FOO,
+ BAR
+};
+
+int main(void)
+{
+ enum {
+ FOO = 2,
+ BAR
+ };
+
+ return BAR - FOO;
+}
+
+#elif defined test_61_undefined_enum
+enum rgb3 c = 42;
+
+#elif defined test_74_non_const_init
+int i = i++;
+
+#endif
diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect
new file mode 100644
index 0000000..ed6a690
--- /dev/null
+++ b/tests/tests2/60_errors_and_warnings.expect
@@ -0,0 +1,28 @@
+[test_56_btype_excess_1]
+60_errors_and_warnings.c:2: error: too many basic types
+
+[test_57_btype_excess_2]
+60_errors_and_warnings.c:5: error: too many basic types
+
+[test_58_function_redefinition]
+60_errors_and_warnings.c:9: error: redefinition of 'f'
+
+[test_global_redefinition]
+60_errors_and_warnings.c:14: error: redefinition of 'xxx'
+
+[test_59_function_array]
+60_errors_and_warnings.c:17: error: declaration of an array of functions
+
+[test_60_enum_redefinition]
+60_errors_and_warnings.c:21: error: struct/union/enum already defined
+
+[test_62_enumerator_redefinition]
+60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
+
+[test_63_local_enumerator_redefinition]
+
+[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
diff --git a/tests/tests2/61_undefined_enum.c b/tests/tests2/61_undefined_enum.c
deleted file mode 100644
index bc7c6ea..0000000
--- a/tests/tests2/61_undefined_enum.c
+++ /dev/null
@@ -1 +0,0 @@
-enum rgb c = 42;
diff --git a/tests/tests2/61_undefined_enum.expect b/tests/tests2/61_undefined_enum.expect
deleted file mode 100644
index eb8b774..0000000
--- a/tests/tests2/61_undefined_enum.expect
+++ /dev/null
@@ -1 +0,0 @@
-61_undefined_enum.c:1: error: unknown type size
diff --git a/tests/tests2/62_enumerator_redefinition.c b/tests/tests2/62_enumerator_redefinition.c
deleted file mode 100644
index 3da85ae..0000000
--- a/tests/tests2/62_enumerator_redefinition.c
+++ /dev/null
@@ -1,4 +0,0 @@
-enum color {RED, GREEN, BLUE};
-enum rgb {RED, G, B};
-
-enum color c = RED;
diff --git a/tests/tests2/62_enumerator_redefinition.expect b/tests/tests2/62_enumerator_redefinition.expect
deleted file mode 100644
index 3d0e879..0000000
--- a/tests/tests2/62_enumerator_redefinition.expect
+++ /dev/null
@@ -1 +0,0 @@
-62_enumerator_redefinition.c:2: error: redefinition of enumerator 'RED'
diff --git a/tests/tests2/63_local_enumerator_redefinition.c b/tests/tests2/63_local_enumerator_redefinition.c
deleted file mode 100644
index dd4d8e0..0000000
--- a/tests/tests2/63_local_enumerator_redefinition.c
+++ /dev/null
@@ -1,14 +0,0 @@
-enum {
- FOO,
- BAR
-};
-
-int main(void)
-{
- enum {
- FOO = 2,
- BAR
- };
-
- return BAR - FOO;
-}
diff --git a/tests/tests2/74_nocode_wanted.c b/tests/tests2/74_nocode_wanted.c
deleted file mode 100644
index e824d02..0000000
--- a/tests/tests2/74_nocode_wanted.c
+++ /dev/null
@@ -1 +0,0 @@
-int i = i++;
diff --git a/tests/tests2/74_nocode_wanted.expect b/tests/tests2/74_nocode_wanted.expect
deleted file mode 100644
index f060ef4..0000000
--- a/tests/tests2/74_nocode_wanted.expect
+++ /dev/null
@@ -1 +0,0 @@
-74_nocode_wanted.c:1: error: initializer element is not constant
diff --git a/tests/tests2/81_types.c b/tests/tests2/81_types.c
index 542d066..fd6d71b 100644
--- a/tests/tests2/81_types.c
+++ b/tests/tests2/81_types.c
@@ -6,4 +6,38 @@ enum E const *e2;
struct S *s;
const struct S *s1;
struct S const *s2;
+
+/* Various strangely looking declarators, which are all valid
+ and have to map to the same numbered typedefs. */
+typedef int (*fptr1)();
+int f1 (int (), int);
+typedef int (*fptr2)(int x);
+int f2 (int (int x), int);
+typedef int (*fptr3)(int);
+int f3 (int (int), int);
+typedef int (*fptr4[4])(int);
+int f4 (int (*[4])(int), int);
+typedef int (*fptr5)(fptr1);
+int f5 (int (int()), fptr1);
+int f1 (fptr1 fp, int i)
+{
+ return (*fp)(i);
+}
+int f2 (fptr2 fp, int i)
+{
+ return (*fp)(i);
+}
+int f3 (fptr3 fp, int i)
+{
+ return (*fp)(i);
+}
+int f4 (fptr4 fp, int i)
+{
+ return (*fp[i])(i);
+}
+int f5 (fptr5 fp, fptr1 i)
+{
+ return fp(i);
+}
+int f8 (int ([4]), int);
int main () { return 0; }
diff --git a/tests/tests2/82_attribs_position.c b/tests/tests2/82_attribs_position.c
index 45039b3..7c9f987 100644
--- a/tests/tests2/82_attribs_position.c
+++ b/tests/tests2/82_attribs_position.c
@@ -11,4 +11,9 @@ typedef union __attribute__((packed)) Unaligned16b {
uint8_t b[2];
} Unaligned16b;
+extern void foo (void) __attribute__((stdcall));
+void __attribute__((stdcall)) foo (void)
+{
+}
+
int main () { return 0; }
diff --git a/tests/tests2/84-hex-float.c b/tests/tests2/84_hex-float.c
index 0ef09bf..0ef09bf 100644
--- a/tests/tests2/84-hex-float.c
+++ b/tests/tests2/84_hex-float.c
diff --git a/tests/tests2/84-hex-float.expect b/tests/tests2/84_hex-float.expect
index 2175385..2175385 100644
--- a/tests/tests2/84-hex-float.expect
+++ b/tests/tests2/84_hex-float.expect
diff --git a/tests/tests2/85-asm-outside-function.expect b/tests/tests2/85-asm-outside-function.expect
deleted file mode 100644
index e69de29..0000000
--- a/tests/tests2/85-asm-outside-function.expect
+++ /dev/null
diff --git a/tests/tests2/85-asm-outside-function.c b/tests/tests2/85_asm-outside-function.c
index 0aa7e33..dc5639a 100644
--- a/tests/tests2/85-asm-outside-function.c
+++ b/tests/tests2/85_asm-outside-function.c
@@ -1,7 +1,9 @@
+extern int printf (const char *, ...);
extern void vide(void);
__asm__("vide: ret");
int main() {
vide();
+ printf ("okay\n");
return 0;
}
diff --git a/tests/tests2/85_asm-outside-function.expect b/tests/tests2/85_asm-outside-function.expect
new file mode 100644
index 0000000..dcf02b2
--- /dev/null
+++ b/tests/tests2/85_asm-outside-function.expect
@@ -0,0 +1 @@
+okay
diff --git a/tests/tests2/86-memory-model.c b/tests/tests2/86_memory-model.c
index ca30737..744c3e2 100755..100644
--- a/tests/tests2/86-memory-model.c
+++ b/tests/tests2/86_memory-model.c
@@ -1,38 +1,38 @@
-#include <stdio.h>
-
-int
-main()
-{
-#if defined(__LLP64__)
- if (sizeof(short) == 2
- && sizeof(int) == 4
- && sizeof(long int) == 4
- && sizeof(long long int) == 8
- && sizeof(void*) == 8) {
- (void)printf("Ok\n");
- } else {
- (void)printf("KO __LLP64__\n");
- }
-#elif defined(__LP64__)
- if (sizeof(short) == 2
- && sizeof(int) == 4
- && sizeof(long int) == 8
- && sizeof(long long int) == 8
- && sizeof(void*) == 8) {
- (void)printf("Ok\n");
- } else {
- (void)printf("KO __LP64__\n");
- }
-#elif defined(__ILP32__)
- if (sizeof(short) == 2
- && sizeof(int) == 4
- && sizeof(long int) == 4
- && sizeof(void*) == 4) {
- (void)printf("Ok\n");
- } else {
- (void)printf("KO __ILP32__\n");
- }
-#else
- (void)printf("KO no __*LP*__ defined.\n");
-#endif
-}
+#include <stdio.h>
+
+int
+main()
+{
+#if defined(__LLP64__)
+ if (sizeof(short) == 2
+ && sizeof(int) == 4
+ && sizeof(long int) == 4
+ && sizeof(long long int) == 8
+ && sizeof(void*) == 8) {
+ (void)printf("Ok\n");
+ } else {
+ (void)printf("KO __LLP64__\n");
+ }
+#elif defined(__LP64__)
+ if (sizeof(short) == 2
+ && sizeof(int) == 4
+ && sizeof(long int) == 8
+ && sizeof(long long int) == 8
+ && sizeof(void*) == 8) {
+ (void)printf("Ok\n");
+ } else {
+ (void)printf("KO __LP64__\n");
+ }
+#elif defined(__ILP32__)
+ if (sizeof(short) == 2
+ && sizeof(int) == 4
+ && sizeof(long int) == 4
+ && sizeof(void*) == 4) {
+ (void)printf("Ok\n");
+ } else {
+ (void)printf("KO __ILP32__\n");
+ }
+#else
+ (void)printf("KO no __*LP*__ defined.\n");
+#endif
+}
diff --git a/tests/tests2/86-memory-model.expect b/tests/tests2/86_memory-model.expect
index a28de60..7326d96 100755..100644
--- a/tests/tests2/86-memory-model.expect
+++ b/tests/tests2/86_memory-model.expect
@@ -1 +1 @@
-Ok
+Ok
diff --git a/tests/tests2/87_dead_code.c b/tests/tests2/87_dead_code.c
index 92983f5..98d4566 100644
--- a/tests/tests2/87_dead_code.c
+++ b/tests/tests2/87_dead_code.c
@@ -9,7 +9,7 @@ static void kb_wait_1(void)
/* Here the else arm is a statement expression that's supposed
to be suppressed. The label inside the while would unsuppress
code generation again if not handled correctly. And that
- would wreak havok to the cond-expression because there's no
+ would wreak havoc to the cond-expression because there's no
jump-around emitted, the whole statement expression really
needs to not generate code (perhaps except useless forward jumps). */
(1 ?
diff --git a/tests/tests2/88_codeopt.c b/tests/tests2/88_codeopt.c
new file mode 100644
index 0000000..647626f
--- /dev/null
+++ b/tests/tests2/88_codeopt.c
@@ -0,0 +1,68 @@
+/* Check some way in where code suppression caused various
+ miscompilations. */
+extern int printf (const char *, ...);
+typedef unsigned long size_t;
+
+size_t _brk_start, _brk_end;
+void * extend_brk(size_t size, size_t align)
+{
+ size_t mask = align - 1;
+ void *ret = 0;
+
+ do {
+ if (__builtin_expect(!!(_brk_start == 0), 0))
+ do {
+ printf("wrong1\n");
+ } while (0);
+ } while (0);
+ _brk_end = (_brk_end + mask) & ~mask;
+ ret = (void *)_brk_end;
+ _brk_end += size;
+
+ return ret;
+}
+
+static void get_args (int a, int b)
+{
+ if (a != 1)
+ printf("wrong2\n");
+ else
+ printf("okay\n");
+}
+
+void bla(void)
+{
+ int __ret = 42;
+ ({
+ if (__builtin_expect(!!(0), 0)) {
+ if (__builtin_expect(!!__ret, 0))
+ printf("wrong3\n");
+ int x = !!(__ret);
+ }
+ __ret;
+ });
+ get_args(!!__ret, sizeof(__ret));
+}
+
+_Bool chk(unsigned long addr, unsigned long limit, unsigned long size)
+{
+ _Bool ret;
+ /* This just needs to compile, no runtime test. (And it doesn't compile
+ only with certain internal checking added that's not committed). */
+ if (0)
+ ret = 0 != (!!(addr > limit - size));
+}
+
+int main()
+{
+ void *r;
+ _brk_start = 1024;
+ _brk_end = 1024;
+ r = extend_brk (4096, 16);
+ if (!r)
+ printf("wrong4\n");
+ else
+ printf("okay\n");
+ bla();
+ return 0;
+}
diff --git a/tests/tests2/88_codeopt.expect b/tests/tests2/88_codeopt.expect
new file mode 100644
index 0000000..439edfd
--- /dev/null
+++ b/tests/tests2/88_codeopt.expect
@@ -0,0 +1,2 @@
+okay
+okay
diff --git a/tests/tests2/82_nocode_wanted.c b/tests/tests2/89_nocode_wanted.c
index a0ec890..73e0a4b 100644
--- a/tests/tests2/82_nocode_wanted.c
+++ b/tests/tests2/89_nocode_wanted.c
@@ -3,7 +3,7 @@ static void kb_wait_1(void)
{
unsigned long timeout = 2;
do {
- (1 ?
+ (1 ?
printf("timeout=%ld\n", timeout) :
({
while (1)
@@ -17,7 +17,7 @@ static void kb_wait_2(void)
{
unsigned long timeout = 2;
do {
- (1 ?
+ (1 ?
printf("timeout=%ld\n", timeout) :
({
for (;;)
@@ -31,7 +31,7 @@ static void kb_wait_2_1(void)
{
unsigned long timeout = 2;
do {
- (1 ?
+ (1 ?
printf("timeout=%ld\n", timeout) :
({
do {
@@ -46,7 +46,7 @@ static void kb_wait_2_2(void)
{
unsigned long timeout = 2;
do {
- (1 ?
+ (1 ?
printf("timeout=%ld\n", timeout) :
({
label:
@@ -61,7 +61,7 @@ static void kb_wait_3(void)
{
unsigned long timeout = 2;
do {
- (1 ?
+ (1 ?
printf("timeout=%ld\n", timeout) :
({
int i = 1;
@@ -78,7 +78,7 @@ static void kb_wait_4(void)
{
unsigned long timeout = 2;
do {
- (1 ?
+ (1 ?
printf("timeout=%ld\n", timeout) :
({
switch(timeout) {
diff --git a/tests/tests2/82_nocode_wanted.expect b/tests/tests2/89_nocode_wanted.expect
index c44d4ea..c44d4ea 100644
--- a/tests/tests2/82_nocode_wanted.expect
+++ b/tests/tests2/89_nocode_wanted.expect
diff --git a/tests/tests2/86-struct-init.c b/tests/tests2/90_struct-init.c
index fd212ba..d931e23 100644
--- a/tests/tests2/86-struct-init.c
+++ b/tests/tests2/90_struct-init.c
@@ -60,7 +60,7 @@ struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} };
struct S gs3 = { (1), {(2)}, {(((3))), {4}}};
/* Superfluous braces, and leaving out braces for V.t, plus cast */
struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46};
-/* Compund literal */
+/* Compound literal */
struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48};
/* Parens around compound literal */
struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50};
@@ -157,7 +157,7 @@ void foo (struct W *w, struct pkthdr *phdr_)
struct S ls3 = { (1), (2), {(((3))), 4}};
/* Superfluous braces, and leaving out braces for V.t, plus cast */
struct V lv = {{3,4,{5,6}}, "haha", (u8)45, 46};
- /* Compund literal */
+ /* Compound literal */
struct V lv2 = {(struct S)w->t.s, {"hihi", 47}, 48};
/* Parens around compound literal */
struct V lv3 = {((struct S){7,8,{9,10}}), ((const struct W *)w)->t.t, 50};
@@ -217,7 +217,40 @@ void test_multi_relocs(void)
for (i = 0; i < sizeof(table)/sizeof(table[0]); i++)
table[i]();
}
+
+/* Following is from GCC gcc.c-torture/execute/20050613-1.c. */
+struct SEA { int i; int j; int k; int l; };
+struct SEB { struct SEA a; int r[1]; };
+struct SEC { struct SEA a; int r[0]; };
+struct SED { struct SEA a; int r[]; };
+
+static void
+test_correct_filling (struct SEA *x)
+{
+ static int i;
+ if (x->i != 0 || x->j != 5 || x->k != 0 || x->l != 0)
+ printf("sea_fill%d: wrong\n", i);
+ else
+ printf("sea_fill%d: okay\n", i);
+ i++;
+}
+
+int
+test_zero_init (void)
+{
+ /* The peculiarity here is that only a.j is initialized. That
+ means that all other members must be zero initialized. TCC
+ once didn't do that for sub-level designators. */
+ struct SEB b = { .a.j = 5 };
+ struct SEC c = { .a.j = 5 };
+ struct SED d = { .a.j = 5 };
+ test_correct_filling (&b.a);
+ test_correct_filling (&c.a);
+ test_correct_filling (&d.a);
+ return 0;
+}
+
int main()
{
print(ce);
@@ -244,5 +277,6 @@ int main()
//printf("q: %s\n", q);
test_compound_with_relocs();
test_multi_relocs();
+ test_zero_init();
return 0;
}
diff --git a/tests/tests2/86-struct-init.expect b/tests/tests2/90_struct-init.expect
index adda76d..e366121 100644
--- a/tests/tests2/86-struct-init.expect
+++ b/tests/tests2/90_struct-init.expect
@@ -38,3 +38,6 @@ 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
one
two
three
+sea_fill0: okay
+sea_fill1: okay
+sea_fill2: okay
diff --git a/tests/tests2/87_ptr_longlong_arith32.c b/tests/tests2/91_ptr_longlong_arith32.c
index bf07915..bf07915 100644
--- a/tests/tests2/87_ptr_longlong_arith32.c
+++ b/tests/tests2/91_ptr_longlong_arith32.c
diff --git a/tests/tests2/87_ptr_longlong_arith32.expect b/tests/tests2/91_ptr_longlong_arith32.expect
index f91e4b4..f91e4b4 100644
--- a/tests/tests2/87_ptr_longlong_arith32.expect
+++ b/tests/tests2/91_ptr_longlong_arith32.expect
diff --git a/tests/tests2/92_enum_bitfield.c b/tests/tests2/92_enum_bitfield.c
new file mode 100644
index 0000000..bb6dc35
--- /dev/null
+++ b/tests/tests2/92_enum_bitfield.c
@@ -0,0 +1,57 @@
+/* This checks if enums needing 8 bit but only having positive
+ values are correctly zero extended (instead of sign extended)
+ when stored into/loaded from a 8 bit bit-field of enum type (which
+ itself is implementation defined, so isn't necessarily supported by all
+ other compilers). */
+enum tree_code {
+ SOME_CODE = 148, /* has bit 7 set, and hence all further enum values as well */
+ LAST_AND_UNUSED_TREE_CODE
+};
+typedef union tree_node *tree;
+struct tree_common
+{
+ union tree_node *chain;
+ union tree_node *type;
+ enum tree_code code : 8;
+ unsigned side_effects_flag : 1;
+};
+union tree_node
+{
+ struct tree_common common;
+ };
+enum c_tree_code {
+ C_DUMMY_TREE_CODE = LAST_AND_UNUSED_TREE_CODE,
+ STMT_EXPR,
+ LAST_C_TREE_CODE
+};
+enum cplus_tree_code {
+ CP_DUMMY_TREE_CODE = LAST_C_TREE_CODE,
+ AMBIG_CONV,
+ LAST_CPLUS_TREE_CODE
+};
+
+extern int printf(const char *, ...);
+int blah(){return 0;}
+
+int convert_like_real (tree convs)
+{
+ switch (((enum tree_code) (convs)->common.code))
+ {
+ case AMBIG_CONV: /* This has bit 7 set, which must not be the sign
+ bit in tree_common.code, i.e. the bitfield must
+ be somehow marked unsigned. */
+ return blah();
+ default:
+ break;
+ };
+ printf("unsigned enum bit-fields broken\n");
+}
+
+int main()
+{
+ union tree_node convs;
+
+ convs.common.code = AMBIG_CONV;
+ convert_like_real (&convs);
+ return 0;
+}
diff --git a/tests/tests2/63_local_enumerator_redefinition.expect b/tests/tests2/92_enum_bitfield.expect
index e69de29..e69de29 100644
--- a/tests/tests2/63_local_enumerator_redefinition.expect
+++ b/tests/tests2/92_enum_bitfield.expect
diff --git a/tests/tests2/93_integer_promotion.c b/tests/tests2/93_integer_promotion.c
new file mode 100644
index 0000000..a1176fc
--- /dev/null
+++ b/tests/tests2/93_integer_promotion.c
@@ -0,0 +1,71 @@
+/* integer promotion */
+
+int printf(const char*, ...);
+#define promote(s) printf(" %ssigned : %s\n", (s) - 100 < 0 ? " " : "un", #s);
+
+int main (void)
+{
+ struct {
+ unsigned ub:3;
+ unsigned u:32;
+ unsigned long long ullb:35;
+ unsigned long long ull:64;
+ unsigned char c;
+ } s = { 1, 1, 1 };
+
+ promote(s.ub);
+ promote(s.u);
+ promote(s.ullb);
+ promote(s.ull);
+ promote(s.c);
+ printf("\n");
+
+ promote((1 ? s.ub : 1));
+ promote((1 ? s.u : 1));
+ promote((1 ? s.ullb : 1));
+ promote((1 ? s.ull : 1));
+ promote((1 ? s.c : 1));
+ printf("\n");
+
+ promote(s.ub << 1);
+ promote(s.u << 1);
+ promote(s.ullb << 1);
+ promote(s.ull << 1);
+ promote(s.c << 1);
+ printf("\n");
+
+ promote(+s.ub);
+ promote(+s.u);
+ promote(+s.ullb);
+ promote(+s.ull);
+ promote(+s.c);
+ printf("\n");
+
+ promote(-s.ub);
+ promote(-s.u);
+ promote(-s.ullb);
+ promote(-s.ull);
+ promote(-s.c);
+ printf("\n");
+
+ promote(~s.ub);
+ promote(~s.u);
+ promote(~s.ullb);
+ promote(~s.ull);
+ promote(~s.c);
+ printf("\n");
+
+ promote(!s.ub);
+ promote(!s.u);
+ promote(!s.ullb);
+ promote(!s.ull);
+ promote(!s.c);
+ printf("\n");
+
+ promote(+(unsigned)s.ub);
+ promote(-(unsigned)s.ub);
+ promote(~(unsigned)s.ub);
+ promote(!(unsigned)s.ub);
+
+ return 0;
+}
diff --git a/tests/tests2/93_integer_promotion.expect b/tests/tests2/93_integer_promotion.expect
new file mode 100644
index 0000000..34b9c14
--- /dev/null
+++ b/tests/tests2/93_integer_promotion.expect
@@ -0,0 +1,46 @@
+ signed : s.ub
+ unsigned : s.u
+ signed : s.ullb
+ unsigned : s.ull
+ signed : s.c
+
+ signed : (1 ? s.ub : 1)
+ unsigned : (1 ? s.u : 1)
+ signed : (1 ? s.ullb : 1)
+ unsigned : (1 ? s.ull : 1)
+ signed : (1 ? s.c : 1)
+
+ signed : s.ub << 1
+ unsigned : s.u << 1
+ signed : s.ullb << 1
+ unsigned : s.ull << 1
+ signed : s.c << 1
+
+ signed : +s.ub
+ unsigned : +s.u
+ signed : +s.ullb
+ unsigned : +s.ull
+ signed : +s.c
+
+ signed : -s.ub
+ unsigned : -s.u
+ signed : -s.ullb
+ unsigned : -s.ull
+ signed : -s.c
+
+ signed : ~s.ub
+ unsigned : ~s.u
+ signed : ~s.ullb
+ unsigned : ~s.ull
+ signed : ~s.c
+
+ signed : !s.ub
+ signed : !s.u
+ signed : !s.ullb
+ signed : !s.ull
+ signed : !s.c
+
+ unsigned : +(unsigned)s.ub
+ unsigned : -(unsigned)s.ub
+ unsigned : ~(unsigned)s.ub
+ signed : !(unsigned)s.ub
diff --git a/tests/tests2/94_generic.c b/tests/tests2/94_generic.c
new file mode 100644
index 0000000..d7fb5fc
--- /dev/null
+++ b/tests/tests2/94_generic.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+
+const int a = 0;
+
+struct a {
+ int a;
+};
+
+struct b {
+ int a;
+};
+
+int a_f()
+{
+ return 20;
+}
+
+int b_f()
+{
+ return 10;
+}
+
+typedef int int_type1;
+
+#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123);
+
+int main()
+{
+ int i = 0;
+ signed long int l = 2;
+ struct b titi;
+ const int * const ptr;
+ const char *ti;
+ int_type1 i2;
+
+ i = _Generic(a, int: a_f, const int: b_f)();
+ printf("%d\n", i);
+ i = _Generic(a, int: a_f() / 2, const int: b_f() / 2);
+ printf("%d\n", i);
+ i = _Generic(ptr, int *:1, int * const:2, default:20);
+ printf("%d\n", i);
+ i = gen_sw(a);
+ printf("%d\n", i);
+ i = _Generic(titi, struct a:1, struct b:2, default:20);
+ printf("%d\n", i);
+ i = _Generic(i2, char: 1, int : 0);
+ printf("%d\n", i);
+ i = _Generic(a, char:1, int[4]:2, default:5);
+ printf("%d\n", i);
+ i = _Generic(17, int :1, int **:2);
+ printf("%d\n", i);
+ i = _Generic(17L, int :1, long :2, long long : 3);
+ printf("%d\n", i);
+ i = _Generic("17, io", char *: 3, const char *: 1);
+ printf("%d\n", i);
+ i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3,
+ const signed char *:2);
+ printf("%d\n", i);
+ printf("%s\n", _Generic(i + 2L, long: "long", int: "int",
+ long long: "long long"));
+ i = _Generic(l, long: 1, int: 2);
+ printf("%d\n", i);
+ return 0;
+}
diff --git a/tests/tests2/94_generic.expect b/tests/tests2/94_generic.expect
new file mode 100644
index 0000000..9aa9275
--- /dev/null
+++ b/tests/tests2/94_generic.expect
@@ -0,0 +1,13 @@
+20
+10
+20
+123
+2
+0
+5
+1
+2
+3
+4
+long
+1 \ No newline at end of file
diff --git a/tests/tests2/95_bitfields.c b/tests/tests2/95_bitfields.c
new file mode 100644
index 0000000..f025c57
--- /dev/null
+++ b/tests/tests2/95_bitfields.c
@@ -0,0 +1,218 @@
+/* ----------------------------------------------------------------------- */
+#if TEST == 1
+{
+ struct M P A __s
+ {
+ unsigned x : 12;
+ unsigned char y : 7;
+ unsigned z : 28;
+ unsigned a: 4;
+ unsigned b: 5;
+ };
+ TEST_STRUCT(0x333,0x44,0x555555,6,7);
+}
+
+/* ----------------------------------------------------------------------- */
+#elif TEST == 2
+{
+ struct M P __s
+ {
+ int x: 12;
+ char y: 6;
+ long long z:63;
+ A char a:4;
+ long long b:2;
+
+ };
+ TEST_STRUCT(3,30,0x123456789abcdef0LL,5,2);
+}
+
+/* ----------------------------------------------------------------------- */
+#elif TEST == 3
+{
+ struct M P __s
+ {
+ unsigned x:5, y:5, :0, z:5; char a:5; A short b:5;
+ };
+ TEST_STRUCT(21,23,25,6,14);
+}
+
+/* ----------------------------------------------------------------------- */
+#elif TEST == 4
+{
+ struct M P __s {
+ int x : 3;
+ int : 2;
+ int y : 1;
+ int : 0;
+ int z : 5;
+ int a : 7;
+ unsigned int b : 7;
+ };
+ TEST_STRUCT(3,1,15,120,120);
+}
+
+/* ----------------------------------------------------------------------- */
+#elif TEST == 5
+{
+ struct M P __s {
+ long long x : 45;
+ long long : 2;
+ long long y : 30;
+ unsigned long long z : 38;
+ char a; short b;
+ };
+ TEST_STRUCT(0x123456789ULL, 120<<25, 120, 0x44, 0x77);
+}
+
+/* ----------------------------------------------------------------------- */
+#elif TEST == 6
+{
+ struct M P __s {
+ int a;
+ signed char b;
+ int x : 12, y : 4, : 0, : 4, z : 3;
+ char d;
+ };
+ TEST_STRUCT(1,2,3,4,-3);
+}
+
+/* ----------------------------------------------------------------------- */
+#elif defined PACK
+
+#if PACK
+# pragma pack(push,1)
+# define P //_P
+#else
+# define P
+#endif
+
+printf("\n\n" + 2*top);
+#define TEST 1
+#include SELF
+top = 0;
+#define TEST 2
+#include SELF
+#define TEST 3
+#include SELF
+#define TEST 4
+#include SELF
+#define TEST 5
+#include SELF
+#define TEST 6
+#include SELF
+
+#if PACK
+# pragma pack(pop)
+#endif
+
+#undef P
+#undef PACK
+
+/* ----------------------------------------------------------------------- */
+#elif defined ALIGN
+
+#if ALIGN
+# define A _A(16)
+#else
+# define A
+#endif
+
+#define PACK 0
+#include SELF
+#define PACK 1
+#include SELF
+
+#undef A
+#undef ALIGN
+
+/* ----------------------------------------------------------------------- */
+#elif defined MS_BF
+
+#if MS_BF
+# ifdef __TINYC__
+# pragma comment(option, "-mms-bitfields")
+# elif defined __GNUC__
+# define M __attribute__((ms_struct))
+# endif
+#else
+# ifdef __TINYC__
+# pragma comment(option, "-mno-ms-bitfields")
+# elif defined __GNUC__
+# define M __attribute__((gcc_struct))
+# endif
+#endif
+#ifndef M
+# define M
+#endif
+
+#define ALIGN 0
+#include SELF
+#define ALIGN 1
+#include SELF
+
+#undef M
+#undef MS_BF
+
+/* ----------------------------------------------------------------------- */
+#else
+
+#include <stdio.h>
+#include <string.h>
+/* some gcc headers #define __attribute__ to empty if it's not gcc */
+#undef __attribute__
+
+void dump(void *p, int s)
+{
+ int i;
+ for (i = s; --i >= 0;)
+ printf("%02X", ((unsigned char*)p)[i]);
+ printf("\n");
+}
+
+#define pv(m) \
+ printf(sizeof (s->m + 0) == 8 ? " %016llx" : " %02x", s->m)
+
+#define TEST_STRUCT(v1,v2,v3,v4,v5) { \
+ struct __s _s, *s = & _s; \
+ printf("\n---- TEST %d%s%s%s ----\n" + top, \
+ TEST, MS_BF?" - MS-BITFIELDS":"", \
+ PACK?" - PACKED":"", \
+ ALIGN?" - WITH ALIGN":""); \
+ memset(s, 0, sizeof *s); \
+ s->x = -1, s->y = -1, s->z = -1, s->a = -1, s->b = -1; \
+ printf("bits in use : "), dump(s, sizeof *s); \
+ s->x = v1, s->y = v2, s->z = v3, s->a += v4, ++s->a, s->b = v5; \
+ printf("bits as set : "), dump(s, sizeof *s); \
+ printf("values :"), pv(x), pv(y), pv(z), pv(a), pv(b), printf("\n"); \
+ printf("align/size : %d %d\n", alignof(struct __s),sizeof(struct __s)); \
+ }
+
+#ifdef _MSC_VER
+# define _A(n) __declspec(align(n))
+# define _P
+# define alignof(x) __alignof(x)
+#else
+# define _A(n) __attribute__((aligned(n)))
+# define _P __attribute__((packed))
+# define alignof(x) __alignof__(x)
+#endif
+
+#ifndef MS_BITFIELDS
+# define MS_BITFIELDS 0
+#endif
+
+#define SELF "95_bitfields.c"
+
+int top = 1;
+
+int main()
+{
+#define MS_BF MS_BITFIELDS
+#include SELF
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+#endif
+#undef TEST
diff --git a/tests/tests2/95_bitfields.expect b/tests/tests2/95_bitfields.expect
new file mode 100644
index 0000000..6a8fd9a
--- /dev/null
+++ b/tests/tests2/95_bitfields.expect
@@ -0,0 +1,149 @@
+---- TEST 1 ----
+bits in use : 0000001FFFFFFFFF007F0FFF
+bits as set : 000000076055555500440333
+values : 333 44 555555 06 07
+align/size : 4 12
+
+---- TEST 2 ----
+bits in use : 000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF
+bits as set : 0000000000000025123456789ABCDEF000000000001E0003
+values : 03 1e 123456789abcdef0 05 fffffffe
+align/size : 8 24
+
+---- TEST 3 ----
+bits in use : 001F1F1F000003FF
+bits as set : 000E0619000002F5
+values : 15 17 19 06 0e
+align/size : 4 8
+
+---- TEST 4 ----
+bits in use : 0007FFFF00000027
+bits as set : 00078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 4 8
+
+---- TEST 5 ----
+bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 007744000000007800000000300000000000000123456789
+values : 0000000123456789 f0000000 0000000000000078 44 77
+align/size : 8 24
+
+---- TEST 6 ----
+bits in use : 0000007000FFFFFFFFFFFFFF
+bits as set : 00000030002001FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 4 12
+
+
+
+---- TEST 1 - PACKED ----
+bits in use : FFFFFFFFFFFFFF
+bits as set : 3B02AAAAAC4333
+values : 333 44 555555 06 07
+align/size : 1 7
+
+---- TEST 2 - PACKED ----
+bits in use : 7FFFFFFFFFFFFFFFFFFFFF
+bits as set : 4A48D159E26AF37BC1E003
+values : 03 1e 123456789abcdef0 05 fffffffe
+align/size : 1 11
+
+---- TEST 3 - PACKED ----
+bits in use : 7FFF000003FF
+bits as set : 38D9000002F5
+values : 15 17 19 06 0e
+align/size : 1 6
+
+---- TEST 4 - PACKED ----
+bits in use : 07FFFF00000027
+bits as set : 078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 1 7
+
+---- TEST 5 - PACKED ----
+bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF
+bits as set : 007744000000000F18000000000123456789
+values : 0000000123456789 f0000000 0000000000000078 44 77
+align/size : 1 18
+
+---- TEST 6 - PACKED ----
+bits in use : 007000FFFFFFFFFFFFFF
+bits as set : 0030002001FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 1 10
+
+
+
+---- TEST 1 - WITH ALIGN ----
+bits in use : 000000000000001FFFFFFFFF007F0FFF
+bits as set : 00000000000000076055555500440333
+values : 333 44 555555 06 07
+align/size : 16 16
+
+---- TEST 2 - WITH ALIGN ----
+bits in use : 0000000000000000000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF
+bits as set : 00000000000000000000000000000025123456789ABCDEF000000000001E0003
+values : 03 1e 123456789abcdef0 05 fffffffe
+align/size : 16 32
+
+---- TEST 3 - WITH ALIGN ----
+bits in use : 0000000000000000000000000000001F000000000000000000001F1F000003FF
+bits as set : 0000000000000000000000000000000E000000000000000000000619000002F5
+values : 15 17 19 06 0e
+align/size : 16 32
+
+---- TEST 4 - WITH ALIGN ----
+bits in use : 0007FFFF00000027
+bits as set : 00078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 4 8
+
+---- TEST 5 - WITH ALIGN ----
+bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 007744000000007800000000300000000000000123456789
+values : 0000000123456789 f0000000 0000000000000078 44 77
+align/size : 8 24
+
+---- TEST 6 - WITH ALIGN ----
+bits in use : 0000007000FFFFFFFFFFFFFF
+bits as set : 00000030002001FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 4 12
+
+
+
+---- TEST 1 - PACKED - WITH ALIGN ----
+bits in use : 000000000000000000FFFFFFFFFFFFFF
+bits as set : 0000000000000000003B02AAAAAC4333
+values : 333 44 555555 06 07
+align/size : 16 16
+
+---- TEST 2 - PACKED - WITH ALIGN ----
+bits in use : 3F01FFFFFFFFFFFFFFFFFFFF
+bits as set : 250048D159E26AF37BC1E003
+values : 03 1e 123456789abcdef0 05 fffffffe
+align/size : 1 12
+
+---- TEST 3 - PACKED - WITH ALIGN ----
+bits in use : 1F03FF000003FF
+bits as set : 0E00D9000002F5
+values : 15 17 19 06 0e
+align/size : 1 7
+
+---- TEST 4 - PACKED - WITH ALIGN ----
+bits in use : 07FFFF00000027
+bits as set : 078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 1 7
+
+---- TEST 5 - PACKED - WITH ALIGN ----
+bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF
+bits as set : 007744000000000F18000000000123456789
+values : 0000000123456789 f0000000 0000000000000078 44 77
+align/size : 1 18
+
+---- TEST 6 - PACKED - WITH ALIGN ----
+bits in use : 007000FFFFFFFFFFFFFF
+bits as set : 0030002001FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 1 10
diff --git a/tests/tests2/95_bitfields_ms.c b/tests/tests2/95_bitfields_ms.c
new file mode 100644
index 0000000..b196fbd
--- /dev/null
+++ b/tests/tests2/95_bitfields_ms.c
@@ -0,0 +1,2 @@
+#define MS_BITFIELDS 1
+#include "95_bitfields.c"
diff --git a/tests/tests2/95_bitfields_ms.expect b/tests/tests2/95_bitfields_ms.expect
new file mode 100644
index 0000000..8ccafb7
--- /dev/null
+++ b/tests/tests2/95_bitfields_ms.expect
@@ -0,0 +1,149 @@
+---- TEST 1 - MS-BITFIELDS ----
+bits in use : 0000001FFFFFFFFF0000007F00000FFF
+bits as set : 00000007605555550000004400000333
+values : 333 44 555555 06 07
+align/size : 4 16
+
+---- TEST 2 - MS-BITFIELDS ----
+bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF
+bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003
+values : 03 1e 123456789abcdef0 05 fffffffffffffffe
+align/size : 8 32
+
+---- TEST 3 - MS-BITFIELDS ----
+bits in use : 001F001F0000001F000003FF
+bits as set : 000E000600000019000002F5
+values : 15 17 19 06 0e
+align/size : 4 12
+
+---- TEST 4 - MS-BITFIELDS ----
+bits in use : 0007FFFF00000027
+bits as set : 00078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 4 8
+
+---- TEST 5 - MS-BITFIELDS ----
+bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 0000000000770044000000000000007800000000300000000000000123456789
+values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
+align/size : 8 32
+
+---- TEST 6 - MS-BITFIELDS ----
+bits in use : 00000000000000700000FFFF000000FFFFFFFFFF
+bits as set : 000000000000003000002001000000FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 4 20
+
+
+
+---- TEST 1 - MS-BITFIELDS - PACKED ----
+bits in use : 0000001FFFFFFFFF7F00000FFF
+bits as set : 00000007605555554400000333
+values : 333 44 555555 06 07
+align/size : 1 13
+
+---- TEST 2 - MS-BITFIELDS - PACKED ----
+bits in use : 00000000000000030F7FFFFFFFFFFFFFFF3F00000FFF
+bits as set : 000000000000000205123456789ABCDEF01E00000003
+values : 03 1e 123456789abcdef0 05 fffffffffffffffe
+align/size : 1 22
+
+---- TEST 3 - MS-BITFIELDS - PACKED ----
+bits in use : 001F1F0000001F000003FF
+bits as set : 000E0600000019000002F5
+values : 15 17 19 06 0e
+align/size : 1 11
+
+---- TEST 4 - MS-BITFIELDS - PACKED ----
+bits in use : 0007FFFF00000027
+bits as set : 00078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 1 8
+
+---- TEST 5 - MS-BITFIELDS - PACKED ----
+bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 007744000000000000007800000000300000000000000123456789
+values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
+align/size : 1 27
+
+---- TEST 6 - MS-BITFIELDS - PACKED ----
+bits in use : 00000000700000FFFFFFFFFFFFFF
+bits as set : 000000003000002001FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 1 14
+
+
+
+---- TEST 1 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 0000001FFFFFFFFF0000007F00000FFF
+bits as set : 00000007605555550000004400000333
+values : 333 44 555555 06 07
+align/size : 16 16
+
+---- TEST 2 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF
+bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003
+values : 03 1e 123456789abcdef0 05 fffffffffffffffe
+align/size : 16 32
+
+---- TEST 3 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 0000000000000000000000000000001F000000000000001F0000001F000003FF
+bits as set : 0000000000000000000000000000000E000000000000000600000019000002F5
+values : 15 17 19 06 0e
+align/size : 16 32
+
+---- TEST 4 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 0007FFFF00000027
+bits as set : 00078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 4 8
+
+---- TEST 5 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 0000000000770044000000000000007800000000300000000000000123456789
+values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
+align/size : 8 32
+
+---- TEST 6 - MS-BITFIELDS - WITH ALIGN ----
+bits in use : 00000000000000700000FFFF000000FFFFFFFFFF
+bits as set : 000000000000003000002001000000FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 4 20
+
+
+
+---- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : 0000000000001FFFFFFFFF7F00000FFF
+bits as set : 00000000000007605555554400000333
+values : 333 44 555555 06 07
+align/size : 16 16
+
+---- TEST 2 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : 00000000000000030F0000007FFFFFFFFFFFFFFF3F00000FFF
+bits as set : 000000000000000205000000123456789ABCDEF01E00000003
+values : 03 1e 123456789abcdef0 05 fffffffffffffffe
+align/size : 16 25
+
+---- TEST 3 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : 001F000000000000001F0000001F000003FF
+bits as set : 000E000000000000000600000019000002F5
+values : 15 17 19 06 0e
+align/size : 16 18
+
+---- TEST 4 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : 0007FFFF00000027
+bits as set : 00078F0F00000023
+values : 03 ffffffff 0f fffffff8 78
+align/size : 1 8
+
+---- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 007744000000000000007800000000300000000000000123456789
+values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
+align/size : 1 27
+
+---- TEST 6 - MS-BITFIELDS - PACKED - WITH ALIGN ----
+bits in use : 00000000700000FFFFFFFFFFFFFF
+bits as set : 000000003000002001FD00000004
+values : 01 02 03 04 fffffffd
+align/size : 1 14
diff --git a/tests/tests2/96_nodata_wanted.c b/tests/tests2/96_nodata_wanted.c
new file mode 100644
index 0000000..cc211d3
--- /dev/null
+++ b/tests/tests2/96_nodata_wanted.c
@@ -0,0 +1,84 @@
+/*****************************************************************************/
+/* test 'nodata_wanted' data output suppression */
+
+#if defined test_static_data_error
+void foo() {
+ if (1) {
+ static short w = (int)&foo; /* initializer not computable */
+ }
+}
+
+#elif defined test_static_nodata_error
+void foo() {
+ if (0) {
+ static short w = (int)&foo; /* initializer not computable */
+ }
+}
+
+#elif defined test_global_data_error
+void foo();
+static short w = (int)&foo; /* initializer not computable */
+
+
+#elif defined test_local_data_noerror
+void foo() {
+ short w = &foo; /* 2 cast warnings */
+}
+
+#elif defined test_data_suppression_off || defined test_data_suppression_on
+
+#if defined test_data_suppression_on
+# define SKIP 1
+#else
+# define SKIP 0
+#endif
+
+#include <stdio.h>
+/* some gcc headers #define __attribute__ to empty if it's not gcc */
+#undef __attribute__
+
+int main()
+{
+ __label__ ts0, te0, ts1, te1;
+ int tl, dl;
+
+ static char ds0 = 0;
+ static char de0 = 0;
+ /* get reference size of empty jmp */
+ts0:;
+ if (!SKIP) {}
+te0:;
+ dl = -(&de0 - &ds0);
+ tl = -(&&te0 - &&ts0);
+
+ /* test data and code suppression */
+ 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)) {
+ unsigned x : 12;
+ unsigned char y : 7;
+ unsigned z : 28, a: 4, b: 5;
+ } s = { 0x333,0x44,0x555555,6,7 };
+
+ printf("data:\n");
+ printf(" %d - %.1f - %.1f - %s - %s\n",
+ sizeof 8.0, 8.0, d, __FUNCTION__, cc);
+ printf(" %x %x %x %x %x\n",
+ s.x, s.y, s.z, s.a, s.b);
+ }
+te1:;
+ static char de1 = 0;
+
+ dl += &de1 - &ds1;
+ tl += &&te1 - &&ts1;
+ printf("size of data/text:\n %s/%s\n",
+ dl ? "non-zero":"zero", tl ? "non-zero":"zero");
+ /*printf("# %d/%d\n", dl, tl);*/
+}
+
+#endif
diff --git a/tests/tests2/96_nodata_wanted.expect b/tests/tests2/96_nodata_wanted.expect
new file mode 100644
index 0000000..2749109
--- /dev/null
+++ b/tests/tests2/96_nodata_wanted.expect
@@ -0,0 +1,23 @@
+[test_static_data_error]
+96_nodata_wanted.c:7: error: initializer element is not computable at load time
+
+[test_static_nodata_error]
+96_nodata_wanted.c:14: error: initializer element is not computable at load time
+
+[test_global_data_error]
+96_nodata_wanted.c:20: error: initializer element is not computable at load time
+
+[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
+
+[test_data_suppression_off]
+data:
+ 8 - 8.0 - 8.0 - main - static string
+ 333 44 555555 6 7
+size of data/text:
+ non-zero/non-zero
+
+[test_data_suppression_on]
+size of data/text:
+ zero/zero
diff --git a/tests/tests2/97_utf8_string_literal.c b/tests/tests2/97_utf8_string_literal.c
new file mode 100644
index 0000000..96fbab0
--- /dev/null
+++ b/tests/tests2/97_utf8_string_literal.c
@@ -0,0 +1,12 @@
+// this file contains BMP chars encoded in UTF-8
+#include <stdio.h>
+#include <wchar.h>
+
+int main()
+{
+ wchar_t s[] = L"hello$$你好¢¢世界€€world";
+ wchar_t *p;
+ for (p = s; *p; p++) printf("%04X ", (unsigned) *p);
+ printf("\n");
+ return 0;
+}
diff --git a/tests/tests2/97_utf8_string_literal.expect b/tests/tests2/97_utf8_string_literal.expect
new file mode 100644
index 0000000..9a1593c
--- /dev/null
+++ b/tests/tests2/97_utf8_string_literal.expect
@@ -0,0 +1 @@
+0068 0065 006C 006C 006F 0024 0024 4F60 597D 00A2 00A2 4E16 754C 20AC 20AC 0077 006F 0072 006C 0064
diff --git a/tests/tests2/98_al_ax_extend.c b/tests/tests2/98_al_ax_extend.c
new file mode 100644
index 0000000..9b4e02f
--- /dev/null
+++ b/tests/tests2/98_al_ax_extend.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <stdlib.h>
+asm (
+ ".text;"
+ ".globl _us;.globl _ss;.globl _uc;.globl _sc;"
+ "_us:;_ss:;_uc:;_sc:;"
+ "movl $0x1234ABCD, %eax;"
+ "ret;"
+);
+
+#if 1
+#define us _us
+#define ss _ss
+#define uc _uc
+#define sc _sc
+#endif
+
+int main()
+{
+ unsigned short us(void);
+ short ss(void);
+ unsigned char uc(void);
+ signed char sc(void);
+
+ unsigned short (*fpus)(void) = us;
+ short (*fpss)(void) = ss;
+ unsigned char (*fpuc)(void) = uc;
+ signed char (*fpsc)(void) = sc;
+
+ printf("%08X %08X\n", us() + 1, fpus() + 1);
+ printf("%08X %08X\n", ss() + 1, fpss() + 1);
+ printf("%08X %08X\n", uc() + 1, fpuc() + 1);
+ printf("%08X %08X\n", sc() + 1, fpsc() + 1);
+ printf("\n");
+ printf("%08X %08X\n", fpus() + 1, us() + 1);
+ printf("%08X %08X\n", fpss() + 1, ss() + 1);
+ printf("%08X %08X\n", fpuc() + 1, uc() + 1);
+ printf("%08X %08X\n", fpsc() + 1, sc() + 1);
+
+ return 0;
+}
diff --git a/tests/tests2/98_al_ax_extend.expect b/tests/tests2/98_al_ax_extend.expect
new file mode 100644
index 0000000..c5752e8
--- /dev/null
+++ b/tests/tests2/98_al_ax_extend.expect
@@ -0,0 +1,9 @@
+0000ABCE 0000ABCE
+FFFFABCE FFFFABCE
+000000CE 000000CE
+FFFFFFCE FFFFFFCE
+
+0000ABCE 0000ABCE
+FFFFABCE FFFFABCE
+000000CE 000000CE
+FFFFFFCE FFFFFFCE
diff --git a/tests/tests2/99_fastcall.c b/tests/tests2/99_fastcall.c
new file mode 100644
index 0000000..ee4b67d
--- /dev/null
+++ b/tests/tests2/99_fastcall.c
@@ -0,0 +1,276 @@
+#include <stdio.h>
+#include <assert.h>
+
+#ifndef _WIN32
+#define __fastcall __attribute((fastcall))
+#endif
+
+#if 1
+#define SYMBOL(x) _##x
+#else
+#define SYMBOL(x) x
+#endif
+
+/////////////////////////////////////////////////////////////////////////
+////////// TRAP FRAMEWORK
+/////////////////////////////////////////////////////////////////////////
+// if you cast 'TRAP' to a function pointer and call it,
+// it will save all 8 registers,
+// and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'),
+// in C-code you can pop DWORDs from stack and modify registers
+//
+
+void *SYMBOL(trap_handler);
+
+extern unsigned char SYMBOL(trap)[];
+asm (
+ ".text;"
+ "_trap:;"
+ "pushl %esp;"
+ "pusha;"
+ "addl $0x4, 0xc(%esp);"
+ "pushl %esp;"
+ "call *_trap_handler;"
+ "addl $0x4, %esp;"
+ "movl 0xc(%esp), %eax;"
+ "movl %eax, 0x20(%esp);"
+ "popa;"
+ "popl %esp;"
+ "ret;"
+);
+
+struct trapframe {
+ unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
+};
+
+
+#define M_FLOAT(addr) (*(float *)(addr))
+#define M_DWORD(addr) (*(unsigned *)(addr))
+#define M_WORD(addr) (*(unsigned short *)(addr))
+#define M_BYTE(addr) (*(unsigned char *)(addr))
+#define R_EAX ((tf)->eax)
+#define R_ECX ((tf)->ecx)
+#define R_EDX ((tf)->edx)
+#define R_EBX ((tf)->ebx)
+#define R_ESP ((tf)->esp)
+#define R_EBP ((tf)->ebp)
+#define R_ESI ((tf)->esi)
+#define R_EDI ((tf)->edi)
+
+#define ARG(x) (M_DWORD(R_ESP + (x) * 4))
+
+#define RETN(x) do { \
+ M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \
+ R_ESP += (x); \
+} while (0)
+
+#define DUMP() do { \
+ unsigned i; \
+ printf("EAX: %08X\n", R_EAX); \
+ printf("ECX: %08X\n", R_ECX); \
+ printf("EDX: %08X\n", R_EDX); \
+ printf("EBX: %08X\n", R_EBX); \
+ printf("ESP: %08X\n", R_ESP); \
+ printf("EBP: %08X\n", R_EBP); \
+ printf("ESI: %08X\n", R_ESI); \
+ printf("EDI: %08X\n", R_EDI); \
+ printf("\n"); \
+ printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \
+ for (i = 1; i <= 8; i++) { \
+ printf("[ARG%4d]: %08X\n", i, ARG(i)); \
+ } \
+} while (0)
+
+#define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x))
+#define TRAP ((void *) &SYMBOL(trap))
+
+
+
+/////////////////////////////////////////////////////////////////////////
+////////// SAFECALL FRAMEWORK
+/////////////////////////////////////////////////////////////////////////
+// this framework will convert any calling convention to cdecl
+// usage: first set call target with 'SET_SAFECALL_TARGET(x)'
+// then cast 'SAFECALL' to target function pointer type and invoke it
+// after calling, 'ESPDIFF' is the difference of old and new esp
+
+void *SYMBOL(sc_call_target);
+unsigned SYMBOL(sc_retn_addr);
+unsigned SYMBOL(sc_old_esp);
+unsigned SYMBOL(sc_new_esp);
+
+extern unsigned char SYMBOL(safecall)[];
+asm (
+ ".text;"
+ "_safecall:;"
+ "popl _sc_retn_addr;"
+ "movl %esp, _sc_old_esp;"
+ "call *_sc_call_target;"
+ "movl %esp, _sc_new_esp;"
+ "movl _sc_old_esp, %esp;"
+ "jmp *_sc_retn_addr;"
+);
+
+#define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x))
+#define SAFECALL ((void *) &SYMBOL(safecall))
+#define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp))
+
+
+/////////////////////////////////////////////////////////////////////////
+////////// TEST FASTCALL INVOKE
+/////////////////////////////////////////////////////////////////////////
+
+void check_fastcall_invoke_0(struct trapframe *tf)
+{
+ //DUMP();
+ RETN(0);
+}
+
+void check_fastcall_invoke_1(struct trapframe *tf)
+{
+ //DUMP();
+ assert(R_ECX == 0x11111111);
+ RETN(0);
+}
+void check_fastcall_invoke_2(struct trapframe *tf)
+{
+ //DUMP();
+ assert(R_ECX == 0x11111111);
+ assert(R_EDX == 0x22222222);
+ RETN(0);
+}
+void check_fastcall_invoke_3(struct trapframe *tf)
+{
+ //DUMP();
+ assert(R_ECX == 0x11111111);
+ assert(R_EDX == 0x22222222);
+ assert(ARG(1) == 0x33333333);
+ RETN(1*4);
+}
+void check_fastcall_invoke_4(struct trapframe *tf)
+{
+ //DUMP();
+ assert(R_ECX == 0x11111111);
+ assert(R_EDX == 0x22222222);
+ assert(ARG(1) == 0x33333333);
+ assert(ARG(2) == 0x44444444);
+ RETN(2*4);
+}
+
+void check_fastcall_invoke_5(struct trapframe *tf)
+{
+ //DUMP();
+ assert(R_ECX == 0x11111111);
+ assert(R_EDX == 0x22222222);
+ assert(ARG(1) == 0x33333333);
+ assert(ARG(2) == 0x44444444);
+ assert(ARG(3) == 0x55555555);
+ RETN(3*4);
+}
+
+void test_fastcall_invoke()
+{
+ SET_TRAP_HANDLER(check_fastcall_invoke_0);
+ ((void __fastcall (*)(void)) TRAP)();
+
+ SET_TRAP_HANDLER(check_fastcall_invoke_1);
+ ((void __fastcall (*)(unsigned)) TRAP)(0x11111111);
+
+ SET_TRAP_HANDLER(check_fastcall_invoke_2);
+ ((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222);
+
+ SET_TRAP_HANDLER(check_fastcall_invoke_3);
+ ((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333);
+
+ SET_TRAP_HANDLER(check_fastcall_invoke_4);
+ ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444);
+
+ SET_TRAP_HANDLER(check_fastcall_invoke_5);
+ ((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555);
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+////////// TEST FUNCTION CODE GENERATION
+/////////////////////////////////////////////////////////////////////////
+
+int __fastcall check_fastcall_espdiff_0(void)
+{
+ return 0;
+}
+
+int __fastcall check_fastcall_espdiff_1(int a)
+{
+ return a;
+}
+
+int __fastcall check_fastcall_espdiff_2(int a, int b)
+{
+ return a + b;
+}
+
+int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
+{
+ return a + b + c;
+}
+
+int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
+{
+ return a + b + c + d;
+}
+
+int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e)
+{
+ return a + b + c + d + e;
+}
+
+void test_fastcall_espdiff()
+{
+ int x;
+ SET_SAFECALL_TARGET(check_fastcall_espdiff_0);
+ x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)();
+ assert(x == 0);
+ assert(ESPDIFF == 0);
+
+ SET_SAFECALL_TARGET(check_fastcall_espdiff_1);
+ x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1);
+ assert(x == 1);
+ assert(ESPDIFF == 0);
+
+ SET_SAFECALL_TARGET(check_fastcall_espdiff_2);
+ x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2);
+ assert(x == 1 + 2);
+ assert(ESPDIFF == 0);
+
+ SET_SAFECALL_TARGET(check_fastcall_espdiff_3);
+ x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3);
+ assert(x == 1 + 2 + 3);
+ assert(ESPDIFF == 1*4);
+
+ SET_SAFECALL_TARGET(check_fastcall_espdiff_4);
+ x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4);
+ assert(x == 1 + 2 + 3 + 4);
+ assert(ESPDIFF == 2*4);
+
+ SET_SAFECALL_TARGET(check_fastcall_espdiff_5);
+ x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5);
+ assert(x == 1 + 2 + 3 + 4 + 5);
+ assert(ESPDIFF == 3*4);
+}
+
+int main()
+{
+#define N 10000
+ int i;
+
+ for (i = 1; i <= N; i++) {
+ test_fastcall_espdiff();
+ }
+
+ for (i = 1; i <= N; i++) {
+ test_fastcall_invoke();
+ }
+
+ puts("TEST OK");
+ return 0;
+}
diff --git a/tests/tests2/99_fastcall.expect b/tests/tests2/99_fastcall.expect
new file mode 100644
index 0000000..3835d63
--- /dev/null
+++ b/tests/tests2/99_fastcall.expect
@@ -0,0 +1 @@
+TEST OK
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 2434215..190b2d9 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -1,32 +1,33 @@
TOP = ../..
-include $(TOP)/config.mak
+include $(TOP)/Makefile
SRC = $(TOPSRC)/tests/tests2
VPATH = $(SRC)
-# run local version of tcc with local libraries and includes
-TCCFLAGS = -B$(TOP) -I$(TOPSRC)/include
-ifdef CONFIG_WIN32
- TCCFLAGS = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -L$(TOP)
-endif
-TCC = $(TOP)/tcc $(TCCFLAGS)
-
TESTS = $(patsubst %.c,%.test,$(sort $(notdir $(wildcard $(SRC)/*.c))))
-# 34_array_assignment.test -- array assignment is not in C standard
-SKIP = 34_array_assignment.test
-
# some tests do not pass on all platforms, remove them for now
+SKIP = 34_array_assignment.test # array assignment is not in C standard
ifeq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
SKIP += 22_floating_point.test
endif
-ifeq ($(TARGETOS),Darwin)
- SKIP += 40_stdio.test
+ifdef CONFIG_OSX
+ SKIP += 40_stdio.test 42_function_pointer.test
+ FLAGS += -w
endif
-ifeq ($(ARCH),x86-64)
+ifeq ($(ARCH),x86_64)
SKIP += 73_arm64.test
endif
-ifeq (,$(filter i386 x86-64,$(ARCH)))
- SKIP += 85-asm-outside-function.test
+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
+endif
+ifeq (-$(findstring gcc,$(CC))-,--)
+ SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
+endif
+ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
+ SKIP += 95_bitfields%.test # type_align is different on 32bit-non-windows
endif
# Some tests might need arguments
@@ -34,8 +35,24 @@ ARGS =
31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5
46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c
+# And some tests don't test the right thing with -run
+NORUN =
+42_function_pointer.test : NORUN = true
+
# Some tests might need different flags
-76_dollars_in_identifiers.test : TCCFLAGS += -fdollars-in-identifiers
+FLAGS =
+76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers
+
+# These tests run several snippets from the same file one by one
+60_errors_and_warnings.test : FLAGS += -dt
+96_nodata_wanted.test : FLAGS += -dt
+
+# Always generate certain .expects (don't put these in the GIT),
+GEN-ALWAYS =
+# GEN-ALWAYS += 95_bitfields.expect # does not work
+
+# using the ms compiler for the really ms-compatible bitfields
+95_bitfields_ms.test : GEN = $(GEN-MSC)
# Filter source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed 's,$(SRC)/,,g'
@@ -44,20 +61,52 @@ ifeq (-$(findstring arm,$(ARCH))-,-arm-)
FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
endif
-all test: $(filter-out $(SKIP),$(TESTS))
+all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
%.test: %.c %.expect
@echo Test: $*...
-# test -run
- @$(TCC) -run $< $(ARGS) $(FILTER) >$*.output 2>&1 || true
- @diff -Nbu $(SRC)/$*.expect $*.output && rm -f $*.output
+ @$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3))
+
+T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS)
+T2 = $(TCC) $(FLAGS) -run $< $(ARGS)
+T3 = $(FILTER) >$*.output 2>&1 || true \
+ && diff -Nbu $(filter %.expect,$^) $*.output \
+ && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))
+
+# run single test and update .expect file, e.g. "make tests2.37+"
+tests2.%+:
+ @$(MAKE) $(call F2,$(call F1,$*)) --no-print-directory
+
+# just run tcc to see the output, e.g. "make tests2.37-"
+tests2.%-:
+ @$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory
+
+# run single test, e.g. "make tests2.37"
+tests2.%:
+ @$(MAKE) $(call F1,$*) --no-print-directory
+
+F1 = $(or $(filter $1_%,$(TESTS)),$1_???.test)
+F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)"
# automatically generate .expect files with gcc:
-%.expect : %.c
- (gcc -w $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe
+%.expect :
+ @echo Generating: $@
+ @$(call GEN,$(SRC)/$*.c) $(FILTER) >$@ 2>&1
+ @rm -f *.exe *.obj *.pdb
+
+# using TCC for .expect if -dt in FLAGS
+GEN = $(if $(filter -dt,$(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-MSC = $(MS-CC) $1 && ./$(basename $@).exe
+MS-CC = cl
# tell make not to delete
.PRECIOUS: %.expect
+# force .expect generation for these files
+$(sort $(GEN-ALWAYS) $(UPDATE)) : force
+force:
+
clean:
- rm -f fred.txt *.output a.exe
+ rm -f fred.txt *.output a.exe $(GEN-ALWAYS)
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index c795c19..913b068 100644..100755
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -1,67 +1,189 @@
-@rem ----------------------------------------------------
-@rem batch file to build tcc using mingw gcc
-@rem ----------------------------------------------------
-
-@set /p VERSION= < ..\VERSION
-echo>..\config.h #define TCC_VERSION "%VERSION%"
-
-@if _%PROCESSOR_ARCHITECTURE%_==_AMD64_ goto x86_64
-@if _%PROCESSOR_ARCHITEW6432%_==_AMD64_ goto x86_64
-
-@set target=-DTCC_TARGET_PE -DTCC_TARGET_I386
-@set CC=gcc -m32 -Os -s -fno-strict-aliasing
-@set P=32
-@goto tools
-
-:x86_64
-@set target=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
-@set CC=gcc -m64 -Os -s -fno-strict-aliasing
-@set P=64
-@goto tools
-
-:tools
-%CC% %target% tools/tiny_impdef.c -o tiny_impdef.exe
-%CC% %target% tools/tiny_libmaker.c -o tiny_libmaker.exe
-
-:libtcc
-if not exist libtcc mkdir libtcc
-copy ..\libtcc.h libtcc\libtcc.h
-%CC% %target% -shared -DLIBTCC_AS_DLL -DONE_SOURCE ../libtcc.c -o libtcc.dll -Wl,-out-implib,libtcc/libtcc.a
-tiny_impdef libtcc.dll -o libtcc/libtcc.def
-
-:tcc
-%CC% %target% ../tcc.c -o tcc.exe -ltcc -Llibtcc
-
-:copy_std_includes
-copy ..\include\*.h include
-copy ..\tcclib.h include
-copy ..\tests\libtcc_test.c examples
-
-:libtcc1.a
-.\tcc %target% -c ../lib/libtcc1.c
-.\tcc %target% -c lib/crt1.c
-.\tcc %target% -c lib/wincrt1.c
-.\tcc %target% -c lib/dllcrt1.c
-.\tcc %target% -c lib/dllmain.c
-.\tcc %target% -c lib/chkstk.S
-goto lib%P%
-
-:lib32
-.\tcc %target% -c ../lib/alloca86.S
-.\tcc %target% -c ../lib/alloca86-bt.S
-.\tcc %target% -c ../lib/bcheck.c
-tiny_libmaker lib/libtcc1.a libtcc1.o alloca86.o alloca86-bt.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o bcheck.o
-@goto the_end
-
-:lib64
-.\tcc %target% -c ../lib/alloca86_64.S
-tiny_libmaker lib/libtcc1.a libtcc1.o alloca86_64.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
-
-:the_end
-del *.o
-
-:makedoc
-if not exist doc md doc
-copy tcc-win32.txt doc
-echo>..\config.texi @set VERSION %VERSION%
-makeinfo --html --no-split -o doc\tcc-doc.html ../tcc-doc.texi || echo *** tcc-doc.html was not built ***
+@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%
diff --git a/win32/examples/dll.c b/win32/examples/dll.c
index 4c1d8ce..052a056 100644
--- a/win32/examples/dll.c
+++ b/win32/examples/dll.c
@@ -4,9 +4,10 @@
//
#include <windows.h>
-#define DLL_EXPORT __declspec(dllexport)
-DLL_EXPORT void HelloWorld (void)
+__declspec(dllexport) const char *hello_data = "(not set)";
+
+__declspec(dllexport) void hello_func (void)
{
- MessageBox (0, "Hello World!", "From DLL", MB_ICONINFORMATION);
+ MessageBox (0, hello_data, "From DLL", MB_ICONINFORMATION);
}
diff --git a/win32/examples/hello_dll.c b/win32/examples/hello_dll.c
index 7adba77..4813c5b 100644
--- a/win32/examples/hello_dll.c
+++ b/win32/examples/hello_dll.c
@@ -5,15 +5,16 @@
#include <windows.h>
-void HelloWorld (void);
+void hello_func (void);
+__declspec(dllimport) extern const char *hello_data;
int WINAPI WinMain(
- HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
{
- HelloWorld();
- return 0;
+ hello_data = "Hello World!";
+ hello_func();
+ return 0;
}
-
diff --git a/win32/include/_mingw.h b/win32/include/_mingw.h
index 2e565a6..2fc9798 100644
--- a/win32/include/_mingw.h
+++ b/win32/include/_mingw.h
@@ -83,8 +83,12 @@
#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 */
#define _SIZE_T_DEFINED
@@ -139,6 +143,18 @@ typedef struct localeinfo_struct _locale_tstruct,*_locale_t;
#define NOSERVICE 1
#define NOMCX 1
#define NOIME 1
+#define __INTRIN_H_
+#ifndef DUMMYUNIONNAME
+# define DUMMYUNIONNAME
+# define DUMMYUNIONNAME1
+# define DUMMYUNIONNAME2
+# define DUMMYUNIONNAME3
+# define DUMMYUNIONNAME4
+# define DUMMYUNIONNAME5
+#endif
+#ifndef DUMMYSTRUCTNAME
+# define DUMMYSTRUCTNAME
+#endif
#ifndef WINVER
# define WINVER 0x0502
#endif
@@ -149,5 +165,6 @@ typedef struct localeinfo_struct _locale_tstruct,*_locale_t;
#define __C89_NAMELESS
#define __MINGW_EXTENSION
#define WINAPI_FAMILY_PARTITION(X) 1
+#define MINGW_HAS_SECURE_API
#endif /* __MINGW_H */
diff --git a/win32/include/assert.h b/win32/include/assert.h
index c1678a3..466d457 100644
--- a/win32/include/assert.h
+++ b/win32/include/assert.h
@@ -39,14 +39,17 @@ __CRT_INLINE __MINGW_ATTRIB_NORETURN void __cdecl _Exit(int status)
extern "C" {
#endif
+
extern void __cdecl _wassert(const wchar_t *_Message,const wchar_t *_File,unsigned _Line);
+extern void __cdecl _assert(const char *, const char *, unsigned);
#ifdef __cplusplus
}
#endif
#ifndef assert
-#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0))
+//#define assert(_Expression) (void)((!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression),_CRT_WIDE(__FILE__),__LINE__),0))
+#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__))
#endif
#endif
diff --git a/win32/include/conio.h b/win32/include/conio.h
index 6c1dc97..39f779e 100644
--- a/win32/include/conio.h
+++ b/win32/include/conio.h
@@ -194,7 +194,7 @@ extern "C" {
}
/* Register sizes are different between 32/64 bit mode. So we have to do this for _WIN64 and _WIN32
- seperatly. */
+ separately. */
#ifdef _WIN64
__CRT_INLINE void __writecr0(unsigned __int64 Data)
diff --git a/win32/include/math.h b/win32/include/math.h
index 297184f..74add20 100644
--- a/win32/include/math.h
+++ b/win32/include/math.h
@@ -327,7 +327,7 @@ extern "C" {
#define isinf(x) (fpclassify(x) == FP_INFINITE)
/* 7.12.3.4 */
- /* We don't need to worry about trucation here:
+ /* We don't need to worry about truncation here:
A NaN stays a NaN. */
#define isnan(x) (fpclassify(x) == FP_NAN)
diff --git a/win32/include/stdint.h b/win32/include/stdint.h
index cdebf44..cde32b6 100644
--- a/win32/include/stdint.h
+++ b/win32/include/stdint.h
@@ -178,7 +178,7 @@ typedef unsigned long long uintmax_t;
/* 7.18.4.1 Macros for minimum-width integer constants
- Accoding to Douglas Gwyn <gwyn@arl.mil>:
+ According to Douglas Gwyn <gwyn@arl.mil>:
"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
9899:1999 as initially published, the expansion was required
to be an integer constant of precisely matching type, which
diff --git a/win32/include/tcc/tcc_libm.h b/win32/include/tcc/tcc_libm.h
index c9a6ad1..0a62e6f 100644
--- a/win32/include/tcc/tcc_libm.h
+++ b/win32/include/tcc/tcc_libm.h
@@ -1,7 +1,7 @@
#ifndef _TCC_LIBM_H_
#define _TCC_LIBM_H_
-#include "../include/math.h"
+#include "../math.h"
/* TCC uses 8 bytes for double and long double, so effectively the l variants
* are never used. For now, they just run the normal (double) variant.
@@ -20,7 +20,7 @@
musl as a whole is licensed under the following standard MIT license:
----------------------------------------------------------------------
-Copyright © 2005-2014 Rich Felker, et al.
+Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/win32/include/values.h b/win32/include/values.h
index 10e16a2..1cd643c 100644
--- a/win32/include/values.h
+++ b/win32/include/values.h
@@ -1,4 +1,4 @@
/*
* TODO: Nothing here yet. Should provide UNIX compatibility constants
- * comparible to those in limits.h and float.h.
+ * comparable to those in limits.h and float.h.
*/
diff --git a/win32/include/winapi/intrin.h b/win32/include/winapi/intrin.h
deleted file mode 100644
index 960a0f8..0000000
--- a/win32/include/winapi/intrin.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * 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 __INTRIN_H_
-#define __INTRIN_H_
-
-//!__TINYC__: intrinsic stuff removed
-
-#endif /* end __INTRIN_H_ */
diff --git a/win32/include/winapi/reason.h b/win32/include/winapi/reason.h
deleted file mode 100644
index 4d923e2..0000000
--- a/win32/include/winapi/reason.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * 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.
- */
-#if !defined SENTINEL_Reason
-#define SENTINEL_Reason
-
-#define SHTDN_REASON_FLAG_COMMENT_REQUIRED 0x01000000
-#define SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED 0x02000000
-#define SHTDN_REASON_FLAG_CLEAN_UI 0x04000000
-#define SHTDN_REASON_FLAG_DIRTY_UI 0x08000000
-#define SHTDN_REASON_FLAG_USER_DEFINED 0x40000000
-#define SHTDN_REASON_FLAG_PLANNED 0x80000000
-#define SHTDN_REASON_MAJOR_OTHER 0x00000000
-#define SHTDN_REASON_MAJOR_NONE 0x00000000
-#define SHTDN_REASON_MAJOR_HARDWARE 0x00010000
-#define SHTDN_REASON_MAJOR_OPERATINGSYSTEM 0x00020000
-#define SHTDN_REASON_MAJOR_SOFTWARE 0x00030000
-#define SHTDN_REASON_MAJOR_APPLICATION 0x00040000
-#define SHTDN_REASON_MAJOR_SYSTEM 0x00050000
-#define SHTDN_REASON_MAJOR_POWER 0x00060000
-#define SHTDN_REASON_MAJOR_LEGACY_API 0x00070000
-#define SHTDN_REASON_MINOR_OTHER 0x00000000
-#define SHTDN_REASON_MINOR_NONE 0x000000ff
-#define SHTDN_REASON_MINOR_MAINTENANCE 0x00000001
-#define SHTDN_REASON_MINOR_INSTALLATION 0x00000002
-#define SHTDN_REASON_MINOR_UPGRADE 0x00000003
-#define SHTDN_REASON_MINOR_RECONFIG 0x00000004
-#define SHTDN_REASON_MINOR_HUNG 0x00000005
-#define SHTDN_REASON_MINOR_UNSTABLE 0x00000006
-#define SHTDN_REASON_MINOR_DISK 0x00000007
-#define SHTDN_REASON_MINOR_PROCESSOR 0x00000008
-#define SHTDN_REASON_MINOR_NETWORKCARD 0x00000009
-#define SHTDN_REASON_MINOR_POWER_SUPPLY 0x0000000a
-#define SHTDN_REASON_MINOR_CORDUNPLUGGED 0x0000000b
-#define SHTDN_REASON_MINOR_ENVIRONMENT 0x0000000c
-#define SHTDN_REASON_MINOR_HARDWARE_DRIVER 0x0000000d
-#define SHTDN_REASON_MINOR_OTHERDRIVER 0x0000000e
-#define SHTDN_REASON_MINOR_BLUESCREEN 0x0000000F
-#define SHTDN_REASON_MINOR_SERVICEPACK 0x00000010
-#define SHTDN_REASON_MINOR_HOTFIX 0x00000011
-#define SHTDN_REASON_MINOR_SECURITYFIX 0x00000012
-#define SHTDN_REASON_MINOR_SECURITY 0x00000013
-#define SHTDN_REASON_MINOR_NETWORK_CONNECTIVITY 0x00000014
-#define SHTDN_REASON_MINOR_WMI 0x00000015
-#define SHTDN_REASON_MINOR_SERVICEPACK_UNINSTALL 0x00000016
-#define SHTDN_REASON_MINOR_HOTFIX_UNINSTALL 0x00000017
-#define SHTDN_REASON_MINOR_SECURITYFIX_UNINSTALL 0x00000018
-#define SHTDN_REASON_MINOR_MMC 0x00000019
-#define SHTDN_REASON_MINOR_SYSTEMRESTORE 0x0000001a
-#define SHTDN_REASON_MINOR_TERMSRV 0x00000020
-#define SHTDN_REASON_MINOR_DC_PROMOTION 0x00000021
-#define SHTDN_REASON_MINOR_DC_DEMOTION 0x00000022
-#define SHTDN_REASON_UNKNOWN SHTDN_REASON_MINOR_NONE
-#define SHTDN_REASON_LEGACY_API (SHTDN_REASON_MAJOR_LEGACY_API | SHTDN_REASON_FLAG_PLANNED)
-#define SHTDN_REASON_VALID_BIT_MASK 0xc0ffffff
-
-#define PCLEANUI (SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_FLAG_CLEAN_UI)
-#define UCLEANUI (SHTDN_REASON_FLAG_CLEAN_UI)
-#define PDIRTYUI (SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_FLAG_DIRTY_UI)
-#define UDIRTYUI (SHTDN_REASON_FLAG_DIRTY_UI)
-
-#define MAX_REASON_NAME_LEN 64
-#define MAX_REASON_DESC_LEN 256
-#define MAX_REASON_BUGID_LEN 32
-#define MAX_REASON_COMMENT_LEN 512
-#define SHUTDOWN_TYPE_LEN 32
-
-#define POLICY_SHOWREASONUI_NEVER 0
-#define POLICY_SHOWREASONUI_ALWAYS 1
-#define POLICY_SHOWREASONUI_WORKSTATIONONLY 2
-#define POLICY_SHOWREASONUI_SERVERONLY 3
-
-#define SNAPSHOT_POLICY_NEVER 0
-#define SNAPSHOT_POLICY_ALWAYS 1
-#define SNAPSHOT_POLICY_UNPLANNED 2
-
-#define MAX_NUM_REASONS 256
-#endif
diff --git a/win32/include/winapi/specstrings.h b/win32/include/winapi/specstrings.h
deleted file mode 100644
index 4130ed3..0000000
--- a/win32/include/winapi/specstrings.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * 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.
- */
-
-#define __specstrings
diff --git a/win32/include/winapi/stralign.h b/win32/include/winapi/stralign.h
deleted file mode 100644
index 3812035..0000000
--- a/win32/include/winapi/stralign.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * 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 __STRALIGN_H_
-#define __STRALIGN_H_
-
-#ifndef _STRALIGN_USE_SECURE_CRT
-#define _STRALIGN_USE_SECURE_CRT 0
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(I_X86_)
-#define WSTR_ALIGNED(s) TRUE
-#define ua_CharUpperW CharUpperW
-#define ua_lstrcmpiW lstrcmpiW
-#define ua_lstrcmpW lstrcmpW
-#define ua_lstrlenW lstrlenW
-#define ua_wcschr wcschr
-#define ua_wcsicmp wcsicmp
-#define ua_wcslen wcslen
-#define ua_wcsrchr wcsrchr
- static __inline PUWSTR ua_wcscpy(PUWSTR Destination,PCUWSTR Source) { return wcscpy(Destination,Source); }
-#else
-#define WSTR_ALIGNED(s) (((DWORD_PTR)(s) & (sizeof(WCHAR)-1))==0)
-
- LPUWSTR WINAPI uaw_CharUpperW(LPUWSTR String);
- int WINAPI uaw_lstrcmpW(PCUWSTR String1,PCUWSTR String2);
- int WINAPI uaw_lstrcmpiW(PCUWSTR String1,PCUWSTR String2);
- int WINAPI uaw_lstrlenW(LPCUWSTR String);
- PUWSTR __cdecl uaw_wcschr(PCUWSTR String,WCHAR Character);
- PUWSTR __cdecl uaw_wcscpy(PUWSTR Destination,PCUWSTR Source);
- int __cdecl uaw_wcsicmp(PCUWSTR String1,PCUWSTR String2);
- size_t __cdecl uaw_wcslen(PCUWSTR String);
- PUWSTR __cdecl uaw_wcsrchr(PCUWSTR String,WCHAR Character);
-#ifdef CharUpper
- static __inline LPUWSTR ua_CharUpperW(LPUWSTR String) {
- if(WSTR_ALIGNED(String)) return CharUpperW((PWSTR)String);
- return uaw_CharUpperW(String);
- }
-#endif
-
-#ifdef lstrcmp
- static __inline int ua_lstrcmpW(LPCUWSTR String1,LPCUWSTR String2) {
- if(WSTR_ALIGNED(String1) && WSTR_ALIGNED(String2)) return lstrcmpW((LPCWSTR)String1,(LPCWSTR)String2);
- return uaw_lstrcmpW(String1,String2);
- }
-#endif
-
-#ifdef lstrcmpi
- static __inline int ua_lstrcmpiW(LPCUWSTR String1,LPCUWSTR String2) {
- if(WSTR_ALIGNED(String1) && WSTR_ALIGNED(String2)) return lstrcmpiW((LPCWSTR)String1,(LPCWSTR)String2);
- return uaw_lstrcmpiW(String1,String2);
- }
-#endif
-
-#ifdef lstrlen
- static __inline int ua_lstrlenW(LPCUWSTR String) {
- if(WSTR_ALIGNED(String)) return lstrlenW((PCWSTR)String);
- return uaw_lstrlenW(String);
- }
-#endif
-
-#if defined(_WSTRING_DEFINED)
-#ifdef _WConst_return
- typedef _WConst_return WCHAR UNALIGNED *PUWSTR_C;
-#else
- typedef WCHAR UNALIGNED *PUWSTR_C;
-#endif
- static __inline PUWSTR_C ua_wcschr(PCUWSTR String,WCHAR Character) {
- if(WSTR_ALIGNED(String)) return wcschr((PCWSTR)String,Character);
- return (PUWSTR_C)uaw_wcschr(String,Character);
- }
- static __inline PUWSTR_C ua_wcsrchr(PCUWSTR String,WCHAR Character) {
- if(WSTR_ALIGNED(String)) return wcsrchr((PCWSTR)String,Character);
- return (PUWSTR_C)uaw_wcsrchr(String,Character);
- }
-#if defined(__cplusplus) && defined(_WConst_Return)
- static __inline PUWSTR ua_wcschr(PUWSTR String,WCHAR Character) {
- if(WSTR_ALIGNED(String)) return wcscpy((PWSTR)Destination,(PCWSTR)Source);
- return uaw_wcscpy(Destination,Source);
- }
- static __inline PUWSTR ua_wcsrchr(PUWSTR String,WCHAR Character) {
- if(WSTR_ALIGNED(String)) return wcsrchr(String,Character);
- return uaw_wcsrchr((PCUWSTR)String,Character);
- }
-#endif
-
- static __inline PUWSTR ua_wcscpy(PUWSTR Destination,PCUWSTR Source) {
- if(WSTR_ALIGNED(Source) && WSTR_ALIGNED(Destination)) return wcscpy((PWSTR)Destination,(PCWSTR)Source);
- return uaw_wcscpy(Destination,Source);
- }
- static __inline size_t ua_wcslen(PCUWSTR String) {
- if(WSTR_ALIGNED(String)) return wcslen((PCWSTR)String);
- return uaw_wcslen(String);
- }
-#endif
-
- static __inline int ua_wcsicmp(LPCUWSTR String1,LPCUWSTR String2) {
- if(WSTR_ALIGNED(String1) && WSTR_ALIGNED(String2)) return _wcsicmp((LPCWSTR)String1,(LPCWSTR)String2);
- return uaw_wcsicmp(String1,String2);
- }
-#endif
-
-#ifndef __UA_WCSLEN
-#define __UA_WCSLEN ua_wcslen
-#endif
-
-#define __UA_WSTRSIZE(s) ((__UA_WCSLEN(s)+1)*sizeof(WCHAR))
-#define __UA_STACKCOPY(p,s) memcpy(_alloca(s),p,s)
-
-#ifdef I_X86_
-#define WSTR_ALIGNED_STACK_COPY(d,s) (*(d) = (PCWSTR)(s))
-#else
-#define WSTR_ALIGNED_STACK_COPY(d,s) { PCUWSTR __ua_src; ULONG __ua_size; PWSTR __ua_dst; __ua_src = (s); if(WSTR_ALIGNED(__ua_src)) { __ua_dst = (PWSTR)__ua_src; } else { __ua_size = __UA_WSTRSIZE(__ua_src); __ua_dst = (PWSTR)_alloca(__ua_size); memcpy(__ua_dst,__ua_src,__ua_size); } *(d) = (PCWSTR)__ua_dst; }
-#endif
-
-#define ASTR_ALIGNED_STACK_COPY(d,s) (*(d) = (PCSTR)(s))
-
-#ifndef I_X86_
-#define __UA_STRUC_ALIGNED(t,s) (((DWORD_PTR)(s) & (TYPE_ALIGNMENT(t)-1))==0)
-#define STRUC_ALIGNED_STACK_COPY(t,s) __UA_STRUC_ALIGNED(t,s) ? ((t const *)(s)) : ((t const *)__UA_STACKCOPY((s),sizeof(t)))
-#else
-#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))
-#endif
-
-#ifdef UNICODE
-#define TSTR_ALIGNED_STACK_COPY(d,s) WSTR_ALIGNED_STACK_COPY(d,s)
-#define TSTR_ALIGNED(x) WSTR_ALIGNED(x)
-#define ua_CharUpper ua_CharUpperW
-#define ua_lstrcmp ua_lstrcmpW
-#define ua_lstrcmpi ua_lstrcmpiW
-#define ua_lstrlen ua_lstrlenW
-#define ua_tcscpy ua_wcscpy
-#else
-#define TSTR_ALIGNED_STACK_COPY(d,s) ASTR_ALIGNED_STACK_COPY(d,s)
-#define TSTR_ALIGNED(x) TRUE
-#define ua_CharUpper CharUpperA
-#define ua_lstrcmp lstrcmpA
-#define ua_lstrcmpi lstrcmpiA
-#define ua_lstrlen lstrlenA
-#define ua_tcscpy strcpy
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#include <sec_api/stralign_s.h>
-#endif
diff --git a/win32/include/winapi/windef.h b/win32/include/winapi/windef.h
index 3e38816..d63bdef 100644
--- a/win32/include/winapi/windef.h
+++ b/win32/include/winapi/windef.h
@@ -122,7 +122,7 @@ typedef CONST void *LPCVOID;
#include <winnt.h>
#endif
-#include <specstrings.h>
+//gr #include <specstrings.h>
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
diff --git a/win32/include/winapi/windows.h b/win32/include/winapi/windows.h
index 38c2414..2660d7f 100644
--- a/win32/include/winapi/windows.h
+++ b/win32/include/winapi/windows.h
@@ -67,11 +67,11 @@
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
-#include <winnls.h>
+//gr #include <winnls.h>
#include <wincon.h>
#include <winver.h>
#include <winreg.h>
-#include <winnetwk.h>
+//gr #include <winnetwk.h>
#ifndef WIN32_LEAN_AND_MEAN
#include <cderr.h>
@@ -104,7 +104,7 @@
#endif
#endif
-#include <stralign.h>
+//gr #include <stralign.h>
#ifdef INC_OLE2
#include <ole2.h>
diff --git a/win32/include/winapi/winnetwk.h b/win32/include/winapi/winnetwk.h
deleted file mode 100644
index afb7f4f..0000000
--- a/win32/include/winapi/winnetwk.h
+++ /dev/null
@@ -1,476 +0,0 @@
-/**
- * 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 _WINNETWK_
-#define _WINNETWK_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define WNNC_NET_MSNET 0x00010000
-#define WNNC_NET_LANMAN 0x00020000
-#define WNNC_NET_NETWARE 0x00030000
-#define WNNC_NET_VINES 0x00040000
-#define WNNC_NET_10NET 0x00050000
-#define WNNC_NET_LOCUS 0x00060000
-#define WNNC_NET_SUN_PC_NFS 0x00070000
-#define WNNC_NET_LANSTEP 0x00080000
-#define WNNC_NET_9TILES 0x00090000
-#define WNNC_NET_LANTASTIC 0x000A0000
-#define WNNC_NET_AS400 0x000B0000
-#define WNNC_NET_FTP_NFS 0x000C0000
-#define WNNC_NET_PATHWORKS 0x000D0000
-#define WNNC_NET_LIFENET 0x000E0000
-#define WNNC_NET_POWERLAN 0x000F0000
-#define WNNC_NET_BWNFS 0x00100000
-#define WNNC_NET_COGENT 0x00110000
-#define WNNC_NET_FARALLON 0x00120000
-#define WNNC_NET_APPLETALK 0x00130000
-#define WNNC_NET_INTERGRAPH 0x00140000
-#define WNNC_NET_SYMFONET 0x00150000
-#define WNNC_NET_CLEARCASE 0x00160000
-#define WNNC_NET_FRONTIER 0x00170000
-#define WNNC_NET_BMC 0x00180000
-#define WNNC_NET_DCE 0x00190000
-#define WNNC_NET_AVID 0x001A0000
-#define WNNC_NET_DOCUSPACE 0x001B0000
-#define WNNC_NET_MANGOSOFT 0x001C0000
-#define WNNC_NET_SERNET 0x001D0000
-#define WNNC_NET_RIVERFRONT1 0X001E0000
-#define WNNC_NET_RIVERFRONT2 0x001F0000
-#define WNNC_NET_DECORB 0x00200000
-#define WNNC_NET_PROTSTOR 0x00210000
-#define WNNC_NET_FJ_REDIR 0x00220000
-#define WNNC_NET_DISTINCT 0x00230000
-#define WNNC_NET_TWINS 0x00240000
-#define WNNC_NET_RDR2SAMPLE 0x00250000
-#define WNNC_NET_CSC 0x00260000
-#define WNNC_NET_3IN1 0x00270000
-#define WNNC_NET_EXTENDNET 0x00290000
-#define WNNC_NET_STAC 0x002A0000
-#define WNNC_NET_FOXBAT 0x002B0000
-#define WNNC_NET_YAHOO 0x002C0000
-#define WNNC_NET_EXIFS 0x002D0000
-#define WNNC_NET_DAV 0x002E0000
-#define WNNC_NET_KNOWARE 0x002F0000
-#define WNNC_NET_OBJECT_DIRE 0x00300000
-#define WNNC_NET_MASFAX 0x00310000
-#define WNNC_NET_HOB_NFS 0x00320000
-#define WNNC_NET_SHIVA 0x00330000
-#define WNNC_NET_IBMAL 0x00340000
-#define WNNC_NET_LOCK 0x00350000
-#define WNNC_NET_TERMSRV 0x00360000
-#define WNNC_NET_SRT 0x00370000
-#define WNNC_NET_QUINCY 0x00380000
-
-#define WNNC_CRED_MANAGER 0xFFFF0000
-
-#define RESOURCE_CONNECTED 0x00000001
-#define RESOURCE_GLOBALNET 0x00000002
-#define RESOURCE_REMEMBERED 0x00000003
-#define RESOURCE_RECENT 0x00000004
-#define RESOURCE_CONTEXT 0x00000005
-
-#define RESOURCETYPE_ANY 0x00000000
-#define RESOURCETYPE_DISK 0x00000001
-#define RESOURCETYPE_PRINT 0x00000002
-#define RESOURCETYPE_RESERVED 0x00000008
-#define RESOURCETYPE_UNKNOWN 0xFFFFFFFF
-
-#define RESOURCEUSAGE_CONNECTABLE 0x00000001
-#define RESOURCEUSAGE_CONTAINER 0x00000002
-#define RESOURCEUSAGE_NOLOCALDEVICE 0x00000004
-#define RESOURCEUSAGE_SIBLING 0x00000008
-#define RESOURCEUSAGE_ATTACHED 0x00000010
-#define RESOURCEUSAGE_ALL (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED)
-#define RESOURCEUSAGE_RESERVED 0x80000000
-
-#define RESOURCEDISPLAYTYPE_GENERIC 0x00000000
-#define RESOURCEDISPLAYTYPE_DOMAIN 0x00000001
-#define RESOURCEDISPLAYTYPE_SERVER 0x00000002
-#define RESOURCEDISPLAYTYPE_SHARE 0x00000003
-#define RESOURCEDISPLAYTYPE_FILE 0x00000004
-#define RESOURCEDISPLAYTYPE_GROUP 0x00000005
-#define RESOURCEDISPLAYTYPE_NETWORK 0x00000006
-#define RESOURCEDISPLAYTYPE_ROOT 0x00000007
-#define RESOURCEDISPLAYTYPE_SHAREADMIN 0x00000008
-#define RESOURCEDISPLAYTYPE_DIRECTORY 0x00000009
-#define RESOURCEDISPLAYTYPE_TREE 0x0000000A
-#define RESOURCEDISPLAYTYPE_NDSCONTAINER 0x0000000B
-
- typedef struct _NETRESOURCEA {
- DWORD dwScope;
- DWORD dwType;
- DWORD dwDisplayType;
- DWORD dwUsage;
- LPSTR lpLocalName;
- LPSTR lpRemoteName;
- LPSTR lpComment;
- LPSTR lpProvider;
- }NETRESOURCEA,*LPNETRESOURCEA;
- typedef struct _NETRESOURCEW {
- DWORD dwScope;
- DWORD dwType;
- DWORD dwDisplayType;
- DWORD dwUsage;
- LPWSTR lpLocalName;
- LPWSTR lpRemoteName;
- LPWSTR lpComment;
- LPWSTR lpProvider;
- }NETRESOURCEW,*LPNETRESOURCEW;
-#ifdef UNICODE
- typedef NETRESOURCEW NETRESOURCE;
- typedef LPNETRESOURCEW LPNETRESOURCE;
-#else
- typedef NETRESOURCEA NETRESOURCE;
- typedef LPNETRESOURCEA LPNETRESOURCE;
-#endif
-
-#define NETPROPERTY_PERSISTENT 1
-
-#define CONNECT_UPDATE_PROFILE 0x00000001
-#define CONNECT_UPDATE_RECENT 0x00000002
-#define CONNECT_TEMPORARY 0x00000004
-#define CONNECT_INTERACTIVE 0x00000008
-#define CONNECT_PROMPT 0x00000010
-#define CONNECT_NEED_DRIVE 0x00000020
-#define CONNECT_REFCOUNT 0x00000040
-#define CONNECT_REDIRECT 0x00000080
-#define CONNECT_LOCALDRIVE 0x00000100
-#define CONNECT_CURRENT_MEDIA 0x00000200
-#define CONNECT_DEFERRED 0x00000400
-#define CONNECT_RESERVED 0xFF000000
-#define CONNECT_COMMANDLINE 0x00000800
-#define CONNECT_CMD_SAVECRED 0x00001000
-
-#ifdef UNICODE
-#define WNetAddConnection WNetAddConnectionW
-#define WNetAddConnection2 WNetAddConnection2W
-#define WNetAddConnection3 WNetAddConnection3W
-#define WNetCancelConnection WNetCancelConnectionW
-#define WNetCancelConnection2 WNetCancelConnection2W
-#define WNetGetConnection WNetGetConnectionW
-#define WNetRestoreConnection WNetRestoreConnectionW
-#define WNetUseConnection WNetUseConnectionW
-#else
-#define WNetAddConnection WNetAddConnectionA
-#define WNetAddConnection2 WNetAddConnection2A
-#define WNetAddConnection3 WNetAddConnection3A
-#define WNetCancelConnection WNetCancelConnectionA
-#define WNetCancelConnection2 WNetCancelConnection2A
-#define WNetGetConnection WNetGetConnectionA
-#define WNetRestoreConnection WNetRestoreConnectionA
-#define WNetUseConnection WNetUseConnectionA
-#endif
-
- DWORD WINAPI WNetAddConnectionA(LPCSTR lpRemoteName,LPCSTR lpPassword,LPCSTR lpLocalName);
- DWORD WINAPI WNetAddConnectionW(LPCWSTR lpRemoteName,LPCWSTR lpPassword,LPCWSTR lpLocalName);
- DWORD WINAPI WNetAddConnection2A(LPNETRESOURCEA lpNetResource,LPCSTR lpPassword,LPCSTR lpUserName,DWORD dwFlags);
- DWORD WINAPI WNetAddConnection2W(LPNETRESOURCEW lpNetResource,LPCWSTR lpPassword,LPCWSTR lpUserName,DWORD dwFlags);
- DWORD WINAPI WNetAddConnection3A(HWND hwndOwner,LPNETRESOURCEA lpNetResource,LPCSTR lpPassword,LPCSTR lpUserName,DWORD dwFlags);
- DWORD WINAPI WNetAddConnection3W(HWND hwndOwner,LPNETRESOURCEW lpNetResource,LPCWSTR lpPassword,LPCWSTR lpUserName,DWORD dwFlags);
- DWORD WINAPI WNetCancelConnectionA(LPCSTR lpName,WINBOOL fForce);
- DWORD WINAPI WNetCancelConnectionW(LPCWSTR lpName,WINBOOL fForce);
- DWORD WINAPI WNetCancelConnection2A(LPCSTR lpName,DWORD dwFlags,WINBOOL fForce);
- DWORD WINAPI WNetCancelConnection2W(LPCWSTR lpName,DWORD dwFlags,WINBOOL fForce);
- DWORD WINAPI WNetGetConnectionA(LPCSTR lpLocalName,LPSTR lpRemoteName,LPDWORD lpnLength);
- DWORD WINAPI WNetGetConnectionW(LPCWSTR lpLocalName,LPWSTR lpRemoteName,LPDWORD lpnLength);
- DWORD WINAPI WNetRestoreConnectionA(HWND hwndParent,LPCSTR lpDevice);
- DWORD WINAPI WNetRestoreConnectionW(HWND hwndParent,LPCWSTR lpDevice);
- DWORD WINAPI WNetUseConnectionA(HWND hwndOwner,LPNETRESOURCEA lpNetResource,LPCSTR lpPassword,LPCSTR lpUserID,DWORD dwFlags,LPSTR lpAccessName,LPDWORD lpBufferSize,LPDWORD lpResult);
- DWORD WINAPI WNetUseConnectionW(HWND hwndOwner,LPNETRESOURCEW lpNetResource,LPCWSTR lpPassword,LPCWSTR lpUserID,DWORD dwFlags,LPWSTR lpAccessName,LPDWORD lpBufferSize,LPDWORD lpResult);
- DWORD WINAPI WNetConnectionDialog(HWND hwnd,DWORD dwType);
- DWORD WINAPI WNetDisconnectDialog(HWND hwnd,DWORD dwType);
-
- typedef struct _CONNECTDLGSTRUCTA {
- DWORD cbStructure;
- HWND hwndOwner;
- LPNETRESOURCEA lpConnRes;
- DWORD dwFlags;
- DWORD dwDevNum;
- } CONNECTDLGSTRUCTA,*LPCONNECTDLGSTRUCTA;
-
- typedef struct _CONNECTDLGSTRUCTW {
- DWORD cbStructure;
- HWND hwndOwner;
- LPNETRESOURCEW lpConnRes;
- DWORD dwFlags;
- DWORD dwDevNum;
- } CONNECTDLGSTRUCTW,*LPCONNECTDLGSTRUCTW;
-#ifdef UNICODE
- typedef CONNECTDLGSTRUCTW CONNECTDLGSTRUCT;
- typedef LPCONNECTDLGSTRUCTW LPCONNECTDLGSTRUCT;
-#else
- typedef CONNECTDLGSTRUCTA CONNECTDLGSTRUCT;
- typedef LPCONNECTDLGSTRUCTA LPCONNECTDLGSTRUCT;
-#endif
-
-#define CONNDLG_RO_PATH 0x00000001
-#define CONNDLG_CONN_POINT 0x00000002
-#define CONNDLG_USE_MRU 0x00000004
-#define CONNDLG_HIDE_BOX 0x00000008
-
-#define CONNDLG_PERSIST 0x00000010
-#define CONNDLG_NOT_PERSIST 0x00000020
-
-#ifdef UNICODE
-#define WNetConnectionDialog1 WNetConnectionDialog1W
-#else
-#define WNetConnectionDialog1 WNetConnectionDialog1A
-#endif
-
- DWORD WINAPI WNetConnectionDialog1A(LPCONNECTDLGSTRUCTA lpConnDlgStruct);
- DWORD WINAPI WNetConnectionDialog1W(LPCONNECTDLGSTRUCTW lpConnDlgStruct);
-
- typedef struct _DISCDLGSTRUCTA {
- DWORD cbStructure;
- HWND hwndOwner;
- LPSTR lpLocalName;
- LPSTR lpRemoteName;
- DWORD dwFlags;
- } DISCDLGSTRUCTA,*LPDISCDLGSTRUCTA;
-
- typedef struct _DISCDLGSTRUCTW {
- DWORD cbStructure;
- HWND hwndOwner;
- LPWSTR lpLocalName;
- LPWSTR lpRemoteName;
- DWORD dwFlags;
- } DISCDLGSTRUCTW,*LPDISCDLGSTRUCTW;
-
-#ifdef UNICODE
- typedef DISCDLGSTRUCTW DISCDLGSTRUCT;
- typedef LPDISCDLGSTRUCTW LPDISCDLGSTRUCT;
-#else
- typedef DISCDLGSTRUCTA DISCDLGSTRUCT;
- typedef LPDISCDLGSTRUCTA LPDISCDLGSTRUCT;
-#endif
-
-#define DISC_UPDATE_PROFILE 0x00000001
-#define DISC_NO_FORCE 0x00000040
-
-#ifdef UNICODE
-#define WNetDisconnectDialog1 WNetDisconnectDialog1W
-#define WNetOpenEnum WNetOpenEnumW
-#define WNetEnumResource WNetEnumResourceW
-#define WNetGetResourceParent WNetGetResourceParentW
-#define WNetGetResourceInformation WNetGetResourceInformationW
-#else
-#define WNetDisconnectDialog1 WNetDisconnectDialog1A
-#define WNetOpenEnum WNetOpenEnumA
-#define WNetEnumResource WNetEnumResourceA
-#define WNetGetResourceParent WNetGetResourceParentA
-#define WNetGetResourceInformation WNetGetResourceInformationA
-#endif
-
- DWORD WINAPI WNetDisconnectDialog1A(LPDISCDLGSTRUCTA lpConnDlgStruct);
- DWORD WINAPI WNetDisconnectDialog1W(LPDISCDLGSTRUCTW lpConnDlgStruct);
- DWORD WINAPI WNetOpenEnumA(DWORD dwScope,DWORD dwType,DWORD dwUsage,LPNETRESOURCEA lpNetResource,LPHANDLE lphEnum);
- DWORD WINAPI WNetOpenEnumW(DWORD dwScope,DWORD dwType,DWORD dwUsage,LPNETRESOURCEW lpNetResource,LPHANDLE lphEnum);
- DWORD WINAPI WNetEnumResourceA(HANDLE hEnum,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize);
- DWORD WINAPI WNetEnumResourceW(HANDLE hEnum,LPDWORD lpcCount,LPVOID lpBuffer,LPDWORD lpBufferSize);
- DWORD WINAPI WNetCloseEnum(HANDLE hEnum);
- DWORD WINAPI WNetGetResourceParentA(LPNETRESOURCEA lpNetResource,LPVOID lpBuffer,LPDWORD lpcbBuffer);
- DWORD WINAPI WNetGetResourceParentW(LPNETRESOURCEW lpNetResource,LPVOID lpBuffer,LPDWORD lpcbBuffer);
- DWORD WINAPI WNetGetResourceInformationA(LPNETRESOURCEA lpNetResource,LPVOID lpBuffer,LPDWORD lpcbBuffer,LPSTR *lplpSystem);
- DWORD WINAPI WNetGetResourceInformationW(LPNETRESOURCEW lpNetResource,LPVOID lpBuffer,LPDWORD lpcbBuffer,LPWSTR *lplpSystem);
-
-#define UNIVERSAL_NAME_INFO_LEVEL 0x00000001
-#define REMOTE_NAME_INFO_LEVEL 0x00000002
-
- typedef struct _UNIVERSAL_NAME_INFOA {
- LPSTR lpUniversalName;
- } UNIVERSAL_NAME_INFOA,*LPUNIVERSAL_NAME_INFOA;
-
- typedef struct _UNIVERSAL_NAME_INFOW {
- LPWSTR lpUniversalName;
- } UNIVERSAL_NAME_INFOW,*LPUNIVERSAL_NAME_INFOW;
-
-#ifdef UNICODE
- typedef UNIVERSAL_NAME_INFOW UNIVERSAL_NAME_INFO;
- typedef LPUNIVERSAL_NAME_INFOW LPUNIVERSAL_NAME_INFO;
-#else
- typedef UNIVERSAL_NAME_INFOA UNIVERSAL_NAME_INFO;
- typedef LPUNIVERSAL_NAME_INFOA LPUNIVERSAL_NAME_INFO;
-#endif
-
- typedef struct _REMOTE_NAME_INFOA {
- LPSTR lpUniversalName;
- LPSTR lpConnectionName;
- LPSTR lpRemainingPath;
- } REMOTE_NAME_INFOA,*LPREMOTE_NAME_INFOA;
-
- typedef struct _REMOTE_NAME_INFOW {
- LPWSTR lpUniversalName;
- LPWSTR lpConnectionName;
- LPWSTR lpRemainingPath;
- } REMOTE_NAME_INFOW,*LPREMOTE_NAME_INFOW;
-
-#ifdef UNICODE
- typedef REMOTE_NAME_INFOW REMOTE_NAME_INFO;
- typedef LPREMOTE_NAME_INFOW LPREMOTE_NAME_INFO;
-#else
- typedef REMOTE_NAME_INFOA REMOTE_NAME_INFO;
- typedef LPREMOTE_NAME_INFOA LPREMOTE_NAME_INFO;
-#endif
-
-#ifdef UNICODE
-#define WNetGetUniversalName WNetGetUniversalNameW
-#define WNetGetUser WNetGetUserW
-#define WNetGetProviderName WNetGetProviderNameW
-#else
-#define WNetGetUniversalName WNetGetUniversalNameA
-#define WNetGetUser WNetGetUserA
-#define WNetGetProviderName WNetGetProviderNameA
-#endif
-
- DWORD WINAPI WNetGetUniversalNameA(LPCSTR lpLocalPath,DWORD dwInfoLevel,LPVOID lpBuffer,LPDWORD lpBufferSize);
- DWORD WINAPI WNetGetUniversalNameW(LPCWSTR lpLocalPath,DWORD dwInfoLevel,LPVOID lpBuffer,LPDWORD lpBufferSize);
- DWORD WINAPI WNetGetUserA(LPCSTR lpName,LPSTR lpUserName,LPDWORD lpnLength);
- DWORD WINAPI WNetGetUserW(LPCWSTR lpName,LPWSTR lpUserName,LPDWORD lpnLength);
-
-#define WNFMT_MULTILINE 0x01
-#define WNFMT_ABBREVIATED 0x02
-#define WNFMT_INENUM 0x10
-#define WNFMT_CONNECTION 0x20
-
- DWORD WINAPI WNetGetProviderNameA(DWORD dwNetType,LPSTR lpProviderName,LPDWORD lpBufferSize);
- DWORD WINAPI WNetGetProviderNameW(DWORD dwNetType,LPWSTR lpProviderName,LPDWORD lpBufferSize);
-
- typedef struct _NETINFOSTRUCT {
- DWORD cbStructure;
- DWORD dwProviderVersion;
- DWORD dwStatus;
- DWORD dwCharacteristics;
- ULONG_PTR dwHandle;
- WORD wNetType;
- DWORD dwPrinters;
- DWORD dwDrives;
- } NETINFOSTRUCT,*LPNETINFOSTRUCT;
-
-#define NETINFO_DLL16 0x00000001
-#define NETINFO_DISKRED 0x00000004
-#define NETINFO_PRINTERRED 0x00000008
-
-#ifdef UNICODE
-#define WNetGetNetworkInformation WNetGetNetworkInformationW
-#else
-#define WNetGetNetworkInformation WNetGetNetworkInformationA
-#endif
-
- DWORD WINAPI WNetGetNetworkInformationA(LPCSTR lpProvider,LPNETINFOSTRUCT lpNetInfoStruct);
- DWORD WINAPI WNetGetNetworkInformationW(LPCWSTR lpProvider,LPNETINFOSTRUCT lpNetInfoStruct);
-
- typedef UINT (WINAPI *PFNGETPROFILEPATHA) (LPCSTR pszUsername,LPSTR pszBuffer,UINT cbBuffer);
- typedef UINT (WINAPI *PFNGETPROFILEPATHW) (LPCWSTR pszUsername,LPWSTR pszBuffer,UINT cbBuffer);
-
-#ifdef UNICODE
-#define PFNGETPROFILEPATH PFNGETPROFILEPATHW
-#else
-#define PFNGETPROFILEPATH PFNGETPROFILEPATHA
-#endif
-
- typedef UINT (WINAPI *PFNRECONCILEPROFILEA) (LPCSTR pszCentralFile,LPCSTR pszLocalFile,DWORD dwFlags);
- typedef UINT (WINAPI *PFNRECONCILEPROFILEW) (LPCWSTR pszCentralFile,LPCWSTR pszLocalFile,DWORD dwFlags);
-
-#ifdef UNICODE
-#define PFNRECONCILEPROFILE PFNRECONCILEPROFILEW
-#else
-#define PFNRECONCILEPROFILE PFNRECONCILEPROFILEA
-#endif
-
-#define RP_LOGON 0x01
-#define RP_INIFILE 0x02
-
- typedef WINBOOL (WINAPI *PFNPROCESSPOLICIESA) (HWND hwnd,LPCSTR pszPath,LPCSTR pszUsername,LPCSTR pszComputerName,DWORD dwFlags);
- typedef WINBOOL (WINAPI *PFNPROCESSPOLICIESW) (HWND hwnd,LPCWSTR pszPath,LPCWSTR pszUsername,LPCWSTR pszComputerName,DWORD dwFlags);
-
-#ifdef UNICODE
-#define PFNPROCESSPOLICIES PFNPROCESSPOLICIESW
-#else
-#define PFNPROCESSPOLICIES PFNPROCESSPOLICIESA
-#endif
-
-#define PP_DISPLAYERRORS 0x01
-
-#ifdef UNICODE
-#define WNetGetLastError WNetGetLastErrorW
-#else
-#define WNetGetLastError WNetGetLastErrorA
-#endif
-
- DWORD WINAPI WNetGetLastErrorA(LPDWORD lpError,LPSTR lpErrorBuf,DWORD nErrorBufSize,LPSTR lpNameBuf,DWORD nNameBufSize);
- DWORD WINAPI WNetGetLastErrorW(LPDWORD lpError,LPWSTR lpErrorBuf,DWORD nErrorBufSize,LPWSTR lpNameBuf,DWORD nNameBufSize);
-
-#define WN_SUCCESS NO_ERROR
-#define WN_NO_ERROR NO_ERROR
-#define WN_NOT_SUPPORTED ERROR_NOT_SUPPORTED
-#define WN_CANCEL ERROR_CANCELLED
-#define WN_RETRY ERROR_RETRY
-#define WN_NET_ERROR ERROR_UNEXP_NET_ERR
-#define WN_MORE_DATA ERROR_MORE_DATA
-#define WN_BAD_POINTER ERROR_INVALID_ADDRESS
-#define WN_BAD_VALUE ERROR_INVALID_PARAMETER
-#define WN_BAD_USER ERROR_BAD_USERNAME
-#define WN_BAD_PASSWORD ERROR_INVALID_PASSWORD
-#define WN_ACCESS_DENIED ERROR_ACCESS_DENIED
-#define WN_FUNCTION_BUSY ERROR_BUSY
-#define WN_WINDOWS_ERROR ERROR_UNEXP_NET_ERR
-#define WN_OUT_OF_MEMORY ERROR_NOT_ENOUGH_MEMORY
-#define WN_NO_NETWORK ERROR_NO_NETWORK
-#define WN_EXTENDED_ERROR ERROR_EXTENDED_ERROR
-#define WN_BAD_LEVEL ERROR_INVALID_LEVEL
-#define WN_BAD_HANDLE ERROR_INVALID_HANDLE
-#define WN_NOT_INITIALIZING ERROR_ALREADY_INITIALIZED
-#define WN_NO_MORE_DEVICES ERROR_NO_MORE_DEVICES
-#define WN_NOT_CONNECTED ERROR_NOT_CONNECTED
-#define WN_OPEN_FILES ERROR_OPEN_FILES
-#define WN_DEVICE_IN_USE ERROR_DEVICE_IN_USE
-#define WN_BAD_NETNAME ERROR_BAD_NET_NAME
-#define WN_BAD_LOCALNAME ERROR_BAD_DEVICE
-#define WN_ALREADY_CONNECTED ERROR_ALREADY_ASSIGNED
-#define WN_DEVICE_ERROR ERROR_GEN_FAILURE
-#define WN_CONNECTION_CLOSED ERROR_CONNECTION_UNAVAIL
-#define WN_NO_NET_OR_BAD_PATH ERROR_NO_NET_OR_BAD_PATH
-#define WN_BAD_PROVIDER ERROR_BAD_PROVIDER
-#define WN_CANNOT_OPEN_PROFILE ERROR_CANNOT_OPEN_PROFILE
-#define WN_BAD_PROFILE ERROR_BAD_PROFILE
-#define WN_BAD_DEV_TYPE ERROR_BAD_DEV_TYPE
-#define WN_DEVICE_ALREADY_REMEMBERED ERROR_DEVICE_ALREADY_REMEMBERED
-#define WN_CONNECTED_OTHER_PASSWORD ERROR_CONNECTED_OTHER_PASSWORD
-#define WN_CONNECTED_OTHER_PASSWORD_DEFAULT ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT
-#define WN_NO_MORE_ENTRIES ERROR_NO_MORE_ITEMS
-#define WN_NOT_CONTAINER ERROR_NOT_CONTAINER
-#define WN_NOT_AUTHENTICATED ERROR_NOT_AUTHENTICATED
-#define WN_NOT_LOGGED_ON ERROR_NOT_LOGGED_ON
-#define WN_NOT_VALIDATED ERROR_NO_LOGON_SERVERS
-
- typedef struct _NETCONNECTINFOSTRUCT {
- DWORD cbStructure;
- DWORD dwFlags;
- DWORD dwSpeed;
- DWORD dwDelay;
- DWORD dwOptDataSize;
- } NETCONNECTINFOSTRUCT,*LPNETCONNECTINFOSTRUCT;
-
-#define WNCON_FORNETCARD 0x00000001
-#define WNCON_NOTROUTED 0x00000002
-#define WNCON_SLOWLINK 0x00000004
-#define WNCON_DYNAMIC 0x00000008
-
-#ifdef UNICODE
-#define MultinetGetConnectionPerformance MultinetGetConnectionPerformanceW
-#else
-#define MultinetGetConnectionPerformance MultinetGetConnectionPerformanceA
-#endif
-
- DWORD WINAPI MultinetGetConnectionPerformanceA(LPNETRESOURCEA lpNetResource,LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct);
- DWORD WINAPI MultinetGetConnectionPerformanceW(LPNETRESOURCEW lpNetResource,LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/win32/include/winapi/winnls.h b/win32/include/winapi/winnls.h
deleted file mode 100644
index 563c643..0000000
--- a/win32/include/winapi/winnls.h
+++ /dev/null
@@ -1,765 +0,0 @@
-/**
- * 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 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);
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/win32/include/winapi/winnt.h b/win32/include/winapi/winnt.h
index 348d9a8..4cf685d 100644
--- a/win32/include/winapi/winnt.h
+++ b/win32/include/winapi/winnt.h
@@ -13,7 +13,7 @@ extern "C" {
#include <ctype.h>
#define ANYSIZE_ARRAY 1
-#include <specstrings.h>
+//gr #include <specstrings.h>
#define RESTRICTED_POINTER
diff --git a/win32/include/winapi/winreg.h b/win32/include/winapi/winreg.h
index 50e5ff3..f158d28 100644
--- a/win32/include/winapi/winreg.h
+++ b/win32/include/winapi/winreg.h
@@ -238,7 +238,7 @@ extern "C" {
WINADVAPI WINBOOL WINAPI AbortSystemShutdownA(LPSTR lpMachineName);
WINADVAPI WINBOOL WINAPI AbortSystemShutdownW(LPWSTR lpMachineName);
-#include <reason.h>
+//gr #include <reason.h>
#define REASON_SWINSTALL SHTDN_REASON_MAJOR_SOFTWARE|SHTDN_REASON_MINOR_INSTALLATION
#define REASON_HWINSTALL SHTDN_REASON_MAJOR_HARDWARE|SHTDN_REASON_MINOR_INSTALLATION
diff --git a/win32/lib/chkstk.S b/win32/lib/chkstk.S
index 2726061..ec5c07f 100644
--- a/win32/lib/chkstk.S
+++ b/win32/lib/chkstk.S
@@ -2,7 +2,7 @@
/* chkstk86.s */
/* ---------------------------------------------- */
-#ifndef TCC_TARGET_X86_64
+#ifndef __x86_64__
/* ---------------------------------------------- */
.globl __chkstk
@@ -68,7 +68,7 @@ tinyc_getbp:
/* ---------------------------------------------- */
-#ifndef TCC_TARGET_X86_64
+#ifndef __x86_64__
/* ---------------------------------------------- */
/*
diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c
index 7a2d765..0e04fc0 100644
--- a/win32/lib/crt1.c
+++ b/win32/lib/crt1.c
@@ -1,6 +1,9 @@
// =============================================
// crt1.c
+// _UNICODE for tchar.h, UNICODE for API
+#include <tchar.h>
+
#include <stdio.h>
#include <stdlib.h>
@@ -13,41 +16,64 @@
#define _PC_53 0x00010000 // 53 bits
#define _PC_64 0x00000000 // 64 bits
-typedef struct
-{
- int newmode;
-} _startupinfo;
+#ifdef _UNICODE
+#define __tgetmainargs __wgetmainargs
+#define _tstart _wstart
+#define _tmain wmain
+#define _runtmain _runwmain
+#else
+#define __tgetmainargs __getmainargs
+#define _tstart _start
+#define _tmain main
+#define _runtmain _runmain
+#endif
-int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
+typedef struct { int newmode; } _startupinfo;
+int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
void __cdecl __set_app_type(int apptype);
unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask);
-int main(int argc, char * argv[], char * env[]);
+extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
/* Allow command-line globbing with "int _dowildcard = 1;" in the user source */
int _dowildcard;
-void _start(void)
+void _tstart(void)
{
__TRY__
- int argc, ret;
- char **argv;
- char **env;
- _startupinfo start_info;
+ _startupinfo start_info = {0};
// Sets the current application type
__set_app_type(_CONSOLE_APP);
// Set default FP precision to 53 bits (8-byte double)
- // _MCW_PC (Precision control) is not supported on
- // the ARM and x64 architectures
-#ifdef __i386
+ // _MCW_PC (Precision control) is not supported on ARM
+#if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC);
#endif
- start_info.newmode = 0;
- __getmainargs( &argc, &argv, &env, _dowildcard, &start_info);
- ret = main(argc, argv, env);
- exit(ret);
+ __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
+ exit(_tmain(__argc, __targv, _tenviron));
+}
+
+int _runtmain(int argc, /* as tcc passed in */ char **argv)
+{
+#ifdef UNICODE
+ _startupinfo start_info = {0};
+
+ __tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info);
+ /* may be wrong when tcc has received wildcards (*.c) */
+ if (argc < __argc) {
+ __targv += __argc - argc;
+ __argc = argc;
+ }
+#else
+ __argc = argc;
+ __targv = argv;
+#endif
+#if defined __i386__ || defined __x86_64__
+ _controlfp(_PC_53, _MCW_PC);
+#endif
+ return _tmain(__argc, __targv, _tenviron);
}
// =============================================
diff --git a/win32/lib/crt1w.c b/win32/lib/crt1w.c
new file mode 100644
index 0000000..2b8bbc8
--- /dev/null
+++ b/win32/lib/crt1w.c
@@ -0,0 +1,3 @@
+#define _UNICODE 1
+#define UNICODE 1
+#include "crt1.c"
diff --git a/win32/lib/user32.def b/win32/lib/user32.def
index 4d2f704..a034dac 100644
--- a/win32/lib/user32.def
+++ b/win32/lib/user32.def
@@ -336,6 +336,10 @@ GetWindow
GetWindowContextHelpId
GetWindowDC
GetWindowInfo
+GetWindowLongPtrA
+GetWindowLongPtrW
+SetWindowLongPtrA
+SetWindowLongPtrW
GetWindowLongA
GetWindowLongW
GetWindowModuleFileNameA
diff --git a/win32/lib/wincrt1.c b/win32/lib/wincrt1.c
index 663fd33..ce3a63f 100644
--- a/win32/lib/wincrt1.c
+++ b/win32/lib/wincrt1.c
@@ -1,5 +1,8 @@
//+---------------------------------------------------------------------------
+// _UNICODE for tchar.h, UNICODE for API
+#include <tchar.h>
+
#include <windows.h>
#include <stdlib.h>
@@ -9,56 +12,64 @@
void __set_app_type(int);
void _controlfp(unsigned a, unsigned b);
-int _winstart(void)
-{
- __TRY__
- char *szCmd;
- STARTUPINFO startinfo;
- int fShow;
- int ret;
+#ifdef _UNICODE
+#define __tgetmainargs __wgetmainargs
+#define _twinstart _wwinstart
+#define _runtwinmain _runwwinmain
+int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
+#else
+#define __tgetmainargs __getmainargs
+#define _twinstart _winstart
+#define _runtwinmain _runwinmain
+#endif
- __set_app_type(__GUI_APP);
- _controlfp(0x10000, 0x30000);
+typedef struct { int newmode; } _startupinfo;
+int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
- szCmd = GetCommandLine();
- if (szCmd) {
- while (' ' == *szCmd)
- szCmd++;
- if ('\"' == *szCmd) {
- while (*++szCmd)
- if ('\"' == *szCmd) {
- szCmd++;
- break;
- }
- } else {
- while (*szCmd && ' ' != *szCmd)
- szCmd++;
- }
- while (' ' == *szCmd)
- szCmd++;
- }
+static int go_winmain(TCHAR *arg1)
+{
+ STARTUPINFO si;
+ _TCHAR *szCmd, *p;
+ int fShow;
- GetStartupInfo(&startinfo);
- fShow = startinfo.wShowWindow;
- if (0 == (startinfo.dwFlags & STARTF_USESHOWWINDOW))
+ GetStartupInfo(&si);
+ if (si.dwFlags & STARTF_USESHOWWINDOW)
+ fShow = si.wShowWindow;
+ else
fShow = SW_SHOWDEFAULT;
- ret = WinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
- exit(ret);
+ szCmd = NULL, p = GetCommandLine();
+ if (arg1)
+ szCmd = _tcsstr(p, arg1);
+ if (NULL == szCmd)
+ szCmd = _tcsdup(__T(""));
+ else if (szCmd > p && szCmd[-1] == __T('"'))
+ --szCmd;
+#if defined __i386__ || defined __x86_64__
+ _controlfp(0x10000, 0x30000);
+#endif
+ return _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
}
-int _runwinmain(int argc, char **argv)
+int _twinstart(void)
{
- char *szCmd, *p;
+ __TRY__
+ _startupinfo start_info_con = {0};
+ __set_app_type(__GUI_APP);
+ __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info_con);
+ exit(go_winmain(__argc > 1 ? __targv[1] : NULL));
+}
- p = GetCommandLine();
- szCmd = NULL;
- if (argc > 1)
- szCmd = strstr(p, argv[1]);
- if (NULL == szCmd)
- szCmd = "";
- else if (szCmd > p && szCmd[-1] == '\"')
- --szCmd;
- _controlfp(0x10000, 0x30000);
- return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
+int _runtwinmain(int argc, /* as tcc passed in */ char **argv)
+{
+#ifdef UNICODE
+ _startupinfo start_info = {0};
+ __tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info);
+ /* may be wrong when tcc has received wildcards (*.c) */
+ if (argc < __argc)
+ __targv += __argc - argc, __argc = argc;
+#else
+ __argc = argc, __targv = argv;
+#endif
+ return go_winmain(__argc > 1 ? __targv[1] : NULL);
}
diff --git a/win32/lib/wincrt1w.c b/win32/lib/wincrt1w.c
new file mode 100644
index 0000000..a7d349e
--- /dev/null
+++ b/win32/lib/wincrt1w.c
@@ -0,0 +1,3 @@
+#define _UNICODE 1
+#define UNICODE 1
+#include "wincrt1.c"
diff --git a/win32/tcc-win32.txt b/win32/tcc-win32.txt
index da07e44..ab73007 100644
--- a/win32/tcc-win32.txt
+++ b/win32/tcc-win32.txt
@@ -1,162 +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
- tiny_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 included 'tiny_impdef' program may be used to make additional
- .def files for any DLL. For example:
-
- tiny_impdef.exe opengl32.dll
-
- 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 included tiny_libmaker tool by Timovj Lahde can be used as
- 'ar' replacement to make a library from several object files:
-
- tiny_libmaker [rcs] library objectfiles ...
-
-
- Compilation from source:
- ------------------------
- * You can use the MinGW and MSYS tools available at
-
- http://www.mingw.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
-
- * Alternatively you can compile TCC with just GCC from MinGW using
-
- build-tcc.bat (from the win32 directory)
-
- To install, copy the entire contents of the win32 directory to
- where you want.
-
-
- 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 tiny_libmaker
- or MinGW's ar.
-
- - No leading underscore is generated in the ELF symbols.
-
- - Bounds checking (option -b) is not supported on 64-bit OS.
-
-
- 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/tools/tiny_impdef.c b/win32/tools/tiny_impdef.c
deleted file mode 100644
index b6debe6..0000000
--- a/win32/tools/tiny_impdef.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/* -------------------------------------------------------------- */
-/*
- * tiny_impdef creates an export definition file (.def) from a dll
- * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
- *
- * Copyright (c) 2005,2007 grischka
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef TINY_IMPDEF_GET_EXPORT_NAMES_ONLY
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <stdio.h>
-#include <io.h>
-#include <malloc.h>
-
-static char *get_export_names(int fd);
-#define tcc_free free
-#define tcc_realloc realloc
-
-/* extract the basename of a file */
-static char *file_basename(const char *name)
-{
- const char *p = strchr(name, 0);
- while (p > name
- && p[-1] != '/'
- && p[-1] != '\\'
- )
- --p;
- return (char*)p;
-}
-
-int main(int argc, char **argv)
-{
- int ret, v, i;
- char infile[MAX_PATH];
- char outfile[MAX_PATH];
-
- static const char *ext[] = { ".dll", ".exe", NULL };
- const char *file, **pp;
- char path[MAX_PATH], *p, *q;
- FILE *fp, *op;
-
- infile[0] = 0;
- outfile[0] = 0;
- fp = op = NULL;
- v = 0;
- ret = 1;
- p = NULL;
-
- for (i = 1; i < argc; ++i) {
- const char *a = argv[i];
- if ('-' == a[0]) {
- if (0 == strcmp(a, "-v")) {
- v = 1;
- } else if (0 == strcmp(a, "-o")) {
- if (++i == argc)
- goto usage;
- strcpy(outfile, argv[i]);
- } else
- goto usage;
- } else if (0 == infile[0])
- strcpy(infile, a);
- else
- goto usage;
- }
-
- if (0 == infile[0]) {
-usage:
- fprintf(stderr,
- "tiny_impdef: create export definition file (.def) from a dll\n"
- "Usage: tiny_impdef library.dll [-o outputfile]\n"
- );
- goto the_end;
- }
-
- if (0 == outfile[0])
- {
- strcpy(outfile, file_basename(infile));
- q = strrchr(outfile, '.');
- if (NULL == q)
- q = strchr(outfile, 0);
- strcpy(q, ".def");
- }
-
- file = infile;
-
-#ifdef _WIN32
- pp = ext;
- do if (SearchPath(NULL, file, *pp, sizeof path, path, NULL)) {
- file = path;
- break;
- } while (*pp++);
-#endif
-
- fp = fopen(file, "rb");
- if (NULL == fp) {
- fprintf(stderr, "tiny_impdef: no such file: %s\n", infile);
- goto the_end;
- }
- if (v)
- printf("--> %s\n", file);
-
- p = get_export_names(fileno(fp));
- if (NULL == p) {
- fprintf(stderr, "tiny_impdef: could not get exported function names.\n");
- goto the_end;
- }
-
- op = fopen(outfile, "w");
- if (NULL == op) {
- fprintf(stderr, "tiny_impdef: could not create output file: %s\n", outfile);
- goto the_end;
- }
-
- fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(file));
- for (q = p, i = 0; *q; ++i) {
- fprintf(op, "%s\n", q);
- q += strlen(q) + 1;
- }
-
- if (v) {
- printf("<-- %s\n", outfile);
- printf("%d symbol(s) found\n", i);
- }
-
- ret = 0;
-
-the_end:
- if (p)
- free(p);
- if (fp)
- fclose(fp);
- if (op)
- fclose(op);
- return ret;
-}
-
-int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
-{
- lseek(fd, offset, SEEK_SET);
- return len == read(fd, buffer, len);
-}
-
-/* -------------------------------------------------------------- */
-
-#if defined TCC_TARGET_X86_64
-# define IMAGE_FILE_MACHINE 0x8664
-#elif defined TCC_TARGET_ARM
-# define IMAGE_FILE_MACHINE 0x01C0
-#elif 1 /* defined TCC_TARGET_I386 */
-# define IMAGE_FILE_MACHINE 0x014C
-#endif
-
-/* -------------------------------------------------------------- */
-#endif
-
-static char *get_export_names(int fd)
-{
- int l, i, n, n0;
- char *p;
-
- IMAGE_SECTION_HEADER ish;
- IMAGE_EXPORT_DIRECTORY ied;
- IMAGE_DOS_HEADER dh;
- IMAGE_FILE_HEADER ih;
- DWORD sig, ref, addr, ptr, namep;
-#ifdef TCC_TARGET_X86_64
- IMAGE_OPTIONAL_HEADER64 oh;
-#else
- IMAGE_OPTIONAL_HEADER32 oh;
-#endif
- int pef_hdroffset, opt_hdroffset, sec_hdroffset;
-
- n = n0 = 0;
- p = NULL;
-
- if (!read_mem(fd, 0, &dh, sizeof dh))
- goto the_end;
- if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
- goto the_end;
- if (sig != 0x00004550)
- goto the_end;
- pef_hdroffset = dh.e_lfanew + sizeof sig;
- if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
- goto the_end;
- if (IMAGE_FILE_MACHINE != ih.Machine)
- goto the_end;
- opt_hdroffset = pef_hdroffset + sizeof ih;
- sec_hdroffset = opt_hdroffset + sizeof oh;
- if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
- goto the_end;
-
- if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
- goto the_end;
-
- addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
- //printf("addr: %08x\n", addr);
- for (i = 0; i < ih.NumberOfSections; ++i) {
- if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
- goto the_end;
- //printf("vaddr: %08x\n", ish.VirtualAddress);
- if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
- goto found;
- }
- goto the_end;
-
-found:
- ref = ish.VirtualAddress - ish.PointerToRawData;
- if (!read_mem(fd, addr - ref, &ied, sizeof ied))
- goto the_end;
-
- namep = ied.AddressOfNames - ref;
- for (i = 0; i < ied.NumberOfNames; ++i) {
- if (!read_mem(fd, namep, &ptr, sizeof ptr))
- goto the_end;
- namep += sizeof ptr;
- for (l = 0;;) {
- if (n+1 >= n0)
- p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256);
- if (!read_mem(fd, ptr - ref + l++, p + n, 1)) {
- tcc_free(p), p = NULL;
- goto the_end;
- }
- if (p[n++] == 0)
- break;
- }
- }
- if (p)
- p[n] = 0;
-the_end:
- return p;
-}
-
-/* -------------------------------------------------------------- */
diff --git a/win32/tools/tiny_libmaker.c b/win32/tools/tiny_libmaker.c
deleted file mode 100644
index a694915..0000000
--- a/win32/tools/tiny_libmaker.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * This program is for making libtcc1.a without ar
- * tiny_libmaker - tiny elf lib maker
- * usage: tiny_libmaker [lib] files...
- * Copyright (c) 2007 Timppa
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "../../elf.h"
-
-#ifdef TCC_TARGET_X86_64
-# define ELFCLASSW ELFCLASS64
-# define ElfW(type) Elf##64##_##type
-# define ELFW(type) ELF##64##_##type
-#else
-# define ELFCLASSW ELFCLASS32
-# define ElfW(type) Elf##32##_##type
-# define ELFW(type) ELF##32##_##type
-#endif
-
-#define ARMAG "!<arch>\n"
-#define ARFMAG "`\n"
-
-typedef struct ArHdr {
- char ar_name[16];
- char ar_date[12];
- char ar_uid[6];
- char ar_gid[6];
- char ar_mode[8];
- char ar_size[10];
- char ar_fmag[2];
-} ArHdr;
-
-unsigned long le2belong(unsigned long ul) {
- return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
- ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
-}
-
-ArHdr arhdr = {
- "/ ",
- " ",
- "0 ",
- "0 ",
- "0 ",
- " ",
- ARFMAG
- };
-
-ArHdr arhdro = {
- " ",
- " ",
- "0 ",
- "0 ",
- "0 ",
- " ",
- ARFMAG
- };
-
-/* Returns 1 if s contains any of the chars of list, else 0 */
-int contains_any(const char *s, const char *list) {
- const char *l;
- for (; *s; s++) {
- for (l = list; *l; l++) {
- if (*s == *l)
- return 1;
- }
- }
- return 0;
-}
-
-int usage(int ret) {
- fprintf(stderr, "usage: tiny_libmaker [rcsv] lib file...\n");
- fprintf(stderr, "Always creates a new lib. [abdioptxN] are explicitly rejected.\n");
- return ret;
-}
-
-int main(int argc, char **argv)
-{
- FILE *fi, *fh = NULL, *fo = NULL;
- ElfW(Ehdr) *ehdr;
- ElfW(Shdr) *shdr;
- ElfW(Sym) *sym;
- int i, fsize, i_lib, i_obj;
- char *buf, *shstr, *symtab = NULL, *strtab = NULL;
- int symtabsize = 0;//, strtabsize = 0;
- char *anames = NULL;
- int *afpos = NULL;
- int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
- char tfile[260], stmp[20];
- char *file, *name;
- int ret = 2;
- char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored.
- int verbose = 0;
-
- i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
- for (i = 1; i < argc; i++) {
- const char *a = argv[i];
- if (*a == '-' && strstr(a, "."))
- return usage(1); // -x.y is always invalid (same as gnu ar)
- if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument
- if (contains_any(a, ops_conflict))
- return usage(1);
- if (strstr(a, "v"))
- verbose = 1;
- } else { // lib or obj files: don't abort - keep validating all args.
- if (!i_lib) // first file is the lib
- i_lib = i;
- else if (!i_obj) // second file is the first obj
- i_obj = i;
- }
- }
- if (!i_obj) // i_obj implies also i_lib. we require both.
- return usage(1);
-
- if ((fh = fopen(argv[i_lib], "wb")) == NULL)
- {
- fprintf(stderr, "Can't open file %s \n", argv[i_lib]);
- goto the_end;
- }
-
- sprintf(tfile, "%s.tmp", argv[i_lib]);
- if ((fo = fopen(tfile, "wb+")) == NULL)
- {
- fprintf(stderr, "Can't create temporary file %s\n", tfile);
- goto the_end;
- }
-
- funcmax = 250;
- afpos = realloc(NULL, funcmax * sizeof *afpos); // 250 func
- memcpy(&arhdro.ar_mode, "100666", 6);
-
- // i_obj = first input object file
- while (i_obj < argc)
- {
- if (*argv[i_obj] == '-') { // by now, all options start with '-'
- i_obj++;
- continue;
- }
- if (verbose)
- printf("a - %s\n", argv[i_obj]);
-
- if ((fi = fopen(argv[i_obj], "rb")) == NULL)
- {
- fprintf(stderr, "Can't open file %s \n", argv[i_obj]);
- goto the_end;
- }
- fseek(fi, 0, SEEK_END);
- fsize = ftell(fi);
- fseek(fi, 0, SEEK_SET);
- buf = malloc(fsize + 1);
- fread(buf, fsize, 1, fi);
- fclose(fi);
-
- // elf header
- ehdr = (ElfW(Ehdr) *)buf;
- if (ehdr->e_ident[4] != ELFCLASSW)
- {
- fprintf(stderr, "Unsupported Elf Class: %s\n", argv[i_obj]);
- goto the_end;
- }
-
- shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
- shstr = (char *)(buf + shdr->sh_offset);
- for (i = 0; i < ehdr->e_shnum; i++)
- {
- shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
- if (!shdr->sh_offset)
- continue;
- if (shdr->sh_type == SHT_SYMTAB)
- {
- symtab = (char *)(buf + shdr->sh_offset);
- symtabsize = shdr->sh_size;
- }
- if (shdr->sh_type == SHT_STRTAB)
- {
- if (!strcmp(shstr + shdr->sh_name, ".strtab"))
- {
- strtab = (char *)(buf + shdr->sh_offset);
- //strtabsize = shdr->sh_size;
- }
- }
- }
-
- if (symtab && symtabsize)
- {
- int nsym = symtabsize / sizeof(ElfW(Sym));
- //printf("symtab: info size shndx name\n");
- for (i = 1; i < nsym; i++)
- {
- sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
- if (sym->st_shndx &&
- (sym->st_info == 0x10
- || sym->st_info == 0x11
- || sym->st_info == 0x12
- )) {
- //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
- istrlen = strlen(strtab + sym->st_name)+1;
- anames = realloc(anames, strpos+istrlen);
- strcpy(anames + strpos, strtab + sym->st_name);
- strpos += istrlen;
- if (++funccnt >= funcmax) {
- funcmax += 250;
- afpos = realloc(afpos, funcmax * sizeof *afpos); // 250 func more
- }
- afpos[funccnt] = fpos;
- }
- }
- }
-
- file = argv[i_obj];
- for (name = strchr(file, 0);
- name > file && name[-1] != '/' && name[-1] != '\\';
- --name);
- istrlen = strlen(name);
- if (istrlen >= sizeof(arhdro.ar_name))
- istrlen = sizeof(arhdro.ar_name) - 1;
- memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
- memcpy(arhdro.ar_name, name, istrlen);
- arhdro.ar_name[istrlen] = '/';
- sprintf(stmp, "%-10d", fsize);
- memcpy(&arhdro.ar_size, stmp, 10);
- fwrite(&arhdro, sizeof(arhdro), 1, fo);
- fwrite(buf, fsize, 1, fo);
- free(buf);
- i_obj++;
- fpos += (fsize + sizeof(arhdro));
- }
- hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
- fpos = 0;
- if ((hofs & 1)) // align
- hofs++, fpos = 1;
- // write header
- fwrite("!<arch>\n", 8, 1, fh);
- sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)));
- memcpy(&arhdr.ar_size, stmp, 10);
- fwrite(&arhdr, sizeof(arhdr), 1, fh);
- afpos[0] = le2belong(funccnt);
- for (i=1; i<=funccnt; i++)
- afpos[i] = le2belong(afpos[i] + hofs);
- fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
- fwrite(anames, strpos, 1, fh);
- if (fpos)
- fwrite("", 1, 1, fh);
- // write objects
- fseek(fo, 0, SEEK_END);
- fsize = ftell(fo);
- fseek(fo, 0, SEEK_SET);
- buf = malloc(fsize + 1);
- fread(buf, fsize, 1, fo);
- fwrite(buf, fsize, 1, fh);
- free(buf);
- ret = 0;
-the_end:
- if (anames)
- free(anames);
- if (afpos)
- free(afpos);
- if (fh)
- fclose(fh);
- if (fo)
- fclose(fo), remove(tfile);
- return ret;
-}
diff --git a/win32/vs2015/libtcc.vcxproj b/win32/vs2015/libtcc.vcxproj
deleted file mode 100644
index d8c45a4..0000000
--- a/win32/vs2015/libtcc.vcxproj
+++ /dev/null
@@ -1,190 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectGuid>{41F2DA74-9707-49A3-A466-157C7028BD79}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libtcc</RootNamespace>
- <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>ONE_SOURCE;LIBTCC_AS_DLL;TCC_TARGET_PE;TCC_TARGET_I386;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBTCC_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>ONE_SOURCE;LIBTCC_AS_DLL;TCC_TARGET_PE;TCC_TARGET_X86_64;_DEBUG;_WINDOWS;_USRDLL;LIBTCC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>ONE_SOURCE;LIBTCC_AS_DLL;TCC_TARGET_PE;TCC_TARGET_I386;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBTCC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>ONE_SOURCE;LIBTCC_AS_DLL;TCC_TARGET_PE;TCC_TARGET_X86_64;NDEBUG;_WINDOWS;_USRDLL;LIBTCC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemGroup>
- <ClCompile Include="..\..\libtcc.c" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\arm-gen.c" />
- <ClInclude Include="..\..\arm64-gen.c" />
- <ClInclude Include="..\..\c67-gen.c" />
- <ClInclude Include="..\..\conftest.c" />
- <ClInclude Include="..\..\i386-asm.c" />
- <ClInclude Include="..\..\i386-gen.c" />
- <ClInclude Include="..\..\il-gen.c" />
- <ClInclude Include="..\..\tcc.h" />
- <ClInclude Include="..\..\tccasm.c" />
- <ClInclude Include="..\..\tcccoff.c" />
- <ClInclude Include="..\..\tccelf.c" />
- <ClInclude Include="..\..\tccgen.c" />
- <ClInclude Include="..\..\tccpe.c" />
- <ClInclude Include="..\..\tccpp.c" />
- <ClInclude Include="..\..\tccrun.c" />
- <ClInclude Include="..\..\x86_64-gen.c" />
- <ClInclude Include="..\..\coff.h" />
- <ClInclude Include="..\..\elf.h" />
- <ClInclude Include="..\..\i386-asm.h" />
- <ClInclude Include="..\..\i386-tok.h" />
- <ClInclude Include="..\..\il-opcodes.h" />
- <ClInclude Include="..\..\libtcc.h" />
- <ClInclude Include="..\..\stab.h" />
- <ClInclude Include="..\..\tcclib.h" />
- <ClInclude Include="..\..\tcctok.h" />
- <ClInclude Include="..\..\x86_64-asm.h" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project> \ No newline at end of file
diff --git a/win32/vs2015/tcc.sln b/win32/vs2015/tcc.sln
deleted file mode 100644
index 9015cd0..0000000
--- a/win32/vs2015/tcc.sln
+++ /dev/null
@@ -1,41 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcc", "tcc.vcxproj", "{6E7932A7-B123-48EB-AB39-40867AF28105}"
- ProjectSection(ProjectDependencies) = postProject
- {41F2DA74-9707-49A3-A466-157C7028BD79} = {41F2DA74-9707-49A3-A466-157C7028BD79}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtcc", "libtcc.vcxproj", "{41F2DA74-9707-49A3-A466-157C7028BD79}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Debug|x64.ActiveCfg = Debug|x64
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Debug|x64.Build.0 = Debug|x64
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Debug|x86.ActiveCfg = Debug|Win32
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Debug|x86.Build.0 = Debug|Win32
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Release|x64.ActiveCfg = Release|x64
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Release|x64.Build.0 = Release|x64
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Release|x86.ActiveCfg = Release|Win32
- {6E7932A7-B123-48EB-AB39-40867AF28105}.Release|x86.Build.0 = Release|Win32
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Debug|x64.ActiveCfg = Debug|x64
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Debug|x64.Build.0 = Debug|x64
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Debug|x86.ActiveCfg = Debug|Win32
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Debug|x86.Build.0 = Debug|Win32
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Release|x64.ActiveCfg = Release|x64
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Release|x64.Build.0 = Release|x64
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Release|x86.ActiveCfg = Release|Win32
- {41F2DA74-9707-49A3-A466-157C7028BD79}.Release|x86.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/win32/vs2015/tcc.vcxproj b/win32/vs2015/tcc.vcxproj
deleted file mode 100644
index 7417358..0000000
--- a/win32/vs2015/tcc.vcxproj
+++ /dev/null
@@ -1,173 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectGuid>{6E7932A7-B123-48EB-AB39-40867AF28105}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>tcc</RootNamespace>
- <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v140</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>TCC_TARGET_PE;TCC_TARGET_I386;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>
- <AdditionalDependencies>libtcc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>TCC_TARGET_PE;TCC_TARGET_X86_64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>libtcc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>x64\Debug</AdditionalLibraryDirectories>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>TCC_TARGET_PE;TCC_TARGET_I386;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>
- <AdditionalDependencies>libtcc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <PrecompiledHeader>
- </PrecompiledHeader>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>TCC_TARGET_PE;TCC_TARGET_X86_64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>libtcc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalLibraryDirectories>x64\Release</AdditionalLibraryDirectories>
- </Link>
- <PostBuildEvent>
- <Command>copy $(TargetPath) $(SolutionDir)..</Command>
- </PostBuildEvent>
- </ItemDefinitionGroup>
- <ItemGroup>
- <ClCompile Include="..\..\tcc.c" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\tcc.h" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
-</Project> \ No newline at end of file
diff --git a/x86_64-asm.h b/x86_64-asm.h
index 675e7df..cb9eb16 100644
--- a/x86_64-asm.h
+++ b/x86_64-asm.h
@@ -106,8 +106,8 @@ ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
the full movabs form (64bit immediate). For IM32->REG64 we prefer
the 0xc7 opcode. So disallow all 64bit forms and code the rest by hand. */
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG))
-ALT(DEF_ASM_OP2(mov, 0x48b8, 0, OPC_REG, OPT_IM64, OPT_REG64))
-ALT(DEF_ASM_OP2(movq, 0x48b8, 0, OPC_REG, OPT_IM64, OPT_REG64))
+ALT(DEF_ASM_OP2(mov, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64))
+ALT(DEF_ASM_OP2(movq, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64))
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG))
@@ -123,7 +123,7 @@ ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movsbq, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movswq, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG))
-ALT(DEF_ASM_OP2(movslq, 0x4863, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG))
+ALT(DEF_ASM_OP2(movslq, 0x63, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG))
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movzwq, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG))
@@ -354,8 +354,8 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
If the operand would use extended registers we would have to modify
it instead of generating a second one. Currently that's no
problem with TCC, we don't use extended registers. */
- DEF_ASM_OP1(fxsaveq, 0x480fae, 0, OPC_MODRM, OPT_EA )
- DEF_ASM_OP1(fxrstorq, 0x480fae, 1, OPC_MODRM, OPT_EA )
+ DEF_ASM_OP1(fxsaveq, 0x0fae, 0, OPC_MODRM | OPC_48, OPT_EA )
+ DEF_ASM_OP1(fxrstorq, 0x0fae, 1, OPC_MODRM | OPC_48, OPT_EA )
/* segments */
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
@@ -376,7 +376,7 @@ ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)
DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG32 | OPT_EA)
ALT(DEF_ASM_OP1(str, 0x660f00, 1, OPC_MODRM, OPT_REG16))
-ALT(DEF_ASM_OP1(str, 0x480f00, 1, OPC_MODRM, OPT_REG64))
+ALT(DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM | OPC_48, OPT_REG64))
DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP0L(swapgs, 0x0f01, 7, OPC_MODRM)
@@ -385,7 +385,7 @@ ALT(DEF_ASM_OP1(str, 0x480f00, 1, OPC_MODRM, OPT_REG64))
/* bswap can't be applied to 16bit regs */
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
DEF_ASM_OP1(bswapl, 0x0fc8, 0, OPC_REG, OPT_REG32 )
- DEF_ASM_OP1(bswapq, 0x480fc8, 0, OPC_REG, OPT_REG64 )
+ DEF_ASM_OP1(bswapq, 0x0fc8, 0, OPC_REG | OPC_48, OPT_REG64 )
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA ))
ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA ))
@@ -395,7 +395,7 @@ ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OP
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
/* AMD 64 */
- DEF_ASM_OP1(cmpxchg16b, 0x480fc7, 1, OPC_MODRM, OPT_EA )
+ DEF_ASM_OP1(cmpxchg16b, 0x0fc7, 1, OPC_MODRM | OPC_48, OPT_EA )
/* pentium pro */
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
@@ -420,7 +420,7 @@ ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT
/* movd shouldn't accept REG64, but AMD64 spec uses it for 32 and 64 bit
moves, so let's be compatible. */
ALT(DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG64, OPT_MMXSSE ))
-ALT(DEF_ASM_OP2(movq, 0x480f6e, 0, OPC_MODRM, OPT_REG64, OPT_MMXSSE ))
+ALT(DEF_ASM_OP2(movq, 0x0f6e, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_MMXSSE ))
ALT(DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ))
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 ))
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 ))
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 86e097e..e33a38a 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -25,6 +25,7 @@
/* number of available registers */
#define NB_REGS 25
#define NB_ASM_REGS 16
+#define CONFIG_TCC_ASM
/* a register can belong to several classes. The classes must be
sorted from more general to more precise (see gv2() code which does
@@ -145,6 +146,8 @@ static int func_ret_sub;
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);
@@ -213,9 +216,6 @@ void gsym(int t)
gsym_addr(t, ind);
}
-/* psym is used to put an instruction with a data field which is a
- reference to a symbol. It is in fact the same as oad ! */
-#define psym oad
static int is64_type(int t)
{
@@ -225,21 +225,21 @@ static int is64_type(int t)
}
/* instruction + 4 bytes data. Return the address of the data */
-ST_FUNC int oad(int c, int s)
+static int oad(int c, int s)
{
- int ind1;
-
+ int t;
+ if (nocode_wanted)
+ return s;
o(c);
- ind1 = ind + 4;
- if (ind1 > cur_text_section->data_allocated)
- section_realloc(cur_text_section, ind1);
- write32le(cur_text_section->data + ind, s);
- s = ind;
- ind = ind1;
- return s;
+ t = ind;
+ gen_le32(s);
+ return t;
}
-ST_FUNC void gen_addr32(int r, Sym *sym, long c)
+/* generate jmp to a label */
+#define gjmp2(instr,lbl) oad(instr,lbl)
+
+ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloca(cur_text_section, sym, ind, R_X86_64_32S, c), c=0;
@@ -255,7 +255,7 @@ ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c)
}
/* output constant with relocation if 'r & VT_SYM' is true */
-ST_FUNC void gen_addrpc32(int r, Sym *sym, long c)
+ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloca(cur_text_section, sym, ind, R_X86_64_PC32, c-4), c=4;
@@ -265,17 +265,15 @@ ST_FUNC void gen_addrpc32(int r, Sym *sym, long c)
/* output got address with relocation */
static void gen_gotpcrel(int r, Sym *sym, int c)
{
-#ifndef TCC_TARGET_PE
- greloca(cur_text_section, sym, ind, R_X86_64_GOTPCREL, -4);
-#else
+#ifdef TCC_TARGET_PE
tcc_error("internal error: no GOT on PE: %s %x %x | %02x %02x %02x\n",
get_tok_str(sym->v, NULL), c, r,
cur_text_section->data[ind-3],
cur_text_section->data[ind-2],
cur_text_section->data[ind-1]
);
- greloc(cur_text_section, sym, ind, R_X86_64_PC32);
#endif
+ greloca(cur_text_section, sym, ind, R_X86_64_GOTPCREL, -4);
gen_le32(0);
if (c) {
/* we use add c, %xxx for displacement */
@@ -290,12 +288,18 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got)
op_reg = REG_VALUE(op_reg) << 3;
if ((r & VT_VALMASK) == VT_CONST) {
/* constant memory reference */
- o(0x05 | op_reg);
- if (is_got) {
- gen_gotpcrel(r, sym, c);
- } else {
- gen_addrpc32(r, sym, c);
- }
+ if (!(r & VT_SYM)) {
+ /* Absolute memory reference */
+ o(0x04 | op_reg); /* [sib] | destreg */
+ oad(0x25, c); /* disp32 */
+ } else {
+ o(0x05 | op_reg); /* (%rip)+disp32 | destreg */
+ if (is_got) {
+ gen_gotpcrel(r, sym, c);
+ } else {
+ gen_addrpc32(r, sym, c);
+ }
+ }
} else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */
if (c == (char)c) {
@@ -317,14 +321,14 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got)
}
}
-/* generate a modrm reference. 'op_reg' contains the addtionnal 3
+/* generate a modrm reference. 'op_reg' contains the additional 3
opcode bits */
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
{
gen_modrm_impl(op_reg, r, sym, c, 0);
}
-/* generate a modrm reference. 'op_reg' contains the addtionnal 3
+/* generate a modrm reference. 'op_reg' contains the additional 3
opcode bits */
static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c)
{
@@ -383,6 +387,19 @@ void load(int r, SValue *sv)
fr = get_reg(RC_INT);
load(fr, &v1);
}
+ if (fc != sv->c.i) {
+ /* If the addends doesn't fit into a 32bit signed
+ we must use a 64bit move. We've checked above
+ that this doesn't have a sym associated. */
+ v1.type.t = VT_LLONG;
+ v1.r = VT_CONST;
+ v1.c.i = sv->c.i;
+ fr = r;
+ if (!(reg_classes[fr] & (RC_INT|RC_R11)))
+ fr = get_reg(RC_INT);
+ load(fr, &v1);
+ fc = 0;
+ }
ll = 0;
/* Like GCC we can load from small enough properly sized
structs and unions as well.
@@ -417,9 +434,11 @@ void load(int r, SValue *sv)
} else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
b = 0xb70f; /* movzwl */
} else {
- assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG)
- || ((ft & VT_BTYPE) == VT_PTR) || ((ft & VT_BTYPE) == VT_ENUM)
- || ((ft & VT_BTYPE) == VT_FUNC));
+ assert(((ft & VT_BTYPE) == VT_INT)
+ || ((ft & VT_BTYPE) == VT_LLONG)
+ || ((ft & VT_BTYPE) == VT_PTR)
+ || ((ft & VT_BTYPE) == VT_FUNC)
+ );
ll = is64_type(ft);
b = 0x8b;
}
@@ -730,13 +749,13 @@ static int arg_prepare_reg(int idx) {
return arg_regs[idx];
}
-static int func_scratch;
+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. */
-void gen_offs_sp(int b, int r, int d)
+static void gen_offs_sp(int b, int r, int d)
{
orex(1,0,r & 0x100 ? 0 : r, b);
if (d == (char)d) {
@@ -748,30 +767,31 @@ void gen_offs_sp(int b, int r, int d)
}
}
+static int using_regs(int size)
+{
+ return !(size > 8 || (size & (size - 1)));
+}
+
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
{
int size, align;
- *regsize = 8;
*ret_align = 1; // Never have to re-align return values for x86-64
+ *regsize = 8;
size = type_size(vt, &align);
- ret->ref = NULL;
- if (size > 8) {
+ if (!using_regs(size))
return 0;
- } else if (size > 4) {
+ if (size == 8)
ret->t = VT_LLONG;
- return 1;
- } else if (size > 2) {
+ else if (size == 4)
ret->t = VT_INT;
- return 1;
- } else if (size > 1) {
+ else if (size == 2)
ret->t = VT_SHORT;
- return 1;
- } else {
+ else
ret->t = VT_BYTE;
- return 1;
- }
+ ret->ref = NULL;
+ return 1;
}
static int is_sse_float(int t) {
@@ -780,7 +800,7 @@ static int is_sse_float(int t) {
return bt == VT_DOUBLE || bt == VT_FLOAT;
}
-int gfunc_arg_size(CType *type) {
+static int gfunc_arg_size(CType *type) {
int align;
if (type->t & (VT_ARRAY|VT_BITFIELD))
return 8;
@@ -807,7 +827,7 @@ void gfunc_call(int nb_args)
bt = (sv->type.t & VT_BTYPE);
size = gfunc_arg_size(&sv->type);
- if (size <= 8)
+ if (using_regs(size))
continue; /* arguments smaller than 8 bytes passed in registers or on stack */
if (bt == VT_STRUCT) {
@@ -841,7 +861,7 @@ void gfunc_call(int nb_args)
bt = (vtop->type.t & VT_BTYPE);
size = gfunc_arg_size(&vtop->type);
- if (size > 8) {
+ if (!using_regs(size)) {
/* align to stack align size */
size = (size + 15) & ~15;
if (arg >= REGN) {
@@ -901,6 +921,12 @@ void gfunc_call(int nb_args)
}
gcall_or_jmp(0);
+
+ 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))
@@ -932,6 +958,7 @@ void gfunc_prolog(CType *func_type)
func_ret_sub = 0;
func_scratch = 0;
+ func_alloca = 0;
loc = 0;
addr = PTR_SIZE * 2;
@@ -944,9 +971,9 @@ 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->c == FUNC_ELLIPSIS);
+ func_var = (sym->f.func_type == FUNC_ELLIPSIS);
size = gfunc_arg_size(&func_vt);
- if (size > 8) {
+ if (!using_regs(size)) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
func_vc = addr;
reg_param_index++;
@@ -958,11 +985,11 @@ void gfunc_prolog(CType *func_type)
type = &sym->type;
bt = type->t & VT_BTYPE;
size = gfunc_arg_size(type);
- if (size > 8) {
+ if (!using_regs(size)) {
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_LOCAL | VT_LVAL | VT_REF, addr);
+ sym_push(sym->v & ~SYM_FIELD, type, VT_LLOCAL | VT_LVAL, addr);
} else {
if (reg_param_index < REGN) {
/* save arguments passed by register */
@@ -982,7 +1009,7 @@ void gfunc_prolog(CType *func_type)
}
while (reg_param_index < REGN) {
- if (func_type->ref->c == FUNC_ELLIPSIS) {
+ if (func_type->ref->f.func_type == FUNC_ELLIPSIS) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
addr += 8;
}
@@ -1007,6 +1034,7 @@ 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;
if (v >= 4096) {
@@ -1021,6 +1049,13 @@ void gfunc_epilog(void)
gen_le32(v);
}
+ /* 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);
+ }
+
cur_text_section->data_offset = saved_ind;
pe_add_unwind_data(ind, saved_ind, v);
ind = cur_text_section->data_offset;
@@ -1079,7 +1114,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty)
case VT_BOOL:
case VT_PTR:
case VT_FUNC:
- case VT_ENUM: return x86_64_mode_integer;
+ return x86_64_mode_integer;
case VT_FLOAT:
case VT_DOUBLE: return x86_64_mode_sse;
@@ -1202,209 +1237,119 @@ void gfunc_call(int nb_args)
{
X86_64_Mode mode;
CType type;
- int size, align, r, args_size, stack_adjust, run_start, run_end, i, reg_count;
+ int size, align, r, args_size, stack_adjust, i, reg_count;
int nb_reg_args = 0;
int nb_sse_args = 0;
int sse_reg, gen_reg;
-
- /* calculate the number of integer/float register arguments */
- for(i = 0; i < nb_args; i++) {
+ char _onstack[nb_args], *onstack = _onstack;
+
+ /* calculate the number of integer/float register arguments, remember
+ arguments to be passed via stack (in onstack[]), and also remember
+ if we have to align the stack pointer to 16 (onstack[i] == 2). Needs
+ to be done in a left-to-right pass over arguments. */
+ stack_adjust = 0;
+ for(i = nb_args - 1; i >= 0; i--) {
mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
- if (mode == x86_64_mode_sse)
+ if (mode == x86_64_mode_sse && nb_sse_args + reg_count <= 8) {
nb_sse_args += reg_count;
- else if (mode == x86_64_mode_integer)
+ onstack[i] = 0;
+ } else if (mode == x86_64_mode_integer && nb_reg_args + reg_count <= REGN) {
nb_reg_args += reg_count;
+ onstack[i] = 0;
+ } else if (mode == x86_64_mode_none) {
+ onstack[i] = 0;
+ } else {
+ if (align == 16 && (stack_adjust &= 15)) {
+ onstack[i] = 2;
+ stack_adjust = 0;
+ } else
+ onstack[i] = 1;
+ stack_adjust += size;
+ }
}
if (nb_sse_args && tcc_state->nosse)
tcc_error("SSE disabled but floating point arguments passed");
- /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments
- and ended by a 16-byte aligned argument. This is because, from the point of view of
- the callee, argument alignment is computed from the bottom up. */
+ /* fetch cpu flag before generating any code */
+ if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP)
+ gv(RC_INT);
+
/* for struct arguments, we need to call memcpy and the function
call breaks register passing arguments we are preparing.
So, we process arguments which will be passed by stack first. */
gen_reg = nb_reg_args;
sse_reg = nb_sse_args;
- run_start = 0;
args_size = 0;
- while (run_start != nb_args) {
- int run_gen_reg = gen_reg, run_sse_reg = sse_reg;
-
- run_end = nb_args;
- stack_adjust = 0;
- for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) {
- mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
- switch (mode) {
- case x86_64_mode_memory:
- case x86_64_mode_x87:
- stack_arg:
- if (align == 16)
- run_end = i;
- else
- stack_adjust += size;
- break;
-
- case x86_64_mode_sse:
- sse_reg -= reg_count;
- if (sse_reg + reg_count > 8) goto stack_arg;
- break;
-
- case x86_64_mode_integer:
- gen_reg -= reg_count;
- if (gen_reg + reg_count > REGN) goto stack_arg;
- break;
- default: break; /* nothing to be done for x86_64_mode_none */
- }
- }
-
- gen_reg = run_gen_reg;
- sse_reg = run_sse_reg;
-
- /* adjust stack to align SSE boundary */
- if (stack_adjust &= 15) {
- /* fetch cpu flag before the following sub will change the value */
- if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP)
- gv(RC_INT);
-
- stack_adjust = 16 - stack_adjust;
- o(0x48);
- oad(0xec81, stack_adjust); /* sub $xxx, %rsp */
- args_size += stack_adjust;
- }
-
- for(i = run_start; i < run_end;) {
- /* Swap argument to top, it will possibly be changed here,
- and might use more temps. At the end of the loop we keep
- in on the stack and swap it back to its original position
- if it is a register. */
- SValue tmp = vtop[0];
- int arg_stored = 1;
-
- vtop[0] = vtop[-i];
- vtop[-i] = tmp;
- mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, &reg_count);
-
- switch (vtop->type.t & VT_BTYPE) {
- case VT_STRUCT:
- if (mode == x86_64_mode_sse) {
- if (sse_reg > 8)
- sse_reg -= reg_count;
- else
- arg_stored = 0;
- } else if (mode == x86_64_mode_integer) {
- if (gen_reg > REGN)
- gen_reg -= reg_count;
- else
- arg_stored = 0;
- }
-
- if (arg_stored) {
- /* allocate the necessary size on stack */
- o(0x48);
- oad(0xec81, size); /* sub $xxx, %rsp */
- /* generate structure store */
- r = get_reg(RC_INT);
- orex(1, r, 0, 0x89); /* mov %rsp, r */
- o(0xe0 + REG_VALUE(r));
- vset(&vtop->type, r | VT_LVAL, 0);
- vswap();
- vstore();
- args_size += size;
- }
- break;
-
- case VT_LDOUBLE:
- assert(0);
- break;
-
- case VT_FLOAT:
- case VT_DOUBLE:
- assert(mode == x86_64_mode_sse);
- if (sse_reg > 8) {
- --sse_reg;
- r = gv(RC_FLOAT);
- o(0x50); /* push $rax */
- /* movq %xmmN, (%rsp) */
- o(0xd60f66);
- o(0x04 + REG_VALUE(r)*8);
- o(0x24);
- args_size += size;
- } else {
- arg_stored = 0;
- }
- break;
-
- default:
- assert(mode == x86_64_mode_integer);
- /* simple type */
- /* XXX: implicit cast ? */
- if (gen_reg > REGN) {
- --gen_reg;
- r = gv(RC_INT);
- orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
- args_size += size;
- } else {
- arg_stored = 0;
- }
- break;
- }
-
- /* And swap the argument back to it's original position. */
- tmp = vtop[0];
- vtop[0] = vtop[-i];
- vtop[-i] = tmp;
-
- if (arg_stored) {
- vrotb(i+1);
- assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
- vpop();
- --nb_args;
- --run_end;
- } else {
- ++i;
- }
+ stack_adjust &= 15;
+ for (i = 0; i < nb_args;) {
+ mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
+ if (!onstack[i]) {
+ ++i;
+ continue;
+ }
+ /* Possibly adjust stack to align SSE boundary. We're processing
+ args from right to left while allocating happens left to right
+ (stack grows down), so the adjustment needs to happen _after_
+ an argument that requires it. */
+ if (stack_adjust) {
+ o(0x50); /* push %rax; aka sub $8,%rsp */
+ args_size += 8;
+ stack_adjust = 0;
}
-
- /* handle 16 byte aligned arguments at end of run */
- run_start = i = run_end;
- while (i < nb_args) {
- /* Rotate argument to top since it will always be popped */
- mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);
- if (align != 16)
- break;
-
- vrotb(i+1);
-
- if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+ if (onstack[i] == 2)
+ stack_adjust = 1;
+
+ vrotb(i+1);
+
+ switch (vtop->type.t & VT_BTYPE) {
+ case VT_STRUCT:
+ /* allocate the necessary size on stack */
+ o(0x48);
+ oad(0xec81, size); /* sub $xxx, %rsp */
+ /* generate structure store */
+ r = get_reg(RC_INT);
+ orex(1, r, 0, 0x89); /* mov %rsp, r */
+ o(0xe0 + REG_VALUE(r));
+ vset(&vtop->type, r | VT_LVAL, 0);
+ vswap();
+ vstore();
+ break;
+
+ case VT_LDOUBLE:
gv(RC_ST0);
oad(0xec8148, size); /* sub $xxx, %rsp */
o(0x7cdb); /* fstpt 0(%rsp) */
g(0x24);
g(0x00);
- args_size += size;
- } else {
- assert(mode == x86_64_mode_memory);
+ break;
+
+ case VT_FLOAT:
+ case VT_DOUBLE:
+ assert(mode == x86_64_mode_sse);
+ r = gv(RC_FLOAT);
+ o(0x50); /* push $rax */
+ /* movq %xmmN, (%rsp) */
+ o(0xd60f66);
+ o(0x04 + REG_VALUE(r)*8);
+ o(0x24);
+ break;
+
+ default:
+ assert(mode == x86_64_mode_integer);
+ /* simple type */
+ /* XXX: implicit cast ? */
+ r = gv(RC_INT);
+ orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
+ break;
+ }
+ args_size += size;
- /* allocate the necessary size on stack */
- o(0x48);
- oad(0xec81, size); /* sub $xxx, %rsp */
- /* generate structure store */
- r = get_reg(RC_INT);
- orex(1, r, 0, 0x89); /* mov %rsp, r */
- o(0xe0 + REG_VALUE(r));
- vset(&vtop->type, r | VT_LVAL, 0);
- vswap();
- vstore();
- args_size += size;
- }
-
- vpop();
- --nb_args;
- }
+ vpop();
+ --nb_args;
+ onstack++;
}
-
+
/* XXX This should be superfluous. */
save_regs(0); /* save used temporary registers */
@@ -1470,7 +1415,7 @@ void gfunc_call(int nb_args)
}
}
- if (vtop->type.ref->c != FUNC_NEW) /* implies FUNC_OLD or FUNC_ELLIPSIS */
+ if (vtop->type.ref->f.func_type != FUNC_NEW) /* implies FUNC_OLD or FUNC_ELLIPSIS */
oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */
gcall_or_jmp(0);
if (args_size)
@@ -1502,7 +1447,7 @@ void gfunc_prolog(CType *func_type)
func_sub_sp_offset = ind;
func_ret_sub = 0;
- if (func_type->ref->c == FUNC_ELLIPSIS) {
+ if (sym->f.func_type == FUNC_ELLIPSIS) {
int seen_reg_num, seen_sse_num, seen_stack_size;
seen_reg_num = seen_sse_num = 0;
/* frame pointer and return address */
@@ -1519,21 +1464,15 @@ void gfunc_prolog(CType *func_type)
break;
case x86_64_mode_integer:
- if (seen_reg_num + reg_count <= 8) {
- seen_reg_num += reg_count;
- } else {
- seen_reg_num = 8;
- goto stack_arg;
- }
+ if (seen_reg_num + reg_count > REGN)
+ goto stack_arg;
+ seen_reg_num += reg_count;
break;
case x86_64_mode_sse:
- if (seen_sse_num + reg_count <= 8) {
- seen_sse_num += reg_count;
- } else {
- seen_sse_num = 8;
- goto stack_arg;
- }
+ if (seen_sse_num + reg_count > 8)
+ goto stack_arg;
+ seen_sse_num += reg_count;
break;
}
}
@@ -1666,14 +1605,14 @@ void gfunc_epilog(void)
func_bound_offset, lbounds_section->data_offset);
saved_ind = ind;
ind = func_bound_ind;
- greloc(cur_text_section, sym_data, ind + 1, R_386_32);
+ 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 */
- greloc(cur_text_section, sym_data, ind + 1, R_386_32);
+ 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);
@@ -1703,7 +1642,7 @@ void gfunc_epilog(void)
/* generate a jump to a label */
int gjmp(int t)
{
- return psym(0xe9, t);
+ return gjmp2(0xe9, t);
}
/* generate a jump to a fixed address */
@@ -1749,7 +1688,10 @@ ST_FUNC void gtst_addr(int inv, int a)
ST_FUNC int gtst(int inv, int t)
{
int v = vtop->r & VT_VALMASK;
- if (v == VT_CMP) {
+
+ if (nocode_wanted) {
+ ;
+ } else if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
if (vtop->c.i & 0x100)
{
@@ -1766,11 +1708,11 @@ ST_FUNC int gtst(int inv, int t)
else
{
g(0x0f);
- t = psym(0x8a, t); /* jp t */
+ t = gjmp2(0x8a, t); /* jp t */
}
}
g(0x0f);
- t = psym((vtop->c.i - 16) ^ inv, t);
+ t = gjmp2((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
@@ -1925,7 +1867,7 @@ void gen_opl(int op)
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
- two operands are guaranted to have the same floating point type */
+ two operands are guaranteed to have the same floating point type */
/* XXX: need to use ST1 too */
void gen_opf(int op)
{
@@ -2281,6 +2223,14 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
gen_modrm64(0x8b, TREG_RSP, VT_LOCAL, NULL, addr);
}
+#ifdef TCC_TARGET_PE
+/* Save result of gen_vla_alloc onto the stack */
+ST_FUNC void gen_vla_result(int addr) {
+ /* mov %rax,addr(%rbp)*/
+ gen_modrm64(0x89, TREG_RAX, VT_LOCAL, NULL, addr);
+}
+#endif
+
/* 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
diff --git a/x86_64-link.c b/x86_64-link.c
index 602a8ef..a96144c 100644
--- a/x86_64-link.c
+++ b/x86_64-link.c
@@ -8,6 +8,7 @@
#define R_JMP_SLOT R_X86_64_JUMP_SLOT
#define R_GLOB_DAT R_X86_64_GLOB_DAT
#define R_COPY R_X86_64_COPY
+#define R_RELATIVE R_X86_64_RELATIVE
#define R_NUM R_X86_64_NUM
@@ -29,18 +30,24 @@ int code_reloc (int reloc_type)
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPC64:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_GOTTPOFF:
case R_X86_64_GOT32:
+ case R_X86_64_GOT64:
case R_X86_64_GLOB_DAT:
case R_X86_64_COPY:
- case R_X86_64_RELATIVE:
+ case R_X86_64_RELATIVE:
+ case R_X86_64_GOTOFF64:
return 0;
case R_X86_64_PC32:
+ case R_X86_64_PC64:
case R_X86_64_PLT32:
+ case R_X86_64_PLTOFF64:
case R_X86_64_JUMP_SLOT:
return 1;
}
@@ -49,7 +56,7 @@ int code_reloc (int reloc_type)
return -1;
}
-/* Returns an enumerator to describe wether and when the relocation needs a
+/* 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)
@@ -58,23 +65,32 @@ int gotplt_entry_type (int reloc_type)
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
case R_X86_64_COPY:
- case R_X86_64_RELATIVE:
+ case R_X86_64_RELATIVE:
return NO_GOTPLT_ENTRY;
+ /* The following relocs wouldn't normally need GOT or PLT
+ slots, but we need them for simplicity in the link
+ editor part. See our caller for comments. */
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
case R_X86_64_PC32:
+ case R_X86_64_PC64:
return AUTO_GOTPLT_ENTRY;
case R_X86_64_GOTTPOFF:
return BUILD_GOT_ONLY;
case R_X86_64_GOT32:
+ case R_X86_64_GOT64:
+ case R_X86_64_GOTPC32:
+ case R_X86_64_GOTPC64:
+ case R_X86_64_GOTOFF64:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
- case R_X86_64_REX_GOTPCRELX:
+ case R_X86_64_REX_GOTPCRELX:
case R_X86_64_PLT32:
+ case R_X86_64_PLTOFF64:
return ALWAYS_GOTPLT_ENTRY;
}
@@ -91,7 +107,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
modrm = 0x25;
- /* empty PLT: create PLT0 entry that pushes the library indentifier
+ /* empty PLT: create PLT0 entry that pushes the library identifier
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
(GOT + 2 * PTR_SIZE) */
if (plt->data_offset == 0) {
@@ -154,7 +170,7 @@ void relocate_init(Section *sr)
qrel = (ElfW_Rel *) sr->data;
}
-void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
+void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
int sym_index, esym_index;
@@ -167,12 +183,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
- qrel->r_addend = rel->r_addend;
+ qrel->r_addend = rel->r_addend;
qrel++;
break;
} else {
- qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
- qrel->r_addend = read64le(ptr) + val;
+ qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
+ qrel->r_addend = read64le(ptr) + val;
qrel++;
}
}
@@ -207,10 +223,10 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
goto plt32pc32;
case R_X86_64_PLT32:
- /* fallthrough: val already holds the PLT slot address */
+ /* fallthrough: val already holds the PLT slot address */
- plt32pc32:
- {
+ plt32pc32:
+ {
long long diff;
diff = (long long)val - addr;
if (diff < -2147483648LL || diff > 2147483647LL) {
@@ -219,17 +235,43 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
add32le(ptr, diff);
}
break;
+
+ case R_X86_64_PLTOFF64:
+ add64le(ptr, val - s1->got->sh_addr + rel->r_addend);
+ break;
+
+ case R_X86_64_PC64:
+ if (s1->output_type == TCC_OUTPUT_DLL) {
+ /* DLL relocation */
+ esym_index = s1->sym_attrs[sym_index].dyn_index;
+ if (esym_index) {
+ qrel->r_offset = rel->r_offset;
+ qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC64);
+ qrel->r_addend = read64le(ptr) + rel->r_addend;
+ qrel++;
+ break;
+ }
+ }
+ add64le(ptr, val - addr);
+ break;
+
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
/* They don't need addend */
write64le(ptr, val - rel->r_addend);
break;
case R_X86_64_GOTPCREL:
- case R_X86_64_GOTPCRELX:
- case R_X86_64_REX_GOTPCRELX:
+ 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);
break;
+ case R_X86_64_GOTPC32:
+ add32le(ptr, s1->got->sh_addr - addr + rel->r_addend);
+ break;
+ case R_X86_64_GOTPC64:
+ add64le(ptr, s1->got->sh_addr - addr + rel->r_addend);
+ break;
case R_X86_64_GOTTPOFF:
add32le(ptr, val - s1->got->sh_addr);
break;
@@ -237,7 +279,17 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add
/* we load the got offset */
add32le(ptr, s1->sym_attrs[sym_index].got_offset);
break;
+ case R_X86_64_GOT64:
+ /* we load the got offset */
+ add64le(ptr, s1->sym_attrs[sym_index].got_offset);
+ break;
+ case R_X86_64_GOTOFF64:
+ add64le(ptr, val - s1->got->sh_addr);
+ break;
case R_X86_64_RELATIVE:
+#ifdef TCC_TARGET_PE
+ add32le(ptr, val - s1->pe_imagebase);
+#endif
/* do nothing */
break;
}