forked from Mirrors/tinycc
Compare commits
313 Commits
Author | SHA1 | Date |
---|---|---|
grischka | 4429cef9f6 | |
grischka | 7bb5454ef3 | |
Christian Jullien | 92236bfe1d | |
grischka | 9c28349757 | |
grischka | 5bc1720776 | |
Michael Matz | 8de7c092f0 | |
herman ten brugge | 29ba50da29 | |
herman ten brugge | 8370bc03a1 | |
herman ten brugge | 973a14bb2f | |
herman ten brugge | 3e731e3a78 | |
Michael Matz | fb1fb8219c | |
Michael Matz | 2f94390223 | |
Michael Matz | 245f6a0d13 | |
Michael Matz | 8c6143d86f | |
Robert Hoelzl | 1803762e3f | |
Michael Matz | 38ab621b55 | |
Michael Matz | c085645f98 | |
Michael Matz | 00fbf65524 | |
Michael Matz | 096c93c0c6 | |
grischka | 6696da2f61 | |
grischka | d019586378 | |
Tyge | 024214af2d | |
Tyge | df67d8617b | |
wanjochan | c386ca91c6 | |
Christian Jullien | 5ade19c421 | |
Christian Jullien | ec0e93616f | |
wanjochan | 6fa78a3635 | |
wanjochan | 4caa9a4cc7 | |
matthias | 704b602184 | |
matthias | cb041f11f6 | |
Sizhe Zhao | e050ae845e | |
Udo | 923100c498 | |
Udo | 9272fac7c4 | |
Udo | a9e7fe19c7 | |
Udo | 89b3cf0b87 | |
Udo | c092f2ed61 | |
grischka | 7e901299bf | |
Michael Matz | aeac24de98 | |
Michael Matz | 23a8bac7b5 | |
Michael Matz | fdeeb62e28 | |
grischka | d79e1dee8c | |
Michael Matz | a5f6e6189e | |
grischka | 2b7cffac74 | |
gr | ef42295fe8 | |
herman ten brugge | 4092b05068 | |
Christian Jullien | c2976962da | |
Christian Jullien | c7e3d5d7a3 | |
herman ten brugge | 0d7c40b948 | |
Michael Matz | 65f2fe390c | |
Michael Matz | 4a70b2bc2d | |
herman ten brugge | 3877618785 | |
Christian Jullien | 0d6801b130 | |
herman ten brugge | 269042503e | |
Michael Matz | f150f93854 | |
Giovanni Mascellani | 43fb5a72e7 | |
Michael Matz | 1d4d74d6d0 | |
Michael Matz | c8ca64d28b | |
Michael Matz | 2d17e5a6c4 | |
grischka | d30d68d738 | |
grischka | a64353ce71 | |
grischka | 89372dc482 | |
grischka | 35475b5423 | |
grischka | 5914f4d57d | |
grischka | ff3b5ee91c | |
Michael Matz | b476a5f478 | |
Michael Matz | 6cb68c3a17 | |
Michael Matz | 2fb79a6326 | |
grischka | 65f74a4df0 | |
grischka | 56db092ab7 | |
herman ten brugge | a86f47889c | |
herman ten brugge | 87639aae7c | |
herman ten brugge | 56e70bfa31 | |
herman ten brugge | 39c0ff311d | |
herman ten brugge | 35512be1ee | |
herman ten brugge | 75145ddc1a | |
herman ten brugge | 4a2e33d160 | |
Michael Matz | ce4eafb34f | |
Michael Matz | 11fc58fa13 | |
Michael Matz | 90e09ed75f | |
Michael Matz | 83f822d0cd | |
Michael Matz | 8b23662d53 | |
herman ten brugge | b3893baa45 | |
herman ten brugge | b45a8d456d | |
herman ten brugge | 426d32af23 | |
herman ten brugge | a0bc149b0c | |
grischka | 72729d8e36 | |
grischka | 6082dd62bb | |
grischka | df349ddc43 | |
herman ten brugge | 4d297d354c | |
Michael Matz | fb22e0c12d | |
Michael Matz | ac2a61d1b3 | |
Michael Matz | 353db307ed | |
herman ten brugge | 88dd577302 | |
herman ten brugge | 17850a51f5 | |
herman ten brugge | 4461f38a9e | |
Michael Matz | 474f95dda8 | |
Michael Matz | 1dc92f8ff8 | |
Sergey Sushilin | 4873f6fada | |
Sergey Sushilin | 14fc6b6dcb | |
herman ten brugge | df72b8d487 | |
Michael Matz | 4e9ce59fe8 | |
Michael Matz | 8a93ce106a | |
Christian Jullien | 25781e4552 | |
Jookia | f420259ee5 | |
herman ten brugge | 96f1fb1da0 | |
herman ten brugge | fadfc118e5 | |
herman ten brugge | 800c3a5e0b | |
herman ten brugge | c4c5ea4381 | |
herman ten brugge | b84ab23011 | |
herman ten brugge | 588dd6827a | |
Pursuer2 | a7b37f9c63 | |
herman ten brugge | 749dd15ee8 | |
herman ten brugge | 66a14a1e33 | |
herman ten brugge | b073a9c103 | |
herman ten brugge | 7268fe7239 | |
Luc Everse | 491773ac58 | |
Jan Boon | 944c4003bd | |
Øyvind A. Holm | c6635504fe | |
Sergey Sushilin | 53a1521c2e | |
grischka | 7b8799e5ff | |
Sergey Sushilin | 9298555eb6 | |
Siddhesh Poyarekar | 7d4a71fc8b | |
Michael Matz | 9264f06efe | |
Michael Matz | 91e297acd3 | |
Michael Matz | 48ba22c744 | |
Michael Matz | d5bb407cc4 | |
Michael Matz | f8d80464a9 | |
Michael Matz | 83cf5bf17f | |
Michael Matz | c505074a9f | |
Michael Matz | 9b0efa9346 | |
Michael Matz | 0cb6e3fff8 | |
Michael Matz | 98f1b83ffe | |
Michael Matz | 98dc4c123d | |
Michael Matz | e9c2a1996a | |
Michael Matz | 509f561823 | |
Michael Matz | 1ada32900b | |
Michael Matz | 06184aec53 | |
Michael Matz | 69c77d1597 | |
Michael Matz | 2668eda595 | |
Michael Matz | 2616c6b230 | |
Michael Matz | 982de78e8d | |
Michael Matz | f44df9d85b | |
Michael Matz | ddb0c2de92 | |
Michael Matz | b69c2ea2cf | |
Michael Matz | 31ecaa7c28 | |
Michael Matz | b0329ac081 | |
Michael Matz | 5390a729d9 | |
Michael Matz | 9164594d1f | |
Michael Matz | 215bc1aab4 | |
Michael Matz | f64d460d29 | |
Michael Matz | 5fcb87138d | |
Michael Matz | 9309585dbe | |
Michael Matz | 9c1b17407f | |
Michael Matz | 02c8e69a07 | |
Michael Matz | 0d3db83f16 | |
Michael Matz | 9214087259 | |
Michael Matz | b1c7520886 | |
Michael Matz | 16edda58b7 | |
Michael Matz | 55040845f3 | |
Michael Matz | ef7c1a4e96 | |
Michael Matz | 35d7b5934e | |
Michael Matz | 1353ccd9e2 | |
Michael Matz | 0676d5bc23 | |
Michael Matz | 9e429dbef0 | |
grischka | ce1ef5b8fc | |
Christian Jullien | 4bb5bc4401 | |
YX Hao | 756e766295 | |
Christian Jullien | a4997bf3d9 | |
Christian Jullien | a9340dd325 | |
Avi Halachmi (:avih) | a7eef33859 | |
Avi Halachmi (:avih) | 84779b2b84 | |
grischka | 3d78918e63 | |
grischka | 8227db3a23 | |
grischka | 1b57560502 | |
grischka | 8569048031 | |
Pascal Cuoq | cbbba01b46 | |
Michael Matz | 942b73bbbb | |
Avi Halachmi (:avih) | 6599483304 | |
Michael Matz | dd60b20c6e | |
Michael Matz | 7894f39e65 | |
grischka | e6d8f9a8bb | |
Avi Halachmi (:avih) | 5dfcc7506c | |
Pascal Cuoq | 944fe7036c | |
Christian Jullien | d39c49db2d | |
Christian Jullien | d052f609fe | |
Christian Jullien | 21841cb622 | |
Christian Jullien | 78ee3eb7c7 | |
Michael Matz | cb73be5346 | |
Michael Matz | c3f0937012 | |
Michael Matz | 3980e4a5b9 | |
Michael Matz | fe23a14ebb | |
Michael Matz | 69a46b0c53 | |
Michael Matz | cb8bbf1ab9 | |
Michael Matz | 4dfc27b101 | |
Michael Matz | 7ed2d15345 | |
Michael Matz | eaf5f3fa52 | |
Michael Matz | 4c2b55f962 | |
Petr Skocik | 47722a8c2e | |
Petr Skocik | 587e1f5598 | |
Petr Skocik | f2fd56a27d | |
Petr Skocik | 60ceab1453 | |
Petr Skocik | 18a2ed2936 | |
Michael Matz | d04ce7772c | |
Vlad Vissoultchev | 1dd6842654 | |
matthias | cf3d23741f | |
matthias | 14be3a1dc1 | |
matthias | 0d54946dec | |
Michael Matz | d30bc6d00a | |
matthias gatto | e371642e6b | |
matthias | 5a0101856b | |
Michael Matz | 85483f321d | |
Michael Matz | c07e81b087 | |
Christian Jullien | f2461096b1 | |
Michael Matz | c16dadbb97 | |
Michael Matz | 105107124d | |
Michael Matz | 0344c0b6a0 | |
Michael Matz | 94846d3eef | |
Michael Matz | ce4aea2478 | |
Michael Matz | 38a6aba468 | |
Ziga Lenarcic | fa0ef91a24 | |
Michael Matz | 2a417b50ee | |
Michael Matz | 5ac2a26666 | |
Michael Matz | d00f98a7a5 | |
Devin Hussey | 9382a3ad58 | |
Michael Matz | 1fd3709379 | |
Michael Matz | e6980f6cc7 | |
Michael Matz | d72b877e45 | |
Vincent Lefevre | be7c870718 | |
Vincent Lefevre | 920f773a81 | |
Michael Matz | 4b46e0ec63 | |
Michael Matz | ef0397cf3d | |
matthias | b082659f19 | |
Michael Matz | fef838db2d | |
Michael Matz | 749d19d70b | |
Michael Matz | 5f737fb4d3 | |
Michael Matz | 5c862a08b4 | |
matthias | d27ea5155f | |
Michael Matz | 08e22d8ad2 | |
Michael Matz | 4cc802a88e | |
Detlef Riekenberg | 5d805a90e3 | |
matthias | 46145af4a1 | |
matthias | 5010023428 | |
matthias | de92fbee7e | |
matthias | 26f0cf0708 | |
matthias | ff38d90d5d | |
matthias | 0d91ba749c | |
Giovanni Mascellani | f6be0d483b | |
Christian Jullien | acac38afb2 | |
Michael Matz | 45b8b0e57d | |
Michael Matz | 05f6aa1ade | |
Michael Matz | adbe794a46 | |
Christian Jullien | d44d8cdf60 | |
Pursuer | ecb90de4cc | |
Christian Jullien | 8482f9e54b | |
Petr Skocik | 065a3b35fc | |
Matthias Gatto | 2b94c0c3b1 | |
matthias gatto | 756988e8f9 | |
Christian Jullien | a3a291784a | |
Kurt Nalty | 337dc84b57 | |
Petr Skocik | 51f6e52dd3 | |
Pursuer | 3f05d88d5b | |
Pursuer | b3b685d92a | |
Pursuer | 0c313f491b | |
Petr Skocik | 7369cfc490 | |
Petr Skocik | 7eceba178d | |
Christian Jullien | f21b53b5ed | |
Michael Matz | 3e007193a2 | |
Christian Jullien | 325241c0de | |
general | bf09349f8e | |
Theodore Dubois | 82abfd75f3 | |
Michael Matz | 63f69c2bdd | |
Michael Matz | f68a1f50fd | |
Christian Jullien | adfcf3b1dd | |
Christian Jullien | 8494f2c318 | |
Petr Skocik | 070646b790 | |
Michael Matz | c4787e3626 | |
Petr Skocik | f7779efe58 | |
Petr Skocik | 49dfb5755a | |
Petr Skocik | 3058d4116e | |
Petr Skocik | 9d44b02a49 | |
Petr Skocik | e0012c2767 | |
Petr Skocik | c81116e29a | |
Petr Skocik | f85b1e393f | |
Petr Skocik | 1e2e5671f7 | |
Petr Skocik | 314843ffc3 | |
Petr Skocik | 73ca09ff32 | |
Petr Skocik | 93a4ddfa63 | |
Michael Matz | 3b9c3fd186 | |
Michael Matz | 61ba9f2299 | |
Michael Matz | 22420ee1ee | |
Jonathan Newman | 0edbed1d52 | |
Michael Matz | d79caa9ff6 | |
Michael Matz | 65c7f19deb | |
Andrey Gursky | 91bdb5a4a3 | |
grischka | 8f6fcb709a | |
grischka | 2b155a8c16 | |
grischka | ace1225492 | |
Michael Matz | 671dcace82 | |
Petr Skocik | ef668aae1e | |
Petr Skocik | d6d3cf00ec | |
Michael Matz | f0a25ca263 | |
Thomas Preud'homme | c41caac02d | |
Thomas Preud'homme | e76058c478 | |
Thomas Preud'homme | 776aa0c093 | |
Michael Matz | 3e6515b64f | |
Michael Matz | 7ad2cf8d68 | |
Michael Matz | 8294285d8f | |
foobar | 988e2ff7fe | |
Michael Matz | 414b224efa | |
Michael Matz | 9e47b18229 | |
Michael Matz | 3b27b3b1d1 | |
Michael Matz | 1b1b270f1e | |
Michael Matz | 3f8225509b |
|
@ -50,8 +50,10 @@ tests/*.gcc
|
|||
tests/*-cc*
|
||||
tests/*-tcc*
|
||||
tests/libtcc_test
|
||||
tests/libtcc_test_mt
|
||||
tests/asm-c-connect
|
||||
tests/asm-c-connect-sep
|
||||
tests/vla_test
|
||||
tests/hello
|
||||
tests/tests2/fred.txt
|
||||
libtcc.dylib
|
||||
|
|
172
Makefile
172
Makefile
|
@ -8,9 +8,11 @@ ifndef TOP
|
|||
INCLUDED = no
|
||||
endif
|
||||
|
||||
include $(TOP)/config.mak
|
||||
ifeq ($(findstring $(MAKECMDGOALS),clean distclean),)
|
||||
include $(TOP)/config.mak
|
||||
endif
|
||||
|
||||
ifeq (-$(CC)-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-gcc-4--)
|
||||
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
|
||||
CFLAGS += -D_FORTIFY_SOURCE=0
|
||||
endif
|
||||
|
||||
|
@ -30,7 +32,7 @@ ifdef CONFIG_WIN32
|
|||
CFGWIN = -win
|
||||
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
|
||||
else
|
||||
LIBS=-lm
|
||||
LIBS=-lm -lpthread
|
||||
ifneq ($(CONFIG_ldl),no)
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
|
@ -47,7 +49,7 @@ else
|
|||
ifdef CONFIG_OSX
|
||||
NATIVE_TARGET = $(ARCH)-osx
|
||||
LDFLAGS += -flat_namespace -undefined warning
|
||||
export MACOSX_DEPLOYMENT_TARGET := 10.2
|
||||
export MACOSX_DEPLOYMENT_TARGET := 10.4
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -60,6 +62,11 @@ ifdef CONFIG_OSX
|
|||
TCCFLAGS += -D_ANSI_SOURCE
|
||||
endif
|
||||
|
||||
# cross compiler targets to build
|
||||
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
|
||||
TCC_X += riscv64
|
||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
||||
|
||||
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
|
||||
LIBS_P = $(LIBS)
|
||||
LDFLAGS_P = $(LDFLAGS)
|
||||
|
@ -78,6 +85,7 @@ NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
|
|||
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI
|
||||
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP
|
||||
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64
|
||||
NATIVE_DEFINES_$(CONFIG_riscv64) += -DTCC_TARGET_RISCV64
|
||||
NATIVE_DEFINES += $(NATIVE_DEFINES_yes)
|
||||
|
||||
ifeq ($(INCLUDED),no)
|
||||
|
@ -85,17 +93,14 @@ ifeq ($(INCLUDED),no)
|
|||
# running top Makefile
|
||||
|
||||
PROGS = tcc$(EXESUF)
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
|
||||
TCCLIBS = $(LIBTCCDEF) $(LIBTCC) $(LIBTCC1)
|
||||
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
||||
|
||||
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||
|
||||
# cross compiler targets to build
|
||||
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
|
||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
||||
|
||||
# cross libtcc1.a targets to build
|
||||
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
|
||||
LIBTCC1_X += riscv64
|
||||
|
||||
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
|
||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
|
||||
|
@ -106,8 +111,8 @@ cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
|
|||
# build specific cross compiler & lib
|
||||
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
|
||||
|
||||
install: ; @$(MAKE) --no-print-directory install$(CFGWIN)
|
||||
install-strip: ; @$(MAKE) --no-print-directory install$(CFGWIN) CONFIG_strip=yes
|
||||
install: ; @$(MAKE) --no-print-directory install$(CFGWIN)
|
||||
install-strip: ; @$(MAKE) --no-print-directory install$(CFGWIN) CONFIG_strip=yes
|
||||
uninstall: ; @$(MAKE) --no-print-directory uninstall$(CFGWIN)
|
||||
|
||||
ifdef CONFIG_cross
|
||||
|
@ -125,7 +130,7 @@ DEF-i386-win32 = -DTCC_TARGET_PE -DTCC_TARGET_I386
|
|||
DEF-x86_64-win32= -DTCC_TARGET_PE -DTCC_TARGET_X86_64
|
||||
DEF-x86_64-osx = -DTCC_TARGET_MACHO -DTCC_TARGET_X86_64
|
||||
DEF-arm-wince = -DTCC_TARGET_PE -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP -DTCC_ARM_HARDFLOAT
|
||||
DEF-arm64 = -DTCC_TARGET_ARM64
|
||||
DEF-arm64 = -DTCC_TARGET_ARM64 -Wno-format
|
||||
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
|
||||
DEF-arm-fpa = -DTCC_TARGET_ARM
|
||||
DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
|
||||
|
@ -133,6 +138,7 @@ DEF-arm-vfp = -DTCC_TARGET_ARM -DTCC_ARM_VFP
|
|||
DEF-arm-eabi = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI
|
||||
DEF-arm-eabihf = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT
|
||||
DEF-arm = $(DEF-arm-eabihf)
|
||||
DEF-riscv64 = -DTCC_TARGET_RISCV64
|
||||
DEF-$(NATIVE_TARGET) = $(NATIVE_DEFINES)
|
||||
|
||||
DEFINES += $(DEF-$T) $(DEF-all)
|
||||
|
@ -164,8 +170,15 @@ x86_64-win32_FILES = $(x86_64_FILES) tccpe.c
|
|||
x86_64-osx_FILES = $(x86_64_FILES)
|
||||
arm_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c
|
||||
arm-wince_FILES = $(arm_FILES) tccpe.c
|
||||
arm-eabihf_FILES = $(arm_FILES)
|
||||
arm-fpa_FILES = $(arm_FILES)
|
||||
arm-fpa-ld_FILES = $(arm_FILES)
|
||||
arm-vfp_FILES = $(arm_FILES)
|
||||
arm-eabi_FILES = $(arm_FILES)
|
||||
arm-eabihf_FILES = $(arm_FILES)
|
||||
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
|
||||
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
|
||||
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c
|
||||
|
||||
# libtcc sources
|
||||
LIBTCC_SRC = $(filter-out tcc.c tcctools.c,$(filter %.c,$($T_FILES)))
|
||||
|
@ -182,72 +195,87 @@ TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
|
|||
$(TCC_FILES) : DEFINES += -DONE_SOURCE=0
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_strip),no)
|
||||
CFLAGS += -g
|
||||
LDFLAGS += -g
|
||||
else
|
||||
CONFIG_strip = yes
|
||||
LDFLAGS += -s
|
||||
endif
|
||||
|
||||
# target specific object rule
|
||||
$(X)%.o : %.c $(LIBTCC_INC)
|
||||
$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
|
||||
$S$(CC) -o $@ -c $< $(DEFINES) $(CFLAGS)
|
||||
|
||||
# additional dependencies
|
||||
$(X)tcc.o : tcctools.c
|
||||
|
||||
# Host Tiny C Compiler
|
||||
tcc$(EXESUF): tcc.o $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
|
||||
$S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
|
||||
|
||||
# Cross Tiny C Compilers
|
||||
%-tcc$(EXESUF): FORCE
|
||||
@$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
|
||||
|
||||
$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
|
||||
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
|
||||
$S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
|
||||
|
||||
# profiling version
|
||||
tcc_p$(EXESUF): $($T_FILES)
|
||||
$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
||||
$S$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
||||
|
||||
# static libtcc library
|
||||
libtcc.a: $(LIBTCC_OBJ)
|
||||
$(AR) rcs $@ $^
|
||||
$S$(AR) rcs $@ $^
|
||||
|
||||
# dynamic libtcc library
|
||||
libtcc.so: $(LIBTCC_OBJ)
|
||||
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
|
||||
$S$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
|
||||
|
||||
libtcc.so: CFLAGS+=-fPIC
|
||||
libtcc.so: LDFLAGS+=-fPIC
|
||||
|
||||
libtcc.dylib: $(LIBTCC_OBJ)
|
||||
$(CC) -shared -o libtcc.dylib libtcc.o tccpp.o tccgen.o tccelf.o tccasm.o tccrun.o x86_64-gen.o x86_64-link.o i386-asm.o -flat_namespace
|
||||
|
||||
# windows dynamic libtcc library
|
||||
libtcc.dll : $(LIBTCC_OBJ)
|
||||
$(CC) -shared -o $@ $^ $(LDFLAGS)
|
||||
$S$(CC) -shared -o $@ $^ $(LDFLAGS)
|
||||
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
|
||||
|
||||
# import file for windows libtcc.dll
|
||||
libtcc.def : libtcc.dll tcc$(EXESUF)
|
||||
$(XTCC) -impdef $< -o $@
|
||||
$S$(XTCC) -impdef $< -o $@
|
||||
XTCC ?= ./tcc$(EXESUF)
|
||||
|
||||
# TinyCC runtime libraries
|
||||
libtcc1.a : tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -C lib DEFINES='$(DEF-$T)'
|
||||
@$(MAKE) -C lib
|
||||
|
||||
# Cross libtcc1.a
|
||||
%-libtcc1.a : %-tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
|
||||
@$(MAKE) -C lib CROSS_TARGET=$*
|
||||
|
||||
.PRECIOUS: %-libtcc1.a
|
||||
FORCE:
|
||||
|
||||
run-if = $(if $(shell which $1),$S $1 $2)
|
||||
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# documentation and man page
|
||||
tcc-doc.html: tcc-doc.texi
|
||||
makeinfo --no-split --html --number-sections -o $@ $< || true
|
||||
|
||||
tcc.1: tcc-doc.texi
|
||||
$(TOPSRC)/texi2pod.pl $< tcc.pod \
|
||||
&& pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod >tmp.1 \
|
||||
&& mv tmp.1 $@ || rm -f tmp.1
|
||||
$(call run-if,makeinfo,--no-split --html --number-sections -o $@ $<)
|
||||
|
||||
tcc-doc.info: tcc-doc.texi
|
||||
makeinfo $< || true
|
||||
$(call run-if,makeinfo,$< || true)
|
||||
|
||||
tcc.1 : tcc-doc.pod
|
||||
$(call run-if,pod2man,--section=1 --center="Tiny C Compiler" \
|
||||
--release="$(VERSION)" $< >$@ && rm -f $<)
|
||||
%.pod : %.texi
|
||||
$(call run-if,perl,$(TOPSRC)/texi2pod.pl $< $@)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# install
|
||||
|
@ -258,16 +286,19 @@ STRIP_yes = -s
|
|||
|
||||
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
|
||||
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS))
|
||||
IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2)
|
||||
IB = $(if $1,$(IM) mkdir -p $2 && $(INSTALLBIN) $1 $2)
|
||||
IBw = $(call IB,$(wildcard $1),$2)
|
||||
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
|
||||
IF = $(if $1,$(IM) mkdir -p $2 && $(INSTALL) $1 $2)
|
||||
IFw = $(call IF,$(wildcard $1),$2)
|
||||
IR = mkdir -p $2 && cp -r $1/. $2
|
||||
IR = $(IM) mkdir -p $2 && cp -r $1/. $2
|
||||
IM = $(info -> $2 : $1)@
|
||||
|
||||
B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
|
||||
|
||||
# install progs & libs
|
||||
install-unx:
|
||||
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
|
||||
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
|
||||
$(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
|
||||
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
|
||||
|
@ -286,13 +317,13 @@ uninstall-unx:
|
|||
@rm -fv "$(libdir)/libtcc.a" "$(libdir)/libtcc.so" "$(includedir)/libtcc.h"
|
||||
@rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
|
||||
@rm -fv "$(docdir)/tcc-doc.html"
|
||||
rm -r "$(tccdir)"
|
||||
@rm -frv "$(tccdir)"
|
||||
|
||||
# install progs & libs on windows
|
||||
install-win:
|
||||
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
|
||||
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
|
||||
$(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib")
|
||||
$(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
||||
|
@ -305,17 +336,16 @@ ifneq "$(wildcard $(LIBTCC1_U))" ""
|
|||
endif
|
||||
|
||||
# the msys-git shell works to configure && make except it does not have install
|
||||
ifeq "$(and $(CONFIG_WIN32),$(shell which install >/dev/null 2>&1 || echo no))" "no"
|
||||
ifeq ($(CONFIG_WIN32)-$(shell which install || echo no),yes-no)
|
||||
install-win : INSTALL = cp
|
||||
install-win : INSTALLBIN = cp
|
||||
endif
|
||||
|
||||
# uninstall on windows
|
||||
uninstall-win:
|
||||
@rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS) libtcc.dll,"$(bindir)/$P")
|
||||
@rm -fv $(foreach F,tcc-doc.html tcc-win32.txt,"$(docdir)/$F")
|
||||
@rm -fv $(foreach F,libtcc.h libtcc.def libtcc.a,"$(libdir)/$F")
|
||||
rm -r "$(tccdir)"
|
||||
@rm -fv $(foreach P,libtcc.dll $(PROGS) *-tcc.exe,"$(bindir)/$P")
|
||||
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P"/*)
|
||||
@rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P")
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# other stuff
|
||||
|
@ -328,8 +358,9 @@ ETAGS : ; etags $(TAGFILES)
|
|||
# create release tarball from *current* git branch (including tcc-doc.html
|
||||
# and converting two files to CRLF)
|
||||
TCC-VERSION = tcc-$(VERSION)
|
||||
TCC-VERSION = tinycc-mob-$(shell git rev-parse --short=7 HEAD)
|
||||
tar: tcc-doc.html
|
||||
mkdir $(TCC-VERSION)
|
||||
mkdir -p $(TCC-VERSION)
|
||||
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
|
||||
cp tcc-doc.html $(TCC-VERSION)
|
||||
for f in tcc-win32.txt build-tcc.bat ; do \
|
||||
|
@ -344,19 +375,22 @@ config.mak:
|
|||
|
||||
# run all tests
|
||||
test:
|
||||
$(MAKE) -C tests
|
||||
@$(MAKE) -C tests
|
||||
# run test(s) from tests2 subdir (see make help)
|
||||
tests2.%:
|
||||
$(MAKE) -C tests/tests2 $@
|
||||
@$(MAKE) -C tests/tests2 $@
|
||||
|
||||
testspp.%:
|
||||
@$(MAKE) -C tests/pp $@
|
||||
|
||||
clean:
|
||||
rm -f tcc$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) tcc.pod
|
||||
rm -f *~ *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out tags TAGS
|
||||
@$(MAKE) -C lib $@
|
||||
@$(MAKE) -C tests $@
|
||||
@rm -f tcc$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF) tcc.pod
|
||||
@rm -f *.o *.a *.so* *.out *.log lib*.def *.exe *.dll a.out tags TAGS *.dylib
|
||||
@$(MAKE) -s -C lib $@
|
||||
@$(MAKE) -s -C tests $@
|
||||
|
||||
distclean: clean
|
||||
rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
|
||||
@rm -fv config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
|
||||
|
||||
.PHONY: all clean test tar tags ETAGS distclean install uninstall FORCE
|
||||
|
||||
|
@ -367,27 +401,13 @@ help:
|
|||
@echo "make cross"
|
||||
@echo " build cross compilers (from one source)"
|
||||
@echo ""
|
||||
@echo "make ONE_SOURCE=yes / no"
|
||||
@echo " force building from one source / separate objects"
|
||||
@echo "make ONE_SOURCE=no/yes SILENT=no/yes"
|
||||
@echo " force building from separate/one object(s), less/more silently"
|
||||
@echo ""
|
||||
@echo "make cross-TARGET"
|
||||
@echo " build one specific cross compiler for 'TARGET', as in"
|
||||
@echo " $(TCC_X)"
|
||||
@echo ""
|
||||
@echo "Custom configuration:"
|
||||
@echo " The makefile includes a file 'config-extra.mak' if it is present."
|
||||
@echo " This file may contain some custom configuration. For example:"
|
||||
@echo ""
|
||||
@echo " NATIVE_DEFINES += -D..."
|
||||
@echo ""
|
||||
@echo " Or for example to configure the search paths for a cross-compiler"
|
||||
@echo " that expects the linux files in <tccdir>/i386-linux:"
|
||||
@echo ""
|
||||
@echo " ROOT-i386 = {B}/i386-linux"
|
||||
@echo " CRT-i386 = {B}/i386-linux/usr/lib"
|
||||
@echo " LIB-i386 = {B}/i386-linux/lib:{B}/i386-linux/usr/lib"
|
||||
@echo " INC-i386 = {B}/lib/include:{B}/i386-linux/usr/include"
|
||||
@echo " DEF-i386 += -D__linux__"
|
||||
@echo " build one specific cross compiler for 'TARGET'. Currently supported:"
|
||||
@echo " $(wordlist 1,6,$(TCC_X))"
|
||||
@echo " $(wordlist 7,99,$(TCC_X))"
|
||||
@echo ""
|
||||
@echo "make test"
|
||||
@echo " run all tests"
|
||||
|
@ -395,9 +415,23 @@ help:
|
|||
@echo "make tests2.all / make tests2.37 / make tests2.37+"
|
||||
@echo " run all/single test(s) from tests2, optionally update .expect"
|
||||
@echo ""
|
||||
@echo "Other supported make targets:"
|
||||
@echo " install install-strip tags ETAGS tar clean distclean help"
|
||||
@echo "make testspp.all / make testspp.17"
|
||||
@echo " run all/single test(s) from tests/pp"
|
||||
@echo ""
|
||||
@echo "Other supported make targets:"
|
||||
@echo " install install-strip doc clean tags ETAGS tar distclean help"
|
||||
@echo ""
|
||||
@echo "Custom configuration:"
|
||||
@echo " The makefile includes a file 'config-extra.mak' if it is present."
|
||||
@echo " This file may contain some custom configuration. For example:"
|
||||
@echo " NATIVE_DEFINES += -D..."
|
||||
@echo " Or for example to configure the search paths for a cross-compiler"
|
||||
@echo " that expects the linux files in <tccdir>/i386-linux:"
|
||||
@echo " ROOT-i386 = {B}/i386-linux"
|
||||
@echo " CRT-i386 = {B}/i386-linux/usr/lib"
|
||||
@echo " LIB-i386 = {B}/i386-linux/lib:{B}/i386-linux/usr/lib"
|
||||
@echo " INC-i386 = {B}/lib/include:{B}/i386-linux/usr/include"
|
||||
@echo " DEF-i386 += -D__linux__"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
endif # ($(INCLUDED),no)
|
||||
|
|
4
README
4
README
|
@ -12,14 +12,14 @@ Features:
|
|||
-O0'.
|
||||
|
||||
- UNLIMITED! Any C dynamic library can be used directly. TCC is
|
||||
heading torward full ISOC99 compliance. TCC can of course compile
|
||||
heading toward full ISOC99 compliance. TCC can of course compile
|
||||
itself.
|
||||
|
||||
- SAFE! tcc includes an optional memory and bound checker. Bound
|
||||
checked code can be mixed freely with standard code.
|
||||
|
||||
- Compile and execute C source directly. No linking or assembly
|
||||
necessary. Full C preprocessor included.
|
||||
necessary. Full C preprocessor included.
|
||||
|
||||
- C script supported : just add '#!/usr/local/bin/tcc -run' at the first
|
||||
line of your C source, and execute it directly from the command
|
||||
|
|
|
@ -16,7 +16,7 @@ ST_FUNC void gen_le32(int c);
|
|||
/*************************************************************/
|
||||
#else
|
||||
/*************************************************************/
|
||||
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
static void asm_error(void)
|
||||
|
|
161
arm-gen.c
161
arm-gen.c
|
@ -59,7 +59,7 @@
|
|||
#define RC_F7 0x4000
|
||||
#endif
|
||||
#define RC_IRET RC_R0 /* function return: integer register */
|
||||
#define RC_LRET RC_R1 /* function return: second integer register */
|
||||
#define RC_IRE2 RC_R1 /* function return: second integer register */
|
||||
#define RC_FRET RC_F0 /* function return: float register */
|
||||
|
||||
/* pretty names for the registers */
|
||||
|
@ -89,7 +89,7 @@ enum {
|
|||
|
||||
/* return registers for function */
|
||||
#define REG_IRET TREG_R0 /* single word int return register */
|
||||
#define REG_LRET TREG_R1 /* second word return register (for long long) */
|
||||
#define REG_IRE2 TREG_R1 /* second word return register (for long long) */
|
||||
#define REG_FRET TREG_F0 /* float return register */
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
|
@ -132,6 +132,7 @@ enum {
|
|||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
/******************************************************/
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
enum float_abi float_abi;
|
||||
|
@ -170,7 +171,7 @@ ST_FUNC void arm_init(struct TCCState *s)
|
|||
|
||||
float_abi = s->float_abi;
|
||||
#ifndef TCC_ARM_HARDFLOAT
|
||||
tcc_warning("soft float ABI currently not supported: default to softfp");
|
||||
# warning "soft float ABI currently not supported: default to softfp"
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
@ -382,11 +383,6 @@ void gsym_addr(int t, int a)
|
|||
}
|
||||
}
|
||||
|
||||
void gsym(int t)
|
||||
{
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
static uint32_t vfpr(int r)
|
||||
{
|
||||
|
@ -409,9 +405,9 @@ static uint32_t intr(int r)
|
|||
return 12;
|
||||
if(r >= TREG_R0 && r <= TREG_R3)
|
||||
return r - TREG_R0;
|
||||
if (r >= TREG_SP && r <= TREG_LR)
|
||||
return r + (13 - TREG_SP);
|
||||
tcc_error("compiler error! register %i is no int register",r);
|
||||
if (!(r >= TREG_SP && r <= TREG_LR))
|
||||
tcc_error("compiler error! register %i is no int register",r);
|
||||
return r + (13 - TREG_SP);
|
||||
}
|
||||
|
||||
static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift)
|
||||
|
@ -739,25 +735,28 @@ static void gadd_sp(int val)
|
|||
static void gcall_or_jmp(int is_jmp)
|
||||
{
|
||||
int r;
|
||||
uint32_t x;
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||
uint32_t x;
|
||||
/* constant case */
|
||||
x=encbranch(ind,ind+vtop->c.i,0);
|
||||
if(x) {
|
||||
if (vtop->r & VT_SYM) {
|
||||
/* relocation case */
|
||||
greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
|
||||
} else
|
||||
put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
|
||||
o(x|(is_jmp?0xE0000000:0xE1000000));
|
||||
} else {
|
||||
if(!is_jmp)
|
||||
o(0xE28FE004); // add lr,pc,#4
|
||||
o(0xE51FF004); // ldr pc,[pc,#-4]
|
||||
if (vtop->r & VT_SYM)
|
||||
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
|
||||
o(vtop->c.i);
|
||||
}
|
||||
if(vtop->r & VT_SYM){
|
||||
x=encbranch(ind,ind+vtop->c.i,0);
|
||||
if(x) {
|
||||
/* relocation case */
|
||||
greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
|
||||
o(x|(is_jmp?0xE0000000:0xE1000000));
|
||||
} else {
|
||||
if(!is_jmp)
|
||||
o(0xE28FE004); // add lr,pc,#4
|
||||
o(0xE51FF004); // ldr pc,[pc,#-4]
|
||||
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
|
||||
o(vtop->c.i);
|
||||
}
|
||||
}else{
|
||||
if(!is_jmp)
|
||||
o(0xE28FE004); // add lr,pc,#4
|
||||
o(0xE51FF004); // ldr pc,[pc,#-4]
|
||||
o(vtop->c.i);
|
||||
}
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
r = gv(RC_INT);
|
||||
|
@ -1138,7 +1137,7 @@ again:
|
|||
/* XXX: implicit cast ? */
|
||||
size=4;
|
||||
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
|
||||
lexpand_nr();
|
||||
lexpand();
|
||||
size = 8;
|
||||
r = gv(RC_INT);
|
||||
o(0xE52D0004|(intr(r)<<12)); /* push r */
|
||||
|
@ -1162,7 +1161,7 @@ again:
|
|||
|
||||
case CORE_CLASS:
|
||||
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
|
||||
lexpand_nr();
|
||||
lexpand();
|
||||
gv(regmask(pplan->end));
|
||||
pplan->sval->r2 = vtop->r;
|
||||
vtop--;
|
||||
|
@ -1266,8 +1265,9 @@ void gfunc_call(int nb_args)
|
|||
}
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
void gfunc_prolog(CType *func_type)
|
||||
void gfunc_prolog(Sym *func_sym)
|
||||
{
|
||||
CType *func_type = &func_sym->type;
|
||||
Sym *sym,*sym2;
|
||||
int n, nf, size, align, rs, struct_ret = 0;
|
||||
int addr, pn, sn; /* pn=core, sn=stack */
|
||||
|
@ -1278,8 +1278,6 @@ void gfunc_prolog(CType *func_type)
|
|||
#endif
|
||||
|
||||
sym = func_type->ref;
|
||||
func_vt = sym->type;
|
||||
func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS);
|
||||
|
||||
n = nf = 0;
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
|
||||
|
@ -1363,7 +1361,7 @@ from_stack:
|
|||
addr = (n + nf + sn) * 4;
|
||||
sn += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t),
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL,
|
||||
addr + 12);
|
||||
}
|
||||
last_itod_magic=0;
|
||||
|
@ -1410,8 +1408,18 @@ void gfunc_epilog(void)
|
|||
}
|
||||
}
|
||||
|
||||
ST_FUNC void gen_fill_nops(int bytes)
|
||||
{
|
||||
if ((bytes & 3))
|
||||
tcc_error("alignment of code section not multiple of 4");
|
||||
while (bytes > 0) {
|
||||
o(0xE1A00000);
|
||||
bytes -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a jump to a label */
|
||||
int gjmp(int t)
|
||||
ST_FUNC int gjmp(int t)
|
||||
{
|
||||
int r;
|
||||
if (nocode_wanted)
|
||||
|
@ -1422,51 +1430,37 @@ int gjmp(int t)
|
|||
}
|
||||
|
||||
/* generate a jump to a fixed address */
|
||||
void gjmp_addr(int a)
|
||||
ST_FUNC void gjmp_addr(int a)
|
||||
{
|
||||
gjmp(a);
|
||||
}
|
||||
|
||||
/* generate a test. set 'inv' to invert test. Stack entry is popped */
|
||||
int gtst(int inv, int t)
|
||||
ST_FUNC int gjmp_cond(int op, int t)
|
||||
{
|
||||
int v, r;
|
||||
uint32_t op;
|
||||
|
||||
v = vtop->r & VT_VALMASK;
|
||||
int r;
|
||||
if (nocode_wanted)
|
||||
return t;
|
||||
r=ind;
|
||||
op=mapcc(op);
|
||||
op|=encbranch(r,t,1);
|
||||
o(op);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (nocode_wanted) {
|
||||
;
|
||||
} else if (v == VT_CMP) {
|
||||
op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
|
||||
op|=encbranch(r,t,1);
|
||||
o(op);
|
||||
t=r;
|
||||
} else if (v == VT_JMP || v == VT_JMPI) {
|
||||
if ((v & 1) == inv) {
|
||||
if(!vtop->c.i)
|
||||
vtop->c.i=t;
|
||||
else {
|
||||
uint32_t *x;
|
||||
int p,lp;
|
||||
if(t) {
|
||||
p = vtop->c.i;
|
||||
do {
|
||||
p = decbranch(lp=p);
|
||||
} while(p);
|
||||
x = (uint32_t *)(cur_text_section->data + lp);
|
||||
*x &= 0xff000000;
|
||||
*x |= encbranch(lp,t,1);
|
||||
}
|
||||
t = vtop->c.i;
|
||||
}
|
||||
} else {
|
||||
t = gjmp(t);
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
ST_FUNC int gjmp_append(int n, int t)
|
||||
{
|
||||
uint32_t *x;
|
||||
int p,lp;
|
||||
if(n) {
|
||||
p = n;
|
||||
do {
|
||||
p = decbranch(lp=p);
|
||||
} while(p);
|
||||
x = (uint32_t *)(cur_text_section->data + lp);
|
||||
*x &= 0xff000000;
|
||||
*x |= encbranch(lp,t,1);
|
||||
t = n;
|
||||
}
|
||||
vtop--;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -1546,7 +1540,7 @@ void gen_opi(int op)
|
|||
case '%':
|
||||
#ifdef TCC_ARM_EABI
|
||||
func=TOK___aeabi_idivmod;
|
||||
retreg=REG_LRET;
|
||||
retreg=REG_IRE2;
|
||||
#else
|
||||
func=TOK___modsi3;
|
||||
#endif
|
||||
|
@ -1555,7 +1549,7 @@ void gen_opi(int op)
|
|||
case TOK_UMOD:
|
||||
#ifdef TCC_ARM_EABI
|
||||
func=TOK___aeabi_uidivmod;
|
||||
retreg=REG_LRET;
|
||||
retreg=REG_IRE2;
|
||||
#else
|
||||
func=TOK___umodsi3;
|
||||
#endif
|
||||
|
@ -1603,10 +1597,8 @@ void gen_opi(int op)
|
|||
o(opc|(r<<12)|fr);
|
||||
done:
|
||||
vtop--;
|
||||
if (op >= TOK_ULT && op <= TOK_GT) {
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
}
|
||||
if (op >= TOK_ULT && op <= TOK_GT)
|
||||
vset_VT_CMP(op);
|
||||
break;
|
||||
case 2:
|
||||
opc=0xE1A00000|(opc<<5);
|
||||
|
@ -1722,9 +1714,7 @@ void gen_opf(int op)
|
|||
case TOK_UGE: op=TOK_GE; break;
|
||||
case TOK_UGT: op=TOK_GT; break;
|
||||
}
|
||||
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
vset_VT_CMP(op);
|
||||
return;
|
||||
}
|
||||
r=gv(RC_FLOAT);
|
||||
|
@ -1926,8 +1916,9 @@ void gen_opf(int op)
|
|||
} else {
|
||||
r2=fpr(gv(RC_FLOAT));
|
||||
}
|
||||
vtop[-1].r = VT_CMP;
|
||||
vtop[-1].c.i = op;
|
||||
--vtop;
|
||||
vset_VT_CMP(op);
|
||||
++vtop;
|
||||
} else {
|
||||
tcc_error("unknown fp op %x!",op);
|
||||
return;
|
||||
|
@ -1949,7 +1940,7 @@ void gen_opf(int op)
|
|||
|
||||
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
|
||||
and 'long long' cases. */
|
||||
ST_FUNC void gen_cvt_itof1(int t)
|
||||
ST_FUNC void gen_cvt_itof(int t)
|
||||
{
|
||||
uint32_t r, r2;
|
||||
int bt;
|
||||
|
@ -2082,7 +2073,7 @@ void gen_cvt_ftoi(int t)
|
|||
gfunc_call(1);
|
||||
vpushi(0);
|
||||
if(t == VT_LLONG)
|
||||
vtop->r2 = REG_LRET;
|
||||
vtop->r2 = REG_IRE2;
|
||||
vtop->r = REG_IRET;
|
||||
return;
|
||||
}
|
||||
|
|
22
arm-link.c
22
arm-link.c
|
@ -57,8 +57,6 @@ int code_reloc (int reloc_type)
|
|||
case R_ARM_JUMP_SLOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -97,8 +95,6 @@ int gotplt_entry_type (int reloc_type)
|
|||
case R_ARM_GOT32:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -165,8 +161,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||
}
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
|
@ -254,24 +248,24 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
int index;
|
||||
uint8_t *p;
|
||||
char *name, buf[1024];
|
||||
Section *text_section;
|
||||
Section *text;
|
||||
|
||||
name = (char *) symtab_section->link->data + sym->st_name;
|
||||
text_section = s1->sections[sym->st_shndx];
|
||||
text = s1->sections[sym->st_shndx];
|
||||
/* Modify reloc to target a thumb stub to switch to ARM */
|
||||
snprintf(buf, sizeof(buf), "%s_from_thumb", name);
|
||||
index = put_elf_sym(symtab_section,
|
||||
text_section->data_offset + 1,
|
||||
text->data_offset + 1,
|
||||
sym->st_size, sym->st_info, 0,
|
||||
sym->st_shndx, buf);
|
||||
to_thumb = 1;
|
||||
val = text_section->data_offset + 1;
|
||||
val = text->data_offset + 1;
|
||||
rel->r_info = ELFW(R_INFO)(index, type);
|
||||
/* Create a thumb stub function to switch to ARM mode */
|
||||
put_elf_reloc(symtab_section, text_section,
|
||||
text_section->data_offset + 4, R_ARM_JUMP24,
|
||||
put_elf_reloc(symtab_section, text,
|
||||
text->data_offset + 4, R_ARM_JUMP24,
|
||||
sym_index);
|
||||
p = section_ptr_add(text_section, 8);
|
||||
p = section_ptr_add(text, 8);
|
||||
write32le(p, 0x4778); /* bx pc */
|
||||
write32le(p+2, 0x46c0); /* nop */
|
||||
write32le(p+4, 0xeafffffe); /* b $sym */
|
||||
|
@ -365,7 +359,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
return;
|
||||
case R_ARM_GOT32:
|
||||
/* we load the got offset */
|
||||
*(int *)ptr += s1->sym_attrs[sym_index].got_offset;
|
||||
*(int *)ptr += get_sym_attr(s1, sym_index, 0)->got_offset;
|
||||
return;
|
||||
case R_ARM_COPY:
|
||||
return;
|
||||
|
|
118
arm64-gen.c
118
arm64-gen.c
|
@ -40,9 +40,13 @@
|
|||
|
||||
#define CHAR_IS_UNSIGNED
|
||||
|
||||
/* define if return values need to be extended explicitely
|
||||
at caller side (for interfacing with non-TCC compilers) */
|
||||
#define PROMOTE_RET
|
||||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
/******************************************************/
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -236,25 +240,24 @@ ST_FUNC void gsym_addr(int t_, int a_)
|
|||
}
|
||||
}
|
||||
|
||||
// Patch all branches in list pointed to by t to branch to current location:
|
||||
ST_FUNC void gsym(int t)
|
||||
{
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
static int arm64_type_size(int t)
|
||||
{
|
||||
/*
|
||||
* case values are in increasing order (from 1 to 11).
|
||||
* which 'may' help compiler optimizers. See tcc.h
|
||||
*/
|
||||
switch (t & VT_BTYPE) {
|
||||
case VT_INT: return 2;
|
||||
case VT_BYTE: return 0;
|
||||
case VT_SHORT: return 1;
|
||||
case VT_INT: return 2;
|
||||
case VT_LLONG: return 3;
|
||||
case VT_PTR: return 3;
|
||||
case VT_FUNC: return 3;
|
||||
case VT_STRUCT: return 3;
|
||||
case VT_FLOAT: return 2;
|
||||
case VT_DOUBLE: return 3;
|
||||
case VT_LDOUBLE: return 4;
|
||||
case VT_BOOL: return 0;
|
||||
case VT_LLONG: return 3;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
|
@ -446,10 +449,12 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend)
|
|||
}
|
||||
}
|
||||
|
||||
static void arm64_load_cmp(int r, SValue *sv);
|
||||
|
||||
ST_FUNC void load(int r, SValue *sv)
|
||||
{
|
||||
int svtt = sv->type.t;
|
||||
int svr = sv->r & ~VT_LVAL_TYPE;
|
||||
int svr = sv->r;
|
||||
int svrv = svr & VT_VALMASK;
|
||||
uint64_t svcul = (uint32_t)sv->c.i;
|
||||
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
|
||||
|
@ -537,6 +542,11 @@ ST_FUNC void load(int r, SValue *sv)
|
|||
return;
|
||||
}
|
||||
|
||||
if (svr == VT_CMP) {
|
||||
arm64_load_cmp(r, sv);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("load(%x, (%x, %x, %llx))\n", r, svtt, sv->r, (long long)svcul);
|
||||
assert(0);
|
||||
}
|
||||
|
@ -544,7 +554,7 @@ ST_FUNC void load(int r, SValue *sv)
|
|||
ST_FUNC void store(int r, SValue *sv)
|
||||
{
|
||||
int svtt = sv->type.t;
|
||||
int svr = sv->r & ~VT_LVAL_TYPE;
|
||||
int svr = sv->r;
|
||||
int svrv = svr & VT_VALMASK;
|
||||
uint64_t svcul = (uint32_t)sv->c.i;
|
||||
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
|
||||
|
@ -580,8 +590,8 @@ ST_FUNC void store(int r, SValue *sv)
|
|||
|
||||
static void arm64_gen_bl_or_b(int b)
|
||||
{
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||
assert(!b && (vtop->r & VT_SYM));
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
|
||||
assert(!b);
|
||||
greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0);
|
||||
o(0x94000000); // bl .
|
||||
}
|
||||
|
@ -957,11 +967,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
{
|
||||
int rt = return_type->t;
|
||||
int bt = rt & VT_BTYPE;
|
||||
if (bt == VT_BYTE || bt == VT_SHORT)
|
||||
// Promote small integers:
|
||||
o(0x13001c00 | (bt == VT_SHORT) << 13 |
|
||||
(uint32_t)!!(rt & VT_UNSIGNED) << 30); // [su]xt[bh] w0,w0
|
||||
else if (bt == VT_STRUCT && !(a[0] & 1)) {
|
||||
if (bt == VT_STRUCT && !(a[0] & 1)) {
|
||||
// A struct was returned in registers, so write it out:
|
||||
gv(RC_R(8));
|
||||
--vtop;
|
||||
|
@ -995,16 +1001,15 @@ static int arm64_func_va_list_gr_offs;
|
|||
static int arm64_func_va_list_vr_offs;
|
||||
static int arm64_func_sub_sp_offset;
|
||||
|
||||
ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
{
|
||||
CType *func_type = &func_sym->type;
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
Sym *sym;
|
||||
CType **t;
|
||||
unsigned long *a;
|
||||
|
||||
// Why doesn't the caller (gen_function) set func_vt?
|
||||
func_vt = func_type->ref->type;
|
||||
func_vc = 144; // offset of where x8 is stored
|
||||
|
||||
for (sym = func_type->ref; sym; sym = sym->next)
|
||||
|
@ -1036,7 +1041,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
|
||||
224 + ((a[i] - 32) >> 1 << 1));
|
||||
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | lvalue_type(sym->type.t),
|
||||
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
|
||||
off);
|
||||
|
||||
if (a[i] < 16) {
|
||||
|
@ -1123,7 +1128,7 @@ ST_FUNC void gen_va_arg(CType *t)
|
|||
gaddrof();
|
||||
r0 = intr(gv(RC_INT));
|
||||
r1 = get_reg(RC_INT);
|
||||
vtop[0].r = r1 | lvalue_type(t->t);
|
||||
vtop[0].r = r1 | VT_LVAL;
|
||||
r1 = intr(r1);
|
||||
|
||||
if (!hfa) {
|
||||
|
@ -1276,6 +1281,16 @@ ST_FUNC void gfunc_epilog(void)
|
|||
o(0xd65f03c0); // ret
|
||||
}
|
||||
|
||||
ST_FUNC void gen_fill_nops(int bytes)
|
||||
{
|
||||
if ((bytes & 3))
|
||||
tcc_error("alignment of code section not multiple of 4");
|
||||
while (bytes > 0) {
|
||||
o(0xd503201f); // nop
|
||||
bytes -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate forward branch to label:
|
||||
ST_FUNC int gjmp(int t)
|
||||
{
|
||||
|
@ -1293,9 +1308,50 @@ ST_FUNC void gjmp_addr(int a)
|
|||
o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
|
||||
}
|
||||
|
||||
ST_FUNC int gtst(int inv, int t)
|
||||
ST_FUNC int gjmp_append(int n, int t)
|
||||
{
|
||||
void *p;
|
||||
/* insert vtop->c jump list in t */
|
||||
if (n) {
|
||||
uint32_t n1 = n, n2;
|
||||
while ((n2 = read32le(p = cur_text_section->data + n1)))
|
||||
n1 = n2;
|
||||
write32le(p, t);
|
||||
t = n;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void arm64_vset_VT_CMP(int op)
|
||||
{
|
||||
if (op >= TOK_ULT && op <= TOK_GT) {
|
||||
vtop->cmp_r = vtop->r;
|
||||
vset_VT_CMP(0x80);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm64_gen_opil(int op, uint32_t l);
|
||||
|
||||
static void arm64_load_cmp(int r, SValue *sv)
|
||||
{
|
||||
sv->r = sv->cmp_r;
|
||||
if (sv->c.i & 1) {
|
||||
vpushi(1);
|
||||
arm64_gen_opil('^', 0);
|
||||
}
|
||||
if (r != sv->r) {
|
||||
load(r, sv);
|
||||
sv->r = r;
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC int gjmp_cond(int op, int t)
|
||||
{
|
||||
int bt = vtop->type.t & VT_BTYPE;
|
||||
|
||||
int inv = op & 1;
|
||||
vtop->r = vtop->cmp_r;
|
||||
|
||||
if (bt == VT_LDOUBLE) {
|
||||
uint32_t a, b, f = fltr(gv(RC_FLOAT));
|
||||
a = get_reg(RC_INT);
|
||||
|
@ -1320,7 +1376,6 @@ ST_FUNC int gtst(int inv, int t)
|
|||
uint32_t a = intr(gv(RC_INT));
|
||||
o(0x34000040 | a | !!inv << 24 | ll << 31); // cbz/cbnz wA,.+8
|
||||
}
|
||||
--vtop;
|
||||
return gjmp(t);
|
||||
}
|
||||
|
||||
|
@ -1549,11 +1604,13 @@ static void arm64_gen_opil(int op, uint32_t l)
|
|||
ST_FUNC void gen_opi(int op)
|
||||
{
|
||||
arm64_gen_opil(op, 0);
|
||||
arm64_vset_VT_CMP(op);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_opl(int op)
|
||||
{
|
||||
arm64_gen_opil(op, 1);
|
||||
arm64_vset_VT_CMP(op);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_opf(int op)
|
||||
|
@ -1653,6 +1710,7 @@ ST_FUNC void gen_opf(int op)
|
|||
default:
|
||||
assert(0);
|
||||
}
|
||||
arm64_vset_VT_CMP(op);
|
||||
}
|
||||
|
||||
// Generate sign extension from 32 to 64 bits:
|
||||
|
@ -1662,6 +1720,16 @@ ST_FUNC void gen_cvt_sxtw(void)
|
|||
o(0x93407c00 | r | r << 5); // sxtw x(r),w(r)
|
||||
}
|
||||
|
||||
/* char/short to int conversion */
|
||||
ST_FUNC void gen_cvt_csti(int t)
|
||||
{
|
||||
int r = intr(gv(RC_INT));
|
||||
o(0x13001c00
|
||||
| ((t & VT_BTYPE) == VT_SHORT) << 13
|
||||
| (uint32_t)!!(t & VT_UNSIGNED) << 30
|
||||
| r | r << 5); // [su]xt[bh] w(r),w(r)
|
||||
}
|
||||
|
||||
ST_FUNC void gen_cvt_itof(int t)
|
||||
{
|
||||
if (t == VT_LDOUBLE) {
|
||||
|
@ -1721,7 +1789,7 @@ ST_FUNC void gen_cvt_ftoi(int t)
|
|||
|
||||
ST_FUNC void gen_cvt_ftof(int t)
|
||||
{
|
||||
int f = vtop[0].type.t;
|
||||
int f = vtop[0].type.t & VT_BTYPE;
|
||||
assert(t == VT_FLOAT || t == VT_DOUBLE || t == VT_LDOUBLE);
|
||||
assert(f == VT_FLOAT || f == VT_DOUBLE || f == VT_LDOUBLE);
|
||||
if (t == f)
|
||||
|
|
12
arm64-link.c
12
arm64-link.c
|
@ -12,7 +12,7 @@
|
|||
#define R_NUM R_AARCH64_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x00400000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
#define ELF_PAGE_SIZE 0x10000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 1
|
||||
#define RELOCATE_DLLPLT 1
|
||||
|
@ -46,8 +46,6 @@ int code_reloc (int reloc_type)
|
|||
case R_AARCH64_JUMP_SLOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -79,8 +77,6 @@ int gotplt_entry_type (int reloc_type)
|
|||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -152,8 +148,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||
}
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
int sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
|
@ -215,7 +209,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
case R_AARCH64_ADR_GOT_PAGE: {
|
||||
uint64_t off =
|
||||
(((s1->got->sh_addr +
|
||||
s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
|
||||
get_sym_attr(s1, sym_index, 0)->got_offset) >> 12) - (addr >> 12));
|
||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
|
||||
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
||||
|
@ -226,7 +220,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
write32le(ptr,
|
||||
((read32le(ptr) & 0xfff803ff) |
|
||||
((s1->got->sh_addr +
|
||||
s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
|
||||
get_sym_attr(s1, sym_index, 0)->got_offset) & 0xff8) << 7));
|
||||
return;
|
||||
case R_AARCH64_COPY:
|
||||
return;
|
||||
|
|
69
c67-gen.c
69
c67-gen.c
|
@ -56,7 +56,7 @@
|
|||
#define RC_C67_B12 0x04000000
|
||||
#define RC_C67_B13 0x08000000
|
||||
#define RC_IRET RC_C67_A4 /* function return: integer register */
|
||||
#define RC_LRET RC_C67_A5 /* function return: second integer register */
|
||||
#define RC_IRE2 RC_C67_A5 /* function return: second integer register */
|
||||
#define RC_FRET RC_C67_A4 /* function return: float register */
|
||||
|
||||
/* pretty names for the registers */
|
||||
|
@ -89,7 +89,7 @@ enum {
|
|||
|
||||
/* return registers for function */
|
||||
#define REG_IRET TREG_C67_A4 /* single word int return register */
|
||||
#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */
|
||||
#define REG_IRE2 TREG_C67_A5 /* second word return register (for long long) */
|
||||
#define REG_FRET TREG_C67_A4 /* float return register */
|
||||
|
||||
/* defined if function parameters must be evaluated in reverse order */
|
||||
|
@ -111,6 +111,7 @@ enum {
|
|||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
/******************************************************/
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
ST_DATA const int reg_classes[NB_REGS] = {
|
||||
|
@ -226,11 +227,6 @@ void gsym_addr(int t, int a)
|
|||
}
|
||||
}
|
||||
|
||||
void gsym(int t)
|
||||
{
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
// these are regs that tcc doesn't really know about,
|
||||
// but assign them unique values so the mapping routines
|
||||
// can distinguish them
|
||||
|
@ -1944,8 +1940,9 @@ void gfunc_call(int nb_args)
|
|||
// parameters are loaded and restored upon return (or if/when needed).
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
void gfunc_prolog(CType * func_type)
|
||||
void gfunc_prolog(Sym *func_sym)
|
||||
{
|
||||
CType *func_type = &func_sym->type;
|
||||
int addr, align, size, func_call, i;
|
||||
Sym *sym;
|
||||
CType *type;
|
||||
|
@ -1955,8 +1952,6 @@ void gfunc_prolog(CType * func_type)
|
|||
addr = 8;
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
func_var = (sym->f.func_type == FUNC_ELLIPSIS);
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
|
@ -1967,7 +1962,7 @@ void gfunc_prolog(CType * func_type)
|
|||
/* define parameters */
|
||||
while ((sym = sym->next) != NULL) {
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
|
||||
|
@ -2035,6 +2030,16 @@ void gfunc_epilog(void)
|
|||
}
|
||||
}
|
||||
|
||||
ST_FUNC void gen_fill_nops(int bytes)
|
||||
{
|
||||
if ((bytes & 3))
|
||||
tcc_error("alignment of code section not multiple of 4");
|
||||
while (bytes > 0) {
|
||||
C67_NOP(4);
|
||||
bytes -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a jump to a label */
|
||||
int gjmp(int t)
|
||||
{
|
||||
|
@ -2067,15 +2072,13 @@ void gjmp_addr(int a)
|
|||
}
|
||||
|
||||
/* generate a test. set 'inv' to invert test. Stack entry is popped */
|
||||
int gtst(int inv, int t)
|
||||
ST_FUNC int gjmp_cond(int op, int t)
|
||||
{
|
||||
int ind1, n;
|
||||
int v, *p;
|
||||
int ind1;
|
||||
int inv = op & 1;
|
||||
if (nocode_wanted)
|
||||
return t;
|
||||
|
||||
v = vtop->r & VT_VALMASK;
|
||||
if (nocode_wanted) {
|
||||
;
|
||||
} else if (v == VT_CMP) {
|
||||
/* fast case : can jump directly since flags are set */
|
||||
// C67 uses B2 sort of as flags register
|
||||
ind1 = ind;
|
||||
|
@ -2093,16 +2096,18 @@ int gtst(int inv, int t)
|
|||
C67_NOP(5);
|
||||
t = ind1; //return where we need to patch
|
||||
|
||||
} else if (v == VT_JMP || v == VT_JMPI) {
|
||||
/* && or || optimization */
|
||||
if ((v & 1) == inv) {
|
||||
return t;
|
||||
}
|
||||
|
||||
ST_FUNC int gjmp_append(int n0, int t)
|
||||
{
|
||||
if (n0) {
|
||||
int n = n0, *p;
|
||||
/* insert vtop->c jump list in t */
|
||||
|
||||
// I guess the idea is to traverse to the
|
||||
// null at the end of the list and store t
|
||||
// there
|
||||
|
||||
n = vtop->c.i;
|
||||
while (n != 0) {
|
||||
p = (int *) (cur_text_section->data + n);
|
||||
|
||||
|
@ -2112,14 +2117,8 @@ int gtst(int inv, int t)
|
|||
}
|
||||
*p |= (t & 0xffff) << 7;
|
||||
*(p + 1) |= ((t >> 16) & 0xffff) << 7;
|
||||
t = vtop->c.i;
|
||||
|
||||
} else {
|
||||
t = gjmp(t);
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
t = n0;
|
||||
}
|
||||
vtop--;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -2195,10 +2194,8 @@ void gen_opi(int op)
|
|||
ALWAYS_ASSERT(FALSE);
|
||||
|
||||
vtop--;
|
||||
if (op >= TOK_ULT && op <= TOK_GT) {
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
}
|
||||
if (op >= TOK_ULT && op <= TOK_GT)
|
||||
vset_VT_CMP(0x80);
|
||||
break;
|
||||
case '-':
|
||||
case TOK_SUBC1: /* sub with carry generation */
|
||||
|
@ -2354,7 +2351,7 @@ void gen_opf(int op)
|
|||
} else {
|
||||
ALWAYS_ASSERT(FALSE);
|
||||
}
|
||||
vtop->r = VT_CMP; // tell TCC that result is in "flags" actually B2
|
||||
vset_VT_CMP(0x80);
|
||||
} else {
|
||||
if (op == '+') {
|
||||
if ((ft & VT_BTYPE) == VT_DOUBLE) {
|
||||
|
@ -2393,7 +2390,7 @@ void gen_opf(int op)
|
|||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
vtop->r = REG_FRET;
|
||||
vtop->r2 = REG_LRET;
|
||||
vtop->r2 = REG_IRE2;
|
||||
|
||||
} else {
|
||||
// must call intrinsic SP floating point divide
|
||||
|
|
|
@ -39,8 +39,6 @@ int code_reloc (int reloc_type)
|
|||
case R_C60_PLT32:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -64,8 +62,6 @@ int gotplt_entry_type (int reloc_type)
|
|||
case R_C60_GOT32:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -95,8 +91,6 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||
}
|
||||
}
|
||||
|
||||
void relocate_init(Section *sr) {}
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
switch(type) {
|
||||
|
|
|
@ -55,7 +55,7 @@ case $targetos in
|
|||
confvars="$confvars OSX"
|
||||
DLLSUF=".dylib"
|
||||
;;
|
||||
MINGW*|MSYS*|CYGWIN*)
|
||||
Windows_NT|MINGW*|MSYS*|CYGWIN*)
|
||||
mingw32=yes
|
||||
;;
|
||||
DragonFly|OpenBSD|FreeBSD|NetBSD)
|
||||
|
@ -135,6 +135,8 @@ for opt do
|
|||
;;
|
||||
--strip-binaries) confvars="$confvars strip"
|
||||
;;
|
||||
--debug) confvars="$confvars strip=no"
|
||||
;;
|
||||
--with-libgcc) confvars="$confvars libgcc"
|
||||
;;
|
||||
--with-selinux) confvars="$confvars selinux"
|
||||
|
@ -150,11 +152,15 @@ for opt do
|
|||
esac
|
||||
done
|
||||
|
||||
cc="${cross_prefix}${cc}"
|
||||
ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
if test -z "$cpu" ; then
|
||||
if test -n "$ARCH" ; then
|
||||
cpu="$ARCH"
|
||||
cpu="$ARCH"
|
||||
else
|
||||
cpu=`uname -m`
|
||||
cpu=`uname -m`
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -197,6 +203,9 @@ case "$cpu" in
|
|||
s390)
|
||||
cpu="s390"
|
||||
;;
|
||||
riscv64)
|
||||
cpu="riscv64"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
|
@ -205,14 +214,14 @@ esac
|
|||
|
||||
# Checking for CFLAGS
|
||||
if test -z "$CFLAGS"; then
|
||||
CFLAGS="-Wall -g -O2"
|
||||
CFLAGS="-Wall -O2"
|
||||
fi
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
if test "$source_path_used" = "no"; then
|
||||
source_path="."
|
||||
fi
|
||||
if test "$cc" = gcc; then
|
||||
if test "${cc%% *}" = "gcc"; then
|
||||
test -z "$LDFLAGS" && LDFLAGS="-static"
|
||||
fi
|
||||
test -z "$prefix" && prefix="C:/Program Files/tcc"
|
||||
|
@ -286,6 +295,7 @@ Advanced options (experts only):
|
|||
--extra-ldflags= specify linker options []
|
||||
--cpu=CPU CPU [$cpu]
|
||||
--strip-binaries strip symbol tables from resulting binaries
|
||||
--debug include debug info with resulting binaries
|
||||
--disable-static make libtcc.so instead of libtcc.a
|
||||
--enable-static make libtcc.a instead of libtcc.dll (win32)
|
||||
--disable-rpath disable use of -rpath with the above
|
||||
|
@ -303,10 +313,6 @@ EOF
|
|||
exit 1
|
||||
fi
|
||||
|
||||
cc="${cross_prefix}${cc}"
|
||||
ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
CONFTEST=./conftest$EXESUF
|
||||
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
|
||||
|
@ -326,7 +332,7 @@ if test -z "$cross_prefix" ; then
|
|||
fi
|
||||
|
||||
if test -z "$triplet"; then
|
||||
if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
|
||||
if test $cpu = "x86_64" -o $cpu = "aarch64" -o $cpu = "riscv64" ; then
|
||||
if test -f "/usr/lib64/crti.o" ; then
|
||||
tcc_lddir="lib64"
|
||||
fi
|
||||
|
@ -335,7 +341,7 @@ if test -z "$cross_prefix" ; then
|
|||
|
||||
if test "$cpu" = "arm" ; then
|
||||
if test "${triplet%eabihf}" != "$triplet" ; then
|
||||
confvars="$confvars arm_eabihf"
|
||||
confvars="$confvars arm_eabihf arm_vfp"
|
||||
elif test "${triplet%eabi}" != "$triplet" ; then
|
||||
confvars="$confvars arm_eabi"
|
||||
fi
|
||||
|
@ -368,7 +374,7 @@ fi
|
|||
if ! echo "$cc" | grep -q "tcc"; then
|
||||
OPT1="-Wdeclaration-after-statement -fno-strict-aliasing"
|
||||
# we want -Wno- but gcc does not always reject unknown -Wno- options
|
||||
OPT2="-Wpointer-sign -Wsign-compare -Wunused-result"
|
||||
OPT2="-Wpointer-sign -Wsign-compare -Wunused-result -Wformat-truncation"
|
||||
if echo "$cc" | grep -q "clang"; then
|
||||
OPT1="$OPT1 -fheinous-gnu-extensions"
|
||||
OPT2="$OPT2 -Wstring-plus-int"
|
||||
|
@ -485,6 +491,10 @@ if test "$source_path_used" = "yes" ; then
|
|||
else
|
||||
echo 'TOPSRC=$(TOP)' >>config.mak
|
||||
fi
|
||||
cat >>$TMPH <<EOF
|
||||
#define GCC_MAJOR $gcc_major
|
||||
#define GCC_MINOR $gcc_minor
|
||||
EOF
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
/* Define architecture */
|
||||
#if defined(__i386__) || defined _M_IX86
|
||||
# define TRIPLET_ARCH "i386"
|
||||
|
@ -9,6 +13,8 @@
|
|||
# define TRIPLET_ARCH "arm"
|
||||
#elif defined(__aarch64__)
|
||||
# define TRIPLET_ARCH "aarch64"
|
||||
#elif defined(__riscv) && defined(__LP64__)
|
||||
# define TRIPLET_ARCH "riscv64"
|
||||
#else
|
||||
# define TRIPLET_ARCH "unknown"
|
||||
#endif
|
||||
|
@ -49,6 +55,9 @@ int _CRT_glob = 0;
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
_setmode(_fileno(stdout), _O_BINARY); /* don't translate \n to \r\n */
|
||||
#endif
|
||||
switch(argc == 2 ? argv[1][0] : 0) {
|
||||
case 'b':
|
||||
{
|
||||
|
|
71
elf.h
71
elf.h
|
@ -262,7 +262,8 @@ typedef struct
|
|||
#define EM_AARCH64 183 /* ARM AARCH64 */
|
||||
#define EM_TILEPRO 188 /* Tilera TILEPro */
|
||||
#define EM_TILEGX 191 /* Tilera TILE-Gx */
|
||||
#define EM_NUM 192
|
||||
#define EM_RISCV 243 /* RISC-V */
|
||||
#define EM_NUM 253
|
||||
|
||||
/* If it is necessary to assign new unofficial EM_* values, please
|
||||
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
|
||||
|
@ -381,7 +382,7 @@ typedef struct
|
|||
#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
|
||||
#define SHF_ORDERED (1 << 30) /* Special ordering requirement
|
||||
(Solaris). */
|
||||
#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless
|
||||
#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless
|
||||
referenced or allocated (Solaris).*/
|
||||
|
||||
/* Section group handling. */
|
||||
|
@ -3233,5 +3234,71 @@ typedef Elf32_Addr Elf32_Conflict;
|
|||
|
||||
#define R_TILEGX_NUM 130
|
||||
|
||||
/* RISC-V ELF Flags */
|
||||
#define EF_RISCV_RVC 0x0001
|
||||
#define EF_RISCV_FLOAT_ABI 0x0006
|
||||
#define EF_RISCV_FLOAT_ABI_SOFT 0x0000
|
||||
#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002
|
||||
#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
|
||||
#define EF_RISCV_FLOAT_ABI_QUAD 0x0006
|
||||
|
||||
/* RISC-V relocations. */
|
||||
#define R_RISCV_NONE 0
|
||||
#define R_RISCV_32 1
|
||||
#define R_RISCV_64 2
|
||||
#define R_RISCV_RELATIVE 3
|
||||
#define R_RISCV_COPY 4
|
||||
#define R_RISCV_JUMP_SLOT 5
|
||||
#define R_RISCV_TLS_DTPMOD32 6
|
||||
#define R_RISCV_TLS_DTPMOD64 7
|
||||
#define R_RISCV_TLS_DTPREL32 8
|
||||
#define R_RISCV_TLS_DTPREL64 9
|
||||
#define R_RISCV_TLS_TPREL32 10
|
||||
#define R_RISCV_TLS_TPREL64 11
|
||||
#define R_RISCV_BRANCH 16
|
||||
#define R_RISCV_JAL 17
|
||||
#define R_RISCV_CALL 18
|
||||
#define R_RISCV_CALL_PLT 19
|
||||
#define R_RISCV_GOT_HI20 20
|
||||
#define R_RISCV_TLS_GOT_HI20 21
|
||||
#define R_RISCV_TLS_GD_HI20 22
|
||||
#define R_RISCV_PCREL_HI20 23
|
||||
#define R_RISCV_PCREL_LO12_I 24
|
||||
#define R_RISCV_PCREL_LO12_S 25
|
||||
#define R_RISCV_HI20 26
|
||||
#define R_RISCV_LO12_I 27
|
||||
#define R_RISCV_LO12_S 28
|
||||
#define R_RISCV_TPREL_HI20 29
|
||||
#define R_RISCV_TPREL_LO12_I 30
|
||||
#define R_RISCV_TPREL_LO12_S 31
|
||||
#define R_RISCV_TPREL_ADD 32
|
||||
#define R_RISCV_ADD8 33
|
||||
#define R_RISCV_ADD16 34
|
||||
#define R_RISCV_ADD32 35
|
||||
#define R_RISCV_ADD64 36
|
||||
#define R_RISCV_SUB8 37
|
||||
#define R_RISCV_SUB16 38
|
||||
#define R_RISCV_SUB32 39
|
||||
#define R_RISCV_SUB64 40
|
||||
#define R_RISCV_GNU_VTINHERIT 41
|
||||
#define R_RISCV_GNU_VTENTRY 42
|
||||
#define R_RISCV_ALIGN 43
|
||||
#define R_RISCV_RVC_BRANCH 44
|
||||
#define R_RISCV_RVC_JUMP 45
|
||||
#define R_RISCV_RVC_LUI 46
|
||||
#define R_RISCV_GPREL_I 47
|
||||
#define R_RISCV_GPREL_S 48
|
||||
#define R_RISCV_TPREL_I 49
|
||||
#define R_RISCV_TPREL_S 50
|
||||
#define R_RISCV_RELAX 51
|
||||
#define R_RISCV_SUB6 52
|
||||
#define R_RISCV_SET6 53
|
||||
#define R_RISCV_SET8 54
|
||||
#define R_RISCV_SET16 55
|
||||
#define R_RISCV_SET32 56
|
||||
#define R_RISCV_32_PCREL 57
|
||||
|
||||
#define R_RISCV_NUM 58
|
||||
|
||||
|
||||
#endif /* elf.h */
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
#define MAX_OPERANDS 3
|
||||
|
|
344
i386-gen.c
344
i386-gen.c
|
@ -37,7 +37,7 @@
|
|||
#define RC_EBX 0x0040
|
||||
|
||||
#define RC_IRET RC_EAX /* function return: integer register */
|
||||
#define RC_LRET RC_EDX /* function return: second integer register */
|
||||
#define RC_IRE2 RC_EDX /* function return: second integer register */
|
||||
#define RC_FRET RC_ST0 /* function return: float register */
|
||||
|
||||
/* pretty names for the registers */
|
||||
|
@ -52,7 +52,7 @@ enum {
|
|||
|
||||
/* return registers for function */
|
||||
#define REG_IRET TREG_EAX /* single word int return register */
|
||||
#define REG_LRET TREG_EDX /* second word return register (for long long) */
|
||||
#define REG_IRE2 TREG_EDX /* second word return register (for long long) */
|
||||
#define REG_FRET TREG_ST0 /* float return register */
|
||||
|
||||
/* defined if function parameters must be evaluated in reverse order */
|
||||
|
@ -71,9 +71,14 @@ enum {
|
|||
/* maximum alignment (for aligned attribute support) */
|
||||
#define MAX_ALIGN 8
|
||||
|
||||
/* define if return values need to be extended explicitely
|
||||
at caller side (for interfacing with non-TCC compilers) */
|
||||
#define PROMOTE_RET
|
||||
|
||||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
/******************************************************/
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
/* define to 1/0 to [not] have EBX as 4th register */
|
||||
|
@ -92,6 +97,9 @@ static int func_ret_sub;
|
|||
#ifdef CONFIG_TCC_BCHECK
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
static int func_bound_alloca_used;
|
||||
static void gen_bounds_prolog(void);
|
||||
static void gen_bounds_epilog(void);
|
||||
#endif
|
||||
|
||||
/* XXX: make it faster ? */
|
||||
|
@ -140,11 +148,6 @@ ST_FUNC void gsym_addr(int t, int a)
|
|||
}
|
||||
}
|
||||
|
||||
ST_FUNC void gsym(int t)
|
||||
{
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
/* instruction + 4 bytes data. Return the address of the data */
|
||||
static int oad(int c, int s)
|
||||
{
|
||||
|
@ -157,6 +160,12 @@ static int oad(int c, int s)
|
|||
return t;
|
||||
}
|
||||
|
||||
ST_FUNC void gen_fill_nops(int bytes)
|
||||
{
|
||||
while (bytes--)
|
||||
g(0x90);
|
||||
}
|
||||
|
||||
/* generate jmp to a label */
|
||||
#define gjmp2(instr,lbl) oad(instr,lbl)
|
||||
|
||||
|
@ -260,10 +269,10 @@ ST_FUNC void load(int r, SValue *sv)
|
|||
o(0xe8 + r); /* mov %ebp, r */
|
||||
}
|
||||
} else if (v == VT_CMP) {
|
||||
oad(0xb8 + r, 0); /* mov $0, r */
|
||||
o(0x0f); /* setxx %br */
|
||||
o(fc);
|
||||
o(0xc0 + r);
|
||||
o(0xc0b60f + r * 0x90000); /* movzbl %al, %eax */
|
||||
} else if (v == VT_JMP || v == VT_JMPI) {
|
||||
t = v & 1;
|
||||
oad(0xb8 + r, t); /* mov $1, r */
|
||||
|
@ -335,7 +344,7 @@ static void gen_static_call(int v)
|
|||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = external_global_sym(v, &func_old_type, 0);
|
||||
sym = external_global_sym(v, &func_old_type);
|
||||
oad(0xe8, -4);
|
||||
greloc(cur_text_section, sym, ind-4, R_386_PC32);
|
||||
}
|
||||
|
@ -349,39 +358,16 @@ static void gcall_or_jmp(int is_jmp)
|
|||
/* constant and relocation case */
|
||||
greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32);
|
||||
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && vtop->sym->v == TOK_alloca)
|
||||
func_bound_alloca_used = 1;
|
||||
#endif
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
r = gv(RC_INT);
|
||||
o(0xff); /* call/jmp *r */
|
||||
o(0xd0 + r + (is_jmp << 4));
|
||||
}
|
||||
if (!is_jmp) {
|
||||
int rt;
|
||||
/* extend the return value to the whole register if necessary
|
||||
visual studio and gcc do not always set the whole eax register
|
||||
when assigning the return value of a function */
|
||||
rt = vtop->type.ref->type.t;
|
||||
switch (rt & VT_BTYPE) {
|
||||
case VT_BYTE:
|
||||
if (rt & VT_UNSIGNED) {
|
||||
o(0xc0b60f); /* movzx %al, %eax */
|
||||
}
|
||||
else {
|
||||
o(0xc0be0f); /* movsx %al, %eax */
|
||||
}
|
||||
break;
|
||||
case VT_SHORT:
|
||||
if (rt & VT_UNSIGNED) {
|
||||
o(0xc0b70f); /* movzx %ax, %eax */
|
||||
}
|
||||
else {
|
||||
o(0xc0bf0f); /* movsx %ax, %eax */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
|
@ -422,6 +408,11 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
int size, align, r, args_size, i, func_call;
|
||||
Sym *func_sym;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
args_size = 0;
|
||||
for(i = 0;i < nb_args; i++) {
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
|
@ -496,6 +487,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
|
||||
args_size -= 4;
|
||||
#endif
|
||||
|
||||
gcall_or_jmp(0);
|
||||
|
||||
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
|
||||
|
@ -510,8 +502,9 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
#endif
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
{
|
||||
CType *func_type = &func_sym->type;
|
||||
int addr, align, size, func_call, fastcall_nb_regs;
|
||||
int param_index, param_addr;
|
||||
uint8_t *fastcall_regs_ptr;
|
||||
|
@ -540,8 +533,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
func_sub_sp_offset = ind;
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
func_var = (sym->f.func_type == FUNC_ELLIPSIS);
|
||||
#ifdef TCC_TARGET_PE
|
||||
size = type_size(&func_vt,&align);
|
||||
if (((func_vt.t & VT_BTYPE) == VT_STRUCT)
|
||||
|
@ -576,7 +567,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
addr += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | lvalue_type(type->t), param_addr);
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
param_index++;
|
||||
}
|
||||
func_ret_sub = 0;
|
||||
|
@ -589,13 +580,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* leave some room for bound checking code */
|
||||
if (tcc_state->do_bounds_check) {
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
}
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_prolog();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -605,34 +591,8 @@ ST_FUNC void gfunc_epilog(void)
|
|||
addr_t v, saved_ind;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check
|
||||
&& func_bound_offset != lbounds_section->data_offset) {
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
|
||||
/* add end of table info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
|
||||
*bounds_ptr = 0;
|
||||
|
||||
/* generate bound local allocation */
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
greloc(cur_text_section, sym_data,
|
||||
ind + 1, R_386_32);
|
||||
oad(0xb8, 0); /* mov %eax, xxx */
|
||||
gen_static_call(TOK___bound_local_new);
|
||||
ind = saved_ind;
|
||||
|
||||
/* generate bound check local freeing */
|
||||
o(0x5250); /* save returned value, if any */
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
oad(0xb8, 0); /* mov %eax, xxx */
|
||||
gen_static_call(TOK___bound_local_delete);
|
||||
o(0x585a); /* restore returned value, if any */
|
||||
}
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_epilog();
|
||||
#endif
|
||||
|
||||
/* align local size to word & save local variables */
|
||||
|
@ -690,63 +650,39 @@ ST_FUNC void gjmp_addr(int a)
|
|||
}
|
||||
}
|
||||
|
||||
ST_FUNC void gtst_addr(int inv, int a)
|
||||
#if 0
|
||||
/* generate a jump to a fixed address */
|
||||
ST_FUNC void gjmp_cond_addr(int a, int op)
|
||||
{
|
||||
int v = vtop->r & VT_VALMASK;
|
||||
if (v == VT_CMP) {
|
||||
inv ^= (vtop--)->c.i;
|
||||
a -= ind + 2;
|
||||
if (a == (char)a) {
|
||||
g(inv - 32);
|
||||
g(a);
|
||||
} else {
|
||||
g(0x0f);
|
||||
oad(inv - 16, a - 4);
|
||||
}
|
||||
} else if ((v & ~1) == VT_JMP) {
|
||||
if ((v & 1) != inv) {
|
||||
gjmp_addr(a);
|
||||
gsym(vtop->c.i);
|
||||
} else {
|
||||
gsym(vtop->c.i);
|
||||
o(0x05eb);
|
||||
gjmp_addr(a);
|
||||
}
|
||||
vtop--;
|
||||
}
|
||||
int r = a - ind - 2;
|
||||
if (r == (char)r)
|
||||
g(op - 32), g(r);
|
||||
else
|
||||
g(0x0f), gjmp2(op - 16, r - 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* generate a test. set 'inv' to invert test. Stack entry is popped */
|
||||
ST_FUNC int gtst(int inv, int t)
|
||||
ST_FUNC int gjmp_append(int n, int t)
|
||||
{
|
||||
int v = vtop->r & VT_VALMASK;
|
||||
if (nocode_wanted) {
|
||||
;
|
||||
} else if (v == VT_CMP) {
|
||||
/* fast case : can jump directly since flags are set */
|
||||
g(0x0f);
|
||||
t = gjmp2((vtop->c.i - 16) ^ inv, t);
|
||||
} else if (v == VT_JMP || v == VT_JMPI) {
|
||||
/* && or || optimization */
|
||||
if ((v & 1) == inv) {
|
||||
/* insert vtop->c jump list in t */
|
||||
uint32_t n1, n = vtop->c.i;
|
||||
if (n) {
|
||||
while ((n1 = read32le(cur_text_section->data + n)))
|
||||
n = n1;
|
||||
write32le(cur_text_section->data + n, t);
|
||||
t = vtop->c.i;
|
||||
}
|
||||
} else {
|
||||
t = gjmp(t);
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
void *p;
|
||||
/* insert vtop->c jump list in t */
|
||||
if (n) {
|
||||
uint32_t n1 = n, n2;
|
||||
while ((n2 = read32le(p = cur_text_section->data + n1)))
|
||||
n1 = n2;
|
||||
write32le(p, t);
|
||||
t = n;
|
||||
}
|
||||
vtop--;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* generate an integer binary operation */
|
||||
ST_FUNC int gjmp_cond(int op, int t)
|
||||
{
|
||||
g(0x0f);
|
||||
t = gjmp2(op - 16, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
ST_FUNC void gen_opi(int op)
|
||||
{
|
||||
int r, fr, opc, c;
|
||||
|
@ -764,10 +700,9 @@ ST_FUNC void gen_opi(int op)
|
|||
c = vtop->c.i;
|
||||
if (c == (char)c) {
|
||||
/* generate inc and dec for smaller code */
|
||||
if (c==1 && opc==0 && op != TOK_ADDC1) {
|
||||
o (0x40 | r); // inc
|
||||
} else if (c==1 && opc==5 && op != TOK_SUBC1) {
|
||||
o (0x48 | r); // dec
|
||||
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
|
||||
opc = (c == 1) ^ (op == '+');
|
||||
o (0x40 | (opc << 3) | r); // inc,dec
|
||||
} else {
|
||||
o(0x83);
|
||||
o(0xc0 | (opc << 3) | r);
|
||||
|
@ -785,10 +720,8 @@ ST_FUNC void gen_opi(int op)
|
|||
o(0xc0 + r + fr * 8);
|
||||
}
|
||||
vtop--;
|
||||
if (op >= TOK_ULT && op <= TOK_GT) {
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
}
|
||||
if (op >= TOK_ULT && op <= TOK_GT)
|
||||
vset_VT_CMP(op);
|
||||
break;
|
||||
case '-':
|
||||
case TOK_SUBC1: /* sub with carry generation */
|
||||
|
@ -946,8 +879,7 @@ ST_FUNC void gen_opf(int op)
|
|||
op = TOK_EQ;
|
||||
}
|
||||
vtop--;
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
vset_VT_CMP(op);
|
||||
} else {
|
||||
/* no memory reference possible for long double operations */
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
|
@ -1015,6 +947,7 @@ ST_FUNC void gen_cvt_itof(int t)
|
|||
o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
|
||||
o(0x242cdf); /* fildll (%esp) */
|
||||
o(0x08c483); /* add $8, %esp */
|
||||
vtop->r2 = VT_CONST;
|
||||
} else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
|
||||
(VT_INT | VT_UNSIGNED)) {
|
||||
/* unsigned int to float/double/long double */
|
||||
|
@ -1029,6 +962,7 @@ ST_FUNC void gen_cvt_itof(int t)
|
|||
o(0x2404db); /* fildl (%esp) */
|
||||
o(0x04c483); /* add $4, %esp */
|
||||
}
|
||||
vtop->r2 = VT_CONST;
|
||||
vtop->r = TREG_ST0;
|
||||
}
|
||||
|
||||
|
@ -1046,7 +980,8 @@ ST_FUNC void gen_cvt_ftoi(int t)
|
|||
gfunc_call(1);
|
||||
vpushi(0);
|
||||
vtop->r = REG_IRET;
|
||||
vtop->r2 = REG_LRET;
|
||||
if ((t & VT_BTYPE) == VT_LLONG)
|
||||
vtop->r2 = REG_IRE2;
|
||||
}
|
||||
|
||||
/* convert from one floating point type to another */
|
||||
|
@ -1056,6 +991,19 @@ ST_FUNC void gen_cvt_ftof(int t)
|
|||
gv(RC_FLOAT);
|
||||
}
|
||||
|
||||
/* char/short to int conversion */
|
||||
ST_FUNC void gen_cvt_csti(int t)
|
||||
{
|
||||
int r, sz, xl;
|
||||
r = gv(RC_INT);
|
||||
sz = !(t & VT_UNSIGNED);
|
||||
xl = (t & VT_BTYPE) == VT_SHORT;
|
||||
o(0xc0b60f /* mov[sz] %a[xl], %eax */
|
||||
| (sz << 3 | xl) << 8
|
||||
| (r << 3 | r) << 16
|
||||
);
|
||||
}
|
||||
|
||||
/* computed goto support */
|
||||
ST_FUNC void ggoto(void)
|
||||
{
|
||||
|
@ -1065,21 +1013,18 @@ ST_FUNC void ggoto(void)
|
|||
|
||||
/* bound check support functions */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
/* 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);
|
||||
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
/* returned pointer is in eax */
|
||||
vtop++;
|
||||
vtop->r = TREG_EAX | VT_BOUNDED;
|
||||
/* address of bounding function call point */
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
|
||||
}
|
||||
|
||||
|
@ -1092,16 +1037,10 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
|||
Elf32_Rel *rel;
|
||||
Sym *sym;
|
||||
|
||||
size = 0;
|
||||
/* XXX: put that code in generic part of tcc */
|
||||
if (!is_float(vtop->type.t)) {
|
||||
if (vtop->r & VT_LVAL_BYTE)
|
||||
size = 1;
|
||||
else if (vtop->r & VT_LVAL_SHORT)
|
||||
size = 2;
|
||||
}
|
||||
if (!size)
|
||||
size = type_size(&vtop->type, &align);
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
|
||||
size = type_size(&vtop->type, &align);
|
||||
switch(size) {
|
||||
case 1: func = TOK___bound_ptr_indir1; break;
|
||||
case 2: func = TOK___bound_ptr_indir2; break;
|
||||
|
@ -1110,19 +1049,61 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
|||
case 12: func = TOK___bound_ptr_indir12; break;
|
||||
case 16: func = TOK___bound_ptr_indir16; break;
|
||||
default:
|
||||
tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
func = 0;
|
||||
break;
|
||||
/* may happen with struct member access */
|
||||
return;
|
||||
//tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
//func = 0;
|
||||
//break;
|
||||
}
|
||||
|
||||
sym = external_global_sym(func, &func_old_type);
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
/* patch relocation */
|
||||
/* XXX: find a better solution ? */
|
||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
|
||||
sym = external_global_sym(func, &func_old_type, 0);
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
|
||||
}
|
||||
|
||||
static void gen_bounds_prolog(void)
|
||||
{
|
||||
/* leave some room for bound checking code */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
func_bound_alloca_used = 0;
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
}
|
||||
|
||||
static void gen_bounds_epilog(void)
|
||||
{
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
|
||||
if (func_bound_offset == lbounds_section->data_offset && !func_bound_alloca_used)
|
||||
return;
|
||||
|
||||
/* add end of table info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
|
||||
*bounds_ptr = 0;
|
||||
|
||||
/* generate bound local allocation */
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
ind = ind + 5;
|
||||
gen_static_call(TOK___bound_local_new);
|
||||
ind = saved_ind;
|
||||
|
||||
/* generate bound check local freeing */
|
||||
o(0x5250); /* save returned value, if any */
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
oad(0xb8, 0); /* mov %eax, xxx */
|
||||
gen_static_call(TOK___bound_local_delete);
|
||||
o(0x585a); /* restore returned value, if any */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save the stack pointer onto the stack */
|
||||
|
@ -1140,22 +1121,31 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
|
|||
|
||||
/* Subtract from the stack pointer, and push the resulting value onto the stack */
|
||||
ST_FUNC void gen_vla_alloc(CType *type, int align) {
|
||||
#ifdef TCC_TARGET_PE
|
||||
/* alloca does more than just adjust %rsp on Windows */
|
||||
vpush_global_sym(&func_old_type, TOK_alloca);
|
||||
vswap(); /* Move alloca ref past allocation size */
|
||||
gfunc_call(1);
|
||||
#else
|
||||
int r;
|
||||
r = gv(RC_INT); /* allocation size */
|
||||
/* sub r,%rsp */
|
||||
o(0x2b);
|
||||
o(0xe0 | r);
|
||||
/* We align to 16 bytes rather than align */
|
||||
/* and ~15, %esp */
|
||||
o(0xf0e483);
|
||||
vpop();
|
||||
int use_call = 0;
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
use_call = tcc_state->do_bounds_check;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */
|
||||
use_call = 1;
|
||||
#endif
|
||||
if (use_call)
|
||||
{
|
||||
vpush_global_sym(&func_old_type, TOK_alloca);
|
||||
vswap(); /* Move alloca ref past allocation size */
|
||||
gfunc_call(1);
|
||||
}
|
||||
else {
|
||||
int r;
|
||||
r = gv(RC_INT); /* allocation size */
|
||||
/* sub r,%rsp */
|
||||
o(0x2b);
|
||||
o(0xe0 | r);
|
||||
/* We align to 16 bytes rather than align */
|
||||
/* and ~15, %esp */
|
||||
o(0xf0e483);
|
||||
vpop();
|
||||
}
|
||||
}
|
||||
|
||||
/* end of X86 code generator */
|
||||
|
|
19
i386-link.c
19
i386-link.c
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "tcc.h"
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
||||
relocations, returns -1. */
|
||||
int code_reloc (int reloc_type)
|
||||
|
@ -44,8 +45,6 @@ int code_reloc (int reloc_type)
|
|||
case R_386_JMP_SLOT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -81,8 +80,6 @@ int gotplt_entry_type (int reloc_type)
|
|||
case R_386_PLT32:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
|
||||
tcc_error ("Unknown relocation type: %d", reloc_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -152,13 +149,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
|
||||
|
||||
void relocate_init(Section *sr)
|
||||
{
|
||||
qrel = (ElfW_Rel *) sr->data;
|
||||
}
|
||||
#endif
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
||||
{
|
||||
|
@ -169,7 +160,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
switch (type) {
|
||||
case R_386_32:
|
||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||
esym_index = s1->sym_attrs[sym_index].dyn_index;
|
||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
||||
qrel->r_offset = rel->r_offset;
|
||||
if (esym_index) {
|
||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
|
||||
|
@ -185,7 +176,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
case R_386_PC32:
|
||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||
/* DLL relocation */
|
||||
esym_index = s1->sym_attrs[sym_index].dyn_index;
|
||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
||||
if (esym_index) {
|
||||
qrel->r_offset = rel->r_offset;
|
||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
|
||||
|
@ -211,7 +202,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
case R_386_GOT32:
|
||||
case R_386_GOT32X:
|
||||
/* we load the got offset */
|
||||
add32le(ptr, s1->sym_attrs[sym_index].got_offset);
|
||||
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
|
||||
return;
|
||||
case R_386_16:
|
||||
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _STDALIGN_H
|
||||
#define _STDALIGN_H
|
||||
|
||||
#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__))
|
||||
# define _Alignas(t) __attribute__((__aligned__(t)))
|
||||
# define _Alignof(t) __alignof__(t)
|
||||
#endif
|
||||
|
||||
#define alignas _Alignas
|
||||
#define alignof _Alignof
|
||||
|
||||
#define __alignas_is_defined 1
|
||||
#define __alignof_is_defined 1
|
||||
|
||||
#endif /* _STDALIGN_H */
|
||||
|
|
@ -1,76 +1,11 @@
|
|||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
#ifdef __x86_64__
|
||||
#ifndef _WIN64
|
||||
|
||||
//This should be in sync with the declaration on our lib/libtcc1.c
|
||||
/* GCC compatible definition of va_list. */
|
||||
typedef struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
union {
|
||||
unsigned int overflow_offset;
|
||||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
} __va_list_struct;
|
||||
|
||||
typedef __va_list_struct va_list[1];
|
||||
|
||||
void __va_start(__va_list_struct *ap, void *fp);
|
||||
void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);
|
||||
|
||||
#define va_start(ap, last) __va_start(ap, __builtin_frame_address(0))
|
||||
#define va_arg(ap, type) \
|
||||
(*(type *)(__va_arg(ap, __builtin_va_arg_types(type), sizeof(type), __alignof__(type))))
|
||||
#define va_copy(dest, src) (*(dest) = *(src))
|
||||
#define va_end(ap)
|
||||
|
||||
/* avoid conflicting definition for va_list on Macs. */
|
||||
#define _VA_LIST_T
|
||||
|
||||
#else /* _WIN64 */
|
||||
typedef char *va_list;
|
||||
#define va_start(ap,last) __builtin_va_start(ap,last)
|
||||
#define va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
|
||||
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
#define va_end(ap)
|
||||
#endif
|
||||
|
||||
#elif __arm__
|
||||
typedef char *va_list;
|
||||
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
|
||||
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
|
||||
& ~(_tcc_alignof(type) - 1))
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
|
||||
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
typedef struct {
|
||||
void *__stack;
|
||||
void *__gr_top;
|
||||
void *__vr_top;
|
||||
int __gr_offs;
|
||||
int __vr_offs;
|
||||
} va_list;
|
||||
#define va_start(ap, last) __va_start(ap, last)
|
||||
#define va_arg(ap, type) __va_arg(ap, type)
|
||||
#define va_end(ap)
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
|
||||
#else /* __i386__ */
|
||||
typedef char *va_list;
|
||||
/* only correct for i386 */
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
#endif
|
||||
typedef __builtin_va_list va_list;
|
||||
#define va_start __builtin_va_start
|
||||
#define va_arg __builtin_va_arg
|
||||
#define va_copy __builtin_va_copy
|
||||
#define va_end __builtin_va_end
|
||||
|
||||
/* fix a buggy dependency on GCC in libio.h */
|
||||
typedef va_list __gnuc_va_list;
|
||||
|
|
|
@ -8,6 +8,10 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
|||
typedef __PTRDIFF_TYPE__ intptr_t;
|
||||
typedef __SIZE_TYPE__ uintptr_t;
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
typedef union { long long __ll; long double __ld; } max_align_t;
|
||||
#endif
|
||||
|
||||
#ifndef __int8_t_defined
|
||||
#define __int8_t_defined
|
||||
typedef signed char int8_t;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _STDNORETURN_H
|
||||
#define _STDNORETURN_H
|
||||
|
||||
/* ISOC11 noreturn */
|
||||
#define noreturn _Noreturn
|
||||
|
||||
#endif /* _STDNORETURN_H */
|
|
@ -0,0 +1,64 @@
|
|||
#ifdef __x86_64__
|
||||
#ifndef _WIN64
|
||||
|
||||
//This should be in sync with the declaration in 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;
|
||||
} __builtin_va_list[1];
|
||||
|
||||
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
|
||||
|
||||
#define __builtin_va_start(ap, last) \
|
||||
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
||||
#define __builtin_va_arg(ap, t) \
|
||||
(*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t))))
|
||||
#define __builtin_va_copy(dest, src) (*(dest) = *(src))
|
||||
|
||||
#else /* _WIN64 */
|
||||
typedef char *__builtin_va_list;
|
||||
#define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
|
||||
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
|
||||
#endif
|
||||
|
||||
#elif __arm__
|
||||
typedef char *__builtin_va_list;
|
||||
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
|
||||
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
|
||||
& ~(_tcc_alignof(type) - 1))
|
||||
#define __builtin_va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
|
||||
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
typedef struct {
|
||||
void *__stack;
|
||||
void *__gr_top;
|
||||
void *__vr_top;
|
||||
int __gr_offs;
|
||||
int __vr_offs;
|
||||
} __builtin_va_list;
|
||||
|
||||
#elif defined __riscv
|
||||
typedef char *__builtin_va_list;
|
||||
#define __va_reg_size (__riscv_xlen >> 3)
|
||||
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
|
||||
& -(__alignof__(type)))
|
||||
#define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
|
||||
|
||||
#else /* __i386__ */
|
||||
typedef char *__builtin_va_list;
|
||||
#define __builtin_va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define __builtin_va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#endif
|
||||
|
||||
#ifndef __builtin_va_copy
|
||||
#define __builtin_va_copy(dest, src) (dest) = (src)
|
||||
#endif
|
||||
#define __builtin_va_end(ap) (void)(ap)
|
67
lib/Makefile
67
lib/Makefile
|
@ -7,15 +7,15 @@ include $(TOP)/Makefile
|
|||
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
||||
BIN = $(TOP)/$(X)libtcc1.a
|
||||
|
||||
XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
|
||||
XCC = $(XTCC)
|
||||
XAR = $(XTCC) -ar
|
||||
XFLAGS-unx = -B$(TOPSRC)
|
||||
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
||||
XFLAGS = $(XFLAGS$(XCFG))
|
||||
XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
|
||||
XCFG = $(or $(findstring -win,$T),-unx)
|
||||
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
|
||||
|
||||
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
|
||||
arm-libtcc1-usegcc ?= no
|
||||
|
@ -28,46 +28,61 @@ endif
|
|||
|
||||
# only for native compiler
|
||||
$(X)BCHECK_O = bcheck.o
|
||||
$(X)BT_O = bt-exe.o bt-log.o
|
||||
$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
|
||||
|
||||
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
|
||||
BCHECK_O =
|
||||
else
|
||||
DSO_O = dsohandle.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_OSX
|
||||
XFLAGS += -D_ANSI_SOURCE
|
||||
endif
|
||||
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
|
||||
ARM64_O = lib-arm64.o
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
|
||||
ARM64_O = lib-arm64.o $(BT_O)
|
||||
RISCV64_O = lib-arm64.o $(BT_O)
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||
|
||||
OBJ-i386 = $(I386_O) $(BCHECK_O)
|
||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O)
|
||||
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64-osx = $(X86_64_O) va_list.o
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
|
||||
OBJ-arm64 = $(ARM64_O)
|
||||
OBJ-arm = $(ARM_O)
|
||||
OBJ-arm-fpa = $(ARM_O)
|
||||
OBJ-arm-fpa-ld = $(ARM_O)
|
||||
OBJ-arm-vfp = $(ARM_O)
|
||||
OBJ-arm-eabi = $(ARM_O)
|
||||
OBJ-arm-eabihf = $(ARM_O)
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
|
||||
OBJ-arm64 = $(ARM64_O) $(DSO_O)
|
||||
OBJ-arm = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-fpa-ld = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-vfp = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-eabi = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
|
||||
|
||||
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
|
||||
$(XAR) rcs $@ $^
|
||||
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
|
||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||
|
||||
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1)
|
||||
$S$(XAR) rcs $@ $^
|
||||
|
||||
$(X)%.o : %.c
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(X)%.o : %.S
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(TOP)/%.o : %.c
|
||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(TOP)/bcheck.o : XFLAGS += -g
|
||||
$(TOP)/bt-exe.o : $(TOP)/tccrun.c
|
||||
|
||||
$(X)crt1w.o : crt1.c
|
||||
$(X)wincrt1w.o : wincrt1.c
|
||||
|
||||
clean :
|
||||
rm -f *.a *.o $(BIN)
|
||||
rm -f *.a *.o $(ALL)
|
||||
|
|
|
@ -5,35 +5,25 @@
|
|||
__bound_alloca:
|
||||
|
||||
#ifdef _WIN32
|
||||
# bound checking is not implemented
|
||||
pop %rdx
|
||||
mov %rcx,%rax
|
||||
add $15,%rax
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
p1:
|
||||
cmp $4096,%rax
|
||||
jbe p2
|
||||
test %rax,-4096(%rsp)
|
||||
sub $4096,%rsp
|
||||
sub $4096,%rax
|
||||
jmp p1
|
||||
p2:
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rax
|
||||
add $32,%rax
|
||||
|
||||
p3:
|
||||
push %rdx
|
||||
inc %rcx # add one extra to separate regions
|
||||
jmp alloca
|
||||
.globl __bound_alloca_nr
|
||||
__bound_alloca_nr:
|
||||
dec %rcx
|
||||
push %rax
|
||||
mov %rcx,%rdx
|
||||
mov %rax,%rcx
|
||||
sub $32,%rsp
|
||||
call __bound_new_region
|
||||
add $32,%rsp
|
||||
pop %rax
|
||||
ret
|
||||
#else
|
||||
pop %rdx
|
||||
mov %rdi,%rax
|
||||
mov %rax,%rsi # size, a second parm to the __bound_new_region
|
||||
|
||||
add $15,%rax
|
||||
add $15 + 1,%rax # add one extra to separate regions
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ p1:
|
|||
jmp p1
|
||||
p2:
|
||||
#endif
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rax
|
||||
p3:
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
#ifdef __TINYC__
|
||||
|
||||
/* syscall wrapper */
|
||||
unsigned syscall(unsigned syscall_nr, ...);
|
||||
unsigned _tccsyscall(unsigned syscall_nr, ...);
|
||||
|
||||
/* arm-tcc supports only fake asm currently */
|
||||
__asm__(
|
||||
".global syscall\n"
|
||||
"syscall:\n"
|
||||
".global _tccsyscall\n"
|
||||
"_tccsyscall:\n"
|
||||
".int 0xe92d4080\n" // push {r7, lr}
|
||||
".int 0xe1a07000\n" // mov r7, r0
|
||||
".int 0xe1a00001\n" // mov r0, r1
|
||||
|
@ -31,6 +31,8 @@ __asm__(
|
|||
#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
|
||||
#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
|
||||
|
||||
#define syscall _tccsyscall
|
||||
|
||||
#else
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
|
2160
lib/bcheck.c
2160
lib/bcheck.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,67 @@
|
|||
/* ------------------------------------------------------------- */
|
||||
/* stubs for calling bcheck functions from a dll. */
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define REDIR_ALL \
|
||||
REDIR(__bt_init) \
|
||||
REDIR(tcc_backtrace) \
|
||||
\
|
||||
REDIR(__bound_ptr_add) \
|
||||
REDIR(__bound_ptr_indir1) \
|
||||
REDIR(__bound_ptr_indir2) \
|
||||
REDIR(__bound_ptr_indir4) \
|
||||
REDIR(__bound_ptr_indir8) \
|
||||
REDIR(__bound_ptr_indir12) \
|
||||
REDIR(__bound_ptr_indir16) \
|
||||
REDIR(__bound_local_new) \
|
||||
REDIR(__bound_local_delete) \
|
||||
REDIR(__bound_new_region) \
|
||||
\
|
||||
REDIR(__bound_free) \
|
||||
REDIR(__bound_malloc) \
|
||||
REDIR(__bound_realloc) \
|
||||
REDIR(__bound_memcpy) \
|
||||
REDIR(__bound_memcmp) \
|
||||
REDIR(__bound_memmove) \
|
||||
REDIR(__bound_memset) \
|
||||
REDIR(__bound_strlen) \
|
||||
REDIR(__bound_strcpy) \
|
||||
REDIR(__bound_strncpy) \
|
||||
REDIR(__bound_strcmp) \
|
||||
REDIR(__bound_strncmp) \
|
||||
REDIR(__bound_strcat) \
|
||||
REDIR(__bound_strchr) \
|
||||
REDIR(__bound_strdup)
|
||||
|
||||
#define REDIR(s) void *s;
|
||||
static struct { REDIR_ALL } all_ptrs;
|
||||
#undef REDIR
|
||||
#define REDIR(s) #s"\0"
|
||||
static const char all_names[] = REDIR_ALL;
|
||||
#undef REDIR
|
||||
#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) );
|
||||
static void all_jmps() { REDIR_ALL }
|
||||
#undef REDIR
|
||||
|
||||
void __bt_init_dll(int bcheck)
|
||||
{
|
||||
const char *s = all_names;
|
||||
void **p = (void**)&all_ptrs;
|
||||
do {
|
||||
*p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
|
||||
if (NULL == *p) {
|
||||
char buf[100];
|
||||
sprintf(buf,
|
||||
"Error: function '%s()' not found in executable. "
|
||||
"(Need -bt or -b for linking the exe.)", s);
|
||||
if (GetStdHandle(STD_ERROR_HANDLE))
|
||||
fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
|
||||
else
|
||||
MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
|
||||
ExitProcess(1);
|
||||
}
|
||||
s = strchr(s,'\0') + 1, ++p;
|
||||
} while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/* ------------------------------------------------------------- */
|
||||
/* for linking rt_printline and the signal/exception handler
|
||||
from tccrun.c into executables. */
|
||||
|
||||
#define CONFIG_TCC_BACKTRACE_ONLY
|
||||
#include "../tccrun.c"
|
||||
|
||||
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||
|
||||
#ifndef _WIN32
|
||||
# define __declspec(n)
|
||||
#endif
|
||||
|
||||
__declspec(dllexport)
|
||||
void __bt_init(rt_context *p, int num_callers)
|
||||
{
|
||||
__attribute__((weak)) int main();
|
||||
__attribute__((weak)) void __bound_init(void*);
|
||||
struct rt_context *rc = &g_rtctxt;
|
||||
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
|
||||
if (num_callers) {
|
||||
memcpy(rc, p, offsetof(rt_context, next));
|
||||
rc->num_callers = num_callers - 1;
|
||||
rc->top_func = main;
|
||||
__rt_error = _rt_error;
|
||||
set_exception_handler();
|
||||
} else {
|
||||
p->next = rc->next, rc->next = p;
|
||||
}
|
||||
if (__bound_init && p->bounds_start)
|
||||
__bound_init(p->bounds_start);
|
||||
}
|
||||
|
||||
/* copy a string and truncate it. */
|
||||
static char *pstrcpy(char *buf, size_t buf_size, const char *s)
|
||||
{
|
||||
int l = strlen(s);
|
||||
if (l >= buf_size)
|
||||
l = buf_size - 1;
|
||||
memcpy(buf, s, l);
|
||||
buf[l] = 0;
|
||||
return buf;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* ------------------------------------------------------------- */
|
||||
/* function to get a stack backtrace on demand with a message */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||
|
||||
#ifdef _WIN32
|
||||
# define DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
# define DLL_EXPORT
|
||||
#endif
|
||||
|
||||
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
if (__rt_error) {
|
||||
void *fp = __builtin_frame_address(1);
|
||||
void *ip = __builtin_return_address(0);
|
||||
va_start(ap, fmt);
|
||||
ret = __rt_error(fp, ip, fmt, ap);
|
||||
va_end(ap);
|
||||
} else {
|
||||
const char *p;
|
||||
if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
|
||||
fmt = p + 1;
|
||||
va_start(ap, fmt);
|
||||
ret = vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n"), fflush(stderr);
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle;
|
|
@ -24,10 +24,12 @@ void *memcpy(void*,void*,__SIZE_TYPE__);
|
|||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifndef __riscv
|
||||
void __clear_cache(void *beg, void *end)
|
||||
{
|
||||
__arm64_clear_cache(beg, end);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint64_t x0, x1;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#if defined __x86_64__
|
||||
|
||||
/* Avoid include files, they may not be available when cross compiling */
|
||||
extern void *memset(void *s, int c, __SIZE_TYPE__ n);
|
||||
extern void abort(void);
|
||||
|
||||
/* This should be in sync with our include/stdarg.h */
|
||||
|
@ -12,6 +11,7 @@ enum __va_arg_type {
|
|||
};
|
||||
|
||||
/* GCC compatible definition of va_list. */
|
||||
/*predefined by TCC (tcc_predefs.h):
|
||||
typedef struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
|
@ -20,23 +20,16 @@ typedef struct {
|
|||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
} __va_list_struct;
|
||||
} __builtin_va_list[1];
|
||||
*/
|
||||
|
||||
void __va_start(__va_list_struct *ap, void *fp)
|
||||
{
|
||||
memset(ap, 0, sizeof(__va_list_struct));
|
||||
*ap = *(__va_list_struct *)((char *)fp - 16);
|
||||
ap->overflow_arg_area = (char *)fp + ap->overflow_offset;
|
||||
ap->reg_save_area = (char *)fp - 176 - 16;
|
||||
}
|
||||
|
||||
void *__va_arg(__va_list_struct *ap,
|
||||
enum __va_arg_type arg_type,
|
||||
void *__va_arg(__builtin_va_list ap,
|
||||
int arg_type,
|
||||
int size, int align)
|
||||
{
|
||||
size = (size + 7) & ~7;
|
||||
align = (align + 7) & ~7;
|
||||
switch (arg_type) {
|
||||
switch ((enum __va_arg_type)arg_type) {
|
||||
case __va_gen_reg:
|
||||
if (ap->gp_offset + size <= 48) {
|
||||
ap->gp_offset += size;
|
||||
|
@ -60,6 +53,7 @@ void *__va_arg(__va_list_struct *ap,
|
|||
|
||||
default: /* should never happen */
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
15
libtcc.h
15
libtcc.h
|
@ -13,6 +13,8 @@ struct TCCState;
|
|||
|
||||
typedef struct TCCState TCCState;
|
||||
|
||||
typedef void (*TCCErrorFunc)(void *opaque, const char *msg);
|
||||
|
||||
/* create a new TCC compilation context */
|
||||
LIBTCCAPI TCCState *tcc_new(void);
|
||||
|
||||
|
@ -23,8 +25,13 @@ LIBTCCAPI void tcc_delete(TCCState *s);
|
|||
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
|
||||
|
||||
/* set error/warning display callback */
|
||||
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
|
||||
void (*error_func)(void *opaque, const char *msg));
|
||||
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func);
|
||||
|
||||
/* return error/warning callback */
|
||||
LIBTCCAPI TCCErrorFunc tcc_get_error_func(TCCState *s);
|
||||
|
||||
/* return error/warning callback opaque pointer */
|
||||
LIBTCCAPI void *tcc_get_error_opaque(TCCState *s);
|
||||
|
||||
/* set options as from command line (multiple supported) */
|
||||
LIBTCCAPI void tcc_set_options(TCCState *s, const char *str);
|
||||
|
@ -93,6 +100,10 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
|
|||
/* return symbol value or NULL if not found */
|
||||
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
|
||||
|
||||
/* return symbol value or NULL if not found */
|
||||
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
|
||||
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,329 @@
|
|||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define EM_TCC_TARGET EM_RISCV
|
||||
|
||||
#define R_DATA_32 R_RISCV_32
|
||||
#define R_DATA_PTR R_RISCV_64
|
||||
#define R_JMP_SLOT R_RISCV_JUMP_SLOT
|
||||
#define R_GLOB_DAT R_RISCV_64
|
||||
#define R_COPY R_RISCV_COPY
|
||||
#define R_RELATIVE R_RISCV_RELATIVE
|
||||
|
||||
#define R_NUM R_RISCV_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x00010000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 1
|
||||
#define RELOCATE_DLLPLT 1
|
||||
|
||||
#else /* !TARGET_DEFS_ONLY */
|
||||
|
||||
//#define DEBUG_RELOC
|
||||
#include "tcc.h"
|
||||
|
||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
||||
relocations, returns -1. */
|
||||
int code_reloc (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_JAL:
|
||||
return 1;
|
||||
|
||||
case R_RISCV_GOT_HI20:
|
||||
case R_RISCV_PCREL_HI20:
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
case R_RISCV_32_PCREL:
|
||||
case R_RISCV_SET6:
|
||||
case R_RISCV_SUB6:
|
||||
case R_RISCV_ADD16:
|
||||
case R_RISCV_ADD32:
|
||||
case R_RISCV_ADD64:
|
||||
case R_RISCV_SUB16:
|
||||
case R_RISCV_SUB32:
|
||||
case R_RISCV_SUB64:
|
||||
case R_RISCV_32:
|
||||
case R_RISCV_64:
|
||||
return 0;
|
||||
|
||||
case R_RISCV_CALL_PLT:
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns an enumerator to describe whether and when the relocation needs a
|
||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
||||
different values. */
|
||||
int gotplt_entry_type (int reloc_type)
|
||||
{
|
||||
switch (reloc_type) {
|
||||
case R_RISCV_ALIGN:
|
||||
case R_RISCV_RELAX:
|
||||
case R_RISCV_RVC_BRANCH:
|
||||
case R_RISCV_RVC_JUMP:
|
||||
case R_RISCV_JUMP_SLOT:
|
||||
case R_RISCV_SET6:
|
||||
case R_RISCV_SUB6:
|
||||
case R_RISCV_ADD16:
|
||||
case R_RISCV_SUB16:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_PCREL_HI20:
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
case R_RISCV_32_PCREL:
|
||||
case R_RISCV_ADD32:
|
||||
case R_RISCV_ADD64:
|
||||
case R_RISCV_SUB32:
|
||||
case R_RISCV_SUB64:
|
||||
case R_RISCV_32:
|
||||
case R_RISCV_64:
|
||||
case R_RISCV_JAL:
|
||||
case R_RISCV_CALL_PLT:
|
||||
return AUTO_GOTPLT_ENTRY;
|
||||
|
||||
case R_RISCV_GOT_HI20:
|
||||
return ALWAYS_GOTPLT_ENTRY;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
||||
{
|
||||
Section *plt = s1->plt;
|
||||
uint8_t *p;
|
||||
unsigned plt_offset;
|
||||
|
||||
if (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);
|
||||
write64le(p, got_offset);
|
||||
return plt_offset;
|
||||
}
|
||||
|
||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
||||
address for PLT and GOT are known (see fill_program_header) */
|
||||
ST_FUNC void relocate_plt(TCCState *s1)
|
||||
{
|
||||
uint8_t *p, *p_end;
|
||||
|
||||
if (!s1->plt)
|
||||
return;
|
||||
|
||||
p = s1->plt->data;
|
||||
p_end = p + s1->plt->data_offset;
|
||||
|
||||
if (p < p_end) {
|
||||
uint64_t plt = s1->plt->sh_addr;
|
||||
uint64_t got = s1->got->sh_addr;
|
||||
uint64_t off = (got - plt + 0x800) >> 12;
|
||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
|
||||
write32le(p, 0x397 | (off << 12)); // auipc t2, %pcrel_hi(got)
|
||||
write32le(p + 4, 0x41c30333); // sub t1, t1, t3
|
||||
write32le(p + 8, 0x0003be03 // ld t3, %pcrel_lo(got)(t2)
|
||||
| (((got - plt) & 0xfff) << 20));
|
||||
write32le(p + 12, 0xfd430313); // addi t1, t1, -(32+12)
|
||||
write32le(p + 16, 0x00038293 // addi t0, t2, %pcrel_lo(got)
|
||||
| (((got - plt) & 0xfff) << 20));
|
||||
write32le(p + 20, 0x00135313); // srli t1, t1, log2(16/PTRSIZE)
|
||||
write32le(p + 24, 0x0082b283); // ld t0, PTRSIZE(t0)
|
||||
write32le(p + 28, 0x000e0067); // jr t3
|
||||
p += 32;
|
||||
while (p < p_end) {
|
||||
uint64_t pc = plt + (p - s1->plt->data);
|
||||
uint64_t addr = got + read64le(p);
|
||||
uint64_t off = (addr - pc + 0x800) >> 12;
|
||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
||||
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
|
||||
write32le(p, 0xe17 | (off << 12)); // auipc t3, %pcrel_hi(func@got)
|
||||
write32le(p + 4, 0x000e3e03 // ld t3, %pcrel_lo(func@got)(t3)
|
||||
| (((addr - pc) & 0xfff) << 20));
|
||||
write32le(p + 8, 0x000e0367); // jalr t1, t3
|
||||
write32le(p + 12, 0x00000013); // nop
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct pcrel_hi {
|
||||
addr_t addr, val;
|
||||
};
|
||||
static struct pcrel_hi last_hi;
|
||||
|
||||
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
addr_t addr, addr_t val)
|
||||
{
|
||||
uint64_t off64;
|
||||
uint32_t off32;
|
||||
int sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
|
||||
switch(type) {
|
||||
case R_RISCV_ALIGN:
|
||||
case R_RISCV_RELAX:
|
||||
return;
|
||||
|
||||
case R_RISCV_BRANCH:
|
||||
off64 = val - addr;
|
||||
if ((off64 + (1 << 12)) & ~(uint64_t)0x1ffe)
|
||||
tcc_error("R_RISCV_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64 >> 1;
|
||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||
| ((off32 & 0x800) << 20)
|
||||
| ((off32 & 0x3f0) << 21)
|
||||
| ((off32 & 0x00f) << 8)
|
||||
| ((off32 & 0x400) >> 3));
|
||||
return;
|
||||
case R_RISCV_JAL:
|
||||
off64 = val - addr;
|
||||
if ((off64 + (1 << 21)) & ~(((uint64_t)1 << 22) - 2))
|
||||
tcc_error("R_RISCV_JAL relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64;
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| (((off32 >> 12) & 0xff) << 12)
|
||||
| (((off32 >> 11) & 1) << 20)
|
||||
| (((off32 >> 1) & 0x3ff) << 21)
|
||||
| (((off32 >> 20) & 1) << 31));
|
||||
return;
|
||||
case R_RISCV_CALL:
|
||||
case R_RISCV_CALL_PLT:
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((val - addr + 0x800) & ~0xfff));
|
||||
write32le(ptr + 4, (read32le(ptr + 4) & 0xfffff)
|
||||
| (((val - addr) & 0xfff) << 20));
|
||||
return;
|
||||
case R_RISCV_PCREL_HI20:
|
||||
#ifdef DEBUG_RELOC
|
||||
printf("PCREL_HI20: val=%lx addr=%lx\n", val, addr);
|
||||
#endif
|
||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx sym=%s",
|
||||
off64, ((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21),
|
||||
symtab_section->link->data + sym->st_name);
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((off64 & 0xfffff) << 12));
|
||||
last_hi.addr = addr;
|
||||
last_hi.val = val;
|
||||
return;
|
||||
case R_RISCV_GOT_HI20:
|
||||
val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
|
||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
||||
tcc_error("R_RISCV_GOT_HI20 relocation failed");
|
||||
last_hi.addr = addr;
|
||||
last_hi.val = val;
|
||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
||||
| ((off64 & 0xfffff) << 12));
|
||||
return;
|
||||
case R_RISCV_PCREL_LO12_I:
|
||||
#ifdef DEBUG_RELOC
|
||||
printf("PCREL_LO12_I: val=%lx addr=%lx\n", val, addr);
|
||||
#endif
|
||||
if (val != last_hi.addr)
|
||||
tcc_error("unsupported hi/lo pcrel reloc scheme");
|
||||
val = last_hi.val;
|
||||
addr = last_hi.addr;
|
||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
||||
| (((val - addr) & 0xfff) << 20));
|
||||
return;
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
if (val != last_hi.addr)
|
||||
tcc_error("unsupported hi/lo pcrel reloc scheme");
|
||||
val = last_hi.val;
|
||||
addr = last_hi.addr;
|
||||
off32 = val - addr;
|
||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||
| ((off32 & 0xfe0) << 20)
|
||||
| ((off32 & 0x01f) << 7));
|
||||
return;
|
||||
|
||||
case R_RISCV_RVC_BRANCH:
|
||||
off64 = (val - addr);
|
||||
if ((off64 + (1 << 8)) & ~(uint64_t)0x1fe)
|
||||
tcc_error("R_RISCV_RVC_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64;
|
||||
write16le(ptr, (read16le(ptr) & 0xe383)
|
||||
| (((off32 >> 5) & 1) << 2)
|
||||
| (((off32 >> 1) & 3) << 3)
|
||||
| (((off32 >> 6) & 3) << 5)
|
||||
| (((off32 >> 3) & 3) << 10)
|
||||
| (((off32 >> 8) & 1) << 12));
|
||||
return;
|
||||
case R_RISCV_RVC_JUMP:
|
||||
off64 = (val - addr);
|
||||
if ((off64 + (1 << 11)) & ~(uint64_t)0xffe)
|
||||
tcc_error("R_RISCV_RVC_BRANCH relocation failed"
|
||||
" (val=%lx, addr=%lx)", val, addr);
|
||||
off32 = off64;
|
||||
write16le(ptr, (read16le(ptr) & 0xe003)
|
||||
| (((off32 >> 5) & 1) << 2)
|
||||
| (((off32 >> 1) & 7) << 3)
|
||||
| (((off32 >> 7) & 1) << 6)
|
||||
| (((off32 >> 6) & 1) << 7)
|
||||
| (((off32 >> 10) & 1) << 8)
|
||||
| (((off32 >> 8) & 3) << 9)
|
||||
| (((off32 >> 4) & 1) << 11)
|
||||
| (((off32 >> 11) & 1) << 12));
|
||||
return;
|
||||
|
||||
case R_RISCV_32:
|
||||
write32le(ptr, val);
|
||||
return;
|
||||
case R_RISCV_JUMP_SLOT:
|
||||
case R_RISCV_64:
|
||||
write64le(ptr, val);
|
||||
return;
|
||||
case R_RISCV_ADD64:
|
||||
write64le(ptr, read64le(ptr) + val);
|
||||
return;
|
||||
case R_RISCV_ADD32:
|
||||
write32le(ptr, read32le(ptr) + val);
|
||||
return;
|
||||
case R_RISCV_SUB64:
|
||||
write64le(ptr, read64le(ptr) - val);
|
||||
return;
|
||||
case R_RISCV_SUB32:
|
||||
write32le(ptr, read32le(ptr) - val);
|
||||
return;
|
||||
case R_RISCV_ADD16:
|
||||
write16le(ptr, read16le(ptr) + val);
|
||||
return;
|
||||
case R_RISCV_SUB16:
|
||||
write16le(ptr, read16le(ptr) - val);
|
||||
return;
|
||||
case R_RISCV_SET6:
|
||||
*ptr = (*ptr & ~0x3f) | (val & 0x3f);
|
||||
return;
|
||||
case R_RISCV_SUB6:
|
||||
*ptr = (*ptr & ~0x3f) | ((*ptr - val) & 0x3f);
|
||||
return;
|
||||
|
||||
case R_RISCV_32_PCREL:
|
||||
case R_RISCV_COPY:
|
||||
/* XXX */
|
||||
return;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
72
tcc-doc.texi
72
tcc-doc.texi
|
@ -322,6 +322,11 @@ Binary image (only for executable output)
|
|||
COFF output format (only for executable output for TMS320C67xx target)
|
||||
@end table
|
||||
|
||||
@item -Wl,--export-all-symbols
|
||||
@item -Wl,--export-dynamic
|
||||
Export global symbols to the dynamic linker. It is useful when a library
|
||||
opened with @code{dlopen()} needs to access executable symbols.
|
||||
|
||||
@item -Wl,-subsystem=console/gui/wince/...
|
||||
Set type for PE (Windows) executables.
|
||||
|
||||
|
@ -349,12 +354,30 @@ fault}.
|
|||
Generate additional support code to check
|
||||
memory allocations and array/pointer bounds. @option{-g} is implied. Note
|
||||
that the generated code is slower and bigger in this case.
|
||||
The bound checking code is not included in shared libaries. The main executable should always be compiled with the @option{-b}.
|
||||
|
||||
Note: @option{-b} is only available on i386 when using libtcc for the moment.
|
||||
There are five environment variables that can be used:
|
||||
@table @option
|
||||
@item TCC_BOUNDS_WARN_POINTER_ADD
|
||||
Print warning when pointer add creates an illegal pointer.
|
||||
@item TCC_BOUNDS_PRINT_CALLS
|
||||
Print bound checking calls. Can be used for debugging.
|
||||
@item TCC_BOUNDS_PRINT_HEAP
|
||||
Print heap objects that are not freed at exit of program.
|
||||
@item TCC_BOUNDS_PRINT_STATISTIC
|
||||
Print statistic information at exit of program.
|
||||
@item TCC_BOUNDS_NEVER_FATAL
|
||||
Try to continue in case of a bound checking error.
|
||||
@end table
|
||||
|
||||
@item -bt N
|
||||
Display N callers in stack traces. This is useful with @option{-g} or
|
||||
@option{-b}.
|
||||
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
|
||||
|
||||
@item -bt[N]
|
||||
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
|
||||
With executables, additional support for stack traces is included.
|
||||
|
||||
A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided
|
||||
to trigger a stack trace with a message on demand.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -543,6 +566,7 @@ instead of
|
|||
@cindex stdcall attribute
|
||||
@cindex regparm attribute
|
||||
@cindex dllexport attribute
|
||||
@cindex nodecorate attribute
|
||||
|
||||
@item The keyword @code{__attribute__} is handled to specify variable or
|
||||
function attributes. The following attributes are supported:
|
||||
|
@ -570,6 +594,8 @@ registers @code{%eax}, @code{%edx} and @code{%ecx}.
|
|||
|
||||
@item @code{dllexport}: export function from dll/executable (win32 only)
|
||||
|
||||
@item @code{nodecorate}: do not apply any decorations that would otherwise be applied when exporting function from dll/executable (win32 only)
|
||||
|
||||
@end itemize
|
||||
|
||||
Here are some examples:
|
||||
|
@ -893,7 +919,7 @@ Here are some examples of caught errors:
|
|||
int *tab;
|
||||
tab = malloc(20 * sizeof(int));
|
||||
for(i=0;i<21;i++) @{
|
||||
sum += tab4[i];
|
||||
sum += tab[i];
|
||||
@}
|
||||
free(tab);
|
||||
@}
|
||||
|
@ -906,7 +932,7 @@ Here are some examples of caught errors:
|
|||
tab = malloc(20 * sizeof(int));
|
||||
free(tab);
|
||||
for(i=0;i<20;i++) @{
|
||||
sum += tab4[i];
|
||||
sum += tab[i];
|
||||
@}
|
||||
@}
|
||||
@end example
|
||||
|
@ -923,6 +949,40 @@ Here are some examples of caught errors:
|
|||
|
||||
@end table
|
||||
|
||||
Signal handlers are not compatible with bounds checking. The code
|
||||
below can be used to protect signal handlers.
|
||||
The call to __bound_checking(1) will disable bounds checking in the
|
||||
whole application.
|
||||
|
||||
The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to
|
||||
disable bounds checking for some code. This is not recommended.
|
||||
It is better to fix the code.
|
||||
|
||||
@example
|
||||
|
||||
#ifdef __BOUNDS_CHECKING_ON
|
||||
extern void __bound_checking (int no_check);
|
||||
#define BOUNDS_CHECKING_OFF __bound_checking(1)
|
||||
#define BOUNDS_CHECKING_ON __bound_checking(-1)
|
||||
#else
|
||||
#define BOUNDS_CHECKING_OFF
|
||||
#define BOUNDS_CHECKING_ON
|
||||
#endif
|
||||
|
||||
void real_signal_handler(int sig, siginfo_t *info, void *ucontext)
|
||||
@{
|
||||
...
|
||||
@}
|
||||
|
||||
void signal_handler(int sig, void *info, void *ucontext)
|
||||
@{
|
||||
BOUNDS_CHECKING_OFF;
|
||||
real_signal_handler(sig, info, data);
|
||||
BOUNDS_CHECKING_ON;
|
||||
@}
|
||||
|
||||
@end example
|
||||
|
||||
@node Libtcc
|
||||
@chapter The @code{libtcc} library
|
||||
|
||||
|
|
125
tcc.c
125
tcc.c
|
@ -29,46 +29,51 @@ static const char help[] =
|
|||
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
|
||||
" tcc [options...] -run infile [arguments...]\n"
|
||||
"General options:\n"
|
||||
" -c compile only - generate an object file\n"
|
||||
" -o outfile set output filename\n"
|
||||
" -run run compiled source\n"
|
||||
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
|
||||
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
|
||||
" -w disable all warnings\n"
|
||||
" -v -vv show version, show search paths or loaded files\n"
|
||||
" -h -hh show this, show more help\n"
|
||||
" -bench show compilation statistics\n"
|
||||
" - use stdin pipe as infile\n"
|
||||
" @listfile read arguments from listfile\n"
|
||||
" -c compile only - generate an object file\n"
|
||||
" -o outfile set output filename\n"
|
||||
" -run run compiled source\n"
|
||||
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
|
||||
" -std=c99 Conform to the ISO 1999 C standard (default).\n"
|
||||
" -std=c11 Conform to the ISO 2011 C standard.\n"
|
||||
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
|
||||
" -w disable all warnings\n"
|
||||
" --version -v show version\n"
|
||||
" -vv show search paths or loaded files\n"
|
||||
" -h -hh show this, show more help\n"
|
||||
" -bench show compilation statistics\n"
|
||||
" - use stdin pipe as infile\n"
|
||||
" @listfile read arguments from listfile\n"
|
||||
"Preprocessor options:\n"
|
||||
" -Idir add include path 'dir'\n"
|
||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||
" -Usym undefine 'sym'\n"
|
||||
" -E preprocess only\n"
|
||||
" -Idir add include path 'dir'\n"
|
||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||
" -Usym undefine 'sym'\n"
|
||||
" -E preprocess only\n"
|
||||
"Linker options:\n"
|
||||
" -Ldir add library path 'dir'\n"
|
||||
" -llib link with dynamic or static library 'lib'\n"
|
||||
" -r generate (relocatable) object file\n"
|
||||
" -shared generate a shared library/dll\n"
|
||||
" -rdynamic export all global symbols to dynamic linker\n"
|
||||
" -soname set name for shared library to be used at runtime\n"
|
||||
" -Ldir add library path 'dir'\n"
|
||||
" -llib link with dynamic or static library 'lib'\n"
|
||||
" -r generate (relocatable) object file\n"
|
||||
" -shared generate a shared library/dll\n"
|
||||
" -rdynamic export all global symbols to dynamic linker\n"
|
||||
" -soname set name for shared library to be used at runtime\n"
|
||||
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
|
||||
"Debugger options:\n"
|
||||
" -g generate runtime debug info\n"
|
||||
" -g generate runtime debug info\n"
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
" -bt N show N callers in stack traces\n"
|
||||
" -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
|
||||
#endif
|
||||
"Misc. options:\n"
|
||||
" -x[c|a|n] specify type of the next infile\n"
|
||||
" -nostdinc do not use standard system include paths\n"
|
||||
" -nostdlib do not link with standard crt and libraries\n"
|
||||
" -Bdir set tcc's private include/library dir\n"
|
||||
" -MD generate dependency file for make\n"
|
||||
" -MF file specify dependency file name\n"
|
||||
" -m32/64 defer to i386/x86_64 cross compiler\n"
|
||||
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
|
||||
" -nostdinc do not use standard system include paths\n"
|
||||
" -nostdlib do not link with standard crt and libraries\n"
|
||||
" -Bdir set tcc's private include/library dir\n"
|
||||
" -MD generate dependency file for make\n"
|
||||
" -MF file specify dependency file name\n"
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
|
||||
" -m32/64 defer to i386/x86_64 cross compiler\n"
|
||||
#endif
|
||||
"Tools:\n"
|
||||
" create library : tcc -ar [rcsv] lib.a files\n"
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
@ -91,7 +96,7 @@ static const char help2[] =
|
|||
" -print-search-dirs print search paths\n"
|
||||
" -dt with -run/-E: auto-define 'test_...' macros\n"
|
||||
"Ignored options:\n"
|
||||
" --param -pedantic -pipe -s -std -traditional\n"
|
||||
" --param -pedantic -pipe -s -traditional\n"
|
||||
"-W... warnings:\n"
|
||||
" all turn on some (*) warnings\n"
|
||||
" error stop after first warning\n"
|
||||
|
@ -117,6 +122,7 @@ static const char help2[] =
|
|||
" -nostdlib do not link with standard crt/libs\n"
|
||||
" -[no-]whole-archive load lib(s) fully/only as needed\n"
|
||||
" -export-all-symbols same as -rdynamic\n"
|
||||
" -export-dynamic same as -rdynamic\n"
|
||||
" -image-base= -Ttext= set base address of executable\n"
|
||||
" -section-alignment= set section alignment in executable\n"
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
@ -152,6 +158,8 @@ static const char version[] =
|
|||
"ARM"
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
"AArch64"
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
"riscv64"
|
||||
#endif
|
||||
#ifdef TCC_ARM_HARDFLOAT
|
||||
" Hard Float"
|
||||
|
@ -182,8 +190,10 @@ static void print_search_dirs(TCCState *s)
|
|||
/* print_dirs("programs", NULL, 0); */
|
||||
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
|
||||
print_dirs("libraries", s->library_paths, s->nb_library_paths);
|
||||
#ifdef TCC_TARGET_PE
|
||||
printf("libtcc1:\n %s/lib/"TCC_LIBTCC1"\n", s->tcc_lib_path);
|
||||
#else
|
||||
printf("libtcc1:\n %s/"TCC_LIBTCC1"\n", s->tcc_lib_path);
|
||||
#ifndef TCC_TARGET_PE
|
||||
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
|
||||
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
|
||||
#endif
|
||||
|
@ -245,8 +255,8 @@ static unsigned getclock_ms(void)
|
|||
|
||||
int main(int argc0, char **argv0)
|
||||
{
|
||||
TCCState *s;
|
||||
int ret, opt, n = 0, t = 0;
|
||||
TCCState *s, *s1;
|
||||
int ret, opt, n = 0, t = 0, done;
|
||||
unsigned start_time = 0;
|
||||
const char *first_file;
|
||||
int argc; char **argv;
|
||||
|
@ -254,14 +264,14 @@ int main(int argc0, char **argv0)
|
|||
|
||||
redo:
|
||||
argc = argc0, argv = argv0;
|
||||
s = tcc_new();
|
||||
s = s1 = tcc_new();
|
||||
opt = tcc_parse_args(s, &argc, &argv, 1);
|
||||
|
||||
if ((n | t) == 0) {
|
||||
if (n == 0) {
|
||||
if (opt == OPT_HELP)
|
||||
return printf(help), 1;
|
||||
return fputs(help, stdout), 0;
|
||||
if (opt == OPT_HELP2)
|
||||
return printf(help2), 1;
|
||||
return fputs(help2, stdout), 0;
|
||||
if (opt == OPT_M32 || opt == OPT_M64)
|
||||
tcc_tool_cross(s, argv, opt); /* never returns */
|
||||
if (s->verbose)
|
||||
|
@ -282,12 +292,11 @@ redo:
|
|||
return 0;
|
||||
}
|
||||
|
||||
n = s->nb_files;
|
||||
if (n == 0)
|
||||
if (s->nb_files == 0)
|
||||
tcc_error("no input files\n");
|
||||
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (s->outfile) {
|
||||
if (s->outfile && 0!=strcmp("-",s->outfile)) {
|
||||
ppfp = fopen(s->outfile, "w");
|
||||
if (!ppfp)
|
||||
tcc_error("could not write '%s'", s->outfile);
|
||||
|
@ -295,7 +304,7 @@ redo:
|
|||
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
|
||||
if (s->nb_libraries)
|
||||
tcc_error("cannot specify libraries with -c");
|
||||
if (n > 1 && s->outfile)
|
||||
if (s->nb_files > 1 && s->outfile)
|
||||
tcc_error("cannot specify output file with -c many files");
|
||||
} else {
|
||||
if (s->option_pthread)
|
||||
|
@ -313,15 +322,21 @@ redo:
|
|||
s->ppfp = ppfp;
|
||||
|
||||
if ((s->output_type == TCC_OUTPUT_MEMORY
|
||||
|| s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16))
|
||||
s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files;
|
||||
|| s->output_type == TCC_OUTPUT_PREPROCESS)
|
||||
&& (s->dflag & 16)) { /* -dt option */
|
||||
if (t)
|
||||
s->dflag |= 32;
|
||||
s->run_test = ++t;
|
||||
if (n)
|
||||
--n;
|
||||
}
|
||||
|
||||
/* compile or add each files or library */
|
||||
for (first_file = NULL, ret = 0;;) {
|
||||
struct filespec *f = s->files[s->nb_files - n];
|
||||
first_file = NULL, ret = 0;
|
||||
do {
|
||||
struct filespec *f = s->files[n];
|
||||
s->filetype = f->type;
|
||||
s->alacarte_link = f->alacarte;
|
||||
if (f->type == AFF_TYPE_LIB) {
|
||||
if (f->type & AFF_TYPE_LIB) {
|
||||
if (tcc_add_library_err(s, f->name) < 0)
|
||||
ret = 1;
|
||||
} else {
|
||||
|
@ -332,12 +347,8 @@ redo:
|
|||
if (tcc_add_file(s, f->name) < 0)
|
||||
ret = 1;
|
||||
}
|
||||
s->filetype = 0;
|
||||
s->alacarte_link = 1;
|
||||
if (--n == 0 || ret
|
||||
|| (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
|
||||
break;
|
||||
}
|
||||
done = ret || ++n >= s->nb_files;
|
||||
} while (!done && (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
|
||||
|
||||
if (s->run_test) {
|
||||
t = 0;
|
||||
|
@ -358,10 +369,10 @@ redo:
|
|||
}
|
||||
}
|
||||
|
||||
if (s->do_bench && (n | t | ret) == 0)
|
||||
if (s->do_bench && done && !(t | ret))
|
||||
tcc_print_stats(s, getclock_ms() - start_time);
|
||||
tcc_delete(s);
|
||||
if (ret == 0 && n)
|
||||
if (!done)
|
||||
goto redo; /* compile more files with -c */
|
||||
if (t)
|
||||
goto redo; /* run more tests with -dt -run */
|
||||
|
|
423
tcc.h
423
tcc.h
|
@ -24,9 +24,9 @@
|
|||
#define _GNU_SOURCE
|
||||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
@ -46,6 +46,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <io.h> /* open, close etc. */
|
||||
# include <direct.h> /* getcwd */
|
||||
|
@ -73,6 +74,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
# pragma warning (disable : 4018) // signed/unsigned mismatch
|
||||
# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
# define ssize_t intptr_t
|
||||
# ifdef _X86_
|
||||
# define __i386__ 1
|
||||
# endif
|
||||
# ifdef _AMD64_
|
||||
# define __x86_64__ 1
|
||||
# endif
|
||||
# endif
|
||||
# undef CONFIG_TCC_STATIC
|
||||
#endif
|
||||
|
@ -92,9 +99,16 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
#ifdef _MSC_VER
|
||||
# define NORETURN __declspec(noreturn)
|
||||
# define ALIGNED(x) __declspec(align(x))
|
||||
# define PRINTF_LIKE(x,y)
|
||||
#else
|
||||
# define NORETURN __attribute__((noreturn))
|
||||
# define ALIGNED(x) __attribute__((aligned(x)))
|
||||
# define PRINTF_LIKE(x,y) __attribute__ ((format (printf, (x), (y))))
|
||||
#endif
|
||||
|
||||
/* gnu headers use to #define __attribute__ to empty for non-gcc compilers */
|
||||
#ifdef __TINYC__
|
||||
# undef __attribute__
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -117,7 +131,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
/* #define PP_DEBUG */
|
||||
/* include file debug */
|
||||
/* #define INC_DEBUG */
|
||||
/* memory leak debug */
|
||||
/* memory leak debug (only for single threaded usage) */
|
||||
/* #define MEM_DEBUG */
|
||||
/* assembler debug */
|
||||
/* #define ASM_DEBUG */
|
||||
|
@ -128,19 +142,23 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
/* #define TCC_TARGET_ARM *//* ARMv4 code generator */
|
||||
/* #define TCC_TARGET_ARM64 *//* ARMv8 code generator */
|
||||
/* #define TCC_TARGET_C67 *//* TMS320C67xx code generator */
|
||||
/* #define TCC_TARGET_RISCV64 *//* risc-v code generator */
|
||||
|
||||
/* default target is I386 */
|
||||
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
|
||||
!defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
|
||||
!defined(TCC_TARGET_X86_64)
|
||||
# if defined __x86_64__ || defined _AMD64_
|
||||
!defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_RISCV64)
|
||||
# if defined __x86_64__
|
||||
# define TCC_TARGET_X86_64
|
||||
# elif defined __arm__
|
||||
# define TCC_TARGET_ARM
|
||||
# define TCC_ARM_EABI
|
||||
# define TCC_ARM_VFP
|
||||
# define TCC_ARM_HARDFLOAT
|
||||
# elif defined __aarch64__
|
||||
# define TCC_TARGET_ARM64
|
||||
# elif defined __riscv
|
||||
# define TCC_TARGET_RISCV64
|
||||
# else
|
||||
# define TCC_TARGET_I386
|
||||
# endif
|
||||
|
@ -151,14 +169,16 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
|
||||
/* only native compiler supports -run */
|
||||
#if defined _WIN32 == defined TCC_TARGET_PE
|
||||
# if (defined __i386__ || defined _X86_) && defined TCC_TARGET_I386
|
||||
# if defined __i386__ && defined TCC_TARGET_I386
|
||||
# define TCC_IS_NATIVE
|
||||
# elif (defined __x86_64__ || defined _AMD64_) && defined TCC_TARGET_X86_64
|
||||
# elif defined __x86_64__ && defined TCC_TARGET_X86_64
|
||||
# define TCC_IS_NATIVE
|
||||
# elif defined __arm__ && defined TCC_TARGET_ARM
|
||||
# define TCC_IS_NATIVE
|
||||
# elif defined __aarch64__ && defined TCC_TARGET_ARM64
|
||||
# define TCC_IS_NATIVE
|
||||
# elif defined __riscv && defined __LP64__ && defined TCC_TARGET_RISCV64
|
||||
# define TCC_IS_NATIVE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -252,9 +272,15 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
# else
|
||||
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
|
||||
# endif
|
||||
# elif defined(TCC_TARGET_RISCV64)
|
||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
|
||||
# elif !defined(TCC_ARM_EABI)
|
||||
# if defined(TCC_MUSL)
|
||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
|
||||
# if defined(TCC_TARGET_I386)
|
||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-i386.so.1"
|
||||
# else
|
||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-arm.so.1"
|
||||
# endif
|
||||
# else
|
||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
|
||||
# endif
|
||||
|
@ -294,6 +320,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
# define ONE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* support using libtcc from threads */
|
||||
#define CONFIG_TCC_SEMLOCK
|
||||
|
||||
#if ONE_SOURCE
|
||||
#define ST_INLN static inline
|
||||
#define ST_FUNC static
|
||||
|
@ -315,25 +344,26 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||
#ifdef TCC_TARGET_I386
|
||||
# include "i386-gen.c"
|
||||
# include "i386-link.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#elif defined TCC_TARGET_X86_64
|
||||
# include "x86_64-gen.c"
|
||||
# include "x86_64-link.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
#elif defined TCC_TARGET_ARM
|
||||
# include "arm-gen.c"
|
||||
# include "arm-link.c"
|
||||
# include "arm-asm.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
# include "arm64-gen.c"
|
||||
# include "arm64-link.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_C67
|
||||
#elif defined TCC_TARGET_C67
|
||||
# define TCC_TARGET_COFF
|
||||
# include "coff.h"
|
||||
# include "c67-gen.c"
|
||||
# include "c67-link.c"
|
||||
#elif defined(TCC_TARGET_RISCV64)
|
||||
# include "riscv64-gen.c"
|
||||
# include "riscv64-link.c"
|
||||
#else
|
||||
#error unknown target
|
||||
#endif
|
||||
#undef TARGET_DEFS_ONLY
|
||||
|
||||
|
@ -426,9 +456,15 @@ typedef struct SValue {
|
|||
unsigned short r; /* register + flags */
|
||||
unsigned short r2; /* second register, used for 'long long'
|
||||
type. If not used, set to VT_CONST */
|
||||
CValue c; /* constant, if VT_CONST */
|
||||
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if
|
||||
result of unary() for an identifier. */
|
||||
union {
|
||||
struct { int jtrue, jfalse; }; /* forward jmps */
|
||||
CValue c; /* constant, if VT_CONST */
|
||||
};
|
||||
union {
|
||||
struct { unsigned short cmp_op, cmp_r; }; /* VT_CMP operation */
|
||||
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST), or if */
|
||||
}; /* result of unary() for an identifier. */
|
||||
|
||||
} SValue;
|
||||
|
||||
/* symbol attributes */
|
||||
|
@ -439,8 +475,10 @@ struct SymAttr {
|
|||
weak : 1,
|
||||
visibility : 2,
|
||||
dllexport : 1,
|
||||
nodecorate : 1,
|
||||
dllimport : 1,
|
||||
unused : 5;
|
||||
addrtaken : 1,
|
||||
xxxx : 3; /* not used */
|
||||
};
|
||||
|
||||
/* function attributes or temporary attributes for parsing */
|
||||
|
@ -448,19 +486,12 @@ struct FuncAttr {
|
|||
unsigned
|
||||
func_call : 3, /* calling convention (0..5), see below */
|
||||
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
|
||||
func_noreturn : 1, /* attribute((noreturn)) */
|
||||
func_ctor : 1, /* attribute((constructor)) */
|
||||
func_dtor : 1, /* attribute((destructor)) */
|
||||
func_args : 8; /* PE __stdcall args */
|
||||
};
|
||||
|
||||
/* GNUC attribute definition */
|
||||
typedef struct AttributeDef {
|
||||
struct SymAttr a;
|
||||
struct FuncAttr f;
|
||||
struct Section *section;
|
||||
int alias_target; /* token */
|
||||
int asm_label; /* associated asm label */
|
||||
char attr_mode; /* __attribute__((__mode__(...))) */
|
||||
} AttributeDef;
|
||||
|
||||
/* symbol management */
|
||||
typedef struct Sym {
|
||||
int v; /* symbol token */
|
||||
|
@ -478,10 +509,12 @@ typedef struct Sym {
|
|||
};
|
||||
long long enum_val; /* enum constant if IS_ENUM_VAL */
|
||||
int *d; /* define token stream */
|
||||
struct Sym *ncl; /* next cleanup */
|
||||
};
|
||||
CType type; /* associated type */
|
||||
union {
|
||||
struct Sym *next; /* next related symbol (for fields and anoms) */
|
||||
struct Sym *cleanupstate; /* in defined labels */
|
||||
int asm_label; /* associated asm label */
|
||||
};
|
||||
struct Sym *prev; /* prev symbol in stack */
|
||||
|
@ -493,6 +526,7 @@ typedef struct Section {
|
|||
unsigned long data_offset; /* current data offset */
|
||||
unsigned char *data; /* section data */
|
||||
unsigned long data_allocated; /* used for realloc() handling */
|
||||
TCCState *s1;
|
||||
int sh_name; /* elf section name (only used during output) */
|
||||
int sh_num; /* elf section number */
|
||||
int sh_type; /* elf section type */
|
||||
|
@ -544,6 +578,8 @@ typedef struct DLLReference {
|
|||
#define LABEL_DEFINED 0 /* label is defined */
|
||||
#define LABEL_FORWARD 1 /* label is forward defined */
|
||||
#define LABEL_DECLARED 2 /* label is declared but never used */
|
||||
#define LABEL_GONE 3 /* label isn't in scope, but not yet popped
|
||||
from local_label_stack (stmt exprs) */
|
||||
|
||||
/* type_decl() types */
|
||||
#define TYPE_ABSTRACT 1 /* type without variable */
|
||||
|
@ -585,6 +621,17 @@ typedef struct TokenString {
|
|||
char alloc;
|
||||
} TokenString;
|
||||
|
||||
/* GNUC attribute definition */
|
||||
typedef struct AttributeDef {
|
||||
struct SymAttr a;
|
||||
struct FuncAttr f;
|
||||
struct Section *section;
|
||||
Sym *cleanup_func;
|
||||
int alias_target; /* token */
|
||||
int asm_label; /* associated asm label */
|
||||
char attr_mode; /* __attribute__((__mode__(...))) */
|
||||
} AttributeDef;
|
||||
|
||||
/* inline functions */
|
||||
typedef struct InlineFunc {
|
||||
TokenString *func_str;
|
||||
|
@ -638,20 +685,20 @@ struct sym_attr {
|
|||
};
|
||||
|
||||
struct TCCState {
|
||||
|
||||
int verbose; /* if true, display some information during compilation */
|
||||
int nostdinc; /* if true, no standard headers are added */
|
||||
int nostdlib; /* if true, no standard libraries are added */
|
||||
int nocommon; /* if true, do not use common symbols for .bss data */
|
||||
int static_link; /* if true, static linking is performed */
|
||||
int rdynamic; /* if true, all symbols are exported */
|
||||
int symbolic; /* if true, resolve symbols in the current module first */
|
||||
int alacarte_link; /* if true, only link in referenced objects from archive */
|
||||
unsigned char verbose; /* if true, display some information during compilation */
|
||||
unsigned char nostdinc; /* if true, no standard headers are added */
|
||||
unsigned char nostdlib; /* if true, no standard libraries are added */
|
||||
unsigned char nocommon; /* if true, do not use common symbols for .bss data */
|
||||
unsigned char static_link; /* if true, static linking is performed */
|
||||
unsigned char rdynamic; /* if true, all symbols are exported */
|
||||
unsigned char symbolic; /* if true, resolve symbols in the current module first */
|
||||
unsigned char filetype; /* file type for compilation (NONE,C,ASM) */
|
||||
unsigned int cversion; /* supported C ISO version, 199901 (the default), 201112, ... */
|
||||
|
||||
char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
|
||||
char *soname; /* as specified on the command line (-soname) */
|
||||
char *rpath; /* as specified on the command line (-Wl,-rpath=) */
|
||||
int enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */
|
||||
unsigned char enable_new_dtags; /* ditto, (-Wl,--enable-new-dtags) */
|
||||
|
||||
/* output type, see TCC_OUTPUT_XXX */
|
||||
int output_type;
|
||||
|
@ -659,25 +706,26 @@ struct TCCState {
|
|||
int output_format;
|
||||
|
||||
/* C language options */
|
||||
int char_is_unsigned;
|
||||
int leading_underscore;
|
||||
int ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
|
||||
int dollars_in_identifiers; /* allows '$' char in identifiers */
|
||||
int ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
|
||||
unsigned char char_is_unsigned;
|
||||
unsigned char leading_underscore;
|
||||
unsigned char ms_extensions; /* allow nested named struct w/o identifier behave like unnamed */
|
||||
unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */
|
||||
unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */
|
||||
|
||||
/* warning switches */
|
||||
int warn_write_strings;
|
||||
int warn_unsupported;
|
||||
int warn_error;
|
||||
int warn_none;
|
||||
int warn_implicit_function_declaration;
|
||||
int warn_gcc_compat;
|
||||
unsigned char warn_write_strings;
|
||||
unsigned char warn_unsupported;
|
||||
unsigned char warn_error;
|
||||
unsigned char warn_none;
|
||||
unsigned char warn_implicit_function_declaration;
|
||||
unsigned char warn_gcc_compat;
|
||||
|
||||
/* compile with debug symbol (and use them if error during execution) */
|
||||
int do_debug;
|
||||
unsigned char do_debug;
|
||||
unsigned char do_backtrace;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* compile with built-in memory and bounds checker */
|
||||
int do_bounds_check;
|
||||
unsigned char do_bounds_check;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
enum float_abi float_abi; /* float ABI of the generated code*/
|
||||
|
@ -685,10 +733,15 @@ struct TCCState {
|
|||
int run_test; /* nth test to run with -dt -run */
|
||||
|
||||
addr_t text_addr; /* address of text section */
|
||||
int has_text_addr;
|
||||
unsigned char has_text_addr;
|
||||
|
||||
unsigned section_align; /* section alignment */
|
||||
|
||||
/* use GNU C extensions */
|
||||
unsigned char gnu_ext;
|
||||
/* use TinyCC extensions */
|
||||
unsigned char tcc_ext;
|
||||
|
||||
char *init_symbol; /* symbols to call at load-time (not used currently) */
|
||||
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
|
||||
|
||||
|
@ -696,7 +749,7 @@ struct TCCState {
|
|||
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
int nosse; /* For -mno-sse support. */
|
||||
unsigned char nosse; /* For -mno-sse support. */
|
||||
#endif
|
||||
|
||||
/* array of all loaded dlls (including those referenced by loaded dlls) */
|
||||
|
@ -718,9 +771,10 @@ struct TCCState {
|
|||
char **crt_paths;
|
||||
int nb_crt_paths;
|
||||
|
||||
/* -include files */
|
||||
char **cmd_include_files;
|
||||
int nb_cmd_include_files;
|
||||
/* -D / -U options */
|
||||
CString cmdline_defs;
|
||||
/* -include options */
|
||||
CString cmdline_incl;
|
||||
|
||||
/* error handling */
|
||||
void *error_opaque;
|
||||
|
@ -777,6 +831,22 @@ struct TCCState {
|
|||
Section *got;
|
||||
Section *plt;
|
||||
|
||||
/* predefined sections */
|
||||
Section *text_section, *data_section, *bss_section;
|
||||
Section *common_section;
|
||||
Section *cur_text_section; /* current section where function code is generated */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* bound check related sections */
|
||||
Section *bounds_section; /* contains global data bound description */
|
||||
Section *lbounds_section; /* contains local data bound description */
|
||||
#endif
|
||||
/* symbol sections */
|
||||
Section *symtab_section;
|
||||
/* debug sections */
|
||||
Section *stab_section;
|
||||
/* Is there a new undefined sym since last new_undef_sym() */
|
||||
int new_undef_sym;
|
||||
|
||||
/* temporary dynamic symbol sections (for dll loading) */
|
||||
Section *dynsymtab_section;
|
||||
/* exported dynamic symbol section */
|
||||
|
@ -786,6 +856,9 @@ struct TCCState {
|
|||
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
|
||||
struct sym_attr *sym_attrs;
|
||||
int nb_sym_attrs;
|
||||
/* ptr to next reloc entry reused */
|
||||
ElfW_Rel *qrel;
|
||||
# define qrel s1->qrel
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
/* PE info */
|
||||
|
@ -799,6 +872,17 @@ struct TCCState {
|
|||
int uw_sym;
|
||||
unsigned uw_offs;
|
||||
# endif
|
||||
# define ELF_OBJ_ONLY
|
||||
#endif
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
int nb_sym_versions;
|
||||
struct sym_version *sym_versions;
|
||||
int nb_sym_to_version;
|
||||
int *sym_to_version;
|
||||
int dt_verneednum;
|
||||
Section *versym_section;
|
||||
Section *verneed_section;
|
||||
#endif
|
||||
|
||||
#ifdef TCC_IS_NATIVE
|
||||
|
@ -807,24 +891,36 @@ struct TCCState {
|
|||
int nb_runtime_mem;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
int rt_num_callers;
|
||||
#endif
|
||||
|
||||
int fd, cc; /* used by tcc_load_ldscript */
|
||||
|
||||
/* benchmark info */
|
||||
int total_idents;
|
||||
int total_lines;
|
||||
int total_bytes;
|
||||
|
||||
/* option -dnum (for general development purposes) */
|
||||
int g_debug;
|
||||
|
||||
/* used by main and tcc_parse_args only */
|
||||
struct filespec **files; /* files seen on command line */
|
||||
int nb_files; /* number thereof */
|
||||
int nb_libraries; /* number of libs thereof */
|
||||
int filetype;
|
||||
char *outfile; /* output filename */
|
||||
int option_r; /* option -r */
|
||||
int do_bench; /* option -bench */
|
||||
unsigned char option_r; /* option -r */
|
||||
unsigned char do_bench; /* option -bench */
|
||||
int gen_deps; /* option -MD */
|
||||
char *deps_outfile; /* option -MF */
|
||||
int option_pthread; /* -pthread option */
|
||||
unsigned char option_pthread; /* -pthread option */
|
||||
int argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
struct filespec {
|
||||
char type;
|
||||
char alacarte;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
|
@ -838,17 +934,12 @@ struct filespec {
|
|||
#define VT_JMPI 0x0035 /* value is the consequence of jmp false (odd) */
|
||||
#define VT_LVAL 0x0100 /* var is an lvalue */
|
||||
#define VT_SYM 0x0200 /* a symbol value is added */
|
||||
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
|
||||
#define VT_MUSTCAST 0x0C00 /* value must be casted to be correct (used for
|
||||
char/short stored in integer registers) */
|
||||
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
|
||||
#define VT_MUSTBOUND 0x4000 /* bound checking must be done before
|
||||
dereferencing value */
|
||||
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
|
||||
bounding function call point is in vc */
|
||||
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
|
||||
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
|
||||
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
|
||||
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
|
||||
|
||||
/* types */
|
||||
#define VT_BTYPE 0x000f /* mask for basic type */
|
||||
#define VT_VOID 0 /* void type */
|
||||
|
@ -883,7 +974,7 @@ struct filespec {
|
|||
/* currently unused: 0x000[1248]0000 */
|
||||
|
||||
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
|
||||
#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
|
||||
#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
|
||||
#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
|
||||
#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
|
||||
|
||||
|
@ -903,6 +994,11 @@ struct filespec {
|
|||
#define VT_ASM (VT_VOID | VT_UNSIGNED)
|
||||
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
|
||||
|
||||
/* general: set/get the pseudo-bitfield value for bit-mask M */
|
||||
#define BFVAL(M,N) ((unsigned)((M) & ~((M) << 1)) * (N))
|
||||
#define BFGET(X,M) (((X) & (M)) / BFVAL(M,1))
|
||||
#define BFSET(X,M,N) ((X) = ((X) & ~(M)) | BFVAL(M,N))
|
||||
|
||||
/* token values */
|
||||
|
||||
/* warning: the following compare tokens depend on i386 asm code */
|
||||
|
@ -1079,16 +1175,11 @@ enum tcc_token {
|
|||
|
||||
/* ------------ libtcc.c ------------ */
|
||||
|
||||
/* use GNU C extensions */
|
||||
ST_DATA int gnu_ext;
|
||||
/* use Tiny C extensions */
|
||||
ST_DATA int tcc_ext;
|
||||
/* XXX: get rid of this ASAP */
|
||||
ST_DATA struct TCCState *tcc_state;
|
||||
|
||||
/* public functions currently used by the tcc main function */
|
||||
ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s);
|
||||
ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s);
|
||||
ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s);
|
||||
ST_FUNC char *pstrncpy(char *out, const char *in, size_t num);
|
||||
PUB_FUNC char *tcc_basename(const char *name);
|
||||
PUB_FUNC char *tcc_fileextension (const char *name);
|
||||
|
@ -1117,10 +1208,9 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
|
|||
#define realloc(p, s) use_tcc_realloc(p, s)
|
||||
#undef strdup
|
||||
#define strdup(s) use_tcc_strdup(s)
|
||||
PUB_FUNC void tcc_memcheck(void);
|
||||
PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
|
||||
PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);
|
||||
PUB_FUNC void tcc_warning(const char *fmt, ...);
|
||||
PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2);
|
||||
PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2);
|
||||
PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2);
|
||||
|
||||
/* other utilities */
|
||||
ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
|
||||
|
@ -1130,6 +1220,7 @@ ST_FUNC void cstr_cat(CString *cstr, const char *str, int len);
|
|||
ST_FUNC void cstr_wccat(CString *cstr, int ch);
|
||||
ST_FUNC void cstr_new(CString *cstr);
|
||||
ST_FUNC void cstr_free(CString *cstr);
|
||||
ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...) PRINTF_LIKE(2,3);
|
||||
ST_FUNC void cstr_reset(CString *cstr);
|
||||
|
||||
ST_INLN void sym_free(Sym *sym);
|
||||
|
@ -1150,12 +1241,14 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */
|
||||
#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */
|
||||
#define AFF_TYPE_BIN 0x40 /* file to add is binary */
|
||||
#define AFF_WHOLE_ARCHIVE 0x80 /* load all objects from archive */
|
||||
/* s->filetype: */
|
||||
#define AFF_TYPE_NONE 0
|
||||
#define AFF_TYPE_C 1
|
||||
#define AFF_TYPE_ASM 2
|
||||
#define AFF_TYPE_ASMPP 3
|
||||
#define AFF_TYPE_LIB 4
|
||||
#define AFF_TYPE_ASMPP 4
|
||||
#define AFF_TYPE_LIB 8
|
||||
#define AFF_TYPE_MASK (15 | AFF_TYPE_BIN)
|
||||
/* values from tcc_object_type(...) */
|
||||
#define AFF_BINTYPE_REL 1
|
||||
#define AFF_BINTYPE_DYN 2
|
||||
|
@ -1163,8 +1256,16 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
#define AFF_BINTYPE_C67 4
|
||||
|
||||
|
||||
#ifndef TCC_TARGET_PE
|
||||
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
|
||||
#endif
|
||||
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1);
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
ST_FUNC void tcc_add_btstub(TCCState *s1);
|
||||
#endif
|
||||
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
|
||||
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
|
||||
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
|
||||
|
@ -1194,8 +1295,6 @@ ST_DATA int tok_flags;
|
|||
ST_DATA CString tokcstr; /* current parsed string, if any */
|
||||
|
||||
/* display benchmark infos */
|
||||
ST_DATA int total_lines;
|
||||
ST_DATA int total_bytes;
|
||||
ST_DATA int tok_ident;
|
||||
ST_DATA TokenSym **table_ident;
|
||||
|
||||
|
@ -1270,18 +1369,14 @@ static inline int toup(int c) {
|
|||
/* ------------ tccgen.c ------------ */
|
||||
|
||||
#define SYM_POOL_NB (8192 / sizeof(Sym))
|
||||
ST_DATA Sym *sym_free_first;
|
||||
ST_DATA void **sym_pools;
|
||||
ST_DATA int nb_sym_pools;
|
||||
|
||||
ST_DATA Sym *global_stack;
|
||||
ST_DATA Sym *local_stack;
|
||||
ST_DATA Sym *local_label_stack;
|
||||
ST_DATA Sym *global_label_stack;
|
||||
ST_DATA Sym *define_stack;
|
||||
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
|
||||
ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop, *pvtop;
|
||||
#define vstack (__vstack + 1)
|
||||
ST_DATA CType int_type, func_old_type, char_pointer_type;
|
||||
ST_DATA SValue *vtop;
|
||||
ST_DATA int rsym, anon_sym, ind, loc;
|
||||
|
||||
ST_DATA int const_wanted; /* true if constant wanted */
|
||||
|
@ -1290,18 +1385,20 @@ ST_DATA int global_expr; /* true if compound literals must be allocated globall
|
|||
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
|
||||
ST_DATA int func_var; /* true if current function is variadic */
|
||||
ST_DATA int func_vc;
|
||||
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
|
||||
ST_DATA const char *funcname;
|
||||
ST_DATA int g_debug;
|
||||
|
||||
ST_FUNC void tcc_debug_start(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_end(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_bincl(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_eincl(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename);
|
||||
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
|
||||
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
|
||||
ST_FUNC void tcc_debug_line(TCCState *s1);
|
||||
|
||||
ST_FUNC void tccgen_init(TCCState *s1);
|
||||
ST_FUNC int tccgen_compile(TCCState *s1);
|
||||
ST_FUNC void free_inline_functions(TCCState *s);
|
||||
ST_FUNC void tccgen_finish(TCCState *s1);
|
||||
ST_FUNC void check_vstack(void);
|
||||
|
||||
ST_INLN int is_float(int t);
|
||||
|
@ -1310,16 +1407,19 @@ ST_FUNC void test_lvalue(void);
|
|||
ST_FUNC void vpushi(int v);
|
||||
ST_FUNC ElfSym *elfsym(Sym *);
|
||||
ST_FUNC void update_storage(Sym *sym);
|
||||
ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
|
||||
ST_FUNC Sym *external_global_sym(int v, CType *type);
|
||||
ST_FUNC void vset(CType *type, int r, int v);
|
||||
ST_FUNC void vset_VT_CMP(int op);
|
||||
ST_FUNC void vswap(void);
|
||||
ST_FUNC void vpush_global_sym(CType *type, int v);
|
||||
ST_FUNC void vrote(SValue *e, int n);
|
||||
ST_FUNC void vrott(int n);
|
||||
ST_FUNC void vrotb(int n);
|
||||
#if PTR_SIZE == 4
|
||||
ST_FUNC void lexpand(void);
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
ST_FUNC int get_reg_ex(int rc, int rc2);
|
||||
ST_FUNC void lexpand_nr(void);
|
||||
#endif
|
||||
ST_FUNC void vpushv(SValue *v);
|
||||
ST_FUNC void save_reg(int r);
|
||||
|
@ -1337,11 +1437,8 @@ ST_FUNC void vstore(void);
|
|||
ST_FUNC void inc(int post, int c);
|
||||
ST_FUNC void parse_mult_str (CString *astr, const char *msg);
|
||||
ST_FUNC void parse_asm_str(CString *astr);
|
||||
ST_FUNC int lvalue_type(int t);
|
||||
ST_FUNC void indir(void);
|
||||
ST_FUNC void unary(void);
|
||||
ST_FUNC void expr_prod(void);
|
||||
ST_FUNC void expr_sum(void);
|
||||
ST_FUNC void gexpr(void);
|
||||
ST_FUNC int expr_const(void);
|
||||
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
|
||||
|
@ -1350,6 +1447,9 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
|
|||
#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
|
||||
ST_FUNC int classify_x86_64_va_arg(CType *ty);
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void gbound_args(int nb_args);
|
||||
#endif
|
||||
|
||||
/* ------------ tccelf.c ------------ */
|
||||
|
||||
|
@ -1367,29 +1467,14 @@ typedef struct {
|
|||
unsigned int n_value; /* value of symbol */
|
||||
} Stab_Sym;
|
||||
|
||||
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
|
||||
ST_DATA Section *common_section;
|
||||
ST_DATA Section *cur_text_section; /* current section where function code is generated */
|
||||
#ifdef CONFIG_TCC_ASM
|
||||
ST_DATA Section *last_text_section; /* to handle .previous asm directive */
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* bound check related sections */
|
||||
ST_DATA Section *bounds_section; /* contains global data bound description */
|
||||
ST_DATA Section *lbounds_section; /* contains local data bound description */
|
||||
ST_FUNC void tccelf_bounds_new(TCCState *s);
|
||||
#endif
|
||||
/* symbol sections */
|
||||
ST_DATA Section *symtab_section;
|
||||
/* debug sections */
|
||||
ST_DATA Section *stab_section, *stabstr_section;
|
||||
|
||||
ST_FUNC void tccelf_new(TCCState *s);
|
||||
ST_FUNC void tccelf_delete(TCCState *s);
|
||||
ST_FUNC void tccelf_stab_new(TCCState *s);
|
||||
ST_FUNC void tccelf_begin_file(TCCState *s1);
|
||||
ST_FUNC void tccelf_end_file(TCCState *s1);
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void tccelf_bounds_new(TCCState *s);
|
||||
#endif
|
||||
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
|
||||
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
|
||||
ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
|
||||
|
@ -1412,10 +1497,9 @@ ST_FUNC int find_elf_sym(Section *s, const char *name);
|
|||
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol);
|
||||
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend);
|
||||
|
||||
ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value);
|
||||
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
|
||||
ST_FUNC void put_stabn(int type, int other, int desc, int value);
|
||||
ST_FUNC void put_stabd(int type, int other, int desc);
|
||||
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value);
|
||||
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
|
||||
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value);
|
||||
|
||||
ST_FUNC void resolve_common_syms(TCCState *s1);
|
||||
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
|
||||
|
@ -1423,26 +1507,28 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s);
|
|||
|
||||
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
|
||||
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
|
||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd);
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1);
|
||||
ST_FUNC void tcc_add_runtime(TCCState *s1);
|
||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
|
||||
ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
ST_FUNC void build_got_entries(TCCState *s1);
|
||||
#endif
|
||||
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
|
||||
ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
|
||||
|
||||
ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err);
|
||||
ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
|
||||
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
||||
#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
|
||||
ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
|
||||
#endif
|
||||
|
||||
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs);
|
||||
|
||||
#ifndef TCC_TARGET_PE
|
||||
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
|
||||
ST_FUNC int tcc_load_ldscript(TCCState *s1);
|
||||
ST_FUNC uint8_t *parse_comment(uint8_t *p);
|
||||
ST_FUNC void minp(void);
|
||||
ST_INLN void inp(void);
|
||||
ST_FUNC int handle_eob(void);
|
||||
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
|
||||
ST_FUNC void tcc_add_runtime(TCCState *s1);
|
||||
#endif
|
||||
|
||||
/* ------------ xxx-link.c ------------ */
|
||||
|
@ -1456,12 +1542,13 @@ enum gotplt_entry {
|
|||
ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */
|
||||
};
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
ST_FUNC int code_reloc (int reloc_type);
|
||||
ST_FUNC int gotplt_entry_type (int reloc_type);
|
||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr);
|
||||
ST_FUNC void relocate_init(Section *sr);
|
||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
|
||||
ST_FUNC void relocate_plt(TCCState *s1);
|
||||
#endif
|
||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val);
|
||||
|
||||
/* ------------ xxx-gen.c ------------ */
|
||||
|
||||
|
@ -1473,27 +1560,22 @@ ST_FUNC void load(int r, SValue *sv);
|
|||
ST_FUNC void store(int r, SValue *v);
|
||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
|
||||
ST_FUNC void gfunc_call(int nb_args);
|
||||
ST_FUNC void gfunc_prolog(CType *func_type);
|
||||
ST_FUNC void gfunc_prolog(Sym *func_sym);
|
||||
ST_FUNC void gfunc_epilog(void);
|
||||
ST_FUNC void gen_fill_nops(int);
|
||||
ST_FUNC int gjmp(int t);
|
||||
ST_FUNC void gjmp_addr(int a);
|
||||
ST_FUNC int gtst(int inv, int t);
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
ST_FUNC void gtst_addr(int inv, int a);
|
||||
#else
|
||||
#define gtst_addr(inv, a) gsym_addr(gtst(inv, 0), a)
|
||||
#endif
|
||||
ST_FUNC int gjmp_cond(int op, int t);
|
||||
ST_FUNC int gjmp_append(int n, int t);
|
||||
ST_FUNC void gen_opi(int op);
|
||||
ST_FUNC void gen_opf(int op);
|
||||
ST_FUNC void gen_cvt_ftoi(int t);
|
||||
ST_FUNC void gen_cvt_itof(int t);
|
||||
ST_FUNC void gen_cvt_ftof(int t);
|
||||
ST_FUNC void ggoto(void);
|
||||
#ifndef TCC_TARGET_C67
|
||||
ST_FUNC void o(unsigned int c);
|
||||
#endif
|
||||
#ifndef TCC_TARGET_ARM
|
||||
ST_FUNC void gen_cvt_itof(int t);
|
||||
#endif
|
||||
ST_FUNC void gen_vla_sp_save(int addr);
|
||||
ST_FUNC void gen_vla_sp_restore(int addr);
|
||||
ST_FUNC void gen_vla_alloc(CType *type, int align);
|
||||
|
@ -1530,6 +1612,7 @@ ST_FUNC void gen_le16(int c);
|
|||
ST_FUNC void gen_le32(int c);
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
|
||||
ST_FUNC void gen_cvt_csti(int t);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|
@ -1544,6 +1627,8 @@ ST_FUNC void gen_opl(int op);
|
|||
#ifdef TCC_TARGET_PE
|
||||
ST_FUNC void gen_vla_result(int addr);
|
||||
#endif
|
||||
ST_FUNC void gen_cvt_sxtw(void);
|
||||
ST_FUNC void gen_cvt_csti(int t);
|
||||
#endif
|
||||
|
||||
/* ------------ arm-gen.c ------------ */
|
||||
|
@ -1552,17 +1637,26 @@ ST_FUNC void gen_vla_result(int addr);
|
|||
PUB_FUNC const char *default_elfinterp(struct TCCState *s);
|
||||
#endif
|
||||
ST_FUNC void arm_init(struct TCCState *s);
|
||||
ST_FUNC void gen_cvt_itof1(int t);
|
||||
#endif
|
||||
|
||||
/* ------------ arm64-gen.c ------------ */
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
ST_FUNC void gen_cvt_sxtw(void);
|
||||
ST_FUNC void gen_opl(int op);
|
||||
ST_FUNC void gfunc_return(CType *func_type);
|
||||
ST_FUNC void gen_va_start(void);
|
||||
ST_FUNC void gen_va_arg(CType *t);
|
||||
ST_FUNC void gen_clear_cache(void);
|
||||
ST_FUNC void gen_cvt_sxtw(void);
|
||||
ST_FUNC void gen_cvt_csti(int t);
|
||||
#endif
|
||||
|
||||
/* ------------ riscv64-gen.c ------------ */
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
ST_FUNC void gen_opl(int op);
|
||||
//ST_FUNC void gfunc_return(CType *func_type);
|
||||
ST_FUNC void gen_va_start(void);
|
||||
ST_FUNC void arch_transfer_ret_regs(int);
|
||||
ST_FUNC void gen_cvt_sxtw(void);
|
||||
#endif
|
||||
|
||||
/* ------------ c67-gen.c ------------ */
|
||||
|
@ -1630,12 +1724,6 @@ ST_FUNC void dlclose(void *p);
|
|||
ST_FUNC const char *dlerror(void);
|
||||
ST_FUNC void *dlsym(void *handle, const char *symbol);
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
ST_DATA int rt_num_callers;
|
||||
ST_DATA const char **rt_bound_error_msg;
|
||||
ST_DATA void *rt_prog_main;
|
||||
ST_FUNC void tcc_set_num_callers(int n);
|
||||
#endif
|
||||
ST_FUNC void tcc_run_free(TCCState *s1);
|
||||
#endif
|
||||
|
||||
|
@ -1656,5 +1744,42 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
|||
#else
|
||||
#define ST_DATA
|
||||
#endif
|
||||
/********************************************************/
|
||||
|
||||
#define text_section TCC_STATE_VAR(text_section)
|
||||
#define data_section TCC_STATE_VAR(data_section)
|
||||
#define bss_section TCC_STATE_VAR(bss_section)
|
||||
#define common_section TCC_STATE_VAR(common_section)
|
||||
#define cur_text_section TCC_STATE_VAR(cur_text_section)
|
||||
#define bounds_section TCC_STATE_VAR(bounds_section)
|
||||
#define lbounds_section TCC_STATE_VAR(lbounds_section)
|
||||
#define symtab_section TCC_STATE_VAR(symtab_section)
|
||||
#define stab_section TCC_STATE_VAR(stab_section)
|
||||
#define stabstr_section stab_section->link
|
||||
#define gnu_ext TCC_STATE_VAR(gnu_ext)
|
||||
#define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort)
|
||||
#define tcc_error TCC_SET_STATE(_tcc_error)
|
||||
#define tcc_warning TCC_SET_STATE(_tcc_warning)
|
||||
|
||||
#define total_idents TCC_STATE_VAR(total_idents)
|
||||
#define total_lines TCC_STATE_VAR(total_lines)
|
||||
#define total_bytes TCC_STATE_VAR(total_bytes)
|
||||
|
||||
PUB_FUNC void tcc_enter_state(TCCState *s1);
|
||||
|
||||
/********************************************************/
|
||||
#endif /* _TCC_H */
|
||||
|
||||
#undef TCC_STATE_VAR
|
||||
#undef TCC_SET_STATE
|
||||
|
||||
#ifdef USING_GLOBALS
|
||||
# define TCC_STATE_VAR(sym) tcc_state->sym
|
||||
# define TCC_SET_STATE(fn) fn
|
||||
# undef USING_GLOBALS
|
||||
#else
|
||||
# define TCC_STATE_VAR(sym) s1->sym
|
||||
# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
|
||||
/* actually we could avoid the tcc_enter_state(s1) hack by using
|
||||
__VA_ARGS__ except that some compiler doesn't support it. */
|
||||
#endif
|
||||
|
|
23
tccasm.c
23
tccasm.c
|
@ -18,9 +18,12 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
#ifdef CONFIG_TCC_ASM
|
||||
|
||||
static Section *last_text_section; /* to handle .previous asm directive */
|
||||
|
||||
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
||||
{
|
||||
char buf[64];
|
||||
|
@ -38,7 +41,7 @@ static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, in
|
|||
static Sym *asm_label_find(int v)
|
||||
{
|
||||
Sym *sym = sym_find(v);
|
||||
while (sym && sym->sym_scope)
|
||||
while (sym && sym->sym_scope && !(sym->type.t & VT_STATIC))
|
||||
sym = sym->prev_tok;
|
||||
return sym;
|
||||
}
|
||||
|
@ -48,9 +51,7 @@ static Sym *asm_label_push(int v)
|
|||
/* We always add VT_EXTERN, for sym definition that's tentative
|
||||
(for .set, removed for real defs), for mere references it's correct
|
||||
as is. */
|
||||
Sym *sym = global_identifier_push(v, VT_ASM | VT_EXTERN | VT_STATIC, 0);
|
||||
sym->r = VT_CONST | VT_SYM;
|
||||
return sym;
|
||||
return global_identifier_push(v, VT_ASM | VT_EXTERN | VT_STATIC, 0);
|
||||
}
|
||||
|
||||
/* Return a symbol we can use inside the assembler, having name NAME.
|
||||
|
@ -107,7 +108,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
|||
if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF))
|
||||
sym = sym->prev_tok;
|
||||
if (!sym)
|
||||
tcc_error("local label '%d' not found backward", n);
|
||||
tcc_error("local label '%d' not found backward", (int)n);
|
||||
} else {
|
||||
/* forward */
|
||||
if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
|
||||
|
@ -914,9 +915,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
|||
next();
|
||||
if (tok == TOK_EOF)
|
||||
break;
|
||||
/* generate line number info */
|
||||
if (global && s1->do_debug)
|
||||
tcc_debug_line(s1);
|
||||
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
||||
redo:
|
||||
if (tok == '#') {
|
||||
|
@ -1148,8 +1146,8 @@ ST_FUNC void asm_instr(void)
|
|||
ASMOperand operands[MAX_ASM_OPERANDS];
|
||||
int nb_outputs, nb_operands, i, must_subst, out_reg;
|
||||
uint8_t clobber_regs[NB_ASM_REGS];
|
||||
Section *sec;
|
||||
|
||||
next();
|
||||
/* since we always generate the asm() instruction, we can ignore
|
||||
volatile */
|
||||
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
|
||||
|
@ -1222,8 +1220,15 @@ ST_FUNC void asm_instr(void)
|
|||
asm_gen_code(operands, nb_operands, nb_outputs, 0,
|
||||
clobber_regs, out_reg);
|
||||
|
||||
/* We don't allow switching section within inline asm to
|
||||
bleed out to surrounding code. */
|
||||
sec = cur_text_section;
|
||||
/* assemble the string with tcc internal assembler */
|
||||
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
|
||||
if (sec != cur_text_section) {
|
||||
tcc_warning("inline asm tries to change current section");
|
||||
use_section1(tcc_state, sec);
|
||||
}
|
||||
|
||||
/* restore the current C token */
|
||||
next();
|
||||
|
|
14
tcccoff.c
14
tcccoff.c
|
@ -40,12 +40,12 @@ int FuncEntries[MAX_FUNCS];
|
|||
|
||||
int OutputTheSection(Section * sect);
|
||||
short int GetCoffFlags(const char *s);
|
||||
void SortSymbolTable(void);
|
||||
void SortSymbolTable(TCCState *s1);
|
||||
Section *FindSection(TCCState * s1, const char *sname);
|
||||
|
||||
int C67_main_entry_point;
|
||||
|
||||
int FindCoffSymbolIndex(const char *func_name);
|
||||
int FindCoffSymbolIndex(TCCState * s1, const char *func_name);
|
||||
int nb_syms;
|
||||
|
||||
typedef struct {
|
||||
|
@ -92,7 +92,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
|
|||
sbss = FindSection(s1, ".bss");
|
||||
|
||||
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
|
||||
coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1");
|
||||
coff_nb_syms = FindCoffSymbolIndex(s1, "XXXXXXXXXX1");
|
||||
|
||||
file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */
|
||||
file_hdr.f_timdat = 0; /* time & date stamp */
|
||||
|
@ -366,7 +366,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
|
|||
// finally global symbols
|
||||
|
||||
if (s1->do_debug)
|
||||
SortSymbolTable();
|
||||
SortSymbolTable(s1);
|
||||
|
||||
// write line no data
|
||||
|
||||
|
@ -437,7 +437,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
|
|||
// output a function begin
|
||||
|
||||
CoffLineNo.l_addr.l_symndx =
|
||||
FindCoffSymbolIndex(func_name);
|
||||
FindCoffSymbolIndex(s1, func_name);
|
||||
CoffLineNo.l_lnno = 0;
|
||||
|
||||
fwrite(&CoffLineNo, 6, 1, f);
|
||||
|
@ -690,7 +690,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
|
|||
// group the symbols in order of filename, func1, func2, etc
|
||||
// finally global symbols
|
||||
|
||||
void SortSymbolTable(void)
|
||||
void SortSymbolTable(TCCState *s1)
|
||||
{
|
||||
int i, j, k, n = 0;
|
||||
Elf32_Sym *p, *p2, *NewTable;
|
||||
|
@ -770,7 +770,7 @@ void SortSymbolTable(void)
|
|||
}
|
||||
|
||||
|
||||
int FindCoffSymbolIndex(const char *func_name)
|
||||
int FindCoffSymbolIndex(TCCState *s1, const char *func_name)
|
||||
{
|
||||
int i, n = 0;
|
||||
Elf32_Sym *p;
|
||||
|
|
378
tccpe.c
378
tccpe.c
|
@ -231,6 +231,15 @@ typedef struct _IMAGE_BASE_RELOCATION {
|
|||
#define IMAGE_REL_BASED_REL32 7
|
||||
#define IMAGE_REL_BASED_DIR64 10
|
||||
|
||||
#define IMAGE_SCN_CNT_CODE 0x00000020
|
||||
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
|
||||
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_SHARED 0x10000000
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
@ -279,17 +288,6 @@ struct pe_rsrc_reloc {
|
|||
/* ------------------------------------------------------------- */
|
||||
/* internal temporary structures */
|
||||
|
||||
/*
|
||||
#define IMAGE_SCN_CNT_CODE 0x00000020
|
||||
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
|
||||
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_SHARED 0x10000000
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
*/
|
||||
|
||||
enum {
|
||||
sec_text = 0,
|
||||
sec_data ,
|
||||
|
@ -299,10 +297,12 @@ enum {
|
|||
sec_other ,
|
||||
sec_rsrc ,
|
||||
sec_stab ,
|
||||
sec_stabstr ,
|
||||
sec_reloc ,
|
||||
sec_last
|
||||
};
|
||||
|
||||
#if 0
|
||||
static const DWORD pe_sec_flags[] = {
|
||||
0x60000020, /* ".text" , */
|
||||
0xC0000040, /* ".data" , */
|
||||
|
@ -314,14 +314,15 @@ static const DWORD pe_sec_flags[] = {
|
|||
0x42000802, /* ".stab" , */
|
||||
0x42000040, /* ".reloc" , */
|
||||
};
|
||||
#endif
|
||||
|
||||
struct section_info {
|
||||
int cls, ord;
|
||||
int cls;
|
||||
char name[32];
|
||||
DWORD sh_addr;
|
||||
DWORD sh_size;
|
||||
DWORD sh_flags;
|
||||
unsigned char *data;
|
||||
DWORD pe_flags;
|
||||
Section *sec;
|
||||
DWORD data_size;
|
||||
IMAGE_SECTION_HEADER ish;
|
||||
};
|
||||
|
@ -357,7 +358,7 @@ struct pe_info {
|
|||
int subsystem;
|
||||
DWORD section_align;
|
||||
DWORD file_align;
|
||||
struct section_info *sec_info;
|
||||
struct section_info **sec_info;
|
||||
int sec_count;
|
||||
struct pe_import_info **imp_info;
|
||||
int imp_count;
|
||||
|
@ -430,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ST_FN DWORD umin(DWORD a, DWORD b)
|
||||
static DWORD umin(DWORD a, DWORD b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
#endif
|
||||
|
||||
static DWORD umax(DWORD a, DWORD b)
|
||||
{
|
||||
|
@ -465,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz
|
|||
hdr->opthdr.DataDirectory[dir].Size = size;
|
||||
}
|
||||
|
||||
static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
|
||||
struct pe_file {
|
||||
FILE *op;
|
||||
DWORD sum;
|
||||
unsigned pos;
|
||||
};
|
||||
|
||||
static int pe_fwrite(void *data, int len, struct pe_file *pf)
|
||||
{
|
||||
if (psum) {
|
||||
DWORD sum = *psum;
|
||||
WORD *p = data;
|
||||
int i;
|
||||
for (i = len; i > 0; i -= 2) {
|
||||
sum += (i >= 2) ? *p++ : *(BYTE*)p;
|
||||
sum = (sum + (sum >> 16)) & 0xFFFF;
|
||||
}
|
||||
*psum = sum;
|
||||
WORD *p = data;
|
||||
DWORD sum;
|
||||
int ret, i;
|
||||
pf->pos += (ret = fwrite(data, 1, len, pf->op));
|
||||
sum = pf->sum;
|
||||
for (i = len; i > 0; i -= 2) {
|
||||
sum += (i >= 2) ? *p++ : *(BYTE*)p;
|
||||
sum = (sum + (sum >> 16)) & 0xFFFF;
|
||||
}
|
||||
return len == fwrite(data, 1, len, fp) ? 0 : -1;
|
||||
pf->sum = sum;
|
||||
return len == ret ? 0 : -1;
|
||||
}
|
||||
|
||||
static void pe_fpad(FILE *fp, DWORD new_pos)
|
||||
static void pe_fpad(struct pe_file *pf, DWORD new_pos)
|
||||
{
|
||||
DWORD pos = ftell(fp);
|
||||
while (++pos <= new_pos)
|
||||
fputc(0, fp);
|
||||
char buf[256];
|
||||
int n, diff = new_pos - pf->pos;
|
||||
memset(buf, 0, sizeof buf);
|
||||
while (diff > 0) {
|
||||
diff -= n = umin(diff, sizeof buf);
|
||||
fwrite(buf, n, 1, pf->op);
|
||||
}
|
||||
pf->pos = new_pos;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
@ -596,13 +606,14 @@ static int pe_write(struct pe_info *pe)
|
|||
struct pe_header pe_header = pe_template;
|
||||
|
||||
int i;
|
||||
FILE *op;
|
||||
DWORD file_offset, sum;
|
||||
struct pe_file pf = {0};
|
||||
DWORD file_offset;
|
||||
struct section_info *si;
|
||||
IMAGE_SECTION_HEADER *psh;
|
||||
TCCState *s1 = pe->s1;
|
||||
|
||||
op = fopen(pe->filename, "wb");
|
||||
if (NULL == op) {
|
||||
pf.op = fopen(pe->filename, "wb");
|
||||
if (NULL == pf.op) {
|
||||
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -621,7 +632,7 @@ static int pe_write(struct pe_info *pe)
|
|||
DWORD addr, size;
|
||||
const char *sh_name;
|
||||
|
||||
si = pe->sec_info + i;
|
||||
si = pe->sec_info[i];
|
||||
sh_name = si->name;
|
||||
addr = si->sh_addr - pe->imagebase;
|
||||
size = si->sh_size;
|
||||
|
@ -633,12 +644,14 @@ static int pe_write(struct pe_info *pe)
|
|||
|
||||
switch (si->cls) {
|
||||
case sec_text:
|
||||
pe_header.opthdr.BaseOfCode = addr;
|
||||
if (!pe_header.opthdr.BaseOfCode)
|
||||
pe_header.opthdr.BaseOfCode = addr;
|
||||
break;
|
||||
|
||||
case sec_data:
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
pe_header.opthdr.BaseOfData = addr;
|
||||
if (!pe_header.opthdr.BaseOfData)
|
||||
pe_header.opthdr.BaseOfData = addr;
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
@ -656,27 +669,22 @@ static int pe_write(struct pe_info *pe)
|
|||
case sec_pdata:
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size);
|
||||
break;
|
||||
|
||||
case sec_stab:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pe->thunk == pe->s1->sections[si->ord]) {
|
||||
if (pe->imp_size) {
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
|
||||
pe->imp_offs + addr, pe->imp_size);
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
|
||||
pe->iat_offs + addr, pe->iat_size);
|
||||
}
|
||||
if (pe->exp_size) {
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||
pe->exp_offs + addr, pe->exp_size);
|
||||
}
|
||||
if (pe->imp_size) {
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
|
||||
pe->imp_offs, pe->imp_size);
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
|
||||
pe->iat_offs, pe->iat_size);
|
||||
}
|
||||
if (pe->exp_size) {
|
||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||
pe->exp_offs, pe->exp_size);
|
||||
}
|
||||
|
||||
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
|
||||
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
|
||||
|
||||
psh->Characteristics = pe_sec_flags[si->cls];
|
||||
psh->Characteristics = si->pe_flags;
|
||||
psh->VirtualAddress = addr;
|
||||
psh->Misc.VirtualSize = size;
|
||||
pe_header.opthdr.SizeOfImage =
|
||||
|
@ -705,25 +713,29 @@ static int pe_write(struct pe_info *pe)
|
|||
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
|
||||
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
|
||||
|
||||
sum = 0;
|
||||
pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
|
||||
pe_fwrite(&pe_header, sizeof pe_header, &pf);
|
||||
for (i = 0; i < pe->sec_count; ++i)
|
||||
pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
|
||||
pe_fpad(op, pe->sizeofheaders);
|
||||
pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
|
||||
|
||||
file_offset = pe->sizeofheaders;
|
||||
for (i = 0; i < pe->sec_count; ++i) {
|
||||
si = pe->sec_info + i;
|
||||
psh = &si->ish;
|
||||
if (si->data_size) {
|
||||
pe_fwrite(si->data, si->data_size, op, &sum);
|
||||
file_offset = psh->PointerToRawData + psh->SizeOfRawData;
|
||||
pe_fpad(op, file_offset);
|
||||
Section *s;
|
||||
si = pe->sec_info[i];
|
||||
for (s = si->sec; s; s = s->prev) {
|
||||
pe_fpad(&pf, file_offset);
|
||||
pe_fwrite(s->data, s->data_offset, &pf);
|
||||
if (s->prev)
|
||||
file_offset += s->prev->sh_addr - s->sh_addr;
|
||||
}
|
||||
file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
|
||||
pe_fpad(&pf, file_offset);
|
||||
}
|
||||
|
||||
pe_header.opthdr.CheckSum = sum + file_offset;
|
||||
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
|
||||
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
|
||||
fclose (op);
|
||||
pf.sum += file_offset;
|
||||
fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
|
||||
pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
|
||||
|
||||
fclose (pf.op);
|
||||
#ifndef _WIN32
|
||||
chmod(pe->filename, 0777);
|
||||
#endif
|
||||
|
@ -785,6 +797,7 @@ static void pe_build_imports(struct pe_info *pe)
|
|||
int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
|
||||
DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
|
||||
int ndlls = pe->imp_count;
|
||||
TCCState *s1 = pe->s1;
|
||||
|
||||
for (sym_cnt = i = 0; i < ndlls; ++i)
|
||||
sym_cnt += pe->imp_info[i]->sym_count;
|
||||
|
@ -793,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe)
|
|||
return;
|
||||
|
||||
pe_align_section(pe->thunk, 16);
|
||||
|
||||
pe->imp_offs = dll_ptr = pe->thunk->data_offset;
|
||||
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||
pe->iat_offs = dll_ptr + pe->imp_size;
|
||||
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
|
||||
dll_ptr = pe->thunk->data_offset;
|
||||
thk_ptr = dll_ptr + pe->imp_size;
|
||||
ent_ptr = thk_ptr + pe->iat_size;
|
||||
pe->imp_offs = dll_ptr + rva_base;
|
||||
pe->iat_offs = thk_ptr + rva_base;
|
||||
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
|
||||
|
||||
thk_ptr = pe->iat_offs;
|
||||
ent_ptr = pe->iat_offs + pe->iat_size;
|
||||
|
||||
for (i = 0; i < pe->imp_count; ++i) {
|
||||
IMAGE_IMPORT_DESCRIPTOR *hdr;
|
||||
int k, n, dllindex;
|
||||
|
@ -892,10 +904,11 @@ static void pe_build_exports(struct pe_info *pe)
|
|||
{
|
||||
ElfW(Sym) *sym;
|
||||
int sym_index, sym_end;
|
||||
DWORD rva_base, func_o, name_o, ord_o, str_o;
|
||||
DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
|
||||
IMAGE_EXPORT_DIRECTORY *hdr;
|
||||
int sym_count, ord;
|
||||
struct pe_sort_sym **sorted, *p;
|
||||
TCCState *s1 = pe->s1;
|
||||
|
||||
FILE *op;
|
||||
char buf[260];
|
||||
|
@ -933,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe)
|
|||
pe_align_section(pe->thunk, 16);
|
||||
dllname = tcc_basename(pe->filename);
|
||||
|
||||
pe->exp_offs = pe->thunk->data_offset;
|
||||
func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
|
||||
base_o = pe->thunk->data_offset;
|
||||
func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
|
||||
name_o = func_o + sym_count * sizeof (DWORD);
|
||||
ord_o = name_o + sym_count * sizeof (DWORD);
|
||||
str_o = ord_o + sym_count * sizeof(WORD);
|
||||
|
||||
hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
|
||||
hdr = section_ptr_add(pe->thunk, str_o - base_o);
|
||||
hdr->Characteristics = 0;
|
||||
hdr->Base = 1;
|
||||
hdr->NumberOfFunctions = sym_count;
|
||||
|
@ -981,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe)
|
|||
if (op)
|
||||
fprintf(op, "%s\n", name);
|
||||
}
|
||||
pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
|
||||
|
||||
pe->exp_offs = base_o + rva_base;
|
||||
pe->exp_size = pe->thunk->data_offset - base_o;
|
||||
dynarray_reset(&sorted, &sym_count);
|
||||
if (op)
|
||||
fclose(op);
|
||||
|
@ -990,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe)
|
|||
/* ------------------------------------------------------------- */
|
||||
static void pe_build_reloc (struct pe_info *pe)
|
||||
{
|
||||
DWORD offset, block_ptr, addr;
|
||||
DWORD offset, block_ptr, sh_addr, addr;
|
||||
int count, i;
|
||||
ElfW_Rel *rel, *rel_end;
|
||||
Section *s = NULL, *sr;
|
||||
struct pe_reloc_header *hdr;
|
||||
|
||||
offset = addr = block_ptr = count = i = 0;
|
||||
sh_addr = offset = block_ptr = count = i = 0;
|
||||
rel = rel_end = NULL;
|
||||
|
||||
for(;;) {
|
||||
if (rel < rel_end) {
|
||||
int type = ELFW(R_TYPE)(rel->r_info);
|
||||
addr = rel->r_offset + s->sh_addr;
|
||||
addr = rel->r_offset + sh_addr;
|
||||
++ rel;
|
||||
if (type != REL_TYPE_DIRECT)
|
||||
continue;
|
||||
|
@ -1018,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe)
|
|||
}
|
||||
-- rel;
|
||||
|
||||
} else if (i < pe->sec_count) {
|
||||
sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
|
||||
} else if (s) {
|
||||
sr = s->reloc;
|
||||
if (sr) {
|
||||
rel = (ElfW_Rel *)sr->data;
|
||||
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
|
||||
sh_addr = s->sh_addr;
|
||||
}
|
||||
s = s->prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count) {
|
||||
/* store the last block and ready for a new one */
|
||||
struct pe_reloc_header *hdr;
|
||||
if (count & 1) /* align for DWORDS */
|
||||
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
|
||||
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
|
||||
hdr -> offset = offset - pe->imagebase;
|
||||
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
|
||||
count = 0;
|
||||
}
|
||||
} else if (i < pe->sec_count) {
|
||||
s = pe->sec_info[i]->sec, ++i;
|
||||
continue;
|
||||
|
||||
if (rel >= rel_end)
|
||||
} else if (!count)
|
||||
break;
|
||||
|
||||
/* fill the last block and ready for a new one */
|
||||
if (count & 1) /* align for DWORDS */
|
||||
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
|
||||
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
|
||||
hdr -> offset = offset - pe->imagebase;
|
||||
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1064,7 +1082,6 @@ static int pe_section_class(Section *s)
|
|||
return sec_idata;
|
||||
if (0 == strcmp(name, ".pdata"))
|
||||
return sec_pdata;
|
||||
return sec_other;
|
||||
} else if (type == SHT_NOBITS) {
|
||||
if (flags & SHF_WRITE)
|
||||
return sec_bss;
|
||||
|
@ -1072,9 +1089,11 @@ static int pe_section_class(Section *s)
|
|||
} else {
|
||||
if (0 == strcmp(name, ".reloc"))
|
||||
return sec_reloc;
|
||||
if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */
|
||||
return sec_stab;
|
||||
}
|
||||
if (0 == memcmp(name, ".stab", 5))
|
||||
return name[5] ? sec_stabstr : sec_stab;
|
||||
if (flags & SHF_ALLOC)
|
||||
return sec_other;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1088,48 +1107,39 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||
|
||||
if (PE_DLL == pe->type)
|
||||
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
|
||||
|
||||
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
|
||||
|
||||
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
|
||||
for (o = k = 0 ; k < sec_last; ++k) {
|
||||
for (i = 1; i < pe->s1->nb_sections; ++i) {
|
||||
s = pe->s1->sections[i];
|
||||
if (k == pe_section_class(s)) {
|
||||
// printf("%s %d\n", s->name, k);
|
||||
s->sh_addr = pe->imagebase;
|
||||
if (k == pe_section_class(s))
|
||||
section_order[o++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
|
||||
si = NULL;
|
||||
addr = pe->imagebase + 1;
|
||||
|
||||
for (i = 0; i < o; ++i)
|
||||
{
|
||||
for (i = 0; i < o; ++i) {
|
||||
k = section_order[i];
|
||||
s = pe->s1->sections[k];
|
||||
c = pe_section_class(s);
|
||||
si = &pe->sec_info[pe->sec_count];
|
||||
|
||||
if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
|
||||
continue;
|
||||
|
||||
#ifdef PE_MERGE_DATA
|
||||
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
|
||||
/* append .bss to .data */
|
||||
s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
|
||||
addr += s->data_offset;
|
||||
si[-1].sh_size = addr - si[-1].sh_addr;
|
||||
continue;
|
||||
}
|
||||
if (c == sec_bss)
|
||||
c = sec_data;
|
||||
#endif
|
||||
if (c == sec_stab && 0 == pe->s1->do_debug)
|
||||
continue;
|
||||
|
||||
strcpy(si->name, s->name);
|
||||
si->cls = c;
|
||||
si->ord = k;
|
||||
si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
|
||||
si->sh_flags = s->sh_flags;
|
||||
if (si && c == si->cls) {
|
||||
/* merge with previous section */
|
||||
s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
|
||||
} else {
|
||||
si = NULL;
|
||||
s->sh_addr = addr = pe_virtual_align(pe, addr);
|
||||
}
|
||||
|
||||
if (c == sec_data && NULL == pe->thunk)
|
||||
pe->thunk = s;
|
||||
|
@ -1138,36 +1148,60 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||
pe_build_imports(pe);
|
||||
pe_build_exports(pe);
|
||||
}
|
||||
|
||||
if (c == sec_reloc)
|
||||
if (s == pe->reloc)
|
||||
pe_build_reloc (pe);
|
||||
|
||||
if (s->data_offset)
|
||||
{
|
||||
if (s->sh_type != SHT_NOBITS) {
|
||||
si->data = s->data;
|
||||
si->data_size = s->data_offset;
|
||||
}
|
||||
if (0 == s->data_offset)
|
||||
continue;
|
||||
|
||||
addr += s->data_offset;
|
||||
si->sh_size = s->data_offset;
|
||||
++pe->sec_count;
|
||||
if (si)
|
||||
goto add_section;
|
||||
|
||||
si = tcc_mallocz(sizeof *si);
|
||||
dynarray_add(&pe->sec_info, &pe->sec_count, si);
|
||||
|
||||
strcpy(si->name, s->name);
|
||||
si->cls = c;
|
||||
si->sh_addr = addr;
|
||||
|
||||
si->pe_flags = IMAGE_SCN_MEM_READ;
|
||||
if (s->sh_flags & SHF_EXECINSTR)
|
||||
si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
|
||||
else if (s->sh_type == SHT_NOBITS)
|
||||
si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
|
||||
else
|
||||
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||
if (s->sh_flags & SHF_WRITE)
|
||||
si->pe_flags |= IMAGE_SCN_MEM_WRITE;
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
|
||||
|
||||
add_section:
|
||||
addr += s->data_offset;
|
||||
si->sh_size = addr - si->sh_addr;
|
||||
if (s->sh_type != SHT_NOBITS) {
|
||||
Section **ps = &si->sec;
|
||||
while (*ps)
|
||||
ps = &(*ps)->prev;
|
||||
*ps = s, s->prev = NULL;
|
||||
si->data_size = si->sh_size;
|
||||
}
|
||||
// printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name);
|
||||
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
|
||||
}
|
||||
|
||||
tcc_free(section_order);
|
||||
#if 0
|
||||
for (i = 1; i < pe->s1->nb_sections; ++i) {
|
||||
Section *s = pe->s1->sections[i];
|
||||
int type = s->sh_type;
|
||||
int flags = s->sh_flags;
|
||||
printf("section %-16s %-10s %5x %s,%s,%s\n",
|
||||
printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
|
||||
s->name,
|
||||
type == SHT_PROGBITS ? "progbits" :
|
||||
type == SHT_NOBITS ? "nobits" :
|
||||
type == SHT_SYMTAB ? "symtab" :
|
||||
type == SHT_STRTAB ? "strtab" :
|
||||
type == SHT_RELX ? "rel" : "???",
|
||||
s->sh_addr,
|
||||
s->data_offset,
|
||||
flags & SHF_ALLOC ? "alloc" : "",
|
||||
flags & SHF_WRITE ? "write" : "",
|
||||
|
@ -1176,14 +1210,12 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||
}
|
||||
pe->s1->verbose = 2;
|
||||
#endif
|
||||
|
||||
tcc_free(section_order);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
static int pe_isafunc(int sym_index)
|
||||
static int pe_isafunc(TCCState *s1, int sym_index)
|
||||
{
|
||||
Section *sr = text_section->reloc;
|
||||
ElfW_Rel *rel, *rel_end;
|
||||
|
@ -1203,6 +1235,7 @@ static int pe_check_symbols(struct pe_info *pe)
|
|||
ElfW(Sym) *sym;
|
||||
int sym_index, sym_end;
|
||||
int ret = 0;
|
||||
TCCState *s1 = pe->s1;
|
||||
|
||||
pe_align_section(text_section, 8);
|
||||
|
||||
|
@ -1222,7 +1255,7 @@ static int pe_check_symbols(struct pe_info *pe)
|
|||
|
||||
if (type == STT_NOTYPE) {
|
||||
/* symbols from assembler have no type, find out which */
|
||||
if (pe_isafunc(sym_index))
|
||||
if (pe_isafunc(s1, sym_index))
|
||||
type = STT_FUNC;
|
||||
else
|
||||
type = STT_OBJECT;
|
||||
|
@ -1747,7 +1780,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
|
|||
ret = pe_load_def(s1, fd);
|
||||
else if (pe_load_res(s1, fd) == 0)
|
||||
ret = 0;
|
||||
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4))
|
||||
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2))
|
||||
ret = pe_load_dll(s1, filename);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1757,7 +1790,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
|
|||
static unsigned pe_add_uwwind_info(TCCState *s1)
|
||||
{
|
||||
if (NULL == s1->uw_pdata) {
|
||||
s1->uw_pdata = find_section(tcc_state, ".pdata");
|
||||
s1->uw_pdata = find_section(s1, ".pdata");
|
||||
s1->uw_pdata->sh_addralign = 4;
|
||||
}
|
||||
if (0 == s1->uw_sym)
|
||||
|
@ -1820,6 +1853,12 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
|||
#define PE_STDSYM(n,s) "_" n s
|
||||
#endif
|
||||
|
||||
static void tcc_add_support(TCCState *s1, const char *filename)
|
||||
{
|
||||
if (tcc_add_dll(s1, filename, 0) < 0)
|
||||
tcc_error_noabort("%s not found", filename);
|
||||
}
|
||||
|
||||
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||
{
|
||||
const char *start_symbol;
|
||||
|
@ -1836,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||
else
|
||||
if (TCC_OUTPUT_DLL == s1->output_type) {
|
||||
pe_type = PE_DLL;
|
||||
/* need this for 'tccelf.c:relocate_section()' */
|
||||
s1->output_type = TCC_OUTPUT_EXE;
|
||||
}
|
||||
else {
|
||||
pe_type = PE_EXE;
|
||||
|
@ -1857,34 +1894,46 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||
if (!s1->leading_underscore || strchr(start_symbol, '@'))
|
||||
++start_symbol;
|
||||
|
||||
/* grab the startup code from libtcc1 */
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
if (s1->do_backtrace) {
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bcheck.o");
|
||||
#endif
|
||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||
tcc_add_support(s1, "bt-exe.o");
|
||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bt-dll.o");
|
||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bt-log.o");
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||
tcc_add_btstub(s1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* grab the startup code from libtcc1.a */
|
||||
#ifdef TCC_IS_NATIVE
|
||||
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
|
||||
#endif
|
||||
set_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, start_symbol);
|
||||
|
||||
tcc_add_pragma_libs(s1);
|
||||
set_global_sym(s1, start_symbol, NULL, 0);
|
||||
|
||||
if (0 == s1->nostdlib) {
|
||||
static const char *libs[] = {
|
||||
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||
};
|
||||
const char **pp, *p;
|
||||
tcc_add_support(s1, TCC_LIBTCC1);
|
||||
for (pp = libs; 0 != (p = *pp); ++pp) {
|
||||
if (0 == *p) {
|
||||
if (PE_DLL != pe_type && PE_GUI != pe_type)
|
||||
break;
|
||||
} else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
|
||||
continue;
|
||||
} else {
|
||||
if (*p)
|
||||
tcc_add_library_err(s1, p);
|
||||
}
|
||||
else if (PE_DLL != pe_type && PE_GUI != pe_type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* need this for 'tccelf.c:relocate_section()' */
|
||||
if (TCC_OUTPUT_DLL == s1->output_type)
|
||||
s1->output_type = TCC_OUTPUT_EXE;
|
||||
if (TCC_OUTPUT_MEMORY == s1->output_type)
|
||||
pe_type = PE_RUN;
|
||||
pe->type = pe_type;
|
||||
|
@ -1948,7 +1997,10 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||
pe.filename = filename;
|
||||
pe.s1 = s1;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
tcc_add_bcheck(s1);
|
||||
#endif
|
||||
tcc_add_pragma_libs(s1);
|
||||
pe_add_runtime(s1, &pe);
|
||||
resolve_common_syms(s1);
|
||||
pe_set_options(s1, &pe);
|
||||
|
@ -1973,7 +2025,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||
ret = -1;
|
||||
else
|
||||
ret = pe_write(&pe);
|
||||
tcc_free(pe.sec_info);
|
||||
dynarray_reset(&pe.sec_info, &pe.sec_count);
|
||||
} else {
|
||||
#ifdef TCC_IS_NATIVE
|
||||
pe.thunk = data_section;
|
||||
|
|
169
tccpp.c
169
tccpp.c
|
@ -18,6 +18,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
/********************************************************/
|
||||
|
@ -33,8 +34,6 @@ ST_DATA const int *macro_ptr;
|
|||
ST_DATA CString tokcstr; /* current parsed string, if any */
|
||||
|
||||
/* display benchmark infos */
|
||||
ST_DATA int total_lines;
|
||||
ST_DATA int total_bytes;
|
||||
ST_DATA int tok_ident;
|
||||
ST_DATA TokenSym **table_ident;
|
||||
|
||||
|
@ -54,7 +53,6 @@ static void tok_print(const char *msg, const int *str);
|
|||
|
||||
static struct TinyAlloc *toksym_alloc;
|
||||
static struct TinyAlloc *tokstr_alloc;
|
||||
static struct TinyAlloc *cstr_alloc;
|
||||
|
||||
static TokenString *macro_stack;
|
||||
|
||||
|
@ -250,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
|
|||
tail_call:
|
||||
is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
|
||||
if ((!p || is_own) && size <= al->limit) {
|
||||
if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
|
||||
if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {
|
||||
header = (tal_header_t *)al->p;
|
||||
header->size = adj_size;
|
||||
#ifdef TAL_DEBUG
|
||||
|
@ -331,7 +329,7 @@ static void cstr_realloc(CString *cstr, int new_size)
|
|||
size = 8; /* no need to allocate a too small first string */
|
||||
while (size < new_size)
|
||||
size = size * 2;
|
||||
cstr->data = tal_realloc(cstr_alloc, cstr->data, size);
|
||||
cstr->data = tcc_realloc(cstr->data, size);
|
||||
cstr->size_allocated = size;
|
||||
}
|
||||
|
||||
|
@ -377,7 +375,7 @@ ST_FUNC void cstr_new(CString *cstr)
|
|||
/* free string and reset it to NULL */
|
||||
ST_FUNC void cstr_free(CString *cstr)
|
||||
{
|
||||
tal_free(cstr_alloc, cstr->data);
|
||||
tcc_free(cstr->data);
|
||||
cstr_new(cstr);
|
||||
}
|
||||
|
||||
|
@ -387,6 +385,24 @@ ST_FUNC void cstr_reset(CString *cstr)
|
|||
cstr->size = 0;
|
||||
}
|
||||
|
||||
ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
|
||||
{
|
||||
va_list v;
|
||||
int len, size;
|
||||
|
||||
va_start(v, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, v);
|
||||
va_end(v);
|
||||
size = cstr->size + len + 1;
|
||||
if (size > cstr->size_allocated)
|
||||
cstr_realloc(cstr, size);
|
||||
va_start(v, fmt);
|
||||
vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
|
||||
va_end(v);
|
||||
cstr->size += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* XXX: unicode ? */
|
||||
static void add_char(CString *cstr, int c)
|
||||
{
|
||||
|
@ -584,7 +600,7 @@ ST_FUNC const char *get_tok_str(int v, CValue *cv)
|
|||
|
||||
/* return the current character, handling end of block if necessary
|
||||
(but not stray) */
|
||||
ST_FUNC int handle_eob(void)
|
||||
static int handle_eob(void)
|
||||
{
|
||||
BufferedFile *bf = file;
|
||||
int len;
|
||||
|
@ -617,7 +633,7 @@ ST_FUNC int handle_eob(void)
|
|||
}
|
||||
|
||||
/* read next char from current input file and handle end of input buffer */
|
||||
ST_INLN void inp(void)
|
||||
static inline void inp(void)
|
||||
{
|
||||
ch = *(++(file->buf_ptr));
|
||||
/* end of buffer/file handling */
|
||||
|
@ -703,7 +719,7 @@ static int handle_stray1(uint8_t *p)
|
|||
/* input with '\[\r]\n' handling. Note that this function cannot
|
||||
handle other characters after '\', so you cannot call it inside
|
||||
strings or comments */
|
||||
ST_FUNC void minp(void)
|
||||
static void minp(void)
|
||||
{
|
||||
inp();
|
||||
if (ch == '\\')
|
||||
|
@ -748,7 +764,7 @@ static uint8_t *parse_line_comment(uint8_t *p)
|
|||
}
|
||||
|
||||
/* C comments */
|
||||
ST_FUNC uint8_t *parse_comment(uint8_t *p)
|
||||
static uint8_t *parse_comment(uint8_t *p)
|
||||
{
|
||||
int c;
|
||||
|
||||
|
@ -1119,9 +1135,9 @@ ST_FUNC void end_macro(void)
|
|||
macro_stack = str->prev;
|
||||
macro_ptr = str->prev_ptr;
|
||||
file->line_num = str->save_line_num;
|
||||
if (str->alloc == 2) {
|
||||
str->alloc = 3; /* just mark as finished */
|
||||
} else {
|
||||
if (str->alloc != 0) {
|
||||
if (str->alloc == 2)
|
||||
str->str = NULL; /* don't free */
|
||||
tok_str_free(str);
|
||||
}
|
||||
}
|
||||
|
@ -1213,8 +1229,7 @@ ST_FUNC void tok_str_add_tok(TokenString *s)
|
|||
tok_str_add2(s, tok, &tokc);
|
||||
}
|
||||
|
||||
/* get a token from an integer array and increment pointer
|
||||
accordingly. we code it as a macro to avoid pointer aliasing. */
|
||||
/* get a token from an integer array and increment pointer. */
|
||||
static inline void TOK_GET(int *t, const int **pp, CValue *cv)
|
||||
{
|
||||
const int *p = *pp;
|
||||
|
@ -1339,18 +1354,6 @@ ST_FUNC void free_defines(Sym *b)
|
|||
define_undef(top);
|
||||
sym_free(top);
|
||||
}
|
||||
|
||||
/* restore remaining (-D or predefined) symbols if they were
|
||||
#undef'd in the file */
|
||||
while (b) {
|
||||
int v = b->v;
|
||||
if (v >= TOK_IDENT && v < tok_ident) {
|
||||
Sym **d = &table_ident[v - TOK_IDENT]->sym_define;
|
||||
if (!*d)
|
||||
*d = b;
|
||||
}
|
||||
b = b->prev;
|
||||
}
|
||||
}
|
||||
|
||||
/* label lookup */
|
||||
|
@ -1399,9 +1402,12 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
|
|||
}
|
||||
}
|
||||
/* remove label */
|
||||
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
|
||||
if (s->r != LABEL_GONE)
|
||||
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
|
||||
if (!keep)
|
||||
sym_free(s);
|
||||
else
|
||||
s->r = LABEL_GONE;
|
||||
}
|
||||
if (!keep)
|
||||
*ptop = slast;
|
||||
|
@ -1800,9 +1806,9 @@ ST_FUNC void preprocess(int is_bof)
|
|||
|
||||
if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE)
|
||||
tcc_error("#include recursion too deep");
|
||||
/* store current file in stack, but increment stack later below */
|
||||
*s1->include_stack_ptr = file;
|
||||
i = tok == TOK_INCLUDE_NEXT ? file->include_next_index : 0;
|
||||
/* push current file on stack */
|
||||
*s1->include_stack_ptr++ = file;
|
||||
i = tok == TOK_INCLUDE_NEXT ? file->include_next_index: 0;
|
||||
n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths;
|
||||
for (; i < n; ++i) {
|
||||
char buf1[sizeof file->filename];
|
||||
|
@ -1850,19 +1856,19 @@ ST_FUNC void preprocess(int is_bof)
|
|||
printf("%s: including %s\n", file->prev->filename, file->filename);
|
||||
#endif
|
||||
/* update target deps */
|
||||
dynarray_add(&s1->target_deps, &s1->nb_target_deps,
|
||||
if (s1->gen_deps) {
|
||||
dynarray_add(&s1->target_deps, &s1->nb_target_deps,
|
||||
tcc_strdup(buf1));
|
||||
/* push current file in stack */
|
||||
++s1->include_stack_ptr;
|
||||
}
|
||||
/* add include file debug info */
|
||||
if (s1->do_debug)
|
||||
put_stabs(file->filename, N_BINCL, 0, 0, 0);
|
||||
tcc_debug_bincl(tcc_state);
|
||||
tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
|
||||
ch = file->buf_ptr[0];
|
||||
goto the_end;
|
||||
}
|
||||
tcc_error("include file '%s' not found", buf);
|
||||
include_done:
|
||||
--s1->include_stack_ptr;
|
||||
break;
|
||||
case TOK_IFNDEF:
|
||||
c = 1;
|
||||
|
@ -1953,7 +1959,11 @@ include_done:
|
|||
if (tok == TOK_STR) {
|
||||
if (file->true_filename == file->filename)
|
||||
file->true_filename = tcc_strdup(file->filename);
|
||||
pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.str.data);
|
||||
/* prepend directory from real file */
|
||||
pstrcpy(buf, sizeof buf, file->true_filename);
|
||||
*tcc_basename(buf) = 0;
|
||||
pstrcat(buf, sizeof buf, (char *)tokc.str.data);
|
||||
tcc_debug_putfile(s1, buf);
|
||||
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
||||
break;
|
||||
else
|
||||
|
@ -1963,8 +1973,6 @@ include_done:
|
|||
if (file->fd > 0)
|
||||
total_lines += file->line_num - n;
|
||||
file->line_num = n;
|
||||
if (s1->do_debug)
|
||||
put_stabs(file->filename, N_BINCL, 0, 0, 0);
|
||||
break;
|
||||
case TOK_ERROR:
|
||||
case TOK_WARNING:
|
||||
|
@ -2278,7 +2286,7 @@ static void parse_number(const char *p)
|
|||
q--;
|
||||
ch = *p++;
|
||||
b = 16;
|
||||
} else if (tcc_ext && (ch == 'b' || ch == 'B')) {
|
||||
} else if (tcc_state->tcc_ext && (ch == 'b' || ch == 'B')) {
|
||||
q--;
|
||||
ch = *p++;
|
||||
b = 2;
|
||||
|
@ -2621,9 +2629,7 @@ static inline void next_nomacro1(void)
|
|||
}
|
||||
|
||||
/* add end of include file debug info */
|
||||
if (tcc_state->do_debug) {
|
||||
put_stabd(N_EINCL, 0, 0);
|
||||
}
|
||||
tcc_debug_eincl(tcc_state);
|
||||
/* pop include stack */
|
||||
tcc_close();
|
||||
s1->include_stack_ptr--;
|
||||
|
@ -3144,7 +3150,7 @@ static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
|
|||
if (is_space(tok))
|
||||
continue;
|
||||
tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid"
|
||||
" preprocessing token", n, cstr.data, (char*)cstr.data + n);
|
||||
" preprocessing token", n, (char *)cstr.data, (char*)cstr.data + n);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -3487,14 +3493,14 @@ static void macro_subst(
|
|||
}
|
||||
|
||||
{
|
||||
TokenString str;
|
||||
str.str = (int*)macro_str;
|
||||
begin_macro(&str, 2);
|
||||
TokenString *str = tok_str_alloc();
|
||||
str->str = (int*)macro_str;
|
||||
begin_macro(str, 2);
|
||||
|
||||
tok = t;
|
||||
macro_subst_tok(tok_str, nested_list, s);
|
||||
|
||||
if (str.alloc == 3) {
|
||||
if (macro_stack != str) {
|
||||
/* already finished by reading function macro arguments */
|
||||
break;
|
||||
}
|
||||
|
@ -3552,7 +3558,7 @@ ST_FUNC void next(void)
|
|||
tokstr_buf.len = 0;
|
||||
macro_subst_tok(&tokstr_buf, &nested_list, s);
|
||||
tok_str_add(&tokstr_buf, 0);
|
||||
begin_macro(&tokstr_buf, 2);
|
||||
begin_macro(&tokstr_buf, 0);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
@ -3581,7 +3587,8 @@ ST_INLN void unget_tok(int last_tok)
|
|||
ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
|
||||
{
|
||||
CString cstr;
|
||||
int i;
|
||||
|
||||
tccpp_new(s1);
|
||||
|
||||
s1->include_stack_ptr = s1->include_stack;
|
||||
s1->ifdef_stack_ptr = s1->ifdef_stack;
|
||||
|
@ -3590,7 +3597,6 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
|
|||
pp_counter = 0;
|
||||
pp_debug_tok = pp_debug_symv = 0;
|
||||
pp_once++;
|
||||
pvtop = vtop = vstack - 1;
|
||||
s1->pack_stack[0] = 0;
|
||||
s1->pack_stack_ptr = s1->pack_stack;
|
||||
|
||||
|
@ -3598,26 +3604,22 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
|
|||
set_idnum('.', is_asm ? IS_ID : 0);
|
||||
|
||||
cstr_new(&cstr);
|
||||
cstr_cat(&cstr, "\"", -1);
|
||||
cstr_cat(&cstr, file->filename, -1);
|
||||
cstr_cat(&cstr, "\"", 0);
|
||||
tcc_define_symbol(s1, "__BASE_FILE__", cstr.data);
|
||||
|
||||
cstr_reset(&cstr);
|
||||
for (i = 0; i < s1->nb_cmd_include_files; i++) {
|
||||
cstr_cat(&cstr, "#include \"", -1);
|
||||
cstr_cat(&cstr, s1->cmd_include_files[i], -1);
|
||||
cstr_cat(&cstr, "\"\n", -1);
|
||||
}
|
||||
if (cstr.size) {
|
||||
*s1->include_stack_ptr++ = file;
|
||||
tcc_open_bf(s1, "<command line>", cstr.size);
|
||||
memcpy(file->buffer, cstr.data, cstr.size);
|
||||
}
|
||||
cstr_free(&cstr);
|
||||
|
||||
if (s1->cmdline_defs.size)
|
||||
cstr_cat(&cstr, s1->cmdline_defs.data, s1->cmdline_defs.size);
|
||||
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
|
||||
if (is_asm)
|
||||
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
|
||||
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
|
||||
if (s1->output_type == TCC_OUTPUT_MEMORY)
|
||||
cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
|
||||
if (!is_asm && s1->output_type != TCC_OUTPUT_PREPROCESS)
|
||||
cstr_cat(&cstr, "#include \"tcc_predefs.h\"\n", -1);
|
||||
if (s1->cmdline_incl.size)
|
||||
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
|
||||
//printf("%s\n", (char*)cstr.data);
|
||||
*s1->include_stack_ptr++ = file;
|
||||
tcc_open_bf(s1, "<command line>", cstr.size);
|
||||
memcpy(file->buffer, cstr.data, cstr.size);
|
||||
cstr_free(&cstr);
|
||||
|
||||
parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0;
|
||||
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
|
||||
|
@ -3629,6 +3631,9 @@ ST_FUNC void preprocess_end(TCCState *s1)
|
|||
while (macro_stack)
|
||||
end_macro();
|
||||
macro_ptr = NULL;
|
||||
while (file)
|
||||
tcc_close();
|
||||
tccpp_delete(s1);
|
||||
}
|
||||
|
||||
ST_FUNC void tccpp_new(TCCState *s)
|
||||
|
@ -3636,10 +3641,6 @@ ST_FUNC void tccpp_new(TCCState *s)
|
|||
int i, c;
|
||||
const char *p, *r;
|
||||
|
||||
/* might be used in error() before preprocess_start() */
|
||||
s->include_stack_ptr = s->include_stack;
|
||||
s->ppfp = stdout;
|
||||
|
||||
/* init isid table */
|
||||
for(i = CH_EOF; i<128; i++)
|
||||
set_idnum(i,
|
||||
|
@ -3654,14 +3655,15 @@ ST_FUNC void tccpp_new(TCCState *s)
|
|||
/* init allocators */
|
||||
tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
|
||||
tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
|
||||
tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
|
||||
|
||||
memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
|
||||
memset(s->cached_includes_hash, 0, sizeof s->cached_includes_hash);
|
||||
|
||||
cstr_new(&cstr_buf);
|
||||
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
|
||||
tok_str_new(&tokstr_buf);
|
||||
tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
|
||||
|
||||
|
||||
tok_ident = TOK_IDENT;
|
||||
p = tcc_keywords;
|
||||
while (*p) {
|
||||
|
@ -3674,17 +3676,26 @@ ST_FUNC void tccpp_new(TCCState *s)
|
|||
tok_alloc(p, r - p - 1);
|
||||
p = r;
|
||||
}
|
||||
|
||||
/* we add dummy defines for some special macros to speed up tests
|
||||
and to have working defined() */
|
||||
define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
|
||||
}
|
||||
|
||||
ST_FUNC void tccpp_delete(TCCState *s)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
/* free -D and compiler defines */
|
||||
free_defines(NULL);
|
||||
dynarray_reset(&s->cached_includes, &s->nb_cached_includes);
|
||||
|
||||
/* free tokens */
|
||||
n = tok_ident - TOK_IDENT;
|
||||
if (n > total_idents)
|
||||
total_idents = n;
|
||||
for(i = 0; i < n; i++)
|
||||
tal_free(toksym_alloc, table_ident[i]);
|
||||
tcc_free(table_ident);
|
||||
|
@ -3701,8 +3712,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
|
|||
toksym_alloc = NULL;
|
||||
tal_delete(tokstr_alloc);
|
||||
tokstr_alloc = NULL;
|
||||
tal_delete(cstr_alloc);
|
||||
cstr_alloc = NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
|
31
tcctok.h
31
tcctok.h
|
@ -38,6 +38,7 @@
|
|||
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
|
||||
|
||||
DEF(TOK_GENERIC, "_Generic")
|
||||
DEF(TOK_STATIC_ASSERT, "_Static_assert")
|
||||
|
||||
DEF(TOK_FLOAT, "float")
|
||||
DEF(TOK_DOUBLE, "double")
|
||||
|
@ -53,6 +54,8 @@
|
|||
DEF(TOK_ATTRIBUTE2, "__attribute__")
|
||||
DEF(TOK_ALIGNOF1, "__alignof")
|
||||
DEF(TOK_ALIGNOF2, "__alignof__")
|
||||
DEF(TOK_ALIGNOF3, "_Alignof")
|
||||
DEF(TOK_ALIGNAS, "_Alignas")
|
||||
DEF(TOK_TYPEOF1, "typeof")
|
||||
DEF(TOK_TYPEOF2, "__typeof")
|
||||
DEF(TOK_TYPEOF3, "__typeof__")
|
||||
|
@ -122,6 +125,12 @@
|
|||
DEF(TOK_FASTCALL3, "__fastcall__")
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
DEF(TOK_CLEANUP1, "cleanup")
|
||||
DEF(TOK_CLEANUP2, "__cleanup__")
|
||||
DEF(TOK_CONSTRUCTOR1, "constructor")
|
||||
DEF(TOK_CONSTRUCTOR2, "__constructor__")
|
||||
DEF(TOK_DESTRUCTOR1, "destructor")
|
||||
DEF(TOK_DESTRUCTOR2, "__destructor__")
|
||||
|
||||
DEF(TOK_MODE, "__mode__")
|
||||
DEF(TOK_MODE_QI, "__QI__")
|
||||
|
@ -132,8 +141,10 @@
|
|||
|
||||
DEF(TOK_DLLEXPORT, "dllexport")
|
||||
DEF(TOK_DLLIMPORT, "dllimport")
|
||||
DEF(TOK_NODECORATE, "nodecorate")
|
||||
DEF(TOK_NORETURN1, "noreturn")
|
||||
DEF(TOK_NORETURN2, "__noreturn__")
|
||||
DEF(TOK_NORETURN3, "_Noreturn")
|
||||
DEF(TOK_VISIBILITY1, "visibility")
|
||||
DEF(TOK_VISIBILITY2, "__visibility__")
|
||||
|
||||
|
@ -149,8 +160,10 @@
|
|||
#elif defined TCC_TARGET_X86_64
|
||||
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
DEF(TOK___va_start, "__va_start")
|
||||
DEF(TOK___va_arg, "__va_arg")
|
||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||
DEF(TOK_builtin_va_arg, "__builtin_va_arg")
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||
#endif
|
||||
|
||||
/* pragma */
|
||||
|
@ -254,7 +267,7 @@
|
|||
#if defined TCC_TARGET_PE
|
||||
DEF(TOK___chkstk, "__chkstk")
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
||||
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
|
||||
DEF(TOK___addtf3, "__addtf3")
|
||||
DEF(TOK___subtf3, "__subtf3")
|
||||
|
@ -293,14 +306,26 @@
|
|||
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
# ifdef TCC_TARGET_PE
|
||||
# ifdef TCC_TARGET_X86_64
|
||||
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
|
||||
# endif
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
DEF(TOK_realloc, "realloc")
|
||||
DEF(TOK_memalign, "memalign")
|
||||
DEF(TOK_calloc, "calloc")
|
||||
# endif
|
||||
DEF(TOK_mmap, "mmap")
|
||||
DEF(TOK_munmap, "munmap")
|
||||
DEF(TOK_memcmp, "memcmp")
|
||||
DEF(TOK_strlen, "strlen")
|
||||
DEF(TOK_strcpy, "strcpy")
|
||||
DEF(TOK_strncpy, "strncpy")
|
||||
DEF(TOK_strcmp, "strcmp")
|
||||
DEF(TOK_strncmp, "strncmp")
|
||||
DEF(TOK_strcat, "strcat")
|
||||
DEF(TOK_strchr, "strchr")
|
||||
DEF(TOK_strdup, "strdup")
|
||||
#endif
|
||||
|
||||
/* Tiny Assembler */
|
||||
|
|
12
tcctools.c
12
tcctools.c
|
@ -430,7 +430,7 @@ the_end:
|
|||
|
||||
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
|
||||
|
||||
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
|
||||
ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int option)
|
||||
{
|
||||
tcc_error("-m%d not implemented.", option);
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ static int execvp_win32(const char *prog, char **argv)
|
|||
#define execvp execvp_win32
|
||||
#endif /* _WIN32 */
|
||||
|
||||
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
|
||||
ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int target)
|
||||
{
|
||||
char program[4096];
|
||||
char *a0 = argv[0];
|
||||
|
@ -515,7 +515,7 @@ int _dowildcard = 1;
|
|||
/* -------------------------------------------------------------- */
|
||||
/* generate xxx.d file */
|
||||
|
||||
ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
||||
ST_FUNC void gen_makedeps(TCCState *s1, const char *target, const char *filename)
|
||||
{
|
||||
FILE *depout;
|
||||
char buf[1024];
|
||||
|
@ -528,7 +528,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
|||
filename = buf;
|
||||
}
|
||||
|
||||
if (s->verbose)
|
||||
if (s1->verbose)
|
||||
printf("<- %s\n", filename);
|
||||
|
||||
/* XXX return err codes instead of error() ? */
|
||||
|
@ -537,8 +537,8 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
|||
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]);
|
||||
for (i=0; i<s1->nb_target_deps; ++i)
|
||||
fprintf(depout, " %s \\\n", s1->target_deps[i]);
|
||||
fprintf(depout, "\n");
|
||||
fclose(depout);
|
||||
}
|
||||
|
|
146
tests/Makefile
146
tests/Makefile
|
@ -12,6 +12,7 @@ TESTS = \
|
|||
hello-exe \
|
||||
hello-run \
|
||||
libtest \
|
||||
libtest_mt \
|
||||
test3 \
|
||||
memtest \
|
||||
dlltest \
|
||||
|
@ -22,18 +23,18 @@ TESTS = \
|
|||
tests2-dir \
|
||||
pp-dir
|
||||
|
||||
BTESTS = test1b test3b btest
|
||||
|
||||
# test4 -- problem with -static
|
||||
BTESTS = btest test1b
|
||||
# test4_static -- Not all relocation types are implemented yet.
|
||||
# asmtest / asmtest2 -- minor differences with gcc
|
||||
# btest -- works on i386 (including win32)
|
||||
|
||||
# bounds-checking is supported only on i386
|
||||
ifneq ($(ARCH),i386)
|
||||
TESTS := $(filter-out $(BTESTS),$(TESTS))
|
||||
# bounds-checking is supported on i386 and x86_64 on linux and windows
|
||||
ifeq (-$(CONFIG_musl)-, --)
|
||||
ifeq ($(ARCH),i386)
|
||||
TESTS += $(BTESTS)
|
||||
endif
|
||||
ifeq ($(ARCH),x86_64)
|
||||
TESTS += $(BTESTS)
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
TESTS := $(filter-out $(BTESTS),$(TESTS))
|
||||
endif
|
||||
ifdef CONFIG_OSX # -run only
|
||||
TESTS := hello-run libtest tests2-dir pp-dir
|
||||
|
@ -47,19 +48,30 @@ endif
|
|||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||
TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
|
||||
endif
|
||||
ifndef CONFIG_cross
|
||||
TESTS := $(filter-out cross-%,$(TESTS))
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
|
||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),arm)
|
||||
# tcctest refers to the alignment of functions, and with thumb mode
|
||||
# the low bit of code addresses selects the mode, so the "alignment"
|
||||
# of functions via bit masking comes out as 1. Just disable thumb.
|
||||
test.ref: CFLAGS+=-marm
|
||||
endif
|
||||
ifeq ($(ARCH),i386)
|
||||
# tcctest.c:get_asm_string uses a construct that is checked too strictly
|
||||
# by GCC in 32bit mode when PIC is enabled.
|
||||
test.ref: CFLAGS+=-fno-PIC -fno-PIE
|
||||
endif
|
||||
|
||||
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||
DISAS = objdump -d
|
||||
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
||||
|
||||
all test : clean-s $(TESTS)
|
||||
all test :
|
||||
@$(MAKE) --no-print-directory -s clean
|
||||
@$(MAKE) --no-print-directory -s -r $(TESTS)
|
||||
|
||||
hello-exe: ../examples/ex1.c
|
||||
@echo ------------ $@ ------------
|
||||
|
@ -69,13 +81,16 @@ hello-run: ../examples/ex1.c
|
|||
@echo ------------ $@ ------------
|
||||
$(TCC) -run $< || $(DUMPTCC)
|
||||
|
||||
libtest: libtcc_test$(EXESUF)
|
||||
libtes%: libtcc_tes%$(EXESUF)
|
||||
@echo ------------ $@ ------------
|
||||
./libtcc_test$(EXESUF) $(TCCFLAGS)
|
||||
./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES)
|
||||
|
||||
libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
libtcc_test_mt$(EXESUF): libtcc_test_mt.c $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
%-dir:
|
||||
@echo ------------ $@ ------------
|
||||
$(MAKE) -k -C $*
|
||||
|
@ -88,22 +103,24 @@ test.ref: tcctest.c
|
|||
# auto test
|
||||
test1 test1b: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -run $< > test.out1
|
||||
@diff -u test.ref test.out1 && echo "Auto Test OK"
|
||||
$(TCC) $(RUN_TCC) -w -run $< > test.out1
|
||||
@diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
|
||||
|
||||
# iterated test2 (compile tcc then compile tcctest.c !)
|
||||
test2 test2b: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
|
||||
@diff -u test.ref test.out2 && echo "Auto Test2 OK"
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2
|
||||
@diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
|
||||
|
||||
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
||||
test3 test3b: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
|
||||
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3
|
||||
@diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
|
||||
|
||||
test%b : TCCFLAGS += -b
|
||||
AUTO_TEST = Auto Test
|
||||
test%b : TCCFLAGS += -b -bt1
|
||||
test%b : AUTO_TEST = Auto Bound-Test
|
||||
|
||||
# binary output test
|
||||
test4: tcctest.c test.ref
|
||||
|
@ -112,19 +129,22 @@ test4: tcctest.c test.ref
|
|||
$(TCC) -c -o tcctest3.o $<
|
||||
$(TCC) -o tcctest3 tcctest3.o
|
||||
./tcctest3 > test3.out
|
||||
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
|
||||
@if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
|
||||
# dynamic output
|
||||
$(TCC) -o tcctest1 $<
|
||||
./tcctest1 > test1.out
|
||||
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
||||
@if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
|
||||
# dynamic output + bound check
|
||||
$(TCC) -b -o tcctest4 $<
|
||||
./tcctest4 > test4.out
|
||||
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
||||
# static output
|
||||
@if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
|
||||
|
||||
test4_static: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
# static output.
|
||||
$(TCC) -static -o tcctest2 $<
|
||||
./tcctest2 > test2.out
|
||||
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
|
||||
@if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
|
||||
|
||||
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
|
||||
dlltest:
|
||||
|
@ -145,32 +165,30 @@ memtest:
|
|||
@echo ------------ $@ ------------
|
||||
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
|
||||
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
|
||||
@echo OK
|
||||
|
||||
# memory and bound check auto test
|
||||
BOUNDS_OK = 1 4 8 10 14
|
||||
BOUNDS_FAIL= 2 5 7 9 11 12 13 15
|
||||
BOUNDS_OK = 1 4 8 10 14 16
|
||||
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
|
||||
|
||||
btest: boundtest.c
|
||||
@echo ------------ $@ ------------
|
||||
@for i in $(BOUNDS_OK); do \
|
||||
echo ; echo --- boundtest $$i ---; \
|
||||
if $(TCC) -b -run $< $$i ; then \
|
||||
echo succeeded as expected; \
|
||||
if $(TCC) -b -run $< $$i >/dev/null 2>&1 ; then \
|
||||
echo "Test $$i succeeded as expected" ; \
|
||||
else\
|
||||
echo Failed positive test $$i ; exit 1 ; \
|
||||
echo "Failed positive test $$i" ; exit 1 ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
for i in $(BOUNDS_FAIL); do \
|
||||
echo ; echo --- boundtest $$i ---; \
|
||||
if $(TCC) -b -run $< $$i ; then \
|
||||
echo Failed negative test $$i ; exit 1 ;\
|
||||
if $(TCC) -b -bt1 -run $< $$i >/dev/null 2>&1 ; then \
|
||||
echo "Failed negative test $$i" ; exit 1 ;\
|
||||
else\
|
||||
echo failed as expected; \
|
||||
echo "Test $$i failed as expected" ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
echo; echo Bound test OK
|
||||
echo Bound test OK
|
||||
|
||||
# speed test
|
||||
speedtest: ex2 ex3
|
||||
|
@ -181,6 +199,7 @@ speedtest: ex2 ex3
|
|||
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
|
||||
|
||||
weaktest: tcctest.c test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -c $< -o weaktest.tcc.o
|
||||
$(CC) -c $< -o weaktest.gcc.o $(NATIVE_DEFINES) $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
||||
objdump -t weaktest.tcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.tcc.o.txt
|
||||
|
@ -206,22 +225,19 @@ asmtest2: MAYBE_RUN_TCC = $(RUN_TCC)
|
|||
|
||||
# Check that code generated by libtcc is binary compatible with
|
||||
# that generated by CC
|
||||
abitest-cc$(EXESUF): abitest.c $(LIBTCC)
|
||||
abitest-cc.exe: abitest.c $(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
|
||||
|
||||
abitest-tcc$(EXESUF): abitest.c libtcc.c
|
||||
abitest-tcc.exe: abitest.c libtcc.c
|
||||
$(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS)
|
||||
|
||||
ABITESTS := abitest-cc$(EXESUF)
|
||||
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
|
||||
ABITESTS += abitest-tcc$(EXESUF)
|
||||
endif
|
||||
|
||||
abitest: $(ABITESTS)
|
||||
abitest-% : abitest-%.exe
|
||||
@echo ------------ $@ ------------
|
||||
./abitest-cc$(EXESUF) $(TCCFLAGS)
|
||||
./$< $(TCCFLAGS)
|
||||
|
||||
abitest: abitest-cc
|
||||
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
|
||||
./abitest-tcc$(EXESUF) $(TCCFLAGS)
|
||||
abitest: abitest-tcc
|
||||
endif
|
||||
|
||||
vla_test$(EXESUF): vla_test.c
|
||||
|
@ -244,21 +260,18 @@ asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
|
|||
@echo ------------ $@ ------------
|
||||
./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1
|
||||
./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2
|
||||
@diff -u asm-c-connect.out1 asm-c-connect.out2 && echo "ok"
|
||||
@diff -u asm-c-connect.out1 asm-c-connect.out2 || (echo "error"; exit 1)
|
||||
|
||||
TCC_YY = $(foreach T,$(TCC_X),$(if $(wildcard $(TOP)/$T-tcc$(EXESUF)),$T))
|
||||
|
||||
cross-test :
|
||||
$(if $(strip $(TCC_YY)),\
|
||||
$(MAKE) $(foreach T,$(TCC_YY),cross-$T.test) --no-print-directory,:)
|
||||
|
||||
cross-%.test :
|
||||
@echo ------------ $@ ------------
|
||||
$(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
$(TOP)/$*-tcc$(EXESUF) -v $(TCCFLAGS-$(if $(findstring win,$*),win,unx))\
|
||||
-c $(TOPSRC)/examples/ex3.c
|
||||
|
||||
# targets for development
|
||||
%.bin: %.c tcc
|
||||
|
@ -279,11 +292,8 @@ cache: tcc_g
|
|||
clean:
|
||||
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc
|
||||
rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234]
|
||||
rm -f asm-c-connect$(EXESUF)
|
||||
rm -f ex? tcc_g weaktest.*.txt *.def
|
||||
rm -f asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
|
||||
rm -f ex? tcc_g weaktest.*.txt *.def libtcc_test_mt
|
||||
@$(MAKE) -C tests2 $@
|
||||
@$(MAKE) -C pp $@
|
||||
|
||||
# silent clean, used before running tests
|
||||
clean-s:
|
||||
@$(MAKE) -s --no-print-directory clean
|
||||
|
|
|
@ -50,15 +50,12 @@ int test4(void)
|
|||
int i, sum = 0;
|
||||
int *tab4;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
tab4 = malloc(20 * sizeof(int));
|
||||
for(i=0;i<20;i++) {
|
||||
sum += tab4[i];
|
||||
}
|
||||
free(tab4);
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
@ -68,20 +65,16 @@ int test5(void)
|
|||
int i, sum = 0;
|
||||
int *tab4;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
tab4 = malloc(20 * sizeof(int));
|
||||
for(i=0;i<21;i++) {
|
||||
sum += tab4[i];
|
||||
}
|
||||
free(tab4);
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* error */
|
||||
/* XXX: currently: bug */
|
||||
int test6(void)
|
||||
{
|
||||
int i, sum = 0;
|
||||
|
@ -199,16 +192,13 @@ 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) );
|
||||
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* error */
|
||||
|
@ -217,16 +207,13 @@ 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) );
|
||||
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int (*table_test[])(void) = {
|
||||
|
@ -246,15 +233,25 @@ int (*table_test[])(void) = {
|
|||
test14,
|
||||
test15,
|
||||
test16,
|
||||
test17,
|
||||
test17
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
char *cp;
|
||||
int index;
|
||||
int (*ftest)(void);
|
||||
int index_max = sizeof(table_test)/sizeof(table_test[0]);
|
||||
|
||||
/* check bounds checking main arg */
|
||||
for (i = 0; i < argc; i++) {
|
||||
cp = argv[i];
|
||||
while (*cp) {
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
printf(
|
||||
"test TCC bound checking system\n"
|
||||
|
|
|
@ -6,9 +6,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "libtcc.h"
|
||||
|
||||
void handle_error(void *opaque, const char *msg)
|
||||
{
|
||||
fprintf(opaque, "%s\n", msg);
|
||||
}
|
||||
|
||||
/* this function is called by the generated code */
|
||||
int add(int a, int b)
|
||||
{
|
||||
|
@ -53,6 +59,14 @@ int main(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
assert(tcc_get_error_func(s) == NULL);
|
||||
assert(tcc_get_error_opaque(s) == NULL);
|
||||
|
||||
tcc_set_error_func(s, stderr, handle_error);
|
||||
|
||||
assert(tcc_get_error_func(s) == handle_error);
|
||||
assert(tcc_get_error_opaque(s) == stderr);
|
||||
|
||||
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
||||
for (i = 1; i < argc; ++i) {
|
||||
char *a = argv[i];
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Multi-thread Test for libtcc
|
||||
*/
|
||||
|
||||
#ifndef FIB
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libtcc.h"
|
||||
|
||||
#define M 20 /* number of states */
|
||||
#define F(n) (n % 20 + 2) /* fib argument */
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define TF_TYPE(func, param) DWORD WINAPI func(void *param)
|
||||
typedef TF_TYPE(ThreadFunc, x);
|
||||
HANDLE hh[M];
|
||||
void create_thread(ThreadFunc f, int n)
|
||||
{
|
||||
DWORD tid;
|
||||
hh[n] = CreateThread(NULL, 0, f, (void*)(size_t)n, 0, &tid);
|
||||
}
|
||||
void wait_threads(int n)
|
||||
{
|
||||
WaitForMultipleObjects(n, hh, TRUE, INFINITE);
|
||||
while (n)
|
||||
CloseHandle(hh[--n]);
|
||||
}
|
||||
void sleep_ms(unsigned n)
|
||||
{
|
||||
Sleep(n);
|
||||
}
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#define TF_TYPE(func, param) void* func(void *param)
|
||||
typedef TF_TYPE(ThreadFunc, x);
|
||||
pthread_t hh[M];
|
||||
void create_thread(ThreadFunc f, int n)
|
||||
{
|
||||
pthread_create(&hh[n], NULL, f, (void*)(size_t)n);
|
||||
}
|
||||
void wait_threads(int n)
|
||||
{
|
||||
while (n)
|
||||
pthread_join(hh[--n], NULL);
|
||||
|
||||
}
|
||||
void sleep_ms(unsigned n)
|
||||
{
|
||||
usleep(n * 1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
void handle_error(void *opaque, const char *msg)
|
||||
{
|
||||
fprintf(opaque, "%s\n", msg);
|
||||
}
|
||||
|
||||
/* this function is called by the generated code */
|
||||
int add(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
#define _str(s) #s
|
||||
#define str(s) _str(s)
|
||||
/* as a trick, prepend #line directive for better error/warning messages */
|
||||
#define PROG(lbl) \
|
||||
char lbl[] = "#line " str(__LINE__) " " str(__FILE__) "\n\n"
|
||||
|
||||
PROG(my_program)
|
||||
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
|
||||
"int add(int a, int b);\n"
|
||||
"int fib(int n)\n"
|
||||
"{\n"
|
||||
" if (n <= 2)\n"
|
||||
" return 1;\n"
|
||||
" else\n"
|
||||
" return add(fib(n-1),fib(n-2));\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"int foo(int n)\n"
|
||||
"{\n"
|
||||
" printf(\" %d\", fib(n));\n"
|
||||
" return 0;\n"
|
||||
"# warning is this the correct file:line...\n"
|
||||
"}\n";
|
||||
|
||||
int g_argc; char **g_argv;
|
||||
|
||||
void parse_args(TCCState *s)
|
||||
{
|
||||
int i;
|
||||
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
||||
for (i = 1; i < g_argc; ++i) {
|
||||
char *a = g_argv[i];
|
||||
if (a[0] == '-') {
|
||||
if (a[1] == 'B')
|
||||
tcc_set_lib_path(s, a+2);
|
||||
else if (a[1] == 'I')
|
||||
tcc_add_include_path(s, a+2);
|
||||
else if (a[1] == 'L')
|
||||
tcc_add_library_path(s, a+2);
|
||||
else if (a[1] == 'D') {
|
||||
char *dup = strdup(a);
|
||||
char *eq = strchr(dup+2, '=');
|
||||
if (eq) {
|
||||
*eq = 0;
|
||||
tcc_define_symbol(s, dup+2, eq+1);
|
||||
*eq = '=';
|
||||
} else
|
||||
tcc_define_symbol(s, dup+2, NULL);
|
||||
free(dup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TCCState *new_state(int w)
|
||||
{
|
||||
TCCState *s = tcc_new();
|
||||
if (!s) {
|
||||
fprintf(stderr, __FILE__ ": could not create tcc state\n");
|
||||
exit(1);
|
||||
}
|
||||
tcc_set_error_func(s, stdout, handle_error);
|
||||
parse_args(s);
|
||||
if (!w) tcc_set_options(s, "-w");
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
return s;
|
||||
}
|
||||
|
||||
void *reloc_state(TCCState *s, const char *entry)
|
||||
{
|
||||
void *func;
|
||||
tcc_add_symbol(s, "add", add);
|
||||
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) {
|
||||
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
|
||||
return NULL;
|
||||
}
|
||||
func = tcc_get_symbol(s, entry);
|
||||
if (!func)
|
||||
fprintf(stderr, __FILE__ ": could not get entry symbol.\n");
|
||||
return func;
|
||||
}
|
||||
|
||||
/* work with several states at the same time */
|
||||
int state_test(void)
|
||||
{
|
||||
TCCState *s[M];
|
||||
int (*func[M])(int);
|
||||
int n;
|
||||
|
||||
for (n = 0; n < M + 4; ++n) {
|
||||
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
|
||||
if (a < M)
|
||||
s[a] = new_state(0);
|
||||
if (b < M)
|
||||
if (tcc_compile_string(s[b], my_program) == -1)
|
||||
break;
|
||||
if (c < M)
|
||||
func[c] = reloc_state(s[c], "foo");
|
||||
if (d < M && func[d])
|
||||
func[d](F(d));
|
||||
if (e < M)
|
||||
tcc_delete(s[e]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* simple compilation in threads */
|
||||
TF_TYPE(thread_test_simple, vn)
|
||||
{
|
||||
TCCState *s;
|
||||
int (*func)(int);
|
||||
int ret;
|
||||
int n = (size_t)vn;
|
||||
|
||||
s = new_state(0);
|
||||
sleep_ms(1);
|
||||
ret = tcc_compile_string(s, my_program);
|
||||
sleep_ms(1);
|
||||
if (ret >= 0) {
|
||||
func = reloc_state(s, "foo");
|
||||
if (func)
|
||||
func(F(n));
|
||||
}
|
||||
tcc_delete(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* more complex compilation in threads */
|
||||
TF_TYPE(thread_test_complex, vn)
|
||||
{
|
||||
TCCState *s;
|
||||
int ret;
|
||||
int n = (size_t)vn;
|
||||
char *argv[30], b[10];
|
||||
int argc = 0, i;
|
||||
|
||||
sprintf(b, "%d", F(n));
|
||||
|
||||
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
||||
#if 0
|
||||
argv[argc++] = "-run";
|
||||
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
||||
#endif
|
||||
argv[argc++] = "-DFIB";
|
||||
argv[argc++] = "-run";
|
||||
argv[argc++] = __FILE__;
|
||||
argv[argc++] = b;
|
||||
argv[argc] = NULL;
|
||||
|
||||
s = new_state(1);
|
||||
sleep_ms(2);
|
||||
ret = tcc_add_file(s, argv[0]);
|
||||
sleep_ms(3);
|
||||
if (ret < 0)
|
||||
exit(1);
|
||||
tcc_run(s, argc, argv);
|
||||
tcc_delete(s);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void time_tcc(int n, const char *src)
|
||||
{
|
||||
TCCState *s;
|
||||
int ret;
|
||||
while (--n >= 0) {
|
||||
s = new_state(1);
|
||||
ret = tcc_add_file(s, src);
|
||||
tcc_delete(s);
|
||||
if (ret < 0)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned getclock_ms(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return GetTickCount();
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n;
|
||||
unsigned t;
|
||||
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 1
|
||||
printf("mixed calls\n "), fflush(stdout);
|
||||
t = getclock_ms();
|
||||
state_test();
|
||||
printf("\n(%u ms)\n", getclock_ms() - t);
|
||||
#endif
|
||||
#if 1
|
||||
printf("threads\n "), fflush(stdout);
|
||||
t = getclock_ms();
|
||||
for (n = 0; n < M; ++n)
|
||||
create_thread(thread_test_simple, n);
|
||||
wait_threads(n);
|
||||
printf("\n(%u ms)\n", getclock_ms() - t);
|
||||
#endif
|
||||
#if 1
|
||||
printf("tcc in threads\n "), fflush(stdout);
|
||||
t = getclock_ms();
|
||||
for (n = 0; n < M; ++n)
|
||||
create_thread(thread_test_complex, n);
|
||||
wait_threads(n);
|
||||
printf("\n(%u ms)\n", getclock_ms() - t);
|
||||
#endif
|
||||
#if 1
|
||||
printf("compiling tcc 10 times\n"), fflush(stdout);
|
||||
t = getclock_ms();
|
||||
time_tcc(10, argv[1]);
|
||||
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <tcclib.h>
|
||||
int fib(n)
|
||||
{
|
||||
return (n <= 2) ? 1 : fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf(" %d", fib(atoi(argv[1]), 2));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -10,7 +10,7 @@ VPATH = $(SRC)
|
|||
files = $(patsubst %.$1,%.test,$(notdir $(wildcard $(SRC)/*.$1)))
|
||||
TESTS = $(call files,c) $(call files,S)
|
||||
|
||||
all test : $(sort $(TESTS))
|
||||
all test testspp.all: $(sort $(TESTS))
|
||||
|
||||
DIFF_OPTS = -Nu -b -B
|
||||
|
||||
|
@ -29,6 +29,8 @@ FILTER = 2>&1 | sed 's,$(SRC)/,,g'
|
|||
diff $(DIFF_OPTS) $(SRC)/$*.expect $*.output \
|
||||
&& rm -f $*.output
|
||||
|
||||
testspp.%: %.test ;
|
||||
|
||||
# automatically generate .expect files with gcc:
|
||||
%.expect: # %.c
|
||||
gcc -E -P $*.[cS] >$*.expect 2>&1
|
||||
|
|
297
tests/tcctest.c
297
tests/tcctest.c
|
@ -3,8 +3,6 @@
|
|||
*/
|
||||
#include "config.h"
|
||||
|
||||
#if GCC_MAJOR >= 3
|
||||
|
||||
/* Unfortunately, gcc version < 3 does not handle that! */
|
||||
#define ALL_ISOC99
|
||||
|
||||
|
@ -14,6 +12,14 @@
|
|||
/* gcc 2.95.3 does not handle correctly CR in strings or after strays */
|
||||
#define CORRECT_CR_HANDLING
|
||||
|
||||
/* __VA_ARGS__ and __func__ support */
|
||||
#define C99_MACROS
|
||||
|
||||
/* deprecated and no longer supported in gcc 3.3 */
|
||||
//#define ACCEPT_CR_IN_STRINGS
|
||||
|
||||
#ifndef __TINYC__
|
||||
typedef __SIZE_TYPE__ uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
@ -33,12 +39,6 @@
|
|||
#define LONG_DOUBLE_LITERAL(x) x ## L
|
||||
#endif
|
||||
|
||||
/* deprecated and no longer supported in gcc 3.3 */
|
||||
//#define ACCEPT_CR_IN_STRINGS
|
||||
|
||||
/* __VA_ARGS__ and __func__ support */
|
||||
#define C99_MACROS
|
||||
|
||||
/* test various include syntaxes */
|
||||
|
||||
#define TCCLIB_INC <tcclib.h>
|
||||
|
@ -77,8 +77,10 @@ void expr_test();
|
|||
void macro_test();
|
||||
void recursive_macro_test();
|
||||
void scope_test();
|
||||
void scope_test2();
|
||||
void forward_test();
|
||||
void funcptr_test();
|
||||
void if_test();
|
||||
void loop_test();
|
||||
void switch_test();
|
||||
void goto_test();
|
||||
|
@ -122,6 +124,7 @@ void math_cmp_test(void);
|
|||
void callsave_test(void);
|
||||
void builtin_frame_address_test(void);
|
||||
void attrib_test(void);
|
||||
void bounds_check1_test(void);
|
||||
|
||||
int fib(int n);
|
||||
void num(int n);
|
||||
|
@ -178,7 +181,7 @@ static int onetwothree = 123;
|
|||
|
||||
#ifdef __TINYC__
|
||||
/* We try to handle this syntax. Make at least sure it doesn't segfault. */
|
||||
char invalid_function_def()[] {}
|
||||
char invalid_function_def()[] {return 0;}
|
||||
#endif
|
||||
|
||||
#define __INT64_C(c) c ## LL
|
||||
|
@ -507,6 +510,40 @@ void string_test()
|
|||
}
|
||||
}
|
||||
|
||||
void if1t(int n, int a, int b, int c)
|
||||
{
|
||||
if (a && b) printf("if1t: %d 1 %d %d\n", n, a, b);
|
||||
if (a && !b) printf("if1t: %d 2 %d %d\n", n, a, b);
|
||||
if (!a && b) printf("if1t: %d 3 %d %d\n", n, a, b);
|
||||
if (!a && !b) printf("if1t: %d 4 %d %d\n", n, a, b);
|
||||
if (a || b) printf("if1t: %d 5 %d %d\n", n, a, b);
|
||||
if (a || !b) printf("if1t: %d 6 %d %d\n", n, a, b);
|
||||
if (!a || b) printf("if1t: %d 7 %d %d\n", n, a, b);
|
||||
if (!a || !b) printf("if1t: %d 8 %d %d\n", n, a, b);
|
||||
if (a && b || c) printf("if1t: %d 9 %d %d %d\n", n, a, b, c);
|
||||
if (a || b && c) printf("if1t: %d 10 %d %d %d\n", n, a, b, c);
|
||||
if (a > b - 1 && c) printf("if1t: %d 11 %d %d %d\n", n, a, b, c);
|
||||
if (a > b - 1 || c) printf("if1t: %d 12 %d %d %d\n", n, a, b, c);
|
||||
if (a > 0 && 1) printf("if1t: %d 13 %d %d %d\n", n, a, b, c);
|
||||
if (a > 0 || 0) printf("if1t: %d 14 %d %d %d\n", n, a, b, c);
|
||||
}
|
||||
|
||||
void if2t(void)
|
||||
{
|
||||
if (0 && 1 || printf("if2t:ok\n") || 1)
|
||||
printf("if2t:ok2\n");
|
||||
printf("if2t:ok3\n");
|
||||
}
|
||||
|
||||
void if_test(void)
|
||||
{
|
||||
if1t(1, 0, 0, 0);
|
||||
if1t(2, 0, 3, 0);
|
||||
if1t(3, 2, 0, 0);
|
||||
if1t(4, 2, 3, 0);
|
||||
if2t();
|
||||
}
|
||||
|
||||
void loop_test()
|
||||
{
|
||||
int i;
|
||||
|
@ -571,6 +608,7 @@ void goto_test()
|
|||
printf("goto:\n");
|
||||
i = 0;
|
||||
/* This needs to parse as label, not as start of decl. */
|
||||
typedef_and_label x;
|
||||
typedef_and_label:
|
||||
s_loop:
|
||||
if (i >= 10)
|
||||
|
@ -718,8 +756,10 @@ int main(int argc, char **argv)
|
|||
macro_test();
|
||||
recursive_macro_test();
|
||||
scope_test();
|
||||
scope_test2();
|
||||
forward_test();
|
||||
funcptr_test();
|
||||
if_test();
|
||||
loop_test();
|
||||
switch_test();
|
||||
goto_test();
|
||||
|
@ -768,6 +808,7 @@ int main(int argc, char **argv)
|
|||
if (via_volatile (42) != 42)
|
||||
printf ("via_volatile broken\n");
|
||||
attrib_test();
|
||||
bounds_check1_test();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -800,6 +841,30 @@ void scope_test()
|
|||
printf("g5=%d\n", g);
|
||||
}
|
||||
|
||||
int st2_i;
|
||||
int *st2_p = &st2_i;
|
||||
void scope_test2()
|
||||
{
|
||||
char a[50];
|
||||
st2_i = 42;
|
||||
for (int st2_i = 1; st2_i < 10; st2_i++) {
|
||||
extern int st2_i;
|
||||
st2_i++;
|
||||
printf("exloc: %d\n", st2_i);
|
||||
}
|
||||
printf("exloc: %d\n", *st2_p);
|
||||
}
|
||||
|
||||
/* C has tentative definition, and they may be repeated. */
|
||||
extern int st_global1;
|
||||
int st_global1=42;
|
||||
extern int st_global1;
|
||||
int st_global1;
|
||||
extern int st_global2;
|
||||
int st_global2;
|
||||
extern int st_global2;
|
||||
int st_global2;
|
||||
|
||||
void array_test()
|
||||
{
|
||||
int i, j, a[4];
|
||||
|
@ -917,6 +982,8 @@ void expr2_test()
|
|||
printf("res= %d %d\n", a, b);
|
||||
}
|
||||
|
||||
int const_len_ar[sizeof(1/0)]; /* div-by-zero, but in unevaluated context */
|
||||
|
||||
void constant_expr_test()
|
||||
{
|
||||
int a;
|
||||
|
@ -925,6 +992,7 @@ void constant_expr_test()
|
|||
printf("%d\n", a * 16);
|
||||
printf("%d\n", a * 1);
|
||||
printf("%d\n", a + 0);
|
||||
printf("%d\n", sizeof(const_len_ar));
|
||||
}
|
||||
|
||||
int tab4[10];
|
||||
|
@ -1134,7 +1202,7 @@ void struct_test()
|
|||
s->f3 = 1;
|
||||
printf("st2: %d %d %d\n",
|
||||
s->f1, s->f2, s->f3);
|
||||
printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1);
|
||||
printf("str_addr=%x\n", (int)(uintptr_t)st1.str - (int)(uintptr_t)&st1.f1);
|
||||
|
||||
/* align / size tests */
|
||||
printf("aligntest1 sizeof=%d alignof=%d\n",
|
||||
|
@ -1174,17 +1242,24 @@ void struct_test()
|
|||
printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
|
||||
}
|
||||
|
||||
/* simulate char/short return value with undefined upper bits */
|
||||
static int __csf(int x) { return x; }
|
||||
static void *_csf = __csf;
|
||||
#define csf(t,n) ((t(*)(int))_csf)(n)
|
||||
|
||||
/* XXX: depend on endianness */
|
||||
void char_short_test()
|
||||
{
|
||||
int var1, var2;
|
||||
signed char var3;
|
||||
long long var4;
|
||||
|
||||
printf("char_short:\n");
|
||||
|
||||
var1 = 0x01020304;
|
||||
var2 = 0xfffefdfc;
|
||||
printf("s8=%d %d\n",
|
||||
*(char *)&var1, *(char *)&var2);
|
||||
*(signed char *)&var1, *(signed char *)&var2);
|
||||
printf("u8=%d %d\n",
|
||||
*(unsigned char *)&var1, *(unsigned char *)&var2);
|
||||
printf("s16=%d %d\n",
|
||||
|
@ -1195,12 +1270,44 @@ void char_short_test()
|
|||
*(int *)&var1, *(int *)&var2);
|
||||
printf("u32=%d %d\n",
|
||||
*(unsigned int *)&var1, *(unsigned int *)&var2);
|
||||
*(char *)&var1 = 0x08;
|
||||
*(signed char *)&var1 = 0x08;
|
||||
printf("var1=%x\n", var1);
|
||||
*(short *)&var1 = 0x0809;
|
||||
printf("var1=%x\n", var1);
|
||||
*(int *)&var1 = 0x08090a0b;
|
||||
printf("var1=%x\n", var1);
|
||||
|
||||
var1 = 0x778899aa;
|
||||
var4 = 0x11223344aa998877ULL;
|
||||
var1 = var3 = var1 + 1;
|
||||
var4 = var3 = var4 + 1;
|
||||
printf("promote char/short assign %d "LONG_LONG_FORMAT"\n", var1, var4);
|
||||
var1 = 0x778899aa;
|
||||
var4 = 0x11223344aa998877ULL;
|
||||
printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
|
||||
printf("promote char/short cast VA %d %d\n", (signed char)(var1 + 1), (signed char)(var4 + 1));
|
||||
#if !defined(__arm__)
|
||||
/* We can't really express GCC behaviour of return type promotion in
|
||||
the presence of undefined behaviour (like __csf is). */
|
||||
var1 = csf(unsigned char,0x89898989);
|
||||
var4 = csf(signed char,0xabababab);
|
||||
printf("promote char/short funcret %d "LONG_LONG_FORMAT"\n", var1, var4);
|
||||
printf("promote char/short fumcret VA %d %d %d %d\n",
|
||||
csf(unsigned short,0xcdcdcdcd),
|
||||
csf(short,0xefefefef),
|
||||
csf(_Bool,0x33221100),
|
||||
csf(_Bool,0x33221101));
|
||||
#endif
|
||||
var3 = -10;
|
||||
var1 = (signed char)(unsigned char)(var3 + 1);
|
||||
var4 = (signed char)(unsigned char)(var3 + 1);
|
||||
printf("promote multicast (char)(unsigned char) %d "LONG_LONG_FORMAT"\n", var1, var4);
|
||||
var4 = 0x11223344aa998877ULL;
|
||||
var4 = (unsigned)(int)(var4 + 1);
|
||||
printf("promote multicast (unsigned)(int) "LONG_LONG_FORMAT"\n", var4);
|
||||
var4 = 0x11223344bbaa9988ULL;
|
||||
var4 = (unsigned)(signed char)(var4 + 1);
|
||||
printf("promote multicast (unsigned)(char) "LONG_LONG_FORMAT"\n", var4);
|
||||
}
|
||||
|
||||
/******************/
|
||||
|
@ -1374,6 +1481,12 @@ void optimize_out(void)
|
|||
printf("ool6:%d\n", defined_function());
|
||||
goto breakhere;
|
||||
}
|
||||
j = 1;
|
||||
while (j) {
|
||||
j--;
|
||||
continue;
|
||||
printf("ool7:%d\n", undefined_function());
|
||||
}
|
||||
|
||||
/* Test that constants in logical && are optimized: */
|
||||
i = 0 && undefined_function();
|
||||
|
@ -1433,6 +1546,9 @@ int defined_function(void)
|
|||
static int tab_reinit[];
|
||||
static int tab_reinit[10];
|
||||
|
||||
static int tentative_ar[];
|
||||
static int tentative_ar[] = {1,2,3};
|
||||
|
||||
//int cinit1; /* a global variable can be defined several times without error ! */
|
||||
int cinit1;
|
||||
int cinit1;
|
||||
|
@ -1597,6 +1713,7 @@ void cast_test()
|
|||
unsigned b,d;
|
||||
short s;
|
||||
char *p = NULL;
|
||||
unsigned long ul = 0x80000000UL;
|
||||
p -= 0x700000000042;
|
||||
|
||||
printf("cast_test:\n");
|
||||
|
@ -1649,6 +1766,9 @@ void cast_test()
|
|||
/* from integers to pointers */
|
||||
printf("%p %p %p %p\n",
|
||||
(void *)a, (void *)b, (void *)c, (void *)d);
|
||||
|
||||
/* int to int with sign set */
|
||||
printf("0x%lx\n", (unsigned long)(int)ul);
|
||||
}
|
||||
|
||||
/* initializers tests */
|
||||
|
@ -1752,6 +1872,8 @@ arrtype2 sinit22 = {5,6,7};
|
|||
int sinit23[2] = { "astring" ? sizeof("astring") : -1,
|
||||
&sinit23 ? 42 : -1 };
|
||||
|
||||
int sinit24 = 2 || 1 / 0; /* exception in constant but unevaluated context */
|
||||
|
||||
extern int external_inited = 42;
|
||||
|
||||
void init_test(void)
|
||||
|
@ -1866,6 +1988,7 @@ void init_test(void)
|
|||
printf("arrtype6: %d\n", sizeof(arrtype2));
|
||||
|
||||
printf("sinit23= %d %d\n", sinit23[0], sinit23[1]);
|
||||
printf("sinit24=%d\n", sinit24);
|
||||
printf("linit18= %d %d\n", linit18[0], linit18[1]);
|
||||
}
|
||||
|
||||
|
@ -1991,7 +2114,7 @@ void c99_bool_test(void)
|
|||
{
|
||||
#ifdef BOOL_ISOC99
|
||||
int a;
|
||||
_Bool b;
|
||||
_Bool b, b2;
|
||||
|
||||
printf("bool_test:\n");
|
||||
printf("sizeof(_Bool) = %d\n", sizeof(_Bool));
|
||||
|
@ -2001,6 +2124,9 @@ void c99_bool_test(void)
|
|||
printf("b = %d\n", b);
|
||||
b++;
|
||||
printf("b = %d\n", b);
|
||||
b2 = 0;
|
||||
printf("sizeof(x ? _Bool : _Bool) = %d (should be sizeof int)\n",
|
||||
sizeof((volatile)a ? b : b2));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2234,6 +2360,9 @@ void float_test(void)
|
|||
double da, db;
|
||||
int a;
|
||||
unsigned int b;
|
||||
static double nan2 = 0.0/0.0;
|
||||
static double inf1 = 1.0/0.0;
|
||||
static double inf2 = 1e5000;
|
||||
|
||||
printf("float_test:\n");
|
||||
printf("sizeof(float) = %d\n", sizeof(float));
|
||||
|
@ -2255,6 +2384,7 @@ void float_test(void)
|
|||
b = 4000000000;
|
||||
db = b;
|
||||
printf("db = %f\n", db);
|
||||
printf("nan != nan = %d, inf1 = %f, inf2 = %f\n", nan2 != nan2, inf1, inf2);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2266,6 +2396,12 @@ int fib(int n)
|
|||
return fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
#if __GNUC__ == 3
|
||||
# define aligned_function 0
|
||||
#else
|
||||
void __attribute__((aligned(16))) aligned_function(int i) {}
|
||||
#endif
|
||||
|
||||
void funcptr_test()
|
||||
{
|
||||
void (*func)(int);
|
||||
|
@ -2296,6 +2432,10 @@ void funcptr_test()
|
|||
func(42);
|
||||
(func + diff)(42);
|
||||
(num + a)(43);
|
||||
|
||||
/* Check that we can align functions */
|
||||
func = aligned_function;
|
||||
printf("aligned_function (should be zero): %d\n", ((int)(uintptr_t)func) & 15);
|
||||
}
|
||||
|
||||
void lloptest(long long a, long long b)
|
||||
|
@ -2420,6 +2560,11 @@ long long llfunc2(long long x, long long y, int z)
|
|||
return x * y * z;
|
||||
}
|
||||
|
||||
void check_opl_save_regs(char *a, long long b, int c)
|
||||
{
|
||||
*a = b < 0 && !c;
|
||||
}
|
||||
|
||||
void longlong_test(void)
|
||||
{
|
||||
long long a, b, c;
|
||||
|
@ -2487,6 +2632,19 @@ void longlong_test(void)
|
|||
a = 0x123;
|
||||
long long *p = &a;
|
||||
llshift(*p, 5);
|
||||
|
||||
/* shortening followed by widening */
|
||||
unsigned long long u = 0x8000000000000001ULL;
|
||||
u = (unsigned)(u + 1);
|
||||
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
|
||||
u = 0x11223344aa998877ULL;
|
||||
u = (unsigned)(int)(u + 1);
|
||||
printf("long long u=" ULONG_LONG_FORMAT "\n", u);
|
||||
|
||||
/* was a problem with missing save_regs in gen_opl on 32-bit platforms */
|
||||
char cc = 78;
|
||||
check_opl_save_regs(&cc, -1, 0);
|
||||
printf("check_opl_save_regs: %d\n", cc);
|
||||
}
|
||||
|
||||
void manyarg_test(void)
|
||||
|
@ -2524,6 +2682,18 @@ void manyarg_test(void)
|
|||
42.0, 43.0, ld);
|
||||
}
|
||||
|
||||
void*
|
||||
va_arg_with_struct_ptr(va_list ap) {
|
||||
/*
|
||||
* This was a BUG identified with FFTW-3.3.8 on arm64.
|
||||
* The test case only checks it compiles on all supported
|
||||
* architectures. This function is not currently called.
|
||||
*/
|
||||
struct X { int _x; };
|
||||
struct X *x = va_arg(ap, struct X *);
|
||||
return x;
|
||||
}
|
||||
|
||||
void vprintf1(const char *fmt, ...)
|
||||
{
|
||||
va_list ap, aq;
|
||||
|
@ -2601,6 +2771,19 @@ void stdarg_for_libc(const char *fmt, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void stdarg_syntax(int n, ...)
|
||||
{
|
||||
int i;
|
||||
va_list ap;
|
||||
if (1)
|
||||
va_start(ap, n);
|
||||
else
|
||||
;
|
||||
i = va_arg(ap, int);
|
||||
printf("stdarg_void_expr: %d\n", i);
|
||||
(va_end(ap));
|
||||
}
|
||||
|
||||
void stdarg_test(void)
|
||||
{
|
||||
LONG_DOUBLE ld = 1234567891234LL;
|
||||
|
@ -2648,6 +2831,7 @@ void stdarg_test(void)
|
|||
bob.profile = 42;
|
||||
stdarg_for_struct(bob, bob, bob, bob.profile);
|
||||
stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456);
|
||||
stdarg_syntax(1, 17);
|
||||
}
|
||||
|
||||
void whitespace_test(void)
|
||||
|
@ -2816,10 +3000,6 @@ void c99_vla_test(int size1, int size2)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef __TINYC__
|
||||
typedef __SIZE_TYPE__ uintptr_t;
|
||||
#endif
|
||||
|
||||
void sizeof_test(void)
|
||||
{
|
||||
int a;
|
||||
|
@ -2962,6 +3142,22 @@ void statement_expr_test(void)
|
|||
|
||||
/* Test that we can give out addresses of local labels. */
|
||||
consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
|
||||
|
||||
/* Test interaction between local and global label stacks and the
|
||||
need to defer popping symbol from them when within statement
|
||||
expressions. Note how the labels are both named LBL. */
|
||||
i = 0;
|
||||
({
|
||||
{
|
||||
__label__ LBL;
|
||||
LBL: if (i++ == 0) goto LBL;
|
||||
}
|
||||
/* jump to a classical label out of an expr-stmt that had previously
|
||||
overshadowed that classical label */
|
||||
goto LBL;
|
||||
});
|
||||
LBL:
|
||||
printf("stmtexpr: %d should be 2\n", i);
|
||||
}
|
||||
|
||||
void local_label_test(void)
|
||||
|
@ -3189,6 +3385,20 @@ void override_func2 (void)
|
|||
extern int bug_table[] __attribute__((section("__bug_table")));
|
||||
char * get_asm_string (void)
|
||||
{
|
||||
/* On i386 when -fPIC is enabled this would cause a compile error with GCC,
|
||||
the problem being the "i" constraint used with a symbolic operand
|
||||
resolving to a local label. That check is overly zealous as the code
|
||||
within the asm makes sure to use it only in PIC-possible contexts,
|
||||
but all GCC versions behave like so. We arrange for PIC to be disabled
|
||||
for compiling tcctest.c in the Makefile.
|
||||
|
||||
Additionally the usage of 'c' in "%c0" in the template is actually wrong,
|
||||
as that would expect an operand that is a condition code. The operand
|
||||
as is (a local label) is accepted by GCC in non-PIC mode, and on x86-64.
|
||||
What the linux kernel really wanted is 'p' to disable the addition of '$'
|
||||
to the printed operand (as in "$.LC0" where the template only wants the
|
||||
bare operand ".LC0"). But the code below is what the linux kernel
|
||||
happens to use and as such is the one we want to test. */
|
||||
extern int some_symbol;
|
||||
asm volatile (".globl some_symbol\n"
|
||||
"jmp .+6\n"
|
||||
|
@ -3255,7 +3465,7 @@ void clobber_r12(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
void test_high_clobbers(void)
|
||||
void test_high_clobbers_really(void)
|
||||
{
|
||||
#if defined __x86_64__ && !defined _WIN64
|
||||
register long val asm("r12");
|
||||
|
@ -3271,6 +3481,20 @@ void test_high_clobbers(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
void test_high_clobbers(void)
|
||||
{
|
||||
#if defined __x86_64__ && !defined _WIN64
|
||||
long x1, x2;
|
||||
asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
|
||||
test_high_clobbers_really();
|
||||
asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
|
||||
asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */
|
||||
/* should be 0 but tcc doesn't save r12 automatically, which has
|
||||
bad effects when gcc helds TCCState *s in r12 in tcc.c:main */
|
||||
//printf("r12-clobber-diff: %lx\n", x2 - x1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static long cpu_number;
|
||||
void trace_console(long len, long len2)
|
||||
{
|
||||
|
@ -3387,10 +3611,18 @@ void asm_dot_test(void)
|
|||
case 2:
|
||||
asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0");
|
||||
case 3:
|
||||
asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4");
|
||||
#ifndef _WIN32
|
||||
asm(".pushsection \".data\"; Y=.; .int 999; X=Y; .int 456; X=.-4; .popsection");
|
||||
#else
|
||||
asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4; .text");
|
||||
#endif
|
||||
asm(".text; mov X"RX",%eax; jmp p0");
|
||||
case 4:
|
||||
asm(".data; X=.; .int 789; Y=.; .int 999");
|
||||
#ifndef _WIN32
|
||||
asm(".data; X=.; .int 789; Y=.; .int 999; .previous");
|
||||
#else
|
||||
asm(".data; X=.; .int 789; Y=.; .int 999; .text");
|
||||
#endif
|
||||
asm(".text; mov X"RX",%eax; X=Y; jmp p0");
|
||||
case 0:
|
||||
asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
|
||||
|
@ -3535,6 +3767,9 @@ void builtin_test(void)
|
|||
printf("res = %d\n", __builtin_constant_p(&constant_p_var));
|
||||
printf("res = %d\n", __builtin_constant_p(constant_p_var));
|
||||
printf("res = %d\n", __builtin_constant_p(100000 / constant_p_var));
|
||||
printf("res = %d\n", __builtin_constant_p(i && 0));
|
||||
printf("res = %d\n", __builtin_constant_p(i && 1));
|
||||
printf("res = %d\n", __builtin_constant_p(i && 0 ? i : 34));
|
||||
s = 1;
|
||||
ll = 2;
|
||||
i = __builtin_choose_expr (1 != 0, ll, s);
|
||||
|
@ -3695,6 +3930,7 @@ int fcompare (double a, double b, int code)
|
|||
case 4: return a > b;
|
||||
case 5: return a <= b;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void math_cmp_test(void)
|
||||
|
@ -3703,6 +3939,7 @@ void math_cmp_test(void)
|
|||
double one = 1.0;
|
||||
double two = 2.0;
|
||||
int comp = 0;
|
||||
int v;
|
||||
#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part)
|
||||
|
||||
/* This asserts that "a op b" is _not_ true, but "a iop b" is true.
|
||||
|
@ -3724,7 +3961,8 @@ void math_cmp_test(void)
|
|||
if ((a iop b) || comp) \
|
||||
; \
|
||||
else \
|
||||
bug (a,b,op,iop,5);
|
||||
bug (a,b,op,iop,5); \
|
||||
if (v = !(a op b), !v) bug(a,b,op,iop,7);
|
||||
|
||||
/* Equality tests. */
|
||||
FCMP(nan, nan, ==, !=, 0);
|
||||
|
@ -3793,8 +4031,10 @@ void builtin_frame_address_test(void)
|
|||
char *fp0 = __builtin_frame_address(0);
|
||||
|
||||
printf("str: %s\n", str);
|
||||
#ifndef __riscv
|
||||
bfa1(str-fp0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
char via_volatile (char i)
|
||||
|
@ -3869,3 +4109,18 @@ int force_get_order(unsigned long s)
|
|||
{
|
||||
return __get_order(s);
|
||||
}
|
||||
|
||||
#define pv(m) printf(sizeof (s->m + 0) == 8 ? "%016llx\n" : "%02x\n", s->m)
|
||||
|
||||
/* Test failed when using bounds checking */
|
||||
void bounds_check1_test (void)
|
||||
{
|
||||
struct s {
|
||||
int x;
|
||||
long long y;
|
||||
} _s, *s = &_s;
|
||||
s->x = 10;
|
||||
s->y = 20;
|
||||
pv(x);
|
||||
pv(y);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
#include <stdio.h>
|
||||
extern int printf(const char*, ...);
|
||||
|
||||
struct fred
|
||||
struct fred;
|
||||
|
||||
void fred$(struct fred* this)
|
||||
{
|
||||
printf("~fred()\n");
|
||||
}
|
||||
|
||||
struct __attribute__((__cleanup__(fred$))) fred
|
||||
{
|
||||
int boris;
|
||||
int natasha;
|
||||
|
@ -8,7 +15,7 @@ struct fred
|
|||
|
||||
int main()
|
||||
{
|
||||
struct fred bloggs;
|
||||
struct fred __attribute__((__cleanup__(fred$))) bloggs;
|
||||
|
||||
bloggs.boris = 12;
|
||||
bloggs.natasha = 34;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
03_struct.c:14: warning: attribute '__cleanup__' ignored on type
|
||||
12
|
||||
34
|
||||
12
|
||||
34
|
||||
56
|
||||
78
|
||||
~fred()
|
||||
|
|
|
@ -15,6 +15,11 @@ void qfunc()
|
|||
printf("qfunc()\n");
|
||||
}
|
||||
|
||||
void zfunc()
|
||||
{
|
||||
((void (*)(void))0) ();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("%d\n", myfunc(3));
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
void foo(int [5]);
|
||||
void fooc(int x[const 5]);
|
||||
void foos(int x[static 5]);
|
||||
void foov(int x[volatile 5]);
|
||||
void foor(int x[restrict 5]);
|
||||
void fooc(int [const 5]);
|
||||
void foos(int [static 5]);
|
||||
void foov(int [volatile 5]);
|
||||
void foor(int [restrict 5]);
|
||||
void fooc(int (* const x));
|
||||
void foos(int *x);
|
||||
void foov(int * volatile x);
|
||||
void foor(int * restrict x);
|
||||
void fooc(int x[volatile 5])
|
||||
{
|
||||
x[3] = 42;
|
||||
#ifdef INVALID
|
||||
x = 0;
|
||||
#endif
|
||||
}
|
||||
void foovm(int x[const *]);
|
||||
void foovm(int * const x);
|
||||
#ifdef INVALID
|
||||
void wrongc(int x[3][const 4]);
|
||||
void wrongvm(int x[static *]);
|
||||
void foovm(int x[const *])
|
||||
{
|
||||
x[2] = 1;
|
||||
}
|
||||
#endif
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
extern int printf(const char*, ...);
|
||||
static int glob_i = 0;
|
||||
|
||||
void incr_glob_i(int *i)
|
||||
{
|
||||
glob_i += *i;
|
||||
}
|
||||
|
||||
#define INCR_GI { \
|
||||
int i __attribute__ ((__cleanup__(incr_glob_i))) = 1; \
|
||||
}
|
||||
|
||||
#define INCR_GI0 INCR_GI INCR_GI INCR_GI INCR_GI
|
||||
#define INCR_GI1 INCR_GI0 INCR_GI0 INCR_GI0 INCR_GI0
|
||||
#define INCR_GI2 INCR_GI1 INCR_GI1 INCR_GI1 INCR_GI1
|
||||
#define INCR_GI3 INCR_GI2 INCR_GI2 INCR_GI2 INCR_GI2
|
||||
#define INCR_GI4 INCR_GI3 INCR_GI3 INCR_GI3 INCR_GI3
|
||||
#define INCR_GI5 INCR_GI4 INCR_GI4 INCR_GI4 INCR_GI4
|
||||
#define INCR_GI6 INCR_GI5 INCR_GI5 INCR_GI5 INCR_GI5
|
||||
#define INCR_GI7 INCR_GI6 INCR_GI6 INCR_GI6 INCR_GI6
|
||||
|
||||
|
||||
void check2(char **hum);
|
||||
|
||||
void check(int *j)
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "wololo";
|
||||
int chk = 0;
|
||||
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "plop";
|
||||
|
||||
{
|
||||
non_plopage:
|
||||
printf("---- %d\n", chk);
|
||||
}
|
||||
if (!chk) {
|
||||
chk = 1;
|
||||
goto non_plopage;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "tata !";
|
||||
|
||||
goto out;
|
||||
stop_that = "titi";
|
||||
}
|
||||
again:
|
||||
chk = 2;
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) cascade1 = "1";
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) cascade2 = "2";
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) cascade3 = "3";
|
||||
|
||||
goto out;
|
||||
cascade3 = "nope";
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (chk != 2)
|
||||
goto again;
|
||||
{
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) out = "last goto out";
|
||||
++chk;
|
||||
if (chk != 3)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void check_oh_i(char *oh_i)
|
||||
{
|
||||
printf("c: %c\n", *oh_i);
|
||||
}
|
||||
|
||||
void goto_hell(double *f)
|
||||
{
|
||||
printf("oo: %f\n", *f);
|
||||
}
|
||||
|
||||
char *test()
|
||||
{
|
||||
char *__attribute__ ((cleanup(check2))) str = "I don't think this should be print(but gcc got it wrong too)";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void test_ret_subcall(char *that)
|
||||
{
|
||||
printf("should be print before\n");
|
||||
}
|
||||
|
||||
void test_ret()
|
||||
{
|
||||
char *__attribute__ ((cleanup(check2))) that = "that";
|
||||
return test_ret_subcall(that);
|
||||
}
|
||||
|
||||
void test_ret2()
|
||||
{
|
||||
char *__attribute__ ((cleanup(check2))) that = "-that";
|
||||
{
|
||||
char *__attribute__ ((cleanup(check2))) that = "this should appear only once";
|
||||
}
|
||||
{
|
||||
char *__attribute__ ((cleanup(check2))) that = "-that2";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void test2(void) {
|
||||
int chk = 0;
|
||||
again:
|
||||
if (!chk) {
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "test2";
|
||||
chk++;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
int test3(void) {
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "three";
|
||||
int chk = 0;
|
||||
|
||||
if (chk) {
|
||||
{
|
||||
outside:
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "two";
|
||||
printf("---- %d\n", chk);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!chk)
|
||||
{
|
||||
char * __attribute__ ((cleanup(check2))) stop_that = "one";
|
||||
|
||||
if (!chk) {
|
||||
chk = 1;
|
||||
goto outside;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cl(int *ip)
|
||||
{
|
||||
printf("%d\n", *ip);
|
||||
}
|
||||
|
||||
void loop_cleanups(void)
|
||||
{
|
||||
__attribute__((cleanup(cl))) int l = 1000;
|
||||
|
||||
printf("-- loop 0 --\n");
|
||||
for ( __attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
|
||||
__attribute__((cleanup(cl))) int j = 100;
|
||||
}
|
||||
|
||||
printf("-- loop 1 --\n");
|
||||
for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
|
||||
__attribute__((cleanup(cl))) int j = 200;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("-- loop 2 --\n");
|
||||
for (__attribute__((cleanup(cl))) int i = 0; i < 10; ++i) {
|
||||
__attribute__((cleanup(cl))) int j = 300;
|
||||
break;
|
||||
}
|
||||
|
||||
printf("-- loop 3 --\n");
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
__attribute__((cleanup(cl))) int j = 400;
|
||||
switch (i) {
|
||||
case 0:
|
||||
continue;
|
||||
default:
|
||||
{
|
||||
__attribute__((cleanup(cl))) int jj = 500;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("after break\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i __attribute__ ((__cleanup__(check))) = 0, not_i;
|
||||
int chk = 0;
|
||||
(void)not_i;
|
||||
|
||||
{
|
||||
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a';
|
||||
}
|
||||
|
||||
INCR_GI7;
|
||||
printf("glob_i: %d\n", glob_i);
|
||||
naaaaaaaa:
|
||||
if (!chk) {
|
||||
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'f';
|
||||
double __attribute__ ((__cleanup__(goto_hell))) f = 2.6;
|
||||
|
||||
chk = 1;
|
||||
goto naaaaaaaa;
|
||||
}
|
||||
i = 105;
|
||||
printf("because what if free was call inside cleanup function %s\n", test());
|
||||
test_ret();
|
||||
test_ret2();
|
||||
test2();
|
||||
test3();
|
||||
loop_cleanups();
|
||||
return i;
|
||||
}
|
||||
|
||||
void check2(char **hum)
|
||||
{
|
||||
printf("str: %s\n", *hum);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
c: a
|
||||
c: o
|
||||
glob_i: 65536
|
||||
oo: 2.600000
|
||||
c: f
|
||||
str: I don't think this should be print(but gcc got it wrong too)
|
||||
because what if free was call inside cleanup function I don't think this should be print(but gcc got it wrong too)
|
||||
should be print before
|
||||
str: that
|
||||
str: this should appear only once
|
||||
str: -that2
|
||||
str: -that
|
||||
str: test2
|
||||
str: one
|
||||
---- 1
|
||||
str: two
|
||||
str: three
|
||||
-- loop 0 --
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
10
|
||||
-- loop 1 --
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
200
|
||||
10
|
||||
-- loop 2 --
|
||||
300
|
||||
0
|
||||
-- loop 3 --
|
||||
400
|
||||
500
|
||||
400
|
||||
after break
|
||||
1000
|
||||
---- 0
|
||||
---- 1
|
||||
str: plop
|
||||
str: tata !
|
||||
str: 3
|
||||
str: 2
|
||||
str: 1
|
||||
str: last goto out
|
||||
str: wololo
|
|
@ -0,0 +1,29 @@
|
|||
_Alignas(16) int i1;
|
||||
int _Alignas(16) i2;
|
||||
void _Alignas(16) *p2;
|
||||
_Alignas(16) i3;
|
||||
int _Alignas(double) i4;
|
||||
int _Alignas(int) i5;
|
||||
#if 0
|
||||
/* The following are currently wrongly accepted by TCC but really shouldn't. */
|
||||
int _Alignas(int _Alignas(16)) i6; //wrong, 'int _Alignas(16)' is no type-name
|
||||
typedef int _Alignas(16) int16aligned_t; //wrong, _Alignas invalid on typedef
|
||||
int16aligned_t i7;
|
||||
#endif
|
||||
/* i8 should get an alignment of 16, because unlike _Alignas the
|
||||
corresponding attribute _does_ apply to type-name, though not in
|
||||
some clang versions. */
|
||||
int _Alignas(int __attribute__((aligned(16)))) i8;
|
||||
extern int printf(const char*, ...);
|
||||
#ifdef _MSC_VER
|
||||
#define alignof(x) (int)__alignof(x)
|
||||
#else
|
||||
#define alignof(x) (int)__alignof__(x)
|
||||
#endif
|
||||
int main()
|
||||
{
|
||||
printf("%d %d %d %d\n",
|
||||
alignof(i1) == 16, alignof(i4) == alignof(double),
|
||||
alignof(i5) == alignof(int) , alignof(i8) == 16);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
1 1 1 1
|
|
@ -0,0 +1,20 @@
|
|||
/* Test that the memmove TCC is emitting for the struct copy
|
||||
and hence implicitely declares can be declared properly also
|
||||
later. */
|
||||
struct S { int a,b,c,d, e[1024];};
|
||||
int foo (struct S *a, struct S *b)
|
||||
{
|
||||
*a = *b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memmove(void*,void*,long);
|
||||
void foo2 (struct S *a, struct S *b)
|
||||
{
|
||||
memmove(a, b, sizeof *a);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
#define GOT(f) \
|
||||
__attribute__((weak)) void f(void); \
|
||||
printf("%d %s\n", !!f, #f);
|
||||
|
||||
int printf(const char*, ...);
|
||||
|
||||
void check_exports()
|
||||
{
|
||||
// 0
|
||||
GOT(inline_inline_2decl_only)
|
||||
GOT(inline_inline_undeclared)
|
||||
GOT(inline_inline_predeclared)
|
||||
GOT(inline_inline_postdeclared)
|
||||
GOT(inline_inline_prepostdeclared)
|
||||
GOT(inline_inline_undeclared2)
|
||||
GOT(inline_inline_predeclared2)
|
||||
GOT(inline_inline_postdeclared2)
|
||||
GOT(inline_inline_prepostdeclared2)
|
||||
|
||||
// 1
|
||||
GOT(extern_extern_postdeclared)
|
||||
GOT(extern_extern_postdeclared2)
|
||||
GOT(extern_extern_predeclared)
|
||||
GOT(extern_extern_predeclared2)
|
||||
GOT(extern_extern_prepostdeclared)
|
||||
GOT(extern_extern_prepostdeclared2)
|
||||
GOT(extern_extern_undeclared)
|
||||
GOT(extern_extern_undeclared2)
|
||||
GOT(extern_postdeclared)
|
||||
GOT(extern_postdeclared2)
|
||||
GOT(extern_predeclared)
|
||||
GOT(extern_predeclared2)
|
||||
GOT(extern_prepostdeclared)
|
||||
GOT(extern_undeclared)
|
||||
GOT(extern_undeclared2)
|
||||
GOT(inst2_extern_inline_postdeclared)
|
||||
GOT(inst2_extern_inline_predeclared)
|
||||
GOT(inst3_extern_inline_predeclared)
|
||||
GOT(inst_extern_inline_postdeclared)
|
||||
GOT(inst_extern_inline_predeclared)
|
||||
GOT(main)
|
||||
GOT(noinst_extern_inline_func)
|
||||
GOT(noinst_extern_inline_postdeclared)
|
||||
GOT(noinst_extern_inline_postdeclared2)
|
||||
GOT(noinst_extern_inline_undeclared)
|
||||
|
||||
// 0
|
||||
GOT(noinst_static_inline_postdeclared)
|
||||
GOT(noinst2_static_inline_postdeclared)
|
||||
GOT(noinst_static_inline_predeclared)
|
||||
GOT(noinst2_static_inline_predeclared)
|
||||
GOT(static_func)
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
inline void inline_inline_2decl_only(void);
|
||||
inline void inline_inline_2decl_only(void);
|
||||
|
||||
inline void inline_inline_undeclared(void){}
|
||||
|
||||
inline void inline_inline_predeclared(void);
|
||||
inline void inline_inline_predeclared(void){}
|
||||
|
||||
inline void inline_inline_postdeclared(void){}
|
||||
inline void inline_inline_postdeclared(void);
|
||||
|
||||
inline void inline_inline_prepostdeclared(void);
|
||||
inline void inline_inline_prepostdeclared(void){}
|
||||
inline void inline_inline_prepostdeclared(void);
|
||||
|
||||
inline void inline_inline_undeclared2(void){}
|
||||
|
||||
inline void inline_inline_predeclared2(void);
|
||||
inline void inline_inline_predeclared2(void);
|
||||
inline void inline_inline_predeclared2(void){}
|
||||
|
||||
inline void inline_inline_postdeclared2(void){}
|
||||
inline void inline_inline_postdeclared2(void);
|
||||
inline void inline_inline_postdeclared2(void);
|
||||
|
||||
inline void inline_inline_prepostdeclared2(void);
|
||||
inline void inline_inline_prepostdeclared2(void);
|
||||
inline void inline_inline_prepostdeclared2(void){}
|
||||
inline void inline_inline_prepostdeclared2(void);
|
||||
inline void inline_inline_prepostdeclared2(void);
|
||||
|
||||
extern void extern_extern_undeclared(void){}
|
||||
|
||||
extern void extern_extern_predeclared(void);
|
||||
extern void extern_extern_predeclared(void){}
|
||||
|
||||
extern void extern_extern_postdeclared(void){}
|
||||
extern void extern_extern_postdeclared(void);
|
||||
|
||||
extern void extern_extern_prepostdeclared(void);
|
||||
extern void extern_extern_prepostdeclared(void){}
|
||||
extern void extern_extern_prepostdeclared(void);
|
||||
|
||||
extern void extern_extern_undeclared2(void){}
|
||||
|
||||
extern void extern_extern_predeclared2(void);
|
||||
extern void extern_extern_predeclared2(void);
|
||||
extern void extern_extern_predeclared2(void){}
|
||||
|
||||
extern void extern_extern_postdeclared2(void){}
|
||||
extern void extern_extern_postdeclared2(void);
|
||||
extern void extern_extern_postdeclared2(void);
|
||||
|
||||
extern void extern_extern_prepostdeclared2(void);
|
||||
extern void extern_extern_prepostdeclared2(void);
|
||||
extern void extern_extern_prepostdeclared2(void){}
|
||||
extern void extern_extern_prepostdeclared2(void);
|
||||
extern void extern_extern_prepostdeclared2(void);
|
||||
|
||||
void extern_undeclared(void){}
|
||||
|
||||
void extern_predeclared(void);
|
||||
void extern_predeclared(void){}
|
||||
|
||||
void extern_postdeclared(void){}
|
||||
void extern_postdeclared(void);
|
||||
|
||||
void extern_prepostdeclared(void);
|
||||
void extern_prepostdeclared(void){}
|
||||
void extern_prepostdeclared(void);
|
||||
|
||||
void extern_undeclared2(void){}
|
||||
|
||||
void extern_predeclared2(void);
|
||||
void extern_predeclared2(void);
|
||||
void extern_predeclared2(void){}
|
||||
|
||||
void extern_postdeclared2(void){}
|
||||
void extern_postdeclared2(void);
|
||||
void extern_postdeclared2(void);
|
||||
|
||||
|
||||
extern inline void noinst_extern_inline_undeclared(void){}
|
||||
|
||||
extern inline void noinst_extern_inline_postdeclared(void){}
|
||||
inline void noinst_extern_inline_postdeclared(void);
|
||||
|
||||
extern inline void noinst_extern_inline_postdeclared2(void){}
|
||||
inline void noinst_extern_inline_postdeclared2(void);
|
||||
inline void noinst_extern_inline_postdeclared2(void);
|
||||
|
||||
extern inline void inst_extern_inline_postdeclared(void){}
|
||||
extern inline void inst_extern_inline_postdeclared(void);
|
||||
inline void inst2_extern_inline_postdeclared(void){}
|
||||
void inst2_extern_inline_postdeclared(void);
|
||||
|
||||
void inst_extern_inline_predeclared(void);
|
||||
extern inline void inst_extern_inline_predeclared(void){}
|
||||
void inst2_extern_inline_predeclared(void);
|
||||
inline void inst2_extern_inline_predeclared(void){}
|
||||
extern inline void inst3_extern_inline_predeclared(void);
|
||||
inline void inst3_extern_inline_predeclared(void){}
|
||||
|
||||
static inline void noinst_static_inline_postdeclared(void){}
|
||||
static inline void noinst_static_inline_postdeclared(void);
|
||||
static inline void noinst2_static_inline_postdeclared(void){}
|
||||
static void noinst2_static_inline_postdeclared(void);
|
||||
|
||||
static void noinst_static_inline_predeclared(void);
|
||||
static inline void noinst_static_inline_predeclared(void){}
|
||||
static void noinst2_static_inline_predeclared(void);
|
||||
static inline void noinst2_static_inline_predeclared(void){}
|
||||
|
||||
static void static_func(void);
|
||||
void static_func(void) { }
|
||||
|
||||
inline void noinst_extern_inline_func(void);
|
||||
void noinst_extern_inline_func(void) { }
|
||||
|
||||
int main()
|
||||
{
|
||||
inline_inline_undeclared(); inline_inline_predeclared(); inline_inline_postdeclared();
|
||||
inline_inline_undeclared2(); inline_inline_predeclared2(); inline_inline_postdeclared2();
|
||||
noinst_static_inline_predeclared();
|
||||
noinst2_static_inline_predeclared();
|
||||
noinst_static_inline_predeclared();
|
||||
noinst2_static_inline_predeclared();
|
||||
|
||||
void check_exports();
|
||||
check_exports();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
0 inline_inline_2decl_only
|
||||
0 inline_inline_undeclared
|
||||
0 inline_inline_predeclared
|
||||
0 inline_inline_postdeclared
|
||||
0 inline_inline_prepostdeclared
|
||||
0 inline_inline_undeclared2
|
||||
0 inline_inline_predeclared2
|
||||
0 inline_inline_postdeclared2
|
||||
0 inline_inline_prepostdeclared2
|
||||
1 extern_extern_postdeclared
|
||||
1 extern_extern_postdeclared2
|
||||
1 extern_extern_predeclared
|
||||
1 extern_extern_predeclared2
|
||||
1 extern_extern_prepostdeclared
|
||||
1 extern_extern_prepostdeclared2
|
||||
1 extern_extern_undeclared
|
||||
1 extern_extern_undeclared2
|
||||
1 extern_postdeclared
|
||||
1 extern_postdeclared2
|
||||
1 extern_predeclared
|
||||
1 extern_predeclared2
|
||||
1 extern_prepostdeclared
|
||||
1 extern_undeclared
|
||||
1 extern_undeclared2
|
||||
1 inst2_extern_inline_postdeclared
|
||||
1 inst2_extern_inline_predeclared
|
||||
1 inst3_extern_inline_predeclared
|
||||
1 inst_extern_inline_postdeclared
|
||||
1 inst_extern_inline_predeclared
|
||||
1 main
|
||||
1 noinst_extern_inline_func
|
||||
1 noinst_extern_inline_postdeclared
|
||||
1 noinst_extern_inline_postdeclared2
|
||||
1 noinst_extern_inline_undeclared
|
||||
0 noinst_static_inline_postdeclared
|
||||
0 noinst2_static_inline_postdeclared
|
||||
0 noinst_static_inline_predeclared
|
||||
0 noinst2_static_inline_predeclared
|
||||
0 static_func
|
|
@ -0,0 +1,12 @@
|
|||
extern int printf(const char *, ...);
|
||||
void f(void);
|
||||
void bar(void) { void f(void); f(); }
|
||||
void foo(void) { extern void f(void); f(); }
|
||||
void f(void) { printf("f\n"); }
|
||||
|
||||
int main()
|
||||
{
|
||||
bar();
|
||||
foo();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
f
|
||||
f
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int ret;
|
||||
pthread_condattr_t attr;
|
||||
pthread_cond_t condition;
|
||||
|
||||
pthread_condattr_init (&attr);
|
||||
pthread_condattr_setpshared (&attr, PTHREAD_PROCESS_SHARED);
|
||||
printf ("%s\n", pthread_cond_init (&condition, &attr) ? "fail":"ok");
|
||||
pthread_condattr_destroy (&attr);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ok
|
|
@ -0,0 +1,13 @@
|
|||
extern int printf(const char *, ...);
|
||||
|
||||
static void func_ull_ull(unsigned long long l1,unsigned long long l2){
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int a,b,c,d;
|
||||
a=1;b=2;c=3;d=4;
|
||||
func_ull_ull((unsigned long long)a/1.0,(unsigned long long)b/1.0);
|
||||
printf("%d %d %d %d",a,b,c,d);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
1 2 3 4
|
|
@ -0,0 +1,20 @@
|
|||
extern int write (int fd, void *buf, int len);
|
||||
|
||||
static void __attribute__ ((constructor))
|
||||
testc (void)
|
||||
{
|
||||
write (1, "constructor\n", 12);
|
||||
}
|
||||
|
||||
static void __attribute__ ((destructor))
|
||||
testd (void)
|
||||
{
|
||||
write (1, "destructor\n", 11);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
write (1, "main\n", 5);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
constructor
|
||||
main
|
||||
destructor
|
|
@ -0,0 +1,24 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* This test used to fail on x86_64 on linux with sse registers */
|
||||
|
||||
struct Point {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct Rect {
|
||||
struct Point top_left;
|
||||
struct Point size;
|
||||
};
|
||||
|
||||
float foo(struct Point p, struct Rect r) {
|
||||
return r.size.x;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct Point p = {1, 2};
|
||||
struct Rect r = {{3, 4}, {5, 6}};
|
||||
printf("%f\n", foo(p, r));
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
5.000000
|
|
@ -0,0 +1,27 @@
|
|||
#include <stdio.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double average;
|
||||
int count;
|
||||
}
|
||||
stats_type;
|
||||
|
||||
static void
|
||||
testc (stats_type *s, long long data)
|
||||
{
|
||||
s->average = (s->average * s->count + data) / (s->count + 1);
|
||||
s->count++;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
stats_type s;
|
||||
|
||||
s.average = 0;
|
||||
s.count = 0;
|
||||
testc (&s, 10);
|
||||
testc (&s, 20);
|
||||
printf ("%g %d\n", s.average, s.count);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
15 2
|
|
@ -0,0 +1,22 @@
|
|||
#include <stdio.h>
|
||||
|
||||
union u {
|
||||
unsigned long ul;
|
||||
long double ld;
|
||||
};
|
||||
|
||||
void
|
||||
conv (union u *p)
|
||||
{
|
||||
p->ul = (unsigned int) p->ld;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
union u v;
|
||||
|
||||
v.ld = 42;
|
||||
conv (&v);
|
||||
printf ("%lu\n", v.ul);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
42
|
|
@ -0,0 +1,165 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/* ------------------------------------------------------- */
|
||||
#if defined test_backtrace_1
|
||||
|
||||
void f3()
|
||||
{
|
||||
printf("* f3()\n"), fflush(stdout);
|
||||
*(void**)0 = 0;
|
||||
}
|
||||
void f2()
|
||||
{
|
||||
printf("* f2()\n"), fflush(stdout);
|
||||
f3();
|
||||
}
|
||||
void f1()
|
||||
{
|
||||
printf("* f1()\n"), fflush(stdout);
|
||||
f2();
|
||||
}
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("* main\n"), fflush(stdout);
|
||||
f1();
|
||||
printf("* exit main\n"), fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- */
|
||||
#elif defined test_bcheck_1
|
||||
|
||||
struct s { int a,b,c,d,e; };
|
||||
struct s s[3];
|
||||
struct s *ps = s;
|
||||
void f1()
|
||||
{
|
||||
printf("* f1()\n"), fflush(stdout);
|
||||
ps[3] = ps[2];
|
||||
}
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("* main\n"), fflush(stdout);
|
||||
f1();
|
||||
printf("* exit main\n"), fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- */
|
||||
#elif defined test_tcc_backtrace_2
|
||||
|
||||
/* test custom backtrace and 'exit()' redirection */
|
||||
int tcc_backtrace(const char *fmt, ...);
|
||||
void exit(int);
|
||||
|
||||
void f2()
|
||||
{
|
||||
printf("* f2()\n");
|
||||
printf("* exit f2\n"), fflush(stdout);
|
||||
exit(34);
|
||||
}
|
||||
void f1()
|
||||
{
|
||||
printf("* f1()\n"), fflush(stdout);
|
||||
tcc_backtrace("Hello from %s!", "f1");
|
||||
f2();
|
||||
}
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("* main\n"), fflush(stdout);
|
||||
f1();
|
||||
printf("* exit main\n"), fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- */
|
||||
#elif defined test_tcc_backtrace_3
|
||||
|
||||
/* this test should be run despite of the exit(34) above */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("* main\n"), fflush(stdout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------- */
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
char *strdup();
|
||||
int main()
|
||||
{
|
||||
char pad1[10];
|
||||
char a[10];
|
||||
char pad2[10];
|
||||
char b[10];
|
||||
char pad3[10];
|
||||
memset (pad1, 0, sizeof(pad1));
|
||||
memset (pad2, 0, sizeof(pad2));
|
||||
memset (pad3, 0, sizeof(pad3));
|
||||
|
||||
memset (a, 'a', 10);
|
||||
a[3] = 0;
|
||||
a[9] = 0;
|
||||
memset (b, 'b', 10);
|
||||
|
||||
#if defined test_bcheck_100
|
||||
memcpy(&a[1],&b[0],10);
|
||||
#elif defined test_bcheck_101
|
||||
memcpy(&a[0],&b[1],10);
|
||||
#elif defined test_bcheck_102
|
||||
memcpy(&a[0],&a[3],4);
|
||||
#elif defined test_bcheck_103
|
||||
memcpy(&a[3],&a[0],4);
|
||||
#elif defined test_bcheck_104
|
||||
memcmp(&b[1],&b[0],10);
|
||||
#elif defined test_bcheck_105
|
||||
memcmp(&b[0],&b[1],10);
|
||||
#elif defined test_bcheck_106
|
||||
memmove(&b[1],&b[0],10);
|
||||
#elif defined test_bcheck_107
|
||||
memmove(&b[0],&b[1],10);
|
||||
#elif defined test_bcheck_108
|
||||
memset(&b[1],'b',10);
|
||||
#elif defined test_bcheck_109
|
||||
strlen(&b[0]);
|
||||
#elif defined test_bcheck_110
|
||||
strcpy(&a[7], &a[0]);
|
||||
#elif defined test_bcheck_111
|
||||
strcpy(&a[0], &b[7]);
|
||||
#elif defined test_bcheck_112
|
||||
strcpy(&a[0], &a[1]);
|
||||
#elif defined test_bcheck_113
|
||||
strcpy(&a[2], &a[0]);
|
||||
#elif defined test_bcheck_114
|
||||
strncpy(&a[7], &a[0], 10);
|
||||
#elif defined test_bcheck_115
|
||||
strncpy(&a[0], &b[7], 10);
|
||||
#elif defined test_bcheck_116
|
||||
strncpy(&a[0], &a[1], 10);
|
||||
#elif defined test_bcheck_117
|
||||
strncpy(&a[2], &a[0], 10);
|
||||
#elif defined test_bcheck_118
|
||||
strcmp(&b[2], &b[0]);
|
||||
#elif defined test_bcheck_119
|
||||
strcmp(&b[0], &b[2]);
|
||||
#elif defined test_bcheck_120
|
||||
strncmp(&b[5], &b[0], 10);
|
||||
#elif defined test_bcheck_121
|
||||
strncmp(&b[0], &b[5], 10);
|
||||
#elif defined test_bcheck_122
|
||||
strcat(&a[7], &a[0]);
|
||||
#elif defined test_bcheck_123
|
||||
strcat(&a[0], &b[3]);
|
||||
#elif defined test_bcheck_124
|
||||
strcat(&a[0], &a[4]);
|
||||
#elif defined test_bcheck_125
|
||||
strcat(&a[3], &a[0]);
|
||||
#elif defined test_bcheck_126
|
||||
strchr(&b[0], 'a');
|
||||
#elif defined test_bcheck_127
|
||||
free(strdup(&b[0]));
|
||||
#endif
|
||||
}
|
||||
/* ------------------------------------------------------- */
|
||||
#endif
|
|
@ -0,0 +1,142 @@
|
|||
[test_backtrace_1]
|
||||
* main
|
||||
* f1()
|
||||
* f2()
|
||||
* f3()
|
||||
112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access
|
||||
112_backtrace.c:14: by f2
|
||||
112_backtrace.c:19: by f1
|
||||
112_backtrace.c:24: by main
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_1]
|
||||
* main
|
||||
* f1()
|
||||
112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest
|
||||
112_backtrace.c:43: by main
|
||||
[returns 255]
|
||||
|
||||
[test_tcc_backtrace_2]
|
||||
* main
|
||||
* f1()
|
||||
112_backtrace.c:64: at f1: Hello from f1!
|
||||
112_backtrace.c:70: by main
|
||||
* f2()
|
||||
* exit f2
|
||||
[returns 34]
|
||||
|
||||
[test_tcc_backtrace_3]
|
||||
* main
|
||||
[returns 1]
|
||||
|
||||
[test_bcheck_100]
|
||||
112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_101]
|
||||
112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_102]
|
||||
112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_103]
|
||||
112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in memcpy
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_104]
|
||||
112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_105]
|
||||
112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_106]
|
||||
112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_107]
|
||||
112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_108]
|
||||
112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_109]
|
||||
112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_110]
|
||||
112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_111]
|
||||
112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_112]
|
||||
112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_113]
|
||||
112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcpy
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_114]
|
||||
112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_115]
|
||||
112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_116]
|
||||
112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_117]
|
||||
112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strncpy
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_118]
|
||||
112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_119]
|
||||
112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_120]
|
||||
112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_121]
|
||||
112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_122]
|
||||
112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_123]
|
||||
112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_124]
|
||||
112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_125]
|
||||
112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x?), ........(0x?) in strcat
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_126]
|
||||
112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr
|
||||
[returns 255]
|
||||
|
||||
[test_bcheck_127]
|
||||
112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup
|
||||
[returns 255]
|
|
@ -0,0 +1,43 @@
|
|||
int tcc_backtrace(const char*, ...);
|
||||
#define hello() \
|
||||
tcc_backtrace("hello from %s() / %s:%d",__FUNCTION__,__FILE__,__LINE__)
|
||||
|
||||
#ifndef _WIN32
|
||||
# define __declspec(n)
|
||||
#endif
|
||||
|
||||
#if DLL==1
|
||||
__declspec(dllexport) int f_1()
|
||||
{
|
||||
hello();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#elif DLL==2
|
||||
__declspec(dllexport) int f_2()
|
||||
{
|
||||
hello();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int f_1();
|
||||
int f_2();
|
||||
int f_main()
|
||||
{
|
||||
hello();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
f_1();
|
||||
f_2();
|
||||
f_main();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
113_btdll.c:12: at f_1: hello from f_1() / 113_btdll.c:12
|
||||
113_btdll.c:37: by main
|
||||
113_btdll.c:20: at f_2: hello from f_2() / 113_btdll.c:20
|
||||
113_btdll.c:38: by main
|
||||
113_btdll.c:31: at f_main: hello from f_main() / 113_btdll.c:31
|
||||
113_btdll.c:39: by main
|
|
@ -0,0 +1,94 @@
|
|||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
static volatile int run = 1;
|
||||
static int dummy[10];
|
||||
static sem_t sem;
|
||||
|
||||
static void
|
||||
add (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (sizeof(dummy)/sizeof(dummy[0])); i++) {
|
||||
dummy[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
high_load (void *unused)
|
||||
{
|
||||
while (run) {
|
||||
add();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
do_signal (void *unused)
|
||||
{
|
||||
while (run) {
|
||||
kill (getpid(), SIGUSR1);
|
||||
while (sem_wait(&sem) < 0 && errno == EINTR);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* See tcc-doc.info */
|
||||
#ifdef __BOUNDS_CHECKING_ON
|
||||
extern void __bound_checking (int no_check);
|
||||
#define BOUNDS_CHECKING_OFF __bound_checking(1)
|
||||
#define BOUNDS_CHECKING_ON __bound_checking(-1)
|
||||
#else
|
||||
#define BOUNDS_CHECKING_OFF
|
||||
#define BOUNDS_CHECKING_ON
|
||||
#endif
|
||||
|
||||
static void real_signal_handler(int sig)
|
||||
{
|
||||
add();
|
||||
sem_post (&sem);
|
||||
}
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
BOUNDS_CHECKING_OFF;
|
||||
real_signal_handler(sig);
|
||||
BOUNDS_CHECKING_ON;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int i;
|
||||
pthread_t id1, id2;
|
||||
struct sigaction act;
|
||||
struct timespec request;
|
||||
|
||||
memset (&act, 0, sizeof (act));
|
||||
act.sa_handler = signal_handler;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigaction (SIGUSR1, &act, NULL);
|
||||
sem_init (&sem, 1, 0);
|
||||
pthread_create(&id1, NULL, high_load, NULL);
|
||||
pthread_create(&id2, NULL, do_signal, NULL);
|
||||
clock_gettime (CLOCK_MONOTONIC, &request);
|
||||
request.tv_sec += 1;
|
||||
request.tv_nsec += 0;
|
||||
printf ("start\n");
|
||||
while (clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &request, NULL)) {
|
||||
}
|
||||
printf ("end\n");
|
||||
run = 0;
|
||||
pthread_join(id1, NULL);
|
||||
pthread_join(id2, NULL);
|
||||
sem_destroy (&sem);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
start
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
float fd;
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
// was an internal tcc compiler error with arm64 backend until 2019-11-08
|
||||
if (fd < 5.5) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// variables
|
||||
|
|
|
@ -1,4 +1,43 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
extern int printf(const char*, ...);
|
||||
|
||||
char arr[1];
|
||||
static void f (void){}
|
||||
void (*fp)(void) = f;
|
||||
void call_fp()
|
||||
{
|
||||
(fp?f:f)();
|
||||
(fp?fp:fp)();
|
||||
(fp?fp:&f)();
|
||||
(fp?&f:fp)();
|
||||
(fp?&f:&f)();
|
||||
_Generic(0?arr:arr, char*: (void)0);
|
||||
_Generic(0?&arr[0]:arr, char*: (void)0);
|
||||
_Generic(0?arr:&arr[0], char*: (void)0);
|
||||
_Generic(1?arr:arr, char*: (void)0);
|
||||
_Generic(1?&arr[0]:arr, char*: (void)0);
|
||||
_Generic(1?arr:&arr[0], char*: (void)0);
|
||||
_Generic((__typeof(1?f:f)*){0}, void (**)(void): (void)0);
|
||||
(fp?&f:f)();
|
||||
(fp?f:&f)();
|
||||
_Generic((__typeof(fp?0L:(void)0)*){0}, void*: (void)0);
|
||||
|
||||
/* The following line causes a warning */
|
||||
void *xx = fp?f:1;
|
||||
}
|
||||
|
||||
struct condstruct {
|
||||
int i;
|
||||
};
|
||||
|
||||
static int getme(struct condstruct* s, int i)
|
||||
{
|
||||
int i1 = (i != 0 ? 0 : s)->i;
|
||||
int i2 = (i == 0 ? s : 0)->i;
|
||||
int i3 = (i != 0 ? (void*)0 : s)->i;
|
||||
int i4 = (i == 0 ? s : (void*)0)->i;
|
||||
return i1 + i2 + i3 + i4;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -9,6 +48,32 @@ int main()
|
|||
printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3));
|
||||
}
|
||||
|
||||
{
|
||||
int c = 0;
|
||||
#define ASSERT(X) assert(X)
|
||||
static struct stru { int x; } a={'A'},b={'B'};
|
||||
static const struct stru2 { int x; } d = { 'D' };
|
||||
ASSERT('A'==(*(1?&a:&b)).x);
|
||||
ASSERT('A'==(1?a:b).x);
|
||||
ASSERT('A'==(c?b:a).x);
|
||||
ASSERT('A'==(0?b:a).x);
|
||||
c=1;
|
||||
ASSERT('A'==(c?a:b).x);
|
||||
ASSERT(sizeof(int) == sizeof(0 ? 'a' : c));
|
||||
ASSERT(sizeof(double) == sizeof(0 ? 'a' : 1.0));
|
||||
ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 'a'));
|
||||
ASSERT(sizeof(float) == sizeof(0 ? 'a' : 1.0f));
|
||||
ASSERT(sizeof(double) == sizeof(0 ? 0.0 : 1.0f));
|
||||
struct condstruct cs = { 38 };
|
||||
printf("%d\n", getme(&cs, 0));
|
||||
|
||||
// the following lines contain type mismatch errors in every ternary expression
|
||||
//printf("comparing double with pointer : size = %d\n", sizeof(0 ? &c : 0.0));
|
||||
//printf("'%c' <> '%c'\n", (0 ? a : d).x, (1 ? a : d).x);
|
||||
//0 ? a : 0.0;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
33_ternary_op.c:26: warning: pointer/integer mismatch in conditional expression
|
||||
0
|
||||
1
|
||||
4
|
||||
|
@ -8,3 +9,4 @@
|
|||
21
|
||||
24
|
||||
27
|
||||
152
|
||||
|
|
|
@ -456,11 +456,13 @@ char *pmatch(char *line, char *pattern)
|
|||
while (*l && (e = pmatch(l, p)))
|
||||
l = e; /* Get longest match */
|
||||
while (*p++ != ENDPAT); /* Skip over pattern */
|
||||
while (l >= are) { /* Try to match rest */
|
||||
while (l > are) { /* Try to match rest */
|
||||
if (e = pmatch(l, p))
|
||||
return(e);
|
||||
--l; /* Nope, try earlier */
|
||||
}
|
||||
if (e = pmatch(l, p))
|
||||
return(e);
|
||||
return(0); /* Nothing else worked */
|
||||
|
||||
default:
|
||||
|
|
|
@ -48,4 +48,275 @@ enum rgb3 c = 42;
|
|||
#elif defined test_74_non_const_init
|
||||
int i = i++;
|
||||
|
||||
#elif defined test_pointer_assignment
|
||||
|
||||
void (*f1)(void);
|
||||
void f2(void) {}
|
||||
|
||||
struct s1 *ps1;
|
||||
struct s2 *ps2;
|
||||
|
||||
void *v1, **v2, ***v3;
|
||||
|
||||
enum e1 { a = 4 } e10, *e11, *e12;
|
||||
enum e2 { b = -4 } e20, *e21;
|
||||
enum e3 { c = 5000000000LL } e30;
|
||||
|
||||
int *ip;
|
||||
unsigned int *up;
|
||||
long *lp;
|
||||
long long *llp;
|
||||
|
||||
char **c1;
|
||||
char const **c2;
|
||||
unsigned char **u1;
|
||||
|
||||
int no_main ()
|
||||
{
|
||||
// function
|
||||
f1 = f2;
|
||||
// struct
|
||||
ps1 = ps2;
|
||||
// void*
|
||||
v1 = v3;
|
||||
v2 = v3;
|
||||
|
||||
// enum
|
||||
e11 = e12;
|
||||
e11 = e21;
|
||||
e11 = &e10;
|
||||
ip = &e10;
|
||||
ip = &e20;
|
||||
up = &e10;
|
||||
up = &e20;
|
||||
up = &e30;
|
||||
|
||||
lp = ip;
|
||||
lp = llp;
|
||||
|
||||
// constness
|
||||
c1 = c2;
|
||||
*c1 = *c2;
|
||||
**c1 = **c2;
|
||||
|
||||
// unsigned = signed
|
||||
u1 = c2;
|
||||
*u1 = *c2;
|
||||
**u1 = **c2;
|
||||
|
||||
c2 = c1;
|
||||
*c2 = *c1;
|
||||
**c2 = **c1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#elif defined test_enum_compat
|
||||
enum e4;
|
||||
enum e5;
|
||||
void f3(enum e4 e);
|
||||
void f3(enum e5 e);
|
||||
|
||||
#elif defined test_ptr_to_str
|
||||
void f() { _Generic((int const *[]){0}, int:0); }
|
||||
#elif defined test_fnptr_to_str
|
||||
void f() { _Generic((int (*(*)(float,char))(double,int)){0}, int:0); }
|
||||
#elif defined test_array_to_str
|
||||
void f() { _Generic((int(*)[3]){0}, int:0); }
|
||||
#elif defined test_duplicate_def_1
|
||||
static enum myenum { L = -1 } L;
|
||||
#elif defined test_duplicate_def_2
|
||||
void foo(void) {
|
||||
static enum myenum { L = -1 } L;
|
||||
}
|
||||
#elif defined test_abstract_decls
|
||||
int bar(const char *()); // abstract declarator here is okay
|
||||
int bar (const char *(*g)()) // should match this 'g' argument
|
||||
{
|
||||
g();
|
||||
return 42;
|
||||
}
|
||||
int foo(int ()) // abstract decl is wrong in definitions
|
||||
{
|
||||
return 0;
|
||||
#elif defined test_invalid_1
|
||||
void f(char*);
|
||||
void g(void) {
|
||||
f((char[]){1, ,});
|
||||
}
|
||||
#elif defined test_invalid_2
|
||||
int ga = 0.42 { 2 };
|
||||
#elif defined test_invalid_3
|
||||
struct S { int a, b; };
|
||||
struct T { struct S x; };
|
||||
struct T gt = { 42 a: 1, 43 };
|
||||
#elif defined test_invalid_4
|
||||
enum E {
|
||||
x = 1 / 0
|
||||
};
|
||||
#elif defined test_conflicting_types
|
||||
int i;
|
||||
void foo(void) {
|
||||
int i;
|
||||
{
|
||||
extern double i;
|
||||
i = 42.2;
|
||||
}
|
||||
}
|
||||
#elif defined test_nested_types
|
||||
union u {
|
||||
union u {
|
||||
int i;
|
||||
} m;
|
||||
};
|
||||
#elif defined test_vla_1
|
||||
int X=1;
|
||||
|
||||
int main(void) {
|
||||
int t[][][X];
|
||||
}
|
||||
#elif defined test_invalid_alignas
|
||||
/* _Alignas is no type qualifier */
|
||||
void * _Alignas(16) p1;
|
||||
|
||||
#elif defined test_static_assert
|
||||
|
||||
#define ONE 0
|
||||
_Static_assert(ONE == 0, "don't show me this");
|
||||
_Static_assert(ONE == 1, "ONE is not 1");
|
||||
|
||||
#elif defined test_static_assert_2
|
||||
_Static_assert(1, "1"" is 1");
|
||||
_Static_assert(0, "0"" is 0");
|
||||
|
||||
#elif defined test_static_assert_c2x
|
||||
_Static_assert(1);
|
||||
_Static_assert(0);
|
||||
|
||||
#elif defined test_void_array
|
||||
void t[3];
|
||||
|
||||
#elif defined test_incomplete_enum_array
|
||||
enum e t[3];
|
||||
|
||||
#elif defined test_incomplete_struct_array
|
||||
struct s t[3];
|
||||
|
||||
#elif defined test_const_fun_array
|
||||
typedef void f(void);
|
||||
const f t[3];
|
||||
|
||||
#elif defined test_incomplete_array_array
|
||||
int t[][3]; // gr: not an error, see below
|
||||
|
||||
/******************************************************************/
|
||||
#elif defined test_extern_array
|
||||
int iii[] = { 1,2,3 };
|
||||
extern int iii[];
|
||||
int x[];
|
||||
int x[2];
|
||||
int x[];
|
||||
int x[2];
|
||||
int x[];
|
||||
extern int x[2];
|
||||
extern int x[];
|
||||
int x[3];
|
||||
|
||||
/******************************************************************/
|
||||
#elif defined test_func_1 \
|
||||
|| defined test_func_2 \
|
||||
|| defined test_func_3 \
|
||||
|| defined test_func_4 \
|
||||
|| defined test_func_5 \
|
||||
|| defined test_func_6
|
||||
#if defined test_func_1
|
||||
int hello(int);
|
||||
#elif defined test_func_4
|
||||
static int hello(int);
|
||||
#endif
|
||||
int main () {
|
||||
#if defined test_func_6
|
||||
static
|
||||
#endif
|
||||
int hello(int);
|
||||
hello(123);
|
||||
return 0;
|
||||
}
|
||||
int printf(const char*, ...);
|
||||
#if defined test_func_3
|
||||
static int hello(int a)
|
||||
#elif defined test_func_5
|
||||
int hello(int a, int b)
|
||||
#else
|
||||
int hello(int a)
|
||||
#endif
|
||||
{ printf("%s: a = %d\n", __FUNCTION__, a); return 0; }
|
||||
|
||||
/******************************************************************/
|
||||
#elif defined test_var_1 \
|
||||
|| defined test_var_2 \
|
||||
|| defined test_var_3
|
||||
#define P(n,v) printf("%-5s: %d ; %d\n", __FUNCTION__, n, v)
|
||||
#if defined test_var_1
|
||||
int xxx[];
|
||||
#endif
|
||||
int bar();
|
||||
int printf(const char*, ...);
|
||||
int main ()
|
||||
{
|
||||
#if !defined test_var_3
|
||||
int xxx = 2;
|
||||
#endif
|
||||
{
|
||||
extern int xxx[
|
||||
#if defined test_var_3
|
||||
2
|
||||
#endif
|
||||
];
|
||||
P(1, xxx[0]);
|
||||
xxx[0] += 2;
|
||||
}
|
||||
#if !defined test_var_3
|
||||
P(2, xxx);
|
||||
#endif
|
||||
bar(123);
|
||||
return 0;
|
||||
}
|
||||
int xxx[1] = {1};
|
||||
int bar() { P(3, xxx[0]); return 0; }
|
||||
|
||||
#elif defined test_var_4
|
||||
struct yyy { int y; };
|
||||
struct zzz;
|
||||
void f1() {
|
||||
extern char *x;
|
||||
extern char **xx;
|
||||
extern struct yyy y;
|
||||
extern struct yyy *yy;
|
||||
extern struct zzz z;
|
||||
extern struct zzz *zz;
|
||||
}
|
||||
void f2() {
|
||||
extern char *x;
|
||||
extern char **xx;
|
||||
extern struct yyy y;
|
||||
extern struct yyy *yy;
|
||||
extern struct zzz z;
|
||||
extern struct zzz *zz;
|
||||
}
|
||||
struct yyy y, *yy;
|
||||
struct zzz { int z; } z, *zz;
|
||||
|
||||
/******************************************************************/
|
||||
#elif defined test_long_double_type_for_win32
|
||||
|
||||
int main()
|
||||
{
|
||||
double *a = 0;
|
||||
long double *b = a;
|
||||
int n = _Generic(*a, double:0, long double:1);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
#endif
|
||||
|
|
|
@ -20,9 +20,133 @@
|
|||
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
|
||||
|
||||
[test_63_local_enumerator_redefinition]
|
||||
[returns 1]
|
||||
|
||||
[test_61_undefined_enum]
|
||||
60_errors_and_warnings.c:46: error: unknown type size
|
||||
|
||||
[test_74_non_const_init]
|
||||
60_errors_and_warnings.c:49: error: initializer element is not constant
|
||||
|
||||
[test_pointer_assignment]
|
||||
60_errors_and_warnings.c:79: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:82: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:86: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:88: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:91: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:92: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:94: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:95: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:98: warning: assignment discards qualifiers from pointer target type
|
||||
60_errors_and_warnings.c:99: warning: assignment discards qualifiers from pointer target type
|
||||
60_errors_and_warnings.c:103: warning: assignment discards qualifiers from pointer target type
|
||||
60_errors_and_warnings.c:104: warning: assignment discards qualifiers from pointer target type
|
||||
60_errors_and_warnings.c:109: warning: assignment of read-only location
|
||||
|
||||
[test_enum_compat]
|
||||
60_errors_and_warnings.c:119: error: incompatible types for redefinition of 'f3'
|
||||
|
||||
[test_ptr_to_str]
|
||||
60_errors_and_warnings.c:122: error: type 'const int **' does not match any association
|
||||
|
||||
[test_fnptr_to_str]
|
||||
60_errors_and_warnings.c:124: error: type 'int (*(*)(float, char))(double, int)' does not match any association
|
||||
|
||||
[test_array_to_str]
|
||||
60_errors_and_warnings.c:126: error: type 'int (*)[3]' does not match any association
|
||||
|
||||
[test_duplicate_def_1]
|
||||
60_errors_and_warnings.c:128: error: redefinition of 'L'
|
||||
|
||||
[test_duplicate_def_2]
|
||||
60_errors_and_warnings.c:131: error: redeclaration of 'L'
|
||||
|
||||
[test_abstract_decls]
|
||||
60_errors_and_warnings.c:141: error: identifier expected
|
||||
|
||||
[test_invalid_1]
|
||||
60_errors_and_warnings.c:146: error: identifier expected
|
||||
|
||||
[test_invalid_2]
|
||||
60_errors_and_warnings.c:149: error: ';' expected (got "{")
|
||||
|
||||
[test_invalid_3]
|
||||
60_errors_and_warnings.c:153: error: ',' expected (got "a")
|
||||
|
||||
[test_invalid_4]
|
||||
60_errors_and_warnings.c:157: error: division by zero in constant
|
||||
|
||||
[test_conflicting_types]
|
||||
60_errors_and_warnings.c:163: error: incompatible types for redefinition of 'i'
|
||||
|
||||
[test_nested_types]
|
||||
60_errors_and_warnings.c:170: error: struct/union/enum already defined
|
||||
|
||||
[test_vla_1]
|
||||
60_errors_and_warnings.c:177: error: need explicit inner array size in VLAs
|
||||
|
||||
[test_invalid_alignas]
|
||||
60_errors_and_warnings.c:181: error: identifier expected
|
||||
|
||||
[test_static_assert]
|
||||
60_errors_and_warnings.c:187: error: ONE is not 1
|
||||
|
||||
[test_static_assert_2]
|
||||
60_errors_and_warnings.c:191: error: 0 is 0
|
||||
|
||||
[test_static_assert_c2x]
|
||||
60_errors_and_warnings.c:195: error: _Static_assert fail
|
||||
|
||||
[test_void_array]
|
||||
60_errors_and_warnings.c:198: error: declaration of an array of incomplete type elements
|
||||
|
||||
[test_incomplete_enum_array]
|
||||
60_errors_and_warnings.c:201: error: declaration of an array of incomplete type elements
|
||||
|
||||
[test_incomplete_struct_array]
|
||||
60_errors_and_warnings.c:204: error: declaration of an array of incomplete type elements
|
||||
|
||||
[test_const_fun_array]
|
||||
60_errors_and_warnings.c:208: error: declaration of an array of functions
|
||||
|
||||
[test_incomplete_array_array]
|
||||
|
||||
[test_extern_array]
|
||||
60_errors_and_warnings.c:224: error: incompatible types for redefinition of 'x'
|
||||
|
||||
[test_func_1]
|
||||
hello: a = 123
|
||||
|
||||
[test_func_2]
|
||||
hello: a = 123
|
||||
|
||||
[test_func_3]
|
||||
60_errors_and_warnings.c:254: warning: static storage ignored for redefinition of 'hello'
|
||||
hello: a = 123
|
||||
|
||||
[test_func_4]
|
||||
hello: a = 123
|
||||
|
||||
[test_func_5]
|
||||
60_errors_and_warnings.c:254: error: incompatible types for redefinition of 'hello'
|
||||
|
||||
[test_func_6]
|
||||
60_errors_and_warnings.c:242: error: function without file scope cannot be static
|
||||
|
||||
[test_var_1]
|
||||
main : 1 ; 1
|
||||
main : 2 ; 2
|
||||
bar : 3 ; 3
|
||||
|
||||
[test_var_2]
|
||||
main : 1 ; 1
|
||||
main : 2 ; 2
|
||||
bar : 3 ; 3
|
||||
|
||||
[test_var_3]
|
||||
60_errors_and_warnings.c:286: error: incompatible types for redefinition of 'xxx'
|
||||
|
||||
[test_var_4]
|
||||
|
||||
[test_long_double_type_for_win32]
|
||||
60_errors_and_warnings.c:317: warning: assignment from incompatible pointer type
|
||||
|
|
|
@ -230,6 +230,17 @@ void ret(void)
|
|||
printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
|
||||
}
|
||||
|
||||
void*
|
||||
va_arg_with_struct_ptr(va_list ap) {
|
||||
/*
|
||||
* This was a BUG identified with FFTW-3.3.8 on arm64.
|
||||
* The test case only checks it compiles.
|
||||
*/
|
||||
struct X { int _x; };
|
||||
struct X *x = va_arg(ap, struct X *);
|
||||
return x;
|
||||
}
|
||||
|
||||
int match(const char **s, const char *f)
|
||||
{
|
||||
const char *p = *s;
|
||||
|
|
|
@ -39,5 +39,17 @@ int f5 (fptr5 fp, fptr1 i)
|
|||
{
|
||||
return fp(i);
|
||||
}
|
||||
typedef int intx4[4];
|
||||
int f8 (intx4, int);
|
||||
int f8 (int ([4]), int);
|
||||
int f8 (int y[4], int i)
|
||||
{
|
||||
return y[i];
|
||||
}
|
||||
int f9 (int (*)(int), int);
|
||||
int f9 (int ((int)), int);
|
||||
int f9 (int f(int), int i)
|
||||
{
|
||||
return f(i);
|
||||
}
|
||||
int main () { return 0; }
|
||||
|
|
|
@ -16,4 +16,50 @@ void __attribute__((stdcall)) foo (void)
|
|||
{
|
||||
}
|
||||
|
||||
int main () { return 0; }
|
||||
#define __stdcall __attribute__((stdcall))
|
||||
extern int some_stdcall_func (int, int, int) __stdcall;
|
||||
__stdcall int __stdcall some_stdcall_func(int foo, int bar, int baz) {
|
||||
//printf("Hello from stdcall: %i %i %i\n", foo, bar, baz);
|
||||
return 43;
|
||||
}
|
||||
|
||||
/* The actual attribute isn't important, must just be
|
||||
parsable. */
|
||||
#define ATTR __attribute__((__noinline__))
|
||||
int ATTR actual_function() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
extern int printf (const char *, ...);
|
||||
static int globalvar;
|
||||
int main()
|
||||
{
|
||||
void *function_pointer = &actual_function;
|
||||
int localvar = 42, i;
|
||||
|
||||
int a = ((ATTR int(*) (void)) function_pointer)();
|
||||
printf("%i\n", a);
|
||||
|
||||
/* In the following we once misparsed 'ATTR *' is a btype
|
||||
and hence the whole type was garbled. */
|
||||
int b = ( (int(ATTR *)(void)) function_pointer)();
|
||||
printf("%i\n", b);
|
||||
|
||||
/* All these should work and leave the stack pointer in its original
|
||||
position. */
|
||||
some_stdcall_func(1, 10, 100);
|
||||
((int __stdcall (*)(int, int, int))some_stdcall_func) (2, 20, 200);
|
||||
((int(*__stdcall)(int, int, int))some_stdcall_func) (3, 30, 300);
|
||||
for (i = 0; i < 1024; i++) {
|
||||
globalvar = i;
|
||||
/* This was once misparsed at <= gitrev 325241c0, forgetting
|
||||
the stdcall attribute on the function pointer leading to
|
||||
stack increment being done twice (in callee and caller).
|
||||
This will clobber 'i' and 'localvar' which is how we detect
|
||||
this. */
|
||||
((int(__stdcall*)(int, int, int))some_stdcall_func) (4, 40, 400);
|
||||
if (localvar != 42 || globalvar != i)
|
||||
printf("error, localvar=%d i=%d globalvar=%d\n", localvar, i, globalvar);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
42
|
||||
42
|
|
@ -26,6 +26,36 @@ static void kb_wait_1(void)
|
|||
timeout--;
|
||||
} while (timeout);
|
||||
}
|
||||
|
||||
static int global;
|
||||
|
||||
static void foo(int i)
|
||||
{
|
||||
global+=i;
|
||||
printf ("g=%d\n", global);
|
||||
}
|
||||
|
||||
static int check(void)
|
||||
{
|
||||
printf ("check %d\n", global);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dowhile(void)
|
||||
{
|
||||
do {
|
||||
foo(1);
|
||||
if (global == 1) {
|
||||
continue;
|
||||
} else if (global == 2) {
|
||||
continue;
|
||||
}
|
||||
/* The following break shouldn't disable the check() call,
|
||||
as it's reachable by the continues above. */
|
||||
break;
|
||||
} while (check());
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
int i = 1;
|
||||
|
@ -118,5 +148,8 @@ enterloop3:
|
|||
printf ("error4\n");
|
||||
}
|
||||
}
|
||||
|
||||
dowhile();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue