Compare commits
127 Commits
20b1a1d001
...
cb08f119ca
Author | SHA1 | Date |
---|---|---|
Jan Nieuwenhuizen | cb08f119ca | |
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 | |
grischka | d348a9a51d | |
grischka | 1a4d4b76e8 | |
Michael Matz | 8490c54dbd | |
grischka | 3ae1a2af1c | |
grischka | 877e164d6a | |
Michael Matz | cc6cb7f0e2 | |
Michael Matz | 529b44c0d5 | |
Michael Matz | 9e0d23cc47 | |
Michael Matz | 3494e5de3a | |
Michael Matz | 4266ebd69c | |
Michael Matz | e7c71e2473 | |
Michael Matz | 330c01bfc6 | |
Michael Matz | d0db21757a | |
Michael Matz | a8ece0f2ce | |
Michael Matz | 348dd9f4a6 | |
Michael Matz | 74463eb954 | |
janus.lt | 32c9b51401 | |
emekoi | fc0188ffbc | |
grischka | da8c62f75d | |
YX Hao | faa9744f5d | |
Steffen Nurpmeso | 6f1860e200 | |
Steffen Nurpmeso | 1d5e386b0a | |
Steffen Nurpmeso | a1c9051313 | |
Christian Jullien | 2e5751caf1 | |
Larry Doolittle | 8deb05c3e2 | |
Avi Halachmi (:avih) | abd1532ad4 | |
Larry Doolittle | 560188711d | |
Larry Doolittle | 1b6806e5bb | |
Larry Doolittle | 44d4da62bb | |
grischka | 1443039416 | |
Zdenek Pavlas | 870271ea07 | |
Zhang Boyang | 078d8c2c5a | |
Zhang Boyang | f406f63a38 | |
Zhang Boyang | 978d1ecce0 | |
Zhang Boyang | b39810ff78 | |
Zhang Boyang | 02370acdc9 | |
Zhang Boyang | a82c11f4b4 | |
Zhang Boyang | b8fe8fc210 | |
Edmund Grimley Evans | ac41e015f1 | |
Matthias Gatto | 4f15d08ea1 | |
matthias | c18fc950d7 | |
Christian Jullien | 023d4e0b59 | |
Christian Jullien | 421a1c48bb | |
Matthias Gatto | 52622c3c03 | |
Matthias Gatto | 23064b1734 | |
Matthias Gatto | a4cd2805f9 | |
Christian Jullien | 8258abeb80 | |
Matthias Gatto | 28b7c9b34e | |
Matthias Gatto | b72cddaa6e | |
grischka | 4b3c6e74ab | |
matthias | fdc18d307a | |
grischka | 0cc24d0e84 | |
Matthias Gatto | ba2b25e4ea | |
matthias | 2821644553 | |
Matthias Gatto | 2020a312ca | |
Michael Matz | 3f13e33872 | |
grischka | 7f1ab9b1e1 | |
grischka | 69a137ff88 | |
Michael Matz | 04418c7add | |
Michael Matz | 2acb04f7f2 | |
Michael Matz | 9bea88d616 | |
Michael Matz | 2240422da9 | |
grischka | a9e502cc3b | |
grischka | f87afa72e0 | |
grischka | 9ba76ac834 | |
grischka | 9f79b62ec4 | |
grischka | 6c468c10f7 | |
Michael Matz | 824dcebe59 | |
Michael Matz | 1f3d3957c4 | |
Michael Matz | d8fdd380f3 | |
Matthias Gatto | 16d3dbf2d0 | |
Matthias Gatto | 157bad52cd | |
Michael Matz | 9ed8b54f6c | |
Michael Matz | 580ad5f24c | |
Michael Matz | 27ca303874 | |
Michael Matz | d4fe9aba3f | |
Christian Jullien | b68df809eb | |
Christian Jullien | 6d559d651f | |
Emil | 3e028af453 | |
U-NELSON\jullien | 3e4b7693bf | |
U-NELSON\jullien | 2a348896dd | |
Christian Jullien | 0cc4e570bc | |
Michael Matz | 31e5ad789a | |
Michael Matz | 7cd1ae7710 | |
Michael Matz | 53c5fc2246 |
|
@ -41,16 +41,17 @@ win32/include/stddef.h
|
|||
win32/include/varargs.h
|
||||
win32/include/tcclib.h
|
||||
|
||||
tests/test.out*
|
||||
tests/test*.out
|
||||
tests/tcctest[1234]
|
||||
tests/tcctest.gcc
|
||||
tests/*.out*
|
||||
tests/*.ref
|
||||
tests/*.txt
|
||||
tests/*.gcc
|
||||
tests/*-cc*
|
||||
tests/*-tcc*
|
||||
tests/libtcc_test
|
||||
tests/asm-c-connect
|
||||
tests/asm-c-connect-sep
|
||||
tests/vla_test
|
||||
tests/hello
|
||||
tests/tests2/fred.txt
|
||||
|
|
|
@ -9,11 +9,10 @@ User interface:
|
|||
- -mno-sse on x86-64 disables use of SSE instructions
|
||||
- @listfile support (Vlad Vissoultchev)
|
||||
- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
|
||||
- CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support
|
||||
- CPATH, C_INCLUDE_PATH and LIBRARY_PATH environment variables support
|
||||
(Andrew Aladjev, Urs Janssen)
|
||||
|
||||
Platforms:
|
||||
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
|
||||
- new AARCH64 (arm64) target (Edmund Grimley Evans)
|
||||
- vastly improved support for ARM hard float calling convention
|
||||
(Thomas Preud'homme, Daniel Glöckner)
|
||||
|
@ -22,6 +21,7 @@ Platforms:
|
|||
- ABI tests with native compiler using libtcc (James Lyon)
|
||||
- UNICODE startup code supports wmain and wWinMain (YX Hao)
|
||||
- shared libraries for x86_64 (Michael Matz)
|
||||
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
|
||||
|
||||
Features:
|
||||
- VLA (variable length array) improved (James Lyon, Pip Cet)
|
||||
|
@ -35,6 +35,8 @@ Features:
|
|||
- standard conforming (and GCC compatible) struct initialization
|
||||
(Michael Matz)
|
||||
- bit-field layout made compatible with GCC (Michael Matz)
|
||||
- UTF8 in string literals supported (Zdenek Pavlas)
|
||||
_ _Generic(...) supported (Matthias Gatto)
|
||||
|
||||
Licensing:
|
||||
- TinyCC partly relicensed to MIT license (See RELICENSING file).
|
||||
|
|
178
Makefile
178
Makefile
|
@ -98,16 +98,17 @@ TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
|
|||
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
|
||||
|
||||
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
|
||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),libtcc1-$X.a)
|
||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
|
||||
|
||||
# build cross compilers & libs
|
||||
cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
|
||||
|
||||
# build specific cross compiler & lib
|
||||
cross-%: %-tcc$(EXESUF) libtcc1-%.a ;
|
||||
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
|
||||
|
||||
install: install$(CFGWIN)
|
||||
uninstall: uninstall$(CFGWIN)
|
||||
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
|
||||
all : cross
|
||||
|
@ -143,16 +144,16 @@ DEFINES += $(DEF-$(or $(findstring win,$T),unx))
|
|||
|
||||
ifneq ($(X),)
|
||||
ifeq ($(CONFIG_WIN32),yes)
|
||||
DEF-win += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
|
||||
DEF-unx += -DTCC_LIBTCC1="\"lib/libtcc1-$T.a\""
|
||||
DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
|
||||
DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\""
|
||||
else
|
||||
DEF-all += -DTCC_LIBTCC1="\"libtcc1-$T.a\""
|
||||
DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
|
||||
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
|
||||
endif
|
||||
endif
|
||||
|
||||
# include custom cross-compiler configuration (see make help)
|
||||
-include config-cross.mak
|
||||
# include custom configuration (see make help)
|
||||
-include config-extra.mak
|
||||
|
||||
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
|
||||
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
|
||||
|
@ -173,11 +174,12 @@ ifeq ($(ONE_SOURCE),yes)
|
|||
LIBTCC_OBJ = $(X)libtcc.o
|
||||
LIBTCC_INC = $($T_FILES)
|
||||
TCC_FILES = $(X)tcc.o
|
||||
$(X)libtcc.o $T-tcc$(EXESUF) : DEFINES += -DONE_SOURCE
|
||||
tcc.o : DEFINES += -DONE_SOURCE=0
|
||||
else
|
||||
LIBTCC_OBJ = $(patsubst %.c,$(X)%.o,$(LIBTCC_SRC))
|
||||
LIBTCC_INC = $(filter %.h %-gen.c %-link.c,$($T_FILES))
|
||||
TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
|
||||
$(TCC_FILES) : DEFINES += -DONE_SOURCE=0
|
||||
endif
|
||||
|
||||
# target specific object rule
|
||||
|
@ -200,7 +202,7 @@ $(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
|
|||
|
||||
# profiling version
|
||||
tcc_p$(EXESUF): $($T_FILES)
|
||||
$(CC) -o $@ $< $(DEFINES) -DONE_SOURCE $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
||||
$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
||||
|
||||
# static libtcc library
|
||||
libtcc.a: $(LIBTCC_OBJ)
|
||||
|
@ -216,34 +218,36 @@ libtcc.so: LDFLAGS+=-fPIC
|
|||
# windows dynamic libtcc library
|
||||
libtcc.dll : $(LIBTCC_OBJ)
|
||||
$(CC) -shared -o $@ $^ $(LDFLAGS)
|
||||
|
||||
libtcc.def : libtcc.dll tcc$(EXESUF)
|
||||
./tcc$(EXESUF) -impdef $< -o $@
|
||||
|
||||
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
|
||||
|
||||
# import file for windows libtcc.dll
|
||||
libtcc.def : libtcc.dll tcc$(EXESUF)
|
||||
$(XTCC) -impdef $< -o $@
|
||||
XTCC ?= ./tcc$(EXESUF)
|
||||
|
||||
# TinyCC runtime libraries
|
||||
libtcc1.a : tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -C lib DEFINES="$(DEF-$T)"
|
||||
@$(MAKE) -C lib DEFINES='$(DEF-$T)'
|
||||
|
||||
# Cross libtcc1.a
|
||||
libtcc1-%.a : %-tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -C lib DEFINES="$(DEF-$*)" CROSS_TARGET=$*
|
||||
%-libtcc1.a : %-tcc$(EXESUF) FORCE
|
||||
@$(MAKE) -C lib DEFINES='$(DEF-$*)' CROSS_TARGET=$*
|
||||
|
||||
.PRECIOUS: libtcc1-%.a
|
||||
.PRECIOUS: %-libtcc1.a
|
||||
FORCE:
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# documentation and man page
|
||||
tcc-doc.html: tcc-doc.texi
|
||||
-makeinfo --no-split --html --number-sections -o $@ $<
|
||||
makeinfo --no-split --html --number-sections -o $@ $< || true
|
||||
|
||||
tcc.1: tcc-doc.texi
|
||||
-$(TOPSRC)/texi2pod.pl $< tcc.pod
|
||||
-pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod > $@
|
||||
$(TOPSRC)/texi2pod.pl $< tcc.pod \
|
||||
&& pod2man --section=1 --center="Tiny C Compiler" --release="$(VERSION)" tcc.pod >tmp.1 \
|
||||
&& mv tmp.1 $@ || rm -f tmp.1
|
||||
|
||||
tcc-doc.info: tcc-doc.texi
|
||||
-makeinfo $<
|
||||
makeinfo $< || true
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# install
|
||||
|
@ -251,35 +255,29 @@ tcc-doc.info: tcc-doc.texi
|
|||
INSTALL = install -m644
|
||||
INSTALLBIN = install -m755 $(STRIP_$(CONFIG_strip))
|
||||
STRIP_yes = -s
|
||||
install-strip: install
|
||||
install-strip: CONFIG_strip = yes
|
||||
|
||||
TRY-INSTALL = $(if $(wildcard $1),mkdir -p $2 && $(INSTALL) $1 $2)
|
||||
LIBTCC1_W = $(wildcard $(filter %-win32.a %-wince.a,$(LIBTCC1_CROSS)))
|
||||
LIBTCC1_U = $(wildcard $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS)))
|
||||
PROGS_X = $(wildcard $(PROGS_CROSS))
|
||||
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
|
||||
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS))
|
||||
IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2)
|
||||
IBw = $(call IB,$(wildcard $1),$2)
|
||||
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
|
||||
IFw = $(call IF,$(wildcard $1),$2)
|
||||
IR = mkdir -p $2 && cp -r $1/. $2
|
||||
|
||||
# install progs & libs
|
||||
install-unx:
|
||||
mkdir -p "$(bindir)"
|
||||
$(INSTALLBIN) $(PROGS) $(PROGS_X) "$(bindir)"
|
||||
mkdir -p "$(tccdir)"
|
||||
$(INSTALL) $(LIBTCC1) $(LIBTCC1_U) "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
|
||||
mkdir -p "$(libdir)"
|
||||
$(INSTALL) $(LIBTCC) "$(libdir)"
|
||||
mkdir -p "$(includedir)"
|
||||
$(INSTALL) $(TOPSRC)/libtcc.h "$(includedir)"
|
||||
$(call TRY-INSTALL,tcc.1,"$(mandir)/man1")
|
||||
$(call TRY-INSTALL,tcc-doc.info,"$(infodir)")
|
||||
$(call TRY-INSTALL,tcc-doc.html,"$(docdir)")
|
||||
ifneq "$(LIBTCC1_W)" ""
|
||||
mkdir -p "$(tccdir)/win32/lib"
|
||||
$(INSTALL) $(TOPSRC)/win32/lib/*.def $(LIBTCC1_W) "$(tccdir)/win32/lib"
|
||||
mkdir -p "$(tccdir)/win32/include"
|
||||
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/win32/include"
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/win32/include"
|
||||
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
|
||||
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
|
||||
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
|
||||
$(call IFw,tcc.1,"$(mandir)/man1")
|
||||
$(call IFw,tcc-doc.info,"$(infodir)")
|
||||
$(call IFw,tcc-doc.html,"$(docdir)")
|
||||
ifneq "$(wildcard $(LIBTCC1_W))" ""
|
||||
$(call IFw,$(TOPSRC)/win32/lib/*.def $(LIBTCC1_W),"$(tccdir)/win32/lib")
|
||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/win32/include")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/win32/include")
|
||||
endif
|
||||
|
||||
# uninstall
|
||||
|
@ -292,33 +290,32 @@ uninstall-unx:
|
|||
|
||||
# install progs & libs on windows
|
||||
install-win:
|
||||
mkdir -p "$(tccdir)"
|
||||
$(INSTALL) $(PROGS) $(subst libtcc.a,,$(LIBTCC)) $(PROGS_X) "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/lib"
|
||||
$(INSTALL) $(TOPSRC)/win32/lib/*.def "$(tccdir)/lib"
|
||||
$(INSTALL) libtcc1.a $(LIBTCC1_W) "$(tccdir)/lib"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
cp -r $(TOPSRC)/win32/include/. "$(tccdir)/include"
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/include"
|
||||
mkdir -p "$(tccdir)/examples"
|
||||
cp -r $(TOPSRC)/win32/examples/. "$(tccdir)/examples"
|
||||
$(INSTALL) $(TOPSRC)/tests/libtcc_test.c "$(tccdir)/examples"
|
||||
mkdir -p "$(tccdir)/libtcc"
|
||||
$(INSTALL) $(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)) "$(tccdir)/libtcc"
|
||||
mkdir -p "$(tccdir)/doc"
|
||||
$(INSTALL) $(TOPSRC)/win32/tcc-win32.txt $(wildcard tcc-doc.html) "$(tccdir)/doc"
|
||||
ifneq "$(LIBTCC1_U)" ""
|
||||
$(INSTALL) $(LIBTCC1_U) "$(tccdir)/lib"
|
||||
mkdir -p "$(tccdir)/lib/include";
|
||||
$(INSTALL) $(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h "$(tccdir)/lib/include"
|
||||
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
|
||||
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
|
||||
$(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
||||
$(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
|
||||
$(call IFw,$(TOPSRC)/libtcc.h $(subst .dll,.def,$(LIBTCC)),"$(libdir)")
|
||||
$(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
|
||||
ifneq "$(wildcard $(LIBTCC1_U))" ""
|
||||
$(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/lib/include")
|
||||
endif
|
||||
|
||||
# the msys-git shell works to configure && make except it does not have install
|
||||
ifeq "$(and $(CONFIG_WIN32),$(shell which install >/dev/null 2>&1 || echo no))" "no"
|
||||
install-win : INSTALL = cp
|
||||
install-win : INSTALLBIN = cp
|
||||
endif
|
||||
|
||||
# uninstall on windows
|
||||
uninstall-win:
|
||||
rm -r "$(tccdir)/"*
|
||||
@rm -fv $(foreach P,$(PROGS) $(PROGS_CROSS) libtcc.dll,"$(bindir)/$P")
|
||||
@rm -fv $(foreach F,tcc-doc.html tcc-win32.txt,"$(docdir)/$F")
|
||||
@rm -fv $(foreach F,libtcc.h libtcc.def libtcc.a,"$(libdir)/$F")
|
||||
rm -r "$(tccdir)"
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# other stuff
|
||||
|
@ -345,15 +342,21 @@ tar: tcc-doc.html
|
|||
config.mak:
|
||||
$(if $(wildcard $@),,@echo "Please run ./configure." && exit 1)
|
||||
|
||||
# in tests subdir
|
||||
# run all tests
|
||||
test:
|
||||
$(MAKE) -C tests
|
||||
# run test(s) from tests2 subdir (see make help)
|
||||
tests2.%:
|
||||
$(MAKE) -C tests/tests2 $@
|
||||
|
||||
testspp.%:
|
||||
$(MAKE) -C tests/pp $@
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) $(PROGS_CROSS) tcc_p$(EXESUF) tcc.pod
|
||||
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 tests $@
|
||||
@$(MAKE) -C lib $@
|
||||
@$(MAKE) -C tests $@
|
||||
|
||||
distclean: clean
|
||||
rm -f config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html
|
||||
|
@ -374,19 +377,32 @@ help:
|
|||
@echo " build one specific cross compiler for 'TARGET', as in"
|
||||
@echo " $(TCC_X)"
|
||||
@echo ""
|
||||
@echo "Cross compiler configuration:"
|
||||
@echo " make will read custom configuration for cross compilers from a file"
|
||||
@echo " 'config-cross.mak' if present. For example for a windows->i386-linux"
|
||||
@echo " cross-compiler that expects the linux files in <tccdir>/i386-linux:"
|
||||
@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 " 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 " NATIVE_DEFINES += -D..."
|
||||
@echo ""
|
||||
@echo " Or for example to configure the search paths for a cross-compiler"
|
||||
@echo " that expects the linux files in <tccdir>/i386-linux:"
|
||||
@echo ""
|
||||
@echo " ROOT-i386 = {B}/i386-linux"
|
||||
@echo " CRT-i386 = {B}/i386-linux/usr/lib"
|
||||
@echo " LIB-i386 = {B}/i386-linux/lib:{B}/i386-linux/usr/lib"
|
||||
@echo " INC-i386 = {B}/lib/include:{B}/i386-linux/usr/include"
|
||||
@echo " DEF-i386 += -D__linux__"
|
||||
@echo ""
|
||||
@echo "make test"
|
||||
@echo " run all tests"
|
||||
@echo ""
|
||||
@echo "make tests2.all / make tests2.37 / make tests2.37+"
|
||||
@echo " run all/single test(s) from tests2, optionally update .expect"
|
||||
@echo "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 test tags ETAGS tar clean distclean help"
|
||||
@echo " install install-strip tags ETAGS tar clean distclean help"
|
||||
@echo ""
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
endif # ($(INCLUDED),no)
|
||||
|
|
67
README
67
README
|
@ -1,3 +1,70 @@
|
|||
Bootstrappable TCC/TinyCC -- Tiny C Compiler's bootstrappable fork
|
||||
------------------------------------------------------------------
|
||||
|
||||
Bootstrappable TCC is a fork from mainline TCC development, that
|
||||
started spring 2017 from
|
||||
|
||||
commit 307b7b183d4ee56e74090b0e525d6a587840e31f
|
||||
Author: Aron BARATH <baratharon@caesar.elte.hu>
|
||||
Date: Tue May 16 07:03:26 2017 +0200
|
||||
|
||||
the R_X86_64_GOTOFF64 relocation was missing
|
||||
|
||||
and can be compiled by MesCC (https://gnu.org/s/mes).
|
||||
|
||||
Initially the plan was to make TinyCC itself "bootstrappable"
|
||||
(https://bootstrappable.org).
|
||||
|
||||
The best way to do so would be to gradually simplify the
|
||||
implementation of TinyCC by restricting the use of language constructs
|
||||
to a well-defined subset of C. In bootstrapping each stage or
|
||||
compiler adds functionality; a compiler that is written in itself --a
|
||||
so-called `self-hosting' compiler--is not considered to be
|
||||
bootstrappable.
|
||||
|
||||
At the time this vision was not received with much enthousiasm
|
||||
|
||||
https://lists.nongnu.org/archive/html/tinycc-devel/2017-09/msg00019.html
|
||||
|
||||
so I decided to fork TinyCC and instead grow MesCC (a bootstrappable
|
||||
sub-C compiler in a subset of Guile Scheme) into a full C99 compiler.
|
||||
|
||||
Currently, the Reduced Binary Seed Bootstrap of the GNU Guix System
|
||||
(https://guix.gnu.org/blog/2019/guix-reduces-bootstrap-seed-by-50/)
|
||||
uses bootstrappable-tinycc.
|
||||
|
||||
The fork consists of about 12 patches
|
||||
|
||||
cee58e0 build: Support building from bootstrap-mes.
|
||||
39de356 bootstrappable: Force static link.
|
||||
2b6271d bootstrappable: Work around MesCC bug.
|
||||
379c62d bootstrappable: add tcc.h include guards to include location.
|
||||
274bd06 bootstrappable: Handle libtcc1.a.
|
||||
6ae9aa4 bootstrappable: Skip tidy_section_headers.
|
||||
a130ce1 bootstrappable: HAVE_FLOAT.
|
||||
de906df bootstrappable: HAVE_BITFIELD.
|
||||
540ba0b bootstrappable: HAVE_LONG_LONG.
|
||||
306f677 bootstrappable: Work around Nyacc-0.80.42 bug.
|
||||
9c97705 build: bootstrap build scripts.
|
||||
584478f bootstrappable: Remove non-free grep test.
|
||||
|
||||
that work around bugs and missing C language features in MesCC. Only
|
||||
three of these are really interesting: the HAVE_* patches that allow
|
||||
for stepwise introduction of bitfields, doubles/floats and long longs.
|
||||
|
||||
In time, I hope we can remove the need for this fork; either by
|
||||
upstreaming some bootstrappable work or else by maturing MesCC.
|
||||
|
||||
At the time of writing, mainline (non-bootstrappable) tinycc lives
|
||||
here
|
||||
|
||||
https://repo.or.cz/tinycc.git
|
||||
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
|
||||
|
||||
--
|
||||
janneke
|
||||
|
||||
|
||||
Tiny C Compiler - C Scripting Everywhere - The Smallest ANSI C compiler
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
|||
uint8_t *clobber_regs,
|
||||
int out_reg)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
||||
|
@ -78,7 +77,6 @@ ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
|||
const uint8_t *clobber_regs,
|
||||
int *pout_reg)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
||||
|
|
16
arm-gen.c
16
arm-gen.c
|
@ -1221,7 +1221,7 @@ void gfunc_call(int nb_args)
|
|||
int variadic;
|
||||
|
||||
if (float_abi == ARM_HARD_FLOAT) {
|
||||
variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
|
||||
variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS);
|
||||
if (variadic || floats_in_core_regs(&vtop[-nb_args]))
|
||||
float_abi = ARM_SOFTFP_FLOAT;
|
||||
}
|
||||
|
@ -1279,7 +1279,7 @@ void gfunc_prolog(CType *func_type)
|
|||
|
||||
sym = func_type->ref;
|
||||
func_vt = sym->type;
|
||||
func_var = (func_type->ref->c == FUNC_ELLIPSIS);
|
||||
func_var = (func_type->ref->f.func_type == FUNC_ELLIPSIS);
|
||||
|
||||
n = nf = 0;
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
|
||||
|
@ -1410,6 +1410,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) {
|
||||
o(0xE1A00000);
|
||||
bytes -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a jump to a label */
|
||||
int gjmp(int t)
|
||||
{
|
||||
|
@ -1783,7 +1793,7 @@ static uint32_t is_fconst()
|
|||
}
|
||||
|
||||
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
||||
two operands are guaranted to have the same floating point type */
|
||||
two operands are guaranteed to have the same floating point type */
|
||||
void gen_opf(int op)
|
||||
{
|
||||
uint32_t x, r, r2, c1, c2;
|
||||
|
|
|
@ -382,6 +382,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
/* Nothing to do. Normally used to indicate a dependency
|
||||
on a certain symbol (like for exception handling under EABI). */
|
||||
return;
|
||||
case R_ARM_RELATIVE:
|
||||
#ifdef TCC_TARGET_PE
|
||||
add32le(ptr, val - s1->pe_imagebase);
|
||||
#endif
|
||||
/* do nothing */
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
|
|
17
arm64-gen.c
17
arm64-gen.c
|
@ -249,7 +249,6 @@ static int arm64_type_size(int t)
|
|||
case VT_BYTE: return 0;
|
||||
case VT_SHORT: return 1;
|
||||
case VT_PTR: return 3;
|
||||
case VT_ENUM: return 2;
|
||||
case VT_FUNC: return 3;
|
||||
case VT_FLOAT: return 2;
|
||||
case VT_DOUBLE: return 3;
|
||||
|
@ -428,7 +427,7 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend)
|
|||
// relocation and use only relocations with unlimited range.
|
||||
int avoid_adrp = 1;
|
||||
|
||||
if (avoid_adrp || (sym->type.t & VT_WEAK)) {
|
||||
if (avoid_adrp || sym->a.weak) {
|
||||
// (GCC uses a R_AARCH64_ABS64 in this case.)
|
||||
greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G0_NC, addend);
|
||||
o(0xd2800000 | r); // mov x(rt),#0,lsl #0
|
||||
|
@ -581,8 +580,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 .
|
||||
}
|
||||
|
@ -1277,6 +1276,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)
|
||||
{
|
||||
|
|
|
@ -240,6 +240,12 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
#endif
|
||||
write64le(ptr, val - rel->r_addend);
|
||||
return;
|
||||
case R_AARCH64_RELATIVE:
|
||||
#ifdef TCC_TARGET_PE
|
||||
add32le(ptr, val - s1->pe_imagebase);
|
||||
#endif
|
||||
/* do nothing */
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||
type, (unsigned)addr, ptr, (unsigned)val);
|
||||
|
|
14
c67-gen.c
14
c67-gen.c
|
@ -1951,12 +1951,12 @@ void gfunc_prolog(CType * func_type)
|
|||
CType *type;
|
||||
|
||||
sym = func_type->ref;
|
||||
func_call = sym->r;
|
||||
func_call = sym->f.func_call;
|
||||
addr = 8;
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
func_var = (sym->c == FUNC_ELLIPSIS);
|
||||
func_var = (sym->f.func_type == FUNC_ELLIPSIS);
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
|
@ -2035,6 +2035,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)
|
||||
{
|
||||
|
|
|
@ -56,7 +56,6 @@ case $targetos in
|
|||
DLLSUF=".dylib"
|
||||
;;
|
||||
MINGW*|MSYS*|CYGWIN*)
|
||||
confvars="$confvars WIN32"
|
||||
mingw32=yes
|
||||
;;
|
||||
DragonFly|OpenBSD|FreeBSD|NetBSD)
|
||||
|
@ -126,8 +125,6 @@ for opt do
|
|||
;;
|
||||
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--enable-mingw32) confvars="$confvars WIN32"; mingw32="yes"
|
||||
;;
|
||||
--enable-cross) confvars="$confvars cross"
|
||||
;;
|
||||
--disable-static) confvars="$confvars static=no"
|
||||
|
@ -142,6 +139,8 @@ for opt do
|
|||
;;
|
||||
--with-selinux) confvars="$confvars selinux"
|
||||
;;
|
||||
--config-mingw32*) mingw32=$(echo "$opt=yes" | cut -d '=' -f 2)
|
||||
;;
|
||||
--config-*) confvars="$confvars ${opt#--config-}"; suggest="no"
|
||||
;;
|
||||
--help|-h) show_help="yes"
|
||||
|
@ -161,7 +160,7 @@ fi
|
|||
|
||||
case "$cpu" in
|
||||
x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386)
|
||||
cpu="x86"
|
||||
cpu="i386"
|
||||
;;
|
||||
x86_64|amd64|x86-64)
|
||||
cpu="x86_64"
|
||||
|
@ -184,7 +183,7 @@ case "$cpu" in
|
|||
cpu="arm"
|
||||
;;
|
||||
aarch64)
|
||||
cpu="arm64"
|
||||
cpu="aarch64"
|
||||
;;
|
||||
alpha)
|
||||
cpu="alpha"
|
||||
|
@ -216,22 +215,12 @@ if test "$mingw32" = "yes" ; then
|
|||
if test "$cc" = gcc; then
|
||||
test -z "$LDFLAGS" && LDFLAGS="-static"
|
||||
fi
|
||||
if test x"$tccdir" = x""; then
|
||||
tccdir="tcc"
|
||||
fi
|
||||
if test -z "$prefix" ; then
|
||||
prefix="C:/Program Files/${tccdir}"
|
||||
fi
|
||||
if test -z "$sharedir" ; then
|
||||
sharedir="${prefix}"
|
||||
fi
|
||||
execprefix="$prefix"
|
||||
bindir="${prefix}"
|
||||
tccdir="${prefix}"
|
||||
libdir="${prefix}/lib"
|
||||
docdir="${sharedir}/doc"
|
||||
mandir="${sharedir}/man"
|
||||
infodir="${sharedir}/info"
|
||||
test -z "$prefix" && prefix="C:/Program Files/tcc"
|
||||
test -z "$tccdir" && tccdir="${prefix}"
|
||||
test -z "$bindir" && bindir="${tccdir}"
|
||||
test -z "$docdir" && docdir="${tccdir}/doc"
|
||||
test -z "$libdir" && libdir="${tccdir}/libtcc"
|
||||
confvars="$confvars WIN32"
|
||||
LIBSUF=".lib"
|
||||
EXESUF=".exe"
|
||||
DLLSUF=".dll"
|
||||
|
@ -263,12 +252,11 @@ else
|
|||
if test x"$tccdir" = x""; then
|
||||
tccdir="${libdir}/tcc"
|
||||
fi
|
||||
if test x"$includedir" = x""; then
|
||||
includedir="${prefix}/include"
|
||||
fi
|
||||
fi # mingw32
|
||||
|
||||
if test x"$includedir" = x""; then
|
||||
includedir="${prefix}/include"
|
||||
fi
|
||||
|
||||
if test x"$show_help" = "xyes" ; then
|
||||
cat << EOF
|
||||
Usage: configure [options]
|
||||
|
@ -301,8 +289,7 @@ Advanced options (experts only):
|
|||
--disable-static make libtcc.so instead of libtcc.a
|
||||
--enable-static make libtcc.a instead of libtcc.dll (win32)
|
||||
--disable-rpath disable use of -rpath with the above
|
||||
--with-libgcc use libgcc_s.so.1 instead of libtcc1.a in dynamic link
|
||||
--enable-mingw32 build windows version on linux with mingw32
|
||||
--with-libgcc use libgcc_s.so.1 instead of libtcc1.a
|
||||
--enable-cross build cross compilers
|
||||
--with-selinux use mmap for executable memory (with tcc -run)
|
||||
--sysincludepaths=... specify system include paths, colon separated
|
||||
|
@ -310,7 +297,7 @@ Advanced options (experts only):
|
|||
--crtprefix=... specify locations of crt?.o, colon separated
|
||||
--elfinterp=... specify elf interpreter
|
||||
--triplet=... specify system library/include directory triplet
|
||||
--config-uClibc,-musl... enable specific configuration for some systems
|
||||
--config-uClibc,-musl,-mingw32... enable system specific configurations
|
||||
EOF
|
||||
#echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
|
@ -320,15 +307,14 @@ cc="${cross_prefix}${cc}"
|
|||
ar="${cross_prefix}${ar}"
|
||||
strip="${cross_prefix}${strip}"
|
||||
|
||||
CONFTEST=./conftest$EXESUF
|
||||
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
|
||||
echo "configure: error: '$cc' failed to compile conftest.c."
|
||||
else
|
||||
gcc_major="$($CONFTEST version)"
|
||||
gcc_minor="$($CONFTEST minor)"
|
||||
fi
|
||||
|
||||
if test -z "$cross_prefix" ; then
|
||||
CONFTEST=./conftest$EXESUF
|
||||
if ! $cc -o $CONFTEST $source_path/conftest.c 2>/dev/null ; then
|
||||
echo "configure: error: '$cc' failed to compile conftest.c."
|
||||
else
|
||||
gcc_major="$($CONFTEST version)"
|
||||
gcc_minor="$($CONFTEST minor)"
|
||||
fi
|
||||
bigendian="$($CONFTEST bigendian)"
|
||||
if test "$mingw32" = "no" ; then
|
||||
|
||||
|
@ -340,7 +326,7 @@ if test -z "$cross_prefix" ; then
|
|||
fi
|
||||
|
||||
if test -z "$triplet"; then
|
||||
if test $cpu = "x86_64" -o $cpu = "arm64" ; then
|
||||
if test $cpu = "x86_64" -o $cpu = "aarch64" ; then
|
||||
if test -f "/usr/lib64/crti.o" ; then
|
||||
tcc_lddir="lib64"
|
||||
fi
|
||||
|
@ -349,7 +335,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
|
||||
|
@ -401,16 +387,16 @@ fi
|
|||
|
||||
fcho() { if test -n "$2"; then echo "$1$2"; fi }
|
||||
|
||||
echo "Binary directory $bindir"
|
||||
echo "TinyCC directory $tccdir"
|
||||
echo "Library directory $libdir"
|
||||
echo "Include directory $includedir"
|
||||
echo "Manual directory $mandir"
|
||||
echo "Info directory $infodir"
|
||||
echo "Doc directory $docdir"
|
||||
fcho "Binary directory " "$bindir"
|
||||
fcho "TinyCC directory " "$tccdir"
|
||||
fcho "Library directory " "$libdir"
|
||||
fcho "Include directory " "$includedir"
|
||||
fcho "Manual directory " "$mandir"
|
||||
fcho "Info directory " "$infodir"
|
||||
fcho "Doc directory " "$docdir"
|
||||
fcho "Target root prefix " "$sysroot"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "C compiler $cc ($gcc_major.$gcc_minor)"
|
||||
echo "Target OS $targetos"
|
||||
echo "CPU $cpu"
|
||||
fcho "Triplet " "$triplet"
|
||||
|
@ -471,15 +457,11 @@ print_mak CONFIG_LDDIR "$tcc_lddir"
|
|||
print_mak CONFIG_TRIPLET "$triplet"
|
||||
print_mak_int TCC_CPU_VERSION "$cpuver"
|
||||
|
||||
echo "#define GCC_MAJOR $gcc_major" >> $TMPH
|
||||
echo "#define GCC_MINOR $gcc_minor" >> $TMPH
|
||||
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
if test "$cpu" = "aarch64" ; then
|
||||
echo "ARCH=arm64" >> config.mak
|
||||
else
|
||||
echo "ARCH=$cpu" >> config.mak
|
||||
fi
|
||||
|
||||
echo "TARGETOS=$targetos" >> config.mak
|
||||
|
||||
for v in $confvars ; do
|
||||
|
|
6
elf.h
6
elf.h
|
@ -232,7 +232,7 @@ typedef struct
|
|||
|
||||
#define EM_FX66 66 /* Siemens FX66 microcontroller */
|
||||
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
|
||||
#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
|
||||
#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */
|
||||
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
|
||||
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
|
||||
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
|
||||
|
@ -817,7 +817,7 @@ typedef struct
|
|||
#define DF_1_EDITED 0x00200000 /* Object is modified after built. */
|
||||
#define DF_1_NORELOC 0x00400000
|
||||
#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
|
||||
#define DF_1_GLOBAUDIT 0x01000000 /* Global auditin required. */
|
||||
#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
|
||||
#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
|
||||
|
||||
/* Flags for the feature selection in DT_FEATURE_1. */
|
||||
|
@ -1313,7 +1313,7 @@ typedef struct
|
|||
#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
|
||||
#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
|
||||
#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
|
||||
#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
|
||||
#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */
|
||||
#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
|
||||
#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
|
||||
#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */
|
||||
|
|
33
i386-asm.c
33
i386-asm.c
|
@ -500,12 +500,13 @@ ST_FUNC void gen_expr64(ExprValue *pe)
|
|||
static void gen_disp32(ExprValue *pe)
|
||||
{
|
||||
Sym *sym = pe->sym;
|
||||
if (sym && sym->r == cur_text_section->sh_num) {
|
||||
ElfSym *esym = elfsym(sym);
|
||||
if (esym && esym->st_shndx == cur_text_section->sh_num) {
|
||||
/* same section: we can output an absolute value. Note
|
||||
that the TCC compiler behaves differently here because
|
||||
it always outputs a relocation to ease (future) code
|
||||
elimination in the linker */
|
||||
gen_le32(pe->v + sym->jnext - ind - 4);
|
||||
gen_le32(pe->v + esym->st_value - ind - 4);
|
||||
} else {
|
||||
if (sym && sym->type.t == VT_VOID) {
|
||||
sym->type.t = VT_FUNC;
|
||||
|
@ -726,6 +727,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||
|
||||
s = 0; /* avoid warning */
|
||||
|
||||
again:
|
||||
/* optimize matching by using a lookup table (no hashing is needed
|
||||
!) */
|
||||
for(pa = asm_instrs; pa->sym != 0; pa++) {
|
||||
|
@ -756,8 +758,9 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||
if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
|
||||
continue;
|
||||
/* cmovxx is a test opcode but accepts multiple sizes.
|
||||
TCC doesn't accept the suffixed mnemonic, instead we
|
||||
simply force size autodetection always. */
|
||||
The suffixes aren't encoded in the table, instead we
|
||||
simply force size autodetection always and deal with suffixed
|
||||
variants below when we don't find e.g. "cmovzl". */
|
||||
if (pa->instr_type & OPC_WLX)
|
||||
s = NBWLX - 1;
|
||||
} else if (pa->instr_type & OPC_B) {
|
||||
|
@ -843,8 +846,16 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||
tcc_error("bad operand with opcode '%s'",
|
||||
get_tok_str(opcode, NULL));
|
||||
} else {
|
||||
tcc_error("unknown opcode '%s'",
|
||||
get_tok_str(opcode, NULL));
|
||||
/* Special case for cmovcc, we accept size suffixes but ignore
|
||||
them, but we don't want them to blow up our tables. */
|
||||
TokenSym *ts = table_ident[opcode - TOK_IDENT];
|
||||
if (ts->len >= 6
|
||||
&& strchr("wlq", ts->str[ts->len-1])
|
||||
&& !memcmp(ts->str, "cmov", 4)) {
|
||||
opcode = tok_alloc(ts->str, ts->len-1)->tok;
|
||||
goto again;
|
||||
}
|
||||
tcc_error("unknown opcode '%s'", ts->str);
|
||||
}
|
||||
}
|
||||
/* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
|
||||
|
@ -1017,16 +1028,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||
if (pa->instr_type & OPC_B)
|
||||
v += s >= 1;
|
||||
if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) {
|
||||
Sym *sym;
|
||||
ElfSym *esym;
|
||||
int jmp_disp;
|
||||
|
||||
/* see if we can really generate the jump with a byte offset */
|
||||
sym = ops[0].e.sym;
|
||||
if (!sym)
|
||||
esym = elfsym(ops[0].e.sym);
|
||||
if (!esym || esym->st_shndx != cur_text_section->sh_num)
|
||||
goto no_short_jump;
|
||||
if (sym->r != cur_text_section->sh_num)
|
||||
goto no_short_jump;
|
||||
jmp_disp = ops[0].e.v + sym->jnext - ind - 2 - (v >= 0xff);
|
||||
jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff);
|
||||
if (jmp_disp == (int8_t)jmp_disp) {
|
||||
/* OK to generate jump */
|
||||
ops[0].e.sym = 0;
|
||||
|
|
54
i386-gen.c
54
i386-gen.c
|
@ -157,25 +157,31 @@ 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)
|
||||
|
||||
/* output constant with relocation if 'r & VT_SYM' is true */
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, long c)
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
|
||||
{
|
||||
if (r & VT_SYM)
|
||||
greloc(cur_text_section, sym, ind, R_386_32);
|
||||
gen_le32(c);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, long c)
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
|
||||
{
|
||||
if (r & VT_SYM)
|
||||
greloc(cur_text_section, sym, ind, R_386_PC32);
|
||||
gen_le32(c - 4);
|
||||
}
|
||||
|
||||
/* generate a modrm reference. 'op_reg' contains the addtional 3
|
||||
/* generate a modrm reference. 'op_reg' contains the additional 3
|
||||
opcode bits */
|
||||
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
|
||||
{
|
||||
|
@ -210,7 +216,7 @@ ST_FUNC void load(int r, SValue *sv)
|
|||
#endif
|
||||
|
||||
fr = sv->r;
|
||||
ft = sv->type.t;
|
||||
ft = sv->type.t & ~VT_DEFSIGN;
|
||||
fc = sv->c.i;
|
||||
|
||||
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
||||
|
@ -345,19 +351,18 @@ static void gen_static_call(int v)
|
|||
static void gcall_or_jmp(int is_jmp)
|
||||
{
|
||||
int r;
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||
int rt;
|
||||
/* constant case */
|
||||
if (vtop->r & VT_SYM) {
|
||||
/* relocation case */
|
||||
greloc(cur_text_section, vtop->sym,
|
||||
ind + 1, R_386_PC32);
|
||||
} else {
|
||||
/* put an empty PC32 relocation */
|
||||
put_elf_reloc(symtab_section, cur_text_section,
|
||||
ind + 1, R_386_PC32, 0);
|
||||
}
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
|
||||
/* constant and relocation case */
|
||||
greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32);
|
||||
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
r = gv(RC_INT);
|
||||
o(0xff); /* call/jmp *r */
|
||||
o(0xd0 + r + (is_jmp << 4));
|
||||
}
|
||||
if (!is_jmp) {
|
||||
int rt;
|
||||
/* extend the return value to the whole register if necessary
|
||||
visual studio and gcc do not always set the whole eax register
|
||||
when assigning the return value of a function */
|
||||
|
@ -382,11 +387,6 @@ static void gcall_or_jmp(int is_jmp)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
r = gv(RC_INT);
|
||||
o(0xff); /* call/jmp *r */
|
||||
o(0xd0 + r + (is_jmp << 4));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,7 +477,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
}
|
||||
save_regs(0); /* save used temporary registers */
|
||||
func_sym = vtop->type.ref;
|
||||
func_call = func_sym->a.func_call;
|
||||
func_call = func_sym->f.func_call;
|
||||
/* fast call case */
|
||||
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
|
||||
func_call == FUNC_FASTCALLW) {
|
||||
|
@ -504,7 +504,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
#endif
|
||||
gcall_or_jmp(0);
|
||||
|
||||
if (args_size && func_call != FUNC_STDCALL)
|
||||
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
CType *type;
|
||||
|
||||
sym = func_type->ref;
|
||||
func_call = sym->a.func_call;
|
||||
func_call = sym->f.func_call;
|
||||
addr = 8;
|
||||
loc = 0;
|
||||
func_vc = 0;
|
||||
|
@ -547,7 +547,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
func_var = (sym->c == FUNC_ELLIPSIS);
|
||||
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)
|
||||
|
@ -586,8 +586,8 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
|||
param_index++;
|
||||
}
|
||||
func_ret_sub = 0;
|
||||
/* pascal type call ? */
|
||||
if (func_call == FUNC_STDCALL)
|
||||
/* pascal type call or fastcall ? */
|
||||
if (func_call == FUNC_STDCALL || func_call == FUNC_FASTCALLW)
|
||||
func_ret_sub = addr - 8;
|
||||
#ifndef TCC_TARGET_PE
|
||||
else if (func_vc)
|
||||
|
|
|
@ -226,6 +226,9 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||
write16le(ptr, read16le(ptr) + val - addr);
|
||||
return;
|
||||
case R_386_RELATIVE:
|
||||
#ifdef TCC_TARGET_PE
|
||||
add32le(ptr, val - s1->pe_imagebase);
|
||||
#endif
|
||||
/* do nothing */
|
||||
return;
|
||||
case R_386_COPY:
|
||||
|
|
|
@ -16,11 +16,7 @@ typedef struct {
|
|||
char *reg_save_area;
|
||||
} __va_list_struct;
|
||||
|
||||
/* Avoid conflicting definition for va_list on musl libc */
|
||||
#ifndef __DEFINED_va_list
|
||||
typedef __va_list_struct va_list[1];
|
||||
#define __DEFINED_va_list
|
||||
#endif
|
||||
|
||||
void __va_start(__va_list_struct *ap, void *fp);
|
||||
void *__va_arg(__va_list_struct *ap, int arg_type, int size, int align);
|
||||
|
|
|
@ -13,12 +13,20 @@ typedef __SIZE_TYPE__ uintptr_t;
|
|||
typedef signed char int8_t;
|
||||
typedef signed short int int16_t;
|
||||
typedef signed int int32_t;
|
||||
#ifdef __LP64__
|
||||
typedef signed long int int64_t;
|
||||
#else
|
||||
typedef signed long long int int64_t;
|
||||
#endif
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#ifdef __LP64__
|
||||
typedef unsigned long int uint64_t;
|
||||
#else
|
||||
typedef unsigned long long int uint64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*)0)
|
||||
|
|
20
lib/Makefile
20
lib/Makefile
|
@ -7,20 +7,20 @@ include $(TOP)/Makefile
|
|||
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
||||
BIN = $(TOP)/libtcc1$(if $(CROSS_TARGET),-$(CROSS_TARGET)).a
|
||||
BIN = $(TOP)/$(X)libtcc1.a
|
||||
|
||||
TCC = $(TOP)/$(X)tcc$(EXESUF)
|
||||
XCC = $(TCC)
|
||||
XAR = $(TCC) -ar
|
||||
XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
|
||||
XCC = $(XTCC)
|
||||
XAR = $(XTCC) -ar
|
||||
XFLAGS-unx = -B$(TOPSRC)
|
||||
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
||||
XFLAGS = $(XFLAGS$(XCFG))
|
||||
XCFG = $(or $(findstring -win,$T),-unx)
|
||||
|
||||
# in order to use gcc, tyoe: make <target>lib-usegcc=yes
|
||||
armlib-usegcc ?= no
|
||||
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
|
||||
arm-libtcc1-usegcc ?= no
|
||||
|
||||
ifeq "$($(X)$(T)lib-usegcc)" "yes"
|
||||
ifeq "$($(T)-libtcc1-usegcc)" "yes"
|
||||
XCC = $(CC)
|
||||
XAR = $(AR)
|
||||
XFLAGS = $(CFLAGS) -fPIC
|
||||
|
@ -29,7 +29,7 @@ endif
|
|||
# only for native compiler
|
||||
$(X)BCHECK_O = bcheck.o
|
||||
|
||||
ifeq ($(CONFIG_musl),yes)
|
||||
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
|
||||
BCHECK_O =
|
||||
endif
|
||||
|
||||
|
@ -61,10 +61,10 @@ $(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
|
|||
$(XAR) rcs $@ $^
|
||||
|
||||
$(X)%.o : %.c
|
||||
$(XCC) -c $< -o $@ $(DEFINES) $(XFLAGS)
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(X)%.o : %.S
|
||||
$(XCC) -c $< -o $@ $(DEFINES) $(XFLAGS)
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(X)crt1w.o : crt1.c
|
||||
$(X)wincrt1w.o : wincrt1.c
|
||||
|
|
|
@ -11,7 +11,7 @@ __bound_alloca:
|
|||
and $-4,%eax
|
||||
jz p6
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifdef _WIN32
|
||||
p4:
|
||||
cmp $4096,%eax
|
||||
jbe p5
|
||||
|
|
|
@ -10,7 +10,7 @@ alloca:
|
|||
and $-4,%eax
|
||||
jz p3
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifdef _WIN32
|
||||
p1:
|
||||
cmp $4096,%eax
|
||||
jbe p2
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
.globl __bound_alloca
|
||||
__bound_alloca:
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifdef _WIN32
|
||||
# bound checking is not implemented
|
||||
pop %rdx
|
||||
mov %rcx,%rax
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
alloca:
|
||||
pop %rdx
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifdef _WIN32
|
||||
mov %rcx,%rax
|
||||
#else
|
||||
mov %rdi,%rax
|
||||
|
@ -14,7 +14,7 @@ alloca:
|
|||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifdef _WIN32
|
||||
p1:
|
||||
cmp $4096,%rax
|
||||
jbe p2
|
||||
|
@ -27,10 +27,6 @@ p2:
|
|||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rax
|
||||
#ifdef TCC_TARGET_PE
|
||||
add $32,%rax
|
||||
#endif
|
||||
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
|
|
22
lib/bcheck.c
22
lib/bcheck.c
|
@ -21,10 +21,15 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) \
|
||||
&& !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||
|
||||
#if !defined(__FreeBSD__) \
|
||||
&& !defined(__FreeBSD_kernel__) \
|
||||
&& !defined(__DragonFly__) \
|
||||
&& !defined(__OpenBSD__) \
|
||||
&& !defined(__NetBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
@ -45,10 +50,13 @@
|
|||
#define CONFIG_TCC_MALLOC_HOOKS
|
||||
#define HAVE_MEMALIGN
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
|
||||
|| defined(__DragonFly__) || defined(__dietlibc__) \
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|
||||
|| defined(_WIN32) || defined(TCC_UCLIBC) || defined(TCC_MUSL)
|
||||
#if defined(__FreeBSD__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__OpenBSD__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__dietlibc__) \
|
||||
|| defined(_WIN32)
|
||||
//#warning Bound checking does not support malloc (etc.) in this environment.
|
||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||
#undef HAVE_MEMALIGN
|
||||
|
@ -236,7 +244,7 @@ BOUND_PTR_INDIR(16)
|
|||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 6)
|
||||
/*
|
||||
* At least gcc 6.2 complains when __builtin_frame_address is used whith
|
||||
* At least gcc 6.2 complains when __builtin_frame_address is used with
|
||||
* nonzero argument.
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
|
|
|
@ -107,10 +107,10 @@ union float_long {
|
|||
};
|
||||
|
||||
/* XXX: we don't support several builtin supports for now */
|
||||
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM)
|
||||
#if !defined __x86_64__ && !defined __arm__
|
||||
|
||||
/* XXX: use gcc/tcc intrinsic ? */
|
||||
#if defined(TCC_TARGET_I386)
|
||||
#if defined __i386__
|
||||
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
|
||||
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
|
||||
: "=r" ((USItype) (sh)), \
|
||||
|
@ -589,7 +589,7 @@ long long __fixdfdi (double a1)
|
|||
return s ? ret : -ret;
|
||||
}
|
||||
|
||||
#ifndef TCC_TARGET_ARM
|
||||
#ifndef __arm__
|
||||
unsigned long long __fixunsxfdi (long double a1)
|
||||
{
|
||||
register union ldouble_long dl1;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* va_list.c - tinycc support for va_list on X86_64 */
|
||||
|
||||
#if defined TCC_TARGET_X86_64
|
||||
#if defined __x86_64__
|
||||
|
||||
/* Avoid include files, they may not be available when cross compiling */
|
||||
extern void *memset(void *s, int c, __SIZE_TYPE__ n);
|
||||
|
|
219
libtcc.c
219
libtcc.c
|
@ -36,7 +36,7 @@ static int nb_states;
|
|||
|
||||
/********************************************************/
|
||||
|
||||
#ifdef ONE_SOURCE
|
||||
#if ONE_SOURCE
|
||||
#include "tccpp.c"
|
||||
#include "tccgen.c"
|
||||
#include "tccelf.c"
|
||||
|
@ -58,6 +58,7 @@ static int nb_states;
|
|||
#ifdef TCC_TARGET_C67
|
||||
#include "c67-gen.c"
|
||||
#include "c67-link.c"
|
||||
#include "tcccoff.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#include "x86_64-gen.c"
|
||||
|
@ -67,9 +68,6 @@ static int nb_states;
|
|||
#ifdef CONFIG_TCC_ASM
|
||||
#include "tccasm.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_COFF
|
||||
#include "tcccoff.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_PE
|
||||
#include "tccpe.c"
|
||||
#endif
|
||||
|
@ -106,10 +104,8 @@ static void tcc_set_lib_path_w32(TCCState *s)
|
|||
char path[1024], *p;
|
||||
GetModuleFileNameA(tcc_module, path, sizeof path);
|
||||
p = tcc_basename(normalize_slashes(strlwr(path)));
|
||||
if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
|
||||
p -= 5;
|
||||
else if (p > path)
|
||||
p--;
|
||||
if (p > path)
|
||||
--p;
|
||||
*p = 0;
|
||||
tcc_set_lib_path(s, path);
|
||||
}
|
||||
|
@ -264,7 +260,7 @@ struct mem_debug_header {
|
|||
int line_num;
|
||||
char file_name[MEM_DEBUG_FILE_LEN + 1];
|
||||
unsigned magic2;
|
||||
__attribute__((aligned(16))) unsigned magic3;
|
||||
ALIGNED(16) unsigned magic3;
|
||||
};
|
||||
|
||||
typedef struct mem_debug_header mem_debug_header_t;
|
||||
|
@ -442,7 +438,7 @@ static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *
|
|||
CString str;
|
||||
|
||||
cstr_new(&str);
|
||||
for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) {
|
||||
for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) {
|
||||
if (c == '{' && p[1] && p[2] == '}') {
|
||||
c = p[1], p += 2;
|
||||
if (c == 'B')
|
||||
|
@ -490,7 +486,7 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
|
|||
for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
|
||||
strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
|
||||
(*pf)->filename, (*pf)->line_num);
|
||||
if (f->line_num > 0) {
|
||||
if (s1->error_set_jmp_enabled) {
|
||||
strcat_printf(buf, sizeof(buf), "%s:%d: ",
|
||||
f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
|
||||
} else {
|
||||
|
@ -508,8 +504,9 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
|
|||
|
||||
if (!s1->error_func) {
|
||||
/* default case: stderr */
|
||||
if (s1->ppfp) /* print a newline during tcc -E */
|
||||
fprintf(s1->ppfp, "\n"), fflush(s1->ppfp);
|
||||
if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
|
||||
/* print a newline during tcc -E */
|
||||
printf("\n"), fflush(stdout);
|
||||
fflush(stdout); /* flush -v output */
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
fflush(stderr); /* print error/warning now (win32) */
|
||||
|
@ -581,15 +578,13 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
|
|||
bf->buf_end = bf->buffer + initlen;
|
||||
bf->buf_end[0] = CH_EOB; /* put eob symbol */
|
||||
pstrcpy(bf->filename, sizeof(bf->filename), filename);
|
||||
pstrcpy(bf->filename2, sizeof(bf->filename2), filename);
|
||||
#ifdef _WIN32
|
||||
normalize_slashes(bf->filename);
|
||||
#endif
|
||||
bf->true_filename = bf->filename;
|
||||
bf->line_num = 1;
|
||||
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
|
||||
bf->fd = -1;
|
||||
bf->prev = file;
|
||||
file = bf;
|
||||
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
|
||||
}
|
||||
|
||||
ST_FUNC void tcc_close(void)
|
||||
|
@ -599,6 +594,8 @@ ST_FUNC void tcc_close(void)
|
|||
close(bf->fd);
|
||||
total_lines += bf->line_num;
|
||||
}
|
||||
if (bf->true_filename != bf->filename)
|
||||
tcc_free(bf->true_filename);
|
||||
file = bf->prev;
|
||||
tcc_free(bf);
|
||||
}
|
||||
|
@ -615,49 +612,50 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
|
|||
(int)(s1->include_stack_ptr - s1->include_stack), "", filename);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
tcc_open_bf(s1, filename, 0);
|
||||
#ifdef _WIN32
|
||||
normalize_slashes(file->filename);
|
||||
#endif
|
||||
file->fd = fd;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* compile the C file opened in 'file'. Return non zero if errors. */
|
||||
static int tcc_compile(TCCState *s1)
|
||||
/* compile the file opened in 'file'. Return non zero if errors. */
|
||||
static int tcc_compile(TCCState *s1, int filetype)
|
||||
{
|
||||
Sym *define_start;
|
||||
int is_asm;
|
||||
|
||||
define_start = define_stack;
|
||||
is_asm = !!(filetype & (AFF_TYPE_ASM|AFF_TYPE_ASMPP));
|
||||
tccelf_begin_file(s1);
|
||||
|
||||
if (setjmp(s1->error_jmp_buf) == 0) {
|
||||
s1->nb_errors = 0;
|
||||
s1->error_set_jmp_enabled = 1;
|
||||
|
||||
preprocess_start(s1);
|
||||
tccgen_start(s1);
|
||||
|
||||
#ifdef INC_DEBUG
|
||||
printf("%s: **** new file\n", file->filename);
|
||||
preprocess_start(s1, is_asm);
|
||||
if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
tcc_preprocess(s1);
|
||||
} else if (is_asm) {
|
||||
#ifdef CONFIG_TCC_ASM
|
||||
tcc_assemble(s1, !!(filetype & AFF_TYPE_ASMPP));
|
||||
#else
|
||||
tcc_error_noabort("asm not supported");
|
||||
#endif
|
||||
|
||||
ch = file->buf_ptr[0];
|
||||
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
|
||||
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
|
||||
next();
|
||||
decl(VT_CONST);
|
||||
if (tok != TOK_EOF)
|
||||
expect("declaration");
|
||||
/* free defines here already on behalf of of M.M.'s possibly existing
|
||||
experimental preprocessor implementation. The normal call below
|
||||
is still there to free after error-longjmp */
|
||||
free_defines(define_start);
|
||||
tccgen_end(s1);
|
||||
} else {
|
||||
tccgen_compile(s1);
|
||||
}
|
||||
}
|
||||
s1->error_set_jmp_enabled = 0;
|
||||
|
||||
preprocess_end(s1);
|
||||
free_inline_functions(s1);
|
||||
/* reset define stack, but keep -D and built-ins */
|
||||
free_defines(define_start);
|
||||
sym_pop(&global_stack, NULL, 0);
|
||||
sym_pop(&local_stack, NULL, 0);
|
||||
tccelf_end_file(s1);
|
||||
return s1->nb_errors != 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
@ -668,7 +666,7 @@ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
|
|||
len = strlen(str);
|
||||
tcc_open_bf(s, "<string>", len);
|
||||
memcpy(file->buffer, str, len);
|
||||
ret = tcc_compile(s);
|
||||
ret = tcc_compile(s, s->filetype);
|
||||
tcc_close();
|
||||
return ret;
|
||||
}
|
||||
|
@ -690,10 +688,8 @@ LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *valu
|
|||
memcpy(file->buffer + len1 + 1, value, len2);
|
||||
|
||||
/* parse with define parser */
|
||||
ch = file->buf_ptr[0];
|
||||
next_nomacro();
|
||||
parse_define();
|
||||
|
||||
tcc_close();
|
||||
}
|
||||
|
||||
|
@ -714,6 +710,8 @@ static void tcc_cleanup(void)
|
|||
{
|
||||
if (NULL == tcc_state)
|
||||
return;
|
||||
while (file)
|
||||
tcc_close();
|
||||
tccpp_delete(tcc_state);
|
||||
tcc_state = NULL;
|
||||
/* free sym_pools */
|
||||
|
@ -734,9 +732,9 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||
tcc_state = s;
|
||||
++nb_states;
|
||||
|
||||
s->alacarte_link = 1;
|
||||
s->nocommon = 1;
|
||||
s->warn_implicit_function_declaration = 1;
|
||||
s->ms_extensions = 1;
|
||||
|
||||
#ifdef CHAR_IS_UNSIGNED
|
||||
s->char_is_unsigned = 1;
|
||||
|
@ -762,6 +760,7 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||
define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
|
||||
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
|
||||
{
|
||||
/* define __TINYC__ 92X */
|
||||
char buffer[32]; int a,b,c;
|
||||
|
@ -803,6 +802,8 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||
#endif
|
||||
#elif defined(TCC_TARGET_ARM64)
|
||||
tcc_define_symbol(s, "__aarch64__", NULL);
|
||||
#elif defined TCC_TARGET_C67
|
||||
tcc_define_symbol(s, "__C67__", NULL);
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
@ -826,36 +827,32 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||
# if defined(__FreeBSD_kernel__)
|
||||
tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
|
||||
# endif
|
||||
#endif
|
||||
# if defined(__NetBSD__)
|
||||
tcc_define_symbol(s, "__NetBSD__", "__NetBSD__");
|
||||
# endif
|
||||
# if defined(__OpenBSD__)
|
||||
tcc_define_symbol(s, "__OpenBSD__", "__OpenBSD__");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* TinyCC & gcc defines */
|
||||
#if defined(TCC_TARGET_PE) && PTR_SIZE == 8
|
||||
#if PTR_SIZE == 4
|
||||
/* 32bit systems. */
|
||||
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
|
||||
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
|
||||
tcc_define_symbol(s, "__ILP32__", NULL);
|
||||
#elif LONG_SIZE == 4
|
||||
/* 64bit Windows. */
|
||||
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
|
||||
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
|
||||
tcc_define_symbol(s, "__LLP64__", NULL);
|
||||
#elif PTR_SIZE == 8
|
||||
#else
|
||||
/* Other 64bit systems. */
|
||||
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
|
||||
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
|
||||
tcc_define_symbol(s, "__LP64__", NULL);
|
||||
#else
|
||||
/* Other 32bit systems. */
|
||||
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
|
||||
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
|
||||
tcc_define_symbol(s, "__ILP32__", NULL);
|
||||
#endif
|
||||
|
||||
#if defined(TCC_MUSL)
|
||||
tcc_define_symbol(s, "__builtin_va_list", "void *");
|
||||
#endif /* TCC_MUSL */
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
|
||||
tcc_define_symbol(s, "__WINT_TYPE__", "unsigned short");
|
||||
|
@ -882,6 +879,11 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
|
||||
"name proto __asm__ (#alias) __THROW");
|
||||
# endif
|
||||
# if defined(TCC_MUSL)
|
||||
tcc_define_symbol(s, "__DEFINED_va_list", "");
|
||||
tcc_define_symbol(s, "__DEFINED___isoc_va_list", "");
|
||||
tcc_define_symbol(s, "__isoc_va_list", "void *");
|
||||
# endif /* TCC_MUSL */
|
||||
/* Some GCC builtins that are simple to express as macros. */
|
||||
tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x");
|
||||
#endif /* ndef TCC_TARGET_PE */
|
||||
|
@ -992,26 +994,7 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
|
|||
|
||||
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
||||
{
|
||||
int ret, filetype;
|
||||
|
||||
filetype = flags & 0x0F;
|
||||
if (filetype == 0) {
|
||||
/* use a file extension to detect a filetype */
|
||||
const char *ext = tcc_fileextension(filename);
|
||||
if (ext[0]) {
|
||||
ext++;
|
||||
if (!strcmp(ext, "S"))
|
||||
filetype = AFF_TYPE_ASMPP;
|
||||
else if (!strcmp(ext, "s"))
|
||||
filetype = AFF_TYPE_ASM;
|
||||
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
|
||||
filetype = AFF_TYPE_C;
|
||||
else
|
||||
filetype = AFF_TYPE_BIN;
|
||||
} else {
|
||||
filetype = AFF_TYPE_C;
|
||||
}
|
||||
}
|
||||
int ret;
|
||||
|
||||
/* open the file */
|
||||
ret = tcc_open(s1, filename);
|
||||
|
@ -1025,26 +1008,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
dynarray_add(&s1->target_deps, &s1->nb_target_deps,
|
||||
tcc_strdup(filename));
|
||||
|
||||
parse_flags = 0;
|
||||
/* if .S file, define __ASSEMBLER__ like gcc does */
|
||||
if (filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP) {
|
||||
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
|
||||
parse_flags = PARSE_FLAG_ASM_FILE;
|
||||
}
|
||||
|
||||
if (flags & AFF_PREPROCESS) {
|
||||
ret = tcc_preprocess(s1);
|
||||
} else if (filetype == AFF_TYPE_C) {
|
||||
ret = tcc_compile(s1);
|
||||
#ifdef CONFIG_TCC_ASM
|
||||
} else if (filetype == AFF_TYPE_ASMPP) {
|
||||
/* non preprocessed assembler */
|
||||
ret = tcc_assemble(s1, 1);
|
||||
} else if (filetype == AFF_TYPE_ASM) {
|
||||
/* preprocessed assembler */
|
||||
ret = tcc_assemble(s1, 0);
|
||||
#endif
|
||||
} else {
|
||||
if (flags & AFF_TYPE_BIN) {
|
||||
ElfW(Ehdr) ehdr;
|
||||
int fd, obj_type;
|
||||
|
||||
|
@ -1052,11 +1016,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
obj_type = tcc_object_type(fd, &ehdr);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
/* do not display line number if error */
|
||||
file->line_num = 0;
|
||||
|
||||
#ifdef TCC_TARGET_MACHO
|
||||
if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), "dylib"))
|
||||
if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib"))
|
||||
obj_type = AFF_BINTYPE_DYN;
|
||||
#endif
|
||||
|
||||
|
@ -1079,7 +1040,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
break;
|
||||
#endif
|
||||
case AFF_BINTYPE_AR:
|
||||
ret = tcc_load_archive(s1, fd);
|
||||
ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE));
|
||||
break;
|
||||
#ifdef TCC_TARGET_COFF
|
||||
case AFF_BINTYPE_C67:
|
||||
|
@ -1097,6 +1058,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
tcc_error_noabort("unrecognized file type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret = tcc_compile(s1, flags);
|
||||
}
|
||||
tcc_close();
|
||||
return ret;
|
||||
|
@ -1104,10 +1067,25 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
|
||||
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
|
||||
{
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS)
|
||||
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS | s->filetype);
|
||||
else
|
||||
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | s->filetype);
|
||||
int filetype = s->filetype;
|
||||
if (0 == (filetype & AFF_TYPE_MASK)) {
|
||||
/* use a file extension to detect a filetype */
|
||||
const char *ext = tcc_fileextension(filename);
|
||||
if (ext[0]) {
|
||||
ext++;
|
||||
if (!strcmp(ext, "S"))
|
||||
filetype = AFF_TYPE_ASMPP;
|
||||
else if (!strcmp(ext, "s"))
|
||||
filetype = AFF_TYPE_ASM;
|
||||
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
|
||||
filetype = AFF_TYPE_C;
|
||||
else
|
||||
filetype |= AFF_TYPE_BIN;
|
||||
} else {
|
||||
filetype = AFF_TYPE_C;
|
||||
}
|
||||
}
|
||||
return tcc_add_file_internal(s, filename, filetype | AFF_PRINT_ERROR);
|
||||
}
|
||||
|
||||
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
|
||||
|
@ -1159,9 +1137,10 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
|
|||
const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
|
||||
const char **pp = s->static_link ? libs + 1 : libs;
|
||||
#endif
|
||||
int flags = s->filetype & AFF_WHOLE_ARCHIVE;
|
||||
while (*pp) {
|
||||
if (0 == tcc_add_library_internal(s, *pp,
|
||||
libraryname, 0, s->library_paths, s->nb_library_paths))
|
||||
libraryname, flags, s->library_paths, s->nb_library_paths))
|
||||
return 0;
|
||||
++pp;
|
||||
}
|
||||
|
@ -1386,6 +1365,8 @@ static int tcc_set_linker(TCCState *s, const char *option)
|
|||
ignoring = 1;
|
||||
} else if (link_option(option, "export-all-symbols", &p)) {
|
||||
s->rdynamic = 1;
|
||||
} else if (link_option(option, "export-dynamic", &p)) {
|
||||
s->rdynamic = 1;
|
||||
} else if (link_option(option, "rpath=", &p)) {
|
||||
copy_linker_arg(&s->rpath, p, ':');
|
||||
} else if (link_option(option, "enable-new-dtags", &p)) {
|
||||
|
@ -1427,7 +1408,10 @@ static int tcc_set_linker(TCCState *s, const char *option)
|
|||
goto err;
|
||||
#endif
|
||||
} else if (ret = link_option(option, "?whole-archive", &p), ret) {
|
||||
s->alacarte_link = ret < 0;
|
||||
if (ret > 0)
|
||||
s->filetype |= AFF_WHOLE_ARCHIVE;
|
||||
else
|
||||
s->filetype &= ~AFF_WHOLE_ARCHIVE;
|
||||
} else if (p) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -1518,7 +1502,7 @@ static const TCCOption tcc_options[] = {
|
|||
{ "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
|
||||
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
|
||||
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
|
||||
{ "bench", TCC_OPTION_bench, 0 },
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
|
||||
|
@ -1553,7 +1537,6 @@ static const TCCOption tcc_options[] = {
|
|||
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
|
||||
{ "iwithprefix", TCC_OPTION_iwithprefix, TCC_OPTION_HAS_ARG },
|
||||
{ "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG },
|
||||
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
|
||||
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
|
||||
|
@ -1614,7 +1597,6 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
|
|||
{
|
||||
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
|
||||
f->type = filetype;
|
||||
f->alacarte = s->alacarte_link;
|
||||
strcpy(f->name, filename);
|
||||
dynarray_add(&s->files, &s->nb_files, f);
|
||||
}
|
||||
|
@ -1688,7 +1670,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
|
|||
int last_o = -1;
|
||||
int x;
|
||||
CString linker_arg; /* collect -Wl options */
|
||||
char buf[1024];
|
||||
int tool = 0, arg_start = 0, noaction = optind;
|
||||
char **argv = *pargv;
|
||||
int argc = *pargc;
|
||||
|
@ -1762,7 +1743,7 @@ reparse:
|
|||
tcc_set_lib_path(s, optarg);
|
||||
break;
|
||||
case TCC_OPTION_l:
|
||||
args_parser_add_file(s, optarg, AFF_TYPE_LIB);
|
||||
args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
|
||||
s->nb_libraries++;
|
||||
break;
|
||||
case TCC_OPTION_pthread:
|
||||
|
@ -1798,6 +1779,10 @@ reparse:
|
|||
s->dflag = 3;
|
||||
else if (*optarg == 'M')
|
||||
s->dflag = 7;
|
||||
else if (*optarg == 't')
|
||||
s->dflag = 16;
|
||||
else if (isnum(*optarg))
|
||||
g_debug = atoi(optarg);
|
||||
else
|
||||
goto unsupported_option;
|
||||
break;
|
||||
|
@ -1829,10 +1814,6 @@ reparse:
|
|||
case TCC_OPTION_isystem:
|
||||
tcc_add_sysinclude_path(s, optarg);
|
||||
break;
|
||||
case TCC_OPTION_iwithprefix:
|
||||
snprintf(buf, sizeof buf, "{B}/%s", optarg);
|
||||
tcc_add_sysinclude_path(s, buf);
|
||||
break;
|
||||
case TCC_OPTION_include:
|
||||
dynarray_add(&s->cmd_include_files,
|
||||
&s->nb_cmd_include_files, tcc_strdup(optarg));
|
||||
|
@ -1916,14 +1897,18 @@ reparse:
|
|||
exit(0);
|
||||
break;
|
||||
case TCC_OPTION_x:
|
||||
x = 0;
|
||||
if (*optarg == 'c')
|
||||
s->filetype = AFF_TYPE_C;
|
||||
x = AFF_TYPE_C;
|
||||
else if (*optarg == 'a')
|
||||
s->filetype = AFF_TYPE_ASMPP;
|
||||
x = AFF_TYPE_ASMPP;
|
||||
else if (*optarg == 'b')
|
||||
x = AFF_TYPE_BIN;
|
||||
else if (*optarg == 'n')
|
||||
s->filetype = AFF_TYPE_NONE;
|
||||
x = AFF_TYPE_NONE;
|
||||
else
|
||||
tcc_warning("unsupported language '%s'", optarg);
|
||||
s->filetype = x | (s->filetype & ~AFF_TYPE_MASK);
|
||||
break;
|
||||
case TCC_OPTION_O:
|
||||
last_o = atoi(optarg);
|
||||
|
|
18
tcc-doc.texi
18
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.
|
||||
|
||||
|
@ -543,6 +548,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 +576,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:
|
||||
|
@ -669,7 +677,7 @@ are supported.
|
|||
|
||||
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
|
||||
assembler supports a gas-like syntax (GNU assembler). You can
|
||||
desactivate assembler support if you want a smaller TinyCC executable
|
||||
deactivate assembler support if you want a smaller TinyCC executable
|
||||
(the C compiler does not rely on the assembler).
|
||||
|
||||
TinyCC Assembler is used to handle files with @file{.S} (C
|
||||
|
@ -1046,7 +1054,7 @@ All symbols are stored in hashed symbol stacks. Each symbol stack
|
|||
contains @code{Sym} structures.
|
||||
|
||||
@code{Sym.v} contains the symbol name (remember
|
||||
an idenfier is also a token, so a string is never necessary to store
|
||||
an identifier is also a token, so a string is never necessary to store
|
||||
it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually
|
||||
the register in which the corresponding variable is stored. @code{Sym.c} is
|
||||
usually a constant associated to the symbol like its address for normal
|
||||
|
@ -1089,7 +1097,7 @@ global stack.
|
|||
|
||||
@section Sections
|
||||
|
||||
The generated code and datas are written in sections. The structure
|
||||
The generated code and data are written in sections. The structure
|
||||
@code{Section} contains all the necessary information for a given
|
||||
section. @code{new_section()} creates a new section. ELF file semantics
|
||||
is assumed for each section.
|
||||
|
@ -1276,13 +1284,13 @@ should generate a function prolog/epilog.
|
|||
|
||||
@item gen_opi(op)
|
||||
must generate the binary integer operation @var{op} on the two top
|
||||
entries of the stack which are guaranted to contain integer types.
|
||||
entries of the stack which are guaranteed to contain integer types.
|
||||
|
||||
The result value should be put on the stack.
|
||||
|
||||
@item gen_opf(op)
|
||||
same as @code{gen_opi()} for floating point operations. The two top
|
||||
entries of the stack are guaranted to contain floating point values of
|
||||
entries of the stack are guaranteed to contain floating point values of
|
||||
same types.
|
||||
|
||||
@item gen_cvt_itof()
|
||||
|
|
67
tcc.c
67
tcc.c
|
@ -18,10 +18,9 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef ONE_SOURCE
|
||||
#include "libtcc.c"
|
||||
#else
|
||||
#include "tcc.h"
|
||||
#if ONE_SOURCE
|
||||
# include "libtcc.c"
|
||||
#endif
|
||||
#include "tcctools.c"
|
||||
|
||||
|
@ -63,7 +62,7 @@ static const char help[] =
|
|||
" -bt N show N callers in stack traces\n"
|
||||
#endif
|
||||
"Misc. options:\n"
|
||||
" -x[c|a|n] specify type of the next infile\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"
|
||||
|
@ -87,10 +86,10 @@ static const char help2[] =
|
|||
" -Wp,-opt same as -opt\n"
|
||||
" -include file include 'file' above each input file\n"
|
||||
" -isystem dir add 'dir' to system include path\n"
|
||||
" -iwithprefix dir set tcc's private include/library subdir\n"
|
||||
" -static link to static libraries (not recommended)\n"
|
||||
" -dumpversion print version\n"
|
||||
" -print-search-dirs print search paths\n"
|
||||
" -dt with -run/-E: auto-define 'test_...' macros\n"
|
||||
"Ignored options:\n"
|
||||
" --param -pedantic -pipe -s -std -traditional\n"
|
||||
"-W... warnings:\n"
|
||||
|
@ -98,7 +97,7 @@ static const char help2[] =
|
|||
" error stop after first warning\n"
|
||||
" unsupported warn about ignored options, pragmas, etc.\n"
|
||||
" write-strings strings are const\n"
|
||||
" implicit-function-declaration warn for missing prototype (*)\n"
|
||||
" implicit-function-declaration warn for missing prototype (*)\n"
|
||||
"-f[no-]... flags:\n"
|
||||
" unsigned-char default char is unsigned\n"
|
||||
" signed-char default char is signed\n"
|
||||
|
@ -118,6 +117,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
|
||||
|
@ -183,9 +183,11 @@ 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);
|
||||
#ifndef TCC_TARGET_PE
|
||||
print_dirs("crt", s->crt_paths, s->nb_crt_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);
|
||||
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
|
||||
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
|
||||
#endif
|
||||
}
|
||||
|
@ -196,7 +198,7 @@ static void set_environment(TCCState *s)
|
|||
|
||||
path = getenv("C_INCLUDE_PATH");
|
||||
if(path != NULL) {
|
||||
tcc_add_include_path(s, path);
|
||||
tcc_add_sysinclude_path(s, path);
|
||||
}
|
||||
path = getenv("CPATH");
|
||||
if(path != NULL) {
|
||||
|
@ -244,18 +246,21 @@ static unsigned getclock_ms(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc0, char **argv0)
|
||||
{
|
||||
TCCState *s;
|
||||
int ret, opt, n = 0;
|
||||
int ret, opt, n = 0, t = 0;
|
||||
unsigned start_time = 0;
|
||||
const char *first_file;
|
||||
int argc; char **argv;
|
||||
FILE *ppfp = stdout;
|
||||
|
||||
redo:
|
||||
argc = argc0, argv = argv0;
|
||||
s = tcc_new();
|
||||
opt = tcc_parse_args(s, &argc, &argv, 1);
|
||||
|
||||
if (n == 0) {
|
||||
if ((n | t) == 0) {
|
||||
if (opt == OPT_HELP)
|
||||
return printf(help), 1;
|
||||
if (opt == OPT_HELP2)
|
||||
|
@ -274,6 +279,7 @@ redo:
|
|||
return 0;
|
||||
if (opt == OPT_PRINT_DIRS) {
|
||||
/* initialize search dirs */
|
||||
set_environment(s);
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
print_search_dirs(s);
|
||||
return 0;
|
||||
|
@ -284,11 +290,9 @@ redo:
|
|||
tcc_error("no input files\n");
|
||||
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (!s->outfile) {
|
||||
s->ppfp = stdout;
|
||||
} else {
|
||||
s->ppfp = fopen(s->outfile, "w");
|
||||
if (!s->ppfp)
|
||||
if (s->outfile && 0!=strcmp("-",s->outfile)) {
|
||||
ppfp = fopen(s->outfile, "w");
|
||||
if (!ppfp)
|
||||
tcc_error("could not write '%s'", s->outfile);
|
||||
}
|
||||
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
|
||||
|
@ -297,8 +301,10 @@ redo:
|
|||
if (n > 1 && s->outfile)
|
||||
tcc_error("cannot specify output file with -c many files");
|
||||
} else {
|
||||
if (s->option_pthread)
|
||||
if (s->option_pthread) {
|
||||
tcc_set_options(s, "-lpthread");
|
||||
n = s->nb_files;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->do_bench)
|
||||
|
@ -309,13 +315,17 @@ redo:
|
|||
if (s->output_type == 0)
|
||||
s->output_type = TCC_OUTPUT_EXE;
|
||||
tcc_set_output_type(s, s->output_type);
|
||||
s->ppfp = ppfp;
|
||||
|
||||
if ((s->output_type == TCC_OUTPUT_MEMORY
|
||||
|| s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16))
|
||||
s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files;
|
||||
|
||||
/* compile or add each files or library */
|
||||
for (first_file = NULL, ret = 0;;) {
|
||||
struct filespec *f = s->files[s->nb_files - n];
|
||||
s->filetype = f->type;
|
||||
s->alacarte_link = f->alacarte;
|
||||
if (f->type == AFF_TYPE_LIB) {
|
||||
if (f->type & AFF_TYPE_LIB) {
|
||||
if (tcc_add_library_err(s, f->name) < 0)
|
||||
ret = 1;
|
||||
} else {
|
||||
|
@ -326,16 +336,15 @@ redo:
|
|||
if (tcc_add_file(s, f->name) < 0)
|
||||
ret = 1;
|
||||
}
|
||||
s->filetype = 0;
|
||||
s->alacarte_link = 1;
|
||||
if (ret || --n == 0
|
||||
if (--n == 0 || ret
|
||||
|| (s->output_type == TCC_OUTPUT_OBJ && !s->option_r))
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (s->outfile)
|
||||
fclose(s->ppfp);
|
||||
if (s->run_test) {
|
||||
t = 0;
|
||||
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
;
|
||||
} else if (0 == ret) {
|
||||
if (s->output_type == TCC_OUTPUT_MEMORY) {
|
||||
#ifdef TCC_IS_NATIVE
|
||||
|
@ -351,10 +360,14 @@ redo:
|
|||
}
|
||||
}
|
||||
|
||||
if (s->do_bench && ret == 0 && n == 0)
|
||||
if (s->do_bench && (n | t | ret) == 0)
|
||||
tcc_print_stats(s, getclock_ms() - start_time);
|
||||
tcc_delete(s);
|
||||
if (ret == 0 && n)
|
||||
goto redo; /* compile more files with -c */
|
||||
if (t)
|
||||
goto redo; /* run more tests with -dt -run */
|
||||
if (ppfp && ppfp != stdout)
|
||||
fclose(ppfp);
|
||||
return ret;
|
||||
}
|
||||
|
|
331
tcc.h
331
tcc.h
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* TCC - Tiny C Compiler
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2001-2004 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
|
@ -41,10 +41,11 @@
|
|||
# include <dlfcn.h>
|
||||
# endif
|
||||
/* XXX: need to define this to use them in non ISOC99 context */
|
||||
extern float strtof (const char *__nptr, char **__endptr);
|
||||
extern long double strtold (const char *__nptr, char **__endptr);
|
||||
extern float strtof (const char *__nptr, char **__endptr);
|
||||
extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#endif
|
||||
|
||||
#else /* on _WIN32: */
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# include <io.h> /* open, close etc. */
|
||||
# include <direct.h> /* getcwd */
|
||||
|
@ -52,7 +53,6 @@
|
|||
# include <stdint.h>
|
||||
# endif
|
||||
# define inline __inline
|
||||
# define inp next_inp /* inp is an intrinsic on msvc */
|
||||
# define snprintf _snprintf
|
||||
# define vsnprintf _vsnprintf
|
||||
# ifndef __GNUC__
|
||||
|
@ -65,6 +65,7 @@
|
|||
# define LIBTCCAPI __declspec(dllexport)
|
||||
# define PUB_FUNC LIBTCCAPI
|
||||
# endif
|
||||
# define inp next_inp /* inp is an intrinsic on msvc/mingw */
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning (disable : 4244) // conversion from 'uint64_t' to 'int', possible loss of data
|
||||
# pragma warning (disable : 4267) // conversion from 'size_t' to 'int', possible loss of data
|
||||
|
@ -72,9 +73,6 @@
|
|||
# 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
|
||||
# define __attribute__(x) __declspec x
|
||||
# define aligned align
|
||||
# else
|
||||
# endif
|
||||
# undef CONFIG_TCC_STATIC
|
||||
#endif
|
||||
|
@ -83,28 +81,32 @@
|
|||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define NORETURN __attribute__ ((noreturn))
|
||||
#elif defined _MSC_VER
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#ifndef countof
|
||||
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define NORETURN __declspec(noreturn)
|
||||
# define ALIGNED(x) __declspec(align(x))
|
||||
#else
|
||||
# define NORETURN
|
||||
# define NORETURN __attribute__((noreturn))
|
||||
# define ALIGNED(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# define IS_DIRSEP(c) (c == '/' || c == '\\')
|
||||
# define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2])))
|
||||
# define PATHCMP stricmp
|
||||
# define PATHSEP ";"
|
||||
#else
|
||||
# define IS_DIRSEP(c) (c == '/')
|
||||
# define IS_ABSPATH(p) IS_DIRSEP(p[0])
|
||||
# define PATHCMP strcmp
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
#define PATHSEP ';'
|
||||
#else
|
||||
#define PATHSEP ':'
|
||||
# define PATHSEP ":"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -131,12 +133,20 @@
|
|||
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
|
||||
!defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
|
||||
!defined(TCC_TARGET_X86_64)
|
||||
#define TCC_TARGET_I386
|
||||
#endif
|
||||
|
||||
/* object format selection */
|
||||
#if defined(TCC_TARGET_C67)
|
||||
#define TCC_TARGET_COFF
|
||||
# if defined __x86_64__ || defined _AMD64_
|
||||
# define TCC_TARGET_X86_64
|
||||
# elif defined __arm__
|
||||
# define TCC_TARGET_ARM
|
||||
# define TCC_ARM_EABI
|
||||
# define TCC_ARM_HARDFLOAT
|
||||
# elif defined __aarch64__
|
||||
# define TCC_TARGET_ARM64
|
||||
# else
|
||||
# define TCC_TARGET_I386
|
||||
# endif
|
||||
# ifdef _WIN32
|
||||
# define TCC_TARGET_PE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* only native compiler supports -run */
|
||||
|
@ -166,7 +176,7 @@
|
|||
# define CONFIG_SYSROOT ""
|
||||
#endif
|
||||
#ifndef CONFIG_TCCDIR
|
||||
# define CONFIG_TCCDIR "."
|
||||
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
||||
#endif
|
||||
#ifndef CONFIG_LDDIR
|
||||
# define CONFIG_LDDIR "lib"
|
||||
|
@ -189,7 +199,7 @@
|
|||
/* system include paths */
|
||||
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
|
||||
# ifdef TCC_TARGET_PE
|
||||
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include;{B}/include/winapi"
|
||||
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi"
|
||||
# else
|
||||
# define CONFIG_TCC_SYSINCLUDEPATHS \
|
||||
"{B}/include" \
|
||||
|
@ -280,7 +290,11 @@
|
|||
# define PUB_FUNC
|
||||
#endif
|
||||
|
||||
#ifdef ONE_SOURCE
|
||||
#ifndef ONE_SOURCE
|
||||
# define ONE_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if ONE_SOURCE
|
||||
#define ST_INLN static inline
|
||||
#define ST_FUNC static
|
||||
#define ST_DATA static
|
||||
|
@ -316,6 +330,7 @@
|
|||
# include "arm64-link.c"
|
||||
#endif
|
||||
#ifdef TCC_TARGET_C67
|
||||
# define TCC_TARGET_COFF
|
||||
# include "coff.h"
|
||||
# include "c67-gen.c"
|
||||
# include "c67-link.c"
|
||||
|
@ -341,6 +356,13 @@
|
|||
#endif
|
||||
/* target address type */
|
||||
#define addr_t ElfW(Addr)
|
||||
#define ElfSym ElfW(Sym)
|
||||
|
||||
#if PTR_SIZE == 8 && !defined TCC_TARGET_PE
|
||||
# define LONG_SIZE 8
|
||||
#else
|
||||
# define LONG_SIZE 4
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
|
@ -409,63 +431,65 @@ typedef struct SValue {
|
|||
result of unary() for an identifier. */
|
||||
} SValue;
|
||||
|
||||
struct Attribute {
|
||||
/* symbol attributes */
|
||||
struct SymAttr {
|
||||
unsigned short
|
||||
aligned : 5, /* alignment as log2+1 (0 == unspecified) */
|
||||
packed : 1,
|
||||
weak : 1,
|
||||
visibility : 2,
|
||||
dllexport : 1,
|
||||
nodecorate : 1,
|
||||
dllimport : 1,
|
||||
unused : 4;
|
||||
};
|
||||
|
||||
/* function attributes or temporary attributes for parsing */
|
||||
struct FuncAttr {
|
||||
unsigned
|
||||
func_call : 3, /* calling convention (0..5), see below */
|
||||
aligned : 5, /* alignment as log2+1 (0 == unspecified) */
|
||||
packed : 1,
|
||||
func_export : 1,
|
||||
func_import : 1,
|
||||
func_args : 5,
|
||||
func_body : 1,
|
||||
mode : 4,
|
||||
weak : 1,
|
||||
visibility : 2,
|
||||
unsigned_enum : 1,
|
||||
fill : 7; // 7 bits left to fit well in union below
|
||||
func_call : 3, /* calling convention (0..5), see below */
|
||||
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
|
||||
func_args : 8; /* PE __stdcall args */
|
||||
};
|
||||
|
||||
/* GNUC attribute definition */
|
||||
typedef struct AttributeDef {
|
||||
struct Attribute a;
|
||||
struct SymAttr a;
|
||||
struct FuncAttr f;
|
||||
struct Section *section;
|
||||
int alias_target; /* token */
|
||||
int asm_label; /* associated asm label */
|
||||
int alias_target; /* token */
|
||||
int asm_label; /* associated asm label */
|
||||
char attr_mode; /* __attribute__((__mode__(...))) */
|
||||
} AttributeDef;
|
||||
|
||||
/* symbol management */
|
||||
typedef struct Sym {
|
||||
int v; /* symbol token */
|
||||
int v; /* symbol token */
|
||||
unsigned short r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
|
||||
struct SymAttr a; /* symbol attributes */
|
||||
union {
|
||||
int asm_label; /* associated asm label */
|
||||
int scope; /* scope level for locals */
|
||||
struct {
|
||||
int c; /* associated number or Elf symbol index */
|
||||
union {
|
||||
int sym_scope; /* scope level for locals */
|
||||
int jnext; /* next jump label */
|
||||
struct FuncAttr f; /* function attributes */
|
||||
int auxtype; /* bitfield access type */
|
||||
};
|
||||
};
|
||||
long long enum_val; /* enum constant if IS_ENUM_VAL */
|
||||
int *d; /* define token stream */
|
||||
};
|
||||
union {
|
||||
long r; /* associated register or VT_CONST/VT_LOCAL and LVAL type */
|
||||
struct Attribute a;
|
||||
};
|
||||
union {
|
||||
long c; /* associated number */
|
||||
int *d; /* define token stream */
|
||||
};
|
||||
CType type; /* associated type */
|
||||
CType type; /* associated type */
|
||||
union {
|
||||
struct Sym *next; /* next related symbol (for fields and anoms) */
|
||||
long jnext; /* next jump label */
|
||||
int asm_label; /* associated asm label */
|
||||
};
|
||||
struct Sym *prev; /* prev symbol in stack */
|
||||
struct Sym *prev_tok; /* previous symbol for this token */
|
||||
} Sym;
|
||||
|
||||
/* section definition */
|
||||
/* XXX: use directly ELF structure for parameters ? */
|
||||
/* special flag to indicate that the section should not be linked to
|
||||
the other ones */
|
||||
#define SHF_PRIVATE 0x80000000
|
||||
|
||||
/* special flag, too */
|
||||
#define SECTION_ABS ((void *)1)
|
||||
|
||||
typedef struct Section {
|
||||
unsigned long data_offset; /* current data offset */
|
||||
unsigned char *data; /* section data */
|
||||
|
@ -500,12 +524,12 @@ typedef struct DLLReference {
|
|||
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
|
||||
#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
|
||||
|
||||
/* stored in 'Sym.c' field */
|
||||
/* stored in 'Sym->f.func_type' field */
|
||||
#define FUNC_NEW 1 /* ansi function prototype */
|
||||
#define FUNC_OLD 2 /* old function prototype */
|
||||
#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
|
||||
|
||||
/* stored in 'Sym.r' field */
|
||||
/* stored in 'Sym->f.func_call' field */
|
||||
#define FUNC_CDECL 0 /* standard c call */
|
||||
#define FUNC_STDCALL 1 /* pascal c call */
|
||||
#define FUNC_FASTCALL1 2 /* first param in %eax */
|
||||
|
@ -540,7 +564,7 @@ typedef struct BufferedFile {
|
|||
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
|
||||
int include_next_index; /* next search path */
|
||||
char filename[1024]; /* filename */
|
||||
char filename2[1024]; /* filename not modified by # line directive */
|
||||
char *true_filename; /* filename not modified by # line directive */
|
||||
unsigned char unget[4];
|
||||
unsigned char buffer[1]; /* extra size for CH_EOB char */
|
||||
} BufferedFile;
|
||||
|
@ -548,21 +572,14 @@ typedef struct BufferedFile {
|
|||
#define CH_EOB '\\' /* end of buffer or '\0' char in file */
|
||||
#define CH_EOF (-1) /* end of file */
|
||||
|
||||
/* parsing state (used to save parser state to reparse part of the
|
||||
source several times) */
|
||||
typedef struct ParseState {
|
||||
const int *macro_ptr;
|
||||
int line_num;
|
||||
int tok;
|
||||
CValue tokc;
|
||||
} ParseState;
|
||||
|
||||
/* used to record tokens */
|
||||
typedef struct TokenString {
|
||||
int *str;
|
||||
int len;
|
||||
int lastlen;
|
||||
int allocated_len;
|
||||
int last_line_num;
|
||||
int save_line_num;
|
||||
/* used to chain token-strings with begin/end_macro() */
|
||||
struct TokenString *prev;
|
||||
const int *prev_ptr;
|
||||
|
@ -622,7 +639,6 @@ 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 */
|
||||
|
@ -630,7 +646,7 @@ struct TCCState {
|
|||
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 */
|
||||
int filetype; /* file type for compilation (NONE,C,ASM) */
|
||||
|
||||
char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
|
||||
char *soname; /* as specified on the command line (-soname) */
|
||||
|
@ -666,6 +682,7 @@ struct TCCState {
|
|||
#ifdef TCC_TARGET_ARM
|
||||
enum float_abi float_abi; /* float ABI of the generated code*/
|
||||
#endif
|
||||
int run_test; /* nth test to run with -dt -run */
|
||||
|
||||
addr_t text_addr; /* address of text section */
|
||||
int has_text_addr;
|
||||
|
@ -674,7 +691,7 @@ struct TCCState {
|
|||
|
||||
char *init_symbol; /* symbols to call at load-time (not used currently) */
|
||||
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
|
||||
|
||||
|
||||
#ifdef TCC_TARGET_I386
|
||||
int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
|
||||
#endif
|
||||
|
@ -769,8 +786,6 @@ struct TCCState {
|
|||
/* extra attributes (eg. GOT/PLT value) for symtab symbols */
|
||||
struct sym_attr *sym_attrs;
|
||||
int nb_sym_attrs;
|
||||
/* tiny assembler state */
|
||||
Sym *asm_labels;
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
/* PE info */
|
||||
|
@ -778,6 +793,7 @@ struct TCCState {
|
|||
unsigned pe_characteristics;
|
||||
unsigned pe_file_align;
|
||||
unsigned pe_stack_size;
|
||||
addr_t pe_imagebase;
|
||||
# ifdef TCC_TARGET_X86_64
|
||||
Section *uw_pdata;
|
||||
int uw_sym;
|
||||
|
@ -795,7 +811,6 @@ struct TCCState {
|
|||
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 */
|
||||
|
@ -808,7 +823,6 @@ struct TCCState {
|
|||
|
||||
struct filespec {
|
||||
char type;
|
||||
char alacarte;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
|
@ -835,53 +849,57 @@ struct filespec {
|
|||
|
||||
/* types */
|
||||
#define VT_BTYPE 0x000f /* mask for basic type */
|
||||
#define VT_INT 0 /* integer type */
|
||||
#define VT_VOID 0 /* void type */
|
||||
#define VT_BYTE 1 /* signed byte type */
|
||||
#define VT_SHORT 2 /* short type */
|
||||
#define VT_VOID 3 /* void type */
|
||||
#define VT_PTR 4 /* pointer */
|
||||
#define VT_ENUM 5 /* enum definition */
|
||||
#define VT_INT 3 /* integer type */
|
||||
#define VT_LLONG 4 /* 64 bit integer */
|
||||
#define VT_PTR 5 /* pointer */
|
||||
#define VT_FUNC 6 /* function type */
|
||||
#define VT_STRUCT 7 /* struct/union definition */
|
||||
#define VT_FLOAT 8 /* IEEE float */
|
||||
#define VT_DOUBLE 9 /* IEEE double */
|
||||
#define VT_LDOUBLE 10 /* IEEE long double */
|
||||
#define VT_BOOL 11 /* ISOC99 boolean type */
|
||||
#define VT_LLONG 12 /* 64 bit integer */
|
||||
#define VT_LONG 13 /* long integer (NEVER USED as type, only
|
||||
during parsing) */
|
||||
#define VT_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */
|
||||
#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */
|
||||
#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */
|
||||
#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */
|
||||
|
||||
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
||||
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
|
||||
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
||||
#define VT_CONSTANT 0x0800 /* const modifier */
|
||||
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
||||
#define VT_DEFSIGN 0x2000 /* signed type */
|
||||
#define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
||||
#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */
|
||||
#define VT_ARRAY 0x0040 /* array type (also has VT_PTR) */
|
||||
#define VT_BITFIELD 0x0080 /* bitfield modifier */
|
||||
#define VT_CONSTANT 0x0100 /* const modifier */
|
||||
#define VT_VOLATILE 0x0200 /* volatile modifier */
|
||||
#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
||||
#define VT_LONG 0x0800 /* long type (also has VT_INT rsp. VT_LLONG) */
|
||||
|
||||
/* storage */
|
||||
#define VT_EXTERN 0x00000080 /* extern definition */
|
||||
#define VT_STATIC 0x00000100 /* static variable */
|
||||
#define VT_TYPEDEF 0x00000200 /* typedef definition */
|
||||
#define VT_INLINE 0x00000400 /* inline definition */
|
||||
#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */
|
||||
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
|
||||
#define VT_WEAK 0x00010000 /* weak symbol */
|
||||
#define VT_TLS 0x00040000 /* thread-local storage */
|
||||
#define VT_VIS_SHIFT 19 /* shift for symbol visibility, overlapping
|
||||
bitfield values, because bitfields never
|
||||
have linkage and hence never have
|
||||
visibility. */
|
||||
#define VT_VIS_SIZE 2 /* We have four visibilities. */
|
||||
#define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT)
|
||||
#define VT_EXTERN 0x00001000 /* extern definition */
|
||||
#define VT_STATIC 0x00002000 /* static variable */
|
||||
#define VT_TYPEDEF 0x00004000 /* typedef definition */
|
||||
#define VT_INLINE 0x00008000 /* inline definition */
|
||||
/* currently unused: 0x000[1248]0000 */
|
||||
|
||||
#define VT_STRUCT_SHIFT 19 /* shift for bitfield shift values (max: 32 - 2*6) */
|
||||
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
|
||||
#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
|
||||
#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
|
||||
#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
|
||||
|
||||
#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT)
|
||||
#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */
|
||||
#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
|
||||
|
||||
#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM)
|
||||
#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL)
|
||||
#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
|
||||
|
||||
/* type mask (except storage) */
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK | VT_VIS_MASK)
|
||||
#define VT_TYPE (~(VT_STORAGE))
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
||||
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
|
||||
|
||||
/* symbol was created by tccasm.c first */
|
||||
#define VT_ASM (VT_VOID | VT_UNSIGNED)
|
||||
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
|
||||
|
||||
/* token values */
|
||||
|
||||
|
@ -923,6 +941,7 @@ struct filespec {
|
|||
#define TOK_PPNUM 0xbe /* preprocessor number */
|
||||
#define TOK_PPSTR 0xbf /* preprocessor string */
|
||||
#define TOK_LINENUM 0xc0 /* line number info */
|
||||
#define TOK_TWODOTS 0xa8 /* C++ token ? */
|
||||
/* <-- */
|
||||
|
||||
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
|
||||
|
@ -936,11 +955,13 @@ struct filespec {
|
|||
#define TOK_TWOSHARPS 0xca /* ## preprocessing token */
|
||||
#define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */
|
||||
#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */
|
||||
#define TOK_PPJOIN 0xce /* A '##' in the right position to mean pasting */
|
||||
#define TOK_PPJOIN 0xcd /* A '##' in the right position to mean pasting */
|
||||
#define TOK_CLONG 0xce /* long constant */
|
||||
#define TOK_CULONG 0xcf /* unsigned long constant */
|
||||
|
||||
#define TOK_SHL 0x01 /* shift left */
|
||||
#define TOK_SAR 0x02 /* signed shift right */
|
||||
|
||||
|
||||
/* assignment operators : normal operator or 0x80 */
|
||||
#define TOK_A_MOD 0xa5
|
||||
#define TOK_A_AND 0xa6
|
||||
|
@ -953,14 +974,6 @@ struct filespec {
|
|||
#define TOK_A_SHL 0x81
|
||||
#define TOK_A_SAR 0x82
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#ifndef countof
|
||||
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
|
||||
#endif
|
||||
|
||||
#define TOK_EOF (-1) /* end of file */
|
||||
#define TOK_LINEFEED 10 /* line feed */
|
||||
|
||||
|
@ -1118,13 +1131,13 @@ ST_FUNC void cstr_free(CString *cstr);
|
|||
ST_FUNC void cstr_reset(CString *cstr);
|
||||
|
||||
ST_INLN void sym_free(Sym *sym);
|
||||
ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c);
|
||||
ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c);
|
||||
ST_FUNC Sym *sym_find2(Sym *s, int v);
|
||||
ST_FUNC Sym *sym_push(int v, CType *type, int r, long c);
|
||||
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c);
|
||||
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep);
|
||||
ST_INLN Sym *struct_find(int v);
|
||||
ST_INLN Sym *sym_find(int v);
|
||||
ST_FUNC Sym *global_identifier_push(int v, int t, long c);
|
||||
ST_FUNC Sym *global_identifier_push(int v, int t, int c);
|
||||
|
||||
ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
|
||||
ST_FUNC int tcc_open(TCCState *s1, const char *filename);
|
||||
|
@ -1134,14 +1147,15 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
|||
/* flags: */
|
||||
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */
|
||||
#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */
|
||||
#define AFF_PREPROCESS 0x40 /* preprocess file */
|
||||
/* combined with: */
|
||||
#define AFF_TYPE_BIN 0x40 /* file to add is binary */
|
||||
#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_BIN 4
|
||||
#define AFF_TYPE_LIB 5
|
||||
#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
|
||||
|
@ -1209,9 +1223,7 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len);
|
|||
ST_FUNC const char *get_tok_str(int v, CValue *cv);
|
||||
ST_FUNC void begin_macro(TokenString *str, int alloc);
|
||||
ST_FUNC void end_macro(void);
|
||||
ST_FUNC void set_idnum(int c, int val);
|
||||
ST_FUNC void save_parse_state(ParseState *s);
|
||||
ST_FUNC void restore_parse_state(ParseState *s);
|
||||
ST_FUNC int set_idnum(int c, int val);
|
||||
ST_INLN void tok_str_new(TokenString *s);
|
||||
ST_FUNC TokenString *tok_str_alloc(void);
|
||||
ST_FUNC void tok_str_free(TokenString *s);
|
||||
|
@ -1224,13 +1236,14 @@ ST_INLN Sym *define_find(int v);
|
|||
ST_FUNC void free_defines(Sym *b);
|
||||
ST_FUNC Sym *label_find(int v);
|
||||
ST_FUNC Sym *label_push(Sym **ptop, int v, int flags);
|
||||
ST_FUNC void label_pop(Sym **ptop, Sym *slast);
|
||||
ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep);
|
||||
ST_FUNC void parse_define(void);
|
||||
ST_FUNC void preprocess(int is_bof);
|
||||
ST_FUNC void next_nomacro(void);
|
||||
ST_FUNC void next(void);
|
||||
ST_INLN void unget_tok(int last_tok);
|
||||
ST_FUNC void preprocess_start(TCCState *s1);
|
||||
ST_FUNC void preprocess_start(TCCState *s1, int is_asm);
|
||||
ST_FUNC void preprocess_end(TCCState *s1);
|
||||
ST_FUNC void tccpp_new(TCCState *s);
|
||||
ST_FUNC void tccpp_delete(TCCState *s);
|
||||
ST_FUNC int tcc_preprocess(TCCState *s1);
|
||||
|
@ -1279,6 +1292,7 @@ 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);
|
||||
|
@ -1286,9 +1300,7 @@ ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
|
|||
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
|
||||
ST_FUNC void tcc_debug_line(TCCState *s1);
|
||||
|
||||
ST_FUNC void tccgen_start(TCCState *s1);
|
||||
ST_FUNC void tccgen_end(TCCState *s1);
|
||||
|
||||
ST_FUNC int tccgen_compile(TCCState *s1);
|
||||
ST_FUNC void free_inline_functions(TCCState *s);
|
||||
ST_FUNC void check_vstack(void);
|
||||
|
||||
|
@ -1296,8 +1308,10 @@ ST_INLN int is_float(int t);
|
|||
ST_FUNC int ieee_finite(double d);
|
||||
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 void vset(CType *type, int r, long v);
|
||||
ST_FUNC void vset(CType *type, int r, int v);
|
||||
ST_FUNC void vswap(void);
|
||||
ST_FUNC void vpush_global_sym(CType *type, int v);
|
||||
ST_FUNC void vrote(SValue *e, int n);
|
||||
|
@ -1330,7 +1344,6 @@ ST_FUNC void expr_prod(void);
|
|||
ST_FUNC void expr_sum(void);
|
||||
ST_FUNC void gexpr(void);
|
||||
ST_FUNC int expr_const(void);
|
||||
ST_FUNC void decl(int l);
|
||||
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
|
||||
ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size);
|
||||
#endif
|
||||
|
@ -1367,13 +1380,15 @@ ST_DATA Section *lbounds_section; /* contains local data bound description */
|
|||
ST_FUNC void tccelf_bounds_new(TCCState *s);
|
||||
#endif
|
||||
/* symbol sections */
|
||||
ST_DATA Section *symtab_section, *strtab_section;
|
||||
ST_DATA Section *symtab_section;
|
||||
/* debug sections */
|
||||
ST_DATA Section *stab_section, *stabstr_section;
|
||||
|
||||
ST_FUNC void tccelf_new(TCCState *s);
|
||||
ST_FUNC void tccelf_delete(TCCState *s);
|
||||
ST_FUNC void tccelf_stab_new(TCCState *s);
|
||||
ST_FUNC void tccelf_begin_file(TCCState *s1);
|
||||
ST_FUNC void tccelf_end_file(TCCState *s1);
|
||||
|
||||
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
|
||||
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
|
||||
|
@ -1383,7 +1398,7 @@ ST_FUNC void section_reserve(Section *sec, unsigned long size);
|
|||
ST_FUNC Section *find_section(TCCState *s1, const char *name);
|
||||
ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
|
||||
|
||||
ST_FUNC void put_extern_sym2(Sym *sym, Section *section, addr_t value, unsigned long size, int can_add_underscore);
|
||||
ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, addr_t value, unsigned long size, int can_add_underscore);
|
||||
ST_FUNC void put_extern_sym(Sym *sym, Section *section, addr_t value, unsigned long size);
|
||||
#if PTR_SIZE == 4
|
||||
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
|
||||
|
@ -1402,14 +1417,13 @@ ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigne
|
|||
ST_FUNC void put_stabn(int type, int other, int desc, int value);
|
||||
ST_FUNC void put_stabd(int type, int other, int desc);
|
||||
|
||||
ST_FUNC void relocate_common_syms(void);
|
||||
ST_FUNC void resolve_common_syms(TCCState *s1);
|
||||
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
|
||||
ST_FUNC void relocate_section(TCCState *s1, Section *s);
|
||||
|
||||
ST_FUNC void tcc_add_linker_symbols(TCCState *s1);
|
||||
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
|
||||
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
|
||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd);
|
||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1);
|
||||
ST_FUNC void tcc_add_runtime(TCCState *s1);
|
||||
|
||||
|
@ -1433,7 +1447,7 @@ ST_FUNC int handle_eob(void);
|
|||
|
||||
/* ------------ xxx-link.c ------------ */
|
||||
|
||||
/* Wether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
|
||||
/* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
|
||||
that unknown relocation don't create a GOT or PLT entry */
|
||||
enum gotplt_entry {
|
||||
NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */
|
||||
|
@ -1461,6 +1475,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *reg
|
|||
ST_FUNC void gfunc_call(int nb_args);
|
||||
ST_FUNC void gfunc_prolog(CType *func_type);
|
||||
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);
|
||||
|
@ -1488,13 +1503,13 @@ static inline uint16_t read16le(unsigned char *p) {
|
|||
return p[0] | (uint16_t)p[1] << 8;
|
||||
}
|
||||
static inline void write16le(unsigned char *p, uint16_t x) {
|
||||
p[0] = x & 255, p[1] = x >> 8 & 255;
|
||||
p[0] = x & 255; p[1] = x >> 8 & 255;
|
||||
}
|
||||
static inline uint32_t read32le(unsigned char *p) {
|
||||
return read16le(p) | (uint32_t)read16le(p + 2) << 16;
|
||||
}
|
||||
static inline void write32le(unsigned char *p, uint32_t x) {
|
||||
write16le(p, x), write16le(p + 2, x >> 16);
|
||||
write16le(p, x); write16le(p + 2, x >> 16);
|
||||
}
|
||||
static inline void add32le(unsigned char *p, int32_t x) {
|
||||
write32le(p, read32le(p) + x);
|
||||
|
@ -1503,7 +1518,7 @@ static inline uint64_t read64le(unsigned char *p) {
|
|||
return read32le(p) | (uint64_t)read32le(p + 4) << 32;
|
||||
}
|
||||
static inline void write64le(unsigned char *p, uint64_t x) {
|
||||
write32le(p, x), write32le(p + 4, x >> 32);
|
||||
write32le(p, x); write32le(p + 4, x >> 32);
|
||||
}
|
||||
static inline void add64le(unsigned char *p, int64_t x) {
|
||||
write64le(p, read64le(p) + x);
|
||||
|
@ -1514,8 +1529,8 @@ static inline void add64le(unsigned char *p, int64_t x) {
|
|||
ST_FUNC void g(int c);
|
||||
ST_FUNC void gen_le16(int c);
|
||||
ST_FUNC void gen_le32(int c);
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, long c);
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, long c);
|
||||
ST_FUNC void gen_addr32(int r, Sym *sym, int c);
|
||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|
@ -1527,6 +1542,9 @@ ST_FUNC void gen_bounded_ptr_deref(void);
|
|||
#ifdef TCC_TARGET_X86_64
|
||||
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
|
||||
ST_FUNC void gen_opl(int op);
|
||||
#ifdef TCC_TARGET_PE
|
||||
ST_FUNC void gen_vla_result(int addr);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ------------ arm-gen.c ------------ */
|
||||
|
@ -1586,7 +1604,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str);
|
|||
ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd);
|
||||
ST_FUNC int pe_output_file(TCCState * s1, const char *filename);
|
||||
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value);
|
||||
#ifndef TCC_TARGET_ARM
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2);
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
|
@ -1598,6 +1616,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
|
|||
# define ST_PE_IMPORT 0x20
|
||||
# define ST_PE_STDCALL 0x40
|
||||
#endif
|
||||
#define ST_ASM_SET 0x04
|
||||
|
||||
/* ------------ tccrun.c ----------------- */
|
||||
#ifdef TCC_IS_NATIVE
|
||||
|
@ -1633,7 +1652,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
|
|||
|
||||
/********************************************************/
|
||||
#undef ST_DATA
|
||||
#ifdef ONE_SOURCE
|
||||
#if ONE_SOURCE
|
||||
#define ST_DATA static
|
||||
#else
|
||||
#define ST_DATA
|
||||
|
|
280
tccasm.c
280
tccasm.c
|
@ -31,55 +31,59 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
|||
return ts->tok;
|
||||
}
|
||||
|
||||
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
|
||||
static Sym sym_dot;
|
||||
static Sym* asm_new_label(TCCState *s1, int label, int is_local);
|
||||
static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
|
||||
|
||||
static Sym *asm_label_find(int v)
|
||||
{
|
||||
Sym *sym = sym_find(v);
|
||||
while (sym && sym->sym_scope)
|
||||
sym = sym->prev_tok;
|
||||
return sym;
|
||||
}
|
||||
|
||||
static Sym *asm_label_push(int v)
|
||||
{
|
||||
/* We always add VT_EXTERN, for sym definition that's tentative
|
||||
(for .set, removed for real defs), for mere references it's correct
|
||||
as is. */
|
||||
Sym *sym = global_identifier_push(v, VT_ASM | VT_EXTERN | VT_STATIC, 0);
|
||||
sym->r = VT_CONST | VT_SYM;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* Return a symbol we can use inside the assembler, having name NAME.
|
||||
The assembler symbol table is different from the C symbol table
|
||||
(and the Sym members are used differently). But we must be able
|
||||
to look up file-global C symbols from inside the assembler, e.g.
|
||||
for global asm blocks to be able to refer to defined C symbols.
|
||||
Symbols from asm and C source share a namespace. If we generate
|
||||
an asm symbol it's also a (file-global) C symbol, but it's
|
||||
either not accessible by name (like "L.123"), or its type information
|
||||
is such that it's not usable without a proper C declaration.
|
||||
|
||||
This routine gives back either an existing asm-internal
|
||||
symbol, or a new one. In the latter case the new asm-internal
|
||||
symbol is initialized with info from the C symbol table.
|
||||
|
||||
If CSYM is non-null we take symbol info from it, otherwise
|
||||
we look up NAME in the C symbol table and use that. */
|
||||
Sometimes we need symbols accessible by name from asm, which
|
||||
are anonymous in C, in this case CSYM can be used to transfer
|
||||
all information from that symbol to the (possibly newly created)
|
||||
asm symbol. */
|
||||
ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
|
||||
{
|
||||
Sym *sym = label_find(name);
|
||||
Sym *sym = asm_label_find(name);
|
||||
if (!sym) {
|
||||
sym = label_push(&tcc_state->asm_labels, name, 0);
|
||||
sym->type.t = VT_VOID | VT_EXTERN;
|
||||
if (!csym) {
|
||||
csym = sym_find(name);
|
||||
/* We might be called for an asm block from inside a C routine
|
||||
and so might have local decls on the identifier stack. Search
|
||||
for the first global one. */
|
||||
while (csym && csym->scope)
|
||||
csym = csym->prev_tok;
|
||||
}
|
||||
/* Now, if we have a defined global symbol copy over
|
||||
section and offset. */
|
||||
if (csym &&
|
||||
((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
|
||||
csym->c) {
|
||||
ElfW(Sym) *esym;
|
||||
esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
|
||||
sym->c = csym->c;
|
||||
sym->r = esym->st_shndx;
|
||||
sym->jnext = esym->st_value;
|
||||
/* XXX can't yet store st_size anywhere. */
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
/* Mark that this asm symbol doesn't need to be fed back. */
|
||||
sym->type.t |= VT_IMPORT;
|
||||
}
|
||||
sym = asm_label_push(name);
|
||||
if (csym)
|
||||
sym->c = csym->c;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
static Sym* asm_section_sym(TCCState *s1, Section *sec)
|
||||
{
|
||||
char buf[100];
|
||||
int label = tok_alloc(buf,
|
||||
snprintf(buf, sizeof buf, "L.%s", sec->name)
|
||||
)->tok;
|
||||
Sym *sym = asm_label_find(label);
|
||||
return sym ? sym : asm_new_label1(s1, label, 1, sec->sh_num, 0);
|
||||
}
|
||||
|
||||
/* We do not use the C expression parser to handle symbols. Maybe the
|
||||
C expression parser could be tweaked to do so. */
|
||||
|
||||
|
@ -97,19 +101,18 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
|||
if (*p == 'b' || *p == 'f') {
|
||||
/* backward or forward label */
|
||||
label = asm_get_local_label_name(s1, n);
|
||||
sym = label_find(label);
|
||||
sym = asm_label_find(label);
|
||||
if (*p == 'b') {
|
||||
/* backward : find the last corresponding defined label */
|
||||
if (sym && sym->r == 0)
|
||||
if (sym && (!sym->c || elfsym(sym)->st_shndx == SHN_UNDEF))
|
||||
sym = sym->prev_tok;
|
||||
if (!sym)
|
||||
tcc_error("local label '%d' not found backward", n);
|
||||
} else {
|
||||
/* forward */
|
||||
if (!sym || sym->r) {
|
||||
if (!sym || (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)) {
|
||||
/* if the last label is defined, then define a new one */
|
||||
sym = label_push(&s1->asm_labels, label, 0);
|
||||
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
|
||||
sym = asm_label_push(label);
|
||||
}
|
||||
}
|
||||
pe->v = 0;
|
||||
|
@ -153,21 +156,20 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
|
|||
skip(')');
|
||||
break;
|
||||
case '.':
|
||||
pe->v = 0;
|
||||
pe->sym = &sym_dot;
|
||||
pe->pcrel = 0;
|
||||
sym_dot.type.t = VT_VOID | VT_STATIC;
|
||||
sym_dot.r = cur_text_section->sh_num;
|
||||
sym_dot.jnext = ind;
|
||||
pe->v = ind;
|
||||
pe->sym = asm_section_sym(s1, cur_text_section);
|
||||
pe->pcrel = 0;
|
||||
next();
|
||||
break;
|
||||
default:
|
||||
if (tok >= TOK_IDENT) {
|
||||
ElfSym *esym;
|
||||
/* label case : if the label was not found, add one */
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (sym->r == SHN_ABS) {
|
||||
esym = elfsym(sym);
|
||||
if (esym && esym->st_shndx == SHN_ABS) {
|
||||
/* if absolute symbol, no need to put a symbol value */
|
||||
pe->v = sym->jnext;
|
||||
pe->v = esym->st_value;
|
||||
pe->sym = NULL;
|
||||
pe->pcrel = 0;
|
||||
} else {
|
||||
|
@ -281,20 +283,26 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
|
|||
} else if (pe->sym == e2.sym) {
|
||||
/* OK */
|
||||
pe->sym = NULL; /* same symbols can be subtracted to NULL */
|
||||
} else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
|
||||
/* we also accept defined symbols in the same section */
|
||||
pe->v += pe->sym->jnext - e2.sym->jnext;
|
||||
pe->sym = NULL;
|
||||
} else if (e2.sym->r == cur_text_section->sh_num) {
|
||||
/* When subtracting a defined symbol in current section
|
||||
this actually makes the value PC-relative. */
|
||||
pe->v -= e2.sym->jnext - ind - 4;
|
||||
pe->pcrel = 1;
|
||||
e2.sym = NULL;
|
||||
} else {
|
||||
cannot_relocate:
|
||||
tcc_error("invalid operation with label");
|
||||
}
|
||||
} else {
|
||||
ElfSym *esym1, *esym2;
|
||||
esym1 = elfsym(pe->sym);
|
||||
esym2 = elfsym(e2.sym);
|
||||
if (esym1 && esym1->st_shndx == esym2->st_shndx
|
||||
&& esym1->st_shndx != SHN_UNDEF) {
|
||||
/* we also accept defined symbols in the same section */
|
||||
pe->v += esym1->st_value - esym2->st_value;
|
||||
pe->sym = NULL;
|
||||
} else if (esym2->st_shndx == cur_text_section->sh_num) {
|
||||
/* When subtracting a defined symbol in current section
|
||||
this actually makes the value PC-relative. */
|
||||
pe->v -= esym2->st_value - ind - 4;
|
||||
pe->pcrel = 1;
|
||||
e2.sym = NULL;
|
||||
} else {
|
||||
cannot_relocate:
|
||||
tcc_error("invalid operation with label");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -355,38 +363,38 @@ ST_FUNC int asm_int_expr(TCCState *s1)
|
|||
return e.v;
|
||||
}
|
||||
|
||||
/* NOTE: the same name space as C labels is used to avoid using too
|
||||
much memory when storing labels in TokenStrings */
|
||||
static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
|
||||
int sh_num, int value)
|
||||
{
|
||||
Sym *sym;
|
||||
ElfSym *esym;
|
||||
|
||||
sym = label_find(label);
|
||||
sym = asm_label_find(label);
|
||||
if (sym) {
|
||||
esym = elfsym(sym);
|
||||
/* A VT_EXTERN symbol, even if it has a section is considered
|
||||
overridable. This is how we "define" .set targets. Real
|
||||
definitions won't have VT_EXTERN set. */
|
||||
if (sym->r && !(sym->type.t & VT_EXTERN)) {
|
||||
if (esym && esym->st_shndx != SHN_UNDEF) {
|
||||
/* the label is already defined */
|
||||
if (!is_local) {
|
||||
tcc_error("assembler label '%s' already defined",
|
||||
get_tok_str(label, NULL));
|
||||
} else {
|
||||
/* redefinition of local labels is possible */
|
||||
if (IS_ASM_SYM(sym)
|
||||
&& (is_local == 1 || (sym->type.t & VT_EXTERN)))
|
||||
goto new_label;
|
||||
}
|
||||
if (!(sym->type.t & VT_EXTERN))
|
||||
tcc_error("assembler label '%s' already defined",
|
||||
get_tok_str(label, NULL));
|
||||
}
|
||||
} else {
|
||||
new_label:
|
||||
sym = label_push(&s1->asm_labels, label, 0);
|
||||
/* If we need a symbol to hold a value, mark it as
|
||||
tentative only (for .set). If this is for a real label
|
||||
we'll remove VT_EXTERN. */
|
||||
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
|
||||
sym = asm_label_push(label);
|
||||
}
|
||||
sym->r = sh_num;
|
||||
sym->jnext = value;
|
||||
if (!sym->c)
|
||||
put_extern_sym2(sym, SHN_UNDEF, 0, 0, 0);
|
||||
esym = elfsym(sym);
|
||||
esym->st_shndx = sh_num;
|
||||
esym->st_value = value;
|
||||
if (is_local != 2)
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
@ -401,35 +409,17 @@ static Sym* set_symbol(TCCState *s1, int label)
|
|||
{
|
||||
long n;
|
||||
ExprValue e;
|
||||
Sym *sym;
|
||||
ElfSym *esym;
|
||||
next();
|
||||
asm_expr(s1, &e);
|
||||
n = e.v;
|
||||
if (e.sym)
|
||||
n += e.sym->jnext;
|
||||
return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
|
||||
}
|
||||
|
||||
static void asm_free_labels(TCCState *st)
|
||||
{
|
||||
Sym *s, *s1;
|
||||
Section *sec;
|
||||
|
||||
for(s = st->asm_labels; s != NULL; s = s1) {
|
||||
s1 = s->prev;
|
||||
/* define symbol value in object file */
|
||||
s->type.t &= ~VT_EXTERN;
|
||||
if (s->r && !(s->type.t & VT_IMPORT)) {
|
||||
if (s->r == SHN_ABS)
|
||||
sec = SECTION_ABS;
|
||||
else
|
||||
sec = st->sections[s->r];
|
||||
put_extern_sym2(s, sec, s->jnext, 0, 0);
|
||||
}
|
||||
/* remove label */
|
||||
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
|
||||
sym_free(s);
|
||||
}
|
||||
st->asm_labels = NULL;
|
||||
esym = elfsym(e.sym);
|
||||
if (esym)
|
||||
n += esym->st_value;
|
||||
sym = asm_new_label1(s1, label, 2, esym ? esym->st_shndx : SHN_ABS, n);
|
||||
elfsym(sym)->st_other |= ST_ASM_SET;
|
||||
return sym;
|
||||
}
|
||||
|
||||
static void use_section1(TCCState *s1, Section *sec)
|
||||
|
@ -628,20 +618,16 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
{
|
||||
int repeat;
|
||||
TokenString *init_str;
|
||||
ParseState saved_parse_state = {0};
|
||||
next();
|
||||
repeat = asm_int_expr(s1);
|
||||
init_str = tok_str_alloc();
|
||||
next();
|
||||
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
|
||||
while (next(), tok != TOK_ASMDIR_endr) {
|
||||
if (tok == CH_EOF)
|
||||
tcc_error("we at end of file, .endr not found");
|
||||
tok_str_add_tok(init_str);
|
||||
next();
|
||||
}
|
||||
if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
|
||||
next();
|
||||
tok_str_add(init_str, -1);
|
||||
tok_str_add(init_str, 0);
|
||||
save_parse_state(&saved_parse_state);
|
||||
begin_macro(init_str, 1);
|
||||
while (repeat-- > 0) {
|
||||
tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS),
|
||||
|
@ -649,20 +635,22 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
macro_ptr = init_str->str;
|
||||
}
|
||||
end_macro();
|
||||
restore_parse_state(&saved_parse_state);
|
||||
next();
|
||||
break;
|
||||
}
|
||||
case TOK_ASMDIR_org:
|
||||
{
|
||||
unsigned long n;
|
||||
ExprValue e;
|
||||
ElfSym *esym;
|
||||
next();
|
||||
asm_expr(s1, &e);
|
||||
n = e.v;
|
||||
if (e.sym) {
|
||||
if (e.sym->r != cur_text_section->sh_num)
|
||||
esym = elfsym(e.sym);
|
||||
if (esym) {
|
||||
if (esym->st_shndx != cur_text_section->sh_num)
|
||||
expect("constant or same-section symbol");
|
||||
n += e.sym->jnext;
|
||||
n += esym->st_value;
|
||||
}
|
||||
if (n < ind)
|
||||
tcc_error("attempt to .org backwards");
|
||||
|
@ -687,15 +675,15 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
tok1 = tok;
|
||||
do {
|
||||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = get_asm_sym(tok, NULL);
|
||||
if (tok1 != TOK_ASMDIR_hidden)
|
||||
sym->type.t &= ~VT_STATIC;
|
||||
if (tok1 == TOK_ASMDIR_weak)
|
||||
sym->type.t |= VT_WEAK;
|
||||
sym->a.weak = 1;
|
||||
else if (tok1 == TOK_ASMDIR_hidden)
|
||||
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
|
||||
sym->a.visibility = STV_HIDDEN;
|
||||
update_storage(sym);
|
||||
next();
|
||||
} while (tok == ',');
|
||||
break;
|
||||
|
@ -786,7 +774,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
Sym *sym;
|
||||
|
||||
next();
|
||||
sym = label_find(tok);
|
||||
sym = asm_label_find(tok);
|
||||
if (!sym) {
|
||||
tcc_error("label not found: %s", get_tok_str(tok, NULL));
|
||||
}
|
||||
|
@ -917,13 +905,9 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
||||
{
|
||||
int opcode;
|
||||
int saved_parse_flags = parse_flags;
|
||||
|
||||
/* XXX: undefine C labels */
|
||||
|
||||
ch = file->buf_ptr[0];
|
||||
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
|
||||
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
|
||||
set_idnum('.', IS_ID);
|
||||
if (do_preprocess)
|
||||
parse_flags |= PARSE_FLAG_PREPROCESS;
|
||||
for(;;) {
|
||||
|
@ -942,7 +926,6 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
|||
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
|
||||
asm_parse_directive(s1, global);
|
||||
} else if (tok == TOK_PPNUM) {
|
||||
Sym *sym;
|
||||
const char *p;
|
||||
int n;
|
||||
p = tokc.str.data;
|
||||
|
@ -950,9 +933,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
|||
if (*p != '\0')
|
||||
expect("':'");
|
||||
/* new local label */
|
||||
sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
|
||||
/* Remove the marker for tentative definitions. */
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
|
||||
next();
|
||||
skip(':');
|
||||
goto redo;
|
||||
|
@ -961,19 +942,8 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
|||
opcode = tok;
|
||||
next();
|
||||
if (tok == ':') {
|
||||
/* handle "extern void vide(void); __asm__("vide: ret");" as
|
||||
"__asm__("globl vide\nvide: ret");" */
|
||||
Sym *sym = sym_find(opcode);
|
||||
if (sym && (sym->type.t & VT_EXTERN) && global) {
|
||||
sym = label_find(opcode);
|
||||
if (!sym) {
|
||||
sym = label_push(&s1->asm_labels, opcode, 0);
|
||||
sym->type.t = VT_VOID | VT_EXTERN;
|
||||
}
|
||||
}
|
||||
/* new label */
|
||||
sym = asm_new_label(s1, opcode, 0);
|
||||
sym->type.t &= ~VT_EXTERN;
|
||||
asm_new_label(s1, opcode, 0);
|
||||
next();
|
||||
goto redo;
|
||||
} else if (tok == '=') {
|
||||
|
@ -989,31 +959,22 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
|||
parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
||||
}
|
||||
|
||||
asm_free_labels(s1);
|
||||
parse_flags = saved_parse_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assemble the current file */
|
||||
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
|
||||
{
|
||||
Sym *define_start;
|
||||
int ret;
|
||||
|
||||
define_start = define_stack;
|
||||
preprocess_start(s1);
|
||||
tcc_debug_start(s1);
|
||||
|
||||
/* default section is text */
|
||||
cur_text_section = text_section;
|
||||
ind = cur_text_section->data_offset;
|
||||
nocode_wanted = 0;
|
||||
|
||||
ret = tcc_assemble_internal(s1, do_preprocess, 1);
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
|
||||
tcc_debug_end(s1);
|
||||
free_defines(define_start);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1025,21 +986,16 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
|
|||
end */
|
||||
static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
|
||||
{
|
||||
int saved_parse_flags;
|
||||
const int *saved_macro_ptr;
|
||||
|
||||
saved_parse_flags = parse_flags;
|
||||
saved_macro_ptr = macro_ptr;
|
||||
const int *saved_macro_ptr = macro_ptr;
|
||||
int dotid = set_idnum('.', IS_ID);
|
||||
|
||||
tcc_open_bf(s1, ":asm:", len);
|
||||
memcpy(file->buffer, str, len);
|
||||
|
||||
macro_ptr = NULL;
|
||||
tcc_assemble_internal(s1, 0, global);
|
||||
tcc_close();
|
||||
|
||||
parse_flags = saved_parse_flags;
|
||||
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
|
||||
set_idnum('.', dotid);
|
||||
macro_ptr = saved_macro_ptr;
|
||||
}
|
||||
|
||||
|
|
406
tccelf.c
406
tccelf.c
|
@ -38,13 +38,18 @@ ST_DATA Section *bounds_section; /* contains global data bound description */
|
|||
ST_DATA Section *lbounds_section; /* contains local data bound description */
|
||||
#endif
|
||||
/* symbol sections */
|
||||
ST_DATA Section *symtab_section, *strtab_section;
|
||||
ST_DATA Section *symtab_section;
|
||||
/* debug sections */
|
||||
ST_DATA Section *stab_section, *stabstr_section;
|
||||
|
||||
/* XXX: avoid static variable */
|
||||
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
|
||||
|
||||
/* special flag to indicate that the section should not be linked to the other ones */
|
||||
#define SHF_PRIVATE 0x80000000
|
||||
/* section is dynsymtab_section */
|
||||
#define SHF_DYNSYM 0x40000000
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
ST_FUNC void tccelf_new(TCCState *s)
|
||||
|
@ -63,11 +68,10 @@ ST_FUNC void tccelf_new(TCCState *s)
|
|||
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
|
||||
".strtab",
|
||||
".hashtab", SHF_PRIVATE);
|
||||
strtab_section = symtab_section->link;
|
||||
s->symtab = symtab_section;
|
||||
|
||||
/* private symbol table for dynamic symbols */
|
||||
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
|
||||
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM,
|
||||
".dynstrtab",
|
||||
".dynhashtab", SHF_PRIVATE);
|
||||
get_sym_attr(s, 0, 1);
|
||||
|
@ -128,6 +132,61 @@ ST_FUNC void tccelf_delete(TCCState *s1)
|
|||
/* free loaded dlls array */
|
||||
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
|
||||
tcc_free(s1->sym_attrs);
|
||||
|
||||
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
||||
}
|
||||
|
||||
/* save section data state */
|
||||
ST_FUNC void tccelf_begin_file(TCCState *s1)
|
||||
{
|
||||
Section *s; int i;
|
||||
for (i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
s->sh_offset = s->data_offset;
|
||||
}
|
||||
/* disable symbol hashing during compilation */
|
||||
s = s1->symtab, s->reloc = s->hash, s->hash = NULL;
|
||||
#if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE
|
||||
s1->uw_sym = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* At the end of compilation, convert any UNDEF syms to global, and merge
|
||||
with previously existing symbols */
|
||||
ST_FUNC void tccelf_end_file(TCCState *s1)
|
||||
{
|
||||
Section *s = s1->symtab;
|
||||
int first_sym, nb_syms, *tr, i;
|
||||
|
||||
first_sym = s->sh_offset / sizeof (ElfSym);
|
||||
nb_syms = s->data_offset / sizeof (ElfSym) - first_sym;
|
||||
s->data_offset = s->sh_offset;
|
||||
s->link->data_offset = s->link->sh_offset;
|
||||
s->hash = s->reloc, s->reloc = NULL;
|
||||
tr = tcc_mallocz(nb_syms * sizeof *tr);
|
||||
|
||||
for (i = 0; i < nb_syms; ++i) {
|
||||
ElfSym *sym = (ElfSym*)s->data + first_sym + i;
|
||||
if (sym->st_shndx == SHN_UNDEF
|
||||
&& ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
|
||||
sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info));
|
||||
tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info,
|
||||
sym->st_other, sym->st_shndx, s->link->data + sym->st_name);
|
||||
}
|
||||
/* now update relocations */
|
||||
for (i = 1; i < s1->nb_sections; i++) {
|
||||
Section *sr = s1->sections[i];
|
||||
if (sr->sh_type == SHT_RELX && sr->link == s) {
|
||||
ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset);
|
||||
ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset);
|
||||
for (; rel < rel_end; ++rel) {
|
||||
int n = ELFW(R_SYM)(rel->r_info) - first_sym;
|
||||
//if (n < 0) tcc_error("internal: invalid symbol index in relocation");
|
||||
rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
tcc_free(tr);
|
||||
}
|
||||
|
||||
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
|
||||
|
@ -269,7 +328,7 @@ ST_FUNC int put_elf_str(Section *s, const char *sym)
|
|||
len = strlen(sym) + 1;
|
||||
offset = s->data_offset;
|
||||
ptr = section_ptr_add(s, len);
|
||||
memcpy(ptr, sym, len);
|
||||
memmove(ptr, sym, len);
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
@ -299,6 +358,9 @@ static void rebuild_hash(Section *s, unsigned int nb_buckets)
|
|||
strtab = s->link->data;
|
||||
nb_syms = s->data_offset / sizeof(ElfW(Sym));
|
||||
|
||||
if (!nb_buckets)
|
||||
nb_buckets = ((int*)s->hash->data)[0];
|
||||
|
||||
s->hash->data_offset = 0;
|
||||
ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
|
||||
ptr[0] = nb_buckets;
|
||||
|
@ -332,7 +394,7 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
|
|||
Section *hs;
|
||||
|
||||
sym = section_ptr_add(s, sizeof(ElfW(Sym)));
|
||||
if (name)
|
||||
if (name && name[0])
|
||||
name_offset = put_elf_str(s->link, name);
|
||||
else
|
||||
name_offset = 0;
|
||||
|
@ -349,11 +411,11 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
|
|||
int *ptr, *base;
|
||||
ptr = section_ptr_add(hs, sizeof(int));
|
||||
base = (int *)hs->data;
|
||||
/* only add global or weak symbols */
|
||||
/* only add global or weak symbols. */
|
||||
if (ELFW(ST_BIND)(info) != STB_LOCAL) {
|
||||
/* add another hashing entry */
|
||||
nbuckets = base[0];
|
||||
h = elf_hash((unsigned char *) name) % nbuckets;
|
||||
h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets;
|
||||
*ptr = base[2 + h];
|
||||
base[2 + h] = sym_index;
|
||||
base[1]++;
|
||||
|
@ -370,8 +432,6 @@ ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
|
|||
return sym_index;
|
||||
}
|
||||
|
||||
/* find global ELF symbol 'name' and return its index. Return 0 if not
|
||||
found. */
|
||||
ST_FUNC int find_elf_sym(Section *s, const char *name)
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
|
@ -438,17 +498,15 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
|
|||
sym_type = ELFW(ST_TYPE)(info);
|
||||
sym_vis = ELFW(ST_VISIBILITY)(other);
|
||||
|
||||
sym_index = find_elf_sym(s, name);
|
||||
esym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||
if (sym_index && esym->st_value == value && esym->st_size == size
|
||||
&& esym->st_info == info && esym->st_other == other
|
||||
&& esym->st_shndx == shndx)
|
||||
return sym_index;
|
||||
|
||||
if (sym_bind != STB_LOCAL) {
|
||||
/* we search global or weak symbols */
|
||||
sym_index = find_elf_sym(s, name);
|
||||
if (!sym_index)
|
||||
goto do_def;
|
||||
esym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||
if (esym->st_value == value && esym->st_size == size && esym->st_info == info
|
||||
&& esym->st_other == other && esym->st_shndx == shndx)
|
||||
return sym_index;
|
||||
if (esym->st_shndx != SHN_UNDEF) {
|
||||
esym_bind = ELFW(ST_BIND)(esym->st_info);
|
||||
/* propagate the most constraining visibility */
|
||||
|
@ -484,8 +542,12 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
|
|||
goto do_patch;
|
||||
} else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) {
|
||||
/* data symbol keeps precedence over common/bss */
|
||||
} else if (s == tcc_state->dynsymtab_section) {
|
||||
} else if (s->sh_flags & SHF_DYNSYM) {
|
||||
/* we accept that two DLL define the same symbol */
|
||||
} else if (esym->st_other & ST_ASM_SET) {
|
||||
/* If the existing symbol came from an asm .set
|
||||
we can override. */
|
||||
goto do_patch;
|
||||
} else {
|
||||
#if 0
|
||||
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
|
||||
|
@ -679,7 +741,8 @@ static void sort_syms(TCCState *s1, Section *s)
|
|||
p++;
|
||||
}
|
||||
/* save the number of local symbols in section header */
|
||||
s->sh_info = q - new_syms;
|
||||
if( s->sh_size ) /* this 'if' makes IDA happy */
|
||||
s->sh_info = q - new_syms;
|
||||
|
||||
/* then second pass for non local symbols */
|
||||
p = (ElfW(Sym) *)s->data;
|
||||
|
@ -711,21 +774,6 @@ static void sort_syms(TCCState *s1, Section *s)
|
|||
tcc_free(old_to_new_syms);
|
||||
}
|
||||
|
||||
/* relocate common symbols in the .bss section */
|
||||
ST_FUNC void relocate_common_syms(void)
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
|
||||
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
||||
if (sym->st_shndx == SHN_COMMON) {
|
||||
/* symbol alignment is in st_value for SHN_COMMONs */
|
||||
sym->st_value = section_add(bss_section, sym->st_size,
|
||||
sym->st_value);
|
||||
sym->st_shndx = bss_section->sh_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* relocate symbol table, resolve undefined symbols if do_resolve is
|
||||
true and output error if undefined symbol. */
|
||||
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
|
||||
|
@ -737,7 +785,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
|
|||
for_each_elem(symtab, 1, sym, ElfW(Sym)) {
|
||||
sh_num = sym->st_shndx;
|
||||
if (sh_num == SHN_UNDEF) {
|
||||
name = (char *) strtab_section->data + sym->st_name;
|
||||
name = (char *) s1->symtab->link->data + sym->st_name;
|
||||
/* Use ld.so to resolve symbol for us (for tcc -run) */
|
||||
if (do_resolve) {
|
||||
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
|
||||
|
@ -818,15 +866,24 @@ static void relocate_rel(TCCState *s1, Section *sr)
|
|||
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
|
||||
{
|
||||
ElfW_Rel *rel;
|
||||
int sym_index, type, count;
|
||||
int type, count;
|
||||
|
||||
count = 0;
|
||||
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
type = ELFW(R_TYPE)(rel->r_info);
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
|
||||
int sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
#endif
|
||||
switch(type) {
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
|
||||
#if defined(TCC_TARGET_I386)
|
||||
case R_386_32:
|
||||
if (!get_sym_attr(s1, sym_index, 0)->dyn_index
|
||||
&& ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) {
|
||||
/* don't fixup unresolved (weak) symbols */
|
||||
rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE);
|
||||
break;
|
||||
}
|
||||
#elif defined(TCC_TARGET_X86_64)
|
||||
case R_X86_64_32:
|
||||
case R_X86_64_32S:
|
||||
|
@ -842,6 +899,7 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
|
|||
if (get_sym_attr(s1, sym_index, 0)->dyn_index)
|
||||
count++;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1090,7 +1148,6 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
|
|||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
s->sh_num, sym_end);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tcc_add_support(TCCState *s1, const char *filename)
|
||||
{
|
||||
|
@ -1098,6 +1155,7 @@ static int tcc_add_support(TCCState *s1, const char *filename)
|
|||
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename);
|
||||
return tcc_add_file(s1, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||
{
|
||||
|
@ -1133,8 +1191,10 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
|||
/* add tcc runtime libraries */
|
||||
ST_FUNC void tcc_add_runtime(TCCState *s1)
|
||||
{
|
||||
s1->filetype = 0;
|
||||
tcc_add_bcheck(s1);
|
||||
tcc_add_pragma_libs(s1);
|
||||
#ifndef TCC_TARGET_PE
|
||||
/* add libc */
|
||||
if (!s1->nostdlib) {
|
||||
tcc_add_library_err(s1, "c");
|
||||
|
@ -1151,12 +1211,13 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
|||
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||
tcc_add_crt(s1, "crtn.o");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* add various standard linker symbols (must be done after the
|
||||
sections are filled (for example after allocating common
|
||||
symbols)) */
|
||||
ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
|
||||
static void tcc_add_linker_symbols(TCCState *s1)
|
||||
{
|
||||
char buf[1024];
|
||||
int i;
|
||||
|
@ -1215,6 +1276,24 @@ ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
|
|||
}
|
||||
}
|
||||
|
||||
ST_FUNC void resolve_common_syms(TCCState *s1)
|
||||
{
|
||||
ElfW(Sym) *sym;
|
||||
|
||||
/* Allocate common symbols in BSS. */
|
||||
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
||||
if (sym->st_shndx == SHN_COMMON) {
|
||||
/* symbol alignment is in st_value for SHN_COMMONs */
|
||||
sym->st_value = section_add(bss_section, sym->st_size,
|
||||
sym->st_value);
|
||||
sym->st_shndx = bss_section->sh_num;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now assign linker provided symbols their value. */
|
||||
tcc_add_linker_symbols(s1);
|
||||
}
|
||||
|
||||
static void tcc_output_binary(TCCState *s1, FILE *f,
|
||||
const int *sec_order)
|
||||
{
|
||||
|
@ -1237,14 +1316,6 @@ static void tcc_output_binary(TCCState *s1, FILE *f,
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#define HAVE_PHDR 1
|
||||
#define EXTRA_RELITEMS 14
|
||||
#else
|
||||
#define HAVE_PHDR 1
|
||||
#define EXTRA_RELITEMS 9
|
||||
#endif
|
||||
|
||||
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
|
||||
{
|
||||
int sym_index = ELFW(R_SYM) (rel->r_info);
|
||||
|
@ -1295,6 +1366,8 @@ ST_FUNC void fill_got(TCCState *s1)
|
|||
static void fill_local_got_entries(TCCState *s1)
|
||||
{
|
||||
ElfW_Rel *rel;
|
||||
if (!s1->got->reloc)
|
||||
return;
|
||||
for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) {
|
||||
if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) {
|
||||
int sym_index = ELFW(R_SYM) (rel->r_info);
|
||||
|
@ -1412,13 +1485,12 @@ static void bind_libs_dynsyms(TCCState *s1)
|
|||
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) {
|
||||
name = (char *) s1->dynsymtab_section->link->data + esym->st_name;
|
||||
sym_index = find_elf_sym(symtab_section, name);
|
||||
/* XXX: avoid adding a symbol if already present because of
|
||||
-rdynamic ? */
|
||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
if (sym_index && sym->st_shndx != SHN_UNDEF)
|
||||
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
|
||||
0, sym->st_shndx, name);
|
||||
else if (esym->st_shndx == SHN_UNDEF) {
|
||||
if (sym_index && sym->st_shndx != SHN_UNDEF
|
||||
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
||||
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
|
||||
sym->st_info, 0, sym->st_shndx, name);
|
||||
} else if (esym->st_shndx == SHN_UNDEF) {
|
||||
/* weak symbols can stay undefined */
|
||||
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
|
||||
tcc_warning("undefined dynamic symbol '%s'", name);
|
||||
|
@ -1450,10 +1522,11 @@ static void export_global_syms(TCCState *s1)
|
|||
/* Allocate strings for section names and decide if an unallocated section
|
||||
should be output.
|
||||
NOTE: the strsec section comes last, so its size is also correct ! */
|
||||
static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
|
||||
static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
|
||||
{
|
||||
int i;
|
||||
Section *s;
|
||||
int textrel = 0;
|
||||
|
||||
/* Allocate strings for section names */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
|
@ -1462,13 +1535,12 @@ static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
|
|||
patch them */
|
||||
if (file_type == TCC_OUTPUT_DLL &&
|
||||
s->sh_type == SHT_RELX &&
|
||||
!(s->sh_flags & SHF_ALLOC)) {
|
||||
/* gr: avoid bogus relocs for empty (debug) sections */
|
||||
if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)
|
||||
prepare_dynamic_rel(s1, s);
|
||||
else if (s1->do_debug)
|
||||
s->sh_size = s->data_offset;
|
||||
} else if (s1->do_debug ||
|
||||
!(s->sh_flags & SHF_ALLOC) &&
|
||||
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
|
||||
prepare_dynamic_rel(s1, s)) {
|
||||
if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
|
||||
textrel = 1;
|
||||
} else if ((s1->do_debug && s->sh_type != SHT_RELX) ||
|
||||
file_type == TCC_OUTPUT_OBJ ||
|
||||
(s->sh_flags & SHF_ALLOC) ||
|
||||
i == (s1->nb_sections - 1)) {
|
||||
|
@ -1479,13 +1551,14 @@ static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
|
|||
s->sh_name = put_elf_str(strsec, s->name);
|
||||
}
|
||||
strsec->sh_size = strsec->data_offset;
|
||||
return textrel;
|
||||
}
|
||||
|
||||
/* Info to be copied in dynamic section */
|
||||
struct dyn_inf {
|
||||
Section *dynamic;
|
||||
Section *dynstr;
|
||||
unsigned long dyn_rel_off;
|
||||
unsigned long data_offset;
|
||||
addr_t rel_addr;
|
||||
addr_t rel_size;
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
@ -1541,7 +1614,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
|
|||
the program header table itself if needed. These are done later as
|
||||
they require section layout to be done first. */
|
||||
if (interp)
|
||||
ph += 1 + HAVE_PHDR;
|
||||
ph += 2;
|
||||
|
||||
/* dynamic relocation table information, for .dynamic section */
|
||||
dyninf->rel_addr = dyninf->rel_size = 0;
|
||||
|
@ -1683,19 +1756,14 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
|
|||
if (interp) {
|
||||
ph = &phdr[0];
|
||||
|
||||
if (HAVE_PHDR)
|
||||
{
|
||||
int len = phnum * sizeof(ElfW(Phdr));
|
||||
|
||||
ph->p_type = PT_PHDR;
|
||||
ph->p_offset = sizeof(ElfW(Ehdr));
|
||||
ph->p_vaddr = interp->sh_addr - len;
|
||||
ph->p_paddr = ph->p_vaddr;
|
||||
ph->p_filesz = ph->p_memsz = len;
|
||||
ph->p_flags = PF_R | PF_X;
|
||||
ph->p_align = 4; /* interp->sh_addralign; */
|
||||
ph++;
|
||||
}
|
||||
ph->p_type = PT_PHDR;
|
||||
ph->p_offset = sizeof(ElfW(Ehdr));
|
||||
ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr));
|
||||
ph->p_vaddr = interp->sh_addr - ph->p_filesz;
|
||||
ph->p_paddr = ph->p_vaddr;
|
||||
ph->p_flags = PF_R | PF_X;
|
||||
ph->p_align = 4; /* interp->sh_addralign; */
|
||||
ph++;
|
||||
|
||||
ph->p_type = PT_INTERP;
|
||||
ph->p_offset = interp->sh_offset;
|
||||
|
@ -1726,12 +1794,9 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
|
|||
sections */
|
||||
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
|
||||
{
|
||||
Section *dynamic;
|
||||
|
||||
dynamic = dyninf->dynamic;
|
||||
Section *dynamic = dyninf->dynamic;
|
||||
|
||||
/* put dynamic section entries */
|
||||
dynamic->data_offset = dyninf->dyn_rel_off;
|
||||
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
|
||||
put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr);
|
||||
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
|
||||
|
@ -1776,14 +1841,7 @@ static int final_sections_reloc(TCCState *s1)
|
|||
/* XXX: ignore sections with allocated relocations ? */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_MUSL)
|
||||
if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr
|
||||
/* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC
|
||||
checking is removed */
|
||||
#else
|
||||
if (s->reloc && s != s1->got)
|
||||
/* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */
|
||||
#endif
|
||||
relocate_section(s1, s);
|
||||
}
|
||||
|
||||
|
@ -1831,7 +1889,8 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
|
|||
ehdr.e_ident[4] = ELFCLASSW;
|
||||
ehdr.e_ident[5] = ELFDATA2LSB;
|
||||
ehdr.e_ident[6] = EV_CURRENT;
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
|
||||
/* FIXME: should set only for freebsd _target_, but we exclude only PE target */
|
||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
|
@ -1985,10 +2044,11 @@ static void tidy_section_headers(TCCState *s1, int *sec_order)
|
|||
for_each_elem(symtab_section, 1, sym, ElfW(Sym))
|
||||
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
|
||||
sym->st_shndx = backmap[sym->st_shndx];
|
||||
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
|
||||
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
|
||||
sym->st_shndx = backmap[sym->st_shndx];
|
||||
|
||||
if( !s1->static_link ) {
|
||||
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
|
||||
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
|
||||
sym->st_shndx = backmap[sym->st_shndx];
|
||||
}
|
||||
for (i = 0; i < s1->nb_sections; i++)
|
||||
sec_order[i] = i;
|
||||
tcc_free(s1->sections);
|
||||
|
@ -2006,23 +2066,20 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
|||
ElfW(Phdr) *phdr;
|
||||
ElfW(Sym) *sym;
|
||||
Section *strsec, *interp, *dynamic, *dynstr;
|
||||
int textrel;
|
||||
|
||||
file_type = s1->output_type;
|
||||
s1->nb_errors = 0;
|
||||
|
||||
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
|
||||
if (file_type != TCC_OUTPUT_OBJ) {
|
||||
tcc_add_runtime(s1);
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
phdr = NULL;
|
||||
sec_order = NULL;
|
||||
interp = dynamic = dynstr = NULL; /* avoid warning */
|
||||
textrel = 0;
|
||||
|
||||
if (file_type != TCC_OUTPUT_OBJ) {
|
||||
relocate_common_syms();
|
||||
|
||||
tcc_add_linker_symbols(s1);
|
||||
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
|
||||
tcc_add_runtime(s1);
|
||||
resolve_common_syms(s1);
|
||||
|
||||
if (!s1->static_link) {
|
||||
if (file_type == TCC_OUTPUT_EXE) {
|
||||
|
@ -2054,53 +2111,70 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
|||
|
||||
if (file_type == TCC_OUTPUT_EXE) {
|
||||
bind_exe_dynsyms(s1);
|
||||
|
||||
if (s1->nb_errors) {
|
||||
ret = -1;
|
||||
if (s1->nb_errors)
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
bind_libs_dynsyms(s1);
|
||||
} else /* shared library case: simply export all global symbols */
|
||||
} else {
|
||||
/* shared library case: simply export all global symbols */
|
||||
export_global_syms(s1);
|
||||
|
||||
build_got_entries(s1);
|
||||
|
||||
/* add a list of needed dlls */
|
||||
for(i = 0; i < s1->nb_loaded_dlls; i++) {
|
||||
DLLReference *dllref = s1->loaded_dlls[i];
|
||||
if (dllref->level == 0)
|
||||
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
|
||||
}
|
||||
|
||||
if (s1->rpath)
|
||||
put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
|
||||
put_elf_str(dynstr, s1->rpath));
|
||||
|
||||
/* XXX: currently, since we do not handle PIC code, we
|
||||
must relocate the readonly segments */
|
||||
if (file_type == TCC_OUTPUT_DLL) {
|
||||
if (s1->soname)
|
||||
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
|
||||
put_dt(dynamic, DT_TEXTREL, 0);
|
||||
}
|
||||
|
||||
if (s1->symbolic)
|
||||
put_dt(dynamic, DT_SYMBOLIC, 0);
|
||||
|
||||
/* add necessary space for other entries */
|
||||
dyninf.dyn_rel_off = dynamic->data_offset;
|
||||
dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS;
|
||||
} else {
|
||||
/* still need to build got entries in case of static link */
|
||||
build_got_entries(s1);
|
||||
}
|
||||
build_got_entries(s1);
|
||||
}
|
||||
|
||||
/* we add a section for symbols */
|
||||
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
|
||||
put_elf_str(strsec, "");
|
||||
|
||||
/* Allocate strings for section names */
|
||||
textrel = alloc_sec_names(s1, file_type, strsec);
|
||||
|
||||
if (dynamic) {
|
||||
/* add a list of needed dlls */
|
||||
for(i = 0; i < s1->nb_loaded_dlls; i++) {
|
||||
DLLReference *dllref = s1->loaded_dlls[i];
|
||||
if (dllref->level == 0)
|
||||
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
|
||||
}
|
||||
|
||||
if (s1->rpath)
|
||||
put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
|
||||
put_elf_str(dynstr, s1->rpath));
|
||||
|
||||
if (file_type == TCC_OUTPUT_DLL) {
|
||||
if (s1->soname)
|
||||
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
|
||||
/* XXX: currently, since we do not handle PIC code, we
|
||||
must relocate the readonly segments */
|
||||
if (textrel)
|
||||
put_dt(dynamic, DT_TEXTREL, 0);
|
||||
}
|
||||
|
||||
if (s1->symbolic)
|
||||
put_dt(dynamic, DT_SYMBOLIC, 0);
|
||||
|
||||
dyninf.dynamic = dynamic;
|
||||
dyninf.dynstr = dynstr;
|
||||
/* remember offset and reserve space for 2nd call below */
|
||||
dyninf.data_offset = dynamic->data_offset;
|
||||
fill_dynamic(s1, &dyninf);
|
||||
dynamic->sh_size = dynamic->data_offset;
|
||||
dynstr->sh_size = dynstr->data_offset;
|
||||
}
|
||||
|
||||
/* compute number of program headers */
|
||||
if (file_type == TCC_OUTPUT_OBJ)
|
||||
phnum = 0;
|
||||
else if (file_type == TCC_OUTPUT_DLL)
|
||||
phnum = 3;
|
||||
else if (s1->static_link)
|
||||
phnum = 2;
|
||||
else
|
||||
phnum = 5;
|
||||
|
||||
/* allocate program segment headers */
|
||||
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
|
||||
|
||||
/* compute number of sections */
|
||||
shnum = s1->nb_sections;
|
||||
|
||||
|
@ -2108,41 +2182,16 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
|||
sec_order = tcc_malloc(sizeof(int) * shnum);
|
||||
sec_order[0] = 0;
|
||||
|
||||
/* compute number of program headers */
|
||||
switch(file_type) {
|
||||
default:
|
||||
case TCC_OUTPUT_OBJ:
|
||||
phnum = 0;
|
||||
break;
|
||||
case TCC_OUTPUT_EXE:
|
||||
if (!s1->static_link)
|
||||
phnum = 4 + HAVE_PHDR;
|
||||
else
|
||||
phnum = 2;
|
||||
break;
|
||||
case TCC_OUTPUT_DLL:
|
||||
phnum = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate strings for section names */
|
||||
alloc_sec_names(s1, file_type, strsec);
|
||||
|
||||
/* allocate program segment headers */
|
||||
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
|
||||
|
||||
/* compute section to program header mapping */
|
||||
file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf,
|
||||
sec_order);
|
||||
|
||||
/* Fill remaining program header and finalize relocation related to dynamic
|
||||
linking. */
|
||||
if (phnum > 0) {
|
||||
if (file_type != TCC_OUTPUT_OBJ) {
|
||||
fill_unloadable_phdr(phdr, phnum, interp, dynamic);
|
||||
if (dynamic) {
|
||||
dyninf.dynamic = dynamic;
|
||||
dyninf.dynstr = dynstr;
|
||||
|
||||
dynamic->data_offset = dyninf.data_offset;
|
||||
fill_dynamic(s1, &dyninf);
|
||||
|
||||
/* put in GOT the dynamic section address and relocate PLT */
|
||||
|
@ -2159,22 +2208,20 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if building executable or DLL, then relocate each section
|
||||
except the GOT which is already relocated */
|
||||
if (file_type != TCC_OUTPUT_OBJ) {
|
||||
/* if building executable or DLL, then relocate each section
|
||||
except the GOT which is already relocated */
|
||||
ret = final_sections_reloc(s1);
|
||||
if (ret)
|
||||
goto the_end;
|
||||
tidy_section_headers(s1, sec_order);
|
||||
}
|
||||
|
||||
/* Perform relocation to GOT or PLT entries */
|
||||
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
|
||||
fill_got(s1);
|
||||
else if (s1->got)
|
||||
fill_local_got_entries(s1);
|
||||
/* Perform relocation to GOT or PLT entries */
|
||||
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
|
||||
fill_got(s1);
|
||||
else if (s1->got)
|
||||
fill_local_got_entries(s1);
|
||||
}
|
||||
|
||||
/* Create the ELF file with name 'filename' */
|
||||
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
|
||||
|
@ -2400,8 +2447,11 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
|
|||
a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
|
||||
b = (Stab_Sym *)(s->data + s->data_offset);
|
||||
o = sm_table[stabstr_index].offset;
|
||||
while (a < b)
|
||||
a->n_strx += o, a++;
|
||||
while (a < b) {
|
||||
if (a->n_strx)
|
||||
a->n_strx += o;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
/* second short pass to update sh_link and sh_info fields of new
|
||||
|
@ -2588,7 +2638,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
|
|||
}
|
||||
|
||||
/* load a '.a' file */
|
||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
|
||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte)
|
||||
{
|
||||
ArchiveHeader hdr;
|
||||
char ar_size[11];
|
||||
|
@ -2622,10 +2672,10 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
|
|||
size = (size + 1) & ~1;
|
||||
if (!strcmp(ar_name, "/")) {
|
||||
/* coff symbol table : we handle it */
|
||||
if(s1->alacarte_link)
|
||||
if (alacarte)
|
||||
return tcc_load_alacarte(s1, fd, size, 4);
|
||||
} else if (!strcmp(ar_name, "/SYM64/")) {
|
||||
if(s1->alacarte_link)
|
||||
if (alacarte)
|
||||
return tcc_load_alacarte(s1, fd, size, 8);
|
||||
} else {
|
||||
ElfW(Ehdr) ehdr;
|
||||
|
|
124
tccpe.c
124
tccpe.c
|
@ -26,10 +26,12 @@
|
|||
#ifndef _WIN32
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#include <sys/stat.h> /* chmod() */
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
# define ADDR3264 ULONGLONG
|
||||
# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64
|
||||
# define REL_TYPE_DIRECT R_X86_64_64
|
||||
# define R_XXX_THUNKFIX R_X86_64_PC32
|
||||
# define R_XXX_RELATIVE R_X86_64_RELATIVE
|
||||
|
@ -38,6 +40,7 @@
|
|||
|
||||
#elif defined TCC_TARGET_ARM
|
||||
# define ADDR3264 DWORD
|
||||
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
|
||||
# define REL_TYPE_DIRECT R_ARM_ABS32
|
||||
# define R_XXX_THUNKFIX R_ARM_ABS32
|
||||
# define R_XXX_RELATIVE R_ARM_RELATIVE
|
||||
|
@ -46,6 +49,7 @@
|
|||
|
||||
#elif defined TCC_TARGET_I386
|
||||
# define ADDR3264 DWORD
|
||||
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
|
||||
# define REL_TYPE_DIRECT R_386_32
|
||||
# define R_XXX_THUNKFIX R_386_32
|
||||
# define R_XXX_RELATIVE R_386_RELATIVE
|
||||
|
@ -54,22 +58,6 @@
|
|||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifdef _WIN32
|
||||
void dbg_printf (const char *fmt, ...)
|
||||
{
|
||||
char buffer[4000];
|
||||
va_list arg;
|
||||
int x;
|
||||
va_start(arg, fmt);
|
||||
x = vsprintf (buffer, fmt, arg);
|
||||
strcpy(buffer+x, "\n");
|
||||
OutputDebugString(buffer);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
#ifndef IMAGE_NT_SIGNATURE
|
||||
/* ----------------------------------------------------------- */
|
||||
/* definitions below are from winnt.h */
|
||||
|
@ -241,14 +229,19 @@ typedef struct _IMAGE_BASE_RELOCATION {
|
|||
#define IMAGE_REL_BASED_MIPS_JMPADDR 5
|
||||
#define IMAGE_REL_BASED_SECTION 6
|
||||
#define IMAGE_REL_BASED_REL32 7
|
||||
#define IMAGE_REL_BASED_DIR64 10
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
#endif /* ndef IMAGE_NT_SIGNATURE */
|
||||
/* ----------------------------------------------------------- */
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#ifndef IMAGE_REL_BASED_DIR64
|
||||
# define IMAGE_REL_BASED_DIR64 10
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct pe_header
|
||||
{
|
||||
IMAGE_DOS_HEADER doshdr;
|
||||
|
@ -281,7 +274,6 @@ struct pe_rsrc_reloc {
|
|||
DWORD size;
|
||||
WORD type;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -732,6 +724,9 @@ static int pe_write(struct pe_info *pe)
|
|||
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
|
||||
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
|
||||
fclose (op);
|
||||
#ifndef _WIN32
|
||||
chmod(pe->filename, 0777);
|
||||
#endif
|
||||
|
||||
if (2 == pe->s1->verbose)
|
||||
printf("-------------------------------\n");
|
||||
|
@ -959,7 +954,7 @@ static void pe_build_exports(struct pe_info *pe)
|
|||
/* automatically write exports to <output-filename>.def */
|
||||
pstrcpy(buf, sizeof buf, pe->filename);
|
||||
strcpy(tcc_fileextension(buf), ".def");
|
||||
op = fopen(buf, "w");
|
||||
op = fopen(buf, "wb");
|
||||
if (NULL == op) {
|
||||
tcc_error_noabort("could not create '%s': %s", buf, strerror(errno));
|
||||
} else {
|
||||
|
@ -972,7 +967,7 @@ static void pe_build_exports(struct pe_info *pe)
|
|||
for (ord = 0; ord < sym_count; ++ord)
|
||||
{
|
||||
p = sorted[ord], sym_index = p->index, name = p->name;
|
||||
/* insert actual address later in pe_relocate_rva */
|
||||
/* insert actual address later in relocate_section() */
|
||||
put_elf_reloc(symtab_section, pe->thunk,
|
||||
func_o, R_XXX_RELATIVE, sym_index);
|
||||
*(DWORD*)(pe->thunk->data + name_o)
|
||||
|
@ -1017,7 +1012,7 @@ static void pe_build_reloc (struct pe_info *pe)
|
|||
}
|
||||
if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */
|
||||
WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD));
|
||||
*wp = addr | IMAGE_REL_BASED_HIGHLOW<<12;
|
||||
*wp = addr | PE_IMAGE_REL<<12;
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
|
@ -1186,26 +1181,6 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
static void pe_relocate_rva (struct pe_info *pe, Section *s)
|
||||
{
|
||||
Section *sr = s->reloc;
|
||||
ElfW_Rel *rel, *rel_end;
|
||||
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
|
||||
for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
|
||||
if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) {
|
||||
int sym_index = ELFW(R_SYM)(rel->r_info);
|
||||
DWORD addr = s->sh_addr;
|
||||
if (sym_index) {
|
||||
ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
|
||||
addr = sym->st_value;
|
||||
}
|
||||
// printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
|
||||
*(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
static int pe_isafunc(int sym_index)
|
||||
|
@ -1471,13 +1446,13 @@ static void pe_print_sections(TCCState *s1, const char *fname)
|
|||
/* ------------------------------------------------------------- */
|
||||
/* helper function for load/store to insert one more indirection */
|
||||
|
||||
#ifndef TCC_TARGET_ARM
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
|
||||
{
|
||||
int r2;
|
||||
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
|
||||
return sv;
|
||||
if (!(sv->sym->type.t & VT_IMPORT))
|
||||
if (!sv->sym->a.dllimport)
|
||||
return sv;
|
||||
// printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
|
||||
memset(v2, 0, sizeof *v2);
|
||||
|
@ -1547,11 +1522,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
|
|||
IMAGE_DOS_HEADER dh;
|
||||
IMAGE_FILE_HEADER ih;
|
||||
DWORD sig, ref, addr, ptr, namep;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
IMAGE_OPTIONAL_HEADER64 oh;
|
||||
#else
|
||||
IMAGE_OPTIONAL_HEADER32 oh;
|
||||
#endif
|
||||
|
||||
int pef_hdroffset, opt_hdroffset, sec_hdroffset;
|
||||
|
||||
n = n0 = 0;
|
||||
|
@ -1562,7 +1533,6 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
|
|||
if (fd < 0)
|
||||
goto the_end_1;
|
||||
ret = 1;
|
||||
|
||||
if (!read_mem(fd, 0, &dh, sizeof dh))
|
||||
goto the_end;
|
||||
if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
|
||||
|
@ -1572,22 +1542,26 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
|
|||
pef_hdroffset = dh.e_lfanew + sizeof sig;
|
||||
if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
|
||||
goto the_end;
|
||||
if (IMAGE_FILE_MACHINE != ih.Machine) {
|
||||
if (ih.Machine == 0x014C)
|
||||
ret = 32;
|
||||
else if (ih.Machine == 0x8664)
|
||||
ret = 64;
|
||||
goto the_end;
|
||||
}
|
||||
opt_hdroffset = pef_hdroffset + sizeof ih;
|
||||
sec_hdroffset = opt_hdroffset + sizeof oh;
|
||||
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
|
||||
if (ih.Machine == 0x014C) {
|
||||
IMAGE_OPTIONAL_HEADER32 oh;
|
||||
sec_hdroffset = opt_hdroffset + sizeof oh;
|
||||
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
|
||||
goto the_end;
|
||||
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
|
||||
goto the_end_0;
|
||||
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
} else if (ih.Machine == 0x8664) {
|
||||
IMAGE_OPTIONAL_HEADER64 oh;
|
||||
sec_hdroffset = opt_hdroffset + sizeof oh;
|
||||
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
|
||||
goto the_end;
|
||||
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
|
||||
goto the_end_0;
|
||||
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
} else
|
||||
goto the_end;
|
||||
|
||||
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
|
||||
goto the_end_0;
|
||||
|
||||
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
//printf("addr: %08x\n", addr);
|
||||
for (i = 0; i < ih.NumberOfSections; ++i) {
|
||||
if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
|
||||
|
@ -1639,7 +1613,7 @@ static int pe_load_res(TCCState *s1, int fd)
|
|||
{
|
||||
struct pe_rsrc_header hdr;
|
||||
Section *rsrc_section;
|
||||
int i, ret = -1;
|
||||
int i, ret = -1, sym_index;
|
||||
BYTE *ptr;
|
||||
unsigned offs;
|
||||
|
||||
|
@ -1657,8 +1631,8 @@ static int pe_load_res(TCCState *s1, int fd)
|
|||
if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData))
|
||||
goto quit;
|
||||
offs = hdr.sectionhdr.PointerToRelocations;
|
||||
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
|
||||
{
|
||||
sym_index = put_elf_sym(symtab_section, 0, 0, 0, 0, rsrc_section->sh_num, ".rsrc");
|
||||
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) {
|
||||
struct pe_rsrc_reloc rel;
|
||||
if (!read_mem(fd, offs, &rel, sizeof rel))
|
||||
goto quit;
|
||||
|
@ -1666,7 +1640,7 @@ static int pe_load_res(TCCState *s1, int fd)
|
|||
if (rel.type != RSRC_RELTYPE)
|
||||
goto quit;
|
||||
put_elf_reloc(symtab_section, rsrc_section,
|
||||
rel.offset, R_XXX_RELATIVE, 0);
|
||||
rel.offset, R_XXX_RELATIVE, sym_index);
|
||||
offs += sizeof rel;
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -1785,9 +1759,9 @@ static unsigned pe_add_uwwind_info(TCCState *s1)
|
|||
if (NULL == s1->uw_pdata) {
|
||||
s1->uw_pdata = find_section(tcc_state, ".pdata");
|
||||
s1->uw_pdata->sh_addralign = 4;
|
||||
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
|
||||
}
|
||||
|
||||
if (0 == s1->uw_sym)
|
||||
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_base");
|
||||
if (0 == s1->uw_offs) {
|
||||
/* As our functions all have the same stackframe, we use one entry for all */
|
||||
static const unsigned char uw_info[] = {
|
||||
|
@ -1836,7 +1810,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
|||
|
||||
/* put relocations on it */
|
||||
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
|
||||
put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym);
|
||||
put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
|
||||
}
|
||||
#endif
|
||||
/* ------------------------------------------------------------- */
|
||||
|
@ -1892,8 +1866,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, start_symbol);
|
||||
|
||||
tcc_add_pragma_libs(s1);
|
||||
|
||||
if (0 == s1->nostdlib) {
|
||||
static const char *libs[] = {
|
||||
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||
|
@ -1974,10 +1946,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||
pe.filename = filename;
|
||||
pe.s1 = s1;
|
||||
|
||||
tcc_add_bcheck(s1);
|
||||
tcc_add_runtime(s1);
|
||||
pe_add_runtime(s1, &pe);
|
||||
relocate_common_syms(); /* assign bss addresses */
|
||||
tcc_add_linker_symbols(s1);
|
||||
resolve_common_syms(s1);
|
||||
pe_set_options(s1, &pe);
|
||||
|
||||
ret = pe_check_symbols(&pe);
|
||||
|
@ -1986,11 +1957,11 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||
else if (filename) {
|
||||
pe_assign_addresses(&pe);
|
||||
relocate_syms(s1, s1->symtab, 0);
|
||||
s1->pe_imagebase = pe.imagebase;
|
||||
for (i = 1; i < s1->nb_sections; ++i) {
|
||||
Section *s = s1->sections[i];
|
||||
if (s->reloc) {
|
||||
relocate_section(s1, s);
|
||||
pe_relocate_rva(&pe, s);
|
||||
}
|
||||
}
|
||||
pe.start_addr = (DWORD)
|
||||
|
@ -2006,6 +1977,9 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||
pe.thunk = data_section;
|
||||
pe_build_imports(&pe);
|
||||
s1->runtime_main = pe.start_symbol;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
s1->uw_pdata = find_section(s1, ".pdata");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
109
tccrun.c
109
tccrun.c
|
@ -45,15 +45,13 @@ static void set_exception_handler(void);
|
|||
#endif
|
||||
|
||||
static void set_pages_executable(void *ptr, unsigned long length);
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr);
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
|
||||
|
||||
#ifdef _WIN64
|
||||
static void *win64_add_function_table(TCCState *s1);
|
||||
static void win64_del_function_table(void *);
|
||||
#endif
|
||||
|
||||
// #define HAVE_SELINUX
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Do all relocations (needed before using tcc_get_symbol())
|
||||
Returns -1 on error. */
|
||||
|
@ -61,25 +59,36 @@ static void win64_del_function_table(void *);
|
|||
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
|
||||
{
|
||||
int size;
|
||||
addr_t ptr_diff = 0;
|
||||
|
||||
if (TCC_RELOCATE_AUTO != ptr)
|
||||
return tcc_relocate_ex(s1, ptr);
|
||||
return tcc_relocate_ex(s1, ptr, 0);
|
||||
|
||||
size = tcc_relocate_ex(s1, NULL);
|
||||
size = tcc_relocate_ex(s1, NULL, 0);
|
||||
if (size < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
/* Use mmap instead of malloc for Selinux. */
|
||||
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
tcc_error("tccrun: could not map memory");
|
||||
{
|
||||
/* Using mmap instead of malloc */
|
||||
void *prx;
|
||||
char tmpfname[] = "/tmp/.tccrunXXXXXX";
|
||||
int fd = mkstemp(tmpfname);
|
||||
unlink(tmpfname);
|
||||
ftruncate(fd, size);
|
||||
|
||||
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
|
||||
if (ptr == MAP_FAILED || prx == MAP_FAILED)
|
||||
tcc_error("tccrun: could not map memory");
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
|
||||
ptr_diff = (char*)prx - (char*)ptr;
|
||||
}
|
||||
#else
|
||||
ptr = tcc_malloc(size);
|
||||
#endif
|
||||
tcc_relocate_ex(s1, ptr); /* no more errors expected */
|
||||
tcc_relocate_ex(s1, ptr, ptr_diff); /* no more errors expected */
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, ptr);
|
||||
return 0;
|
||||
}
|
||||
|
@ -91,6 +100,7 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
|||
for (i = 0; i < s1->nb_runtime_mem; ++i) {
|
||||
#ifdef HAVE_SELINUX
|
||||
unsigned size = (unsigned)(addr_t)s1->runtime_mem[i++];
|
||||
munmap(s1->runtime_mem[i++], size);
|
||||
munmap(s1->runtime_mem[i], size);
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
|
@ -108,6 +118,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
|||
int (*prog_main)(int, char **);
|
||||
|
||||
s1->runtime_main = "main";
|
||||
if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
|
||||
return 0;
|
||||
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
|
||||
return -1;
|
||||
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
|
||||
|
@ -157,18 +169,21 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
|||
}
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
/* To avoid that x86 processors would reload cached instructions
|
||||
each time when data is written in the near, we need to make
|
||||
sure that code and data do not share the same 64 byte unit */
|
||||
#define RUN_SECTION_ALIGNMENT 63
|
||||
#else
|
||||
#define RUN_SECTION_ALIGNMENT 15
|
||||
#define RUN_SECTION_ALIGNMENT 0
|
||||
#endif
|
||||
|
||||
/* relocate code. Return -1 on error, required size if ptr is NULL,
|
||||
otherwise copy code into buffer passed by the caller */
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
|
||||
{
|
||||
Section *s;
|
||||
unsigned offset, length, fill, i, k;
|
||||
addr_t mem;
|
||||
unsigned offset, length, align, max_align, i, k, f;
|
||||
addr_t mem, addr;
|
||||
|
||||
if (NULL == ptr) {
|
||||
s1->nb_errors = 0;
|
||||
|
@ -176,42 +191,39 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
|||
pe_output_file(s1, NULL);
|
||||
#else
|
||||
tcc_add_runtime(s1);
|
||||
relocate_common_syms();
|
||||
tcc_add_linker_symbols(s1);
|
||||
resolve_common_syms(s1);
|
||||
build_got_entries(s1);
|
||||
#endif
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = 0, mem = (addr_t)ptr;
|
||||
fill = -mem & RUN_SECTION_ALIGNMENT;
|
||||
offset = max_align = 0, mem = (addr_t)ptr;
|
||||
#ifdef _WIN64
|
||||
offset += sizeof (void*);
|
||||
offset += sizeof (void*); /* space for function_table pointer */
|
||||
#endif
|
||||
for (k = 0; k < 2; ++k) {
|
||||
f = 0, addr = k ? mem : mem + ptr_diff;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
if (k != !(s->sh_flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
offset += fill;
|
||||
s->sh_addr = mem ? mem + offset : 0;
|
||||
align = s->sh_addralign - 1;
|
||||
if (++f == 1 && align < RUN_SECTION_ALIGNMENT)
|
||||
align = RUN_SECTION_ALIGNMENT;
|
||||
if (max_align < align)
|
||||
max_align = align;
|
||||
offset += -(addr + offset) & align;
|
||||
s->sh_addr = mem ? addr + offset : 0;
|
||||
offset += s->data_offset;
|
||||
#if 0
|
||||
if (mem)
|
||||
printf("%-16s +%02lx %p %04x\n",
|
||||
s->name, fill, (void*)s->sh_addr, (unsigned)s->data_offset);
|
||||
printf("%-16s %p len %04x align %2d\n",
|
||||
s->name, (void*)s->sh_addr, (unsigned)s->data_offset, align + 1);
|
||||
#endif
|
||||
offset += s->data_offset;
|
||||
fill = -(mem + offset) & 15;
|
||||
}
|
||||
#if RUN_SECTION_ALIGNMENT > 15
|
||||
/* To avoid that x86 processors would reload cached instructions each time
|
||||
when data is written in the near, we need to make sure that code and data
|
||||
do not share the same 64 byte unit */
|
||||
fill = -(mem + offset) & RUN_SECTION_ALIGNMENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* relocate symbols */
|
||||
|
@ -220,7 +232,11 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
|||
return -1;
|
||||
|
||||
if (0 == mem)
|
||||
return offset + RUN_SECTION_ALIGNMENT;
|
||||
return offset + max_align;
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
s1->pe_imagebase = mem;
|
||||
#endif
|
||||
|
||||
/* relocate each section */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
|
@ -230,24 +246,27 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
|||
}
|
||||
relocate_plt(s1);
|
||||
|
||||
#ifdef _WIN64
|
||||
*(void**)ptr = win64_add_function_table(s1);
|
||||
#endif
|
||||
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
ptr = (void*)s->sh_addr;
|
||||
if (s->sh_flags & SHF_EXECINSTR)
|
||||
ptr = (char*)ptr - ptr_diff;
|
||||
if (NULL == s->data || s->sh_type == SHT_NOBITS)
|
||||
memset(ptr, 0, length);
|
||||
else
|
||||
memcpy(ptr, s->data, length);
|
||||
/* mark executable sections as executable in memory */
|
||||
if (s->sh_flags & SHF_EXECINSTR)
|
||||
set_pages_executable(ptr, length);
|
||||
set_pages_executable((char*)ptr + ptr_diff, length);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
*(void**)mem = win64_add_function_table(s1);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -261,15 +280,17 @@ static void set_pages_executable(void *ptr, unsigned long length)
|
|||
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
#else
|
||||
void __clear_cache(void *beginning, void *end);
|
||||
# ifndef HAVE_SELINUX
|
||||
addr_t start, end;
|
||||
#ifndef PAGESIZE
|
||||
# define PAGESIZE 4096
|
||||
#endif
|
||||
# ifndef PAGESIZE
|
||||
# define PAGESIZE 4096
|
||||
# endif
|
||||
start = (addr_t)ptr & ~(PAGESIZE - 1);
|
||||
end = (addr_t)ptr + length;
|
||||
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
|
||||
if (mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
tcc_error("mprotect failed: did you mean to configure --with-selinux?");
|
||||
# endif
|
||||
# if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
|
||||
__clear_cache(ptr, (char *)ptr + length);
|
||||
# endif
|
||||
|
@ -285,11 +306,11 @@ static void *win64_add_function_table(TCCState *s1)
|
|||
RtlAddFunctionTable(
|
||||
(RUNTIME_FUNCTION*)p,
|
||||
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
|
||||
text_section->sh_addr
|
||||
s1->pe_imagebase
|
||||
);
|
||||
s1->uw_pdata = NULL;
|
||||
}
|
||||
return p;;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void win64_del_function_table(void *p)
|
||||
|
@ -418,7 +439,7 @@ no_stabs:
|
|||
if (wanted_pc >= sym->st_value &&
|
||||
wanted_pc < sym->st_value + sym->st_size) {
|
||||
pstrcpy(last_func_name, sizeof(last_func_name),
|
||||
(char *) strtab_section->data + sym->st_name);
|
||||
(char *) symtab_section->link->data + sym->st_name);
|
||||
func_addr = sym->st_value;
|
||||
goto found;
|
||||
}
|
||||
|
|
24
tcctok.h
24
tcctok.h
|
@ -36,7 +36,9 @@
|
|||
DEF(TOK_RESTRICT2, "__restrict")
|
||||
DEF(TOK_RESTRICT3, "__restrict__")
|
||||
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
|
||||
|
||||
|
||||
DEF(TOK_GENERIC, "_Generic")
|
||||
|
||||
DEF(TOK_FLOAT, "float")
|
||||
DEF(TOK_DOUBLE, "double")
|
||||
DEF(TOK_BOOL, "_Bool")
|
||||
|
@ -51,6 +53,7 @@
|
|||
DEF(TOK_ATTRIBUTE2, "__attribute__")
|
||||
DEF(TOK_ALIGNOF1, "__alignof")
|
||||
DEF(TOK_ALIGNOF2, "__alignof__")
|
||||
DEF(TOK_ALIGNOF3, "_Alignof")
|
||||
DEF(TOK_TYPEOF1, "typeof")
|
||||
DEF(TOK_TYPEOF2, "__typeof")
|
||||
DEF(TOK_TYPEOF3, "__typeof__")
|
||||
|
@ -85,6 +88,7 @@
|
|||
DEF(TOK___TIME__, "__TIME__")
|
||||
DEF(TOK___FUNCTION__, "__FUNCTION__")
|
||||
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
|
||||
DEF(TOK___COUNTER__, "__COUNTER__")
|
||||
|
||||
/* special identifiers */
|
||||
DEF(TOK___FUNC__, "__func__")
|
||||
|
@ -117,6 +121,8 @@
|
|||
DEF(TOK_FASTCALL1, "fastcall")
|
||||
DEF(TOK_FASTCALL2, "__fastcall")
|
||||
DEF(TOK_FASTCALL3, "__fastcall__")
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
|
||||
DEF(TOK_MODE, "__mode__")
|
||||
DEF(TOK_MODE_QI, "__QI__")
|
||||
|
@ -127,27 +133,24 @@
|
|||
|
||||
DEF(TOK_DLLEXPORT, "dllexport")
|
||||
DEF(TOK_DLLIMPORT, "dllimport")
|
||||
DEF(TOK_NODECORATE, "nodecorate")
|
||||
DEF(TOK_NORETURN1, "noreturn")
|
||||
DEF(TOK_NORETURN2, "__noreturn__")
|
||||
DEF(TOK_VISIBILITY1, "visibility")
|
||||
DEF(TOK_VISIBILITY2, "__visibility__")
|
||||
|
||||
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
|
||||
DEF(TOK_builtin_choose_expr, "__builtin_choose_expr")
|
||||
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
||||
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
|
||||
DEF(TOK_builtin_return_address, "__builtin_return_address")
|
||||
DEF(TOK_builtin_expect, "__builtin_expect")
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#ifdef TCC_TARGET_PE
|
||||
/*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
|
||||
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
|
||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||
#else
|
||||
#elif defined TCC_TARGET_X86_64
|
||||
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
||||
#endif
|
||||
#endif
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
DEF(TOK___va_start, "__va_start")
|
||||
DEF(TOK___va_arg, "__va_arg")
|
||||
#endif
|
||||
|
@ -164,6 +167,7 @@
|
|||
DEF(TOK_push_macro, "push_macro")
|
||||
DEF(TOK_pop_macro, "pop_macro")
|
||||
DEF(TOK_once, "once")
|
||||
DEF(TOK_option, "option")
|
||||
|
||||
/* builtin functions or variables */
|
||||
#ifndef TCC_ARM_EABI
|
||||
|
|
|
@ -363,9 +363,8 @@ usage:
|
|||
ret = tcc_get_dllexports(file, &p);
|
||||
if (ret || !p) {
|
||||
fprintf(stderr, "tcc: impdef: %s '%s'\n",
|
||||
ret == 32 ? "can't read symbols from 32bit" :
|
||||
ret == 64 ? "can't read symbols from 64bit" :
|
||||
ret == -1 ? "can't find file" :
|
||||
ret == 1 ? "can't read symbols" :
|
||||
ret == 0 ? "no symbols found in" :
|
||||
"unknown file type", file);
|
||||
ret = 1;
|
||||
|
@ -375,7 +374,7 @@ usage:
|
|||
if (v)
|
||||
printf("-> %s\n", file);
|
||||
|
||||
op = fopen(outfile, "w");
|
||||
op = fopen(outfile, "wb");
|
||||
if (NULL == op) {
|
||||
fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
|
||||
goto the_end;
|
||||
|
|
|
@ -16,6 +16,7 @@ TESTS = \
|
|||
memtest \
|
||||
dlltest \
|
||||
abitest \
|
||||
asm-c-connect-test \
|
||||
vla_test-run \
|
||||
cross-test \
|
||||
tests2-dir \
|
||||
|
@ -44,18 +45,17 @@ ifeq ($(CONFIG_arm_eabi),yes)
|
|||
TESTS := $(filter-out test3,$(TESTS))
|
||||
endif
|
||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||
TESTS := $(filter-out dlltest,$(TESTS))
|
||||
TESTS := $(filter-out dlltest asm-c-connect-test,$(TESTS))
|
||||
endif
|
||||
ifndef CONFIG_cross
|
||||
TESTS := $(filter-out cross-%,$(TESTS))
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
SEP = $(if $(findstring :\,$(PATH)),;,:)
|
||||
PATH := $(CURDIR)/$(TOP)$(SEP)$(PATH) # for libtcc_test to find libtcc.dll
|
||||
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring :\,$(PATH)),;,:)$(PATH)
|
||||
endif
|
||||
|
||||
RUN_TCC = $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||
DISAS = objdump -d
|
||||
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
||||
|
||||
|
@ -129,23 +129,23 @@ test4: tcctest.c test.ref
|
|||
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
|
||||
dlltest:
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
|
||||
$(TCC) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
||||
$(TCC) $(NATIVE_DEFINES) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
|
||||
$(TCC) $(NATIVE_DEFINES) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
||||
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
|
||||
ifndef CONFIG_WIN32
|
||||
@echo ------------ $@ with PIC ------------
|
||||
$(CC) $(CFLAGS) -fPIC -DONE_SOURCE $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
|
||||
$(CC) $(CFLAGS) -fPIC $(NATIVE_DEFINES) -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
|
||||
$(TCC) libtcc.o $(LIBS) -shared -o libtcc2$(DLLSUF)
|
||||
$(TCC) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
||||
$(TCC) $(NATIVE_DEFINES) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
||||
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
|
||||
endif
|
||||
@rm tcc2$(EXESUF) libtcc2$(DLLSUF)
|
||||
|
||||
memtest:
|
||||
@echo ------------ $@ ------------
|
||||
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE $(TOPSRC)/tcc.c $(LIBS)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
|
||||
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
|
||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
|
||||
|
||||
|
||||
# memory and bound check auto test
|
||||
|
@ -210,7 +210,7 @@ abitest-cc$(EXESUF): abitest.c $(LIBTCC)
|
|||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS) -w
|
||||
|
||||
abitest-tcc$(EXESUF): abitest.c libtcc.c
|
||||
$(TCC) -o $@ $^ $(NATIVE_DEFINES) -DONE_SOURCE $(LIBS)
|
||||
$(TCC) -o $@ $^ $(NATIVE_DEFINES) $(LIBS)
|
||||
|
||||
ABITESTS := abitest-cc$(EXESUF)
|
||||
ifneq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
|
||||
|
@ -231,11 +231,30 @@ vla_test-run: vla_test$(EXESUF)
|
|||
@echo ------------ $@ ------------
|
||||
./vla_test$(EXESUF)
|
||||
|
||||
asm-c-connect$(EXESUF): asm-c-connect-1.c asm-c-connect-2.c
|
||||
$(TCC) -o $@ $^
|
||||
|
||||
asm-c-connect-%.o: asm-c-connect-%.c
|
||||
$(TCC) -c -o $@ $<
|
||||
|
||||
asm-c-connect-sep$(EXESUF): asm-c-connect-1.o asm-c-connect-2.o
|
||||
$(TCC) -o $@ $^
|
||||
|
||||
asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
|
||||
@echo ------------ $@ ------------
|
||||
./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1
|
||||
./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2
|
||||
@diff -u asm-c-connect.out1 asm-c-connect.out2 && echo "ok"
|
||||
|
||||
cross-test :
|
||||
@echo ------------ $@ ------------
|
||||
$(TOP)/i386-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/x86_64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm-wince-tcc$(EXESUF) $(TCCFLAGS-win) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/arm64-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/c67-tcc$(EXESUF) $(TCCFLAGS-unx) -c $(TOPSRC)/examples/ex3.c && echo "ok"
|
||||
$(TOP)/i386-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
$(TOP)/x86_64-win32-tcc$(EXESUF) $(TCCFLAGS-win) $(TOPSRC)/win32/examples/hello_win.c && echo "ok"
|
||||
|
@ -260,6 +279,7 @@ 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) asm-c-connect-sep$(EXESUF)
|
||||
rm -f ex? tcc_g weaktest.*.txt *.def
|
||||
@$(MAKE) -C tests2 $@
|
||||
@$(MAKE) -C pp $@
|
||||
|
|
|
@ -425,7 +425,7 @@ static int two_member_union_test(void) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Win64 calling convetntion test.
|
||||
* Win64 calling convention test.
|
||||
*/
|
||||
|
||||
typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
|
||||
|
@ -558,6 +558,36 @@ static int stdarg_test(void) {
|
|||
return run_callback(src, stdarg_test_callback);
|
||||
}
|
||||
|
||||
typedef struct {long long a, b;} stdarg_many_test_struct_type;
|
||||
typedef void (*stdarg_many_test_function_type) (int, int, int, int, int,
|
||||
stdarg_many_test_struct_type,
|
||||
int, int, ...);
|
||||
|
||||
static int stdarg_many_test_callback(void *ptr)
|
||||
{
|
||||
stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr;
|
||||
int x;
|
||||
stdarg_many_test_struct_type l = {10, 11};
|
||||
f(1, 2, 3, 4, 5, l, 6, 7, &x, 44);
|
||||
return x == 44 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int stdarg_many_test(void)
|
||||
{
|
||||
const char *src =
|
||||
"#include <stdarg.h>\n"
|
||||
"typedef struct {long long a, b;} stdarg_many_test_struct_type;\n"
|
||||
"void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n"
|
||||
" va_list ap;\n"
|
||||
" int *p;\n"
|
||||
" va_start (ap, g);\n"
|
||||
" p = va_arg(ap, int*);\n"
|
||||
" *p = va_arg(ap, int);\n"
|
||||
" va_end (ap);\n"
|
||||
"}\n";
|
||||
return run_callback(src, stdarg_many_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test Win32 stdarg handling, since the calling convention will pass a pointer
|
||||
* to the struct and the stdarg pointer must point to that pointer initially.
|
||||
|
@ -637,10 +667,10 @@ int main(int argc, char **argv) {
|
|||
RUN_TEST(ret_longdouble_test);
|
||||
RUN_TEST(ret_2float_test);
|
||||
RUN_TEST(ret_2double_test);
|
||||
#if !defined __x86_64__ || defined _WIN32
|
||||
/* currently broken on x86_64 linux */
|
||||
RUN_TEST(ret_8plus2double_test);
|
||||
RUN_TEST(ret_6plus2longlong_test);
|
||||
#if !defined __x86_64__ || defined _WIN32
|
||||
/* currently broken on x86_64 linux */
|
||||
RUN_TEST(ret_mixed_test);
|
||||
RUN_TEST(ret_mixed2_test);
|
||||
#endif
|
||||
|
@ -654,6 +684,7 @@ int main(int argc, char **argv) {
|
|||
RUN_TEST(many_struct_test_2);
|
||||
RUN_TEST(many_struct_test_3);
|
||||
RUN_TEST(stdarg_test);
|
||||
RUN_TEST(stdarg_many_test);
|
||||
RUN_TEST(stdarg_struct_test);
|
||||
RUN_TEST(arg_align_test);
|
||||
return retval;
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#if defined _WIN32 && !defined __TINYC__
|
||||
# define _ "_"
|
||||
#else
|
||||
# define _
|
||||
#endif
|
||||
|
||||
static int x1_c(void)
|
||||
{
|
||||
printf(" x1");
|
||||
return 1;
|
||||
}
|
||||
|
||||
asm(".text;"_"x1: call "_"x1_c; ret");
|
||||
|
||||
void callx4(void);
|
||||
void callx5_again(void);
|
||||
|
||||
void x6()
|
||||
{
|
||||
printf(" x6-1");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("*");
|
||||
asm("call "_"x1");
|
||||
asm("call "_"x2");
|
||||
asm("call "_"x3");
|
||||
callx4();
|
||||
asm("call "_"x5");
|
||||
callx5_again();
|
||||
x6();
|
||||
printf(" *\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2(void)
|
||||
{
|
||||
printf(" x2");
|
||||
return 2;
|
||||
}
|
||||
|
||||
extern int x3(void);
|
||||
|
||||
void x4(void)
|
||||
{
|
||||
printf(" x4");
|
||||
}
|
||||
|
||||
void x5(void);
|
||||
void x5(void)
|
||||
{
|
||||
printf(" x5");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#if defined _WIN32 && !defined __TINYC__
|
||||
# define _ "_"
|
||||
#else
|
||||
# define _
|
||||
#endif
|
||||
|
||||
int x3(void)
|
||||
{
|
||||
printf(" x3");
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* That callx4 is defined globally (as if ".globl callx4")
|
||||
is a TCC extension. GCC doesn't behave like this. */
|
||||
void callx4(void);
|
||||
__asm__(_"callx4: call "_"x4; ret;"
|
||||
#ifndef __TINYC__
|
||||
" .global "_"callx4"
|
||||
#endif
|
||||
);
|
||||
|
||||
extern void x5(void);
|
||||
|
||||
void callx5_again(void);
|
||||
void callx5_again(void)
|
||||
{
|
||||
x5();
|
||||
asm("call "_"x6");
|
||||
}
|
||||
|
||||
static void x6()
|
||||
{
|
||||
printf(" x6-2");
|
||||
}
|
|
@ -577,10 +577,13 @@ fucomip %st(5), %st
|
|||
cmovs 0x1000, %eax
|
||||
cmovns %edx, %edi
|
||||
cmovne %ax, %si
|
||||
cmovbw %ax, %di
|
||||
cmovnbel %edx, %ecx
|
||||
#ifdef __x86_64__
|
||||
bswapq %rsi
|
||||
bswapq %r10
|
||||
cmovz %rdi,%rbx
|
||||
cmovpeq %rsi, %rdx
|
||||
#endif
|
||||
|
||||
int $3
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
# `modelist' label. Each video mode record looks like:
|
||||
.text
|
||||
endtext:
|
||||
|
|
|
@ -12,7 +12,7 @@ return n(A)n(++)n(+)n(+)n(B);
|
|||
return n(0x1E)n(-1);
|
||||
|
||||
// unlike gcc but correct
|
||||
XXX: return n(x)+n(x)-n(1)+n(1)-2;
|
||||
// XXX: return n(x)+n(x)-n(1)+n(1)-2;
|
||||
|
||||
// unlile gcc, but cannot appear in valid C
|
||||
XXX: return n(x)n(x)n(1)n(2)n(x);
|
||||
// unlike gcc, but cannot appear in valid C
|
||||
// XXX: return n(x)n(x)n(1)n(2)n(x);
|
||||
|
|
|
@ -3,5 +3,3 @@ return A+++B;
|
|||
return A+ ++B;
|
||||
return A+++ +B;
|
||||
return 0x1E -1;
|
||||
XXX: return x+x-1 +1 -2;
|
||||
XXX: return x x 1 2 x;
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
#define M_C2I(a, ...) a ## __VA_ARGS__
|
||||
#define M_C(a, ...) M_C2I(a, __VA_ARGS__)
|
||||
#define M_C3I(a, b, ...) a ## b ## __VA_ARGS__
|
||||
#define M_C3(a, b, ...) M_C3I(a ,b, __VA_ARGS__)
|
||||
|
||||
#define M_RETI_ARG2(a, b, ...) b
|
||||
#define M_RET_ARG2(...) M_RETI_ARG2(__VA_ARGS__)
|
||||
#define M_RETI_ARG27(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa, ...) aa
|
||||
#define M_RET_ARG27(...) M_RETI_ARG27(__VA_ARGS__)
|
||||
|
||||
#define M_TOBOOLI_0 1, 0,
|
||||
#define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless)
|
||||
|
||||
#define M_IFI_0(true_macro, ...) __VA_ARGS__
|
||||
#define M_IFI_1(true_macro, ...) true_macro
|
||||
#define M_IF(c) M_C(M_IFI_, M_BOOL(c))
|
||||
|
||||
#define M_FLAT(...) __VA_ARGS__
|
||||
#define M_INVI_0 1
|
||||
#define M_INVI_1 0
|
||||
#define M_INV(x) M_C(M_INVI_, x)
|
||||
|
||||
#define M_ANDI_00 0
|
||||
#define M_ANDI_01 0
|
||||
#define M_ANDI_10 0
|
||||
#define M_ANDI_11 1
|
||||
#define M_AND(x,y) M_C3(M_ANDI_, x, y)
|
||||
|
||||
#define M_ORI_00 0
|
||||
#define M_ORI_01 1
|
||||
#define M_ORI_10 1
|
||||
#define M_ORI_11 1
|
||||
#define M_OR(x,y) M_C3(M_ORI_, x, y)
|
||||
|
||||
#define M_COMMA_P(...) M_RET_ARG27(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless)
|
||||
|
||||
#define M_EMPTYI_DETECT(...) 0, 1,
|
||||
#define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ ())
|
||||
#define M_EMPTYI_P_C2(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__)
|
||||
#define M_EMPTYI_P_C3(...) M_COMMA_P(__VA_ARGS__ () )
|
||||
#define M_EMPTY_P(...) M_AND(M_EMPTYI_P_C1(__VA_ARGS__), M_INV(M_OR(M_OR(M_EMPTYI_P_C2(__VA_ARGS__), M_COMMA_P(__VA_ARGS__)),M_EMPTYI_P_C3(__VA_ARGS__))))
|
||||
#define M_APPLY_FUNC2B(func, arg1, arg2) \
|
||||
M_IF(M_EMPTY_P(arg2))(,func(arg1, arg2))
|
||||
#define M_MAP2B_0(func, data, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,...) \
|
||||
M_APPLY_FUNC2B(func, data, a) M_APPLY_FUNC2B(func, data, b) M_APPLY_FUNC2B(func, data, c) \
|
||||
M_APPLY_FUNC2B(func, data, d) M_APPLY_FUNC2B(func, data, e) M_APPLY_FUNC2B(func, data, f) \
|
||||
M_APPLY_FUNC2B(func, data, g) M_APPLY_FUNC2B(func, data, h) M_APPLY_FUNC2B(func, data, i) \
|
||||
M_APPLY_FUNC2B(func, data, j) M_APPLY_FUNC2B(func, data, k) M_APPLY_FUNC2B(func, data, l) \
|
||||
M_APPLY_FUNC2B(func, data, m) M_APPLY_FUNC2B(func, data, n) M_APPLY_FUNC2B(func, data, o) \
|
||||
M_APPLY_FUNC2B(func, data, p) M_APPLY_FUNC2B(func, data, q) M_APPLY_FUNC2B(func, data, r) \
|
||||
M_APPLY_FUNC2B(func, data, s) M_APPLY_FUNC2B(func, data, t) M_APPLY_FUNC2B(func, data, u) \
|
||||
M_APPLY_FUNC2B(func, data, v) M_APPLY_FUNC2B(func, data, w) M_APPLY_FUNC2B(func, data, x) \
|
||||
M_APPLY_FUNC2B(func, data, y) M_APPLY_FUNC2B(func, data, z)
|
||||
#define M_MAP2B(f, ...) M_MAP2B_0(f, __VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , )
|
||||
#define M_INIT_INIT(a) ,a,
|
||||
|
||||
#define M_GET_METHOD(method, method_default, ...) \
|
||||
M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,)
|
||||
|
||||
#define M_TEST_METHOD_P(method, oplist) \
|
||||
M_BOOL(M_GET_METHOD (method, 0, M_FLAT oplist))
|
||||
|
||||
#define TRUE 1
|
||||
#define TEST1(n) \
|
||||
M_IF(n)(ok,nok)
|
||||
#define TEST2(op) \
|
||||
M_TEST_METHOD_P(INIT, op)
|
||||
#define TEST3(op) \
|
||||
M_IF(M_TEST_METHOD_P(INIT, op))(ok, nok)
|
||||
#define TEST4(op) \
|
||||
TEST1(TEST2(op))
|
||||
#define KO(a) ((void)1)
|
||||
|
||||
/* This checks that the various expansions that ultimately lead to
|
||||
something like 'KO(arg,arg)', where 'KO' comes from a macro
|
||||
expansion reducing from a large macro chain do not are regarded
|
||||
as funclike macro invocation of KO. E.g. X93 and X94 expand to 'KO',
|
||||
but X95 must not consume the (a,b) arguments outside the M_IF()
|
||||
invocation to reduce the 'KO' macro to an invocation. Instead
|
||||
X95 should reduce via M_IF(KO)(a,b) to 'a'.
|
||||
|
||||
The other lines here are variations on this scheme, with X1 to
|
||||
X6 coming from the bug report at
|
||||
http://lists.nongnu.org/archive/html/tinycc-devel/2017-07/msg00017.html */
|
||||
X92 M_IF(KO)
|
||||
X93 M_GET_METHOD(INIT, 0, INIT(KO))
|
||||
X94 M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO)))
|
||||
X95 M_IF(M_GET_METHOD(INIT, 0, INIT(KO)))(a,b)
|
||||
X96 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))
|
||||
X97 M_IF(M_GET_METHOD(INIT, 0, M_FLAT (INIT(KO))))(ok,nok)
|
||||
X98 (M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
|
||||
X99 M_IF(M_TEST_METHOD_P(INIT, (INIT(KO))))(ok, nok)
|
||||
// test begins
|
||||
X1 TEST1(TRUE) // ==> expect ok, get ok
|
||||
// First test with a token which is not a macro
|
||||
X2 TEST2((INIT(ok))) // ==> expect 1, get 1
|
||||
X3 TEST3((INIT(ok))) // ==> expect ok, get ok
|
||||
// Then test with a token which is a macro, but should not be expanded.
|
||||
X4 TEST2((INIT(KO))) // ==> expect 1, get 1
|
||||
X5 TEST4(INIT(KO))
|
||||
X6 TEST3((INIT(KO))) // ==> expect ok, get "error: macro 'KO' used with too many args"
|
|
@ -0,0 +1,14 @@
|
|||
X92 M_IFI_1
|
||||
X93 KO
|
||||
X94 KO
|
||||
X95 a
|
||||
X96 M_IFI_1
|
||||
X97 ok
|
||||
X98 (1)(ok, nok)
|
||||
X99 ok
|
||||
X1 ok
|
||||
X2 1
|
||||
X3 ok
|
||||
X4 1
|
||||
X5 nok
|
||||
X6 ok
|
|
@ -0,0 +1,13 @@
|
|||
/* Various things I encountered while hacking the pre processor */
|
||||
#define wrap(x) x
|
||||
#define pr_warning(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__)
|
||||
#define pr_warn(x,y) pr_warning(x,y)
|
||||
#define net_ratelimited_function(function, ...) function(__VA_ARGS__)
|
||||
X1 net_ratelimited_function(pr_warn, "pipapo", bla);
|
||||
X2 net_ratelimited_function(wrap(pr_warn), "bla", foo);
|
||||
#define two m n
|
||||
#define chain4(a,b,c,d) a ## b ## c ## d
|
||||
X2 chain4(two,o,p,q)
|
||||
X3 chain4(o,two,p,q)
|
||||
X4 chain4(o,p,two,q)
|
||||
X5 chain4(o,p,q,two)
|
|
@ -0,0 +1,6 @@
|
|||
X1 printk(KERN_WARNING "pipapo",bla);
|
||||
X2 printk(KERN_WARNING "bla",foo);
|
||||
X2 twoopq
|
||||
X3 otwopq
|
||||
X4 optwoq
|
||||
X5 opqtwo
|
|
@ -0,0 +1,36 @@
|
|||
/* accept 'defined' as result of substitution */
|
||||
|
||||
----- 1 ------
|
||||
#define AAA 2
|
||||
#define BBB
|
||||
#define CCC (defined ( AAA ) && AAA > 1 && !defined BBB)
|
||||
#if !CCC
|
||||
OK
|
||||
#else
|
||||
NOT OK
|
||||
#endif
|
||||
|
||||
----- 2 ------
|
||||
#undef BBB
|
||||
#if CCC
|
||||
OK
|
||||
#else
|
||||
NOT OK
|
||||
#endif
|
||||
|
||||
----- 3 ------
|
||||
#define DEFINED defined
|
||||
#define DDD (DEFINED ( AAA ) && AAA > 1 && !DEFINED BBB)
|
||||
#if (DDD)
|
||||
OK
|
||||
#else
|
||||
NOT OK
|
||||
#endif
|
||||
|
||||
----- 4 ------
|
||||
#undef AAA
|
||||
#if !(DDD)
|
||||
OK
|
||||
#else
|
||||
NOT OK
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
----- 1 ------
|
||||
OK
|
||||
----- 2 ------
|
||||
OK
|
||||
----- 3 ------
|
||||
OK
|
||||
----- 4 ------
|
||||
OK
|
|
@ -10,9 +10,9 @@ 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 -I "^\#"
|
||||
DIFF_OPTS = -Nu -b -B
|
||||
|
||||
# Filter source directory in warnings/errors (out-of-tree builds)
|
||||
FILTER = 2>&1 | sed 's,$(SRC)/,,g'
|
||||
|
@ -29,12 +29,11 @@ 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 $< >$*.expect 2>&1
|
||||
|
||||
%.expect: # %.S
|
||||
gcc -E -P $< >$*.expect 2>&1
|
||||
gcc -E -P $*.[cS] >$*.expect 2>&1
|
||||
|
||||
# tell make not to delete
|
||||
.PRECIOUS: %.expect
|
||||
|
@ -43,7 +42,7 @@ clean:
|
|||
rm -f *.output
|
||||
|
||||
02.test : DIFF_OPTS += -w
|
||||
15.test : DIFF_OPTS += -I"^XXX:"
|
||||
# 15.test : DIFF_OPTS += -I"^XXX:"
|
||||
|
||||
# diff options:
|
||||
# -b ighore space changes
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
X1 __COUNTER__
|
||||
X2 __COUNTER__
|
||||
#if __COUNTER__
|
||||
X3 __COUNTER__
|
||||
#endif
|
||||
#define pass(x) x
|
||||
#define a x __COUNTER__ y
|
||||
#define a2 pass(__COUNTER__)
|
||||
#define f(c) c __COUNTER__
|
||||
#define apply(d) d d __COUNTER__ x2 f(d) y2 __COUNTER__
|
||||
#define _paste(a,b) a ## b
|
||||
#define paste(a,b) _paste(a,b)
|
||||
#define _paste3(a,b,c) a ## b ## c
|
||||
#define doublepaste(a,b) _paste3(a,b,b)
|
||||
#define str(x) #x
|
||||
X4 a
|
||||
X5 f(a)
|
||||
X6 f(b)
|
||||
X7 f(__COUNTER__)
|
||||
X8 apply(a)
|
||||
X9 apply(f(a))
|
||||
X10 apply(__COUNTER__)
|
||||
X11 apply(a2)
|
||||
X12 str(__COUNTER__)
|
||||
X13 paste(x,__COUNTER__)
|
||||
X14 _paste(x,__COUNTER__)
|
||||
X15 doublepaste(x,__COUNTER__)
|
|
@ -0,0 +1,15 @@
|
|||
X1 0
|
||||
X2 1
|
||||
X3 3
|
||||
X4 x 4 y
|
||||
X5 x 5 y 6
|
||||
X6 b 7
|
||||
X7 8 9
|
||||
X8 x 10 y x 10 y 11 x2 x 10 y 12 y2 13
|
||||
X9 x 14 y 15 x 14 y 15 16 x2 x 14 y 15 17 y2 18
|
||||
X10 19 19 20 x2 19 21 y2 22
|
||||
X11 23 23 24 x2 23 25 y2 26
|
||||
X12 "__COUNTER__"
|
||||
X13 x27
|
||||
X14 x__COUNTER__
|
||||
X15 x2828
|
132
tests/tcctest.c
132
tests/tcctest.c
|
@ -384,7 +384,7 @@ void macro_test(void)
|
|||
MF_s("hi");
|
||||
MF_t("hi");
|
||||
|
||||
/* test macro substituion inside args (should not eat stream) */
|
||||
/* test macro substitution inside args (should not eat stream) */
|
||||
printf("qq=%d\n", qq(qq)(2));
|
||||
|
||||
/* test zero argument case. NOTE: gcc 2.95.x does not accept a
|
||||
|
@ -404,7 +404,7 @@ comment
|
|||
substituted */
|
||||
TEST2();
|
||||
|
||||
/* And again when the name and parenthes are separated by a
|
||||
/* And again when the name and parentheses are separated by a
|
||||
comment. */
|
||||
TEST2 /* the comment */ ();
|
||||
|
||||
|
@ -1050,8 +1050,8 @@ int pad1;
|
|||
but __alignof__ returns the wrong result (4) because we
|
||||
can't store the alignment yet when specified on symbols
|
||||
directly (it's stored in the type so we'd need to make
|
||||
a copy of it).
|
||||
struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
|
||||
a copy of it). -- FIXED */
|
||||
struct aligntest7 altest7[2] __attribute__((aligned(16)));
|
||||
|
||||
struct aligntest8
|
||||
{
|
||||
|
@ -1161,8 +1161,8 @@ void struct_test()
|
|||
sizeof(altest5), __alignof__(altest5));
|
||||
printf("altest6 sizeof=%d alignof=%d\n",
|
||||
sizeof(altest6), __alignof__(altest6));
|
||||
/*printf("altest7 sizeof=%d alignof=%d\n",
|
||||
sizeof(altest7), __alignof__(altest7));*/
|
||||
printf("altest7 sizeof=%d alignof=%d\n",
|
||||
sizeof(altest7), __alignof__(altest7));
|
||||
|
||||
/* empty structures (GCC extension) */
|
||||
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
||||
|
@ -2234,6 +2234,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 +2258,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 +2270,8 @@ int fib(int n)
|
|||
return fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
void __attribute__((aligned(16))) aligned_function(int i) {}
|
||||
|
||||
void funcptr_test()
|
||||
{
|
||||
void (*func)(int);
|
||||
|
@ -2296,6 +2302,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)func) & 15);
|
||||
}
|
||||
|
||||
void lloptest(long long a, long long b)
|
||||
|
@ -2487,6 +2497,11 @@ 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);
|
||||
}
|
||||
|
||||
void manyarg_test(void)
|
||||
|
@ -2899,6 +2914,11 @@ struct hlist_head {
|
|||
struct hlist_node *first, *last;
|
||||
};
|
||||
|
||||
void consume_ulong (unsigned long i)
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
|
||||
void statement_expr_test(void)
|
||||
{
|
||||
int a, i;
|
||||
|
@ -2954,6 +2974,9 @@ void statement_expr_test(void)
|
|||
});
|
||||
printf ("stmtexpr: %d %d %d\n", t, b, c);
|
||||
printf ("stmtexpr: %ld %ld\n", (long)h.first, (long)h.last);
|
||||
|
||||
/* Test that we can give out addresses of local labels. */
|
||||
consume_ulong(({ __label__ __here; __here: (unsigned long)&&__here; }));
|
||||
}
|
||||
|
||||
void local_label_test(void)
|
||||
|
@ -3109,7 +3132,7 @@ static __inline__ unsigned long long inc64(unsigned long long a)
|
|||
unsigned long long res;
|
||||
#ifdef __x86_64__
|
||||
/* Using the A constraint is wrong, and increments are tested
|
||||
elsewere. */
|
||||
elsewhere. */
|
||||
res = a + 1;
|
||||
#else
|
||||
__asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a));
|
||||
|
@ -3197,8 +3220,37 @@ char * get_asm_string (void)
|
|||
char * str = ((char*)bug_table) + bug_table[1];
|
||||
return str;
|
||||
}
|
||||
|
||||
/* This checks another constructs with local labels. */
|
||||
extern unsigned char alld_stuff[];
|
||||
asm(".data\n"
|
||||
".byte 41\n"
|
||||
"alld_stuff:\n"
|
||||
"661:\n"
|
||||
".byte 42\n"
|
||||
"662:\n"
|
||||
".pushsection .data.ignore\n"
|
||||
".long 661b - .\n" /* This reference to 661 generates an external sym
|
||||
which shouldn't somehow overwrite the offset that's
|
||||
already determined for it. */
|
||||
".popsection\n"
|
||||
".byte 662b - 661b\n" /* So that this value is undeniably 1. */);
|
||||
|
||||
void asm_local_label_diff (void)
|
||||
{
|
||||
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
|
||||
}
|
||||
|
||||
/* This checks that static local variables are available from assembler. */
|
||||
void asm_local_statics (void)
|
||||
{
|
||||
static int localint = 41;
|
||||
asm("incl %0" : "+m" (localint));
|
||||
printf ("asm_local_statics: %d\n", localint);
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
unsigned int set;
|
||||
|
||||
void fancy_copy (unsigned *in, unsigned *out)
|
||||
|
@ -3211,7 +3263,7 @@ void fancy_copy2 (unsigned *in, unsigned *out)
|
|||
asm volatile ("mov %0,(%1)" : : "r" (*in), "r" (out) : "memory");
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
#if defined __x86_64__ && !defined _WIN64
|
||||
void clobber_r12(void)
|
||||
{
|
||||
asm volatile("mov $1, %%r12" ::: "r12");
|
||||
|
@ -3220,7 +3272,7 @@ void clobber_r12(void)
|
|||
|
||||
void test_high_clobbers(void)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
#if defined __x86_64__ && !defined _WIN64
|
||||
register long val asm("r12");
|
||||
long val2;
|
||||
/* This tests if asm clobbers correctly save/restore callee saved
|
||||
|
@ -3229,11 +3281,9 @@ void test_high_clobbers(void)
|
|||
correctly capture the data flow, but good enough for us. */
|
||||
asm volatile("mov $0x4542, %%r12" : "=r" (val):: "memory");
|
||||
clobber_r12();
|
||||
#ifndef _WIN64
|
||||
asm volatile("mov %%r12, %0" : "=r" (val2) : "r" (val): "memory");
|
||||
printf("asmhc: 0x%x\n", val2);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static long cpu_number;
|
||||
|
@ -3310,6 +3360,62 @@ void test_asm_dead_code(void)
|
|||
}));
|
||||
}
|
||||
|
||||
void test_asm_call(void)
|
||||
{
|
||||
#if defined __x86_64__ && !defined _WIN64
|
||||
static char str[] = "PATH";
|
||||
char *s;
|
||||
/* This tests if a reference to an undefined symbol from an asm
|
||||
block, which isn't otherwise referenced in this file, is correctly
|
||||
regarded as global symbol, so that it's resolved by other object files
|
||||
or libraries. We chose getenv here, which isn't used anywhere else
|
||||
in this file. (If we used e.g. printf, which is used we already
|
||||
would have a global symbol entry, not triggering the bug which is
|
||||
tested here). */
|
||||
/* two pushes so stack remains aligned */
|
||||
asm volatile ("push %%rdi; push %%rdi; mov %0, %%rdi;"
|
||||
#if 1 && !defined(__TINYC__) && (defined(__PIC__) || defined(__PIE__))
|
||||
"call getenv@plt;"
|
||||
#else
|
||||
"call getenv;"
|
||||
#endif
|
||||
"pop %%rdi; pop %%rdi"
|
||||
: "=a" (s) : "r" (str));
|
||||
printf("asmd: %s\n", s);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined __x86_64__
|
||||
# define RX "(%rip)"
|
||||
#else
|
||||
# define RX
|
||||
#endif
|
||||
|
||||
void asm_dot_test(void)
|
||||
{
|
||||
int x;
|
||||
for (x = 1;; ++x) {
|
||||
int r = x;
|
||||
switch (x) {
|
||||
case 1:
|
||||
asm(".text; lea S"RX",%eax; lea ."RX",%ecx; sub %ecx,%eax; S=.; jmp p0");
|
||||
case 2:
|
||||
asm(".text; jmp .+6; .int 123; mov .-4"RX",%eax; jmp p0");
|
||||
case 3:
|
||||
asm(".data; Y=.; .int 999; X=Y; .int 456; X=.-4");
|
||||
asm(".text; mov X"RX",%eax; jmp p0");
|
||||
case 4:
|
||||
asm(".data; X=.; .int 789; Y=.; .int 999");
|
||||
asm(".text; mov X"RX",%eax; X=Y; jmp p0");
|
||||
case 0:
|
||||
asm(".text; p0=.; mov %%eax,%0;" : "=m"(r)); break;
|
||||
}
|
||||
if (r == x)
|
||||
break;
|
||||
printf("asm_dot_test %d: %d\n", x, r);
|
||||
}
|
||||
}
|
||||
|
||||
void asm_test(void)
|
||||
{
|
||||
char buf[128];
|
||||
|
@ -3370,6 +3476,8 @@ void asm_test(void)
|
|||
asm volatile(".weak override_func3\n.set override_func3, base_func");
|
||||
override_func3();
|
||||
printf("asmstr: %s\n", get_asm_string());
|
||||
asm_local_label_diff();
|
||||
asm_local_statics();
|
||||
#endif
|
||||
/* Check that we can also load structs of appropriate layout
|
||||
into registers. */
|
||||
|
@ -3394,6 +3502,8 @@ void asm_test(void)
|
|||
test_high_clobbers();
|
||||
trace_console(8, 8);
|
||||
test_asm_dead_code();
|
||||
test_asm_call();
|
||||
asm_dot_test();
|
||||
return;
|
||||
label1:
|
||||
goto label2;
|
||||
|
|
|
@ -15,6 +15,19 @@ void qfunc()
|
|||
printf("qfunc()\n");
|
||||
}
|
||||
|
||||
#if !defined(__ARMEL__)
|
||||
/*
|
||||
* At least on ARM (like RPi), zfunc below fails with something like:
|
||||
* +tcc: error: can't relocate value at 1ef93bc,1
|
||||
* Test is temporary removed for this architecture until ARM maintainers
|
||||
* see what happens with this test.
|
||||
*/
|
||||
void zfunc()
|
||||
{
|
||||
((void (*)(void))0) ();
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
|
@ -12,9 +12,49 @@ enum fred
|
|||
h
|
||||
};
|
||||
|
||||
/* All following uses of enum efoo should compile
|
||||
without warning. While forward enums aren't ISO C,
|
||||
it's accepted by GCC also in strict mode, and only warned
|
||||
about with -pedantic. This happens in the real world. */
|
||||
/* Strict ISO C doesn't allow this kind of forward declaration of
|
||||
enums, but GCC accepts it (and gives only pedantic warning), and
|
||||
it occurs in the wild. */
|
||||
enum efoo;
|
||||
struct Sforward_use {
|
||||
int (*fmember) (enum efoo x);
|
||||
};
|
||||
|
||||
extern enum efoo it_real_fn(void);
|
||||
enum efoo {
|
||||
ONE,
|
||||
TWO,
|
||||
};
|
||||
struct S2 {
|
||||
enum efoo (*f2) (void);
|
||||
};
|
||||
void should_compile(struct S2 *s)
|
||||
{
|
||||
s->f2 = it_real_fn;
|
||||
}
|
||||
|
||||
enum efoo it_real_fn(void)
|
||||
{
|
||||
return TWO;
|
||||
}
|
||||
|
||||
static unsigned int deref_uintptr(unsigned int *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
enum Epositive {
|
||||
epos_one, epos_two
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
enum fred frod;
|
||||
enum Epositive epos = epos_two;
|
||||
|
||||
printf("%d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h);
|
||||
/* printf("%d\n", frod); */
|
||||
|
@ -23,6 +63,9 @@ int main()
|
|||
frod = e;
|
||||
printf("%d\n", frod);
|
||||
|
||||
/* Following should compile without warning. */
|
||||
printf ("enum to int: %u\n", deref_uintptr(&epos));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
0 1 2 3 54 73 74 75
|
||||
12
|
||||
54
|
||||
enum to int: 1
|
||||
|
|
|
@ -1,4 +1,30 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
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);
|
||||
|
||||
//Should cleanly fail, not segfault:
|
||||
/*(fp?f:1);*/
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -9,6 +35,19 @@ 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'};
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,4 +44,22 @@ extern const int cb[1][2][3];
|
|||
extern B b;
|
||||
extern int b[1][2][3];
|
||||
|
||||
/* Funny but valid function declaration. */
|
||||
typedef int functype (int);
|
||||
extern functype func;
|
||||
int func(int i)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
/* Even funnier function decl and definition using typeof. */
|
||||
int set_anon_super(void);
|
||||
int set_anon_super(void)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
typedef int sas_type (void);
|
||||
extern typeof(set_anon_super) set_anon_super;
|
||||
extern sas_type set_anon_super;
|
||||
|
||||
/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
struct A {} int i;
|
|
@ -1 +0,0 @@
|
|||
56_btype_excess-1.c:1: error: too many basic types
|
|
@ -1 +0,0 @@
|
|||
char int i;
|
|
@ -1 +0,0 @@
|
|||
57_btype_excess-2.c:1: error: too many basic types
|
|
@ -1,9 +0,0 @@
|
|||
int f(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
58_function_redefinition.c:7: error: redefinition of 'f'
|
|
@ -1 +0,0 @@
|
|||
int (*fct)[42](int x);
|
|
@ -1 +0,0 @@
|
|||
59_function_array.c:1: error: declaration of an array of functions
|
|
@ -1,4 +0,0 @@
|
|||
enum color {RED, GREEN, BLUE};
|
||||
enum color {R, G, B};
|
||||
|
||||
enum color c;
|
|
@ -1 +0,0 @@
|
|||
60_enum_redefinition.c:2: error: struct/union/enum already defined
|
|
@ -0,0 +1,127 @@
|
|||
#if defined test_56_btype_excess_1
|
||||
struct A {} int i;
|
||||
|
||||
#elif defined test_57_btype_excess_2
|
||||
char int i;
|
||||
|
||||
#elif defined test_58_function_redefinition
|
||||
int f(void) { return 0; }
|
||||
int f(void) { return 1; }
|
||||
|
||||
#elif defined test_global_redefinition
|
||||
int xxx = 1;
|
||||
int xxx;
|
||||
int xxx = 2;
|
||||
|
||||
#elif defined test_59_function_array
|
||||
int (*fct)[42](int x);
|
||||
|
||||
#elif defined test_60_enum_redefinition
|
||||
enum color { RED, GREEN, BLUE };
|
||||
enum color { R, G, B };
|
||||
enum color c;
|
||||
|
||||
#elif defined test_62_enumerator_redefinition
|
||||
enum color { RED, GREEN, BLUE };
|
||||
enum rgb { RED, G, B};
|
||||
enum color c = RED;
|
||||
|
||||
#elif defined test_63_local_enumerator_redefinition
|
||||
enum {
|
||||
FOO,
|
||||
BAR
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
enum {
|
||||
FOO = 2,
|
||||
BAR
|
||||
};
|
||||
|
||||
return BAR - FOO;
|
||||
}
|
||||
|
||||
#elif defined test_61_undefined_enum
|
||||
enum rgb3 c = 42;
|
||||
|
||||
#elif defined test_74_non_const_init
|
||||
int i = i++;
|
||||
|
||||
#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); }
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
[test_56_btype_excess_1]
|
||||
60_errors_and_warnings.c:2: error: too many basic types
|
||||
|
||||
[test_57_btype_excess_2]
|
||||
60_errors_and_warnings.c:5: error: too many basic types
|
||||
|
||||
[test_58_function_redefinition]
|
||||
60_errors_and_warnings.c:9: error: redefinition of 'f'
|
||||
|
||||
[test_global_redefinition]
|
||||
60_errors_and_warnings.c:14: error: redefinition of 'xxx'
|
||||
|
||||
[test_59_function_array]
|
||||
60_errors_and_warnings.c:17: error: declaration of an array of functions
|
||||
|
||||
[test_60_enum_redefinition]
|
||||
60_errors_and_warnings.c:21: error: struct/union/enum already defined
|
||||
|
||||
[test_62_enumerator_redefinition]
|
||||
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
|
||||
|
||||
[test_63_local_enumerator_redefinition]
|
||||
|
||||
[test_61_undefined_enum]
|
||||
60_errors_and_warnings.c:46: error: unknown type size
|
||||
|
||||
[test_74_non_const_init]
|
||||
60_errors_and_warnings.c:49: error: initializer element is not constant
|
||||
|
||||
[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
|
|
@ -1 +0,0 @@
|
|||
enum rgb c = 42;
|
|
@ -1 +0,0 @@
|
|||
61_undefined_enum.c:1: error: unknown type size
|
|
@ -1,4 +0,0 @@
|
|||
enum color {RED, GREEN, BLUE};
|
||||
enum rgb {RED, G, B};
|
||||
|
||||
enum color c = RED;
|
|
@ -1 +0,0 @@
|
|||
62_enumerator_redefinition.c:2: error: redefinition of enumerator 'RED'
|
|
@ -1,14 +0,0 @@
|
|||
enum {
|
||||
FOO,
|
||||
BAR
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
enum {
|
||||
FOO = 2,
|
||||
BAR
|
||||
};
|
||||
|
||||
return BAR - FOO;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
int i = i++;
|
|
@ -1 +0,0 @@
|
|||
74_nocode_wanted.c:1: error: initializer element is not constant
|
|
@ -11,4 +11,30 @@ typedef union __attribute__((packed)) Unaligned16b {
|
|||
uint8_t b[2];
|
||||
} Unaligned16b;
|
||||
|
||||
int main () { return 0; }
|
||||
extern void foo (void) __attribute__((stdcall));
|
||||
void __attribute__((stdcall)) foo (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* 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 *, ...);
|
||||
int main()
|
||||
{
|
||||
void *function_pointer = &actual_function;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
42
|
||||
42
|
|
@ -9,7 +9,7 @@ static void kb_wait_1(void)
|
|||
/* Here the else arm is a statement expression that's supposed
|
||||
to be suppressed. The label inside the while would unsuppress
|
||||
code generation again if not handled correctly. And that
|
||||
would wreak havok to the cond-expression because there's no
|
||||
would wreak havoc to the cond-expression because there's no
|
||||
jump-around emitted, the whole statement expression really
|
||||
needs to not generate code (perhaps except useless forward jumps). */
|
||||
(1 ?
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -16,3 +16,8 @@ once3
|
|||
twice3
|
||||
caseok
|
||||
caseok2
|
||||
g=1
|
||||
check 1
|
||||
g=2
|
||||
check 2
|
||||
g=3
|
||||
|
|
|
@ -60,7 +60,7 @@ struct U gu4 = { 3, {5,6,7,}, 5, { "bla", {44}} };
|
|||
struct S gs3 = { (1), {(2)}, {(((3))), {4}}};
|
||||
/* Superfluous braces, and leaving out braces for V.t, plus cast */
|
||||
struct V gv = {{{3},4,{5,6}}, "haha", (u8)45, 46};
|
||||
/* Compund literal */
|
||||
/* Compound literal */
|
||||
struct V gv2 = {(struct S){7,8,{9,10}}, {"hihi", 47}, 48};
|
||||
/* Parens around compound literal */
|
||||
struct V gv3 = {((struct S){7,8,{9,10}}), {"hoho", 49}, 50};
|
||||
|
@ -157,7 +157,7 @@ void foo (struct W *w, struct pkthdr *phdr_)
|
|||
struct S ls3 = { (1), (2), {(((3))), 4}};
|
||||
/* Superfluous braces, and leaving out braces for V.t, plus cast */
|
||||
struct V lv = {{3,4,{5,6}}, "haha", (u8)45, 46};
|
||||
/* Compund literal */
|
||||
/* Compound literal */
|
||||
struct V lv2 = {(struct S)w->t.s, {"hihi", 47}, 48};
|
||||
/* Parens around compound literal */
|
||||
struct V lv3 = {((struct S){7,8,{9,10}}), ((const struct W *)w)->t.t, 50};
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
#include <stdio.h>
|
||||
|
||||
const int a = 0;
|
||||
|
||||
struct a {
|
||||
int a;
|
||||
};
|
||||
|
||||
struct b {
|
||||
int a;
|
||||
};
|
||||
|
||||
int a_f()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
int b_f()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
typedef int (*fptr)(int);
|
||||
int foo(int i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
typedef int int_type1;
|
||||
|
||||
#define gen_sw(a) _Generic(a, const char *: 1, default: 8, int: 123);
|
||||
|
||||
int main()
|
||||
{
|
||||
int i = 0;
|
||||
signed long int l = 2;
|
||||
struct b titi;
|
||||
const int * const ptr;
|
||||
const char *ti;
|
||||
int_type1 i2;
|
||||
|
||||
i = _Generic(a, int: a_f, const int: b_f)();
|
||||
printf("%d\n", i);
|
||||
i = _Generic(a, int: a_f() / 2, const int: b_f() / 2);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(ptr, int *:1, int * const:2, default:20);
|
||||
printf("%d\n", i);
|
||||
i = gen_sw(a);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(titi, struct a:1, struct b:2, default:20);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(i2, char: 1, int : 0);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(a, char:1, int[4]:2, default:5);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(17, int :1, int **:2);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(17L, int :1, long :2, long long : 3);
|
||||
printf("%d\n", i);
|
||||
i = _Generic("17, io", char *: 3, const char *: 1);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(ti, const unsigned char *:1, const char *:4, char *:3,
|
||||
const signed char *:2);
|
||||
printf("%d\n", i);
|
||||
printf("%s\n", _Generic(i + 2L, long: "long", int: "int",
|
||||
long long: "long long"));
|
||||
i = _Generic(l, long: 1, int: 2);
|
||||
printf("%d\n", i);
|
||||
i = _Generic(foo, fptr: 3, int: 4);
|
||||
printf("%d\n", i);
|
||||
|
||||
(void)_Generic((int(*)[2]){0}, int(*)[2]:0, int(*)[4]:0); //shouldn't match twice
|
||||
|
||||
//should accept ({ }) in the controlling expr of _Generic even in const_wanted contexts
|
||||
struct { _Bool x_0: _Generic(({0;}),default:1); } my_x;
|
||||
|
||||
_Generic((__typeof((float const)((float const){42}))*){0}, float*: 0); //casts lose top-level qualifiers
|
||||
int const x = 42; __typeof((__typeof(x))x) *xp = 0; (void)_Generic(xp, int*: 0); //casts lose top-level qualifiers
|
||||
|
||||
//TEST TERNARY:
|
||||
//Same type
|
||||
_Generic( 0?(long*)0:(long*)0, long*: (void)0);
|
||||
//combining of qualifiers
|
||||
_Generic( 0?(long volatile*)0:(long const*)0, long const volatile*: (void)0);
|
||||
//nul-ptr constant selects other type
|
||||
_Generic( 0?(long*)0:0, long*: (void)0);
|
||||
_Generic( 0?(long*)0:(void*)0, long*: (void)0);
|
||||
|
||||
//void ptrs get chosen preferentially; qualifs still combine
|
||||
_Generic( 0?(int volatile*)0: (void const*)1, void volatile const*: (void)0);
|
||||
//like gcc but not clang, don't treat (void* const as the null-ptr constant)
|
||||
_Generic( 0?(int volatile*)0: (void const*)0, void volatile const*: (void)0);
|
||||
|
||||
//ptrs to incomplete types get completed
|
||||
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
|
||||
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
|
||||
|
||||
{
|
||||
/* completion shouldn't affect the type of decl */
|
||||
char **argv;
|
||||
_Generic(argv, char**: (void)0);
|
||||
_Generic(0?(char const*)0:argv[0], char const*: (void)0);
|
||||
_Generic(argv, char**: (void)0);
|
||||
}
|
||||
{
|
||||
extern int (*ar)[];
|
||||
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : (int (*)[])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
|
||||
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[])0 : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
|
||||
(void)(sizeof(struct { int x:_Generic( 0?ar : (int (*)[4])0, int (*)[4]:+1, int (*)[5]:(void)0); }));
|
||||
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[4])0 : ar, int (*)[4]:+1, int (*)[5]:(void)0); }));
|
||||
(void)(sizeof(struct { int x:_Generic( 0?(int (*)[5])0 : ar, int (*)[5]:+1, int (*)[4]:(void)0); }));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
20
|
||||
10
|
||||
20
|
||||
123
|
||||
2
|
||||
0
|
||||
5
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
long
|
||||
1
|
||||
3
|
|
@ -0,0 +1,218 @@
|
|||
/* ----------------------------------------------------------------------- */
|
||||
#if TEST == 1
|
||||
{
|
||||
struct M P A __s
|
||||
{
|
||||
unsigned x : 12;
|
||||
unsigned char y : 7;
|
||||
unsigned z : 28;
|
||||
unsigned a: 4;
|
||||
unsigned b: 5;
|
||||
};
|
||||
TEST_STRUCT(0x333,0x44,0x555555,6,7);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif TEST == 2
|
||||
{
|
||||
struct M P __s
|
||||
{
|
||||
int x: 12;
|
||||
char y: 6;
|
||||
long long z:63;
|
||||
A char a:4;
|
||||
long long b:2;
|
||||
|
||||
};
|
||||
TEST_STRUCT(3,30,0x123456789abcdef0LL,5,2);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif TEST == 3
|
||||
{
|
||||
struct M P __s
|
||||
{
|
||||
unsigned x:5, y:5, :0, z:5; char a:5; A short b:5;
|
||||
};
|
||||
TEST_STRUCT(21,23,25,6,14);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif TEST == 4
|
||||
{
|
||||
struct M P __s {
|
||||
int x : 3;
|
||||
int : 2;
|
||||
int y : 1;
|
||||
int : 0;
|
||||
int z : 5;
|
||||
int a : 7;
|
||||
unsigned int b : 7;
|
||||
};
|
||||
TEST_STRUCT(3,1,15,120,120);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif TEST == 5
|
||||
{
|
||||
struct M P __s {
|
||||
long long x : 45;
|
||||
long long : 2;
|
||||
long long y : 30;
|
||||
unsigned long long z : 38;
|
||||
char a; short b;
|
||||
};
|
||||
TEST_STRUCT(0x123456789ULL, 120<<25, 120, 0x44, 0x77);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif TEST == 6
|
||||
{
|
||||
struct M P __s {
|
||||
int a;
|
||||
signed char b;
|
||||
int x : 12, y : 4, : 0, : 4, z : 3;
|
||||
char d;
|
||||
};
|
||||
TEST_STRUCT(1,2,3,4,-3);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif defined PACK
|
||||
|
||||
#if PACK
|
||||
# pragma pack(push,1)
|
||||
# define P //_P
|
||||
#else
|
||||
# define P
|
||||
#endif
|
||||
|
||||
printf("\n\n" + 2*top);
|
||||
#define TEST 1
|
||||
#include SELF
|
||||
top = 0;
|
||||
#define TEST 2
|
||||
#include SELF
|
||||
#define TEST 3
|
||||
#include SELF
|
||||
#define TEST 4
|
||||
#include SELF
|
||||
#define TEST 5
|
||||
#include SELF
|
||||
#define TEST 6
|
||||
#include SELF
|
||||
|
||||
#if PACK
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#undef P
|
||||
#undef PACK
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif defined ALIGN
|
||||
|
||||
#if ALIGN
|
||||
# define A _A(16)
|
||||
#else
|
||||
# define A
|
||||
#endif
|
||||
|
||||
#define PACK 0
|
||||
#include SELF
|
||||
#define PACK 1
|
||||
#include SELF
|
||||
|
||||
#undef A
|
||||
#undef ALIGN
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#elif defined MS_BF
|
||||
|
||||
#if MS_BF
|
||||
# ifdef __TINYC__
|
||||
# pragma comment(option, "-mms-bitfields")
|
||||
# elif defined __GNUC__
|
||||
# define M __attribute__((ms_struct))
|
||||
# endif
|
||||
#else
|
||||
# ifdef __TINYC__
|
||||
# pragma comment(option, "-mno-ms-bitfields")
|
||||
# elif defined __GNUC__
|
||||
# define M __attribute__((gcc_struct))
|
||||
# endif
|
||||
#endif
|
||||
#ifndef M
|
||||
# define M
|
||||
#endif
|
||||
|
||||
#define ALIGN 0
|
||||
#include SELF
|
||||
#define ALIGN 1
|
||||
#include SELF
|
||||
|
||||
#undef M
|
||||
#undef MS_BF
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
/* some gcc headers #define __attribute__ to empty if it's not gcc */
|
||||
#undef __attribute__
|
||||
|
||||
void dump(void *p, int s)
|
||||
{
|
||||
int i;
|
||||
for (i = s; --i >= 0;)
|
||||
printf("%02X", ((unsigned char*)p)[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#define pv(m) \
|
||||
printf(sizeof (s->m + 0) == 8 ? " %016llx" : " %02x", s->m)
|
||||
|
||||
#define TEST_STRUCT(v1,v2,v3,v4,v5) { \
|
||||
struct __s _s, *s = & _s; \
|
||||
printf("\n---- TEST %d%s%s%s ----\n" + top, \
|
||||
TEST, MS_BF?" - MS-BITFIELDS":"", \
|
||||
PACK?" - PACKED":"", \
|
||||
ALIGN?" - WITH ALIGN":""); \
|
||||
memset(s, 0, sizeof *s); \
|
||||
s->x = -1, s->y = -1, s->z = -1, s->a = -1, s->b = -1; \
|
||||
printf("bits in use : "), dump(s, sizeof *s); \
|
||||
s->x = v1, s->y = v2, s->z = v3, s->a += v4, ++s->a, s->b = v5; \
|
||||
printf("bits as set : "), dump(s, sizeof *s); \
|
||||
printf("values :"), pv(x), pv(y), pv(z), pv(a), pv(b), printf("\n"); \
|
||||
printf("align/size : %d %d\n", alignof(struct __s),sizeof(struct __s)); \
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _A(n) __declspec(align(n))
|
||||
# define _P
|
||||
# define alignof(x) __alignof(x)
|
||||
#else
|
||||
# define _A(n) __attribute__((aligned(n)))
|
||||
# define _P __attribute__((packed))
|
||||
# define alignof(x) __alignof__(x)
|
||||
#endif
|
||||
|
||||
#ifndef MS_BITFIELDS
|
||||
# define MS_BITFIELDS 0
|
||||
#endif
|
||||
|
||||
#define SELF "95_bitfields.c"
|
||||
|
||||
int top = 1;
|
||||
|
||||
int main()
|
||||
{
|
||||
#define MS_BF MS_BITFIELDS
|
||||
#include SELF
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#endif
|
||||
#undef TEST
|
|
@ -0,0 +1,149 @@
|
|||
---- TEST 1 ----
|
||||
bits in use : 0000001FFFFFFFFF007F0FFF
|
||||
bits as set : 000000076055555500440333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 4 12
|
||||
|
||||
---- TEST 2 ----
|
||||
bits in use : 000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF
|
||||
bits as set : 0000000000000025123456789ABCDEF000000000001E0003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffe
|
||||
align/size : 8 24
|
||||
|
||||
---- TEST 3 ----
|
||||
bits in use : 001F1F1F000003FF
|
||||
bits as set : 000E0619000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 4 8
|
||||
|
||||
---- TEST 4 ----
|
||||
bits in use : 0007FFFF00000027
|
||||
bits as set : 00078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 4 8
|
||||
|
||||
---- TEST 5 ----
|
||||
bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
|
||||
bits as set : 007744000000007800000000300000000000000123456789
|
||||
values : 0000000123456789 f0000000 0000000000000078 44 77
|
||||
align/size : 8 24
|
||||
|
||||
---- TEST 6 ----
|
||||
bits in use : 0000007000FFFFFFFFFFFFFF
|
||||
bits as set : 00000030002001FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 4 12
|
||||
|
||||
|
||||
|
||||
---- TEST 1 - PACKED ----
|
||||
bits in use : FFFFFFFFFFFFFF
|
||||
bits as set : 3B02AAAAAC4333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 1 7
|
||||
|
||||
---- TEST 2 - PACKED ----
|
||||
bits in use : 7FFFFFFFFFFFFFFFFFFFFF
|
||||
bits as set : 4A48D159E26AF37BC1E003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffe
|
||||
align/size : 1 11
|
||||
|
||||
---- TEST 3 - PACKED ----
|
||||
bits in use : 7FFF000003FF
|
||||
bits as set : 38D9000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 1 6
|
||||
|
||||
---- TEST 4 - PACKED ----
|
||||
bits in use : 07FFFF00000027
|
||||
bits as set : 078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 1 7
|
||||
|
||||
---- TEST 5 - PACKED ----
|
||||
bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF
|
||||
bits as set : 007744000000000F18000000000123456789
|
||||
values : 0000000123456789 f0000000 0000000000000078 44 77
|
||||
align/size : 1 18
|
||||
|
||||
---- TEST 6 - PACKED ----
|
||||
bits in use : 007000FFFFFFFFFFFFFF
|
||||
bits as set : 0030002001FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 1 10
|
||||
|
||||
|
||||
|
||||
---- TEST 1 - WITH ALIGN ----
|
||||
bits in use : 000000000000001FFFFFFFFF007F0FFF
|
||||
bits as set : 00000000000000076055555500440333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 16 16
|
||||
|
||||
---- TEST 2 - WITH ALIGN ----
|
||||
bits in use : 0000000000000000000000000000003F7FFFFFFFFFFFFFFF00000000003F0FFF
|
||||
bits as set : 00000000000000000000000000000025123456789ABCDEF000000000001E0003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffe
|
||||
align/size : 16 32
|
||||
|
||||
---- TEST 3 - WITH ALIGN ----
|
||||
bits in use : 0000000000000000000000000000001F000000000000000000001F1F000003FF
|
||||
bits as set : 0000000000000000000000000000000E000000000000000000000619000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 16 32
|
||||
|
||||
---- TEST 4 - WITH ALIGN ----
|
||||
bits in use : 0007FFFF00000027
|
||||
bits as set : 00078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 4 8
|
||||
|
||||
---- TEST 5 - WITH ALIGN ----
|
||||
bits in use : FFFFFF3FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
|
||||
bits as set : 007744000000007800000000300000000000000123456789
|
||||
values : 0000000123456789 f0000000 0000000000000078 44 77
|
||||
align/size : 8 24
|
||||
|
||||
---- TEST 6 - WITH ALIGN ----
|
||||
bits in use : 0000007000FFFFFFFFFFFFFF
|
||||
bits as set : 00000030002001FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 4 12
|
||||
|
||||
|
||||
|
||||
---- TEST 1 - PACKED - WITH ALIGN ----
|
||||
bits in use : 000000000000000000FFFFFFFFFFFFFF
|
||||
bits as set : 0000000000000000003B02AAAAAC4333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 16 16
|
||||
|
||||
---- TEST 2 - PACKED - WITH ALIGN ----
|
||||
bits in use : 3F01FFFFFFFFFFFFFFFFFFFF
|
||||
bits as set : 250048D159E26AF37BC1E003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffe
|
||||
align/size : 1 12
|
||||
|
||||
---- TEST 3 - PACKED - WITH ALIGN ----
|
||||
bits in use : 1F03FF000003FF
|
||||
bits as set : 0E00D9000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 1 7
|
||||
|
||||
---- TEST 4 - PACKED - WITH ALIGN ----
|
||||
bits in use : 07FFFF00000027
|
||||
bits as set : 078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 1 7
|
||||
|
||||
---- TEST 5 - PACKED - WITH ALIGN ----
|
||||
bits in use : FFFFFF07FFFFFFFFFFFFFFFF9FFFFFFFFFFF
|
||||
bits as set : 007744000000000F18000000000123456789
|
||||
values : 0000000123456789 f0000000 0000000000000078 44 77
|
||||
align/size : 1 18
|
||||
|
||||
---- TEST 6 - PACKED - WITH ALIGN ----
|
||||
bits in use : 007000FFFFFFFFFFFFFF
|
||||
bits as set : 0030002001FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 1 10
|
|
@ -0,0 +1,2 @@
|
|||
#define MS_BITFIELDS 1
|
||||
#include "95_bitfields.c"
|
|
@ -0,0 +1,149 @@
|
|||
---- TEST 1 - MS-BITFIELDS ----
|
||||
bits in use : 0000001FFFFFFFFF0000007F00000FFF
|
||||
bits as set : 00000007605555550000004400000333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 4 16
|
||||
|
||||
---- TEST 2 - MS-BITFIELDS ----
|
||||
bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF
|
||||
bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
|
||||
align/size : 8 32
|
||||
|
||||
---- TEST 3 - MS-BITFIELDS ----
|
||||
bits in use : 001F001F0000001F000003FF
|
||||
bits as set : 000E000600000019000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 4 12
|
||||
|
||||
---- TEST 4 - MS-BITFIELDS ----
|
||||
bits in use : 0007FFFF00000027
|
||||
bits as set : 00078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 4 8
|
||||
|
||||
---- TEST 5 - MS-BITFIELDS ----
|
||||
bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
|
||||
bits as set : 0000000000770044000000000000007800000000300000000000000123456789
|
||||
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
|
||||
align/size : 8 32
|
||||
|
||||
---- TEST 6 - MS-BITFIELDS ----
|
||||
bits in use : 00000000000000700000FFFF000000FFFFFFFFFF
|
||||
bits as set : 000000000000003000002001000000FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 4 20
|
||||
|
||||
|
||||
|
||||
---- TEST 1 - MS-BITFIELDS - PACKED ----
|
||||
bits in use : 0000001FFFFFFFFF7F00000FFF
|
||||
bits as set : 00000007605555554400000333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 1 13
|
||||
|
||||
---- TEST 2 - MS-BITFIELDS - PACKED ----
|
||||
bits in use : 00000000000000030F7FFFFFFFFFFFFFFF3F00000FFF
|
||||
bits as set : 000000000000000205123456789ABCDEF01E00000003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
|
||||
align/size : 1 22
|
||||
|
||||
---- TEST 3 - MS-BITFIELDS - PACKED ----
|
||||
bits in use : 001F1F0000001F000003FF
|
||||
bits as set : 000E0600000019000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 1 11
|
||||
|
||||
---- TEST 4 - MS-BITFIELDS - PACKED ----
|
||||
bits in use : 0007FFFF00000027
|
||||
bits as set : 00078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 1 8
|
||||
|
||||
---- TEST 5 - MS-BITFIELDS - PACKED ----
|
||||
bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
|
||||
bits as set : 007744000000000000007800000000300000000000000123456789
|
||||
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
|
||||
align/size : 1 27
|
||||
|
||||
---- TEST 6 - MS-BITFIELDS - PACKED ----
|
||||
bits in use : 00000000700000FFFFFFFFFFFFFF
|
||||
bits as set : 000000003000002001FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 1 14
|
||||
|
||||
|
||||
|
||||
---- TEST 1 - MS-BITFIELDS - WITH ALIGN ----
|
||||
bits in use : 0000001FFFFFFFFF0000007F00000FFF
|
||||
bits as set : 00000007605555550000004400000333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 16 16
|
||||
|
||||
---- TEST 2 - MS-BITFIELDS - WITH ALIGN ----
|
||||
bits in use : 0000000000000003000000000000000F7FFFFFFFFFFFFFFF0000003F00000FFF
|
||||
bits as set : 00000000000000020000000000000005123456789ABCDEF00000001E00000003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
|
||||
align/size : 16 32
|
||||
|
||||
---- TEST 3 - MS-BITFIELDS - WITH ALIGN ----
|
||||
bits in use : 0000000000000000000000000000001F000000000000001F0000001F000003FF
|
||||
bits as set : 0000000000000000000000000000000E000000000000000600000019000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 16 32
|
||||
|
||||
---- TEST 4 - MS-BITFIELDS - WITH ALIGN ----
|
||||
bits in use : 0007FFFF00000027
|
||||
bits as set : 00078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 4 8
|
||||
|
||||
---- TEST 5 - MS-BITFIELDS - WITH ALIGN ----
|
||||
bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
|
||||
bits as set : 0000000000770044000000000000007800000000300000000000000123456789
|
||||
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
|
||||
align/size : 8 32
|
||||
|
||||
---- TEST 6 - MS-BITFIELDS - WITH ALIGN ----
|
||||
bits in use : 00000000000000700000FFFF000000FFFFFFFFFF
|
||||
bits as set : 000000000000003000002001000000FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 4 20
|
||||
|
||||
|
||||
|
||||
---- TEST 1 - MS-BITFIELDS - PACKED - WITH ALIGN ----
|
||||
bits in use : 0000000000001FFFFFFFFF7F00000FFF
|
||||
bits as set : 00000000000007605555554400000333
|
||||
values : 333 44 555555 06 07
|
||||
align/size : 16 16
|
||||
|
||||
---- TEST 2 - MS-BITFIELDS - PACKED - WITH ALIGN ----
|
||||
bits in use : 00000000000000030F0000007FFFFFFFFFFFFFFF3F00000FFF
|
||||
bits as set : 000000000000000205000000123456789ABCDEF01E00000003
|
||||
values : 03 1e 123456789abcdef0 05 fffffffffffffffe
|
||||
align/size : 16 25
|
||||
|
||||
---- TEST 3 - MS-BITFIELDS - PACKED - WITH ALIGN ----
|
||||
bits in use : 001F000000000000001F0000001F000003FF
|
||||
bits as set : 000E000000000000000600000019000002F5
|
||||
values : 15 17 19 06 0e
|
||||
align/size : 16 18
|
||||
|
||||
---- TEST 4 - MS-BITFIELDS - PACKED - WITH ALIGN ----
|
||||
bits in use : 0007FFFF00000027
|
||||
bits as set : 00078F0F00000023
|
||||
values : 03 ffffffff 0f fffffff8 78
|
||||
align/size : 1 8
|
||||
|
||||
---- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ----
|
||||
bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
|
||||
bits as set : 007744000000000000007800000000300000000000000123456789
|
||||
values : 0000000123456789 fffffffff0000000 0000000000000078 44 77
|
||||
align/size : 1 27
|
||||
|
||||
---- TEST 6 - MS-BITFIELDS - PACKED - WITH ALIGN ----
|
||||
bits in use : 00000000700000FFFFFFFFFFFFFF
|
||||
bits as set : 000000003000002001FD00000004
|
||||
values : 01 02 03 04 fffffffd
|
||||
align/size : 1 14
|
|
@ -0,0 +1,98 @@
|
|||
/*****************************************************************************/
|
||||
/* test 'nodata_wanted' data output suppression */
|
||||
|
||||
#if defined test_static_data_error
|
||||
void foo() {
|
||||
if (1) {
|
||||
static short w = (int)&foo; /* initializer not computable */
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined test_static_nodata_error
|
||||
void foo() {
|
||||
if (0) {
|
||||
static short w = (int)&foo; /* initializer not computable */
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined test_global_data_error
|
||||
void foo();
|
||||
static short w = (int)&foo; /* initializer not computable */
|
||||
|
||||
|
||||
#elif defined test_local_data_noerror
|
||||
void foo() {
|
||||
short w = &foo; /* 2 cast warnings */
|
||||
}
|
||||
|
||||
#elif defined test_data_suppression_off || defined test_data_suppression_on
|
||||
|
||||
#if defined test_data_suppression_on
|
||||
# define SKIP 1
|
||||
#else
|
||||
# define SKIP 0
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
/* some gcc headers #define __attribute__ to empty if it's not gcc */
|
||||
#undef __attribute__
|
||||
|
||||
int main()
|
||||
{
|
||||
__label__ ts0, te0, ts1, te1;
|
||||
int tl, dl;
|
||||
|
||||
static char ds0 = 0;
|
||||
static char de0 = 0;
|
||||
/* get reference size of empty jmp */
|
||||
ts0:;
|
||||
if (!SKIP) {}
|
||||
te0:;
|
||||
dl = -(&de0 - &ds0);
|
||||
tl = -(&&te0 - &&ts0);
|
||||
|
||||
/* test data and code suppression */
|
||||
static char ds1 = 0;
|
||||
ts1:;
|
||||
if (!SKIP) {
|
||||
void *p = (void*)&main;
|
||||
char cc[] = "static string";
|
||||
double d = 8.0;
|
||||
struct __attribute__((packed)) {
|
||||
unsigned x : 12;
|
||||
unsigned char y : 7;
|
||||
unsigned z : 28, a: 4, b: 5;
|
||||
} s = { 0x333,0x44,0x555555,6,7 };
|
||||
|
||||
printf("data:\n");
|
||||
printf(" %d - %.1f - %.1f - %s - %s\n",
|
||||
sizeof 8.0, 8.0, d, __FUNCTION__, cc);
|
||||
printf(" %x %x %x %x %x\n",
|
||||
s.x, s.y, s.z, s.a, s.b);
|
||||
}
|
||||
te1:;
|
||||
static char de1 = 0;
|
||||
|
||||
dl += &de1 - &ds1;
|
||||
tl += &&te1 - &&ts1;
|
||||
printf("size of data/text:\n %s/%s\n",
|
||||
dl ? "non-zero":"zero", tl ? "non-zero":"zero");
|
||||
/*printf("# %d/%d\n", dl, tl);*/
|
||||
}
|
||||
|
||||
#elif defined test_static_data
|
||||
|
||||
#include <stdio.h>
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
goto there;
|
||||
if (0) {
|
||||
static int a = 1;
|
||||
printf("hello\n"); /* the "hello\n" string is still suppressed */
|
||||
there:
|
||||
printf("a = %d\n", a);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
[test_static_data_error]
|
||||
96_nodata_wanted.c:7: error: initializer element is not computable at load time
|
||||
|
||||
[test_static_nodata_error]
|
||||
96_nodata_wanted.c:14: error: initializer element is not computable at load time
|
||||
|
||||
[test_global_data_error]
|
||||
96_nodata_wanted.c:20: error: initializer element is not computable at load time
|
||||
|
||||
[test_local_data_noerror]
|
||||
96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast
|
||||
96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short
|
||||
|
||||
[test_data_suppression_off]
|
||||
data:
|
||||
8 - 8.0 - 8.0 - main - static string
|
||||
333 44 555555 6 7
|
||||
size of data/text:
|
||||
non-zero/non-zero
|
||||
|
||||
[test_data_suppression_on]
|
||||
size of data/text:
|
||||
zero/zero
|
||||
|
||||
[test_static_data]
|
||||
a = 1
|
|
@ -0,0 +1,12 @@
|
|||
// this file contains BMP chars encoded in UTF-8
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
wchar_t s[] = L"hello$$你好¢¢世界€€world";
|
||||
wchar_t *p;
|
||||
for (p = s; *p; p++) printf("%04X ", (unsigned) *p);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
0068 0065 006C 006C 006F 0024 0024 4F60 597D 00A2 00A2 4E16 754C 20AC 20AC 0077 006F 0072 006C 0064
|
|
@ -0,0 +1,41 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
asm (
|
||||
".text;"
|
||||
".globl _us;.globl _ss;.globl _uc;.globl _sc;"
|
||||
"_us:;_ss:;_uc:;_sc:;"
|
||||
"movl $0x1234ABCD, %eax;"
|
||||
"ret;"
|
||||
);
|
||||
|
||||
#if 1
|
||||
#define us _us
|
||||
#define ss _ss
|
||||
#define uc _uc
|
||||
#define sc _sc
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
unsigned short us(void);
|
||||
short ss(void);
|
||||
unsigned char uc(void);
|
||||
signed char sc(void);
|
||||
|
||||
unsigned short (*fpus)(void) = us;
|
||||
short (*fpss)(void) = ss;
|
||||
unsigned char (*fpuc)(void) = uc;
|
||||
signed char (*fpsc)(void) = sc;
|
||||
|
||||
printf("%08X %08X\n", us() + 1, fpus() + 1);
|
||||
printf("%08X %08X\n", ss() + 1, fpss() + 1);
|
||||
printf("%08X %08X\n", uc() + 1, fpuc() + 1);
|
||||
printf("%08X %08X\n", sc() + 1, fpsc() + 1);
|
||||
printf("\n");
|
||||
printf("%08X %08X\n", fpus() + 1, us() + 1);
|
||||
printf("%08X %08X\n", fpss() + 1, ss() + 1);
|
||||
printf("%08X %08X\n", fpuc() + 1, uc() + 1);
|
||||
printf("%08X %08X\n", fpsc() + 1, sc() + 1);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
0000ABCE 0000ABCE
|
||||
FFFFABCE FFFFABCE
|
||||
000000CE 000000CE
|
||||
FFFFFFCE FFFFFFCE
|
||||
|
||||
0000ABCE 0000ABCE
|
||||
FFFFABCE FFFFABCE
|
||||
000000CE 000000CE
|
||||
FFFFFFCE FFFFFFCE
|
|
@ -0,0 +1,276 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#define __fastcall __attribute((fastcall))
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define SYMBOL(x) _##x
|
||||
#else
|
||||
#define SYMBOL(x) x
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
////////// TRAP FRAMEWORK
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// if you cast 'TRAP' to a function pointer and call it,
|
||||
// it will save all 8 registers,
|
||||
// and jump into C-code (previously set using 'SET_TRAP_HANDLER(x)'),
|
||||
// in C-code you can pop DWORDs from stack and modify registers
|
||||
//
|
||||
|
||||
void *SYMBOL(trap_handler);
|
||||
|
||||
extern unsigned char SYMBOL(trap)[];
|
||||
asm (
|
||||
".text;"
|
||||
"_trap:;"
|
||||
"pushl %esp;"
|
||||
"pusha;"
|
||||
"addl $0x4, 0xc(%esp);"
|
||||
"pushl %esp;"
|
||||
"call *_trap_handler;"
|
||||
"addl $0x4, %esp;"
|
||||
"movl 0xc(%esp), %eax;"
|
||||
"movl %eax, 0x20(%esp);"
|
||||
"popa;"
|
||||
"popl %esp;"
|
||||
"ret;"
|
||||
);
|
||||
|
||||
struct trapframe {
|
||||
unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
};
|
||||
|
||||
|
||||
#define M_FLOAT(addr) (*(float *)(addr))
|
||||
#define M_DWORD(addr) (*(unsigned *)(addr))
|
||||
#define M_WORD(addr) (*(unsigned short *)(addr))
|
||||
#define M_BYTE(addr) (*(unsigned char *)(addr))
|
||||
#define R_EAX ((tf)->eax)
|
||||
#define R_ECX ((tf)->ecx)
|
||||
#define R_EDX ((tf)->edx)
|
||||
#define R_EBX ((tf)->ebx)
|
||||
#define R_ESP ((tf)->esp)
|
||||
#define R_EBP ((tf)->ebp)
|
||||
#define R_ESI ((tf)->esi)
|
||||
#define R_EDI ((tf)->edi)
|
||||
|
||||
#define ARG(x) (M_DWORD(R_ESP + (x) * 4))
|
||||
|
||||
#define RETN(x) do { \
|
||||
M_DWORD(R_ESP + (x)) = M_DWORD(R_ESP); \
|
||||
R_ESP += (x); \
|
||||
} while (0)
|
||||
|
||||
#define DUMP() do { \
|
||||
unsigned i; \
|
||||
printf("EAX: %08X\n", R_EAX); \
|
||||
printf("ECX: %08X\n", R_ECX); \
|
||||
printf("EDX: %08X\n", R_EDX); \
|
||||
printf("EBX: %08X\n", R_EBX); \
|
||||
printf("ESP: %08X\n", R_ESP); \
|
||||
printf("EBP: %08X\n", R_EBP); \
|
||||
printf("ESI: %08X\n", R_ESI); \
|
||||
printf("EDI: %08X\n", R_EDI); \
|
||||
printf("\n"); \
|
||||
printf("[RETADDR]: %08X\n", M_DWORD(R_ESP)); \
|
||||
for (i = 1; i <= 8; i++) { \
|
||||
printf("[ARG%4d]: %08X\n", i, ARG(i)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_TRAP_HANDLER(x) ((SYMBOL(trap_handler)) = (x))
|
||||
#define TRAP ((void *) &SYMBOL(trap))
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
////////// SAFECALL FRAMEWORK
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// this framework will convert any calling convention to cdecl
|
||||
// usage: first set call target with 'SET_SAFECALL_TARGET(x)'
|
||||
// then cast 'SAFECALL' to target function pointer type and invoke it
|
||||
// after calling, 'ESPDIFF' is the difference of old and new esp
|
||||
|
||||
void *SYMBOL(sc_call_target);
|
||||
unsigned SYMBOL(sc_retn_addr);
|
||||
unsigned SYMBOL(sc_old_esp);
|
||||
unsigned SYMBOL(sc_new_esp);
|
||||
|
||||
extern unsigned char SYMBOL(safecall)[];
|
||||
asm (
|
||||
".text;"
|
||||
"_safecall:;"
|
||||
"popl _sc_retn_addr;"
|
||||
"movl %esp, _sc_old_esp;"
|
||||
"call *_sc_call_target;"
|
||||
"movl %esp, _sc_new_esp;"
|
||||
"movl _sc_old_esp, %esp;"
|
||||
"jmp *_sc_retn_addr;"
|
||||
);
|
||||
|
||||
#define SET_SAFECALL_TARGET(x) ((SYMBOL(sc_call_target)) = (x))
|
||||
#define SAFECALL ((void *) &SYMBOL(safecall))
|
||||
#define ESPDIFF (SYMBOL(sc_new_esp) - SYMBOL(sc_old_esp))
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
////////// TEST FASTCALL INVOKE
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void check_fastcall_invoke_0(struct trapframe *tf)
|
||||
{
|
||||
//DUMP();
|
||||
RETN(0);
|
||||
}
|
||||
|
||||
void check_fastcall_invoke_1(struct trapframe *tf)
|
||||
{
|
||||
//DUMP();
|
||||
assert(R_ECX == 0x11111111);
|
||||
RETN(0);
|
||||
}
|
||||
void check_fastcall_invoke_2(struct trapframe *tf)
|
||||
{
|
||||
//DUMP();
|
||||
assert(R_ECX == 0x11111111);
|
||||
assert(R_EDX == 0x22222222);
|
||||
RETN(0);
|
||||
}
|
||||
void check_fastcall_invoke_3(struct trapframe *tf)
|
||||
{
|
||||
//DUMP();
|
||||
assert(R_ECX == 0x11111111);
|
||||
assert(R_EDX == 0x22222222);
|
||||
assert(ARG(1) == 0x33333333);
|
||||
RETN(1*4);
|
||||
}
|
||||
void check_fastcall_invoke_4(struct trapframe *tf)
|
||||
{
|
||||
//DUMP();
|
||||
assert(R_ECX == 0x11111111);
|
||||
assert(R_EDX == 0x22222222);
|
||||
assert(ARG(1) == 0x33333333);
|
||||
assert(ARG(2) == 0x44444444);
|
||||
RETN(2*4);
|
||||
}
|
||||
|
||||
void check_fastcall_invoke_5(struct trapframe *tf)
|
||||
{
|
||||
//DUMP();
|
||||
assert(R_ECX == 0x11111111);
|
||||
assert(R_EDX == 0x22222222);
|
||||
assert(ARG(1) == 0x33333333);
|
||||
assert(ARG(2) == 0x44444444);
|
||||
assert(ARG(3) == 0x55555555);
|
||||
RETN(3*4);
|
||||
}
|
||||
|
||||
void test_fastcall_invoke()
|
||||
{
|
||||
SET_TRAP_HANDLER(check_fastcall_invoke_0);
|
||||
((void __fastcall (*)(void)) TRAP)();
|
||||
|
||||
SET_TRAP_HANDLER(check_fastcall_invoke_1);
|
||||
((void __fastcall (*)(unsigned)) TRAP)(0x11111111);
|
||||
|
||||
SET_TRAP_HANDLER(check_fastcall_invoke_2);
|
||||
((void __fastcall (*)(unsigned, unsigned)) TRAP)(0x11111111, 0x22222222);
|
||||
|
||||
SET_TRAP_HANDLER(check_fastcall_invoke_3);
|
||||
((void __fastcall (*)(unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333);
|
||||
|
||||
SET_TRAP_HANDLER(check_fastcall_invoke_4);
|
||||
((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444);
|
||||
|
||||
SET_TRAP_HANDLER(check_fastcall_invoke_5);
|
||||
((void __fastcall (*)(unsigned, unsigned, unsigned, unsigned, unsigned)) TRAP)(0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
////////// TEST FUNCTION CODE GENERATION
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int __fastcall check_fastcall_espdiff_0(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fastcall check_fastcall_espdiff_1(int a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
int __fastcall check_fastcall_espdiff_2(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int __fastcall check_fastcall_espdiff_3(int a, int b, int c)
|
||||
{
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
int __fastcall check_fastcall_espdiff_4(int a, int b, int c, int d)
|
||||
{
|
||||
return a + b + c + d;
|
||||
}
|
||||
|
||||
int __fastcall check_fastcall_espdiff_5(int a, int b, int c, int d, int e)
|
||||
{
|
||||
return a + b + c + d + e;
|
||||
}
|
||||
|
||||
void test_fastcall_espdiff()
|
||||
{
|
||||
int x;
|
||||
SET_SAFECALL_TARGET(check_fastcall_espdiff_0);
|
||||
x = ((typeof(&check_fastcall_espdiff_0))SAFECALL)();
|
||||
assert(x == 0);
|
||||
assert(ESPDIFF == 0);
|
||||
|
||||
SET_SAFECALL_TARGET(check_fastcall_espdiff_1);
|
||||
x = ((typeof(&check_fastcall_espdiff_1))SAFECALL)(1);
|
||||
assert(x == 1);
|
||||
assert(ESPDIFF == 0);
|
||||
|
||||
SET_SAFECALL_TARGET(check_fastcall_espdiff_2);
|
||||
x = ((typeof(&check_fastcall_espdiff_2))SAFECALL)(1, 2);
|
||||
assert(x == 1 + 2);
|
||||
assert(ESPDIFF == 0);
|
||||
|
||||
SET_SAFECALL_TARGET(check_fastcall_espdiff_3);
|
||||
x = ((typeof(&check_fastcall_espdiff_3))SAFECALL)(1, 2, 3);
|
||||
assert(x == 1 + 2 + 3);
|
||||
assert(ESPDIFF == 1*4);
|
||||
|
||||
SET_SAFECALL_TARGET(check_fastcall_espdiff_4);
|
||||
x = ((typeof(&check_fastcall_espdiff_4))SAFECALL)(1, 2, 3, 4);
|
||||
assert(x == 1 + 2 + 3 + 4);
|
||||
assert(ESPDIFF == 2*4);
|
||||
|
||||
SET_SAFECALL_TARGET(check_fastcall_espdiff_5);
|
||||
x = ((typeof(&check_fastcall_espdiff_5))SAFECALL)(1, 2, 3, 4, 5);
|
||||
assert(x == 1 + 2 + 3 + 4 + 5);
|
||||
assert(ESPDIFF == 3*4);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#define N 10000
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= N; i++) {
|
||||
test_fastcall_espdiff();
|
||||
}
|
||||
|
||||
for (i = 1; i <= N; i++) {
|
||||
test_fastcall_invoke();
|
||||
}
|
||||
|
||||
puts("TEST OK");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
TEST OK
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue