3 Commits

228 changed files with 12313 additions and 26515 deletions

100
.gitignore vendored
View File

@ -1,56 +1,58 @@
*~
\#*
.#*
*.o
*.a
*.exe
*.dll
*.obj
*.pdb
*.lib
*.exp
*.log
*.bz2
*.zip
.gdb_history
a.out
tcc_g
tcc
*-tcc
libtcc*.def
config*.h
config*.mak
config.texi
conftest*
tags
TAGS
/*-tcc
tc2.c
doc
tc3s.c
p3.c
tc1.c
error.c
i386-gen1.c
test.out1
test.out1b
test.out2
test.out2b
test.out3
test.out3b
web.sh
memdebug.c
bench
Makefile.uClibc
boundtest
prog.ref
test.ref
test.out
tcc-doc.html
ideas
tcctest.ref
linux.tcc
ldtest
libtcc_test
instr.S
p.c
p2.c
tcctest[1234]
test[1234].out
tests/tcclib.h
tests/tcctest.gcc
tests/weaktest.*.o.txt
tests2/fred.txt
.gdb_history
tcc.1
tcc.pod
tcc-doc.html
config.h
config.mak
config.texi
tags
.DS_Store
*.swp
lib/x86_64
lib/i386
lib/x86_64-win32
lib/i386-win32
tcc-doc.info
win32/doc
win32/libtcc
win32/lib/32
win32/lib/64
win32/include/float.h
win32/include/stdarg.h
win32/include/stdbool.h
win32/include/stddef.h
win32/include/varargs.h
win32/include/tcclib.h
tests/test.out*
tests/test*.out
tests/tcctest[1234]
tests/tcctest.gcc
tests/*.ref
tests/*.txt
tests/*.gcc
tests/*-cc*
tests/*-tcc*
tests/libtcc_test
tests/vla_test
tests/hello
tests/tests2/fred.txt
conftest*
tiny_libmaker
*.dSYM

View File

@ -1,44 +1,3 @@
Version 0.9.27:
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 LD_LIBRARY_PATH environment variables support
(Andrew Aladjev, Urs Janssen)
Platforms:
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
- 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)
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)
Licensing:
- TinyCC partly relicensed to MIT license (See RELICENSING file).
version 0.9.26:
User interface:
@ -51,7 +10,7 @@ User interface:
Platforms:
- Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka)
- x86-64 assembler (Frederic Feret)
- Many improvements for ARM target (Daniel Glöckner, Thomas Preud'homme)
- Many improvements for ARM target (Daniel Gl<EFBFBD>ckner, Thomas Preud'homme)
- Support WinCE PE ARM (Timo VJ Lahde)
- Support ARM hardfloat calling convention (Thomas Preud'homme)
- Support SELinux (Security-Enhanced Linux) (Henry Kroll III)
@ -70,7 +29,7 @@ Features:
version 0.9.25:
- first support for x86-64 target (Shinichiro Hamaji)
- support µClibc
- support <EFBFBD>Clibc
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
- improved preprocess output with linenumbers and spaces preserved
- tcc_relocate now copies code into user buffer

View File

@ -1,71 +0,0 @@
In general, use the same coding style as the surrounding code.
However, do not make any unnecessary changes as that complicates
the VCS (git) history and makes it harder to merge patches. So
do not modify code just to make it conform to a coding style.
Indentation
Turn on a "fill tabs with spaces" option in your editor.
Remove tabs and trailing spaces from any lines that are modified.
Note that some files are indented with 2 spaces (when they
have large indentation) while most are indented with 4 spaces.
Language
TCC is mostly implemented in C90. Do not use any non-C90 features
that are not already in use.
Non-C90 features currently in use, as revealed by
./configure --extra-cflags="-std=c90 -Wpedantic":
- long long (including "LL" constants)
- inline
- very long string constants
- assignment between function pointer and 'void *'
- "//" comments
- empty macro arguments (DEF_ASMTEST in i386-tok.h)
- unnamed struct and union fields (in struct Sym), a C11 feature
Testing
A simple "make test" is sufficient for some simple changes. However,
before committing a change consider performing some of the following
additional tests:
- Build and run "make test" on several architectures.
- Build with ./configure --enable-cross.
- If the generation of relocations has been changed, try compiling
with TCC and linking with GCC/Clang. If the linker has been
modified, try compiling with GCC/Clang and linking with TCC.
- Test with ASan/UBSan to detect memory corruption and undefined behaviour:
make clean
./configure
make
make test
cp libtcc.a libtcc.a.hide
make clean
./configure --extra-cflags="-fsanitize=address,undefined -g"
make
cp libtcc.a.hide libtcc.a
make test
- Test with Valgrind to detect some uses of uninitialised values:
make clean
./configure
make
# On Intel, because Valgrind does floating-point arithmetic differently:
( cd tests && gcc -I.. tcctest.c && valgrind -q ./a.out > test.ref )
make test TCC="valgrind -q --leak-check=full `pwd`/tcc -B`pwd` -I`pwd`"
(Because of how VLAs are implemented, invalid reads are expected
with 79_vla_continue.)

588
Makefile
View File

@ -1,328 +1,337 @@
# --------------------------------------------------------------------------
#
# Tiny C Compiler Makefile
#
ifndef TOP
TOP = .
INCLUDED = no
endif
TOP ?= .
include $(TOP)/config.mak
VPATH = $(top_srcdir)
CPPFLAGS = -I$(TOP) # for config.h
ifeq (-$(findstring gcc,$(CC))-,-gcc-)
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
CFLAGS += -D_FORTIFY_SOURCE=0
endif
ifeq (-$(findstring $(GCC_MAJOR),01)-,--)
CFLAGS+=-fno-strict-aliasing
ifeq (-$(findstring $(GCC_MAJOR),23)-,--)
CFLAGS+=-Wno-pointer-sign -Wno-sign-compare
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
CFLAGS+=-D_FORTIFY_SOURCE=0
else
ifeq (-$(findstring clang,$(CC))-,-clang-)
# make clang accept gnuisms in libtcc1.c
CFLAGS+=-fheinous-gnu-extensions
endif
CFLAGS+=-Wno-unused-result
endif
endif
endif
else # not GCC
ifeq (-$(findstring clang,$(CC))-,-clang-)
# make clang accept gnuisms in libtcc1.c
CFLAGS+=-fheinous-gnu-extensions
endif
endif
LIBTCC = libtcc.a
LIBTCC1 = libtcc1.a
LINK_LIBTCC =
LIBS =
CFLAGS += -I$(TOP)
CFLAGS += $(CPPFLAGS)
VPATH = $(TOPSRC)
CPPFLAGS_P=$(CPPFLAGS) -DCONFIG_TCC_STATIC
CFLAGS_P=$(CFLAGS) -pg -static
LIBS_P=
LDFLAGS_P=$(LDFLAGS)
ifdef CONFIG_WIN32
ifneq ($(DISABLE_STATIC),no)
LIBTCC = libtcc.dll
LIBTCCDEF = libtcc.def
endif
CFGWIN = -win
NATIVE_TARGET = $(ARCH)-$(if $(eq $(ARCH),arm),wince,win32)
ifdef CONFIG_WIN64
CONFIG_WIN32=yes
endif
ifndef CONFIG_WIN32
LIBS=-lm
ifndef CONFIG_NOLDL
LIBS+=-ldl
endif
endif
# make libtcc as static or dynamic library?
ifdef DISABLE_STATIC
LIBTCC=libtcc.so.1.0
LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
ifdef DISABLE_RPATH
LINK_LIBTCC=
endif
else
LIBS=-lm
ifndef CONFIG_NOLDL
LIBS+=-ldl
endif
# make libtcc as static or dynamic library?
ifeq ($(DISABLE_STATIC),yes)
LIBTCC=libtcc.so
ifndef DISABLE_RPATH
LINK_LIBTCC += -Wl,-rpath,"$(libdir)"
export LD_LIBRARY_PATH := $(CURDIR)/$(TOP)
endif
endif
CFGWIN =-unx
NATIVE_TARGET = $(ARCH)
LIBTCC=libtcc.a
LINK_LIBTCC=
endif
ifeq ($(TARGETOS),Darwin)
CFLAGS += -Wl,-flat_namespace,-undefined,warning
export MACOSX_DEPLOYMENT_TARGET:=10.2
endif
# run local version of tcc with local libraries and includes
TCCFLAGS-unx = -B$(TOP) -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP)
TCCFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP) -L$(TOP)
TCCFLAGS = $(TCCFLAGS$(CFGWIN))
TCC = $(TOP)/tcc$(EXESUF) $(TCCFLAGS)
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
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_uClibc) += -DTCC_UCLIBC
NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM
NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM -DWITHOUT_LIBTCC
NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
ifeq ($(INCLUDED),no)
# --------------------------------------------------------------------------
# running top Makefile
ifeq ($(TOP),.)
PROGS = tcc$(EXESUF)
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
PROGS=tcc$(EXESUF)
I386_CROSS = i386-tcc$(EXESUF)
WIN32_CROSS = i386-win32-tcc$(EXESUF)
WIN64_CROSS = x86_64-win32-tcc$(EXESUF)
WINCE_CROSS = arm-win32-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_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS)
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-asm.c i386-asm.h i386-tok.h
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c
WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c
X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h
ARM_FILES = $(CORE_FILES) arm-gen.c
C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
ifdef CONFIG_WIN64
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
NATIVE_FILES=$(WIN64_FILES)
PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS)
LIBTCC1_CROSS=lib/i386-win32/libtcc1.a
LIBTCC1=libtcc1.a
else ifdef CONFIG_WIN32
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
NATIVE_FILES=$(WIN32_FILES)
PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS)
LIBTCC1_CROSS=lib/x86_64-win32/libtcc1.a
LIBTCC1=libtcc1.a
else ifeq ($(ARCH),i386)
NATIVE_FILES=$(I386_FILES)
PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS)
LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a
LIBTCC1=libtcc1.a
else ifeq ($(ARCH),x86-64)
NATIVE_FILES=$(X86_64_FILES)
PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS)
LIBTCC1_CROSS=lib/i386-win32/libtcc1.a lib/x86_64-win32/libtcc1.a lib/i386/libtcc1.a
LIBTCC1=libtcc1.a
else ifeq ($(ARCH),arm)
NATIVE_FILES=$(ARM_FILES)
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(C67_CROSS)
endif
ifeq ($(TARGETOS),Darwin)
PROGS+=tiny_libmaker$(EXESUF)
endif
ifdef CONFIG_USE_LIBGCC
LIBTCC1=
endif
TCCLIBS = $(LIBTCC1) $(LIBTCC)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
ifdef CONFIG_CROSS
PROGS+=$(PROGS_CROSS)
TCCLIBS+=$(LIBTCC1_CROSS)
endif
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
# cross compiler targets to build
TCC_X = i386 x86_64 i386-win32 x86_64-win32 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 arm arm64 arm-wince
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),libtcc1-$X.a)
ifdef CONFIG_CROSS
all : $(LIBTCC1_CROSS) $(PROGS_CROSS)
endif
# build cross compilers & libs
cross: all $(LIBTCC1_CROSS) $(PROGS_CROSS)
# build specific cross compiler & lib
cross-%: %-tcc$(EXESUF) libtcc1-%.a ;
install: install$(CFGWIN)
uninstall: uninstall$(CFGWIN)
# --------------------------------------------
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-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="\"libtcc1-$T.a\""
DEF-unx += -DTCC_LIBTCC1="\"lib/libtcc1-$T.a\""
else
DEF-all += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
endif
endif
# include custom cross-compiler configuration (see make help)
-include config-cross.mak
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
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 arm-asm.c,$(filter %.c,$($T_FILES)))
ifeq ($(ONE_SOURCE),yes)
LIBTCC_OBJ = $(X)libtcc.o
LIBTCC_INC = $($T_FILES)
TCC_FILES = tcc.c
$(X)libtcc.o $T-tcc$(EXESUF) : DEFINES += -DONE_SOURCE
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)
endif
# target specific object rule
$(X)%.o : %.c $(LIBTCC_INC)
$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
# additional dependencies
$(X)tcc.o : tcctools.c
$(X)arm-gen.o : arm-asm.c
# Host Tiny C Compiler
tcc$(EXESUF): $(X)tcc.o $(LIBTCC)
$(CC) -o $@ $^ $(DEFINES) $(CFLAGS) $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
tcc$(EXESUF): tcc.o $(LIBTCC)
$(CC) -o $@ $^ $(LIBS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LINK_LIBTCC)
# Cross Tiny C Compilers
%-tcc$(EXESUF): FORCE
@$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
$(CC) -o $@ $^ $(DEFINES) $(CFLAGS) $(LIBS) $(LDFLAGS)
%-tcc$(EXESUF): tcc.c
$(CC) -o $@ $< -DONE_SOURCE $(DEFINES) $(CPPFLAGS) $(CFLAGS) $(LIBS) $(LDFLAGS)
# profiling version
tcc_p$(EXESUF): $($T_FILES)
$(CC) -o $@ $< -$(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
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
$(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_PE
$(C67_CROSS): DEFINES = -DTCC_TARGET_C67
$(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
$(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)
# 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),$(NATIVE_FILES))
else
LIBTCC_OBJ = libtcc.o
LIBTCC_INC = $(NATIVE_FILES)
libtcc.o : NATIVE_DEFINES += -DONE_SOURCE
endif
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
# static libtcc library
libtcc.a: $(LIBTCC_OBJ)
$(AR) rcs $@ $^
# dynamic libtcc library
libtcc.so: $(LIBTCC_OBJ)
libtcc.so.1.0: $(LIBTCC_OBJ)
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
libtcc.so: CFLAGS+=-fPIC
libtcc.so.1.0: CFLAGS+=-fPIC
# windows dynamic libtcc library
libtcc.dll : $(LIBTCC_OBJ)
$(CC) -shared $(LIBTCC_OBJ) -o $@ $(LDFLAGS)
libtcc.def : libtcc.dll tcc$(EXESUF)
./tcc$(EXESUF) -impdef $< -o $@
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
# windows utilities
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
# TinyCC runtime libraries
libtcc1.a : tcc$(EXESUF) FORCE
@$(MAKE) -f lib/Makefile BIN=$@ $@ TOP=. --no-print-directory
# Cross libtcc1.a
libtcc1-%.a : %-tcc$(EXESUF) FORCE
@$(MAKE) -f lib/Makefile BIN=$@ $@ CROSS_TARGET=$* TOP=. --no-print-directory
libtcc1.a : FORCE
$(MAKE) -C lib native
lib/%/libtcc1.a : FORCE $(PROGS_CROSS)
$(MAKE) -C lib cross TARGET=$*
FORCE:
# --------------------------------------------------------------------------
# install
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
INSTALL=install
ifdef STRIP_BINARIES
INSTALLBIN=$(INSTALL) -s
else
INSTALLBIN=$(INSTALL)
endif
ifndef CONFIG_WIN32
install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
mkdir -p "$(bindir)"
ifeq ($(CC),tcc)
$(INSTALL) -m755 $(PROGS) "$(bindir)"
else
$(INSTALLBIN) -m755 $(PROGS) "$(bindir)"
endif
mkdir -p "$(mandir)/man1"
-$(INSTALL) tcc.1 "$(mandir)/man1"
mkdir -p "$(infodir)"
-$(INSTALL) tcc-doc.info "$(infodir)"
mkdir -p "$(tccdir)"
mkdir -p "$(tccdir)/include"
ifneq ($(LIBTCC1),)
$(INSTALL) -m644 $(LIBTCC1) "$(tccdir)"
endif
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
mkdir -p "$(libdir)"
$(INSTALL) -m755 $(LIBTCC) "$(libdir)"
ifdef DISABLE_STATIC
ln -sf "$(ln_libdir)/libtcc.so.1.0" "$(libdir)/libtcc.so.1"
ln -sf "$(ln_libdir)/libtcc.so.1.0" "$(libdir)/libtcc.so"
endif
mkdir -p "$(includedir)"
$(INSTALL) -m644 $(top_srcdir)/libtcc.h "$(includedir)"
mkdir -p "$(docdir)"
-$(INSTALL) -m644 tcc-doc.html "$(docdir)"
ifdef CONFIG_CROSS
mkdir -p "$(tccdir)/win32/lib/32"
mkdir -p "$(tccdir)/win32/lib/64"
ifeq ($(ARCH),x86-64)
mkdir -p "$(tccdir)/i386"
$(INSTALL) -m644 lib/i386/libtcc1.a "$(tccdir)/i386"
cp -r "$(tccdir)/include" "$(tccdir)/i386"
endif
$(INSTALL) -m644 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 win32/include/. "$(tccdir)/win32/include"
cp -r include/. "$(tccdir)/win32/include"
endif
uninstall:
rm -fv $(foreach P,$(PROGS),"$(bindir)/$P")
rm -fv $(foreach P,$(LIBTCC1),"$(tccdir)/$P")
rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P")
rm -fv "$(docdir)/tcc-doc.html" "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
rm -fv "$(libdir)/$(LIBTCC)" "$(includedir)/libtcc.h"
rm -fv "$(libdir)/libtcc.so*"
rm -rf "$(tccdir)/win32"
-rmdir $(tccdir)/include
ifeq ($(ARCH),x86-64)
rm -rf "$(tccdir)/i386"
endif
else
# on windows
install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
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) win32/lib/*.def "$(tccdir)/lib"
cp -r win32/include/. "$(tccdir)/include"
cp -r win32/examples/. "$(tccdir)/examples"
$(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include"
$(INSTALL) -m644 tcc-doc.html win32/tcc-win32.txt "$(tccdir)/doc"
$(INSTALL) -m644 $(LIBTCC) libtcc.h "$(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 $@ $<
-texi2html -monolithic -number $<
tcc.1: tcc-doc.texi
-$(TOPSRC)/texi2pod.pl $< tcc.pod
-pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod > $@
-$(top_srcdir)/texi2pod.pl $< tcc.pod
-pod2man --section=1 --center=" " --release=" " tcc.pod > $@
tcc-doc.info: tcc-doc.texi
-makeinfo $<
# --------------------------------------------------------------------------
# install
# in tests subdir
export LIBTCC1
INSTALL = install -m644
INSTALLBIN = install -m755 $(STRIP_$(STRIP_BINARIES))
STRIP_yes = -s
install-strip: install
install-strip: STRIP_BINARIES = yes
%est:
$(MAKE) -C tests $@
TRY-INSTALL = $(if $(wildcard $1),mkdir -p $2 && $(INSTALL) $1 $2)
LIBTCC1_W = $(wildcard $(filter %-win32.a %-wince.a,$(LIBTCC1_CROSS)))
LIBTCC1_U = $(wildcard $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS)))
PROGS_X = $(wildcard $(PROGS_CROSS))
clean:
rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.so* *.out *.exe libtcc_test$(EXESUF)
$(MAKE) -C tests $@
ifneq ($(LIBTCC1),)
$(MAKE) -C lib $@
endif
# install progs & libs
install-unx:
mkdir -p "$(bindir)"
$(INSTALLBIN) $(PROGS) $(PROGS_X) "$(bindir)"
mkdir -p "$(tccdir)"
$(INSTALL) $(LIBTCC1) $(LIBTCC1_U) "$(tccdir)"
mkdir -p "$(tccdir)/include"
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
mkdir -p "$(libdir)"
$(INSTALL) $(LIBTCC) "$(libdir)"
mkdir -p "$(includedir)"
$(INSTALL) $(TOPSRC)/libtcc.h "$(includedir)"
$(call TRY-INSTALL,tcc.1,"$(mandir)/man1")
$(call TRY-INSTALL,tcc-doc.info,"$(infodir)")
$(call TRY-INSTALL,tcc-doc.html,"$(docdir)")
mkdir -p "$(tccdir)/win32/include"
cp -r $(TOPSRC)/include/. "$(tccdir)/win32/include"
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/win32/include"
mkdir -p "$(tccdir)/win32/lib"
$(INSTALL) $(TOPSRC)/win32/lib/*.def $(LIBTCC1_W) "$(tccdir)/win32/lib"
distclean: clean
rm -vf config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
# uninstall
uninstall-unx:
rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS),"$(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)"
# install progs & libs on windows
install-win:
mkdir -p "$(tccdir)"
$(INSTALL) $(PROGS) $(subst libtcc.a,,$(LIBTCC)) $(PROGS_X) "$(tccdir)"
mkdir -p "$(tccdir)/lib"
$(INSTALL) $(TOPSRC)/win32/lib/*.def "$(tccdir)/lib"
$(INSTALL) libtcc1.a $(LIBTCC1_W) $(LIBTCC1_U) "$(tccdir)/lib"
mkdir -p "$(tccdir)/include"
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/include"
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
mkdir -p "$(tccdir)/lib/include";
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/lib/include"
mkdir -p "$(tccdir)/examples"
cp -r $(TOPSRC)/win32/examples/. "$(tccdir)/examples"
$(INSTALL) $(TOPSRC)/tests/libtcc_test.c "$(tccdir)/examples"
mkdir -p "$(tccdir)/libtcc"
$(INSTALL) $(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)) "$(tccdir)/libtcc"
mkdir -p "$(tccdir)/doc"
$(INSTALL) $(TOPSRC)/win32/tcc-win32.txt $(wildcard tcc-doc.html) "$(tccdir)/doc"
# the msys-git shell works to configure && make except it does not have install
install-win : INSTALL = cp
# uninstall on windows
uninstall-win:
rm -rfv "$(tccdir)/"*
# --------------------------------------------------------------------------
# other stuff
TAGFILES = *.[ch] include/*.h lib/*.[chS]
tags : ; ctags $(TAGFILES)
# cannot have both tags and TAGS on windows
ETAGS : ; etags $(TAGFILES)
config.mak:
@echo "Please run ./configure."
@exit 1
# create release tarball from *current* git branch (including tcc-doc.html
# and converting two files to CRLF)
TCC-VERSION = $(VERSION)
TCC-VERSION := tcc-$(shell cat $(top_srcdir)/VERSION)
tar: tcc-doc.html
mkdir $(TCC-VERSION)
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
@ -334,52 +343,7 @@ tar: tcc-doc.html
rm -rf $(TCC-VERSION)
git reset
config.mak:
$(if $(wildcard $@),,@echo "Please run ./configure." && exit 1)
# in tests subdir
test:
$(MAKE) -C tests
.PHONY: all clean tar distclean install uninstall FORCE
clean:
rm -f $(PROGS) $(PROGS_CROSS) tcc_p$(EXESUF) tcc.pod \
*~ *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out \
tags TAGS libtcc_test$(EXESUF)
$(MAKE) -C tests $@
$(MAKE) -C lib $@
distclean: clean
rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
.PHONY: all clean test tar tags ETAGS distclean install uninstall FORCE
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 "Cross compiler configuration:"
@echo " make will read custom configuration for cross compilers from a file"
@echo " 'config-cross.mak' if present. For example for a windows->i386-linux"
@echo " cross-compiler that expects the linux files in <prefix>/i386-linux:"
@echo ""
@echo " ROOT-i386 = {B}/i386-linux"
@echo " CRT-i386 = $(ROOT-i386)/usr/lib"
@echo " LIB-i386 = $(ROOT-i386)/lib:$(ROOT-i386)/usr/lib"
@echo " INC-i386 = {B}/lib/include:$(ROOT-i386)/usr/include"
@echo " DEF-i386 += -D__linux__"
@echo ""
@echo "Other supported make targets:"
@echo " install install-strip test tags ETAGS tar clean distclean help"
# --------------------------------------------------------------------------
endif # ($(INCLUDED),no)
endif # ifeq ($(TOP),.)

18
README
View File

@ -28,19 +28,25 @@ Features:
Documentation:
-------------
1) Installation on a i386/x86_64/arm Linux/OSX/FreeBSD host
1) Installation on a i386 Linux host (for Windows read tcc-win32.txt)
./configure
make
make test
make install
Notes: For OSX and FreeBSD, gmake should be used instead of make.
For Windows read tcc-win32.txt.
Alternatively, out-of-tree builds are supported: you may use different
directories to hold build objects, kept separate from your source tree:
makeinfo must be installed to compile the doc. By default, tcc is
installed in /usr/local/bin. ./configure --help shows configuration
options.
mkdir _build
cd _build
../configure
make
make test
make install
By default, tcc is installed in /usr/local/bin.
./configure --help shows configuration options.
2) Introduction

View File

@ -1,60 +0,0 @@
Relicensing TinyCC
------------------
The authors listed below hereby confirm their agreement to relicense TinyCC
including their past contributions under the following terms:
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
Author (name) I agree (YES/NO) Files/Features (optional)
------------------------------------------------------------------------------
Adam Sampson YES makefiles
Daniel Glöckner NO arm-gen.c
Daniel Glöckner YES not arm-gen.c
Edmund Grimley Evans YES arm64
Fabrice Bellard YES original author
Frédéric Féret YES x86 64/16 bit asm
grischka YES tccpe.c
Henry Kroll YES
Joe Soroka YES
Kirill Smelkov YES
mingodad YES
Pip Cet YES
Shinichiro Hamaji YES x86_64-gen.c
Vincent Lefèvre YES
Thomas Preud'homme YES arm-gen.c
Timo VJ Lähde (Timppa) ? tiny_libmaker.c
TK ? tcccoff.c c67-gen.c
Urs Janssen YES
waddlesplash YES
Christian Jullien YES Windows Cygwin build and tests
------------------------------------------------------------------------------
Please add yourself to the list above (rsp. replace the question mark)
and (after fetching the latest version) commit to the "mob" branch with
commit message:
Relicensing TinyCC
Thanks.

42
TODO
View File

@ -2,9 +2,17 @@ TODO list:
Bugs:
- i386 fastcall is mostly wrong
- fix macro substitution with nested definitions (ShangHongzhang)
- 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).
- configure --cc=tcc (still one bug in libtcc1.c)
- 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)
@ -19,25 +27,13 @@ Bugs:
- 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:
- it is assumed that int is 32-bit and sizeof(int) == 4
- int is used when host or target size_t would make more sense
- TCC handles target floating-point (fp) values using the host's fp
arithmetic, which is simple and fast but may lead to exceptions
and inaccuracy and wrong representations when cross-compiling
Linking:
- 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
@ -49,10 +45,11 @@ 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:
@ -68,17 +65,17 @@ Not critical:
normative example - only relevant when using gotos! -> must add
boolean variable to tell if compound literal was already
initialized).
- add PowerPC generator and improve codegen for RISC (need
- add PowerPC or ARM code 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
- better constant opt (&&, ||, ?:)
- add portable byte code generator and interpreter for other
unsupported architectures.
- C++: variable declaration in for, minimal 'class' support.
- win32: __intxx. use resolve for bchecked malloc et al.
check exception code (exception filter func).
- handle void (__attribute__() *ptr)()
- VLAs are implemented in a way that is not compatible with signals:
http://lists.gnu.org/archive/html/tinycc-devel/2015-11/msg00018.html
Fixed (probably):
@ -94,8 +91,3 @@ 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.

View File

@ -1 +1 @@
0.9.27
0.9.26

View File

@ -1,94 +0,0 @@
/*************************************************************/
/*
* 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
/*************************************************************/
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)
{
asm_error();
}
ST_FUNC void asm_compute_constraints(ASMOperand *operands,
int nb_operands, int nb_outputs,
const uint8_t *clobber_regs,
int *pout_reg)
{
asm_error();
}
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 */

1082
arm-gen.c

File diff suppressed because it is too large Load Diff

View File

@ -1,391 +0,0 @@
#ifdef TARGET_DEFS_ONLY
#define EM_TCC_TARGET EM_ARM
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_ARM_ABS32
#define R_DATA_PTR R_ARM_ABS32
#define R_JMP_SLOT R_ARM_JUMP_SLOT
#define R_GLOB_DAT R_ARM_GLOB_DAT
#define R_COPY R_ARM_COPY
#define R_NUM R_ARM_NUM
#define ELF_START_ADDR 0x00008000
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 0
enum float_abi {
ARM_SOFTFP_FLOAT,
ARM_HARD_FLOAT,
};
#else /* !TARGET_DEFS_ONLY */
#include "tcc.h"
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
{
switch (reloc_type) {
case R_ARM_MOVT_ABS:
case R_ARM_MOVW_ABS_NC:
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVW_ABS_NC:
case R_ARM_ABS32:
case R_ARM_REL32:
case R_ARM_GOTPC:
case R_ARM_GOTOFF:
case R_ARM_GOT32:
case R_ARM_COPY:
case R_ARM_GLOB_DAT:
case R_ARM_NONE:
return 0;
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
case R_ARM_PLT32:
case R_ARM_THM_PC22:
case R_ARM_THM_JUMP24:
case R_ARM_PREL31:
case R_ARM_V4BX:
case R_ARM_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
/* Returns an enumerator to describe wether 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_ARM_NONE:
case R_ARM_COPY:
case R_ARM_GLOB_DAT:
case R_ARM_JUMP_SLOT:
return NO_GOTPLT_ENTRY;
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
case R_ARM_PLT32:
case R_ARM_THM_PC22:
case R_ARM_THM_JUMP24:
case R_ARM_MOVT_ABS:
case R_ARM_MOVW_ABS_NC:
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVW_ABS_NC:
case R_ARM_PREL31:
case R_ARM_ABS32:
case R_ARM_REL32:
case R_ARM_V4BX:
return AUTO_GOTPLT_ENTRY;
case R_ARM_GOTPC:
case R_ARM_GOTOFF:
return BUILD_GOT_ONLY;
case R_ARM_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
uint8_t *p;
unsigned plt_offset;
/* when building a DLL, GOT entry accesses must be done relative to
start of GOT (see x86_64 examble above) */
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_error("DLLs unimplemented!");
/* empty PLT: create PLT0 entry that push address of call site and
jump to ld.so resolution routine (GOT + 8) */
if (plt->data_offset == 0) {
p = section_ptr_add(plt, 20);
write32le(p, 0xe52de004); /* push {lr} */
write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */
write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
/* p+16 is set in relocate_plt */
}
plt_offset = plt->data_offset;
if (attr->plt_thumb_stub) {
p = section_ptr_add(plt, 4);
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
}
p = section_ptr_add(plt, 16);
/* Jump to GOT entry where ld.so initially put address of PLT0 */
write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */
write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */
write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */
/* p + 12 contains offset to GOT entry once patched by relocate_plt */
write32le(p+12, got_offset);
return plt_offset;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
int x = s1->got->sh_addr - s1->plt->sh_addr - 12;
write32le(s1->plt->data + 16, x - 16);
p += 20;
while (p < p_end) {
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
p += 4;
add32le(p + 12, x + s1->plt->data - p);
p += 16;
}
}
}
void relocate_init(Section *sr) {}
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
{
ElfW(Sym) *sym;
int sym_index;
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
switch(type) {
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
case R_ARM_PLT32:
{
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
x = (*(int *) ptr) & 0xffffff;
#ifdef DEBUG_RELOC
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
#endif
(*(int *)ptr) &= 0xff000000;
if (x & 0x800000)
x -= 0x1000000;
x <<= 2;
blx_avail = (TCC_ARM_VERSION >= 5);
is_thumb = val & 1;
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
x += val - addr;
#ifdef DEBUG_RELOC
printf (" newx=0x%x name=%s\n", x,
(char *) symtab_section->link->data + sym->st_name);
#endif
h = x & 2;
th_ko = (x & 3) && (!blx_avail || !is_call);
if (th_ko || x >= 0x2000000 || x < -0x2000000)
tcc_error("can't relocate value at %x,%d",addr, type);
x >>= 2;
x &= 0xffffff;
/* Only reached if blx is avail and it is a call */
if (is_thumb) {
x |= h << 24;
(*(int *)ptr) = 0xfa << 24; /* bl -> blx */
}
(*(int *) ptr) |= x;
}
return;
/* Since these relocations only concern Thumb-2 and blx instruction was
introduced before Thumb-2, we can assume blx is available and not
guard its use */
case R_ARM_THM_PC22:
case R_ARM_THM_JUMP24:
{
int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11;
int to_thumb, is_call, to_plt, blx_bit = 1 << 12;
Section *plt;
/* weak reference */
if (sym->st_shndx == SHN_UNDEF &&
ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
return;
/* Get initial offset */
hi = (*(uint16_t *)ptr);
lo = (*(uint16_t *)(ptr+2));
s = (hi >> 10) & 1;
j1 = (lo >> 13) & 1;
j2 = (lo >> 11) & 1;
i1 = (j1 ^ s) ^ 1;
i2 = (j2 ^ s) ^ 1;
imm10 = hi & 0x3ff;
imm11 = lo & 0x7ff;
x = (s << 24) | (i1 << 23) | (i2 << 22) |
(imm10 << 12) | (imm11 << 1);
if (x & 0x01000000)
x -= 0x02000000;
/* Relocation infos */
to_thumb = val & 1;
plt = s1->plt;
to_plt = (val >= plt->sh_addr) &&
(val < plt->sh_addr + plt->data_offset);
is_call = (type == R_ARM_THM_PC22);
if (!to_thumb && !to_plt && !is_call) {
int index;
uint8_t *p;
char *name, buf[1024];
Section *text_section;
name = (char *) symtab_section->link->data + sym->st_name;
text_section = s1->sections[sym->st_shndx];
/* Modify reloc to target a thumb stub to switch to ARM */
snprintf(buf, sizeof(buf), "%s_from_thumb", name);
index = put_elf_sym(symtab_section,
text_section->data_offset + 1,
sym->st_size, sym->st_info, 0,
sym->st_shndx, buf);
to_thumb = 1;
val = text_section->data_offset + 1;
rel->r_info = ELFW(R_INFO)(index, type);
/* Create a thumb stub function to switch to ARM mode */
put_elf_reloc(symtab_section, text_section,
text_section->data_offset + 4, R_ARM_JUMP24,
sym_index);
p = section_ptr_add(text_section, 8);
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
write32le(p+4, 0xeafffffe); /* b $sym */
}
/* Compute final offset */
x += val - addr;
if (!to_thumb && is_call) {
blx_bit = 0; /* bl -> blx */
x = (x + 3) & -4; /* Compute offset from aligned PC */
}
/* Check that relocation is possible
* offset must not be out of range
* if target is to be entered in arm mode:
- bit 1 must not set
- instruction must be a call (bl) or a jump to PLT */
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
if (to_thumb || (val & 2) || (!is_call && !to_plt))
tcc_error("can't relocate value at %x,%d",addr, type);
/* Compute and store final offset */
s = (x >> 24) & 1;
i1 = (x >> 23) & 1;
i2 = (x >> 22) & 1;
j1 = s ^ (i1 ^ 1);
j2 = s ^ (i2 ^ 1);
imm10 = (x >> 12) & 0x3ff;
imm11 = (x >> 1) & 0x7ff;
(*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) |
(s << 10) | imm10);
(*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) |
(j1 << 13) | blx_bit | (j2 << 11) |
imm11);
}
return;
case R_ARM_MOVT_ABS:
case R_ARM_MOVW_ABS_NC:
{
int x, imm4, imm12;
if (type == R_ARM_MOVT_ABS)
val >>= 16;
imm12 = val & 0xfff;
imm4 = (val >> 12) & 0xf;
x = (imm4 << 16) | imm12;
if (type == R_ARM_THM_MOVT_ABS)
*(int *)ptr |= x;
else
*(int *)ptr += x;
}
return;
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVW_ABS_NC:
{
int x, i, imm4, imm3, imm8;
if (type == R_ARM_THM_MOVT_ABS)
val >>= 16;
imm8 = val & 0xff;
imm3 = (val >> 8) & 0x7;
i = (val >> 11) & 1;
imm4 = (val >> 12) & 0xf;
x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4;
if (type == R_ARM_THM_MOVT_ABS)
*(int *)ptr |= x;
else
*(int *)ptr += x;
}
return;
case R_ARM_PREL31:
{
int x;
x = (*(int *)ptr) & 0x7fffffff;
(*(int *)ptr) &= 0x80000000;
x = (x * 2) / 2;
x += val - addr;
if((x^(x>>1))&0x40000000)
tcc_error("can't relocate value at %x,%d",addr, type);
(*(int *)ptr) |= x & 0x7fffffff;
}
case R_ARM_ABS32:
*(int *)ptr += val;
return;
case R_ARM_REL32:
*(int *)ptr += val - addr;
return;
case R_ARM_GOTPC:
*(int *)ptr += s1->got->sh_addr - addr;
return;
case R_ARM_GOTOFF:
*(int *)ptr += val - s1->got->sh_addr;
return;
case R_ARM_GOT32:
/* we load the got offset */
*(int *)ptr += s1->sym_attrs[sym_index].got_offset;
return;
case R_ARM_COPY:
return;
case R_ARM_V4BX:
/* trade Thumb support for ARMv4 support */
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
return;
case R_ARM_GLOB_DAT:
case R_ARM_JUMP_SLOT:
*(addr_t *)ptr = val;
return;
case R_ARM_NONE:
/* Nothing to do. Normally used to indicate a dependency
on a certain symbol (like for exception handling under EABI). */
return;
default:
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
return;
}
}
#endif /* !TARGET_DEFS_ONLY */

File diff suppressed because it is too large Load Diff

View File

@ -1,249 +0,0 @@
#ifdef TARGET_DEFS_ONLY
#define EM_TCC_TARGET EM_AARCH64
#define R_DATA_32 R_AARCH64_ABS32
#define R_DATA_PTR R_AARCH64_ABS64
#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
#define R_COPY R_AARCH64_COPY
#define R_NUM R_AARCH64_NUM
#define ELF_START_ADDR 0x00400000
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
#else /* !TARGET_DEFS_ONLY */
#include "tcc.h"
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
{
switch (reloc_type) {
case R_AARCH64_ABS32:
case R_AARCH64_ABS64:
case R_AARCH64_PREL32:
case R_AARCH64_MOVW_UABS_G0_NC:
case R_AARCH64_MOVW_UABS_G1_NC:
case R_AARCH64_MOVW_UABS_G2_NC:
case R_AARCH64_MOVW_UABS_G3:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_COPY:
return 0;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
case R_AARCH64_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
/* Returns an enumerator to describe wether 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_PREL32:
case R_AARCH64_MOVW_UABS_G0_NC:
case R_AARCH64_MOVW_UABS_G1_NC:
case R_AARCH64_MOVW_UABS_G2_NC:
case R_AARCH64_MOVW_UABS_G3:
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_ADD_ABS_LO12_NC:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
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;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_LD64_GOT_LO12_NC:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
uint8_t *p;
unsigned plt_offset;
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_error("DLLs unimplemented!");
if (plt->data_offset == 0) {
section_ptr_add(plt, 32);
}
plt_offset = plt->data_offset;
p = section_ptr_add(plt, 16);
write32le(p, got_offset);
write32le(p + 4, (uint64_t) got_offset >> 32);
return plt_offset;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
uint64_t plt = s1->plt->sh_addr;
uint64_t got = s1->got->sh_addr;
uint64_t off = (got >> 12) - (plt >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
write32le(p + 4, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
(got & 0xff8) << 7));
write32le(p + 12, (0x91000210 | // add x16,x16,#...
(got & 0xfff) << 10));
write32le(p + 16, 0xd61f0220); // br x17
write32le(p + 20, 0xd503201f); // nop
write32le(p + 24, 0xd503201f); // nop
write32le(p + 28, 0xd503201f); // nop
p += 32;
while (p < p_end) {
uint64_t pc = plt + (p - s1->plt->data);
uint64_t addr = got + read64le(p);
uint64_t off = (addr >> 12) - (pc >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
write32le(p, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
(addr & 0xff8) << 7));
write32le(p + 8, (0x91000210 | // add x16,x16,#...
(addr & 0xfff) << 10));
write32le(p + 12, 0xd61f0220); // br x17
p += 16;
}
}
}
void relocate_init(Section *sr) {}
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
{
int sym_index = ELFW(R_SYM)(rel->r_info);
#ifdef DEBUG_RELOC
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
#endif
switch(type) {
case R_AARCH64_ABS64:
write64le(ptr, val);
return;
case R_AARCH64_ABS32:
write32le(ptr, val);
return;
case R_AARCH64_PREL32:
write32le(ptr, val - addr);
return;
case R_AARCH64_MOVW_UABS_G0_NC:
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val & 0xffff) << 5));
return;
case R_AARCH64_MOVW_UABS_G1_NC:
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val >> 16 & 0xffff) << 5));
return;
case R_AARCH64_MOVW_UABS_G2_NC:
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val >> 32 & 0xffff) << 5));
return;
case R_AARCH64_MOVW_UABS_G3:
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
(val >> 48 & 0xffff) << 5));
return;
case R_AARCH64_ADR_PREL_PG_HI21: {
uint64_t off = (val >> 12) - (addr >> 12);
if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
(off & 0x1ffffc) << 3 | (off & 3) << 29));
return;
}
case R_AARCH64_ADD_ABS_LO12_NC:
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
(val & 0xfff) << 10));
return;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed"
" (val=%lx, addr=%lx)", val, addr);
write32le(ptr, (0x14000000 |
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
((val - addr) >> 2 & 0x3ffffff)));
return;
case R_AARCH64_ADR_GOT_PAGE: {
uint64_t off =
(((s1->got->sh_addr +
s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
(off & 0x1ffffc) << 3 | (off & 3) << 29));
return;
}
case R_AARCH64_LD64_GOT_LO12_NC:
write32le(ptr,
((read32le(ptr) & 0xfff803ff) |
((s1->got->sh_addr +
s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
return;
case R_AARCH64_COPY:
return;
case R_AARCH64_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
/* They don't need addend */
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr,
val - rel->r_addend,
(char *) symtab_section->link->data + sym->st_name);
#endif
write64le(ptr, val - rel->r_addend);
return;
default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
return;
}
}
#endif /* !TARGET_DEFS_ONLY */

102
c67-gen.c
View File

@ -20,7 +20,7 @@
#ifdef TARGET_DEFS_ONLY
/* #define ASSEMBLY_LISTING_C67 */
//#define ASSEMBLY_LISTING_C67
/* number of available registers */
#define NB_REGS 24
@ -93,11 +93,11 @@ enum {
#define REG_FRET TREG_C67_A4 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
/* #define INVERT_FUNC_PARAMS */
//#define INVERT_FUNC_PARAMS
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
/* #define FUNC_STRUCT_PARAM_AS_PTR */
//#define FUNC_STRUCT_PARAM_AS_PTR
/* pointer size, in bytes */
#define PTR_SIZE 4
@ -108,6 +108,20 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_C60
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_C60_32
#define R_DATA_PTR R_C60_32
#define R_JMP_SLOT R_C60_JMP_SLOT
#define R_COPY R_C60_COPY
#define ELF_START_ADDR 0x00000400
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
@ -182,8 +196,7 @@ FILE *f = NULL;
void C67_g(int c)
{
int ind1;
if (nocode_wanted)
return;
#ifdef ASSEMBLY_LISTING_C67
fprintf(f, " %08X", c);
#endif
@ -232,15 +245,15 @@ void gsym(int t)
}
// these are regs that tcc doesn't really know about,
// but assign them unique values so the mapping routines
// can distinguish them
// but asign them unique values so the mapping routines
// can distinquish them
#define C67_A0 105
#define C67_SP 106
#define C67_B3 107
#define C67_FP 108
#define C67_B2 109
#define C67_CREG_ZERO -1 /* Special code for no condition reg test */
#define C67_CREG_ZERO -1 // Special code for no condition reg test
int ConvertRegToRegClass(int r)
@ -1554,14 +1567,14 @@ void load(int r, SValue * sv)
fr = sv->r;
ft = sv->type.t;
fc = sv->c.i;
fc = sv->c.ul;
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
if (v == VT_LLOCAL) {
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
v1.c.ul = fc;
load(r, &v1);
fr = r;
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
@ -1713,7 +1726,7 @@ void store(int r, SValue * v)
int fr, bt, ft, fc, size, t, element;
ft = v->type.t;
fc = v->c.i;
fc = v->c.ul;
fr = v->r & VT_VALMASK;
bt = ft & VT_BTYPE;
/* XXX: incorrect if float reg to reg */
@ -1866,13 +1879,6 @@ static void gcall_or_jmp(int is_jmp)
}
}
/* 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) {
*ret_align = 1; // Never have to re-align return values for x86-64
return 0;
}
/* generate function call with address in (vtop->t, vtop->c) and free function
context. Stack entry is popped */
void gfunc_call(int nb_args)
@ -1888,6 +1894,8 @@ void gfunc_call(int nb_args)
for (i = 0; i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
ALWAYS_ASSERT(FALSE);
} else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
ALWAYS_ASSERT(FALSE);
} else {
/* simple type (currently always same size) */
/* XXX: implicit cast ? */
@ -1956,7 +1964,6 @@ void gfunc_prolog(CType * func_type)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
func_var = (sym->c == FUNC_ELLIPSIS);
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr += 4;
@ -2039,8 +2046,6 @@ 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
@ -2073,9 +2078,7 @@ int gtst(int inv, int t)
int v, *p;
v = vtop->r & VT_VALMASK;
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
// C67 uses B2 sort of as flags register
ind1 = ind;
@ -2097,12 +2100,13 @@ int gtst(int inv, int t)
/* && or || optimization */
if ((v & 1) == inv) {
/* insert vtop->c jump list in t */
p = &vtop->c.i;
// I guess the idea is to traverse to the
// null at the end of the list and store t
// there
n = vtop->c.i;
n = *p;
while (n != 0) {
p = (int *) (cur_text_section->data + n);
@ -2118,6 +2122,37 @@ int gtst(int inv, int t)
t = gjmp(t);
gsym(vtop->c.i);
}
} else {
if (is_float(vtop->type.t)) {
vpushi(0);
gen_op(TOK_NE);
}
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
/* constant jmp optimization */
if ((vtop->c.i != 0) != inv)
t = gjmp(t);
} else {
// I think we need to get the value on the stack
// into a register, test it, and generate a branch
// return the address of the branch, so it can be
// later patched
v = gv(RC_INT); // get value into a reg
ind1 = ind;
C67_MVKL(C67_A0, t); //r=reg to load, constant
C67_MVKH(C67_A0, t); //r=reg to load, constant
if (v != TREG_EAX && // check if not already in a conditional test reg
v != TREG_EDX && v != TREG_ST0 && v != C67_B2) {
C67_MV(v, C67_B2);
v = C67_B2;
}
C67_IREG_B_REG(inv, v, C67_A0); // [!R] B.S2x A0
C67_NOP(5);
t = ind1; //return where we need to patch
ind1 = ind;
}
}
vtop--;
return t;
@ -2294,7 +2329,7 @@ void gen_opf(int op)
gv2(RC_FLOAT, RC_FLOAT); // make sure src2 is on b side
ft = vtop->type.t;
fc = vtop->c.i;
fc = vtop->c.ul;
r = vtop->r;
fr = vtop[-1].r;
@ -2519,21 +2554,6 @@ void ggoto(void)
vtop--;
}
/* Save the stack pointer onto the stack and return the location of its address */
ST_FUNC void gen_vla_sp_save(int addr) {
tcc_error("variable length arrays unsupported for this target");
}
/* Restore the SP from a location on the stack */
ST_FUNC void gen_vla_sp_restore(int addr) {
tcc_error("variable length arrays unsupported for this target");
}
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
tcc_error("variable length arrays unsupported for this target");
}
/* end of C67 code generator */
/*************************************************************/
#endif

View File

@ -1,130 +0,0 @@
#ifdef TARGET_DEFS_ONLY
#define EM_TCC_TARGET EM_C60
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_C60_32
#define R_DATA_PTR R_C60_32
#define R_JMP_SLOT R_C60_JMP_SLOT
#define R_GLOB_DAT R_C60_GLOB_DAT
#define R_COPY R_C60_COPY
#define R_NUM R_C60_NUM
#define ELF_START_ADDR 0x00000400
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 0
#define RELOCATE_DLLPLT 0
#else /* !TARGET_DEFS_ONLY */
#include "tcc.h"
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
{
switch (reloc_type) {
case R_C60_32:
case R_C60LO16:
case R_C60HI16:
case R_C60_GOT32:
case R_C60_GOTOFF:
case R_C60_GOTPC:
case R_C60_COPY:
return 0;
case R_C60_PLT32:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
/* Returns an enumerator to describe wether 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_C60_32:
case R_C60LO16:
case R_C60HI16:
case R_C60_COPY:
return NO_GOTPLT_ENTRY;
case R_C60_GOTOFF:
case R_C60_GOTPC:
return BUILD_GOT_ONLY;
case R_C60_PLT32:
case R_C60_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
tcc_error("C67 got not implemented");
return 0;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
/* XXX: TODO */
while (p < p_end) {
/* XXX: TODO */
}
}
}
void relocate_init(Section *sr) {}
void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
{
switch(type) {
case R_C60_32:
*(int *)ptr += val;
break;
case R_C60LO16:
{
uint32_t orig;
/* put the low 16 bits of the absolute address add to what is
already there */
orig = ((*(int *)(ptr )) >> 7) & 0xffff;
orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16;
/* patch both at once - assumes always in pairs Low - High */
*(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) |
(((val+orig) & 0xffff) << 7);
*(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) |
((((val+orig)>>16) & 0xffff) << 7);
}
break;
case R_C60HI16:
break;
default:
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
type, (unsigned) addr, ptr, (unsigned) val);
break;
}
}
#endif /* !TARGET_DEFS_ONLY */

6
coff.h
View File

@ -37,8 +37,8 @@ struct filehdr {
#define F_BYTE_ORDER (F_LITTLE | F_BIG)
#define FILHDR struct filehdr
/* #define FILHSZ sizeof(FILHDR) */
#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */
//#define FILHSZ sizeof(FILHDR)
#define FILHSZ 22 // above rounds to align on 4 bytes which causes problems
#define COFF_C67_MAGIC 0x00c2
@ -150,7 +150,7 @@ struct scnhdr {
/*------------------------------------------------------------------------*/
/* Define constants for names of "special" sections */
/*------------------------------------------------------------------------*/
/* #define _TEXT ".text" */
//#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
#define _CINIT ".cinit"

354
configure vendored
View File

@ -19,7 +19,6 @@ TMPH=$TMPN.h
# default parameters
build_cross="no"
use_libgcc="no"
disable_static=""
prefix=""
execprefix=""
bindir=""
@ -31,6 +30,7 @@ infodir=""
sysroot=""
cross_prefix=""
cc="gcc"
host_cc="gcc"
ar="ar"
strip="strip"
cygwin="no"
@ -39,26 +39,21 @@ bigendian="no"
mingw32="no"
LIBSUF=".a"
EXESUF=""
DLLSUF=".so"
tcc_sysincludepaths=""
tcc_libpaths=""
tcc_crtprefix=""
tcc_elfinterp=""
triplet=
tcc_lddir=
confvars=
cpu=
cpu=`uname -m`
# OS specific
targetos=`uname`
targetos=`uname -s`
case $targetos in
MINGW*) mingw32=yes;;
MSYS*) mingw32=yes;;
CYGWIN*) mingw32=yes; cygwin=yes; cross_prefix="mingw32-";;
MINGW32*) mingw32=yes;;
DragonFly) noldl=yes;;
OpenBSD) noldl=yes;;
FreeBSD) noldl=yes;;
NetBSD) noldl=yes;;
*) ;;
esac
@ -71,10 +66,49 @@ source_path_used="yes"
if test -z "$source_path" -o "$source_path" = "." ; then
source_path=`pwd`
source_path_used="no"
# mingw compilers might not understand cygwin paths
if test $cygwin = "yes"; then source_path="."; fi
fi
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC|i686-AT386)
cpu="x86"
;;
x86_64)
cpu="x86-64"
;;
arm*)
case "$cpu" in
arm|armv4l)
cpuver=4
;;
armv5tel|armv5tejl)
cpuver=5
;;
armv6j|armv6l)
cpuver=6
;;
armv7a|armv7l)
cpuver=7
;;
esac
cpu="armv4l"
;;
alpha)
cpu="alpha"
;;
"Power Macintosh"|ppc|ppc64)
cpu="powerpc"
;;
mips)
cpu="mips"
;;
s390)
cpu="s390"
;;
*)
cpu="unknown"
;;
esac
for opt do
eval opt=\"$opt\"
case "$opt" in
@ -106,13 +140,11 @@ for opt do
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--ar=*) ar=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
;;
--extra-libs=*) extralibs="${opt#--extra-libs=}"
--extra-libs=*) extralibs=${opt#--extra-libs=}
;;
--sysincludepaths=*) tcc_sysincludepaths=`echo $opt | cut -d '=' -f 2`
;;
@ -122,20 +154,18 @@ for opt do
;;
--elfinterp=*) tcc_elfinterp=`echo $opt | cut -d '=' -f 2`
;;
--triplet=*) triplet=`echo $opt | cut -d '=' -f 2`
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--enable-gprof) gprof="yes"
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i686-pc-mingw32-" ; cpu=x86
;;
--enable-cygwin) mingw32="yes" ; cygwin="yes" ; cross_prefix="mingw32-" ; cpu=x86
;;
--enable-cross) build_cross="yes"
;;
--disable-static) disable_static="yes"
;;
--enable-static) disable_static="no"
;;
--disable-rpath) disable_rpath="yes"
;;
--strip-binaries) strip_binaries="yes"
@ -151,58 +181,6 @@ for opt do
esac
done
if test -z "$cpu" ; then
if test -n "$ARCH" ; then
cpu="$ARCH"
else
cpu=`uname -m`
fi
fi
case "$cpu" in
x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386)
cpu="x86"
;;
x86_64|amd64|x86-64)
cpu="x86_64"
;;
arm*)
case "$cpu" in
arm|armv4l)
cpuver=4
;;
armv5tel|armv5tejl)
cpuver=5
;;
armv6j|armv6l)
cpuver=6
;;
armv7a|armv7l)
cpuver=7
;;
esac
cpu="armv4l"
;;
aarch64)
cpu="aarch64"
;;
alpha)
cpu="alpha"
;;
"Power Macintosh"|ppc|ppc64)
cpu="powerpc"
;;
mips)
cpu="mips"
;;
s390)
cpu="s390"
;;
*)
cpu="unknown"
;;
esac
# Checking for CFLAGS
if test -z "$CFLAGS"; then
CFLAGS="-Wall -g -O2"
@ -210,13 +188,13 @@ fi
if test "$mingw32" = "yes" ; then
if test x"$tccdir" = x""; then
tccdir="tcc"
tccdir="tcc"
fi
if test -z "$prefix" ; then
prefix="C:/Program Files/${tccdir}"
prefix="C:/Program Files/${tccdir}"
fi
if test -z "$sharedir" ; then
sharedir="${prefix}"
sharedir="${prefix}"
fi
execprefix="$prefix"
bindir="${prefix}"
@ -227,39 +205,39 @@ if test "$mingw32" = "yes" ; then
infodir="${sharedir}/info"
LIBSUF=".lib"
EXESUF=".exe"
DLLSUF=".dll"
else
if test -z "$prefix" ; then
prefix="/usr/local"
prefix="/usr/local"
fi
if test -z "$sharedir" ; then
sharedir="${prefix}/share"
sharedir="${prefix}/share"
fi
if test x"$execprefix" = x""; then
execprefix="${prefix}"
execprefix="${prefix}"
fi
if test x"$libdir" = x""; then
libdir="${execprefix}/lib"
libdir="${execprefix}/lib"
fi
if test x"$bindir" = x""; then
bindir="${execprefix}/bin"
fi
if test x"$docdir" = x""; then
docdir="${sharedir}/doc"
fi
if test x"$mandir" = x""; then
mandir="${sharedir}/man"
fi
if test x"$infodir" = x""; then
infodir="${sharedir}/info"
bindir="${execprefix}/bin"
fi
if test x"$tccdir" = x""; then
tccdir="${libdir}/tcc"
tccdir="tcc"
fi
if test x"$docdir" = x""; then
docdir="${sharedir}/doc/${tccdir}"
fi
if test x"$mandir" = x""; then
mandir="${sharedir}/man"
fi
if test x"$infodir" = x""; then
infodir="${sharedir}/info"
fi
tccdir="${libdir}/${tccdir}"
fi # mingw32
if test x"$includedir" = x""; then
includedir="${prefix}/include"
includedir="${prefix}/include"
fi
if test x"$show_help" = "xyes" ; then
@ -271,7 +249,7 @@ Standard options:
--help print this message
--prefix=PREFIX install in PREFIX [$prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[same as prefix]
[same as prefix]
--bindir=DIR user executables in DIR [EPREFIX/bin]
--libdir=DIR object code libraries in DIR [EPREFIX/lib]
--tccdir=DIR installation directory [EPREFIX/lib/tcc]
@ -286,23 +264,20 @@ Advanced options (experts only):
--cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]
--sysroot=PREFIX prepend PREFIX to library/include paths []
--cc=CC use C compiler CC [$cc]
--ar=AR create archives using AR [$ar]
--extra-cflags= specify compiler flags [$CFLAGS]
--extra-ldflags= specify linker options []
--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
--with-libgcc use /lib/libgcc_s.so.1 instead of libtcc.a
--enable-mingw32 build windows version on linux with mingw32
--enable-cygwin build windows version on windows with cygwin
--enable-cross build cross compilers
--with-selinux use mmap for executable memory (with tcc -run)
--with-selinux use mmap for exec mem [needs writable /tmp]
--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
EOF
#echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@ -313,46 +288,49 @@ ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
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
gcc_major="$($CONFTEST version)"
gcc_minor="$($CONFTEST minor)"
fi
if test -z "$cross_prefix" ; then
bigendian="$($CONFTEST bigendian)"
if test "$mingw32" = "no" ; then
if test -z "$triplet"; then
tt="$($CONFTEST triplet)"
if test -n "$tt" -a -f "/usr/lib/$tt/crti.o" ; then
triplet="$tt"
fi
fi
if test -z "$triplet"; then
if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
if test -f "/usr/lib64/crti.o" ; then
tcc_lddir="lib64"
fi
fi
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
triplet="$($CONFTEST triplet)"
if test -f "/usr/lib/$triplet/crti.o" ; then
tcc_lddir="lib/$triplet"
multiarch_triplet="$triplet"
elif test -f "/usr/lib64/crti.o" ; then
tcc_lddir="lib64"
fi
if test "$cpu" = "armv4l" ; then
if test "${triplet%eabihf}" != "$triplet" ; then
confvars="$confvars arm_eabihf"
elif test "${triplet%eabi}" != "$triplet" ; then
confvars="$confvars arm_eabi"
fi
if grep -s -q "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo ; then
confvars="$confvars arm_vfp"
fi
if test "${triplet%eabihf}" != "$triplet" ; then
confvars="$confvars arm_eabihf"
elif test "${triplet%eabi}" != "$triplet" ; then
confvars="$confvars arm_eabi"
fi
if grep -s -q "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo ; then
confvars="$confvars arm_vfp"
fi
fi
# multiarch_triplet=${libc_dir#*/}
# multiarch_triplet=${multiarch_triplet%/}
# tcc_lddir="${libc_dir%%/*}"
# if test -n "$multiarch_triplet" ; then
# tcc_lddir="$tcc_lddir/$multiarch_triplet"
# fi
if test -f "/lib/ld-uClibc.so.0" ; then
confvars="$confvars uClibc"
confvars="$confvars uClibc"
fi
# gr: maybe for after the release:
# tcc_elfinterp="$(ldd $CONFTEST | grep 'ld.*.so' | sed 's,\s*\(\S\+\).*,\1,')"
# echo "elfinterp $tcc_elfinterp"
fi
fi
else
# if cross compiling, cannot launch a program, so make a static guess
@ -361,44 +339,24 @@ else
esac
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="pointer-sign sign-compare unused-result"
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
fcho() { if test -n "$2"; then echo "$1$2"; else echo "$1-"; 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 "Target root prefix " "$sysroot"
echo "Source path $source_path"
echo "C compiler $cc"
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"
cat <<EOF
Binary directory $bindir
TinyCC directory $tccdir
Library directory $libdir
Include directory $includedir
Manual directory $mandir
Info directory $infodir
Doc directory $docdir
Target root prefix $sysroot
Source path $source_path
C compiler $cc
Target OS $targetos
CPU $cpu
Big Endian $bigendian
gprof enabled $gprof
cross compilers $build_cross
use libgcc $use_libgcc
EOF
echo "Creating config.mak and config.h"
@ -408,6 +366,7 @@ prefix=$prefix
bindir=\$(DESTDIR)$bindir
tccdir=\$(DESTDIR)$tccdir
libdir=\$(DESTDIR)$libdir
ln_libdir=$libdir
includedir=\$(DESTDIR)$includedir
mandir=\$(DESTDIR)$mandir
infodir=\$(DESTDIR)$infodir
@ -415,13 +374,13 @@ docdir=\$(DESTDIR)$docdir
CC=$cc
GCC_MAJOR=$gcc_major
GCC_MINOR=$gcc_minor
HOST_CC=$host_cc
AR=$ar
STRIP=$strip -s -R .comment -R .note
CFLAGS=$CFLAGS
LDFLAGS=$LDFLAGS
LIBSUF=$LIBSUF
EXESUF=$EXESUF
DLLSUF=$DLLSUF
EOF
print_inc() {
@ -446,28 +405,33 @@ print_mak CONFIG_TCC_LIBPATHS "$tcc_libpaths"
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 CONFIG_MULTIARCHDIR "$multiarch_triplet"
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
echo "#define HOST_I386 1" >> $TMPH
elif test "$cpu" = "x86-64" ; then
echo "ARCH=x86-64" >> config.mak
echo "#define HOST_X86_64 1" >> $TMPH
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak
echo "#define HOST_ARM 1" >> $TMPH
echo "#define TCC_ARM_VERSION $cpuver" >> $TMPH
elif test "$cpu" = "aarch64" ; then
echo "ARCH=arm64" >> config.mak
elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> config.mak
echo "#define HOST_PPC 1" >> $TMPH
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> config.mak
echo "#define HOST_MIPS 1" >> $TMPH
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> config.mak
echo "#define HOST_S390 1" >> $TMPH
elif test "$cpu" = "alpha" ; then
echo "ARCH=alpha" >> config.mak
echo "#define HOST_ALPHA 1" >> $TMPH
else
echo "Unsupported CPU"
exit 1
@ -483,6 +447,13 @@ if test "$noldl" = "yes" ; then
fi
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> config.mak
echo "#define CONFIG_WIN32 1" >> $TMPH
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
@ -495,8 +466,8 @@ fi
if test "$build_cross" = "yes" ; then
echo "CONFIG_CROSS=yes" >> config.mak
fi
if test -n "$disable_static" ; then
echo "DISABLE_STATIC=$disable_static" >> config.mak
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
@ -514,18 +485,20 @@ if test "$have_selinux" = "yes" ; then
fi
version=`head $source_path/VERSION`
echo "VERSION = $version" >> config.mak
echo "VERSION=$version" >>config.mak
echo "#define TCC_VERSION \"$version\"" >> $TMPH
echo "@set VERSION $version" > config.texi
echo "SRC_PATH=$source_path" >>config.mak
if test "$source_path_used" = "yes" ; then
case $source_path in
/*) echo "TOPSRC=$source_path";;
*) echo "TOPSRC=\$(TOP)/$source_path";;
/*) echo "top_srcdir=$source_path";;
*) echo "top_srcdir=\$(TOP)/$source_path";;
esac >>config.mak
else
echo 'TOPSRC=$(TOP)' >>config.mak
echo 'top_srcdir=$(TOP)' >>config.mak
fi
echo 'top_builddir=$(TOP)' >>config.mak
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then
@ -544,22 +517,21 @@ fn_makelink()
tgt=$1/$2
case $2 in
*/*) dn=${2%/*}
test -d $dn || mkdir -p $dn
case $1 in
/*) ;;
*) while test $dn ; do
tgt=../$tgt; dn=${dn#${dn%%/*}}; dn=${dn#/}
done
;;
esac
;;
test -d $dn || mkdir -p $dn
case $1 in
/*) ;;
*) while test $dn ; do
tgt=../$tgt; dn=${dn#${dn%%/*}}; dn=${dn#/}
done
;;
esac
;;
esac
ln -sfn $tgt $2 || ( echo "ln failed. Using cp instead."; cp -f $1/$2 $2 )
ln -sfn $tgt $2
}
if test "$source_path_used" = "yes" ; then
FILES="Makefile lib/Makefile tests/Makefile tests/tests2/Makefile tests/pp/Makefile"
FILES="Makefile lib/Makefile tests/Makefile tests/tests2/Makefile"
for f in $FILES ; do
fn_makelink $source_path $f
done

View File

@ -1,14 +1,12 @@
#include <stdio.h>
/* Define architecture */
#if defined(__i386__) || defined _M_IX86
#if defined(__i386__)
# define TRIPLET_ARCH "i386"
#elif defined(__x86_64__) || defined _M_AMD64
#elif defined(__x86_64__)
# define TRIPLET_ARCH "x86_64"
#elif defined(__arm__)
# define TRIPLET_ARCH "arm"
#elif defined(__aarch64__)
# define TRIPLET_ARCH "aarch64"
#else
# define TRIPLET_ARCH "unknown"
#endif
@ -18,8 +16,6 @@
# 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
@ -35,18 +31,12 @@
# define TRIPLET_ABI "gnu"
#endif
#if defined _WIN32
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS
#elif defined __GNU__
#ifdef __GNU__
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI
#else
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI
#endif
#if defined(_WIN32)
int _CRT_glob = 0;
#endif
int main(int argc, char *argv[])
{
switch(argc == 2 ? argv[1][0] : 0) {
@ -63,13 +53,6 @@ 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':
@ -79,8 +62,9 @@ int main(int argc, char *argv[])
case 't':
puts(TRIPLET);
break;
default:
case -1:
/* to test -Wno-unused-result */
fread(NULL, 1, 1, NULL);
break;
}
return 0;

4059
elf.h

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
#include <tcclib.h>
#include <stdlib.h>
#include <stdio.h>
int fib(n)
{

File diff suppressed because it is too large Load Diff

View File

@ -38,48 +38,53 @@
DEF_ASM_OP0(xlat, 0xd7)
/* strings */
ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX))
ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWL))
ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWL))
/* bits */
ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
/* prefixes */
DEF_ASM_OP0(wait, 0x9b)
DEF_ASM_OP0(fwait, 0x9b)
#ifdef I386_ASM_16
DEF_ASM_OP0(a32, 0x67)
DEF_ASM_OP0(o32, 0x66)
#else
DEF_ASM_OP0(aword, 0x67)
DEF_ASM_OP0(addr16, 0x67)
ALT(DEF_ASM_OP0(word, 0x66))
DEF_ASM_OP0(data16, 0x66)
#endif
DEF_ASM_OP0(lock, 0xf0)
DEF_ASM_OP0(rep, 0xf3)
DEF_ASM_OP0(repe, 0xf3)
@ -97,43 +102,43 @@ ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA
DEF_ASM_OP0(ud2, 0x0f0b)
/* NOTE: we took the same order as gas opcode definition order */
ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX))
ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR))
ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG))
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWL, OPT_ADDR, OPT_EAX))
ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWL, OPT_EAX, OPT_ADDR))
ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWL, OPT_IM, OPT_REG))
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG))
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WL, OPT_SEG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_SEG))
ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG32))
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG32))
ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WLX, OPT_TR, OPT_REG32))
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_CR))
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_DB))
ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_TR))
ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WL, OPT_CR, OPT_REG32))
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WL, OPT_DB, OPT_REG32))
ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WL, OPT_TR, OPT_REG32))
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_CR))
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_DB))
ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_TR))
ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16))
ALT(DEF_ASM_OP2(movsbw, 0x0fbe, 0, OPC_MODRM | OPC_D16, OPT_REG8 | OPT_EA, OPT_REG16))
ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WL, OPT_REG8 | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REGW))
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WLX, OPT_IM8S))
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32))
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG))
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REGW))
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG))
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WL, OPT_SEG))
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX))
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW))
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_REG, OPT_EAX))
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_EAX, OPT_REG))
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX))
ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8))
@ -145,7 +150,7 @@ ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8))
ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX))
ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX))
ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG))
ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WL, OPT_EA, OPT_REG))
ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
@ -154,64 +159,66 @@ ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
/* arith */
ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX))
ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWL, OPT_IM, OPT_EAX))
ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WL, OPT_IM8S, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX))
ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWL, OPT_IM, OPT_EAX))
ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WLX, OPT_REGW))
ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WLX, OPT_REGW))
ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW))
ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW))
ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WL, OPT_REG | OPT_EA, OPT_REG))
ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW))
ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW))
ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX))
ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX))
ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
/* shifts */
ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_EA | OPT_REG))
ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR))
ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP))
ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR))
ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8))
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR))
#ifdef I386_ASM_16
ALT(DEF_ASM_OP1(jmp, 0xff, 0, OPC_JMP | OPC_WL, OPT_REGW))
#endif
ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA))
ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA))
ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32))
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA))
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, 0, OPT_EA))
ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8))
ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8)
DEF_ASM_OP0(leave, 0xc9)
DEF_ASM_OP0(ret, 0xc3)
@ -221,13 +228,13 @@ ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16))
DEF_ASM_OP0(lret, 0xcb)
ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8))
DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8)
DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8)
DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8)
DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8)
DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8)
DEF_ASM_OP1(jecxz, 0xe3, 0, 0, OPT_DISP8)
ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP | OPC_TEST, OPT_ADDR))
DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
DEF_ASM_OP1(loopz, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
DEF_ASM_OP1(loop, 0xe2, 0, OPC_SHORTJMP, OPT_ADDR)
DEF_ASM_OP1(jecxz, 0xe3, 0, OPC_SHORTJMP, OPT_ADDR)
/* float */
/* specific fcomp handling */
@ -341,12 +348,12 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
/* segments */
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
DEF_ASM_OP2(lar, 0x0f02, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG32)
DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG)
DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG)
ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG))
ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG))
DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG)
DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA)
@ -356,20 +363,34 @@ ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)
DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
#ifdef I386_ASM_16
/* 386 */
DEF_ASM_OP0(loadall386, 0x0f07)
#endif
/* 486 */
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
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 ))
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA )
DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA)
DEF_ASM_OP2(boundw, 0x6662, 0, OPC_MODRM, OPT_REG16, OPT_EA)
DEF_ASM_OP2(boundw, 0x62, 0, OPC_MODRM | OPC_D16, OPT_REG16, OPT_EA)
/* pentium */
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
/* pentium pro */
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
#ifdef I386_ASM_16
ALT(DEF_ASM_OP2(cmovno, 0x0f41, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovc, 0x0f42, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovnc, 0x0f43, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovz, 0x0f44, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovnz, 0x0f45, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovna, 0x0f46, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
#endif
DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 )
@ -386,91 +407,63 @@ ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT
/* mmx */
DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE )
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMX )
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_REG32 ))
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(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX ))
ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE ))
ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ))
DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
/* sse */
DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE )
DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
#undef ALT
#undef DEF_ASM_OP0

View File

@ -21,7 +21,7 @@
#ifdef TARGET_DEFS_ONLY
/* number of available registers */
#define NB_REGS 5
#define NB_REGS 4
#define NB_ASM_REGS 8
/* a register can belong to several classes. The classes must be
@ -33,8 +33,6 @@
#define RC_ST0 0x0008
#define RC_ECX 0x0010
#define RC_EDX 0x0020
#define RC_EBX 0x0040
#define RC_IRET RC_EAX /* function return: integer register */
#define RC_LRET RC_EDX /* function return: second integer register */
#define RC_FRET RC_ST0 /* function return: float register */
@ -44,9 +42,7 @@ enum {
TREG_EAX = 0,
TREG_ECX,
TREG_EDX,
TREG_EBX,
TREG_ST0,
TREG_ESP = 4
};
/* return registers for function */
@ -59,7 +55,7 @@ enum {
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
/* #define FUNC_STRUCT_PARAM_AS_PTR */
//#define FUNC_STRUCT_PARAM_AS_PTR
/* pointer size, in bytes */
#define PTR_SIZE 4
@ -70,35 +66,45 @@ enum {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
#define psym oad
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_386
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_386_32
#define R_DATA_PTR R_386_32
#define R_JMP_SLOT R_386_JMP_SLOT
#define R_COPY R_386_COPY
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#include "tcc.h"
/* define to 1/0 to [not] have EBX as 4th register */
#define USE_EBX 0
ST_DATA const int reg_classes[NB_REGS] = {
/* eax */ RC_INT | RC_EAX,
/* ecx */ RC_INT | RC_ECX,
/* edx */ RC_INT | RC_EDX,
/* ebx */ (RC_INT | RC_EBX) * USE_EBX,
/* st0 */ RC_FLOAT | RC_ST0,
};
static unsigned long func_sub_sp_offset;
static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK
static addr_t func_bound_offset;
static unsigned long func_bound_ind;
static unsigned long func_bound_offset;
#endif
/* 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);
@ -131,10 +137,11 @@ ST_FUNC void gen_le32(int c)
/* output a symbol and patch all calls to it */
ST_FUNC void gsym_addr(int t, int a)
{
int n, *ptr;
while (t) {
unsigned char *ptr = cur_text_section->data + t;
uint32_t n = read32le(ptr); /* next value */
write32le(ptr, a - t - 4);
ptr = (int *)(cur_text_section->data + t);
n = *ptr; /* next value */
*ptr = a - t - 4;
t = n;
}
}
@ -144,30 +151,34 @@ 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 */
static int oad(int c, int s)
ST_FUNC int oad(int c, int s)
{
int t;
if (nocode_wanted)
return s;
int ind1;
o(c);
t = ind;
gen_le32(s);
return t;
ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
*(int *)(cur_text_section->data + ind) = s;
s = ind;
ind = ind1;
return s;
}
/* 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);
@ -210,16 +221,14 @@ ST_FUNC void load(int r, SValue *sv)
fr = sv->r;
ft = sv->type.t;
fc = sv->c.i;
ft &= ~(VT_VOLATILE | VT_CONSTANT);
fc = sv->c.ul;
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
if (v == VT_LLOCAL) {
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
v1.c.ul = fc;
fr = r;
if (!(reg_classes[fr] & RC_INT))
fr = get_reg(RC_INT);
@ -234,7 +243,7 @@ ST_FUNC void load(int r, SValue *sv)
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
o(0xdb); /* fldt */
r = 5;
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
} else if ((ft & VT_TYPE) == VT_BYTE) {
o(0xbe0f); /* movsbl */
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
o(0xb60f); /* movzbl */
@ -287,9 +296,8 @@ ST_FUNC void store(int r, SValue *v)
#endif
ft = v->type.t;
fc = v->c.i;
fc = v->c.ul;
fr = v->r & VT_VALMASK;
ft &= ~(VT_VOLATILE | VT_CONSTANT);
bt = ft & VT_BTYPE;
/* XXX: incorrect if float reg to reg */
if (bt == VT_FLOAT) {
@ -329,21 +337,11 @@ static void gadd_sp(int val)
}
}
static void gen_static_call(int v)
{
Sym *sym;
sym = external_global_sym(v, &func_old_type, 0);
oad(0xe8, -4);
greloc(cur_text_section, sym, ind-4, R_386_PC32);
}
/* '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 */
@ -354,31 +352,7 @@ static void gcall_or_jmp(int is_jmp)
put_elf_reloc(symtab_section, cur_text_section,
ind + 1, R_386_PC32, 0);
}
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
/* extend the return value to the whole register if necessary
visual studio and gcc do not always set the whole eax register
when assigning the return value of a function */
rt = vtop->type.ref->type.t;
switch (rt & VT_BTYPE) {
case VT_BYTE:
if (rt & VT_UNSIGNED) {
o(0xc0b60f); /* movzx %al, %eax */
}
else {
o(0xc0be0f); /* movsx %al, %eax */
}
break;
case VT_SHORT:
if (rt & VT_UNSIGNED) {
o(0xc0b70f); /* movzx %ax, %eax */
}
else {
o(0xc0bf0f); /* movsx %ax, %eax */
}
break;
default:
break;
}
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
@ -390,33 +364,6 @@ static void gcall_or_jmp(int is_jmp)
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
/* 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)
{
#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 || (size & (size - 1)))
return 0;
if (size == 8)
ret->t = VT_LLONG;
else if (size == 4)
ret->t = VT_INT;
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;
#endif
}
/* 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. */
@ -474,7 +421,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_CALL(func_sym->r);
/* fast call case */
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
func_call == FUNC_FASTCALLW) {
@ -495,21 +442,21 @@ ST_FUNC void gfunc_call(int nb_args)
args_size -= 4;
}
}
#ifndef TCC_TARGET_PE
else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
args_size -= 4;
#endif
gcall_or_jmp(0);
#ifdef TCC_TARGET_PE
if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
args_size -= 4;
#endif
if (args_size && func_call != FUNC_STDCALL)
gadd_sp(args_size);
vtop--;
}
#ifdef TCC_TARGET_PE
#define FUNC_PROLOG_SIZE (10 + USE_EBX)
#define FUNC_PROLOG_SIZE 10
#else
#define FUNC_PROLOG_SIZE (9 + USE_EBX)
#define FUNC_PROLOG_SIZE 9
#endif
/* generate function prolog of type 't' */
@ -522,7 +469,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
CType *type;
sym = func_type->ref;
func_call = sym->a.func_call;
func_call = FUNC_CALL(sym->r);
addr = 8;
loc = 0;
func_vc = 0;
@ -544,14 +491,7 @@ 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);
#ifdef TCC_TARGET_PE
size = type_size(&func_vt,&align);
if (((func_vt.t & VT_BTYPE) == VT_STRUCT)
&& (size > 8 || (size & (size - 1)))) {
#else
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
#endif
/* XXX: fastcall case ? */
func_vc = addr;
addr += 4;
@ -586,7 +526,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
/* pascal type call ? */
if (func_call == FUNC_STDCALL)
func_ret_sub = addr - 8;
#ifndef TCC_TARGET_PE
#ifdef TCC_TARGET_PE
else if (func_vc)
func_ret_sub = 4;
#endif
@ -594,10 +534,9 @@ ST_FUNC void gfunc_prolog(CType *func_type)
#ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */
if (tcc_state->do_bounds_check) {
func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind;
oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */
func_bound_offset = lbounds_section->data_offset;
}
#endif
}
@ -605,47 +544,42 @@ ST_FUNC void gfunc_prolog(CType *func_type)
/* generate function epilog */
ST_FUNC void gfunc_epilog(void)
{
addr_t v, saved_ind;
int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check
&& func_bound_offset != lbounds_section->data_offset) {
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
int saved_ind;
int *bounds_ptr;
Sym *sym, *sym_data;
/* add end of table info */
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
*bounds_ptr = 0;
/* generate bound local allocation */
saved_ind = ind;
ind = func_bound_ind;
ind = func_sub_sp_offset;
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
func_bound_offset, lbounds_section->data_offset);
greloc(cur_text_section, sym_data,
ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_new);
sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
greloc(cur_text_section, sym,
ind + 1, R_386_PC32);
oad(0xe8, -4);
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);
greloc(cur_text_section, sym_data,
ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_delete);
sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
greloc(cur_text_section, sym,
ind + 1, R_386_PC32);
oad(0xe8, -4);
o(0x585a); /* restore returned value, if any */
}
#endif
/* 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 */
@ -654,30 +588,34 @@ 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
if (v >= 4096) {
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
oad(0xb8, v); /* mov stacksize, %eax */
gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
greloc(cur_text_section, sym, ind-4, R_386_PC32);
} else
#endif
{
o(0xe58955); /* push %ebp, mov %esp, %ebp */
o(0xec81); /* sub esp, stacksize */
gen_le32(v);
#ifdef TCC_TARGET_PE
#if FUNC_PROLOG_SIZE == 10
o(0x90); /* adjust to FUNC_PROLOG_SIZE */
#endif
}
o(0x53 * USE_EBX); /* push ebx */
ind = saved_ind;
}
/* generate a jump to a label */
ST_FUNC int gjmp(int t)
{
return gjmp2(0xe9, t);
return psym(0xe9, t);
}
/* generate a jump to a fixed address */
@ -693,57 +631,46 @@ ST_FUNC void gjmp_addr(int a)
}
}
ST_FUNC void gtst_addr(int inv, int a)
{
int v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
inv ^= (vtop--)->c.i;
a -= ind + 2;
if (a == (char)a) {
g(inv - 32);
g(a);
} else {
g(0x0f);
oad(inv - 16, a - 4);
}
} else if ((v & ~1) == VT_JMP) {
if ((v & 1) != inv) {
gjmp_addr(a);
gsym(vtop->c.i);
} else {
gsym(vtop->c.i);
o(0x05eb);
gjmp_addr(a);
}
vtop--;
}
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
ST_FUNC int gtst(int inv, int t)
{
int v = vtop->r & VT_VALMASK;
if (nocode_wanted) {
;
} else if (v == VT_CMP) {
int v, *p;
v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
g(0x0f);
t = gjmp2((vtop->c.i - 16) ^ inv, t);
t = psym((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
/* insert vtop->c jump list in t */
uint32_t n1, n = vtop->c.i;
if (n) {
while ((n1 = read32le(cur_text_section->data + n)))
n = n1;
write32le(cur_text_section->data + n, t);
t = vtop->c.i;
}
p = &vtop->c.i;
while (*p != 0)
p = (int *)(cur_text_section->data + *p);
*p = t;
t = vtop->c.i;
} else {
t = gjmp(t);
gsym(vtop->c.i);
}
} else {
if (is_float(vtop->type.t) ||
(vtop->type.t & VT_BTYPE) == VT_LLONG) {
vpushi(0);
gen_op(TOK_NE);
}
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
/* constant jmp optimization */
if ((vtop->c.i != 0) != inv)
t = gjmp(t);
} else {
v = gv(RC_INT);
o(0x85);
o(0xc0 + v * 9);
g(0x0f);
t = psym(0x85 ^ inv, t);
}
}
vtop--;
return t;
@ -767,9 +694,9 @@ ST_FUNC void gen_opi(int op)
c = vtop->c.i;
if (c == (char)c) {
/* generate inc and dec for smaller code */
if (c==1 && opc==0 && op != TOK_ADDC1) {
if (c==1 && opc==0) {
o (0x40 | r); // inc
} else if (c==1 && opc==5 && op != TOK_SUBC1) {
} else if (c==1 && opc==5) {
o (0x48 | r); // dec
} else {
o(0x83);
@ -861,8 +788,6 @@ ST_FUNC void gen_opi(int op)
fr = vtop[0].r;
vtop--;
save_reg(TREG_EDX);
/* save EAX too if used otherwise */
save_reg_upstack(TREG_EAX, 1);
if (op == TOK_UMULL) {
o(0xf7); /* mul fr */
o(0xe0 + fr);
@ -929,10 +854,7 @@ ST_FUNC void gen_opf(int op)
swapped = 0;
if (swapped)
o(0xc9d9); /* fxch %st(1) */
if (op == TOK_EQ || op == TOK_NE)
o(0xe9da); /* fucompp */
else
o(0xd9de); /* fcompp */
o(0xe9da); /* fucompp */
o(0xe0df); /* fnstsw %ax */
if (op == TOK_EQ) {
o(0x45e480); /* and $0x45, %ah */
@ -978,7 +900,7 @@ ST_FUNC void gen_opf(int op)
break;
}
ft = vtop->type.t;
fc = vtop->c.i;
fc = vtop->c.ul;
if ((ft & VT_BTYPE) == VT_LDOUBLE) {
o(0xde); /* fxxxp %st, %st(1) */
o(0xc1 + (a << 3));
@ -990,7 +912,7 @@ ST_FUNC void gen_opf(int op)
r = get_reg(RC_INT);
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.i = fc;
v1.c.ul = fc;
load(r, &v1);
fc = 0;
}
@ -1036,20 +958,55 @@ ST_FUNC void gen_cvt_itof(int t)
}
/* convert fp to int 't' type */
/* XXX: handle long long case */
ST_FUNC void gen_cvt_ftoi(int t)
{
int bt = vtop->type.t & VT_BTYPE;
if (bt == VT_FLOAT)
vpush_global_sym(&func_old_type, TOK___fixsfdi);
else if (bt == VT_LDOUBLE)
vpush_global_sym(&func_old_type, TOK___fixxfdi);
int r, r2, size;
Sym *sym;
CType ushort_type;
ushort_type.t = VT_SHORT | VT_UNSIGNED;
ushort_type.ref = 0;
gv(RC_FLOAT);
if (t != VT_INT)
size = 8;
else
size = 4;
o(0x2dd9); /* ldcw xxx */
sym = external_global_sym(TOK___tcc_int_fpu_control,
&ushort_type, VT_LVAL);
greloc(cur_text_section, sym,
ind, R_386_32);
gen_le32(0);
oad(0xec81, size); /* sub $xxx, %esp */
if (size == 4)
o(0x1cdb); /* fistpl */
else
vpush_global_sym(&func_old_type, TOK___fixdfdi);
vswap();
gfunc_call(1);
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = REG_LRET;
o(0x3cdf); /* fistpll */
o(0x24);
o(0x2dd9); /* ldcw xxx */
sym = external_global_sym(TOK___tcc_fpu_control,
&ushort_type, VT_LVAL);
greloc(cur_text_section, sym,
ind, R_386_32);
gen_le32(0);
r = get_reg(RC_INT);
o(0x58 + r); /* pop r */
if (size == 8) {
if (t == VT_LLONG) {
vtop->r = r; /* mark reg as used */
r2 = get_reg(RC_INT);
o(0x58 + r2); /* pop r2 */
vtop->r2 = r2;
} else {
o(0x04c483); /* add $4, %esp */
}
}
vtop->r = r;
}
/* convert from one floating point type to another */
@ -1072,26 +1029,31 @@ ST_FUNC void ggoto(void)
/* generate a bounded pointer addition */
ST_FUNC void gen_bounded_ptr_add(void)
{
Sym *sym;
/* prepare fast i386 function call (args in eax and edx) */
gv2(RC_EAX, RC_EDX);
/* save all temporary registers */
vtop -= 2;
save_regs(0);
/* do a fast function call */
gen_static_call(TOK___bound_ptr_add);
sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
greloc(cur_text_section, sym,
ind + 1, R_386_PC32);
oad(0xe8, -4);
/* returned pointer is in eax */
vtop++;
vtop->r = TREG_EAX | VT_BOUNDED;
/* address of bounding function call point */
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
}
/* patch pointer addition in vtop so that pointer dereferencing is
also tested */
ST_FUNC void gen_bounded_ptr_deref(void)
{
addr_t func;
int size, align;
int func;
int size, align;
Elf32_Rel *rel;
Sym *sym;
@ -1120,7 +1082,7 @@ ST_FUNC void gen_bounded_ptr_deref(void)
/* patch relocation */
/* XXX: find a better solution ? */
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
sym = external_global_sym(func, &func_old_type, 0);
if (!sym->c)
put_extern_sym(sym, NULL, 0, 0);
@ -1128,39 +1090,6 @@ ST_FUNC void gen_bounded_ptr_deref(void)
}
#endif
/* Save the stack pointer onto the stack */
ST_FUNC void gen_vla_sp_save(int addr) {
/* mov %esp,addr(%ebp)*/
o(0x89);
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
}
/* Restore the SP from a location on the stack */
ST_FUNC void gen_vla_sp_restore(int addr) {
o(0x8b);
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
}
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
#ifdef TCC_TARGET_PE
/* alloca does more than just adjust %rsp on Windows */
vpush_global_sym(&func_old_type, TOK_alloca);
vswap(); /* Move alloca ref past allocation size */
gfunc_call(1);
#else
int r;
r = gv(RC_INT); /* allocation size */
/* sub r,%rsp */
o(0x2b);
o(0xe0 | r);
/* We align to 16 bytes rather than align */
/* and ~15, %esp */
o(0xf0e483);
vpop();
#endif
}
/* end of X86 code generator */
/*************************************************************/
#endif

View File

@ -1,243 +0,0 @@
#ifdef TARGET_DEFS_ONLY
#define EM_TCC_TARGET EM_386
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_386_32
#define R_DATA_PTR R_386_32
#define R_JMP_SLOT R_386_JMP_SLOT
#define R_GLOB_DAT R_386_GLOB_DAT
#define R_COPY R_386_COPY
#define R_NUM R_386_NUM
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 0
#define RELOCATE_DLLPLT 0
#else /* !TARGET_DEFS_ONLY */
#include "tcc.h"
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
int code_reloc (int reloc_type)
{
switch (reloc_type) {
case R_386_RELATIVE:
case R_386_16:
case R_386_32:
case R_386_GOTPC:
case R_386_GOTOFF:
case R_386_GOT32:
case R_386_GOT32X:
case R_386_GLOB_DAT:
case R_386_COPY:
return 0;
case R_386_PC16:
case R_386_PC32:
case R_386_PLT32:
case R_386_JMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
/* Returns an enumerator to describe wether 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_386_RELATIVE:
case R_386_16:
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;
case R_386_GOTPC:
case R_386_GOTOFF:
return BUILD_GOT_ONLY;
case R_386_GOT32:
case R_386_GOT32X:
case R_386_PLT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
uint8_t *p;
int modrm;
unsigned plt_offset, relofs;
/* on i386 if we build a DLL, we add a %ebx offset */
if (s1->output_type == TCC_OUTPUT_DLL)
modrm = 0xa3;
else
modrm = 0x25;
/* empty PLT: create PLT0 entry that pushes the library indentifier
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
(GOT + 2 * PTR_SIZE) */
if (plt->data_offset == 0) {
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* pushl got + PTR_SIZE */
p[1] = modrm + 0x10;
write32le(p + 2, PTR_SIZE);
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
p[7] = modrm;
write32le(p + 8, PTR_SIZE * 2);
}
plt_offset = plt->data_offset;
/* The PLT slot refers to the relocation entry it needs via offset.
The reloc entry is created below, so its offset is the current
data_offset */
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
write32le(p + 2, got_offset);
p[6] = 0x68; /* push $xxx */
write32le(p + 7, relofs);
p[11] = 0xe9; /* jmp plt_start */
write32le(p + 12, -(plt->data_offset));
return plt_offset;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
add32le(p + 2, s1->got->sh_addr);
add32le(p + 8, s1->got->sh_addr);
p += 16;
while (p < p_end) {
add32le(p + 2, s1->got->sh_addr);
p += 16;
}
}
}
static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
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)
{
int sym_index, esym_index;
sym_index = ELFW(R_SYM)(rel->r_info);
switch (type) {
case R_386_32:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = s1->sym_attrs[sym_index].dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
qrel++;
return;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
qrel++;
}
}
add32le(ptr, val);
return;
case R_386_PC32:
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_386_PC32);
qrel++;
return;
}
}
add32le(ptr, val - addr);
return;
case R_386_PLT32:
add32le(ptr, val - addr);
return;
case R_386_GLOB_DAT:
case R_386_JMP_SLOT:
write32le(ptr, val);
return;
case R_386_GOTPC:
add32le(ptr, s1->got->sh_addr - addr);
return;
case R_386_GOTOFF:
add32le(ptr, val - s1->got->sh_addr);
return;
case R_386_GOT32:
case R_386_GOT32X:
/* we load the got offset */
add32le(ptr, s1->sym_attrs[sym_index].got_offset);
return;
case R_386_16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
output_file:
tcc_error("can only produce 16-bit binary files");
}
write16le(ptr, read16le(ptr) + val);
return;
case R_386_PC16:
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY)
goto output_file;
write16le(ptr, read16le(ptr) + val - addr);
return;
case R_386_RELATIVE:
/* do nothing */
return;
case R_386_COPY:
/* This reloction 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?
*/
return;
default:
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
return;
}
}
#endif /* !TARGET_DEFS_ONLY */

View File

@ -91,16 +91,7 @@
DEF_ASM(fs)
DEF_ASM(gs)
DEF_ASM(st)
DEF_ASM(rip)
#ifdef TCC_TARGET_X86_64
/* The four low parts of sp/bp/si/di that exist only on
x86-64 (encoding aliased to ah,ch,dh,dh when not using REX). */
DEF_ASM(spl)
DEF_ASM(bpl)
DEF_ASM(sil)
DEF_ASM(dil)
#endif
/* generic two operands */
DEF_BWLX(mov)
@ -135,8 +126,12 @@
DEF_BWLX(shr)
DEF_BWLX(sar)
DEF_WLX(shld)
DEF_WLX(shrd)
DEF_ASM(shldw)
DEF_ASM(shldl)
DEF_ASM(shld)
DEF_ASM(shrdw)
DEF_ASM(shrdl)
DEF_ASM(shrd)
DEF_ASM(pushw)
DEF_ASM(pushl)
@ -155,15 +150,12 @@
DEF_BWL(in)
DEF_BWL(out)
DEF_WLX(movzb)
DEF_WL(movzb)
DEF_ASM(movzwl)
DEF_ASM(movsbw)
DEF_ASM(movsbl)
DEF_ASM(movswl)
#ifdef TCC_TARGET_X86_64
DEF_ASM(movsbq)
DEF_ASM(movswq)
DEF_ASM(movzwq)
DEF_ASM(movslq)
#endif
@ -180,11 +172,10 @@
DEF_ASM(lcall)
DEF_ASM(ljmp)
DEF_ASMTEST(j,)
DEF_ASMTEST(j)
DEF_ASMTEST(set,)
DEF_ASMTEST(set,b)
DEF_ASMTEST(cmov,)
DEF_ASMTEST(set)
DEF_ASMTEST(cmov)
DEF_WLX(bsf)
DEF_WLX(bsr)
@ -193,7 +184,6 @@
DEF_WLX(btr)
DEF_WLX(btc)
DEF_WLX(lar)
DEF_WLX(lsl)
/* generic FP ops */
@ -201,7 +191,7 @@
DEF_FP(mul)
DEF_ASM(fcom)
DEF_ASM(fcom_1) /* non existent op, just to have a regular table */
DEF_ASM(fcom_1) /* non existant op, just to have a regular table */
DEF_FP1(com)
DEF_FP(comp)

View File

@ -53,11 +53,11 @@ const int reg_classes[NB_REGS] = {
#define REG_FRET REG_ST0 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
/* #define INVERT_FUNC_PARAMS */
//#define INVERT_FUNC_PARAMS
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
/* #define FUNC_STRUCT_PARAM_AS_PTR */
//#define FUNC_STRUCT_PARAM_AS_PTR
/* pointer size, in bytes */
#define PTR_SIZE 4
@ -441,7 +441,6 @@ void gfunc_prolog(int t)
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->t;
func_var = (sym->c == FUNC_ELLIPSIS);
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr++;
@ -529,6 +528,19 @@ int gtst(int inv, int t)
t = gjmp(t);
gsym(vtop->c.i);
}
} else {
if (is_float(vtop->t)) {
vpushi(0);
gen_op(TOK_NE);
}
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
/* constant jmp optimization */
if ((vtop->c.i != 0) != inv)
t = gjmp(t);
} else {
v = gv(RC_INT);
t = out_opj(IL_OP_BRTRUE - inv, t);
}
}
vtop--;
return t;

View File

@ -27,7 +27,7 @@
#define DBL_MAX_10_EXP 308
/* horrible intel long double */
#if defined __i386__ || defined __x86_64__
#ifdef __i386__
#define LDBL_MANT_DIG 64
#define LDBL_DIG 18

View File

@ -4,64 +4,26 @@
#ifdef __x86_64__
#ifndef _WIN64
//This should be in sync with the declaration on our lib/libtcc1.c
/* GCC compatible definition of va_list. */
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __va_list_struct;
typedef void *va_list;
typedef __va_list_struct va_list[1];
va_list __va_start(void *fp);
void *__va_arg(va_list ap, int arg_type, int size);
va_list __va_copy(va_list src);
void __va_end(va_list ap);
void __va_start(__va_list_struct *ap, void *fp);
void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);
#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0))
#define va_start(ap, last) ((ap) = __va_start(__builtin_frame_address(0)))
#define va_arg(ap, type) \
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type))))
#define va_copy(dest, src) (*(dest) = *(src))
#define va_end(ap)
/* avoid conflicting definition for va_list on Macs. */
#define _VA_LIST_T
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type))))
#define va_copy(dest, src) ((dest) = __va_copy(src))
#define va_end(ap) __va_end(ap)
#else /* _WIN64 */
typedef char *va_list;
#define va_start(ap,last) __builtin_va_start(ap,last)
#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
#define va_copy(dest, src) ((dest) = (src))
#define va_end(ap)
#endif
#elif __arm__
typedef char *va_list;
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
& ~(_tcc_alignof(type) - 1))
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+7)&~7)
#define va_arg(ap,type) (ap += (sizeof(type)+7)&~7, *(type *)(ap - ((sizeof(type)+7)&~7)))
#define va_copy(dest, src) (dest) = (src)
#define va_end(ap)
#elif defined(__aarch64__)
typedef struct {
void *__stack;
void *__gr_top;
void *__vr_top;
int __gr_offs;
int __vr_offs;
} va_list;
#define va_start(ap, last) __va_start(ap, last)
#define va_arg(ap, type) __va_arg(ap, type)
#define va_end(ap)
#define va_copy(dest, src) ((dest) = (src))
#endif
#else /* __i386__ */
typedef char *va_list;

View File

@ -6,6 +6,5 @@
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#endif /* _STDBOOL_H */

View File

@ -20,27 +20,9 @@ typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
#define offsetof(type, field) ((size_t)&((type *)0)->field)
void *alloca(size_t size);
#endif
/* Older glibc require a wint_t from <stddef.h> (when requested
by __need_wint_t, as otherwise stddef.h isn't allowed to
define this type). Note that this must be outside the normal
_STDDEF_H guard, so that it works even when we've included the file
already (without requiring wint_t). Some other libs define _WINT_T
if they've already provided that type, so we can use that as guard.
TCC defines __WINT_TYPE__ for us. */
#if defined (__need_wint_t)
#ifndef _WINT_T
#define _WINT_T
typedef __WINT_TYPE__ wint_t;
#endif
#undef __need_wint_t
#endif

View File

@ -39,7 +39,6 @@ int getchar(void);
char *gets(char *s);
int ungetc(int c, FILE *stream);
int fflush(FILE *stream);
int putchar (int c);
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
@ -65,7 +64,6 @@ void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
char *strdup(const char *s);
size_t strlen(const char *s);
/* dlfcn.h */
#define RTLD_LAZY 0x001

View File

@ -4,72 +4,99 @@
TOP = ..
include $(TOP)/Makefile
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
VPATH = $(top_srcdir)/lib $(top_srcdir)/win32/lib
TCC = $(TOP)/$(X)tcc$(EXESUF)
XCC = $(TCC)
XAR = $(TCC) -ar
XFLAGS-unx = -B$(TOPSRC)
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
XFLAGS = $(XFLAGS$(XCFG))
XCFG = $(or $(findstring -win,$T),-unx)
ifeq ($(X),)
BCHECK_O = bcheck.o
ifeq "$T" "arm"
XCC = $(CC)
XAR = $(AR)
XFLAGS = $(CFLAGS) -fPIC
ifndef TARGET
ifdef CONFIG_WIN64
TARGET = x86_64-win32
else
ifdef CONFIG_WIN32
TARGET = i386-win32
else
ifeq ($(ARCH),i386)
TARGET = i386
ifneq ($(TARGETOS),Darwin)
XCC = $(CC)
endif
else
ifeq ($(ARCH),x86-64)
TARGET = x86_64
ifneq ($(TARGETOS),Darwin)
XCC = $(CC)
endif
endif
endif
endif
endif
BCHECK_O = bcheck.o
endif
DIR = $(TARGET)
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
WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
ifeq "$(TARGET)" "i386-win32"
OBJ = $(addprefix $(DIR)/,$(WIN32_O))
TGT = -DTCC_TARGET_I386 -DTCC_TARGET_PE
XCC = $(TCC) -B$(top_srcdir)/win32 -I$(top_srcdir)/include
XAR = $(DIR)/tiny_libmaker$(EXESUF)
else
ifeq "$(TARGET)" "x86_64-win32"
OBJ = $(addprefix $(DIR)/,$(WIN64_O))
TGT = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
XCC = $(TCC) -B$(top_srcdir)/win32 -I$(top_srcdir)/include
XAR = $(DIR)/tiny_libmaker$(EXESUF)
else
ifeq "$(TARGET)" "i386"
OBJ = $(addprefix $(DIR)/,$(I386_O))
TGT = -DTCC_TARGET_I386
XCC ?= $(TCC) -B$(TOP)
else
ifeq "$(TARGET)" "x86_64"
OBJ = $(addprefix $(DIR)/,$(X86_64_O))
TGT = -DTCC_TARGET_X86_64
XCC ?= $(TCC) -B$(TOP)
else
$(error libtcc1.a not supported on target '$(TARGET)')
endif
endif
endif
endif
XFLAGS = $(CPPFLAGS) $(CFLAGS) $(TGT)
ifeq ($(TARGETOS),Darwin)
XAR = $(DIR)/tiny_libmaker$(EXESUF)
XFLAGS += -D_ANSI_SOURCE
BCHECK_O =
endif
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
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
ifdef XAR
AR = $(XAR)
endif
OBJ-i386 = $(I386_O)
TGT-i386 = -DTCC_TARGET_I386
$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR)
$(AR) rcs $@ $(OBJ)
$(DIR)/%.o : %.c
$(XCC) -c $< -o $@ $(XFLAGS)
$(DIR)/%.o : %.S
$(XCC) -c $< -o $@ $(XFLAGS)
$(DIR)/%$(EXESUF) : $(TOP)/win32/tools/%.c
$(CC) -o $@ $< $(XFLAGS) $(LDFLAGS)
OBJ-x86_64 = $(X86_64_O)
TGT-x86_64 = -DTCC_TARGET_X86_64
OBJ-arm = $(ARM_O)
TGT-arm = -DTCC_TARGET_ARM
OBJ-arm64 = $(ARM64_O)
TGT-arm64 = -DTCC_TARGET_ARM64
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
TGT-i386-win32 = -DTCC_TARGET_I386 -DTCC_TARGET_PE
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
TGT-x86_64-win32 = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
OBJ-arm-wince = $(ARM_O) $(WIN_O)
TGT-arm-wince = -DTCC_TARGET_ARM -DTCC_TARGET_PE
all : $(BIN)
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
$(XAR) rcs $@ $^
$(X)%.o : %.c
$(XCC) -c $< -o $@ $(TGT-$T) $(XFLAGS)
$(X)%.o : %.S
$(XCC) -c $< -o $@ $(TGT-$T) $(XFLAGS)
$(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c
$(OBJ) $(XAR) : $(DIR)/exists
$(DIR)/exists :
mkdir -p $(DIR)
@echo $@ > $@
clean :
rm -f *.a *.o $(BIN)
rm -rfv i386-win32 x86_64-win32 i386 x86_64

View File

@ -1,17 +0,0 @@
.text
.align 2
.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

View File

@ -14,10 +14,10 @@ __bound_alloca:
#ifdef TCC_TARGET_PE
p4:
cmp $4096,%eax
jbe p5
test %eax,-4096(%esp)
jle p5
sub $4096,%esp
sub $4096,%eax
test %eax,(%esp)
jmp p4
p5:

View File

@ -13,10 +13,10 @@ alloca:
#ifdef TCC_TARGET_PE
p1:
cmp $4096,%eax
jbe p2
test %eax,-4096(%esp)
jle p2
sub $4096,%esp
sub $4096,%eax
test %eax,(%esp)
jmp p1
p2:
#endif
@ -28,4 +28,8 @@ p3:
push %edx
ret
/* mark stack as nonexecutable */
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif
/* ---------------------------------------------- */

View File

@ -1,56 +0,0 @@
/* ---------------------------------------------- */
/* alloca86_64.S */
.globl __bound_alloca
__bound_alloca:
#ifdef TCC_TARGET_PE
# bound checking is not implemented
pop %rdx
mov %rcx,%rax
add $15,%rax
and $-16,%rax
jz p3
p1:
cmp $4096,%rax
jbe p2
test %rax,-4096(%rsp)
sub $4096,%rsp
sub $4096,%rax
jmp p1
p2:
sub %rax,%rsp
mov %rsp,%rax
add $32,%rax
p3:
push %rdx
ret
#else
pop %rdx
mov %rdi,%rax
mov %rax,%rsi # size, a second parm to the __bound_new_region
add $15,%rax
and $-16,%rax
jz p3
sub %rax,%rsp
mov %rsp,%rdi # pointer, a first parm to the __bound_new_region
mov %rsp,%rax
push %rdx
push %rax
call __bound_new_region
pop %rax
pop %rdx
p3:
push %rdx
ret
#endif
/* ---------------------------------------------- */

View File

@ -17,10 +17,10 @@ alloca:
#ifdef TCC_TARGET_PE
p1:
cmp $4096,%rax
jbe p2
test %rax,-4096(%rsp)
jle p2
sub $4096,%rsp
sub $4096,%rax
test %rax,(%rsp)
jmp p1
p2:
#endif
@ -35,4 +35,8 @@ p3:
push %rdx
ret
/* mark stack as nonexecutable */
#if defined __ELF__ && defined __linux__
.section .note.GNU-stack,"",@progbits
#endif
/* ---------------------------------------------- */

View File

@ -1,501 +0,0 @@
/* TCC ARM runtime EABI
Copyright (C) 2013 Thomas Preud'homme
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
#ifdef __TINYC__
#define INT_MIN (-2147483647 - 1)
#define INT_MAX 2147483647
#define UINT_MAX 0xffffffff
#define LONG_MIN (-2147483647L - 1)
#define LONG_MAX 2147483647L
#define ULONG_MAX 0xffffffffUL
#define LLONG_MAX 9223372036854775807LL
#define LLONG_MIN (-9223372036854775807LL - 1)
#define ULLONG_MAX 0xffffffffffffffffULL
#else
#include <limits.h>
#endif
/* We rely on the little endianness and EABI calling convention for this to
work */
typedef struct double_unsigned_struct {
unsigned low;
unsigned high;
} double_unsigned_struct;
typedef struct unsigned_int_struct {
unsigned low;
int high;
} unsigned_int_struct;
#define REGS_RETURN(name, type) \
void name ## _return(type ret) {}
/* Float helper functions */
#define FLOAT_EXP_BITS 8
#define FLOAT_FRAC_BITS 23
#define DOUBLE_EXP_BITS 11
#define DOUBLE_FRAC_BITS 52
#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1)
REGS_RETURN(unsigned_int_struct, unsigned_int_struct)
REGS_RETURN(double_unsigned_struct, double_unsigned_struct)
/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */
/* float to [unsigned] long long conversion */
#define DEFINE__AEABI_F2XLZ(name, with_sign) \
void __aeabi_ ## name(unsigned val) \
{ \
int exp, high_shift, sign; \
double_unsigned_struct ret; \
\
/* compute sign */ \
sign = val >> 31; \
\
/* compute real exponent */ \
exp = val >> FLOAT_FRAC_BITS; \
exp &= (1 << FLOAT_EXP_BITS) - 1; \
exp -= ONE_EXP(FLOAT); \
\
/* undefined behavior if truncated value cannot be represented */ \
if (with_sign) { \
if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
return; \
} else { \
if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
return; \
} \
\
val &= (1 << FLOAT_FRAC_BITS) - 1; \
if (exp >= 32) { \
ret.high = 1 << (exp - 32); \
if (exp - 32 >= FLOAT_FRAC_BITS) { \
ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \
ret.low = 0; \
} else { \
high_shift = FLOAT_FRAC_BITS - (exp - 32); \
ret.high |= val >> high_shift; \
ret.low = val << (32 - high_shift); \
} \
} else { \
ret.high = 0; \
ret.low = 1 << exp; \
if (exp > FLOAT_FRAC_BITS) \
ret.low |= val << (exp - FLOAT_FRAC_BITS); \
else \
ret.low |= val >> (FLOAT_FRAC_BITS - exp); \
} \
\
/* encode negative integer using 2's complement */ \
if (with_sign && sign) { \
ret.low = ~ret.low; \
ret.high = ~ret.high; \
if (ret.low == UINT_MAX) { \
ret.low = 0; \
ret.high++; \
} else \
ret.low++; \
} \
\
double_unsigned_struct_return(ret); \
}
/* float to unsigned long long conversion */
DEFINE__AEABI_F2XLZ(f2ulz, 0)
/* float to long long conversion */
DEFINE__AEABI_F2XLZ(f2lz, 1)
/* double to [unsigned] long long conversion */
#define DEFINE__AEABI_D2XLZ(name, with_sign) \
void __aeabi_ ## name(double_unsigned_struct val) \
{ \
int exp, high_shift, sign; \
double_unsigned_struct ret; \
\
/* compute sign */ \
sign = val.high >> 31; \
\
/* compute real exponent */ \
exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \
exp &= (1 << DOUBLE_EXP_BITS) - 1; \
exp -= ONE_EXP(DOUBLE); \
\
/* undefined behavior if truncated value cannot be represented */ \
if (with_sign) { \
if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
return; \
} else { \
if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
return; \
} \
\
val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \
if (exp >= 32) { \
ret.high = 1 << (exp - 32); \
if (exp >= DOUBLE_FRAC_BITS) { \
high_shift = exp - DOUBLE_FRAC_BITS; \
ret.high |= val.high << high_shift; \
ret.high |= val.low >> (32 - high_shift); \
ret.low = val.low << high_shift; \
} else { \
high_shift = DOUBLE_FRAC_BITS - exp; \
ret.high |= val.high >> high_shift; \
ret.low = val.high << (32 - high_shift); \
ret.low |= val.low >> high_shift; \
} \
} else { \
ret.high = 0; \
ret.low = 1 << exp; \
if (exp > DOUBLE_FRAC_BITS - 32) { \
high_shift = exp - DOUBLE_FRAC_BITS - 32; \
ret.low |= val.high << high_shift; \
ret.low |= val.low >> (32 - high_shift); \
} else \
ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \
} \
\
/* encode negative integer using 2's complement */ \
if (with_sign && sign) { \
ret.low = ~ret.low; \
ret.high = ~ret.high; \
if (ret.low == UINT_MAX) { \
ret.low = 0; \
ret.high++; \
} else \
ret.low++; \
} \
\
double_unsigned_struct_return(ret); \
}
/* double to unsigned long long conversion */
DEFINE__AEABI_D2XLZ(d2ulz, 0)
/* double to long long conversion */
DEFINE__AEABI_D2XLZ(d2lz, 1)
/* long long to float conversion */
#define DEFINE__AEABI_XL2F(name, with_sign) \
unsigned __aeabi_ ## name(unsigned long long v) \
{ \
int s /* shift */, flb /* first lost bit */, sign = 0; \
unsigned p = 0 /* power */, ret; \
double_unsigned_struct val; \
\
/* fraction in negative float is encoded in 1's complement */ \
if (with_sign && (v & (1ULL << 63))) { \
sign = 1; \
v = ~v + 1; \
} \
val.low = v; \
val.high = v >> 32; \
/* fill fraction bits */ \
for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
if (p) { \
ret = val.high & (p - 1); \
if (s < FLOAT_FRAC_BITS) { \
ret <<= FLOAT_FRAC_BITS - s; \
ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \
flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \
} else { \
flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
ret >>= s - FLOAT_FRAC_BITS; \
} \
s += 32; \
} else { \
for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
if (p) { \
ret = val.low & (p - 1); \
if (s <= FLOAT_FRAC_BITS) { \
ret <<= FLOAT_FRAC_BITS - s; \
flb = 0; \
} else { \
flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
ret >>= s - FLOAT_FRAC_BITS; \
} \
} else \
return 0; \
} \
if (flb) \
ret++; \
\
/* fill exponent bits */ \
ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \
\
/* fill sign bit */ \
ret |= sign << 31; \
\
return ret; \
}
/* unsigned long long to float conversion */
DEFINE__AEABI_XL2F(ul2f, 0)
/* long long to float conversion */
DEFINE__AEABI_XL2F(l2f, 1)
/* long long to double conversion */
#define __AEABI_XL2D(name, with_sign) \
void __aeabi_ ## name(unsigned long long v) \
{ \
int s /* shift */, high_shift, sign = 0; \
unsigned tmp, p = 0; \
double_unsigned_struct val, ret; \
\
/* fraction in negative float is encoded in 1's complement */ \
if (with_sign && (v & (1ULL << 63))) { \
sign = 1; \
v = ~v + 1; \
} \
val.low = v; \
val.high = v >> 32; \
\
/* fill fraction bits */ \
for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
if (p) { \
tmp = val.high & (p - 1); \
if (s < DOUBLE_FRAC_BITS - 32) { \
high_shift = DOUBLE_FRAC_BITS - 32 - s; \
ret.high = tmp << high_shift; \
ret.high |= val.low >> (32 - high_shift); \
ret.low = val.low << high_shift; \
} else { \
high_shift = s - (DOUBLE_FRAC_BITS - 32); \
ret.high = tmp >> high_shift; \
ret.low = tmp << (32 - high_shift); \
ret.low |= val.low >> high_shift; \
if ((val.low >> (high_shift - 1)) & 1) { \
if (ret.low == UINT_MAX) { \
ret.high++; \
ret.low = 0; \
} else \
ret.low++; \
} \
} \
s += 32; \
} else { \
for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
if (p) { \
tmp = val.low & (p - 1); \
if (s <= DOUBLE_FRAC_BITS - 32) { \
high_shift = DOUBLE_FRAC_BITS - 32 - s; \
ret.high = tmp << high_shift; \
ret.low = 0; \
} else { \
high_shift = s - (DOUBLE_FRAC_BITS - 32); \
ret.high = tmp >> high_shift; \
ret.low = tmp << (32 - high_shift); \
} \
} else { \
ret.high = ret.low = 0; \
double_unsigned_struct_return(ret); \
} \
} \
\
/* fill exponent bits */ \
ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \
\
/* fill sign bit */ \
ret.high |= sign << 31; \
\
double_unsigned_struct_return(ret); \
}
/* unsigned long long to double conversion */
__AEABI_XL2D(ul2d, 0)
/* long long to double conversion */
__AEABI_XL2D(l2d, 1)
/* Long long helper functions */
/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */
#define define_aeabi_xdivmod_signed_type(basetype, type) \
typedef struct type { \
basetype quot; \
unsigned basetype rem; \
} type
#define define_aeabi_xdivmod_unsigned_type(basetype, type) \
typedef struct type { \
basetype quot; \
basetype rem; \
} type
#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \
static inline rettype aeabi_ ## name (type num, type den) \
{ \
rettype ret; \
type quot = 0; \
\
/* Increase quotient while it is less than numerator */ \
while (num >= den) { \
type q = 1; \
\
/* Find closest power of two */ \
while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \
q <<= 1; \
\
/* Compute difference between current quotient and numerator */ \
num -= q * den; \
quot += q; \
} \
ret.quot = quot; \
ret.rem = num; \
return ret; \
}
#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \
void __aeabi_ ## name(type numerator, type denominator) \
{ \
unsigned type num, den; \
urettype uxdiv_ret; \
rettype ret; \
\
if (numerator >= 0) \
num = numerator; \
else \
num = 0 - numerator; \
if (denominator >= 0) \
den = denominator; \
else \
den = 0 - denominator; \
uxdiv_ret = aeabi_ ## uiname(num, den); \
/* signs differ */ \
if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \
ret.quot = 0 - uxdiv_ret.quot; \
else \
ret.quot = uxdiv_ret.quot; \
if (numerator < 0) \
ret.rem = 0 - uxdiv_ret.rem; \
else \
ret.rem = uxdiv_ret.rem; \
\
rettype ## _return(ret); \
}
define_aeabi_xdivmod_signed_type(long long, lldiv_t);
define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t);
define_aeabi_xdivmod_signed_type(int, idiv_t);
define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t);
REGS_RETURN(lldiv_t, lldiv_t)
REGS_RETURN(ulldiv_t, ulldiv_t)
REGS_RETURN(idiv_t, idiv_t)
REGS_RETURN(uidiv_t, uidiv_t)
AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULLONG)
__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG)
void __aeabi_uldivmod(unsigned long long num, unsigned long long den)
{
ulldiv_t_return(aeabi_uldivmod(num, den));
}
void __aeabi_llsl(double_unsigned_struct val, int shift)
{
double_unsigned_struct ret;
if (shift >= 32) {
val.high = val.low;
val.low = 0;
shift -= 32;
}
if (shift > 0) {
ret.low = val.low << shift;
ret.high = (val.high << shift) | (val.low >> (32 - shift));
double_unsigned_struct_return(ret);
return;
}
double_unsigned_struct_return(val);
}
#define aeabi_lsr(val, shift, fill, type) \
type ## _struct ret; \
\
if (shift >= 32) { \
val.low = val.high; \
val.high = fill; \
shift -= 32; \
} \
if (shift > 0) { \
ret.high = val.high >> shift; \
ret.low = (val.high << (32 - shift)) | (val.low >> shift); \
type ## _struct_return(ret); \
return; \
} \
type ## _struct_return(val);
void __aeabi_llsr(double_unsigned_struct val, int shift)
{
aeabi_lsr(val, shift, 0, double_unsigned);
}
void __aeabi_lasr(unsigned_int_struct val, int shift)
{
aeabi_lsr(val, shift, val.high >> 31, unsigned_int);
}
/* Integer division functions */
AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT)
int __aeabi_idiv(int numerator, int denominator)
{
unsigned num, den;
uidiv_t ret;
if (numerator >= 0)
num = numerator;
else
num = 0 - numerator;
if (denominator >= 0)
den = denominator;
else
den = 0 - denominator;
ret = aeabi_uidivmod(num, den);
if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */
ret.quot *= -1;
return ret.quot;
}
unsigned __aeabi_uidiv(unsigned num, unsigned den)
{
return aeabi_uidivmod(num, den).quot;
}
__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT)
void __aeabi_uidivmod(unsigned num, unsigned den)
{
uidiv_t_return(aeabi_uidivmod(num, den));
}

View File

@ -22,24 +22,18 @@
#include <stdarg.h>
#include <string.h>
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) \
&& !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
&& !defined(__DragonFly__) && !defined(__OpenBSD__)
#include <malloc.h>
#endif
#if !defined(_WIN32)
#include <unistd.h>
#endif
/* #define BOUND_DEBUG */
#ifdef BOUND_DEBUG
#define dprintf(a...) fprintf(a)
#else
#define dprintf(a...)
#endif
//#define BOUND_DEBUG
/* define so that bound array is static (faster, but use memory if
bound checking not used) */
/* #define BOUND_STATIC */
//#define BOUND_STATIC
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
#define CONFIG_TCC_MALLOC_HOOKS
@ -47,49 +41,45 @@
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
|| defined(__DragonFly__) || defined(__dietlibc__) \
|| defined(__UCLIBC__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__UCLIBC__) || defined(__OpenBSD__) \
|| defined(_WIN32) || defined(TCC_UCLIBC)
//#warning Bound checking does not support malloc (etc.) in this environment.
#warning Bound checking does not support malloc (etc.) in this environment.
#undef CONFIG_TCC_MALLOC_HOOKS
#undef HAVE_MEMALIGN
#endif
#define BOUND_T1_BITS 13
#define BOUND_T2_BITS 11
#define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS)
#define BOUND_E_BITS (sizeof(size_t))
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
#define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS)
#define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS)
#define BOUND_T3_SIZE ((size_t)1 << BOUND_T3_BITS)
#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
#define BOUND_E_BITS 4
#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
#define BOUND_T23_SIZE ((size_t)1 << BOUND_T23_BITS)
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
/* this pointer is generated when bound check is incorrect */
#define INVALID_POINTER ((void *)(-2))
/* size of an empty region */
#define EMPTY_SIZE ((size_t)(-1))
#define EMPTY_SIZE 0xffffffff
/* size of an invalid region */
#define INVALID_SIZE 0
typedef struct BoundEntry {
size_t start;
size_t size;
unsigned long start;
unsigned long size;
struct BoundEntry *next;
size_t is_invalid; /* true if pointers outside region are invalid */
unsigned long is_invalid; /* true if pointers outside region are invalid */
} BoundEntry;
/* external interface */
void __bound_init(void);
void __bound_new_region(void *p, size_t size);
void __bound_new_region(void *p, unsigned long size);
int __bound_delete_region(void *p);
#ifdef __attribute__
/* an __attribute__ macro is defined in the system headers */
#undef __attribute__
#endif
#define FASTCALL __attribute__((regparm(3)))
void *__bound_malloc(size_t size, const void *caller);
@ -114,7 +104,7 @@ extern char __bounds_start; /* start of static bounds table */
const char *__bound_error_msg;
/* runtime error output */
extern void rt_error(size_t pc, const char *fmt, ...);
extern void rt_error(unsigned long pc, const char *fmt, ...);
#ifdef BOUND_STATIC
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
@ -126,12 +116,12 @@ static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
{
size_t addr, tmp;
unsigned long addr, tmp;
BoundEntry *e;
e = e1;
while (e != NULL) {
addr = (size_t)p;
addr = (unsigned long)p;
addr -= e->start;
if (addr <= e->size) {
/* put region at the head */
@ -156,8 +146,7 @@ static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
static void bound_error(const char *fmt, ...)
{
__bound_error_msg = fmt;
fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt);
*(void **)0 = 0; /* force a runtime error */
*(int *)0 = 0; /* force a runtime error */
}
static void bound_alloc_error(void)
@ -167,15 +156,13 @@ static void bound_alloc_error(void)
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */
void * FASTCALL __bound_ptr_add(void *p, size_t offset)
void * FASTCALL __bound_ptr_add(void *p, int offset)
{
size_t addr = (size_t)p;
unsigned long addr = (unsigned long)p;
BoundEntry *e;
dprintf(stderr, "%s %s: %p %x\n",
__FILE__, __FUNCTION__, p, (unsigned)offset);
__bound_init();
#if defined(BOUND_DEBUG)
printf("add: 0x%x %d\n", (int)p, offset);
#endif
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
e = (BoundEntry *)((char *)e +
@ -184,29 +171,22 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset)
addr -= e->start;
if (addr > e->size) {
e = __bound_find_region(e, p);
addr = (size_t)p - e->start;
addr = (unsigned long)p - e->start;
}
addr += offset;
if (addr >= e->size) {
fprintf(stderr,"%s %s: %p is outside of the region\n",
__FILE__, __FUNCTION__, p + offset);
if (addr > e->size)
return INVALID_POINTER; /* return an invalid pointer */
}
return p + offset;
}
/* return '(p + offset)' for pointer indirection (the resulting must
be strictly inside the region */
#define BOUND_PTR_INDIR(dsize) \
void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
{ \
size_t addr = (size_t)p; \
unsigned long addr = (unsigned long)p; \
BoundEntry *e; \
\
dprintf(stderr, "%s %s: %p %x start\n", \
__FILE__, __FUNCTION__, p, (unsigned)offset); \
\
__bound_init(); \
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
e = (BoundEntry *)((char *)e + \
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
@ -214,16 +194,11 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
addr -= e->start; \
if (addr > e->size) { \
e = __bound_find_region(e, p); \
addr = (size_t)p - e->start; \
addr = (unsigned long)p - e->start; \
} \
addr += offset + dsize; \
if (addr > e->size) { \
fprintf(stderr,"%s %s: %p is outside of the region\n", \
__FILE__, __FUNCTION__, p + offset); \
if (addr > e->size) \
return INVALID_POINTER; /* return an invalid pointer */ \
} \
dprintf(stderr, "%s %s: return p+offset = %p\n", \
__FILE__, __FUNCTION__, p + offset); \
return p + offset; \
}
@ -234,27 +209,16 @@ BOUND_PTR_INDIR(8)
BOUND_PTR_INDIR(12)
BOUND_PTR_INDIR(16)
#if defined(__GNUC__) && (__GNUC__ >= 6)
/*
* At least gcc 6.2 complains when __builtin_frame_address is used whith
* nonzero argument.
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wframe-address"
#endif
/* return the frame pointer of the caller */
#define GET_CALLER_FP(fp)\
{\
fp = (size_t)__builtin_frame_address(1);\
fp = (unsigned long)__builtin_frame_address(1);\
}
/* called when entering a function to add all the local regions */
void FASTCALL __bound_local_new(void *p1)
{
size_t addr, size, fp, *p = p1;
dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p);
unsigned long addr, size, fp, *p = p1;
GET_CALLER_FP(fp);
for(;;) {
addr = p[0];
@ -265,13 +229,12 @@ void FASTCALL __bound_local_new(void *p1)
p += 2;
__bound_new_region((void *)addr, size);
}
dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
}
/* called when leaving a function to delete all the local regions */
void FASTCALL __bound_local_delete(void *p1)
{
size_t addr, fp, *p = p1;
unsigned long addr, fp, *p = p1;
GET_CALLER_FP(fp);
for(;;) {
addr = p[0];
@ -283,14 +246,10 @@ void FASTCALL __bound_local_delete(void *p1)
}
}
#if defined(__GNUC__) && (__GNUC__ >= 6)
#pragma GCC diagnostic pop
#endif
static BoundEntry *__bound_new_page(void)
{
BoundEntry *page;
size_t i;
int i;
page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
if (!page)
@ -318,11 +277,11 @@ static void bound_free_entry(BoundEntry *e)
libc_free(e);
}
static BoundEntry *get_page(size_t index)
static inline BoundEntry *get_page(int index)
{
BoundEntry *page;
page = __bound_t1[index];
if (!page || page == __bound_empty_t2 || page == __bound_invalid_t2) {
if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
/* create a new page if necessary */
page = __bound_new_page();
__bound_t1[index] = page;
@ -331,11 +290,11 @@ static BoundEntry *get_page(size_t index)
}
/* mark a region as being invalid (can only be used during init) */
static void mark_invalid(size_t addr, size_t size)
static void mark_invalid(unsigned long addr, unsigned long size)
{
size_t start, end;
unsigned long start, end;
BoundEntry *page;
size_t t1_start, t1_end, i, j, t2_start, t2_end;
int t1_start, t1_end, i, j, t2_start, t2_end;
start = addr;
end = addr + size;
@ -347,7 +306,7 @@ static void mark_invalid(size_t addr, size_t size)
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
#if 0
dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end);
printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
#endif
/* first we handle full pages */
@ -386,18 +345,10 @@ static void mark_invalid(size_t addr, size_t size)
void __bound_init(void)
{
size_t i;
int i;
BoundEntry *page;
size_t start, size;
size_t *p;
static int inited;
if (inited)
return;
inited = 1;
dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
unsigned long start, size;
int *p;
/* save malloc hooks and install bound check hooks */
install_malloc_hooks();
@ -423,7 +374,7 @@ void __bound_init(void)
__bound_invalid_t2 = page;
/* invalid pointer zone */
start = (size_t)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
size = BOUND_T23_SIZE;
mark_invalid(start, size);
@ -454,40 +405,26 @@ void __bound_init(void)
* (b) on Linux >= v3.3, the alternative is to read
* start_brk from /proc/self/stat
*/
start = (size_t)sbrk(0);
start = (unsigned long)sbrk(0);
size = 128 * 0x100000;
mark_invalid(start, size);
#endif
/* add all static bound check values */
p = (size_t *)&__bounds_start;
p = (int *)&__bounds_start;
while (p[0] != 0) {
__bound_new_region((void *)p[0], p[1]);
p += 2;
}
dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
}
void __bound_main_arg(void **p)
{
void *start = p;
while (*p++);
dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n",
__FILE__, __FUNCTION__, start, (unsigned)((void *)p - start));
__bound_new_region(start, (void *) p - start);
}
void __bound_exit(void)
{
dprintf(stderr, "%s, %s()\n", __FILE__, __FUNCTION__);
restore_malloc_hooks();
}
static inline void add_region(BoundEntry *e,
size_t start, size_t size)
unsigned long start, unsigned long size)
{
BoundEntry *e1;
if (e->start == 0) {
@ -507,18 +444,13 @@ static inline void add_region(BoundEntry *e,
}
/* create a new region. It should not already exist in the region list */
void __bound_new_region(void *p, size_t size)
void __bound_new_region(void *p, unsigned long size)
{
size_t start, end;
unsigned long start, end;
BoundEntry *page, *e, *e2;
size_t t1_start, t1_end, i, t2_start, t2_end;
int t1_start, t1_end, i, t2_start, t2_end;
dprintf(stderr, "%s, %s(%p, %x) start\n",
__FILE__, __FUNCTION__, p, (unsigned)size);
__bound_init();
start = (size_t)p;
start = (unsigned long)p;
end = start + size;
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
@ -529,7 +461,10 @@ void __bound_new_region(void *p, size_t size)
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
#ifdef BOUND_DEBUG
printf("new %lx %lx %x %x %x %x\n",
start, end, t1_start, t1_end, t2_start, t2_end);
#endif
e = (BoundEntry *)((char *)page + t2_start);
add_region(e, start, size);
@ -571,17 +506,16 @@ void __bound_new_region(void *p, size_t size)
}
add_region(e, start, size);
}
dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
}
/* delete a region */
static inline void delete_region(BoundEntry *e, void *p, size_t empty_size)
static inline void delete_region(BoundEntry *e,
void *p, unsigned long empty_size)
{
size_t addr;
unsigned long addr;
BoundEntry *e1;
addr = (size_t)p;
addr = (unsigned long)p;
addr -= e->start;
if (addr <= e->size) {
/* region found is first one */
@ -605,7 +539,7 @@ static inline void delete_region(BoundEntry *e, void *p, size_t empty_size)
/* region not found: do nothing */
if (e == NULL)
break;
addr = (size_t)p - e->start;
addr = (unsigned long)p - e->start;
if (addr <= e->size) {
/* found: remove entry */
e1->next = e->next;
@ -620,15 +554,11 @@ static inline void delete_region(BoundEntry *e, void *p, size_t empty_size)
/* return non zero if error */
int __bound_delete_region(void *p)
{
size_t start, end, addr, size, empty_size;
unsigned long start, end, addr, size, empty_size;
BoundEntry *page, *e, *e2;
size_t t1_start, t1_end, t2_start, t2_end, i;
int t1_start, t1_end, t2_start, t2_end, i;
dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__);
__bound_init();
start = (size_t)p;
start = (unsigned long)p;
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
@ -640,7 +570,7 @@ int __bound_delete_region(void *p)
if (addr > e->size)
e = __bound_find_region(e, p);
/* test if invalid region */
if (e->size == EMPTY_SIZE || (size_t)p != e->start)
if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
return -1;
/* compute the size we put in invalid regions */
if (e->is_invalid)
@ -694,17 +624,14 @@ int __bound_delete_region(void *p)
}
delete_region(e, p, empty_size);
}
dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__);
return 0;
}
/* return the size of the region starting at p, or EMPTY_SIZE if non
existent region. */
static size_t get_region_size(void *p)
existant region. */
static unsigned long get_region_size(void *p)
{
size_t addr = (size_t)p;
unsigned long addr = (unsigned long)p;
BoundEntry *e;
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
@ -714,7 +641,7 @@ static size_t get_region_size(void *p)
addr -= e->start;
if (addr > e->size)
e = __bound_find_region(e, p);
if (e->start != (size_t)p)
if (e->start != (unsigned long)p)
return EMPTY_SIZE;
return e->size;
}
@ -782,10 +709,6 @@ void *__bound_malloc(size_t size, const void *caller)
if (!ptr)
return NULL;
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
__FILE__, __FUNCTION__, ptr, (unsigned)size);
__bound_new_region(ptr, size);
return ptr;
}
@ -815,10 +738,6 @@ void *__bound_memalign(size_t size, size_t align, const void *caller)
if (!ptr)
return NULL;
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %x)\n",
__FILE__, __FUNCTION__, ptr, (unsigned)size);
__bound_new_region(ptr, size);
return ptr;
}
@ -836,7 +755,7 @@ void __bound_free(void *ptr, const void *caller)
void *__bound_realloc(void *ptr, size_t size, const void *caller)
{
void *ptr1;
size_t old_size;
int old_size;
if (size == 0) {
__bound_free(ptr, caller);
@ -871,23 +790,23 @@ void *__bound_calloc(size_t nmemb, size_t size)
static void bound_dump(void)
{
BoundEntry *page, *e;
size_t i, j;
int i, j;
fprintf(stderr, "region dump:\n");
printf("region dump:\n");
for(i=0;i<BOUND_T1_SIZE;i++) {
page = __bound_t1[i];
for(j=0;j<BOUND_T2_SIZE;j++) {
e = page + j;
/* do not print invalid or empty entries */
if (e->size != EMPTY_SIZE && e->start != 0) {
fprintf(stderr, "%08x:",
printf("%08x:",
(i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
(j << BOUND_T3_BITS));
do {
fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size);
printf(" %08lx:%08lx", e->start, e->start + e->size);
e = e->next;
} while (e != NULL);
fprintf(stderr, "\n");
printf("\n");
}
}
}
@ -901,28 +820,19 @@ static void __bound_check(const void *p, size_t size)
{
if (size == 0)
return;
p = __bound_ptr_add((void *)p, size - 1);
p = __bound_ptr_add((void *)p, size);
if (p == INVALID_POINTER)
bound_error("invalid pointer");
}
void *__bound_memcpy(void *dst, const void *src, size_t size)
{
void* p;
dprintf(stderr, "%s %s: start, dst=%p src=%p size=%x\n",
__FILE__, __FUNCTION__, dst, src, (unsigned)size);
__bound_check(dst, size);
__bound_check(src, size);
/* check also region overlap */
if (src >= dst && src < dst + size)
bound_error("overlapping regions in memcpy()");
p = memcpy(dst, src, size);
dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p);
return p;
return memcpy(dst, src, size);
}
void *__bound_memmove(void *dst, const void *src, size_t size)
@ -942,7 +852,7 @@ void *__bound_memset(void *dst, int c, size_t size)
int __bound_strlen(const char *s)
{
const char *p;
size_t len;
int len;
len = 0;
for(;;) {
@ -958,14 +868,8 @@ int __bound_strlen(const char *s)
char *__bound_strcpy(char *dst, const char *src)
{
size_t len;
void *p;
dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n",
__FILE__, __FUNCTION__, dst, src);
int len;
len = __bound_strlen(src);
p = __bound_memcpy(dst, src, len + 1);
dprintf(stderr, "%s %s: strcpy end, p = %p\n",
__FILE__, __FUNCTION__, p);
return p;
return __bound_memcpy(dst, src, len + 1);
}

View File

@ -1,664 +0,0 @@
/*
* TCC runtime library for arm64.
*
* Copyright (c) 2015 Edmund Grimley Evans
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*/
#ifdef __TINYC__
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
void *memcpy(void*,void*,__SIZE_TYPE__);
#else
#include <stdint.h>
#include <string.h>
#endif
void __clear_cache(void *beg, void *end)
{
__arm64_clear_cache(beg, end);
}
typedef struct {
uint64_t x0, x1;
} u128_t;
static long double f3_zero(int sgn)
{
long double f;
u128_t x = { 0, (uint64_t)sgn << 63 };
memcpy(&f, &x, 16);
return f;
}
static long double f3_infinity(int sgn)
{
long double f;
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
memcpy(&f, &x, 16);
return f;
}
static long double f3_NaN(void)
{
long double f;
#if 0
// ARM's default NaN usually has just the top fraction bit set:
u128_t x = { 0, 0x7fff800000000000 };
#else
// GCC's library sets all fraction bits:
u128_t x = { -1, 0x7fffffffffffffff };
#endif
memcpy(&f, &x, 16);
return f;
}
static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
{
u128_t x = { mnt.x0,
mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
memcpy(f, &x, 16);
return 1;
}
static int fp3_detect_NaNs(long double *f,
int a_sgn, int a_exp, u128_t a,
int b_sgn, int b_exp, u128_t b)
{
// Detect signalling NaNs:
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
return fp3_convert_NaN(f, a_sgn, a);
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
return fp3_convert_NaN(f, b_sgn, b);
// Detect quiet NaNs:
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
return fp3_convert_NaN(f, a_sgn, a);
if (b_exp == 32767 && (b.x0 | b.x1 << 16))
return fp3_convert_NaN(f, b_sgn, b);
return 0;
}
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
{
u128_t x;
memcpy(&x, &f, 16);
*sgn = x.x1 >> 63;
*exp = x.x1 >> 48 & 32767;
x.x1 = x.x1 << 16 >> 16;
if (*exp)
x.x1 |= (uint64_t)1 << 48;
else
*exp = 1;
*mnt = x;
}
static u128_t f3_normalise(int32_t *exp, u128_t mnt)
{
int sh;
if (!(mnt.x0 | mnt.x1))
return mnt;
if (!mnt.x1) {
mnt.x1 = mnt.x0;
mnt.x0 = 0;
*exp -= 64;
}
for (sh = 32; sh; sh >>= 1) {
if (!(mnt.x1 >> (64 - sh))) {
mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh);
mnt.x0 = mnt.x0 << sh;
*exp -= sh;
}
}
return mnt;
}
static u128_t f3_sticky_shift(int32_t sh, u128_t x)
{
if (sh >= 128) {
x.x0 = !!(x.x0 | x.x1);
x.x1 = 0;
return x;
}
if (sh >= 64) {
x.x0 = x.x1 | !!x.x0;
x.x1 = 0;
sh -= 64;
}
if (sh > 0) {
x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh));
x.x1 = x.x1 >> sh;
}
return x;
}
static long double f3_round(int sgn, int32_t exp, u128_t x)
{
long double f;
int error;
if (exp > 0) {
x = f3_sticky_shift(13, x);
}
else {
x = f3_sticky_shift(14 - exp, x);
exp = 0;
}
error = x.x0 & 3;
x.x0 = x.x0 >> 2 | x.x1 << 62;
x.x1 = x.x1 >> 2;
if (error == 3 || ((error == 2) & (x.x0 & 1))) {
if (!++x.x0) {
++x.x1;
if (x.x1 == (uint64_t)1 << 48)
exp = 1;
else if (x.x1 == (uint64_t)1 << 49) {
++exp;
x.x0 = x.x0 >> 1 | x.x1 << 63;
x.x1 = x.x1 >> 1;
}
}
}
if (exp >= 32767)
return f3_infinity(sgn);
x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
memcpy(&f, &x, 16);
return f;
}
static long double f3_add(long double fa, long double fb, int neg)
{
u128_t a, b, x;
int32_t a_exp, b_exp, x_exp;
int a_sgn, b_sgn, x_sgn;
long double fx;
f3_unpack(&a_sgn, &a_exp, &a, fa);
f3_unpack(&b_sgn, &b_exp, &b, fb);
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
return fx;
b_sgn ^= neg;
// Handle infinities and zeroes:
if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn)
return f3_NaN();
if (a_exp == 32767)
return f3_infinity(a_sgn);
if (b_exp == 32767)
return f3_infinity(b_sgn);
if (!(a.x0 | a.x1 | b.x0 | b.x1))
return f3_zero(a_sgn & b_sgn);
a.x1 = a.x1 << 3 | a.x0 >> 61;
a.x0 = a.x0 << 3;
b.x1 = b.x1 << 3 | b.x0 >> 61;
b.x0 = b.x0 << 3;
if (a_exp <= b_exp) {
a = f3_sticky_shift(b_exp - a_exp, a);
a_exp = b_exp;
}
else {
b = f3_sticky_shift(a_exp - b_exp, b);
b_exp = a_exp;
}
x_sgn = a_sgn;
x_exp = a_exp;
if (a_sgn == b_sgn) {
x.x0 = a.x0 + b.x0;
x.x1 = a.x1 + b.x1 + (x.x0 < a.x0);
}
else {
x.x0 = a.x0 - b.x0;
x.x1 = a.x1 - b.x1 - (x.x0 > a.x0);
if (x.x1 >> 63) {
x_sgn ^= 1;
x.x0 = -x.x0;
x.x1 = -x.x1 - !!x.x0;
}
}
if (!(x.x0 | x.x1))
return f3_zero(0);
x = f3_normalise(&x_exp, x);
return f3_round(x_sgn, x_exp + 12, x);
}
long double __addtf3(long double a, long double b)
{
return f3_add(a, b, 0);
}
long double __subtf3(long double a, long double b)
{
return f3_add(a, b, 1);
}
long double __multf3(long double fa, long double fb)
{
u128_t a, b, x;
int32_t a_exp, b_exp, x_exp;
int a_sgn, b_sgn, x_sgn;
long double fx;
f3_unpack(&a_sgn, &a_exp, &a, fa);
f3_unpack(&b_sgn, &b_exp, &b, fb);
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
return fx;
// Handle infinities and zeroes:
if ((a_exp == 32767 && !(b.x0 | b.x1)) ||
(b_exp == 32767 && !(a.x0 | a.x1)))
return f3_NaN();
if (a_exp == 32767 || b_exp == 32767)
return f3_infinity(a_sgn ^ b_sgn);
if (!(a.x0 | a.x1) || !(b.x0 | b.x1))
return f3_zero(a_sgn ^ b_sgn);
a = f3_normalise(&a_exp, a);
b = f3_normalise(&b_exp, b);
x_sgn = a_sgn ^ b_sgn;
x_exp = a_exp + b_exp - 16352;
{
// Convert to base (1 << 30), discarding bottom 6 bits, which are zero,
// so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0):
uint64_t a0 = a.x0 << 28 >> 34;
uint64_t b0 = b.x0 << 28 >> 34;
uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34;
uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34;
uint64_t a2 = a.x1 << 32 >> 34;
uint64_t b2 = b.x1 << 32 >> 34;
uint64_t a3 = a.x1 >> 32;
uint64_t b3 = b.x1 >> 32;
// Use 16 small multiplications and additions that do not overflow:
uint64_t x0 = a0 * b0;
uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0;
uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0;
uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1;
uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2;
uint64_t x6 = (x5 >> 30) + a3 * b3;
// We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...).
// Take the top 128 bits, setting bottom bit if any lower bits were set:
uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 |
!!(x3 << 38 | (x2 | x1 | x0) << 34));
uint64_t y1 = x6;
// Top bit may be zero. Renormalise:
if (!(y1 >> 63)) {
y1 = y1 << 1 | y0 >> 63;
y0 = y0 << 1;
--x_exp;
}
x.x0 = y0;
x.x1 = y1;
}
return f3_round(x_sgn, x_exp, x);
}
long double __divtf3(long double fa, long double fb)
{
u128_t a, b, x;
int32_t a_exp, b_exp, x_exp;
int a_sgn, b_sgn, x_sgn, i;
long double fx;
f3_unpack(&a_sgn, &a_exp, &a, fa);
f3_unpack(&b_sgn, &b_exp, &b, fb);
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
return fx;
// Handle infinities and zeroes:
if ((a_exp == 32767 && b_exp == 32767) ||
(!(a.x0 | a.x1) && !(b.x0 | b.x1)))
return f3_NaN();
if (a_exp == 32767 || !(b.x0 | b.x1))
return f3_infinity(a_sgn ^ b_sgn);
if (!(a.x0 | a.x1) || b_exp == 32767)
return f3_zero(a_sgn ^ b_sgn);
a = f3_normalise(&a_exp, a);
b = f3_normalise(&b_exp, b);
x_sgn = a_sgn ^ b_sgn;
x_exp = a_exp - b_exp + 16395;
a.x0 = a.x0 >> 1 | a.x1 << 63;
a.x1 = a.x1 >> 1;
b.x0 = b.x0 >> 1 | b.x1 << 63;
b.x1 = b.x1 >> 1;
x.x0 = 0;
x.x1 = 0;
for (i = 0; i < 116; i++) {
x.x1 = x.x1 << 1 | x.x0 >> 63;
x.x0 = x.x0 << 1;
if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) {
a.x1 = a.x1 - b.x1 - (a.x0 < b.x0);
a.x0 = a.x0 - b.x0;
x.x0 |= 1;
}
a.x1 = a.x1 << 1 | a.x0 >> 63;
a.x0 = a.x0 << 1;
}
x.x0 |= !!(a.x0 | a.x1);
x = f3_normalise(&x_exp, x);
return f3_round(x_sgn, x_exp, x);
}
long double __extendsftf2(float f)
{
long double fx;
u128_t x;
uint32_t a;
uint64_t aa;
memcpy(&a, &f, 4);
aa = a;
x.x0 = 0;
if (!(a << 1))
x.x1 = aa << 32;
else if (a << 1 >> 24 == 255)
x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
(uint64_t)!!(a << 9) << 47);
else
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
aa << 41 >> 16);
memcpy(&fx, &x, 16);
return fx;
}
long double __extenddftf2(double f)
{
long double fx;
u128_t x;
uint64_t a;
memcpy(&a, &f, 8);
x.x0 = a << 60;
if (!(a << 1))
x.x1 = a;
else if (a << 1 >> 53 == 2047)
x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
(uint64_t)!!(a << 12) << 47);
else
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
memcpy(&fx, &x, 16);
return fx;
}
float __trunctfsf2(long double f)
{
u128_t mnt;
int32_t exp;
int sgn;
uint32_t x;
float fx;
f3_unpack(&sgn, &exp, &mnt, f);
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
else if (exp > 16510)
x = 0x7f800000 | (uint32_t)sgn << 31;
else if (exp < 16233)
x = (uint32_t)sgn << 31;
else {
exp -= 16257;
x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41);
if (exp < 0) {
x = x >> -exp | !!(x << (32 + exp));
exp = 0;
}
if ((x & 3) == 3 || (x & 7) == 6)
x += 4;
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
}
memcpy(&fx, &x, 4);
return fx;
}
double __trunctfdf2(long double f)
{
u128_t mnt;
int32_t exp;
int sgn;
uint64_t x;
double fx;
f3_unpack(&sgn, &exp, &mnt, f);
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
else if (exp > 17406)
x = 0x7ff0000000000000 | (uint64_t)sgn << 63;
else if (exp < 15308)
x = (uint64_t)sgn << 63;
else {
exp -= 15361;
x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6);
if (exp < 0) {
x = x >> -exp | !!(x << (64 + exp));
exp = 0;
}
if ((x & 3) == 3 || (x & 7) == 6)
x += 4;
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
}
memcpy(&fx, &x, 8);
return fx;
}
int32_t __fixtfsi(long double fa)
{
u128_t a;
int32_t a_exp;
int a_sgn;
int32_t x;
f3_unpack(&a_sgn, &a_exp, &a, fa);
if (a_exp < 16369)
return 0;
if (a_exp > 16413)
return a_sgn ? -0x80000000 : 0x7fffffff;
x = a.x1 >> (16431 - a_exp);
return a_sgn ? -x : x;
}
int64_t __fixtfdi(long double fa)
{
u128_t a;
int32_t a_exp;
int a_sgn;
int64_t x;
f3_unpack(&a_sgn, &a_exp, &a, fa);
if (a_exp < 16383)
return 0;
if (a_exp > 16445)
return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff;
x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
return a_sgn ? -x : x;
}
uint32_t __fixunstfsi(long double fa)
{
u128_t a;
int32_t a_exp;
int a_sgn;
f3_unpack(&a_sgn, &a_exp, &a, fa);
if (a_sgn || a_exp < 16369)
return 0;
if (a_exp > 16414)
return -1;
return a.x1 >> (16431 - a_exp);
}
uint64_t __fixunstfdi(long double fa)
{
u128_t a;
int32_t a_exp;
int a_sgn;
f3_unpack(&a_sgn, &a_exp, &a, fa);
if (a_sgn || a_exp < 16383)
return 0;
if (a_exp > 16446)
return -1;
return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
}
long double __floatsitf(int32_t a)
{
int sgn = 0;
int exp = 16414;
uint32_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
if (a < 0) {
sgn = 1;
mnt = -mnt;
}
for (i = 16; i; i >>= 1)
if (!(mnt >> (32 - i))) {
mnt <<= i;
exp -= i;
}
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
(uint64_t)(mnt << 1) << 16);
}
memcpy(&f, &x, 16);
return f;
}
long double __floatditf(int64_t a)
{
int sgn = 0;
int exp = 16446;
uint64_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
if (a < 0) {
sgn = 1;
mnt = -mnt;
}
for (i = 32; i; i >>= 1)
if (!(mnt >> (64 - i))) {
mnt <<= i;
exp -= i;
}
x.x0 = mnt << 49;
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
}
memcpy(&f, &x, 16);
return f;
}
long double __floatunsitf(uint32_t a)
{
int exp = 16414;
uint32_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
for (i = 16; i; i >>= 1)
if (!(mnt >> (32 - i))) {
mnt <<= i;
exp -= i;
}
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
}
memcpy(&f, &x, 16);
return f;
}
long double __floatunditf(uint64_t a)
{
int exp = 16446;
uint64_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
for (i = 32; i; i >>= 1)
if (!(mnt >> (64 - i))) {
mnt <<= i;
exp -= i;
}
x.x0 = mnt << 49;
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
}
memcpy(&f, &x, 16);
return f;
}
static int f3_cmp(long double fa, long double fb)
{
u128_t a, b;
memcpy(&a, &fa, 16);
memcpy(&b, &fb, 16);
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) :
a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 :
a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) :
a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 :
b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0);
}
int __eqtf2(long double a, long double b)
{
return !!f3_cmp(a, b);
}
int __netf2(long double a, long double b)
{
return !!f3_cmp(a, b);
}
int __lttf2(long double a, long double b)
{
return f3_cmp(a, b);
}
int __letf2(long double a, long double b)
{
return f3_cmp(a, b);
}
int __gttf2(long double a, long double b)
{
return -f3_cmp(b, a);
}
int __getf2(long double a, long double b)
{
return -f3_cmp(b, a);
}

View File

@ -103,14 +103,14 @@ union double_long {
union float_long {
float f;
unsigned int l;
long l;
};
/* XXX: we don't support several builtin supports for now */
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
#ifndef __x86_64__
/* 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,6 +478,13 @@ long long __ashldi3(long long a, int b)
#endif
}
#if defined(__i386__)
/* FPU control word for rounding to nearest mode */
unsigned short __tcc_fpu_control = 0x137f;
/* FPU control word for round to zero mode for int conversion */
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
#endif
#endif /* !__x86_64__ */
/* XXX: fix tcc's code generator to do this instead */
@ -598,50 +605,22 @@ 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;
}
#if defined(__x86_64__) && !defined(_WIN64)
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)
/* helper functions for stdarg.h */
#include <stdlib.h>
#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);
/* gives "incompatible types for redefinition of __va_arg" below */
#include <stdio.h>
#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 {
struct __va_list_struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
@ -649,28 +628,30 @@ typedef struct {
char *overflow_arg_area;
};
char *reg_save_area;
} __va_list_struct;
};
void __va_start(__va_list_struct *ap, void *fp)
void *__va_start(void *fp)
{
memset(ap, 0, sizeof(__va_list_struct));
*ap = *(__va_list_struct *)((char *)fp - 16);
struct __va_list_struct *ap =
(struct __va_list_struct *)malloc(sizeof(struct __va_list_struct));
*ap = *(struct __va_list_struct *)((char *)fp - 16);
ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
ap->reg_save_area = (char *)fp - 176 - 16;
return ap;
}
void *__va_arg(__va_list_struct *ap,
void *__va_arg(struct __va_list_struct *ap,
enum __va_arg_type arg_type,
int size, int align)
int size)
{
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;
if (ap->gp_offset < 48) {
ap->gp_offset += 8;
return ap->reg_save_area + ap->gp_offset - 8;
}
size = 8;
goto use_overflow_area;
case __va_float_reg:
@ -684,35 +665,27 @@ void *__va_arg(__va_list_struct *ap,
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 */
default:
#ifndef __TINYC__
fprintf(stderr, "unknown ABI type for __va_arg\n");
#endif
abort();
}
}
#endif /* __x86_64__ */
#if defined TCC_TARGET_ARM && !defined __TINYC__
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
/* Flushing for tccrun */
void __clear_cache(void *beginning, void *end)
void *__va_copy(struct __va_list_struct *src)
{
/* __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
struct __va_list_struct *dest =
(struct __va_list_struct *)malloc(sizeof(struct __va_list_struct));
*dest = *src;
return dest;
}
#endif /* arm */
void __va_end(struct __va_list_struct *ap)
{
free(ap);
}
#endif /* __x86_64__ */

1628
libtcc.c

File diff suppressed because it is too large Load Diff

View File

@ -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 void tcc_set_options(TCCState *s, const char *str);
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
/*****************************/
/* preprocessor */
@ -58,11 +58,11 @@ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
/* set output type. MUST BE CALLED before any compilation */
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */
#define TCC_OUTPUT_EXE 2 /* executable file */
#define TCC_OUTPUT_DLL 3 /* dynamic library */
#define TCC_OUTPUT_OBJ 4 /* object file */
#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */
#define TCC_OUTPUT_MEMORY 0 /* output will be run in memory (default) */
#define TCC_OUTPUT_EXE 1 /* executable file */
#define TCC_OUTPUT_DLL 2 /* dynamic library */
#define TCC_OUTPUT_OBJ 3 /* object file */
#define TCC_OUTPUT_PREPROCESS 4 /* only preprocess (used internally) */
/* equivalent to -Lpath option */
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);

View File

@ -176,15 +176,22 @@ In a script, it gives the following header:
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
@end example
@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. -vvv shows tries too.
Show included files. As sole argument, print search dirs (as below).
@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:
@ -206,15 +213,11 @@ 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:
Note: each of the following options has a negative form beginning with
Note: each of the following warning options has a negative form beginning with
@option{-fno-}.
@table @option
@ -230,14 +233,6 @@ Do not generate common symbols for uninitialized data.
@item -fleading-underscore
Add a leading underscore at the beginning of each C symbol.
@item -fms-extensions
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.
@item -fdollars-in-identifiers
Allow dollar signs in identifiers
@end table
Warning options:
@ -281,7 +276,7 @@ default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}
@item -lxxx
Link your program with dynamic library libxxx.so or static library
libxxx.a. The library is searched in the paths specified by the
@option{-L} option and @env{LIBRARY_PATH} variable.
@option{-L} option.
@item -Bdir
Set the path where the tcc internal libraries (and include files) can be
@ -305,11 +300,7 @@ opened with @code{dlopen()} needs to access executable symbols.
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.
Put custom seatch path for dynamic libraries into executable.
@item -Wl,--oformat=fmt
Use @var{fmt} as output format. The supported output formats are:
@ -331,9 +322,6 @@ 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:
@ -350,7 +338,7 @@ Generate additional support code to check
memory allocations and array/pointer bounds. @option{-g} is implied. Note
that the generated code is slower and bigger in this case.
Note: @option{-b} is only available on i386 when using libtcc for the moment.
Note: @option{-b} is only available on i386 for the moment.
@item -bt N
Display N callers in stack traces. This is useful with @option{-g} or
@ -367,62 +355,18 @@ 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
ignored.
@c man end
@c man begin ENVIRONMENT
Environment variables that affect how tcc operates.
@table @option
@item CPATH
@item C_INCLUDE_PATH
A colon-separated list of directories searched for include files,
directories given with @option{-I} are searched first.
@item LIBRARY_PATH
A colon-separated list of directories searched for libraries for the
@option{-l} option, directories given with @option{-L} are searched first.
@end table
@c man end
@ignore
@setfilename tcc
@settitle Tiny C Compiler
@c man begin SEEALSO
cpp(1),
gcc(1)
@c man end
@ -444,14 +388,13 @@ and floating point numbers (@code{long double}, @code{double}, and
@section ISOC99 extensions
TCC implements many features of the new C standard: ISO C99. Currently
missing items are: complex and imaginary numbers.
missing items are: complex and imaginary numbers and variable length
arrays.
Currently implemented ISOC99 features:
@itemize
@item variable length arrays.
@item 64 bit @code{long long} types are fully supported.
@item The boolean type @code{_Bool} is supported.
@ -653,7 +596,8 @@ are supported.
@itemize
@item @code{__TINYC__} is a predefined macro to indicate that you use TCC.
@item @code{__TINYC__} is a predefined macro to @code{1} to
indicate that you use TCC.
@item @code{#!} at the start of a line is ignored to allow scripting.
@ -758,7 +702,7 @@ They can be defined several times in the same source. Use 'b'
@cindex asciz directive
@cindex ascii directive
All directives are preceded by a '.'. The following directives are
All directives are preceeded by a '.'. The following directives are
supported:
@itemize
@ -977,7 +921,7 @@ reverse order, a first pass is done to reverse the argument order.
@section Types
The types are stored in a single 'int' variable. It was chosen in the
The types are stored in a single 'int' variable. It was choosen in the
first stages of development when tcc was much simpler. Now, it may not
be the best solution.
@ -1004,7 +948,7 @@ be the best solution.
#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_SIGNED 0x2000 /* signed type */
#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
@end example
@ -1114,7 +1058,7 @@ are used when bound checking is activated
@item stab_section
@itemx stabstr_section
are used when debugging is active to store debug information
are used when debugging is actived to store debug information
@item symtab_section
@itemx strtab_section
@ -1214,10 +1158,8 @@ 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.
@item VT_LLOCAL
is a saved lvalue on the stack. @code{VT_LVAL} must also be set with
@code{VT_LLOCAL}. @code{VT_LLOCAL} can arise when a @code{VT_LVAL} in
a register has to be saved to the stack, or it can come from an
architecture-specific calling convention.
is a saved lvalue on the stack. @code{VT_LLOCAL} should be eliminated
ASAP because its semantics are rather complicated.
@item VT_MUSTCAST
indicates that a cast to the value type must be performed if the value

498
tcc.c
View File

@ -23,187 +23,131 @@
#else
#include "tcc.h"
#endif
#include "tcctools.c"
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"
static void help(void)
{
printf("tcc version " TCC_VERSION " - Tiny C Compiler - 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"
" -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"
"Preprocessor options:\n"
" -E preprocess only\n"
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\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"
" -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
#ifdef CONFIG_TCC_BACKTRACE
" -bt N show N callers in stack traces\n"
" -bt N 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
;
"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"
);
}
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"
" -iwithprefix dir set tcc's private include/library subdir\n"
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\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"
/* 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)
{
int ret = spawnvp(P_NOWAIT, prog, (char const*const*)argv);
if (-1 == ret)
return ret;
cwait(&ret, ret, WAIT_CHILD);
exit(ret);
}
#define execvp execvp_win32
#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 seach 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" ("
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
"i386"
#elif defined TCC_TARGET_X86_64
"x86_64"
#elif defined TCC_TARGET_C67
"C67"
#elif defined TCC_TARGET_ARM
"ARM"
#elif defined TCC_TARGET_ARM64
"AArch64"
#endif
#ifdef TCC_ARM_HARDFLOAT
" Hard Float"
#endif
#ifdef TCC_TARGET_PE
" Windows"
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
" FreeBSD"
case 32: break;
case 64: target = "x86_64";
#else
" Linux"
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");
#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
")\n"
;
static void print_dirs(const char *msg, char **paths, int nb_paths)
static void gen_makedeps(TCCState *s, const char *target, const char *filename)
{
FILE *depout;
char buf[1024], *ext;
int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
for(i = 0; i < nb_paths; i++)
printf(" %s\n", paths[i]);
}
static void print_search_dirs(TCCState *s)
{
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);
#ifndef TCC_TARGET_PE
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
}
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;
}
static void set_environment(TCCState *s)
{
char * path;
if (s->verbose)
printf("<- %s\n", filename);
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);
}
/* 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)
@ -214,7 +158,7 @@ static char *default_outputfile(TCCState *s, const char *first_file)
if (first_file && strcmp(first_file, "-"))
name = tcc_basename(first_file);
snprintf(buf, sizeof(buf), "%s", name);
pstrcpy(buf, sizeof(buf), name);
ext = tcc_fileextension(buf);
#ifdef TCC_TARGET_PE
if (s->output_type == TCC_OUTPUT_DLL)
@ -224,135 +168,185 @@ static char *default_outputfile(TCCState *s, const char *first_file)
strcpy(ext, ".exe");
else
#endif
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r && *ext)
if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) ||
(s->output_type == TCC_OUTPUT_PREPROCESS) )
&& *ext)
strcpy(ext, ".o");
else
strcpy(buf, "a.out");
return tcc_strdup(buf);
}
static unsigned getclock_ms(void)
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 void display_info(TCCState *s, int what)
{
switch (what) {
case 0:
printf("tcc version %s ("
#ifdef TCC_TARGET_I386
"i386"
# ifdef TCC_TARGET_PE
" Win32"
# endif
#elif defined TCC_TARGET_X86_64
"x86-64"
# ifdef TCC_TARGET_PE
" Win64"
# endif
#elif defined TCC_TARGET_ARM
"ARM"
# ifdef TCC_ARM_HARDFLOAT
" Hard Float"
# endif
# ifdef TCC_TARGET_PE
" WinCE"
# endif
#endif
#ifndef TCC_TARGET_PE
# ifdef __linux
" Linux"
# endif
#endif
")\n", TCC_VERSION);
break;
case 1:
printf("install: %s/\n", s->tcc_lib_path);
/* print_paths("programs", NULL, 0); */
print_paths("crt", s->crt_paths, s->nb_crt_paths);
print_paths("libraries", s->library_paths, s->nb_library_paths);
print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
printf("elfinterp:\n %s\n", CONFIG_TCC_ELFINTERP);
break;
}
}
static int64_t getclock_us(void)
{
#ifdef _WIN32
return GetTickCount();
struct _timeb tb;
_ftime(&tb);
return (tb.time * 1000LL + tb.millitm) * 1000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
return tv.tv_sec * 1000000LL + tv.tv_usec;
#endif
}
int main(int argc, char **argv)
{
TCCState *s;
int ret, opt, n = 0;
unsigned start_time = 0;
const char *first_file;
int ret, optind, i, bench;
int64_t start_time = 0;
const char *first_file = NULL;
redo:
s = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
s->output_type = TCC_OUTPUT_EXE;
if (n == 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 */
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
print_search_dirs(s);
return 0;
}
optind = tcc_parse_args(s, argc - 1, argv + 1);
n = s->nb_files;
if (n == 0)
tcc_error("no input files\n");
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 && !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");
}
if (s->do_bench)
start_time = getclock_ms();
if (optind == 0) {
help();
return 1;
}
set_environment(s);
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
if (s->option_m)
exec_other_tcc(s, argv, s->option_m);
if (s->verbose)
display_info(s, 0);
if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) {
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
display_info(s, 1);
return 0;
}
if (s->verbose && optind == 1)
return 0;
if (s->nb_files == 0)
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->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);
}
}
bench = s->do_bench;
if (bench)
start_time = getclock_us();
tcc_set_output_type(s, s->output_type);
/* compile or add each files or library */
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)
for(i = ret = 0; i < s->nb_files && ret == 0; i++) {
const char *filename;
filename = s->files[i];
if (filename[0] == '-' && filename[1] == 'l') {
if (tcc_add_library(s, filename + 2) < 0) {
tcc_error_noabort("cannot find '%s'", filename);
ret = 1;
}
} else {
if (1 == s->verbose)
printf("-> %s\n", f->name);
if (!first_file)
first_file = f->name;
if (tcc_add_file(s, f->name) < 0)
printf("-> %s\n", filename);
if (tcc_add_file(s, filename) < 0)
ret = 1;
if (!first_file)
first_file = filename;
}
s->filetype = 0;
s->alacarte_link = 1;
if (ret || --n == 0
|| (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
break;
}
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->ppfp);
} else if (0 == ret) {
if (0 == ret) {
if (bench)
tcc_print_stats(s, getclock_us() - start_time);
if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE
ret = tcc_run(s, argc, argv);
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
#else
tcc_error_noabort("-run is not available in a cross compiler");
ret = 1;
#endif
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->ppfp);
} else {
if (!s->outfile)
s->outfile = default_outputfile(s, first_file);
if (tcc_output_file(s, s->outfile))
ret = 1;
else if (s->gen_deps)
ret = !!tcc_output_file(s, s->outfile);
/* dump collected dependencies */
if (s->gen_deps && !ret)
gen_makedeps(s, s->outfile, s->deps_outfile);
}
}
if (s->do_bench && ret == 0 && n == 0)
tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s);
if (ret == 0 && n)
goto redo; /* compile more files with -c */
if (bench)
tcc_memstats();
return ret;
}

935
tcc.h

File diff suppressed because it is too large Load Diff

538
tccasm.c
View File

@ -32,53 +32,6 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
}
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
static Sym sym_dot;
/* 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. */
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
{
Sym *sym = 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;
}
}
return sym;
}
/* We do not use the C expression parser to handle symbols. Maybe the
C expression parser could be tweaked to do so. */
@ -86,13 +39,12 @@ ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
static void asm_expr_unary(TCCState *s1, ExprValue *pe)
{
Sym *sym;
int op, label;
unsigned long n;
int op, n, label;
const char *p;
switch(tok) {
case TOK_PPNUM:
p = tokc.str.data;
p = tokc.cstr->data;
n = strtoul(p, (char **)&p, 0);
if (*p == 'b' || *p == 'f') {
/* backward or forward label */
@ -109,16 +61,14 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
if (!sym || sym->r) {
/* 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->type.t = VT_STATIC | VT_VOID;
}
}
pe->v = 0;
pe->sym = sym;
pe->pcrel = 0;
pe->v = 0;
pe->sym = sym;
} else if (*p == '\0') {
pe->v = n;
pe->sym = NULL;
pe->pcrel = 0;
} else {
tcc_error("invalid number syntax");
}
@ -144,7 +94,6 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
case TOK_LCHAR:
pe->v = tokc.i;
pe->sym = NULL;
pe->pcrel = 0;
next();
break;
case '(':
@ -152,28 +101,22 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
asm_expr(s1, 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;
next();
break;
default:
if (tok >= TOK_IDENT) {
/* label case : if the label was not found, add one */
sym = get_asm_sym(tok, NULL);
sym = label_find(tok);
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
/* NOTE: by default, the symbol is global */
sym->type.t = VT_VOID;
}
if (sym->r == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
pe->v = sym->jnext;
pe->sym = NULL;
pe->pcrel = 0;
} else {
pe->v = 0;
pe->sym = sym;
pe->pcrel = 0;
}
next();
} else {
@ -276,21 +219,20 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
pe->v -= e2.v;
/* NOTE: we are less powerful than gas in that case
because we store only one symbol in the expression */
if (!e2.sym) {
/* OK */
} 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;
if (!pe->sym && !e2.sym) {
/* OK */
} else if (pe->sym && !e2.sym) {
/* OK */
} else if (pe->sym && e2.sym) {
if (pe->sym == e2.sym) {
/* OK */
} else if (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;
} else {
goto cannot_relocate;
}
pe->sym = NULL; /* same symbols can be substracted to NULL */
} else {
cannot_relocate:
tcc_error("invalid operation with label");
@ -299,51 +241,9 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
}
}
static inline void asm_expr_cmp(TCCState *s1, ExprValue *pe)
{
int op;
ExprValue e2;
asm_expr_sum(s1, pe);
for(;;) {
op = tok;
if (op != TOK_EQ && op != TOK_NE
&& (op > TOK_GT || op < TOK_ULE))
break;
next();
asm_expr_sum(s1, &e2);
if (pe->sym || e2.sym)
tcc_error("invalid operation with label");
switch(op) {
case TOK_EQ:
pe->v = pe->v == e2.v;
break;
case TOK_NE:
pe->v = pe->v != e2.v;
break;
case TOK_LT:
pe->v = (int64_t)pe->v < (int64_t)e2.v;
break;
case TOK_GE:
pe->v = (int64_t)pe->v >= (int64_t)e2.v;
break;
case TOK_LE:
pe->v = (int64_t)pe->v <= (int64_t)e2.v;
break;
case TOK_GT:
pe->v = (int64_t)pe->v > (int64_t)e2.v;
break;
default:
break;
}
/* GAS compare results are -1/0 not 1/0. */
pe->v = -(int64_t)pe->v;
}
}
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe)
{
asm_expr_cmp(s1, pe);
asm_expr_sum(s1, pe);
}
ST_FUNC int asm_int_expr(TCCState *s1)
@ -357,17 +257,14 @@ ST_FUNC int asm_int_expr(TCCState *s1)
/* 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,
static void asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
sym = label_find(label);
if (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 (sym->r) {
/* the label is already defined */
if (!is_local) {
tcc_error("assembler label '%s' already defined",
@ -380,45 +277,26 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
} 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->type.t = VT_STATIC | VT_VOID;
}
sym->r = sh_num;
sym->jnext = value;
return sym;
}
static Sym* asm_new_label(TCCState *s1, int label, int is_local)
static void asm_new_label(TCCState *s1, int label, int is_local)
{
return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
}
/* Set the value of LABEL to that of some expression (possibly
involving other symbols). LABEL can be overwritten later still. */
static Sym* set_symbol(TCCState *s1, int label)
{
long n;
ExprValue e;
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);
asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
}
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) {
if (s->r == SHN_ABS)
sec = SECTION_ABS;
else
@ -446,47 +324,23 @@ static void use_section(TCCState *s1, const char *name)
use_section1(s1, sec);
}
static void push_section(TCCState *s1, const char *name)
{
Section *sec = find_section(s1, name);
sec->prev = cur_text_section;
use_section1(s1, sec);
}
static void pop_section(TCCState *s1)
{
Section *prev = cur_text_section->prev;
if (!prev)
tcc_error(".popsection without .pushsection");
cur_text_section->prev = NULL;
use_section1(s1, prev);
}
static void asm_parse_directive(TCCState *s1, int global)
static void asm_parse_directive(TCCState *s1)
{
int n, offset, v, size, tok1;
Section *sec;
uint8_t *ptr;
/* assembler directive */
next();
sec = cur_text_section;
switch(tok) {
case TOK_ASMDIR_align:
case TOK_ASMDIR_balign:
case TOK_ASMDIR_p2align:
case TOK_ASMDIR_skip:
case TOK_ASMDIR_space:
case TOK_ASM_align:
case TOK_ASM_skip:
case TOK_ASM_space:
tok1 = tok;
next();
n = asm_int_expr(s1);
if (tok1 == TOK_ASMDIR_p2align)
{
if (n < 0 || n > 30)
tcc_error("invalid p2align, must be between 0 and 30");
n = 1 << n;
tok1 = TOK_ASMDIR_align;
}
if (tok1 == TOK_ASMDIR_align || tok1 == TOK_ASMDIR_balign) {
if (tok1 == TOK_ASM_align) {
if (n < 0 || (n & (n-1)) != 0)
tcc_error("alignment must be a positive power of two");
offset = (ind + n - 1) & -n;
@ -495,8 +349,6 @@ static void asm_parse_directive(TCCState *s1, int global)
if (sec->sh_addralign < n)
sec->sh_addralign = n;
} else {
if (n < 0)
n = 0;
size = n;
}
v = 0;
@ -512,17 +364,13 @@ static void asm_parse_directive(TCCState *s1, int global)
}
ind += size;
break;
case TOK_ASMDIR_quad:
#ifdef TCC_TARGET_X86_64
size = 8;
goto asm_data;
#else
case TOK_ASM_quad:
next();
for(;;) {
uint64_t vl;
const char *p;
p = tokc.str.data;
p = tokc.cstr->data;
if (tok != TOK_PPNUM) {
error_constant:
tcc_error("64 bit constant");
@ -543,16 +391,15 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
}
break;
#endif
case TOK_ASMDIR_byte:
case TOK_ASM_byte:
size = 1;
goto asm_data;
case TOK_ASMDIR_word:
case TOK_ASMDIR_short:
case TOK_ASM_word:
case TOK_SHORT:
size = 2;
goto asm_data;
case TOK_ASMDIR_long:
case TOK_ASMDIR_int:
case TOK_LONG:
case TOK_INT:
size = 4;
asm_data:
next();
@ -562,10 +409,6 @@ static void asm_parse_directive(TCCState *s1, int global)
if (sec->sh_type != SHT_NOBITS) {
if (size == 4) {
gen_expr32(&e);
#ifdef TCC_TARGET_X86_64
} else if (size == 8) {
gen_expr64(&e);
#endif
} else {
if (e.sym)
expect("constant");
@ -582,7 +425,7 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
}
break;
case TOK_ASMDIR_fill:
case TOK_ASM_fill:
{
int repeat, size, val, i, j;
uint8_t repeat_buf[8];
@ -624,46 +467,12 @@ static void asm_parse_directive(TCCState *s1, int global)
}
}
break;
case TOK_ASMDIR_rept:
{
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)) {
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),
global);
macro_ptr = init_str->str;
}
end_macro();
restore_parse_state(&saved_parse_state);
break;
}
case TOK_ASMDIR_org:
case TOK_ASM_org:
{
unsigned long n;
ExprValue e;
next();
asm_expr(s1, &e);
n = e.v;
if (e.sym) {
if (e.sym->r != cur_text_section->sh_num)
expect("constant or same-section symbol");
n += e.sym->jnext;
}
/* XXX: handle section symbols too */
n = asm_int_expr(s1);
if (n < ind)
tcc_error("attempt to .org backwards");
v = 0;
@ -671,37 +480,28 @@ static void asm_parse_directive(TCCState *s1, int global)
goto zero_pad;
}
break;
case TOK_ASMDIR_set:
next();
tok1 = tok;
next();
/* Also accept '.set stuff', but don't do anything with this.
It's used in GAS to set various features like '.set mips16'. */
if (tok == ',')
set_symbol(s1, tok1);
break;
case TOK_ASMDIR_globl:
case TOK_ASMDIR_global:
case TOK_ASMDIR_weak:
case TOK_ASMDIR_hidden:
tok1 = tok;
case TOK_ASM_globl:
case TOK_ASM_global:
case TOK_ASM_weak:
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 = label_find(tok);
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID;
}
sym->type.t &= ~VT_STATIC;
if (tok1 == TOK_ASM_weak)
sym->type.t |= VT_WEAK;
else if (tok1 == TOK_ASMDIR_hidden)
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
next();
} while (tok == ',');
break;
case TOK_ASMDIR_string:
case TOK_ASMDIR_ascii:
case TOK_ASMDIR_asciz:
case TOK_ASM_string:
case TOK_ASM_ascii:
case TOK_ASM_asciz:
{
const uint8_t *p;
int i, size, t;
@ -711,9 +511,9 @@ static void asm_parse_directive(TCCState *s1, int global)
for(;;) {
if (tok != TOK_STR)
expect("string constant");
p = tokc.str.data;
size = tokc.str.size;
if (t == TOK_ASMDIR_ascii && size > 0)
p = tokc.cstr->data;
size = tokc.cstr->size;
if (t == TOK_ASM_ascii && size > 0)
size--;
for(i = 0; i < size; i++)
g(p[i]);
@ -726,9 +526,9 @@ static void asm_parse_directive(TCCState *s1, int global)
}
}
break;
case TOK_ASMDIR_text:
case TOK_ASMDIR_data:
case TOK_ASMDIR_bss:
case TOK_ASM_text:
case TOK_ASM_data:
case TOK_ASM_bss:
{
char sname[64];
tok1 = tok;
@ -738,14 +538,11 @@ static void asm_parse_directive(TCCState *s1, int global)
n = asm_int_expr(s1);
next();
}
if (n)
sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n);
else
sprintf(sname, "%s", get_tok_str(tok1, NULL));
sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n);
use_section(s1, sname);
}
break;
case TOK_ASMDIR_file:
case TOK_ASM_file:
{
char filename[512];
@ -753,7 +550,7 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
if (tok == TOK_STR)
pstrcat(filename, sizeof(filename), tokc.str.data);
pstrcat(filename, sizeof(filename), tokc.cstr->data);
else
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
@ -763,7 +560,7 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
}
break;
case TOK_ASMDIR_ident:
case TOK_ASM_ident:
{
char ident[256];
@ -771,7 +568,7 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
if (tok == TOK_STR)
pstrcat(ident, sizeof(ident), tokc.str.data);
pstrcat(ident, sizeof(ident), tokc.cstr->data);
else
pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL));
@ -781,7 +578,7 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
}
break;
case TOK_ASMDIR_size:
case TOK_ASM_size:
{
Sym *sym;
@ -791,36 +588,41 @@ static void asm_parse_directive(TCCState *s1, int global)
tcc_error("label not found: %s", get_tok_str(tok, NULL));
}
next();
skip(',');
/* XXX .size name,label2-label1 */
if (s1->warn_unsupported)
tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
next();
skip(',');
while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
while (tok != '\n' && tok != CH_EOF) {
next();
}
}
break;
case TOK_ASMDIR_type:
case TOK_ASM_type:
{
Sym *sym;
const char *newtype;
next();
sym = get_asm_sym(tok, NULL);
sym = label_find(tok);
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID;
}
next();
skip(',');
if (tok == TOK_STR) {
newtype = tokc.str.data;
newtype = tokc.cstr->data;
} else {
if (tok == '@' || tok == '%')
next();
skip(tok);
newtype = get_tok_str(tok, NULL);
}
if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC;
sym->type.t = VT_FUNC;
}
else if (s1->warn_unsupported)
tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
@ -829,19 +631,16 @@ static void asm_parse_directive(TCCState *s1, int global)
next();
}
break;
case TOK_ASMDIR_pushsection:
case TOK_ASMDIR_section:
case TOK_SECTION1:
{
char sname[256];
int old_nb_section = s1->nb_sections;
tok1 = tok;
/* XXX: support more options */
next();
sname[0] = '\0';
while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
if (tok == TOK_STR)
pstrcat(sname, sizeof(sname), tokc.str.data);
pstrcat(sname, sizeof(sname), tokc.cstr->data);
else
pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
next();
@ -852,26 +651,12 @@ static void asm_parse_directive(TCCState *s1, int global)
if (tok != TOK_STR)
expect("string constant");
next();
if (tok == ',') {
next();
if (tok == '@' || tok == '%')
next();
next();
}
}
last_text_section = cur_text_section;
if (tok1 == TOK_ASMDIR_section)
use_section(s1, sname);
else
push_section(s1, sname);
/* If we just allocated a new section reset its alignment to
1. new_section normally acts for GCC compatibility and
sets alignment to PTR_SIZE. The assembler behaves different. */
if (old_nb_section != s1->nb_sections)
cur_text_section->sh_addralign = 1;
use_section(s1, sname);
}
break;
case TOK_ASMDIR_previous:
case TOK_ASM_previous:
{
Section *sec;
next();
@ -882,18 +667,14 @@ static void asm_parse_directive(TCCState *s1, int global)
last_text_section = sec;
}
break;
case TOK_ASMDIR_popsection:
next();
pop_section(s1);
break;
#ifdef TCC_TARGET_I386
case TOK_ASMDIR_code16:
case TOK_ASM_code16:
{
next();
s1->seg_size = 16;
}
break;
case TOK_ASMDIR_code32:
case TOK_ASM_code32:
{
next();
s1->seg_size = 32;
@ -902,7 +683,7 @@ static void asm_parse_directive(TCCState *s1, int global)
#endif
#ifdef TCC_TARGET_X86_64
/* added for compatibility with GAS */
case TOK_ASMDIR_code64:
case TOK_ASM_code64:
next();
break;
#endif
@ -914,45 +695,70 @@ static void asm_parse_directive(TCCState *s1, int global)
/* assemble a file */
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
{
int opcode;
#if 0
/* print stats about opcodes */
{
const ASMInstr *pa;
int freq[4];
int op_vals[500];
int nb_op_vals, i, j;
nb_op_vals = 0;
memset(freq, 0, sizeof(freq));
for(pa = asm_instrs; pa->sym != 0; pa++) {
freq[pa->nb_ops]++;
for(i=0;i<pa->nb_ops;i++) {
for(j=0;j<nb_op_vals;j++) {
if (pa->op_type[i] == op_vals[j])
goto found;
}
op_vals[nb_op_vals++] = pa->op_type[i];
found: ;
}
}
for(i=0;i<nb_op_vals;i++) {
int v = op_vals[i];
if ((v & (v - 1)) != 0)
printf("%3d: %08x\n", i, v);
}
printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
sizeof(asm_instrs), sizeof(asm_instrs) / sizeof(ASMInstr),
freq[0], freq[1], freq[2], freq[3]);
}
#endif
/* 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);
parse_flags = PARSE_FLAG_ASM_COMMENTS;
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 == '#') {
/* horrible gas comment */
while (tok != TOK_LINEFEED)
next();
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
asm_parse_directive(s1, global);
} else if (tok == '.') {
asm_parse_directive(s1);
} else if (tok == TOK_PPNUM) {
Sym *sym;
const char *p;
int n;
p = tokc.str.data;
p = tokc.cstr->data;
n = strtoul(p, (char **)&p, 10);
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;
@ -961,35 +767,30 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
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) && global) {
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 == '=') {
set_symbol(s1, opcode);
int n;
next();
n = asm_int_expr(s1);
asm_new_label1(s1, opcode, 0, SHN_ABS, n);
goto redo;
} else {
asm_opcode(s1, opcode);
}
}
/* 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);
return 0;
}
@ -999,21 +800,26 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
Sym *define_start;
int ret;
define_start = define_stack;
preprocess_start(s1);
tcc_debug_start(s1);
preprocess_init(s1);
/* default section is text */
cur_text_section = text_section;
ind = cur_text_section->data_offset;
nocode_wanted = 0;
ret = tcc_assemble_internal(s1, do_preprocess, 1);
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);
cur_text_section->data_offset = ind;
tcc_debug_end(s1);
free_defines(define_start);
return ret;
}
@ -1023,7 +829,7 @@ 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, int global)
static void tcc_assemble_inline(TCCState *s1, char *str, int len)
{
int saved_parse_flags;
const int *saved_macro_ptr;
@ -1035,11 +841,10 @@ static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
memcpy(file->buffer, str, len);
macro_ptr = NULL;
tcc_assemble_internal(s1, 0, global);
tcc_assemble_internal(s1, 0);
tcc_close();
parse_flags = saved_parse_flags;
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
macro_ptr = saved_macro_ptr;
}
@ -1104,11 +909,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
}
modifier = 0;
if (*str == 'c' || *str == 'n' ||
*str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
*str == 'q' ||
/* P in GCC would add "@PLT" to symbol refs in PIC mode,
and make literal operands not be decorated with '$'. */
*str == 'P')
*str == 'b' || *str == 'w' || *str == 'h')
modifier = *str++;
index = find_constraint(operands, nb_operands, str, &str);
if (index < 0)
@ -1140,7 +941,6 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
if (tok != ':') {
nb_operands = *nb_operands_ptr;
for(;;) {
CString astr;
if (nb_operands >= MAX_ASM_OPERANDS)
tcc_error("too many asm operands");
op = &operands[nb_operands++];
@ -1153,15 +953,15 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
next();
skip(']');
}
parse_mult_str(&astr, "string constant");
op->constraint = tcc_malloc(astr.size);
strcpy(op->constraint, astr.data);
cstr_free(&astr);
if (tok != TOK_STR)
expect("string constant");
op->constraint = tcc_malloc(tokc.cstr->size);
strcpy(op->constraint, tokc.cstr->data);
next();
skip('(');
gexpr();
if (is_output) {
if (!(vtop->type.t & VT_ARRAY))
test_lvalue();
test_lvalue();
} else {
/* we want to avoid LLOCAL case, except when the 'm'
constraint is used. Note that it may come from
@ -1223,7 +1023,7 @@ ST_FUNC void asm_instr(void)
for(;;) {
if (tok != TOK_STR)
expect("string constant");
asm_clobber(clobber_regs, tokc.str.data);
asm_clobber(clobber_regs, tokc.cstr->data);
next();
if (tok == ',') {
next();
@ -1268,7 +1068,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, 0);
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
/* restore the current C token */
next();
@ -1290,10 +1090,7 @@ 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(')');
@ -1309,7 +1106,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, 1);
tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
cur_text_section->data_offset = ind;
@ -1317,6 +1114,5 @@ ST_FUNC void asm_global_instr(void)
next();
cstr_free(&astr);
nocode_wanted = saved_nocode_wanted;
}
#endif /* CONFIG_TCC_ASM */

