diff options
author | Thomas Preud'homme <robotux@celest.fr> | 2018-02-21 23:26:45 +0000 |
---|---|---|
committer | Thomas Preud'homme <robotux@celest.fr> | 2018-02-21 23:26:45 +0000 |
commit | 1608e08052209fedd11fceef305a08c305dba9c1 (patch) | |
tree | db73a0e818cffa09a5cb04da81561465853cd47d | |
parent | 51d8a1f05eac1e8087ef960a9747cb22242f5e07 (diff) | |
parent | f4ab37b20a5b328cd681740fb2eed649d994b8c1 (diff) |
merge patched into master
172 files changed, 11352 insertions, 7810 deletions
@@ -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: @@ -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) @@ -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 ------------------------------------------------------------------------------ @@ -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. @@ -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 */ @@ -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; @@ -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); @@ -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) { @@ -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: @@ -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 */ @@ -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 @@ -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 @@ -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) { @@ -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") || @@ -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: @@ -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 @@ -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 } @@ -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> </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> </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> </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> </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> </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> </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> </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> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[ << ]</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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC3"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC4"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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> </td><td class=example><pre>#!/usr/local/bin/tcc -run +#include <stdio.h> + +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> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC2"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC6"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC7"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC8"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC8"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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> </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> </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> </td><td class=example><pre> double d = 0x1234p10; +</pre></td></tr></table><P> + +is the same as writing +<TABLE><tr><td> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC9"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC9"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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> </td><td class=example><pre> struct { int x, y; } st = { x: 1, y: 1}; +</pre></td></tr></table>instead of +<TABLE><tr><td> </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> </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> </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> </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> </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>&&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> </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), "=&D" (d1), "=&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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC5"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC11"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC12"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC13"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC13"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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>&, |, ^ +<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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC14"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC14"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC15"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC15"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC10"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC17"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC18"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC19"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC19"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC20"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC20"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC21"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC16"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC22"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC22"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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> </td><td class=example><pre>{ + int tab[10]; + for(i=0;i<11;i++) { + sum += tab[i]; + } +} +</pre></td></tr></table><P> + +<DT>Out of bounds-error in malloc'ed data: +<DD><TABLE><tr><td> </td><td class=example><pre>{ + int *tab; + tab = malloc(20 * sizeof(int)); + for(i=0;i<21;i++) { + sum += tab4[i]; + } + free(tab); +} +</pre></td></tr></table><P> + +<DT>Access of freed memory: +<DD><TABLE><tr><td> </td><td class=example><pre>{ + int *tab; + tab = malloc(20 * sizeof(int)); + free(tab); + for(i=0;i<20;i++) { + sum += tab4[i]; + } +} +</pre></td></tr></table><P> + +<DT>Double free: +<DD><TABLE><tr><td> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC24"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[ << ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC25"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[ << ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC26"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC26"> << </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC27"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC27"> << </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC28"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC28"> << </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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> </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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC29"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC29"> << </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC30"> << </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC31"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC32"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC33"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC33"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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> </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>&&</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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC34"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC34"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC35"> << </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"> >> </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC36"> > </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[ << ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC23"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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. &&, || 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"> < </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ > ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT">[ << ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[<A HREF="tcc-doc.html#SEC_Top"> Up </A>]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT">[ >> ]</TD> +<TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <TD VALIGN="MIDDLE" ALIGN="LEFT"> <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: </th><td><A HREF="tcc-doc.html#cp__" style="text-decoration:none"><b>_</b></A> + +<BR> +<A HREF="tcc-doc.html#cp_A" style="text-decoration:none"><b>A</b></A> + +<A HREF="tcc-doc.html#cp_B" style="text-decoration:none"><b>B</b></A> + +<A HREF="tcc-doc.html#cp_C" style="text-decoration:none"><b>C</b></A> + +<A HREF="tcc-doc.html#cp_D" style="text-decoration:none"><b>D</b></A> + +<A HREF="tcc-doc.html#cp_E" style="text-decoration:none"><b>E</b></A> + +<A HREF="tcc-doc.html#cp_F" style="text-decoration:none"><b>F</b></A> + +<A HREF="tcc-doc.html#cp_G" style="text-decoration:none"><b>G</b></A> + +<A HREF="tcc-doc.html#cp_I" style="text-decoration:none"><b>I</b></A> + +<A HREF="tcc-doc.html#cp_J" style="text-decoration:none"><b>J</b></A> + +<A HREF="tcc-doc.html#cp_L" style="text-decoration:none"><b>L</b></A> + +<A HREF="tcc-doc.html#cp_M" style="text-decoration:none"><b>M</b></A> + +<A HREF="tcc-doc.html#cp_O" style="text-decoration:none"><b>O</b></A> + +<A HREF="tcc-doc.html#cp_P" style="text-decoration:none"><b>P</b></A> + +<A HREF="tcc-doc.html#cp_Q" style="text-decoration:none"><b>Q</b></A> + +<A HREF="tcc-doc.html#cp_R" style="text-decoration:none"><b>R</b></A> + +<A HREF="tcc-doc.html#cp_S" style="text-decoration:none"><b>S</b></A> + +<A HREF="tcc-doc.html#cp_T" style="text-decoration:none"><b>T</b></A> + +<A HREF="tcc-doc.html#cp_U" style="text-decoration:none"><b>U</b></A> + +<A HREF="tcc-doc.html#cp_V" style="text-decoration:none"><b>V</b></A> + +<A HREF="tcc-doc.html#cp_W" style="text-decoration:none"><b>W</b></A> + +</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: </th><td><A HREF="tcc-doc.html#cp__" style="text-decoration:none"><b>_</b></A> + +<BR> +<A HREF="tcc-doc.html#cp_A" style="text-decoration:none"><b>A</b></A> + +<A HREF="tcc-doc.html#cp_B" style="text-decoration:none"><b>B</b></A> + +<A HREF="tcc-doc.html#cp_C" style="text-decoration:none"><b>C</b></A> + +<A HREF="tcc-doc.html#cp_D" style="text-decoration:none"><b>D</b></A> + +<A HREF="tcc-doc.html#cp_E" style="text-decoration:none"><b>E</b></A> + +<A HREF="tcc-doc.html#cp_F" style="text-decoration:none"><b>F</b></A> + +<A HREF="tcc-doc.html#cp_G" style="text-decoration:none"><b>G</b></A> + +<A HREF="tcc-doc.html#cp_I" style="text-decoration:none"><b>I</b></A> + +<A HREF="tcc-doc.html#cp_J" style="text-decoration:none"><b>J</b></A> + +<A HREF="tcc-doc.html#cp_L" style="text-decoration:none"><b>L</b></A> + +<A HREF="tcc-doc.html#cp_M" style="text-decoration:none"><b>M</b></A> + +<A HREF="tcc-doc.html#cp_O" style="text-decoration:none"><b>O</b></A> + +<A HREF="tcc-doc.html#cp_P" style="text-decoration:none"><b>P</b></A> + +<A HREF="tcc-doc.html#cp_Q" style="text-decoration:none"><b>Q</b></A> + +<A HREF="tcc-doc.html#cp_R" style="text-decoration:none"><b>R</b></A> + +<A HREF="tcc-doc.html#cp_S" style="text-decoration:none"><b>S</b></A> + +<A HREF="tcc-doc.html#cp_T" style="text-decoration:none"><b>T</b></A> + +<A HREF="tcc-doc.html#cp_U" style="text-decoration:none"><b>U</b></A> + +<A HREF="tcc-doc.html#cp_V" style="text-decoration:none"><b>V</b></A> + +<A HREF="tcc-doc.html#cp_W" style="text-decoration:none"><b>W</b></A> + +</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"> + [ < ] </TD> +<TD ALIGN="CENTER"> +Back +</TD> +<TD> +previous section in reading order +</TD> +<TD> +1.2.2 +</TD> +</TR> +<TR> +<TD ALIGN="CENTER"> + [ > ] </TD> +<TD ALIGN="CENTER"> +Forward +</TD> +<TD> +next section in reading order +</TD> +<TD> +1.2.4 +</TD> +</TR> +<TR> +<TD ALIGN="CENTER"> + [ << ] </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"> + [ >> ] </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> + +</TD> +</TR> +<TR> +<TD ALIGN="CENTER"> + [Contents] </TD> +<TD ALIGN="CENTER"> +Contents +</TD> +<TD> +table of contents +</TD> +<TD> + +</TD> +</TR> +<TR> +<TD ALIGN="CENTER"> + [Index] </TD> +<TD ALIGN="CENTER"> +Index +</TD> +<TD> +concept index +</TD> +<TD> + +</TD> +</TR> +<TR> +<TD ALIGN="CENTER"> + [ ? ] </TD> +<TD ALIGN="CENTER"> +About +</TD> +<TD> +this page +</TD> +<TD> + +</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 <STRONG> +<== 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() @@ -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; } @@ -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 @@ -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 */ @@ -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)); } } } @@ -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, ®size); 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, ®size); + 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, ®size); - 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); } /* ------------------------------------------------------------------------- */ @@ -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 @@ -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(¯o_equal_buf); TOK_GET(&t, &a, &cv); - cstr_cat(&localbuf, get_tok_str(t, &cv), 0); + cstr_cat(¯o_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(¯o_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(¯o_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(¯o_str1, t, &cval); + } + tok_str_add(¯o_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(¯o_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(¯o_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(¯o_str1, t, &cval); - } - tok_str_add(¯o_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, ¯o_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(¯o_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; } @@ -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; } @@ -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, ®_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, ®_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, ®_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, ®_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, ®_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; } |