2942
tccelf.c

File diff suppressed because it is too large Load Diff

4001
tccgen.c

File diff suppressed because it is too large Load Diff

519
tccpe.c
View File

@ -20,9 +20,6 @@
#include "tcc.h"
#define PE_MERGE_DATA
/* #define PE_PRINT_SECTIONS */
#ifndef _WIN32
#define stricmp strcasecmp
#define strnicmp strncasecmp
@ -32,33 +29,15 @@
#define MAX_PATH 260
#endif
#define PE_MERGE_DATA
// #define PE_PRINT_SECTIONS
#ifdef TCC_TARGET_X86_64
# define ADDR3264 ULONGLONG
# define REL_TYPE_DIRECT R_X86_64_64
# define R_XXX_THUNKFIX R_X86_64_PC32
# define R_XXX_RELATIVE R_X86_64_RELATIVE
# define IMAGE_FILE_MACHINE 0x8664
# define RSRC_RELTYPE 3
#elif defined TCC_TARGET_ARM
#else
# define ADDR3264 DWORD
# define REL_TYPE_DIRECT R_ARM_ABS32
# define R_XXX_THUNKFIX R_ARM_ABS32
# define R_XXX_RELATIVE R_ARM_RELATIVE
# define IMAGE_FILE_MACHINE 0x01C0
# define RSRC_RELTYPE 7 /* ??? (not tested) */
#elif defined TCC_TARGET_I386
# define ADDR3264 DWORD
# define REL_TYPE_DIRECT R_386_32
# define R_XXX_THUNKFIX R_386_32
# define R_XXX_RELATIVE R_386_RELATIVE
# define IMAGE_FILE_MACHINE 0x014C
# define RSRC_RELTYPE 7 /* DIR32NB */
#endif
#if 0
#ifdef _WIN32
void dbg_printf (const char *fmt, ...)
{
@ -71,7 +50,6 @@ void dbg_printf (const char *fmt, ...)
OutputDebugString(buffer);
}
#endif
#endif
/* ----------------------------------------------------------- */
#ifndef IMAGE_NT_SIGNATURE
@ -358,7 +336,6 @@ struct pe_info {
int type;
DWORD sizeofheaders;
ADDR3264 imagebase;
const char *start_symbol;
DWORD start_addr;
DWORD imp_offs;
DWORD imp_size;
@ -386,7 +363,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;
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL))
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & 2))
return name + 1;
return name;
}
@ -396,14 +373,12 @@ 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) {
if (sym->st_other & 2) {
/* try w/0 stdcall deco (windows API convention) */
p = strrchr(s, '@');
if (!p || s[0] != '_')
@ -411,24 +386,19 @@ 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_", 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 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 {
continue;
break;
}
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 n == 2 ? err : sym_index;
return sym_index;
}
/*----------------------------------------------------------------------------*/
@ -537,7 +507,13 @@ static int pe_write(struct pe_info *pe)
0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
{
/* IMAGE_FILE_HEADER filehdr */
IMAGE_FILE_MACHINE, /*WORD Machine; */
#if defined(TCC_TARGET_I386)
0x014C, /*WORD Machine; */
#elif defined(TCC_TARGET_X86_64)
0x8664, /*WORD Machine; */
#elif defined(TCC_TARGET_ARM)
0x01C0, /*WORD Machine; */
#endif
0x0003, /*WORD NumberOfSections; */
0x00000000, /*DWORD TimeDateStamp; */
0x00000000, /*DWORD PointerToSymbolTable; */
@ -646,6 +622,7 @@ 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:
@ -686,7 +663,7 @@ static int pe_write(struct pe_info *pe)
}
}
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
pstrcpy((char*)psh->Name, sizeof psh->Name, sh_name);
psh->Characteristics = pe_sec_flags[si->cls];
psh->VirtualAddress = addr;
@ -698,16 +675,11 @@ 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;
@ -715,7 +687,6 @@ 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);
@ -747,6 +718,24 @@ static int pe_write(struct pe_info *pe)
/*----------------------------------------------------------------------------*/
#if defined(TCC_TARGET_X86_64)
#define REL_TYPE_DIRECT R_X86_64_64
#define R_XXX_THUNKFIX R_X86_64_PC32
#define R_XXX_RELATIVE R_X86_64_RELATIVE
#elif defined(TCC_TARGET_I386)
#define REL_TYPE_DIRECT R_386_32
#define R_XXX_THUNKFIX R_386_32
#define R_XXX_RELATIVE R_386_RELATIVE
#elif defined(TCC_TARGET_ARM)
#define REL_TYPE_DIRECT R_ARM_ABS32
#define R_XXX_THUNKFIX R_ARM_ABS32
#define R_XXX_RELATIVE R_ARM_RELATIVE
#endif
/*----------------------------------------------------------------------------*/
static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
{
int i;
@ -765,7 +754,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(&pe->imp_info, &pe->imp_count, p);
dynarray_add((void***)&pe->imp_info, &pe->imp_count, p);
found_dll:
i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index);
@ -773,21 +762,11 @@ found_dll:
return p->symbols[i];
s = tcc_mallocz(sizeof *s);
dynarray_add(&p->symbols, &p->sym_count, s);
dynarray_add((void***)&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)
{
@ -840,46 +819,36 @@ static void pe_build_imports(struct pe_info *pe)
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;
int ordinal;
org_sym->st_value = thk_ptr;
org_sym->st_shndx = pe->thunk->sh_num;
if (dllref)
v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */
else
ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */
v = pe->thunk->data_offset + rva_base;
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
put_elf_str(pe->thunk, name);
#ifdef TCC_IS_NATIVE
if (pe->type == PE_RUN) {
v = imp_sym->st_value;
if (dllref) {
if ( !dllref->handle )
dllref->handle = LoadLibrary(dllref->name);
v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name);
v = (ADDR3264)GetProcAddress(dllref->handle, name);
}
if (!v)
tcc_error_noabort("can't build symbol '%s'", name);
} else
#endif
if (ordinal) {
v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1);
} else {
v = pe->thunk->data_offset + rva_base;
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
put_elf_str(pe->thunk, name);
tcc_error_noabort("undefined symbol '%s'", name);
}
#endif
} else {
v = 0; /* last entry is zero */
}
*(ADDR3264*)(pe->thunk->data+thk_ptr) =
*(ADDR3264*)(pe->thunk->data+ent_ptr) = v;
thk_ptr += sizeof (ADDR3264);
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);
}
/* ------------------------------------------------------------- */
@ -918,18 +887,18 @@ static void pe_build_exports(struct pe_info *pe)
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
sym = (ElfW(Sym)*)symtab_section->data + sym_index;
name = pe_export_name(pe->s1, sym);
if ((sym->st_other & ST_PE_EXPORT)
if ((sym->st_other & 1)
/* export only symbols from actually written sections */
&& pe->s1->sections[sym->st_shndx]->sh_addr) {
p = tcc_malloc(sizeof *p);
p->index = sym_index;
p->name = name;
dynarray_add(&sorted, &sym_count, p);
dynarray_add((void***)&sorted, &sym_count, p);
}
#if 0
if (sym->st_other & ST_PE_EXPORT)
if (sym->st_other & 1)
printf("export: %s\n", name);
if (sym->st_other & ST_PE_STDCALL)
if (sym->st_other & 2)
printf("stdcall: %s\n", name);
#endif
}
@ -969,7 +938,7 @@ static void pe_build_exports(struct pe_info *pe)
} else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose)
printf("<- %s (%d symbol%s)\n", buf, sym_count, "s" + (sym_count < 2));
printf("<- %s (%d symbols)\n", buf, sym_count);
}
#endif
@ -1095,9 +1064,6 @@ static int pe_assign_addresses (struct pe_info *pe)
struct section_info *si;
Section *s;
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
@ -1246,7 +1212,7 @@ static int pe_check_symbols(struct pe_info *pe)
int imp_sym = pe_find_import(pe->s1, sym);
struct import_symbol *is;
if (imp_sym <= 0)
if (0 == imp_sym)
goto not_found;
if (type == STT_NOTYPE) {
@ -1304,7 +1270,7 @@ static int pe_check_symbols(struct pe_info *pe)
/* patch the original symbol */
sym->st_value = offset;
sym->st_shndx = text_section->sh_num;
sym->st_other &= ~ST_PE_EXPORT; /* do not export */
sym->st_other &= ~1; /* do not export */
continue;
}
@ -1317,17 +1283,13 @@ static int pe_check_symbols(struct pe_info *pe)
}
not_found:
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)?":"");
tcc_error_noabort("undefined symbol '%s'", name);
ret = -1;
} else if (pe->s1->rdynamic
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
/* if -rdynamic option, then export all non local symbols */
sym->st_other |= ST_PE_EXPORT;
sym->st_other |= 1;
}
}
return ret;
@ -1475,15 +1437,25 @@ static void pe_print_sections(TCCState *s1, const char *fname)
/* ------------------------------------------------------------- */
/* helper function for load/store to insert one more indirection */
#ifndef TCC_TARGET_ARM
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;
if (!(sv->sym->type.t & VT_IMPORT))
sym = sv->sym;
if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN)
return sv;
// printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
if (!sym->c)
put_extern_sym(sym, NULL, 0, 0);
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
if (!(esym->st_other & 4))
return sv;
// printf("import %04x %04x %04x %s\n", sv->type.t, 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;
@ -1492,21 +1464,22 @@ 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) {
if (sv->c.ui) {
vpushv(v2);
vpushi(sv->c.i);
vpushi(sv->c.ui);
gen_opi('+');
*v2 = *vtop--;
}
v2->type.t = sv->type.t;
v2->r |= sv->r & VT_LVAL;
return v2;
}
#endif
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value)
{
return set_elf_sym(
return add_elf_sym(
s1->dynsymtab_section,
value,
dllindex, /* st_size */
@ -1526,7 +1499,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(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
return s1->nb_loaded_dlls;
}
@ -1538,102 +1511,6 @@ 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;
#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;
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;
if (IMAGE_FILE_MACHINE != ih.Machine) {
if (ih.Machine == 0x014C)
ret = 32;
else if (ih.Machine == 0x8664)
ret = 64;
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_0;
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_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 ...'.
@ -1650,7 +1527,7 @@ static int pe_load_res(TCCState *s1, int fd)
if (!read_mem(fd, 0, &hdr, sizeof hdr))
goto quit;
if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE
if (hdr.filehdr.Machine != 0x014C
|| hdr.filehdr.NumberOfSections != 1
|| strcmp(hdr.sectionhdr.Name, ".rsrc") != 0)
goto quit;
@ -1667,7 +1544,7 @@ static int pe_load_res(TCCState *s1, int fd)
if (!read_mem(fd, offs, &rel, sizeof rel))
goto quit;
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
if (rel.type != RSRC_RELTYPE)
if (rel.type != 7) /* DIR32NB */
goto quit;
put_elf_reloc(symtab_section, rsrc_section,
rel.offset, R_XXX_RELATIVE, 0);
@ -1679,36 +1556,45 @@ quit:
}
/* ------------------------------------------------------------- */
static char *trimfront(char *p)
{
while (*p && (unsigned char)*p <= ' ')
++p;
++p;
return p;
}
static char *trimback(char *a, char *e)
{
while (e > a && (unsigned char)e[-1] <= ' ')
--e;
--e;
*e = 0;;
return a;
}
static char *get_line(char *line, int size, int fd)
{
int n;
for (n = 0; n < size - 1; )
if (read(fd, line + n, 1) < 1 || line[n++] == '\n')
break;
if (0 == n)
return NULL;
trimback(line, line + n);
return trimfront(line);
}
/* ------------------------------------------------------------- */
static int pe_load_def(TCCState *s1, int fd)
{
int state = 0, ret = -1, dllindex = 0, ord;
char line[400], dllname[80], *p, *x;
FILE *fp;
int state = 0, ret = -1, dllindex = 0;
char line[400], dllname[80], *p;
fp = fdopen(dup(fd), "rb");
while (fgets(line, sizeof line, fp))
{
p = trimfront(trimback(line, strchr(line, 0)));
for (;;) {
p = get_line(line, sizeof line, fd);
if (NULL == p)
break;
if (0 == *p || ';' == *p)
continue;
switch (state) {
case 0:
if (0 != strnicmp(p, "LIBRARY", 7))
@ -1726,45 +1612,32 @@ static int pe_load_def(TCCState *s1, int fd)
case 2:
dllindex = add_dllref(s1, dllname);
++state;
/* fall through */
default:
/* get ordinal and will store in sym->st_value */
ord = 0;
x = strchr(p, ' ');
if (x) {
*x = 0, x = strrchr(x + 1, '@');
if (x) {
char *d;
ord = (int)strtol(x + 1, &d, 10);
if (*d)
ord = 0;
}
}
pe_putimport(s1, dllindex, p, ord);
pe_putimport(s1, dllindex, p, 0);
continue;
}
}
ret = 0;
quit:
fclose(fp);
return ret;
}
/* ------------------------------------------------------------- */
static int pe_load_dll(TCCState *s1, const char *filename)
#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)
{
char *p, *q;
int index, ret;
ret = tcc_get_dllexports(filename, &p);
if (ret) {
int index;
p = get_export_names(fd);
if (!p)
return -1;
} 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);
}
index = add_dllref(s1, dllname);
for (q = p; *q; q += 1 + strlen(q))
pe_putimport(s1, index, q, 0);
tcc_free(p);
return 0;
}
@ -1777,8 +1650,8 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
ret = pe_load_def(s1, fd);
else if (pe_load_res(s1, fd) == 0)
ret = 0;
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4))
ret = pe_load_dll(s1, filename);
else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2))
ret = pe_load_dll(s1, tcc_basename(filename), fd);
return ret;
}
@ -1853,122 +1726,74 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{
const char *start_symbol;
ADDR3264 addr = 0;
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 ? (unicode_entry ? "__runwwinmain" : "__runwinmain")
: (unicode_entry ? "__runwmain" : "__runmain")
? PE_GUI == pe_type ? "__runwinmain" : "_main"
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
: PE_GUI == pe_type ? (unicode_entry ? "__wwinstart": "__winstart")
: (unicode_entry ? "__wstart" : "__start")
: PE_GUI == pe_type ? "__winstart" : "__start"
;
if (!s1->leading_underscore || strchr(start_symbol, '@'))
if (!s1->leading_underscore || strchr(start_symbol, '@')) {
++start_symbol;
if (start_symbol[0] != '_')
start_symbol = NULL;
}
/* grab the startup code from libtcc1 */
#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 (start_symbol)
add_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, start_symbol);
if (0 == s1->nostdlib) {
static const char *libs[] = {
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
"libtcc1.a", "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 (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
continue;
} else {
tcc_add_library_err(s1, p);
} else if (pp == libs ? tcc_add_dll(s1, p, 0) : tcc_add_library(s1, p)) {
tcc_error_noabort("cannot find library: %s", p);
break;
}
}
}
if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN;
if (start_symbol) {
addr = get_elf_sym_addr(s1, start_symbol, 1);
if (PE_RUN == pe_type && addr)
/* for -run GUI's, put '_runwinmain' instead of 'main' */
add_elf_sym(symtab_section,
addr, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
text_section->sh_num, "main");
}
pe->type = pe_type;
pe->start_symbol = start_symbol;
pe->start_addr = addr;
}
static void pe_set_options(TCCState * s1, struct pe_info *pe)
{
if (PE_DLL == pe->type) {
/* XXX: check if is correct for arm-pe target */
pe->imagebase = 0x10000000;
} else {
#if defined(TCC_TARGET_ARM)
pe->imagebase = 0x00010000;
#else
pe->imagebase = 0x00400000;
#endif
}
#if defined(TCC_TARGET_ARM)
/* we use "console" subsystem by default */
pe->subsystem = 9;
#else
if (PE_DLL == pe->type || PE_GUI == pe->type)
pe->subsystem = 2;
else
pe->subsystem = 3;
#endif
/* Allow override via -Wl,-subsystem=... option */
if (s1->pe_subsystem != 0)
pe->subsystem = s1->pe_subsystem;
/* set default file/section alignment */
if (pe->subsystem == 1) {
pe->section_align = 0x20;
pe->file_align = 0x20;
} else {
pe->section_align = 0x1000;
pe->file_align = 0x200;
}
if (s1->section_align != 0)
pe->section_align = s1->section_align;
if (s1->pe_file_align != 0)
pe->file_align = s1->pe_file_align;
if ((pe->subsystem >= 10) && (pe->subsystem <= 12))
pe->imagebase = 0;
if (s1->has_text_addr)
pe->imagebase = s1->text_addr;
}
ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
{
int ret;
struct pe_info pe;
@ -1982,14 +1807,58 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe_add_runtime(s1, &pe);
relocate_common_syms(); /* assign bss adresses */
tcc_add_linker_symbols(s1);
pe_set_options(s1, &pe);
ret = pe_check_symbols(&pe);
if (ret)
;
else if (filename) {
if (PE_DLL == pe.type) {
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
/* XXX: check if is correct for arm-pe target */
pe.imagebase = 0x10000000;
} else {
#if defined(TCC_TARGET_ARM)
pe.imagebase = 0x00010000;
#else
pe.imagebase = 0x00400000;
#endif
}
#if defined(TCC_TARGET_ARM)
/* we use "console" subsystem by default */
pe.subsystem = 9;
#else
if (PE_DLL == pe.type || PE_GUI == pe.type)
pe.subsystem = 2;
else
pe.subsystem = 3;
#endif
/* Allow override via -Wl,-subsystem=... option */
if (s1->pe_subsystem != 0)
pe.subsystem = s1->pe_subsystem;
/* set default file/section alignment */
if (pe.subsystem == 1) {
pe.section_align = 0x20;
pe.file_align = 0x20;
} else {
pe.section_align = 0x1000;
pe.file_align = 0x200;
}
if (s1->section_align != 0)
pe.section_align = s1->section_align;
if (s1->pe_file_align != 0)
pe.file_align = s1->pe_file_align;
if ((pe.subsystem >= 10) && (pe.subsystem <= 12))
pe.imagebase = 0;
if (s1->has_text_addr)
pe.imagebase = s1->text_addr;
pe_assign_addresses(&pe);
relocate_syms(s1, s1->symtab, 0);
relocate_syms(s1, 0);
for (i = 1; i < s1->nb_sections; ++i) {
Section *s = s1->sections[i];
if (s->reloc) {
@ -1997,9 +1866,6 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
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
@ -2009,12 +1875,9 @@ 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;
#endif
}
pe_free_imports(&pe);
#ifdef PE_PRINT_SECTIONS
pe_print_sections(s1, "tcc.log");
#endif

2179
tccpp.c

File diff suppressed because it is too large Load Diff

285
tccrun.c
View File

@ -23,94 +23,81 @@
/* only native compiler supports -run */
#ifdef TCC_IS_NATIVE
#ifndef _WIN32
# include <sys/mman.h>
#endif
#ifdef CONFIG_TCC_BACKTRACE
# ifndef _WIN32
# include <signal.h>
# ifndef __OpenBSD__
# include <sys/ucontext.h>
# endif
# else
# define ucontext_t CONTEXT
# endif
ST_DATA int rt_num_callers = 6;
ST_DATA const char **rt_bound_error_msg;
ST_DATA void *rt_prog_main;
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
static void rt_error(ucontext_t *uc, const char *fmt, ...);
static void set_exception_handler(void);
#endif
#ifdef _WIN32
#define ucontext_t CONTEXT
#endif
static void set_pages_executable(void *ptr, unsigned long length);
static void set_exception_handler(void);
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
static void rt_error(ucontext_t *uc, const char *fmt, ...);
static int tcc_relocate_ex(TCCState *s1, void *ptr);
#ifdef _WIN64
static void *win64_add_function_table(TCCState *s1);
static void win64_del_function_table(void *);
static void win64_add_function_table(TCCState *s1);
#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;
int ret;
if (TCC_RELOCATE_AUTO != ptr)
return tcc_relocate_ex(s1, ptr);
size = tcc_relocate_ex(s1, NULL);
if (size < 0)
return -1;
ret = tcc_relocate_ex(s1, NULL);
if (ret < 0)
return ret;
#ifdef HAVE_SELINUX
/* Use mmap instead of malloc for Selinux. */
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr == MAP_FAILED)
tcc_error("tccrun: could not map memory");
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
#else
ptr = tcc_malloc(size);
#endif
tcc_relocate_ex(s1, ptr); /* no more errors expected */
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
return 0;
}
{ /* Use mmap instead of malloc for Selinux. Ref:
http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
ST_FUNC void tcc_run_free(TCCState *s1)
{
int i;
char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp (tmpfname);
for (i = 0; i < s1->nb_runtime_mem; ++i) {
#ifdef HAVE_SELINUX
unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
munmap(s1->runtime_mem[i], size);
#else
#ifdef _WIN64
win64_del_function_table(*(void**)s1->runtime_mem[i]);
#endif
tcc_free(s1->runtime_mem[i]);
#endif
s1->mem_size = ret;
unlink (tmpfname);
ftruncate (fd, s1->mem_size);
s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
if (s1->write_mem == MAP_FAILED)
tcc_error("/tmp not writeable");
s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
MAP_SHARED, fd, 0);
if (s1->runtime_mem == MAP_FAILED)
tcc_error("/tmp not executable");
ret = tcc_relocate_ex(s1, s1->write_mem);
}
tcc_free(s1->runtime_mem);
#else
s1->runtime_mem = tcc_malloc(ret);
ret = tcc_relocate_ex(s1, s1->runtime_mem);
#endif
return ret;
}
/* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
int (*prog_main)(int, char **);
int ret;
s1->runtime_main = "main";
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1;
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
prog_main = tcc_get_symbol_err(s1, "main");
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_debug) {
@ -119,56 +106,32 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
}
#endif
errno = 0; /* clean errno value */
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
void (*bound_init)(void);
void (*bound_exit)(void);
void (*bound_new_region)(void *p, addr_t size);
int (*bound_delete_region)(void *p);
int i, ret;
/* set error function */
rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
/* XXX: use .init section so that it also work in binary ? */
bound_init = tcc_get_symbol_err(s1, "__bound_init");
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
bound_init();
/* mark argv area as valid */
bound_new_region(argv, argc*sizeof(argv[0]));
for (i=0; i<argc; ++i)
bound_new_region(argv[i], strlen(argv[i]) + 1);
ret = (*prog_main)(argc, argv);
/* unmark argv area */
for (i=0; i<argc; ++i)
bound_delete_region(argv[i]);
bound_delete_region(argv);
bound_exit();
return ret;
}
} else
#endif
return (*prog_main)(argc, argv);
ret = (*prog_main)(argc, argv);
return ret;
}
#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)
{
Section *s;
unsigned offset, length, fill, i, k;
unsigned long offset, length;
addr_t mem;
int i;
if (NULL == ptr) {
s1->nb_errors = 0;
@ -185,42 +148,31 @@ 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 (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;
s->sh_addr = mem ? mem + offset : 0;
#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
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
offset = (offset + length + 15) & ~15;
}
offset += 16;
/* relocate symbols */
relocate_syms(s1, s1->symtab, 1);
relocate_syms(s1, 1);
if (s1->nb_errors)
return -1;
#ifdef TCC_HAS_RUNTIME_PLTGOT
s1->runtime_plt_and_got_offset = 0;
s1->runtime_plt_and_got = (char *)(mem + offset);
/* double the size of the buffer for got and plt entries
XXX: calculate exact size for them? */
offset *= 2;
#endif
if (0 == mem)
return offset + RUN_SECTION_ALIGNMENT;
return offset;
/* relocate each section */
for(i = 1; i < s1->nb_sections; i++) {
@ -228,17 +180,13 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
if (s->reloc)
relocate_section(s1, s);
}
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 %08x %04x\n", s->name, s->sh_addr, length);
ptr = (void*)s->sh_addr;
if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length);
@ -248,6 +196,15 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
if (s->sh_flags & SHF_EXECINSTR)
set_pages_executable(ptr, length);
}
#ifdef TCC_HAS_RUNTIME_PLTGOT
set_pages_executable(s1->runtime_plt_and_got,
s1->runtime_plt_and_got_offset);
#endif
#ifdef _WIN64
win64_add_function_table(s1);
#endif
return 0;
}
@ -260,46 +217,17 @@ static void set_pages_executable(void *ptr, unsigned long length)
unsigned long old_protect;
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
#else
void __clear_cache(void *beginning, void *end);
addr_t start, end;
#ifndef PAGESIZE
# define PAGESIZE 4096
#endif
addr_t start, end;
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
__clear_cache(ptr, (char *)ptr + length);
# endif
mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
}
#ifdef _WIN64
static void *win64_add_function_table(TCCState *s1)
{
void *p = NULL;
if (s1->uw_pdata) {
p = (void*)s1->uw_pdata->sh_addr;
RtlAddFunctionTable(
(RUNTIME_FUNCTION*)p,
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
text_section->sh_addr
);
s1->uw_pdata = NULL;
}
return p;;
}
static void win64_del_function_table(void *p)
{
if (p) {
RtlDeleteFunctionTable((RUNTIME_FUNCTION*)p);
}
}
#endif
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
@ -325,7 +253,7 @@ static addr_t rt_printline(addr_t wanted_pc, const char *msg)
if (stab_section) {
stab_len = stab_section->data_offset;
stab_sym = (Stab_Sym *)stab_section->data;
stab_str = (char *) stabstr_section->data;
stab_str = stabstr_section->data;
}
func_name[0] = '\0';
@ -418,7 +346,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);
strtab_section->data + sym->st_name);
func_addr = sym->st_value;
goto found;
}
@ -551,14 +479,10 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
if (level == 0) {
#if defined(__APPLE__)
*paddr = uc->uc_mcontext->__ss.__eip;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
*paddr = uc->uc_mcontext.mc_eip;
#elif defined(__dietlibc__)
*paddr = uc->uc_mcontext.eip;
#elif defined(__NetBSD__)
*paddr = uc->uc_mcontext.__gregs[_REG_EIP];
#elif defined(__OpenBSD__)
*paddr = uc->sc_eip;
#else
*paddr = uc->uc_mcontext.gregs[REG_EIP];
#endif
@ -566,14 +490,10 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
} else {
#if defined(__APPLE__)
fp = uc->uc_mcontext->__ss.__ebp;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
fp = uc->uc_mcontext.mc_ebp;
#elif defined(__dietlibc__)
fp = uc->uc_mcontext.ebp;
#elif defined(__NetBSD__)
fp = uc->uc_mcontext.__gregs[_REG_EBP];
#elif defined(__OpenBSD__)
*paddr = uc->sc_ebp;
#else
fp = uc->uc_mcontext.gregs[REG_EBP];
#endif
@ -601,10 +521,8 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
/* XXX: only support linux */
#if defined(__APPLE__)
*paddr = uc->uc_mcontext->__ss.__rip;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
*paddr = uc->uc_mcontext.mc_rip;
#elif defined(__NetBSD__)
*paddr = uc->uc_mcontext.__gregs[_REG_RIP];
#else
*paddr = uc->uc_mcontext.gregs[REG_RIP];
#endif
@ -612,10 +530,8 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
} else {
#if defined(__APPLE__)
fp = uc->uc_mcontext->__ss.__rbp;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
fp = uc->uc_mcontext.mc_rbp;
#elif defined(__NetBSD__)
fp = uc->uc_mcontext.__gregs[_REG_RBP];
#else
fp = uc->uc_mcontext.gregs[REG_RBP];
#endif
@ -673,27 +589,6 @@ static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
}
}
/* ------------------------------------------------------------- */
#elif defined(__aarch64__)
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level)
{
if (level < 0)
return -1;
else if (level == 0) {
*paddr = uc->uc_mcontext.pc;
return 0;
}
else {
addr_t *fp = (addr_t *)uc->uc_mcontext.regs[29];
int i;
for (i = 1; i < level; i++)
fp = (addr_t *)fp[0];
*paddr = fp[1];
return 0;
}
}
/* ------------------------------------------------------------- */
#else
@ -738,6 +633,17 @@ static void set_exception_handler(void)
SetUnhandledExceptionFilter(cpu_exception_handler);
}
#ifdef _WIN64
static void win64_add_function_table(TCCState *s1)
{
RtlAddFunctionTable(
(RUNTIME_FUNCTION*)s1->uw_pdata->sh_addr,
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
text_section->sh_addr
);
}
#endif
/* return the PC at frame level 'level'. Return non zero if not found */
static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level)
{
@ -802,7 +708,7 @@ static TCCSyms tcc_syms[] = {
{ NULL, NULL },
};
ST_FUNC void *dlsym(void *handle, const char *symbol)
ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol)
{
TCCSyms *p;
p = tcc_syms;
@ -814,6 +720,13 @@ ST_FUNC void *dlsym(void *handle, const char *symbol)
return NULL;
}
#elif !defined(_WIN32)
ST_FUNC void *resolve_sym(TCCState *s1, const char *sym)
{
return dlsym(RTLD_DEFAULT, sym);
}
#endif /* CONFIG_TCC_STATIC */
#endif /* TCC_IS_NATIVE */
/* ------------------------------------------------------------- */

206
tcctok.h
View File

@ -59,10 +59,6 @@
DEF(TOK_ASM2, "__asm")
DEF(TOK_ASM3, "__asm__")
#ifdef TCC_TARGET_ARM64
DEF(TOK_UINT128, "__uint128_t")
#endif
/*********************************************************************/
/* the following are not keywords. They are included to ease parsing */
/* preprocessor only */
@ -117,41 +113,23 @@
DEF(TOK_FASTCALL1, "fastcall")
DEF(TOK_FASTCALL2, "__fastcall")
DEF(TOK_FASTCALL3, "__fastcall__")
DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__")
DEF(TOK_MODE_DI, "__DI__")
DEF(TOK_MODE_HI, "__HI__")
DEF(TOK_MODE_SI, "__SI__")
DEF(TOK_MODE_word, "__word__")
DEF(TOK_DLLEXPORT, "dllexport")
DEF(TOK_DLLIMPORT, "dllimport")
DEF(TOK_NORETURN1, "noreturn")
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_start, "__builtin_va_start")
#else
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
#endif
#endif
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
#ifdef TCC_TARGET_ARM64
DEF(TOK___va_start, "__va_start")
DEF(TOK___va_arg, "__va_arg")
#endif
/* pragma */
DEF(TOK_pack, "pack")
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64)
@ -159,43 +137,25 @@
DEF(TOK_ASM_push, "push")
DEF(TOK_ASM_pop, "pop")
#endif
DEF(TOK_comment, "comment")
DEF(TOK_lib, "lib")
DEF(TOK_push_macro, "push_macro")
DEF(TOK_pop_macro, "pop_macro")
DEF(TOK_once, "once")
/* builtin functions or variables */
#ifndef TCC_ARM_EABI
#ifdef TCC_ARM_EABI
DEF(TOK_memcpy, "__aeabi_memcpy")
DEF(TOK_memcpy4, "__aeabi_memcpy4")
DEF(TOK_memcpy8, "__aeabi_memcpy8")
DEF(TOK_memset, "__aeabi_memset")
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
#else
DEF(TOK_memcpy, "memcpy")
DEF(TOK_memmove, "memmove")
DEF(TOK_memset, "memset")
DEF(TOK___divdi3, "__divdi3")
DEF(TOK___moddi3, "__moddi3")
DEF(TOK___udivdi3, "__udivdi3")
DEF(TOK___umoddi3, "__umoddi3")
DEF(TOK___ashrdi3, "__ashrdi3")
DEF(TOK___lshrdi3, "__lshrdi3")
DEF(TOK___ashldi3, "__ashldi3")
DEF(TOK___floatundisf, "__floatundisf")
DEF(TOK___floatundidf, "__floatundidf")
# ifndef TCC_ARM_VFP
DEF(TOK___floatundixf, "__floatundixf")
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
# endif
DEF(TOK___fixunssfdi, "__fixunssfdi")
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
#endif
#if defined TCC_TARGET_ARM
# ifdef TCC_ARM_EABI
DEF(TOK_memcpy, "__aeabi_memcpy")
DEF(TOK_memcpy4, "__aeabi_memcpy4")
DEF(TOK_memcpy8, "__aeabi_memcpy8")
DEF(TOK_memmove, "__aeabi_memmove")
DEF(TOK_memset, "__aeabi_memset")
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
#if defined(TCC_TARGET_ARM)
#ifdef TCC_ARM_EABI
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
DEF(TOK___divsi3, "__aeabi_idiv")
@ -204,33 +164,24 @@
DEF(TOK___floatdidf, "__aeabi_l2d")
DEF(TOK___fixsfdi, "__aeabi_f2lz")
DEF(TOK___fixdfdi, "__aeabi_d2lz")
DEF(TOK___ashrdi3, "__aeabi_lasr")
DEF(TOK___lshrdi3, "__aeabi_llsr")
DEF(TOK___ashldi3, "__aeabi_llsl")
DEF(TOK___floatundisf, "__aeabi_ul2f")
DEF(TOK___floatundidf, "__aeabi_ul2d")
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
# else
#else
DEF(TOK___modsi3, "__modsi3")
DEF(TOK___umodsi3, "__umodsi3")
DEF(TOK___divsi3, "__divsi3")
DEF(TOK___udivsi3, "__udivsi3")
DEF(TOK___floatdisf, "__floatdisf")
DEF(TOK___floatdidf, "__floatdidf")
# ifndef TCC_ARM_VFP
#ifndef TCC_ARM_VFP
DEF(TOK___floatdixf, "__floatdixf")
DEF(TOK___fixunssfsi, "__fixunssfsi")
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
DEF(TOK___fixxfdi, "__fixxfdi")
# endif
#endif
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
# endif
#endif
#if defined TCC_TARGET_C67
#elif defined(TCC_TARGET_C67)
DEF(TOK__divi, "_divi")
DEF(TOK__divu, "_divu")
DEF(TOK__divf, "_divf")
@ -238,45 +189,34 @@
DEF(TOK__remi, "_remi")
DEF(TOK__remu, "_remu")
#endif
#if defined TCC_TARGET_I386
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
DEF(TOK___fixxfdi, "__fixxfdi")
#ifdef TCC_TARGET_I386
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
#endif
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
DEF(TOK_alloca, "alloca")
#ifdef TCC_ARM_EABI
DEF(TOK___ashrdi3, "__aeabi_lasr")
DEF(TOK___lshrdi3, "__aeabi_llsr")
DEF(TOK___ashldi3, "__aeabi_llsl")
DEF(TOK___floatundisf, "__aeabi_ul2f")
DEF(TOK___floatundidf, "__aeabi_ul2d")
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
#else
DEF(TOK___ashrdi3, "__ashrdi3")
DEF(TOK___lshrdi3, "__lshrdi3")
DEF(TOK___ashldi3, "__ashldi3")
DEF(TOK___floatundisf, "__floatundisf")
DEF(TOK___floatundidf, "__floatundidf")
#ifndef TCC_ARM_VFP
DEF(TOK___floatundixf, "__floatundixf")
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
#endif
#if defined TCC_TARGET_PE
DEF(TOK___fixunssfdi, "__fixunssfdi")
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
#endif
#ifdef TCC_TARGET_PE
DEF(TOK___chkstk, "__chkstk")
#endif
#ifdef TCC_TARGET_ARM64
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
DEF(TOK___addtf3, "__addtf3")
DEF(TOK___subtf3, "__subtf3")
DEF(TOK___multf3, "__multf3")
DEF(TOK___divtf3, "__divtf3")
DEF(TOK___extendsftf2, "__extendsftf2")
DEF(TOK___extenddftf2, "__extenddftf2")
DEF(TOK___trunctfsf2, "__trunctfsf2")
DEF(TOK___trunctfdf2, "__trunctfdf2")
DEF(TOK___fixtfsi, "__fixtfsi")
DEF(TOK___fixtfdi, "__fixtfdi")
DEF(TOK___fixunstfsi, "__fixunstfsi")
DEF(TOK___fixunstfdi, "__fixunstfdi")
DEF(TOK___floatsitf, "__floatsitf")
DEF(TOK___floatditf, "__floatditf")
DEF(TOK___floatunsitf, "__floatunsitf")
DEF(TOK___floatunditf, "__floatunditf")
DEF(TOK___eqtf2, "__eqtf2")
DEF(TOK___netf2, "__netf2")
DEF(TOK___lttf2, "__lttf2")
DEF(TOK___letf2, "__letf2")
DEF(TOK___gttf2, "__gttf2")
DEF(TOK___getf2, "__getf2")
#endif
/* bound checking symbols */
#ifdef CONFIG_TCC_BCHECK
@ -287,61 +227,51 @@
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
DEF(TOK___bound_main_arg, "__bound_main_arg")
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
# ifdef TCC_TARGET_PE
#ifdef TCC_TARGET_PE
DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free")
DEF(TOK_realloc, "realloc")
DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc")
# endif
#endif
DEF(TOK_memmove, "memmove")
DEF(TOK_strlen, "strlen")
DEF(TOK_strcpy, "strcpy")
#endif
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
DEF(TOK_alloca, "alloca")
#endif
/* Tiny Assembler */
DEF_ASMDIR(byte) /* must be first directive */
DEF_ASMDIR(word)
DEF_ASMDIR(align)
DEF_ASMDIR(balign)
DEF_ASMDIR(p2align)
DEF_ASMDIR(set)
DEF_ASMDIR(skip)
DEF_ASMDIR(space)
DEF_ASMDIR(string)
DEF_ASMDIR(asciz)
DEF_ASMDIR(ascii)
DEF_ASMDIR(file)
DEF_ASMDIR(globl)
DEF_ASMDIR(global)
DEF_ASMDIR(weak)
DEF_ASMDIR(hidden)
DEF_ASMDIR(ident)
DEF_ASMDIR(size)
DEF_ASMDIR(type)
DEF_ASMDIR(text)
DEF_ASMDIR(data)
DEF_ASMDIR(bss)
DEF_ASMDIR(previous)
DEF_ASMDIR(pushsection)
DEF_ASMDIR(popsection)
DEF_ASMDIR(fill)
DEF_ASMDIR(rept)
DEF_ASMDIR(endr)
DEF_ASMDIR(org)
DEF_ASMDIR(quad)
DEF_ASM(byte)
DEF_ASM(word)
DEF_ASM(align)
DEF_ASM(skip)
DEF_ASM(space)
DEF_ASM(string)
DEF_ASM(asciz)
DEF_ASM(ascii)
DEF_ASM(file)
DEF_ASM(globl)
DEF_ASM(global)
DEF_ASM(ident)
DEF_ASM(size)
DEF_ASM(type)
DEF_ASM(text)
DEF_ASM(data)
DEF_ASM(bss)
DEF_ASM(previous)
DEF_ASM(fill)
DEF_ASM(org)
DEF_ASM(quad)
#if defined(TCC_TARGET_I386)
DEF_ASMDIR(code16)
DEF_ASMDIR(code32)
DEF_ASM(code16)
DEF_ASM(code32)
#elif defined(TCC_TARGET_X86_64)
DEF_ASMDIR(code64)
DEF_ASM(code64)
#endif
DEF_ASMDIR(short)
DEF_ASMDIR(long)
DEF_ASMDIR(int)
DEF_ASMDIR(section) /* must be last directive */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#include "i386-tok.h"

View File

@ -1,547 +0,0 @@
/* -------------------------------------------------------------- */
/*
* 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;
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[MAX_PATH];
char outfile[MAX_PATH];
const char *file;
char *p, *q;
FILE *fp, *op;
#ifdef _WIN32
char path[MAX_PATH];
#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 == 32 ? "can't read symbols from 32bit" :
ret == 64 ? "can't read symbols from 64bit" :
ret == -1 ? "can't find file" :
ret == 0 ? "no symbols found in" :
"unknown file type", file);
ret = 1;
goto the_end;
}
if (v)
printf("-> %s\n", file);
op = fopen(outfile, "w");
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);
}
/* -------------------------------------------------------------- */

View File

@ -1,13 +0,0 @@
/* This file is to test compute #include directives. It's named so
that it starts with a pre-processing number which isn't a valid
number (42test.h). Including this must work. */
#ifndef INC42_FIRST
int have_included_42test_h;
#define INC42_FIRST
#elif !defined INC42_SECOND
#define INC42_SECOND
int have_included_42test_h_second;
#else
#define INC42_THIRD
int have_included_42test_h_third;
#endif

View File

@ -4,8 +4,7 @@
TOP = ..
include $(TOP)/Makefile
VPATH = $(TOPSRC)/tests $(TOPSRC) $(TOP)
CFLAGS := $(filter-out -W% -g% -O%,$(CFLAGS)) -I$(TOPSRC)
VPATH = $(top_srcdir)/tests
# what tests to run
TESTS = \
@ -13,58 +12,51 @@ TESTS = \
hello-run \
libtest \
test3 \
memtest \
dlltest \
abitest \
vla_test-run \
cross-test \
tests2-dir \
pp-dir
BTESTS = test1b test3b btest
moretests
# test4 -- problem with -static
# asmtest / asmtest2 -- minor differences with gcc
# asmtest -- minor differences with gcc
# btest -- works on i386 (including win32)
# test3 -- win32 does not know how to printf long doubles
# bounds-checking is supported only on i386
ifneq ($(ARCH),i386)
TESTS := $(filter-out $(BTESTS),$(TESTS))
TESTS := $(filter-out btest,$(TESTS))
endif
ifdef CONFIG_WIN32
TESTS := $(filter-out $(BTESTS),$(TESTS))
endif
ifeq ($(TARGETOS),Darwin)
TESTS := $(filter-out hello-exe test3 $(BTESTS),$(TESTS))
endif
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))
endif
ifndef CONFIG_CROSS
TESTS := $(filter-out cross-%,$(TESTS))
ifeq ($(TARGETOS),Darwin)
TESTS := $(filter-out hello-exe test3 btest,$(TESTS))
endif
ifdef CONFIG_WIN32
PATH := $(CURDIR)/$(TOP):$(PATH) # for libtcc_test to find libtcc.dll
ifdef DISABLE_STATIC
export LD_LIBRARY_PATH:=$(CURDIR)/..
endif
ifeq ($(TARGETOS),Darwin)
CFLAGS += -Wl,-flat_namespace,-undefined,warning
TCCFLAGS += -D_ANSI_SOURCE
CFLAGS+=-Wl,-flat_namespace,-undefined,warning
export MACOSX_DEPLOYMENT_TARGET:=10.2
NATIVE_DEFINES+=-D_ANSI_SOURCE
endif
RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS)
# run local version of tcc with local libraries and includes
TCCFLAGS = -B$(TOP)
ifdef CONFIG_WIN32
TCCFLAGS = -B$(top_srcdir)/win32 -I$(top_srcdir)/include -L$(TOP)
endif
TCC = $(TOP)/tcc $(TCCFLAGS)
RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOP)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
all test : clean-s $(TESTS)
# libtcc test
ifdef LIBTCC1
LIBTCC1:=$(TOP)/$(LIBTCC1)
endif
all test : $(TESTS)
hello-exe: ../examples/ex1.c
@echo ------------ $@ ------------
@ -74,85 +66,63 @@ hello-run: ../examples/ex1.c
@echo ------------ $@ ------------
$(TCC) -run $<
libtest: libtcc_test$(EXESUF)
libtest: libtcc_test$(EXESUF) $(LIBTCC1)
@echo ------------ $@ ------------
./libtcc_test$(EXESUF) $(TCCFLAGS)
./libtcc_test$(EXESUF) lib_path=..
libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
libtcc_test$(EXESUF): libtcc_test.c $(top_builddir)/$(LIBTCC)
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS)
%-dir:
moretests:
@echo ------------ $@ ------------
$(MAKE) -k -C $*
$(MAKE) -C tests2
# test.ref - generate using cc
# test.ref - generate using gcc
# copy only tcclib.h so GCC's stddef and stdarg will be used
test.ref: tcctest.c
$(CC) -o tcctest.gcc $< $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
cp ../include/tcclib.h .
gcc -o tcctest.gcc $< -I. $(CPPFLAGS) -w $(CFLAGS) $(NATIVE_DEFINES) -std=gnu99 -O0 -fno-omit-frame-pointer $(LDFLAGS)
./tcctest.gcc > $@
# auto test
test1 test1b: tcctest.c test.ref
test1: test.ref
@echo ------------ $@ ------------
$(TCC) -run $< > test.out1
@diff -u test.ref test.out1 && echo "Auto Test OK"
$(TCC) -run tcctest.c > test.out1
@if diff -u test.ref test.out1 ; then echo "Auto Test OK"; fi
# iterated test2 (compile tcc then compile tcctest.c !)
test2 test2b: tcctest.c test.ref
test2: test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
@diff -u test.ref test.out2 && echo "Auto Test2 OK"
$(TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out2
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3 test3b: tcctest.c test.ref
test3: test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
test%b : TCCFLAGS += -b
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out3
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
# binary output test
test4: tcctest.c test.ref
test4: test.ref
@echo ------------ $@ ------------
# object + link output
$(TCC) -c -o tcctest3.o $<
$(TCC) -c -o tcctest3.o tcctest.c
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
# dynamic output
$(TCC) -o tcctest1 $<
$(TCC) -o tcctest1 tcctest.c
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 $<
$(TCC) -b -o tcctest4 tcctest.c
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
# static output
$(TCC) -static -o tcctest2 $<
$(TCC) -static -o tcctest2 tcctest.c
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@echo ------------ $@ ------------
$(TCC) -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
$(TCC) $(NATIVE_DEFINES) $(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 $(TOPSRC)/libtcc.c
$(TCC) libtcc.o $(LIBS) -shared -o libtcc2$(DLLSUF)
$(TCC) $(NATIVE_DEFINES) $(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) -DONE_SOURCE -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE $(TOPSRC)/tcc.c $(LIBS)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14
BOUNDS_FAIL= 2 5 7 9 11 12 13 15
@ -161,15 +131,15 @@ btest: boundtest.c
@echo ------------ $@ ------------
@for i in $(BOUNDS_OK); do \
echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -run $< $$i ; then \
echo succeeded as expected; \
if $(TCC) -b -run boundtest.c $$i ; then \
echo succeded as expected; \
else\
echo Failed positive test $$i ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -run $< $$i ; then \
if $(TCC) -b -run boundtest.c $$i ; then \
echo Failed negative test $$i ; exit 1 ;\
else\
echo failed as expected; \
@ -181,71 +151,31 @@ btest: boundtest.c
speedtest: ex2 ex3
@echo ------------ $@ ------------
time ./ex2 1238 2 3 4 10 13 4
time $(TCC) -run $(TOPSRC)/examples/ex2.c 1238 2 3 4 10 13 4
time $(TCC) -run $(top_srcdir)/examples/ex2.c 1238 2 3 4 10 13 4
time ./ex3 35
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
time $(TCC) -run $(top_srcdir)/examples/ex3.c 35
weaktest: tcctest.c test.ref
$(TCC) -c $< -o weaktest.tcc.o
$(CC) -c $< -o weaktest.gcc.o $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
weaktest: test.ref
$(TCC) -c tcctest.c -o weaktest.tcc.o $(CPPFLAGS) $(CFLAGS)
$(CC) -c tcctest.c -o weaktest.gcc.o -I. $(CPPFLAGS) -w $(CFLAGS)
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"
ex%: $(TOPSRC)/examples/ex%.c
$(CC) -o $@ $< $(CFLAGS)
ex%: $(top_srcdir)/examples/ex%.c
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
# tiny assembler testing
asmtest.ref: asmtest.S
$(CC) -Wa,-W -o asmtest.ref.o -c asmtest.S
objdump -D asmtest.ref.o > asmtest.ref
asmtest asmtest2: asmtest.ref
asmtest: asmtest.ref
@echo ------------ $@ ------------
$(TCC) $(MAYBE_RUN_TCC) -c asmtest.S
$(TCC) -c asmtest.S
objdump -D asmtest.o > asmtest.out
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
# test assembler with tcc compiled by itself
asmtest2: MAYBE_RUN_TCC = $(RUN_TCC)
# Check that code generated by libtcc is binary compatible with
# that generated by CC
abitest-cc$(EXESUF): abitest.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
abitest-tcc$(EXESUF): abitest.c libtcc.c
$(TCC) -o $@ $^ $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS)
ABITESTS := abitest-cc$(EXESUF)
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
ABITESTS += abitest-tcc$(EXESUF)
endif
abitest: $(ABITESTS)
@echo ------------ $@ ------------
./abitest-cc$(EXESUF) $(TCCFLAGS)
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
./abitest-tcc$(EXESUF) $(TCCFLAGS)
endif
vla_test$(EXESUF): vla_test.c
$(TCC) -o $@ $^
vla_test-run: vla_test$(EXESUF)
@echo ------------ $@ ------------
./vla_test$(EXESUF)
cross-test :
@echo ------------ $@ ------------
$(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
$(TOP)/arm-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 $@ $<
@ -263,12 +193,7 @@ 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 *.def weaktest.*.txt
$(MAKE) -C tests2 $@
$(MAKE) -C pp $@
rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.gcc *.exe \
hello libtcc_test tcctest[1234] ex? tcc_g tcclib.h
# silent clean, used before running tests
clean-s:
@$(MAKE) -s --no-print-directory clean

View File

@ -1,657 +0,0 @@
#include <libtcc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
#if defined(_WIN32) && defined(__GNUC__)
#define LONG_DOUBLE double
#define LONG_DOUBLE_LITERAL(x) x
#else
#define LONG_DOUBLE long double
#define LONG_DOUBLE_LITERAL(x) x ## L
#endif
static int g_argc;
static char **g_argv;
static void set_options(TCCState *s, int argc, char **argv)
{
int i;
for (i = 1; i < argc; ++i) {
char *a = argv[i];
if (a[0] == '-') {
if (a[1] == 'B')
tcc_set_lib_path(s, a+2);
else if (a[1] == 'I')
tcc_add_include_path(s, a+2);
else if (a[1] == 'L')
tcc_add_library_path(s, a+2);
}
}
}
typedef int (*callback_type) (void*);
/*
* Compile source code and call a callback with a pointer to the symbol "f".
*/
static int run_callback(const char *src, callback_type callback) {
TCCState *s;
int result;
void *ptr;
s = tcc_new();
if (!s)
return -1;
set_options(s, g_argc, g_argv);
if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1)
return -1;
if (tcc_compile_string(s, src) == -1)
return -1;
if (tcc_relocate(s, TCC_RELOCATE_AUTO) == -1)
return -1;
ptr = tcc_get_symbol(s, "f");
if (!ptr)
return -1;
result = callback(ptr);
tcc_delete(s);
return result;
}
#define STR2(x) #x
#define STR(x) STR2(x)
#define RET_PRIMITIVE_TEST(name, type, val) \
static int ret_ ## name ## _test_callback(void *ptr) { \
type (*callback) (type) = (type(*)(type))ptr; \
type x = val; \
type y = callback(x); \
return (y == x+x) ? 0 : -1; \
} \
\
static int ret_ ## name ## _test(void) { \
const char *src = STR(type) " f(" STR(type) " x) {return x+x;}"; \
return run_callback(src, ret_ ## name ## _test_callback); \
}
RET_PRIMITIVE_TEST(int, int, 70000)
RET_PRIMITIVE_TEST(longlong, long long, 4333369356528LL)
RET_PRIMITIVE_TEST(float, float, 63.0)
RET_PRIMITIVE_TEST(double, double, 14789798.0)
RET_PRIMITIVE_TEST(longdouble, LONG_DOUBLE, LONG_DOUBLE_LITERAL(378943892.0))
/*
* ret_2float_test:
*
* On x86-64, a struct with 2 floats should be packed into a single
* SSE register (VT_DOUBLE is used for this purpose).
*/
typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;
typedef ret_2float_test_type (*ret_2float_test_function_type) (ret_2float_test_type);
static int ret_2float_test_callback(void *ptr) {
ret_2float_test_function_type f = (ret_2float_test_function_type)ptr;
ret_2float_test_type a = {10, 35};
ret_2float_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int ret_2float_test(void) {
const char *src =
"typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;"
"ret_2float_test_type f(ret_2float_test_type a) {\n"
" ret_2float_test_type r = {a.x*5, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, ret_2float_test_callback);
}
/*
* ret_2double_test:
*
* On x86-64, a struct with 2 doubles should be passed in two SSE
* registers.
*/
typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;
typedef ret_2double_test_type (*ret_2double_test_function_type) (ret_2double_test_type);
static int ret_2double_test_callback(void *ptr) {
ret_2double_test_function_type f = (ret_2double_test_function_type)ptr;
ret_2double_test_type a = {10, 35};
ret_2double_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int ret_2double_test(void) {
const char *src =
"typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
"ret_2double_test_type f(ret_2double_test_type a) {\n"
" ret_2double_test_type r = {a.x*5, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, ret_2double_test_callback);
}
/*
* ret_8plus2double_test:
*
* This catches a corner case in the x86_64 ABI code: the first 7
* arguments fit into registers, the 8th doesn't, but the 9th argument
* fits into the 8th XMM register.
*
* Note that the purpose of the 10th argument is to avoid a situation
* in which gcc would accidentally put the double at the right
* address, thus causing a success message even though TCC actually
* generated incorrect code.
*/
typedef ret_2double_test_type (*ret_8plus2double_test_function_type) (double, double, double, double, double, double, double, ret_2double_test_type, double, double);
static int ret_8plus2double_test_callback(void *ptr) {
ret_8plus2double_test_function_type f = (ret_8plus2double_test_function_type)ptr;
ret_2double_test_type a = {10, 35};
ret_2double_test_type r;
r = f(0, 0, 0, 0, 0, 0, 0, a, 37, 38);
return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
}
static int ret_8plus2double_test(void) {
const char *src =
"typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
"ret_2double_test_type f(double x1, double x2, double x3, double x4, double x5, double x6, double x7, ret_2double_test_type a, double x8, double x9) {\n"
" ret_2double_test_type r = { x8, x8 };\n"
" return r;\n"
"}\n";
return run_callback(src, ret_8plus2double_test_callback);
}
/*
* ret_mixed_test:
*
* On x86-64, a struct with a double and a 64-bit integer should be
* passed in one SSE register and one integer register.
*/
typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;
typedef ret_mixed_test_type (*ret_mixed_test_function_type) (ret_mixed_test_type);
static int ret_mixed_test_callback(void *ptr) {
ret_mixed_test_function_type f = (ret_mixed_test_function_type)ptr;
ret_mixed_test_type a = {10, 35};
ret_mixed_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int ret_mixed_test(void) {
const char *src =
"typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;"
"ret_mixed_test_type f(ret_mixed_test_type a) {\n"
" ret_mixed_test_type r = {a.x*5, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, ret_mixed_test_callback);
}
/*
* ret_mixed2_test:
*
* On x86-64, a struct with two floats and two 32-bit integers should
* be passed in one SSE register and one integer register.
*/
typedef struct ret_mixed2_test_type_s {float x,x2; int y,y2;} ret_mixed2_test_type;
typedef ret_mixed2_test_type (*ret_mixed2_test_function_type) (ret_mixed2_test_type);
static int ret_mixed2_test_callback(void *ptr) {
ret_mixed2_test_function_type f = (ret_mixed2_test_function_type)ptr;
ret_mixed2_test_type a = {10, 5, 35, 7 };
ret_mixed2_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int ret_mixed2_test(void) {
const char *src =
"typedef struct ret_mixed2_test_type_s {float x, x2; int y,y2;} ret_mixed2_test_type;"
"ret_mixed2_test_type f(ret_mixed2_test_type a) {\n"
" ret_mixed2_test_type r = {a.x*5, 0, a.y*3, 0};\n"
" return r;\n"
"}\n";
return run_callback(src, ret_mixed2_test_callback);
}
/*
* ret_mixed3_test:
*
* On x86-64, this struct should be passed in two integer registers.
*/
typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;
typedef ret_mixed3_test_type (*ret_mixed3_test_function_type) (ret_mixed3_test_type);
static int ret_mixed3_test_callback(void *ptr) {
ret_mixed3_test_function_type f = (ret_mixed3_test_function_type)ptr;
ret_mixed3_test_type a = {10, 5, 35, 7 };
ret_mixed3_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y2 == a.y*3)) ? 0 : -1;
}
static int ret_mixed3_test(void) {
const char *src =
"typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;"
"ret_mixed3_test_type f(ret_mixed3_test_type a) {\n"
" ret_mixed3_test_type r = {a.x*5, 0, 0, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, ret_mixed3_test_callback);
}
/*
* reg_pack_test: return a small struct which should be packed into
* registers (Win32) during return.
*/
typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
static int reg_pack_test_callback(void *ptr) {
reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
reg_pack_test_type a = {10, 35};
reg_pack_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int reg_pack_test(void) {
const char *src =
"typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
"reg_pack_test_type f(reg_pack_test_type a) {\n"
" reg_pack_test_type r = {a.x*5, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, reg_pack_test_callback);
}
/*
* reg_pack_longlong_test: return a small struct which should be packed into
* registers (x86-64) during return.
*/
typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;
typedef reg_pack_longlong_test_type (*reg_pack_longlong_test_function_type) (reg_pack_longlong_test_type);
static int reg_pack_longlong_test_callback(void *ptr) {
reg_pack_longlong_test_function_type f = (reg_pack_longlong_test_function_type)ptr;
reg_pack_longlong_test_type a = {10, 35};
reg_pack_longlong_test_type r;
r = f(a);
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
}
static int reg_pack_longlong_test(void) {
const char *src =
"typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
"reg_pack_longlong_test_type f(reg_pack_longlong_test_type a) {\n"
" reg_pack_longlong_test_type r = {a.x*5, a.y*3};\n"
" return r;\n"
"}\n";
return run_callback(src, reg_pack_longlong_test_callback);
}
/*
* ret_6plus2longlong_test:
*
* This catches a corner case in the x86_64 ABI code: the first 5
* arguments fit into registers, the 6th doesn't, but the 7th argument
* fits into the 6th argument integer register, %r9.
*
* Note that the purpose of the 10th argument is to avoid a situation
* in which gcc would accidentally put the longlong at the right
* address, thus causing a success message even though TCC actually
* generated incorrect code.
*/
typedef reg_pack_longlong_test_type (*ret_6plus2longlong_test_function_type) (long long, long long, long long, long long, long long, reg_pack_longlong_test_type, long long, long long);
static int ret_6plus2longlong_test_callback(void *ptr) {
ret_6plus2longlong_test_function_type f = (ret_6plus2longlong_test_function_type)ptr;
reg_pack_longlong_test_type a = {10, 35};
reg_pack_longlong_test_type r;
r = f(0, 0, 0, 0, 0, a, 37, 38);
return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
}
static int ret_6plus2longlong_test(void) {
const char *src =
"typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
"reg_pack_longlong_test_type f(long long x1, long long x2, long long x3, long long x4, long long x5, reg_pack_longlong_test_type a, long long x8, long long x9) {\n"
" reg_pack_longlong_test_type r = { x8, x8 };\n"
" return r;\n"
"}\n";
return run_callback(src, ret_6plus2longlong_test_callback);
}
/*
* sret_test: Create a struct large enough to be returned via sret
* (hidden pointer as first function argument)
*/
typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;
typedef sret_test_type (*sret_test_function_type) (sret_test_type);
static int sret_test_callback(void *ptr) {
sret_test_function_type f = (sret_test_function_type)(ptr);
sret_test_type x = {5436LL, 658277698LL, 43878957LL};
sret_test_type r = f(x);
return ((r.a==x.a*35)&&(r.b==x.b*19)&&(r.c==x.c*21)) ? 0 : -1;
}
static int sret_test(void) {
const char *src =
"typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;\n"
"sret_test_type f(sret_test_type x) {\n"
" sret_test_type r = {x.a*35, x.b*19, x.c*21};\n"
" return r;\n"
"}\n";
return run_callback(src, sret_test_callback);
}
/*
* one_member_union_test:
*
* In the x86-64 ABI a union should always be passed on the stack. However
* it appears that a single member union is treated by GCC as its member.
*/
typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;
typedef one_member_union_test_type (*one_member_union_test_function_type) (one_member_union_test_type);
static int one_member_union_test_callback(void *ptr) {
one_member_union_test_function_type f = (one_member_union_test_function_type)ptr;
one_member_union_test_type a, b;
a.x = 34;
b = f(a);
return (b.x == a.x*2) ? 0 : -1;
}
static int one_member_union_test(void) {
const char *src =
"typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;\n"
"one_member_union_test_type f(one_member_union_test_type a) {\n"
" one_member_union_test_type b;\n"
" b.x = a.x * 2;\n"
" return b;\n"
"}\n";
return run_callback(src, one_member_union_test_callback);
}
/*
* two_member_union_test:
*
* In the x86-64 ABI a union should always be passed on the stack.
*/
typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;
typedef two_member_union_test_type (*two_member_union_test_function_type) (two_member_union_test_type);
static int two_member_union_test_callback(void *ptr) {
two_member_union_test_function_type f = (two_member_union_test_function_type)ptr;
two_member_union_test_type a, b;
a.x = 34;
b = f(a);
return (b.x == a.x*2) ? 0 : -1;
}
static int two_member_union_test(void) {
const char *src =
"typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;\n"
"two_member_union_test_type f(two_member_union_test_type a) {\n"
" two_member_union_test_type b;\n"
" b.x = a.x * 2;\n"
" return b;\n"
"}\n";
return run_callback(src, two_member_union_test_callback);
}
/*
* Win64 calling convetntion test.
*/
typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
typedef many_struct_test_type (*many_struct_test_function_type) (many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type);
static int many_struct_test_callback(void *ptr) {
many_struct_test_function_type f = (many_struct_test_function_type)ptr;
many_struct_test_type v = {1, 2, 3};
many_struct_test_type r = f(v,v,v,v,v,v);
return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1;
}
static int many_struct_test(void) {
const char *src =
"typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n"
"many_struct_test_type f(many_struct_test_type x1, many_struct_test_type x2, many_struct_test_type x3, many_struct_test_type x4, many_struct_test_type x5, many_struct_test_type x6) {\n"
" many_struct_test_type y;\n"
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
" y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n"
" return y;\n"
"}\n";
return run_callback(src, many_struct_test_callback);
}
/*
* Win64 calling convention test.
*/
typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;
typedef many_struct_test_2_type (*many_struct_test_2_function_type) (many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type);
static int many_struct_test_2_callback(void *ptr) {
many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr;
many_struct_test_2_type v = {1,2};
many_struct_test_2_type r = f(v,v,v,v,v,v);
return ((r.a == 6) && (r.b == 12))?0:-1;
}
static int many_struct_test_2(void) {
const char *src =
"typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n"
"many_struct_test_2_type f(many_struct_test_2_type x1, many_struct_test_2_type x2, many_struct_test_2_type x3, many_struct_test_2_type x4, many_struct_test_2_type x5, many_struct_test_2_type x6) {\n"
" many_struct_test_2_type y;\n"
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
" return y;\n"
"}\n";
return run_callback(src, many_struct_test_2_callback);
}
/*
* Win64 calling convention test.
*/
typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;
typedef many_struct_test_3_type (*many_struct_test_3_function_type) (many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type, ...);
typedef struct many_struct_test_3_struct_type { many_struct_test_3_function_type f; many_struct_test_3_function_type *f2; } many_struct_test_3_struct_type;
static void many_struct_test_3_dummy(double d, ...)
{
volatile double x = d;
}
static int many_struct_test_3_callback(void *ptr) {
many_struct_test_3_struct_type s = { ptr, };
many_struct_test_3_struct_type *s2 = &s;
s2->f2 = &s2->f;
many_struct_test_3_dummy(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, &s2);
many_struct_test_3_function_type f = *(s2->f2);
many_struct_test_3_type v = {1,2};
many_struct_test_3_type r = (*((s2->f2=&f)+0))(v,v,v,v,v,v,1.0);
return ((r.a == 6) && (r.b == 12))?0:-1;
}
static int many_struct_test_3(void) {
const char *src =
"typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;\n"
"many_struct_test_3_type f(many_struct_test_3_type x1, many_struct_test_3_type x2, many_struct_test_3_type x3, many_struct_test_3_type x4, many_struct_test_3_type x5, many_struct_test_3_type x6, ...) {\n"
" many_struct_test_3_type y;\n"
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
" return y;\n"
"}\n";
return run_callback(src, many_struct_test_3_callback);
}
/*
* stdarg_test: Test variable argument list ABI
*/
typedef struct {long long a, b, c;} stdarg_test_struct_type;
typedef void (*stdarg_test_function_type) (int,int,int,...);
static int stdarg_test_callback(void *ptr) {
stdarg_test_function_type f = (stdarg_test_function_type)ptr;
int x;
double y;
stdarg_test_struct_type z = {1, 2, 3}, w;
f(10, 10, 5,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x,
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y,
z, z, z, z, z, &w);
return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1;
}
static int stdarg_test(void) {
const char *src =
"#include <stdarg.h>\n"
"typedef struct {long long a, b, c;} stdarg_test_struct_type;\n"
"void f(int n_int, int n_float, int n_struct, ...) {\n"
" int i, ti = 0;\n"
" double td = 0.0;\n"
" stdarg_test_struct_type ts = {0,0,0}, tmp;\n"
" va_list ap;\n"
" va_start(ap, n_struct);\n"
" for (i = 0, ti = 0; i < n_int; ++i)\n"
" ti += va_arg(ap, int);\n"
" *va_arg(ap, int*) = ti;\n"
" for (i = 0, td = 0; i < n_float; ++i)\n"
" td += va_arg(ap, double);\n"
" *va_arg(ap, double*) = td;\n"
" for (i = 0; i < n_struct; ++i) {\n"
" tmp = va_arg(ap, stdarg_test_struct_type);\n"
" ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;"
" }\n"
" *va_arg(ap, stdarg_test_struct_type*) = ts;\n"
" va_end(ap);"
"}\n";
return run_callback(src, stdarg_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.
*/
typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;
typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...);
static int stdarg_struct_test_callback(void *ptr) {
stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr;
stdarg_struct_test_struct_type v = {10, 35, 99};
int x = f(v, 234);
return (x == 378) ? 0 : -1;
}
static int stdarg_struct_test(void) {
const char *src =
"#include <stdarg.h>\n"
"typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n"
"int f(stdarg_struct_test_struct_type a, ...) {\n"
" va_list ap;\n"
" va_start(ap, a);\n"
" int z = va_arg(ap, int);\n"
" va_end(ap);\n"
" return z + a.a + a.b + a.c;\n"
"}\n";
return run_callback(src, stdarg_struct_test_callback);
}
/* Test that x86-64 arranges the stack correctly for arguments with alignment >8 bytes */
typedef LONG_DOUBLE (*arg_align_test_callback_type) (LONG_DOUBLE,int,LONG_DOUBLE,int,LONG_DOUBLE);
static int arg_align_test_callback(void *ptr) {
arg_align_test_callback_type f = (arg_align_test_callback_type)ptr;
long double x = f(12, 0, 25, 0, 37);
return (x == 74) ? 0 : -1;
}
static int arg_align_test(void) {
const char *src =
"long double f(long double a, int b, long double c, int d, long double e) {\n"
" return a + c + e;\n"
"}\n";
return run_callback(src, arg_align_test_callback);
}
#define RUN_TEST(t) \
if (!testname || (strcmp(#t, testname) == 0)) { \
fputs(#t "... ", stdout); \
fflush(stdout); \
if (t() == 0) { \
fputs("success\n", stdout); \
} else { \
fputs("failure\n", stdout); \
retval = EXIT_FAILURE; \
} \
}
int main(int argc, char **argv) {
int i;
const char *testname = NULL;
int retval = EXIT_SUCCESS;
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < argc; ++i) {
if (!memcmp(argv[i], "run_test=", 9))
testname = argv[i] + 9;
}
g_argv = argv, g_argc = argc;
RUN_TEST(ret_int_test);
RUN_TEST(ret_longlong_test);
RUN_TEST(ret_float_test);
RUN_TEST(ret_double_test);
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_mixed3_test);
RUN_TEST(reg_pack_test);
RUN_TEST(reg_pack_longlong_test);
RUN_TEST(sret_test);
RUN_TEST(one_member_union_test);
RUN_TEST(two_member_union_test);
RUN_TEST(many_struct_test);
RUN_TEST(many_struct_test_2);
RUN_TEST(many_struct_test_3);
RUN_TEST(stdarg_test);
RUN_TEST(stdarg_struct_test);
RUN_TEST(arg_align_test);
return retval;
}

View File

@ -11,22 +11,14 @@
.align 8
.byte 1
/* .align 16, 0x90 gas is too clever for us with 0x90 fill */
.balign 4, 0x92
.align 16, 0x91 /* 0x91 tests the non-clever behaviour */
.skip 3
.skip 15, 0x90
.string "hello\0world"
/* Macro expansion should work like with C, the #n shouldn't be parsed
as asm line comment */
#define __stringify(n) #n
#define stringify(n) __stringify(n)
.skip 8,0x90
.asciz stringify(BLA)
.skip 8,0x90
# 28 "asmtest.S" # a line directive (and a line comment)
movl %eax, %ebx # some more asm comment
/* some label tests */
movl %eax, %ebx
L1:
movl %eax, %ebx
mov 0x10000, %eax
@ -46,7 +38,7 @@ mov %al, 0x10000
mov $1, %edx
mov $1, %dx
mov $1, %cl
mov $1, %dl
movb $2, 0x100(%ebx,%edx,2)
movw $2, 0x100(%ebx,%edx,2)
movl $2, 0x100(%ebx,%edx,2)
@ -54,55 +46,17 @@ movl %eax, 0x100(%ebx,%edx,2)
movl 0x100(%ebx,%edx,2), %edx
movw %ax, 0x100(%ebx,%edx,2)
movw $0x1122,%si
movl $0x112233,%edx
movl $0x80000000, %esi
movl $-0x7fffffff, %edi
#ifdef __x86_64__
mov $0x11223344,%rbx
movq $0x11223344,%rbx
mov $0x1122334455,%rbx
movq $0x1122334455,%rbx
movl $0x11334455,(%rbx)
#endif
mov %eax, 0x12(,%edx,2)
#ifdef __i386__
mov %cr3, %edx
mov %ecx, %cr3
movl %cr3, %eax
movl %tr3, %eax
movl %db3, %ebx
movl %dr6, %eax
#else
mov %cr3, %rdx
mov %rcx, %cr3
movq %cr3, %rax
movq %db3, %rbx
movq %dr6, %rax
mov %cr8, %rsi
mov %rdi, %cr8
#endif
movl %fs, %ecx
movl %ebx, %fs
#ifdef __x86_64__
movq %r8, %r9
movq %r10, %r11
movq %r12, %r13
movq %r14, %r15
movq %rax, %r9
movq %r15, %rsi
inc %r9b
dec %r10w
not %r11d
negq %r12
decb %r13b
incw %r14w
notl %r15d
#endif
movsbl 0x1000, %eax
movsbw 0x1000, %ax
movswl 0x1000, %eax
@ -114,47 +68,19 @@ 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__
pushl %eax
pushw %ax
push %eax
push %cs
#else
pushq %rax
push %rax
#endif
pushw %ax
push %gs
push $1
push $100
push 0x42(%eax)
pop 0x43(%esi)
#ifdef __i386__
popl %eax
popw %ax
pop %eax
pop %ds
#else
popq %rax
pop %rax
#endif
popw %ax
pop %fs
xchg %eax, %ecx
@ -185,34 +111,14 @@ notl %r15d
leal 0x1000(%ebx), %ecx
lea 0x1000(%ebx), %ecx
#ifdef __i386__
les 0x2000, %eax
lds 0x2000, %ebx
lss 0x2000, %edx
#endif
lfs 0x2000, %ecx
lgs 0x2000, %edx
lss 0x2000, %edx
addl $0x123, %eax
add $0x123, %ebx
add $-16, %ecx
add $-0x123, %esi
add $1, %bx
add $1, %ebx
add $-1, %bx
add $-1, %ebx
add $127, %bx
addl $127, %ebx
addl $-128, %ebx
addl $-128, %ebx
addl $-129, %ebx
addl $128, %ebx
addl $255, %ebx
addl $256, %ebx
andb $0xf, %ah
andb $-15, %cl
xorb $127, %dh
cmpb $42, (%eax)
addl $0x123, 0x100
addl $0x123, 0x100(%ebx)
addl $0x123, 0x100(%ebx,%edx,2)
@ -222,24 +128,6 @@ addl $0x123, (%ebp)
addl $0x123, (%esp)
cmpl $0x123, (%esp)
#ifdef __x86_64__
xor %bl,%ah
xor %bl,%r8b
xor %r9b,%bl
xor %sil,%cl
add %eax,(%r8d)
add %ebx,(%r9)
add %edx,(%r10d,%r11d)
add %ecx,(%r12,%r13)
add %esi,(%r14,%r15,4)
add %edi,0x1000(%rbx,%r12,8)
add %r11,0x1000(%ebp,%r9d,8)
movb $12, %ah
movb $13, %bpl
movb $14, %dil
movb $15, %r12b
#endif
add %eax, (%ebx)
add (%ebx), %eax
@ -291,8 +179,6 @@ add (%ebx), %dl
div %bl
div %ecx, %eax
and $15,%bx
and $-20,%edx
shl %edx
shl $10, %edx
@ -309,11 +195,7 @@ shrd %eax, %edx
L4:
call 0x1000
call L4
#ifdef __i386__
call *%eax
#else
call *%rax
#endif
call *0x1000
call func1
@ -322,40 +204,19 @@ call func1
L5:
L6:
#ifdef __i386__
lcall $0x100, $0x1000
#else
lcall *0x100
lcall *(%rax)
#endif
jmp 0x1000
jmp *(%edi)
#ifdef __i386__
jmp *%eax
#else
jmp *%rax
#endif
jmp *0x1000
#ifdef __i386__
ljmp $0x100, $0x1000
#else
ljmp *0x100
ljmp *(%rdi)
ljmpl *(%esi)
ljmpw *(%esi)
#endif
ret
ret $10
#ifdef __i386__
retl
ret $10
retl $10
#else
retq
retq $10
#endif
lret
@ -383,8 +244,6 @@ L3:
seto %al
setc %al
setcb %al
setnp 0x1000
setl 0xaaaa
setg %dl
@ -542,7 +401,6 @@ L3:
fwait
bswap %edx
bswapl %ecx
xadd %ecx, %edx
xaddb %dl, 0x1000
xaddw %ax, 0x1000
@ -553,10 +411,6 @@ cmpxchgw %ax, 0x1000
cmpxchgl %eax, 0x1000
invlpg 0x1000
cmpxchg8b 0x1002
#ifdef __x86_64__
cmpxchg16b (%rax)
cmpxchg16b (%r10,%r11)
#endif
fcmovb %st(5), %st
fcmove %st(5), %st
@ -576,48 +430,32 @@ fucomip %st(5), %st
cmovo 0x1000, %eax
cmovs 0x1000, %eax
cmovns %edx, %edi
cmovne %ax, %si
#ifdef __x86_64__
bswapq %rsi
bswapq %r10
cmovz %rdi,%rbx
#endif
int $3
int $0x10
#ifdef __i386__
pusha
popa
#endif
clc # another comment
cld # a comment with embedded ' tick
clc
cld
cli
clts
cmc
lahf
sahf
#ifdef __i386__
pushfl
popfl
#else
pushfq
popfq
#endif
pushf
popf
stc
std
sti
#ifdef __i386__
aaa
aas
daa
das
aad
aam
into
#endif
cbw
cwd
cwde
@ -628,6 +466,7 @@ int $0x10
cltd
leave
int3
into
iret
rsm
hlt
@ -672,34 +511,7 @@ int $0x10
rdmsr
rdpmc
ud2
#ifdef __x86_64__
syscall
sysret
sysretq
lfence
mfence
sfence
prefetchnta 0x18(%rdx)
prefetcht0 (%rcx)
prefetcht1 (%rsi)
prefetcht2 (%rdi)
prefetchw (%rdi)
clflush 0x1000(%rax,%rcx)
fxsaveq (%rdx)
fxsaveq (%r11)
fxrstorq (%rcx)
fxrstorq (%r10)
#endif
lar %ax,%dx
lar %eax,%dx
lar %ax,%edx
lar %eax,%edx
#ifdef __x86_64__
lar %ax,%rdx
lar %eax,%rdx
#endif
emms
movd %edx, %mm3
movd 0x1000, %mm2
@ -744,58 +556,36 @@ int $0x10
#ifdef __i386__
boundl %edx, 0x10000
boundw %bx, 0x1000
arpl %bx, 0x1000
#endif
lar 0x1000, %eax
lgdt 0x1000
lidt 0x1000
lldt 0x1000
sgdt 0x1000
sidt 0x1000
sldt 0x1000
#ifdef __x86_64__
lgdtq 0x1000
lidtq 0x1000
sgdtq 0x1000
sidtq 0x1000
swapgs
str %rdx
str %r9
#endif
lmsw 0x1000
lsl 0x1000, %ecx
ltr 0x1000
ltr %si
sgdt 0x1000
sidt 0x1000
sldt 0x1000
smsw 0x1000
str 0x1000
str %ecx
str %dx
verr 0x1000
verw 0x1000
#ifdef __i386__
push %ds
pushw %ds
pushl %ds
pop %ds
popw %ds
popl %ds
#endif
fxsave 1(%ebx)
fxrstor 1(%ecx)
#ifdef __i386__
pushl $1
#else
pushq $1
#endif
pushw $1
push $1
@ -803,7 +593,6 @@ int $0x10
inc %eax
#endif
#ifndef _WIN32
ft1: ft2: ft3: ft4: ft5: ft6: ft7: ft8: ft9:
xor %eax, %eax
ret
@ -816,160 +605,5 @@ ft1: ft2: ft3: ft4: ft5: ft6: ft7: ft8: ft9:
.type ft6,@function
.type ft7,%function
.type ft8,"function"
#endif
pause
.rept 6
nop
.endr
.fill 4,1,0x90
.section .text.one,"ax"
nop
.previous
.pushsection .text.one,"ax"
nop
.pushsection .text.two,"ax"
nop
.popsection
.popsection
1: ud2
.pushsection __bug_table,"a"
.align 8
2: .long 1b - 2b
.long 0x600000 - 2b
.long 1b + 42
.long 43 + 1b
.long 2b + 144
.long 145 + 2b
.word 164, 0
.org 2b+32
#ifdef __x86_64__
.quad 1b
#else
.long 1b
#endif
.popsection
3: mov %eax,%ecx
4:
.pushsection .text.three, "ax"
nop
.skip (-((4b-3b) > 0) * 2) , 0x90
.popsection
.globl overrideme
.weak overrideme
nop
.globl notimplemented
notimplemented:
ret
.set overrideme, notimplemented
overrideme = notimplemented
overrideme:
ret
movd %esi, %mm1
movd %edi, %xmm2
movd (%ebx), %mm3
movd (%ebx), %xmm3
movd %mm1, %esi
movd %xmm2, %edi
movd %mm3, (%edx)
movd %xmm3, (%edx)
#ifdef __x86_64__
movd %rsi, %mm1
movd %rdi, %xmm2
movd (%rbx), %mm3
movd (%rbx), %xmm3
movd %mm1, %r12
movd %xmm2, %rdi
movd %mm3, (%r8)
movd %xmm3, (%r13)
#endif
movq (%ebp), %mm1
movq %mm2, (%edi)
movq (%edi), %xmm3
movq %mm4, %mm5
#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). */
movq (%rsi), %xmm3
movq %mm1, %rdx
movq %xmm3, %rcx
movq %xmm4, (%rsi)
#endif
#define TEST_MMX_SSE(insn) \
insn %mm1, %mm2; \
insn %xmm2, %xmm3; \
insn (%ebx), %xmm3;
#define TEST_MMX_SSE_I8(insn) \
TEST_MMX_SSE(insn) \
insn $0x42, %mm4; \
insn $0x42, %xmm4;
TEST_MMX_SSE(packssdw)
TEST_MMX_SSE(packsswb)
TEST_MMX_SSE(packuswb)
TEST_MMX_SSE(paddb)
TEST_MMX_SSE(paddw)
TEST_MMX_SSE(paddd)
TEST_MMX_SSE(paddsb)
TEST_MMX_SSE(paddsw)
TEST_MMX_SSE(paddusb)
TEST_MMX_SSE(paddusw)
TEST_MMX_SSE(pand)
TEST_MMX_SSE(pandn)
TEST_MMX_SSE(pcmpeqb)
TEST_MMX_SSE(pcmpeqw)
TEST_MMX_SSE(pcmpeqd)
TEST_MMX_SSE(pcmpgtb)
TEST_MMX_SSE(pcmpgtw)
TEST_MMX_SSE(pcmpgtd)
TEST_MMX_SSE(pmaddwd)
TEST_MMX_SSE(pmulhw)
TEST_MMX_SSE(pmullw)
TEST_MMX_SSE(por)
TEST_MMX_SSE(psllw)
TEST_MMX_SSE_I8(psllw)
TEST_MMX_SSE(pslld)
TEST_MMX_SSE_I8(pslld)
TEST_MMX_SSE(psllq)
TEST_MMX_SSE_I8(psllq)
TEST_MMX_SSE(psraw)
TEST_MMX_SSE_I8(psraw)
TEST_MMX_SSE(psrad)
TEST_MMX_SSE_I8(psrad)
TEST_MMX_SSE(psrlw)
TEST_MMX_SSE_I8(psrlw)
TEST_MMX_SSE(psrld)
TEST_MMX_SSE_I8(psrld)
TEST_MMX_SSE(psrlq)
TEST_MMX_SSE_I8(psrlq)
TEST_MMX_SSE(psubb)
TEST_MMX_SSE(psubw)
TEST_MMX_SSE(psubd)
TEST_MMX_SSE(psubsb)
TEST_MMX_SSE(psubsw)
TEST_MMX_SSE(psubusb)
TEST_MMX_SSE(psubusw)
TEST_MMX_SSE(punpckhbw)
TEST_MMX_SSE(punpckhwd)
TEST_MMX_SSE(punpckhdq)
TEST_MMX_SSE(punpcklbw)
TEST_MMX_SSE(punpcklwd)
TEST_MMX_SSE(punpckldq)
TEST_MMX_SSE(pxor)
cvtpi2ps %mm1, %xmm2
cvtpi2ps (%ebx), %xmm2
TEST_MMX_SSE(pmaxsw)
TEST_MMX_SSE(pmaxub)
TEST_MMX_SSE(pminsw)
TEST_MMX_SSE(pminub)

View File

@ -1,6 +1,5 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NB_ITS 1000000
//#define NB_ITS 1
@ -50,15 +49,12 @@ int test4(void)
int i, sum = 0;
int *tab4;
fprintf(stderr, "%s start\n", __FUNCTION__);
tab4 = malloc(20 * sizeof(int));
for(i=0;i<20;i++) {
sum += tab4[i];
}
free(tab4);
fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
@ -68,15 +64,12 @@ int test5(void)
int i, sum = 0;
int *tab4;
fprintf(stderr, "%s start\n", __FUNCTION__);
tab4 = malloc(20 * sizeof(int));
for(i=0;i<21;i++) {
sum += tab4[i];
}
free(tab4);
fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
@ -193,43 +186,8 @@ int test15(void)
return strlen(p);
}
/* ok */
int test16()
{
char *demo = "This is only a test.";
char *p;
fprintf(stderr, "%s start\n", __FUNCTION__);
p = alloca(16);
strcpy(p,"12345678901234");
printf("alloca: p is %s\n", p);
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
}
/* error */
int test17()
{
char *demo = "This is only a test.";
char *p;
fprintf(stderr, "%s start\n", __FUNCTION__);
p = alloca(16);
strcpy(p,"12345678901234");
printf("alloca: p is %s\n", p);
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
}
int (*table_test[])(void) = {
test1,
test1,
test2,
test3,
@ -245,33 +203,23 @@ int (*table_test[])(void) = {
test13,
test14,
test15,
test16,
test17,
};
int main(int argc, char **argv)
{
int index;
int (*ftest)(void);
int index_max = sizeof(table_test)/sizeof(table_test[0]);
if (argc < 2) {
printf(
"test TCC bound checking system\n"
"usage: boundtest N\n"
" 1 <= N <= %d\n", index_max);
printf("usage: boundtest n\n"
"test TCC bound checking system\n"
);
exit(1);
}
index = 0;
if (argc >= 2)
index = atoi(argv[1]) - 1;
if ((index < 0) || (index >= index_max)) {
printf("N is outside of the valid range (%d)\n", index);
exit(2);
}
index = atoi(argv[1]);
/* well, we also use bounds on this ! */
ftest = table_test[index];
ftest();

View File

@ -15,16 +15,7 @@ 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"
" if (n <= 2)\n"
@ -35,7 +26,7 @@ char my_program[] =
"\n"
"int foo(int n)\n"
"{\n"
" printf(\"%s\\n\", hello);\n"
" printf(\"Hello World!\\n\");\n"
" printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
" return 0;\n"
@ -44,7 +35,6 @@ char my_program[] =
int main(int argc, char **argv)
{
TCCState *s;
int i;
int (*func)(int);
s = tcc_new();
@ -54,17 +44,8 @@ int main(int argc, char **argv)
}
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < argc; ++i) {
char *a = argv[i];
if (a[0] == '-') {
if (a[1] == 'B')
tcc_set_lib_path(s, a+2);
else if (a[1] == 'I')
tcc_add_include_path(s, a+2);
else if (a[1] == 'L')
tcc_add_library_path(s, a+2);
}
}
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
tcc_set_lib_path(s, argv[1]+9);
/* MUST BE CALLED before any compilation */
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
@ -72,10 +53,9 @@ int main(int argc, char **argv)
if (tcc_compile_string(s, my_program) == -1)
return 1;
/* as a test, we add symbols that the compiled program can use.
/* as a test, we add a symbol that the compiled program can use.
You may also open a dll with tcc_add_dll() and use symbols from that */
tcc_add_symbol(s, "add", add);
tcc_add_symbol(s, "hello", hello);
/* relocate the code */
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)

View File

@ -1,6 +0,0 @@
#define hash_hash # ## #
#define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y);
// char p[] = "x ## y";

View File

@ -1 +0,0 @@
char p[] = "x ## y";

View File

@ -1,28 +0,0 @@
#define x 3
#define f(a) f(x * (a))
#undef x
#define x 2
#define g f
#define z z[0]
#define h g(~
#define m(a) a(w)
#define w 0,1
#define t(a) a
#define p() int
#define q(x) x
#define r(x,y) x ## y
#define str(x) # x
f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
g(x+(3,4)-w) | h 5) & m
(f)^m(m);
char c[2][6] = { str(hello), str() };
/*
* f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
* f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
* char c[2][6] = { "hello", "" };
*/
#define L21 f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
#define L22 g(x+(3,4)-w) | h 5) & m\
(f)^m(m);
L21
L22

View File

@ -1,5 +0,0 @@
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
char c[2][6] = { "hello", "" };
f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);

View File

@ -1,15 +0,0 @@
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
x ## s, x ## t)
#define INCFILE(n) vers ## n
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
== 0) str(: @\n), s);
\#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)

View File

@ -1,5 +0,0 @@
printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
\#include "vers2.h"
"hello";
"hello" ", world"

View File

@ -1,4 +0,0 @@
#define foobar 1
#define C(x,y) x##y
#define D(x) (C(x,bar))
D(foo)

View File

@ -1 +0,0 @@
(1)

View File

@ -1,7 +0,0 @@
#define t(x,y,z) x ## y ## z
#define xxx(s) int s[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), \
t(10,,), t(,11,), t(,,12), t(,,) };
int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
t(10,,), t(,11,), t(,,12), t(,,) };
xxx(j)

View File

@ -1,3 +0,0 @@
int j[] = { 123, 45, 67, 89,
10, 11, 12, };
int j[] = { 123, 45, 67, 89, 10, 11, 12, };

View File

@ -1,5 +0,0 @@
#define X(a,b, \
c,d) \
foo
X(1,2,3,4)

View File

@ -1 +0,0 @@
foo

View File

@ -1,4 +0,0 @@
#define a() YES
#define b() a
b()
b()()

View File

@ -1,2 +0,0 @@
a
YES

View File

@ -1,4 +0,0 @@
// test macro expansion in arguments
#define s_pos s_s.s_pos
#define foo(x) (x)
foo(hej.s_pos)

View File

@ -1 +0,0 @@
(hej.s_s.s_pos)

View File

@ -1,4 +0,0 @@
#define C(a,b,c) a##b##c
#define N(x,y) C(x,_,y)
#define A_O aaaaoooo
N(A,O)

View File

@ -1 +0,0 @@
aaaaoooo

View File

@ -1,10 +0,0 @@
#define f(x) x
#define g(x) f(x) f(x
#define i(x) g(x)) g(x
#define h(x) i(x))) i(x
#define k(x) i(x))) i(x))))
f(x)
g(x))
i(x)))
h(x))))
k(x))))

View File

@ -1,5 +0,0 @@
x
x x
x x x x
x x x x x x x x
x x x x x x x x))))

View File

@ -1,31 +0,0 @@
#define D1(s, ...) s
#define D2(s, ...) s D1(__VA_ARGS__)
#define D3(s, ...) s D2(__VA_ARGS__)
#define D4(s, ...) s D3(__VA_ARGS__)
D1(a)
D2(a, b)
D3(a, b, c)
D4(a, b, c, d)
x D4(a, b, c, d) y
x D4(a, b, c) y
x D4(a, b) y
x D4(a) y
x D4() y
#define GNU_COMMA(X,Y...) X,## Y
x GNU_COMMA(A,B,C) y
x GNU_COMMA(A,B) y
x GNU_COMMA(A) y
x GNU_COMMA() y
#define __sun_attr___noreturn__ __attribute__((__noreturn__))
#define ___sun_attr_inner(__a) __sun_attr_##__a
#define __sun_attr__(__a) ___sun_attr_inner __a
#define __NORETURN __sun_attr__((__noreturn__))
__NORETURN
#define X(...)
#define Y(...) 1 __VA_ARGS__ 2
Y(X X() ())

View File

@ -1,15 +0,0 @@
a
a b
a b c
a b c d
x a b c d y
x a b c y
x a b y
x a y
x y
x A,B,C y
x A,B y
x A y
x y
__attribute__((__noreturn__))
1 2

View File

@ -1,8 +0,0 @@
#define SRC(y...) \
9999: y; \
.section __ex_table, "a"; \
.long 9999b, 6001f ; \
// .previous
SRC(1: movw (%esi), %bx)
6001:

View File

@ -1,2 +0,0 @@
9999: 1: movw (%esi), %bx; .section __ex_table, "a"; .long 9999b, 6001f ;
6001:

View File

@ -1,6 +0,0 @@
# `modelist' label. Each video mode record looks like:
#ifdef AAA
# modelist' label. Each video mode record looks like:
#endif
.text
endtext:

View File

@ -1,3 +0,0 @@
# `modelist' label. Each video mode record looks like:
.text
endtext:

View File

@ -1,13 +0,0 @@
#define W Z
#define Z(X) W(X,2)
#define Y(X) Z(X)
#define X Y
return X(X(1));
#define P Q
#define Q(n) P(n,2)
return P(1);
#define A (B * B)
#define B (A + A)
return A + B;

View File

@ -1,3 +0,0 @@
return Z(Z(1,2),2);
return Q(1,2);
return ((A + A) * (A + A)) + ((B * B) + (B * B));

View File

@ -1,18 +0,0 @@
// insert a space between two tokens if otherwise they
// would form a single token when read back
#define n(x) x
return (n(long)n(double))d;
return n(A)n(++)n(+)n(B);
return n(A)n(+)n(++)n(B);
return n(A)n(++)n(+)n(+)n(B);
// not a hex float
return n(0x1E)n(-1);
// unlike gcc but correct
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);

View File

@ -1,7 +0,0 @@
return (long double)d;
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;

View File

@ -1,3 +0,0 @@
/* The following should warn */
#define A ...
#define A <<=

View File

@ -1,2 +0,0 @@
16.c:3: warning: A redefined

View File

@ -1,14 +0,0 @@
#define STR1(u) # u
#define pass(a) a
#define __ASM_REG(reg) STR1(one##reg)
#define _ASM_DX __ASM_REG(tok)
X162 pass(__ASM_REG(tok))
X161 pass(_ASM_DX)
X163 pass(STR1(one##tok))
X170 pass(x ## y)
X171 pass(x pass(##) y)
#define Y(x) Z(x)
#define X Y
X180 return X(X(1));

View File

@ -1,6 +0,0 @@
X162 "onetok"
X161 "onetok"
X163 "one##tok"
X170 x ## y
X171 x ## y
X180 return Z(Z(1));

View File

@ -1,52 +0,0 @@
#
# credits: 01..13.c from the pcc cpp-tests suite
#
TOP = ../..
include $(TOP)/Makefile
SRC = $(TOPSRC)/tests/pp
VPATH = $(SRC)
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 "^\#"
# 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 $< $(FILTER) >$*.output 2>&1 ; \
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
&& rm -f $*.output
%.test: %.S %.expect
@echo PPTest $* ...
-@$(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
# tell make not to delete
.PRECIOUS: %.expect
clean:
rm -f *.output
02.test : DIFF_OPTS += -w
15.test : DIFF_OPTS += -I"^XXX:"
# diff options:
# -b ighore space changes
# -w ighore all whitespace
# -B ignore blank lines
# -I <RE> ignore lines matching RE

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
static inline const char *get_basefile_from_header(void)
{
return __BASE_FILE__;
}
static inline const char *get_file_from_header(void)
{
return __FILE__;
}

View File

@ -1,510 +0,0 @@
/*
* Test 128-bit floating-point arithmetic on arm64:
* build with two different compilers and compare the output.
*
* Copyright (c) 2015 Edmund Grimley Evans
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__))
void check_fail(const char *assertion, const char *file, unsigned int line)
{
printf("%s:%d: Check (%s) failed.", file, line, assertion);
exit(1);
}
typedef struct {
unsigned long long x0, x1;
} u128_t;
float copy_fi(uint32_t x)
{
float f;
memcpy(&f, &x, 4);
return f;
}
double copy_di(uint64_t x)
{
double f;
memcpy(&f, &x, 8);
return f;
}
long double copy_ldi(u128_t x)
{
long double f;
memcpy(&f, &x, 16);
return f;
}
uint32_t copy_if(float f)
{
uint32_t x;
memcpy(&x, &f, 4);
return x;
}
uint64_t copy_id(double f)
{
uint64_t x;
memcpy(&x, &f, 8);
return x;
}
u128_t copy_ild(long double f)
{
u128_t x;
memcpy(&x, &f, 16);
return x;
}
long double make(int sgn, int exp, uint64_t high, uint64_t low)
{
u128_t x = { low,
(0x0000ffffffffffff & high) |
(0x7fff000000000000 & (uint64_t)exp << 48) |
(0x8000000000000000 & (uint64_t)sgn << 63) };
return copy_ldi(x);
}
void cmp(long double a, long double b)
{
u128_t ax = copy_ild(a);
u128_t bx = copy_ild(b);
int eq = (a == b);
int ne = (a != b);
int lt = (a < b);
int le = (a <= b);
int gt = (a > b);
int ge = (a >= b);
check(eq == 0 || eq == 1);
check(lt == 0 || lt == 1);
check(gt == 0 || gt == 1);
check(ne == !eq && le == (lt | eq) && ge == (gt | eq));
check(eq + lt + gt < 2);
printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n",
ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt);
}
void cmps(void)
{
int i, j;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
cmp(make(i, 0, 0, 0), make(j, 0, 0, 0));
for (i = 0; i < 2; i++) {
for (j = 0; j < 64; j++) {
long double f1 = make(i, 32767, (uint64_t)1 << j, 0);
long double f2 = make(i, 32767, 0, (uint64_t)1 << j);
cmp(f1, 0);
cmp(f2, 0);
cmp(0, f1);
cmp(0, f2);
}
}
for (i = 0; i < 6; i++)
for (j = 0; j < 6; j++)
cmp(make(i & 1, i >> 1, 0, 0),
make(j & 1, j >> 1, 0, 0));
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
int a, b;
for (a = 0; a < 2; a++) {
for (b = 0; b < 2; b++) {
cmp(make(i, j, a, b), make(i, j, 0, 0));
cmp(make(i, j, 0, 0), make(i, j, a, b));
}
}
}
}
}
void xop(const char *name, long double a, long double b, long double c)
{
u128_t ax = copy_ild(a);
u128_t bx = copy_ild(b);
u128_t cx = copy_ild(c);
printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n",
name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0);
}
void fadd(long double a, long double b)
{
xop("add", a, b, a + b);
}
void fsub(long double a, long double b)
{
xop("sub", a, b, a - b);
}
void fmul(long double a, long double b)
{
xop("mul", a, b, a * b);
}
void fdiv(long double a, long double b)
{
xop("div", a, b, a / b);
}
void nanz(void)
{
// Check NaNs:
{
long double x[7];
int i, j, n = 0;
x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53);
x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac);
x[n++] = make(0, 32767, 0, 1);
x[n++] = make(0, 32767, (uint64_t)1 << 46, 0);
x[n++] = make(1, 32767, (uint64_t)1 << 47, 0);
x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9);
x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666);
check(n == sizeof(x) / sizeof(*x));
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
fadd(x[i], x[j]);
fsub(x[i], x[j]);
fmul(x[i], x[j]);
fdiv(x[i], x[j]);
}
}
}
// Check infinities and zeroes:
{
long double x[6];
int i, j, n = 0;
x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044);
x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19);
x[n++] = make(0, 32767, 0, 0);
x[n++] = make(1, 32767, 0, 0);
x[n++] = make(0, 0, 0, 0);
x[n++] = make(1, 0, 0, 0);
check(n == sizeof(x) / sizeof(*x));
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
fadd(x[i], x[j]);
fsub(x[i], x[j]);
fmul(x[i], x[j]);
fdiv(x[i], x[j]);
}
}
}
}
void adds(void)
{
// Check shifting and add/sub:
{
int i;
for (i = -130; i <= 130; i++) {
int s1 = (uint32_t)i % 3 < 1;
int s2 = (uint32_t)i % 5 < 2;
fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031),
make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448));
}
}
// Check normalisation:
{
uint64_t a0 = 0xc6bab0a6afbef5ed;
uint64_t a1 = 0x4f84136c4a2e9b52;
int ee[] = { 0, 1, 10000 };
int e, i;
for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) {
int exp = ee[e];
fsub(make(0, exp, a1, a0), make(0, 0, 0, 0));
for (i = 63; i >= 0; i--)
fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0),
make(0, exp, a1 >> i << i, 0));
for (i = 63; i >=0; i--)
fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1),
make(0, exp, a1, a0 >> i << i));
}
}
// Carry/overflow from rounding:
{
fadd(make(0, 114, -1, -1), make(0, 1, 0, 0));
fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0));
fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0));
}
}
void muls(void)
{
int i, j;
{
long double max = make(0, 32766, -1, -1);
long double min = make(0, 0, 0, 1);
fmul(max, max);
fmul(max, min);
fmul(min, min);
}
for (i = 117; i > 0; i--)
fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a),
make(i & 1, i, 0, 0));
fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1));
// Round to next exponent:
fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1));
// Round from subnormal to normal:
fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0));
for (i = 0; i < 2; i++)
for (j = 0; j < 112; j++)
fmul(make(0, 16383, (uint64_t)1 << i, 0),
make(0, 16383,
j < 64 ? 0 : (uint64_t)1 << (j - 64),
j < 64 ? (uint64_t)1 << j : 0));
}
void divs(void)
{
int i;
{
long double max = make(0, 32766, -1, -1);
long double min = make(0, 0, 0, 1);
fdiv(max, max);
fdiv(max, min);
fdiv(min, max);
fdiv(min, min);
}
for (i = 0; i < 64; i++)
fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i));
for (i = 0; i < 48; i++)
fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0));
}
void cvtlsw(int32_t a)
{
long double f = a;
u128_t x = copy_ild(f);
printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0);
}
void cvtlsx(int64_t a)
{
long double f = a;
u128_t x = copy_ild(f);
printf("cvtlsx %016llx %016llx%016llx\n",
(long long)(uint64_t)a, x.x1, x.x0);
}
void cvtluw(uint32_t a)
{
long double f = a;
u128_t x = copy_ild(f);
printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0);
}
void cvtlux(uint64_t a)
{
long double f = a;
u128_t x = copy_ild(f);
printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0);
}
void cvtil(long double a)
{
u128_t x = copy_ild(a);
int32_t b1 = a;
int64_t b2 = a;
uint32_t b3 = a;
uint64_t b4 = a;
printf("cvtswl %016llx%016llx %08lx\n",
x.x1, x.x0, (long)(uint32_t)b1);
printf("cvtsxl %016llx%016llx %016llx\n",
x.x1, x.x0, (long long)(uint64_t)b2);
printf("cvtuwl %016llx%016llx %08lx\n",
x.x1, x.x0, (long)b3);
printf("cvtuxl %016llx%016llx %016llx\n",
x.x1, x.x0, (long long)b4);
}
void cvtlf(float a)
{
uint32_t ax = copy_if(a);
long double b = a;
u128_t bx = copy_ild(b);
printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0);
}
void cvtld(double a)
{
uint64_t ax = copy_id(a);
long double b = a;
u128_t bx = copy_ild(b);
printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0);
}
void cvtfl(long double a)
{
u128_t ax = copy_ild(a);
float b = a;
uint32_t bx = copy_if(b);
printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx);
}
void cvtdl(long double a)
{
u128_t ax = copy_ild(a);
double b = a;
uint64_t bx = copy_id(b);
printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx);
}
void cvts(void)
{
int i, j;
{
uint32_t x = 0xad040c5b;
cvtlsw(0);
for (i = 0; i < 31; i++)
cvtlsw(x >> (31 - i));
for (i = 0; i < 31; i++)
cvtlsw(-(x >> (31 - i)));
cvtlsw(0x80000000);
}
{
uint64_t x = 0xb630a248cad9afd2;
cvtlsx(0);
for (i = 0; i < 63; i++)
cvtlsx(x >> (63 - i));
for (i = 0; i < 63; i++)
cvtlsx(-(x >> (63 - i)));
cvtlsx(0x8000000000000000);
}
{
uint32_t x = 0xad040c5b;
cvtluw(0);
for (i = 0; i < 32; i++)
cvtluw(x >> (31 - i));
}
{
uint64_t x = 0xb630a248cad9afd2;
cvtlux(0);
for (i = 0; i < 64; i++)
cvtlux(x >> (63 - i));
}
for (i = 0; i < 2; i++) {
cvtil(make(i, 32767, 0, 1));
cvtil(make(i, 32767, (uint64_t)1 << 47, 0));
cvtil(make(i, 32767, 123, 456));
cvtil(make(i, 32767, 0, 0));
cvtil(make(i, 16382, -1, -1));
cvtil(make(i, 16383, -1, -1));
cvtil(make(i, 16384, 0x7fffffffffff, -1));
cvtil(make(i, 16384, 0x800000000000, 0));
for (j = 0; j < 68; j++)
cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d));
}
cvtlf(copy_fi(0x00000000));
cvtlf(copy_fi(0x456789ab));
cvtlf(copy_fi(0x7f800000));
cvtlf(copy_fi(0x7f923456));
cvtlf(copy_fi(0x7fdbcdef));
cvtlf(copy_fi(0x80000000));
cvtlf(copy_fi(0xabcdef12));
cvtlf(copy_fi(0xff800000));
cvtlf(copy_fi(0xff923456));
cvtlf(copy_fi(0xffdbcdef));
cvtld(copy_di(0x0000000000000000));
cvtld(copy_di(0x456789abcdef0123));
cvtld(copy_di(0x7ff0000000000000));
cvtld(copy_di(0x7ff123456789abcd));
cvtld(copy_di(0x7ffabcdef1234567));
cvtld(copy_di(0x8000000000000000));
cvtld(copy_di(0xcdef123456789abc));
cvtld(copy_di(0xfff0000000000000));
cvtld(copy_di(0xfff123456789abcd));
cvtld(copy_di(0xfffabcdef1234567));
for (i = 0; i < 2; i++) { \
cvtfl(make(i, 0, 0, 0));
cvtfl(make(i, 16232, -1, -1));
cvtfl(make(i, 16233, 0, 0));
cvtfl(make(i, 16233, 0, 1));
cvtfl(make(i, 16383, 0xab0ffd000000, 0));
cvtfl(make(i, 16383, 0xab0ffd000001, 0));
cvtfl(make(i, 16383, 0xab0ffeffffff, 0));
cvtfl(make(i, 16383, 0xab0fff000000, 0));
cvtfl(make(i, 16383, 0xab0fff000001, 0));
cvtfl(make(i, 16510, 0xfffffeffffff, -1));
cvtfl(make(i, 16510, 0xffffff000000, 0));
cvtfl(make(i, 16511, 0, 0));
cvtfl(make(i, 32767, 0, 0));
cvtfl(make(i, 32767, 0, 1));
cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
cvtfl(make(i, 32767, 0x800000000000, 1));
cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
}
for (i = 0; i < 2; i++) {
cvtdl(make(i, 0, 0, 0));
cvtdl(make(i, 15307, -1, -1));
cvtdl(make(i, 15308, 0, 0));
cvtdl(make(i, 15308, 0, 1));
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000));
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001));
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff));
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000));
cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001));
cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff));
cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000));
cvtdl(make(i, 17407, 0, 0));
cvtdl(make(i, 32767, 0, 0));
cvtdl(make(i, 32767, 0, 1));
cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
cvtdl(make(i, 32767, 0x800000000000, 1));
cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
}
}
void tests(void)
{
cmps();
nanz();
adds();
muls();
divs();
cvts();
}
int main()
{
#ifdef __aarch64__
tests();
#else
printf("This test program is intended for a little-endian architecture\n"
"with an IEEE-standard 128-bit long double.\n");
#endif
return 0;
}

View File

@ -6,7 +6,7 @@ struct fred
int natasha;
};
int main()
void main()
{
struct fred bloggs;

View File

@ -1,5 +1,3 @@
#define _ISOC99_SOURCE 1
#include <stdio.h>
#include <math.h>

Some files were not shown because too many files have changed in this diff Show More