mirror of
https://github.com/mirror/tinycc.git
synced 2026-08-24 11:33:28 +08:00
Compare commits
176 Commits
release_0_
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
110a4edc15 | ||
|
|
68310299b6 | ||
|
|
bf8d8f5f3e | ||
|
|
aed6a7cb60 | ||
|
|
530b77e365 | ||
|
|
ca4b4a52ad | ||
|
|
03c787d6ce | ||
|
|
40f5ce002e | ||
|
|
67aebdd5b7 | ||
|
|
0a35f9d66e | ||
|
|
f9181416f6 | ||
|
|
5c6509578e | ||
|
|
b8f6e1ae30 | ||
|
|
92204e8818 | ||
|
|
9dc9cbf319 | ||
|
|
0d1ed74102 | ||
|
|
805990b94e | ||
|
|
ae37bd5abc | ||
|
|
a93bcdffae | ||
|
|
15626621fb | ||
|
|
e9e89ad699 | ||
|
|
859da934e0 | ||
|
|
48ae0c0468 | ||
|
|
5829791ffa | ||
|
|
ea5e81bd6a | ||
|
|
e8a52a8249 | ||
|
|
eca1fbaf92 | ||
|
|
b56f956247 | ||
|
|
d165e87340 | ||
|
|
73ba078d2f | ||
|
|
d36fea34e3 | ||
|
|
dd5630ff95 | ||
|
|
0f0ed4a8bf | ||
|
|
90697c4c56 | ||
|
|
d62301b050 | ||
|
|
9a7173bf69 | ||
|
|
e6ba81b012 | ||
|
|
b1697be691 | ||
|
|
795f67428e | ||
|
|
9a8b2912ed | ||
|
|
742cf05875 | ||
|
|
85d016b507 | ||
|
|
39a4b859d4 | ||
|
|
51a7f163ad | ||
|
|
83fd36333a | ||
|
|
be43c8e0ed | ||
|
|
a9c78d04f2 | ||
|
|
b879ffa193 | ||
|
|
de3f0a46fe | ||
|
|
2e9b57b6d0 | ||
|
|
9fe28b610e | ||
|
|
0e239e2ba5 | ||
|
|
fcf2e5981f | ||
|
|
830b7533c9 | ||
|
|
6c10429aa5 | ||
|
|
29c8e1545a | ||
|
|
c80f81c199 | ||
|
|
5818945ef6 | ||
|
|
0e015988cc | ||
|
|
97072b3cd7 | ||
|
|
754b0beb7d | ||
|
|
e6db5f5fb6 | ||
|
|
06fa15fb99 | ||
|
|
ebb874e216 | ||
|
|
6512d9e2ea | ||
|
|
af6cbc48d1 | ||
|
|
040ef000e4 | ||
|
|
fe8f230ab6 | ||
|
|
b8a32d8d40 | ||
|
|
7db1e69df2 | ||
|
|
006c907da7 | ||
|
|
4f056031f4 | ||
|
|
62e73da612 | ||
|
|
ae607280c5 | ||
|
|
4a8c2229ce | ||
|
|
3116744bdd | ||
|
|
b41fc95566 | ||
|
|
00f0932760 | ||
|
|
6213d4b4b6 | ||
|
|
5a044b67bb | ||
|
|
64147b346b | ||
|
|
7c3f19c079 | ||
|
|
aa8d22e38e | ||
|
|
0a9873aa22 | ||
|
|
fb0ac27691 | ||
|
|
1e776b29d3 | ||
|
|
ba8c95a98d | ||
|
|
27d23342ea | ||
|
|
c92daa02e4 | ||
|
|
ce8d71edbc | ||
|
|
2355fc7686 | ||
|
|
d6072d3703 | ||
|
|
73a84cefda | ||
|
|
7dd792ef51 | ||
|
|
76b02c2a03 | ||
|
|
5fd6f7bd44 | ||
|
|
deb410710c | ||
|
|
1b599ea7f8 | ||
|
|
2d9b5e0bb8 | ||
|
|
83466c6151 | ||
|
|
78f288bc87 | ||
|
|
7bebf1f59a | ||
|
|
7f51aa13e7 | ||
|
|
a80acab4fc | ||
|
|
3783b33508 | ||
|
|
43a34d354a | ||
|
|
5a92536cea | ||
|
|
e263ee3cbf | ||
|
|
15e0dc08a6 | ||
|
|
256f6e6200 | ||
|
|
e8039673ad | ||
|
|
12265da6cd | ||
|
|
2c657f6608 | ||
|
|
8f7e3f325d | ||
|
|
2c6cd08bcc | ||
|
|
1300cec38c | ||
|
|
f9bf48d643 | ||
|
|
96bd8f2b25 | ||
|
|
f2698687fb | ||
|
|
5247bbc2f0 | ||
|
|
0d598aca08 | ||
|
|
23594b6980 | ||
|
|
f22e961f80 | ||
|
|
a327c7a552 | ||
|
|
4d9aaacc85 | ||
|
|
cd24bd05b4 | ||
|
|
9bcc0b970b | ||
|
|
88b3cb570e | ||
|
|
6ed868c51c | ||
|
|
e2c89576c7 | ||
|
|
c6537d11cb | ||
|
|
2eaa1104f7 | ||
|
|
265dddbecf | ||
|
|
3667408a57 | ||
|
|
5342b32eef | ||
|
|
adb1456472 | ||
|
|
6c96c41ee4 | ||
|
|
f466577673 | ||
|
|
34140dd627 | ||
|
|
b0d40c12da | ||
|
|
f99d3de221 | ||
|
|
2de1b2d14c | ||
|
|
2bcb964694 | ||
|
|
3e8b9e6d10 | ||
|
|
d778bde7f9 | ||
|
|
54bf8c0556 | ||
|
|
2bcc187b1b | ||
|
|
d13aa5426a | ||
|
|
7097268ac5 | ||
|
|
84f4e99635 | ||
|
|
8b0c4c6582 | ||
|
|
fb2c34f8cd | ||
|
|
65b974e396 | ||
|
|
365d0ad545 | ||
|
|
52b7254b9c | ||
|
|
0bea5c7f21 | ||
|
|
24a19cc37e | ||
|
|
38d2e8b9d8 | ||
|
|
3b8cd565be | ||
|
|
200b58dad8 | ||
|
|
6ca0299e5b | ||
|
|
5487bc23c8 | ||
|
|
aee0da0b17 | ||
|
|
6d66b5a971 | ||
|
|
8ba48f84fe | ||
|
|
62c5a5466a | ||
|
|
7bc5e51847 | ||
|
|
7b8e283980 | ||
|
|
e9c64e3f47 | ||
|
|
81f957ae09 | ||
|
|
3ba1190eb4 | ||
|
|
6f8b8887b1 | ||
|
|
bb24eb9de4 | ||
|
|
44738b516a | ||
|
|
c42532c37d | ||
|
|
b0b8ac13ce |
87
Changelog
87
Changelog
@@ -1,3 +1,90 @@
|
||||
version 0.9.25:
|
||||
|
||||
- first support for x86-64 target (Shinichiro Hamaji)
|
||||
- support µClibc
|
||||
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
|
||||
- improved preprocess output with linenumbers and spaces preserved
|
||||
- tcc_relocate now copies code into user buffer
|
||||
- fix bitfields with non-int types and in unions
|
||||
- improve ARM cross-compiling (Daniel Glöckner)
|
||||
- link stabstr sections from multiple objects
|
||||
- better (still limited) support for multiple TCCStates
|
||||
|
||||
version 0.9.24:
|
||||
|
||||
- added verbosity levels -v, -vv, -vvv
|
||||
- Accept standard input as an inputstream (Hanzac Chen)
|
||||
- Support c89 compilers other than gcc (Hanzac Chen)
|
||||
- -soname linker option (Marc Andre Tanner)
|
||||
- Just warn about unknown directives, ignore quotes in #error/#warning
|
||||
- Define __STDC_VERSION__=199901L (477)
|
||||
- Switch to newer tccpe.c (includes support for resources)
|
||||
- Handle backslashes within #include/#error/#warning
|
||||
- Import changesets (part 4) 428,457,460,467: defines for openbsd etc.
|
||||
- Use _WIN32 for a windows hosted tcc and define it for the PE target,
|
||||
otherwise define __unix / __linux (Detlef Riekenberg)
|
||||
- Import changesets (part 3) 409,410: ARM EABI by Daniel Glöckner
|
||||
- Some in-between fixes:
|
||||
TCC -E no longer hangs with macro calls involving newlines.
|
||||
(next_nomacro1 now advances the read-pointer with TOK_LINEFEED)
|
||||
Global cast (int g_i = 1LL;) no longer crashes tcc.
|
||||
(nocode_wanted is initially 1, and only 0 for gen_function)
|
||||
On win32 now tcc.exe finds 'include' & 'lib' even if itself is in 'bin'.
|
||||
(new function w32_tcc_lib_path removes 'bin' if detected)
|
||||
Added quick build batch file for mingw (win32/build-tcc.bat)
|
||||
Last added case label optimization (455) produced wrong code. Reverted.
|
||||
|
||||
- Import more changesets from Rob Landley's fork (part 2):
|
||||
487: Handle long long constants in gen_opic() (Rob Landley)
|
||||
484: Handle parentheses within __attribute__((...)) (Rob Landley)
|
||||
480: Remove a goto in decl_initializer_alloc (Rob Landley)
|
||||
475: Fix dereferences in inline assembly output (Joshua Phillips)
|
||||
474: Cast ptrs to ints of different sizes correctly (Joshua Phillips)
|
||||
473: Fix size of structs with empty array member (Joshua Phillips)
|
||||
470: No warning for && and || with mixed pointers/integers (Rob Landley)
|
||||
469: Fix symbol visibility problems in the linker (Vincent Pit)
|
||||
468: Allow && and || involving pointer arguments (Rob Landley)
|
||||
455: Optimize case labels with no code in between (Zdenek Pavlas)
|
||||
450: Implement alloca for x86 (grischka)
|
||||
415: Parse unicode escape sequences (Axel Liljencrantz)
|
||||
407: Add a simple va_copy() in stdarg.h (Hasso Tepper)
|
||||
400: Allow typedef names as symbols (Dave Dodge)
|
||||
|
||||
- Import some changesets from Rob Landley's fork (part 1):
|
||||
462: Use LGPL with bcheck.c and il-gen.c
|
||||
458: Fix global compound literals (in unary: case '&':) (Andrew Johnson)
|
||||
456: Use return code from tcc_output_file in main() (Michael Somos)
|
||||
442: Fix indirections with function pointers (***fn)() (grischka)
|
||||
441: Fix LL left shift in libtcc1.c:__shldi3 (grischka)
|
||||
440: Pass structures and function ptrs through ?: (grischka)
|
||||
439: Keep rvalue in bit assignment (bit2 = bit1 = x) (grischka)
|
||||
438: Degrade nonportable pointer assignment to warning (grischka)
|
||||
437: Call 'saveregs()' before jumping with logical and/or/not (grischka)
|
||||
435: Put local static variables into global memory (grischka)
|
||||
432/434: Cast double and ptr to bool (grischka)
|
||||
420: Zero pad x87 tenbyte long doubles (Felix Nawothnig)
|
||||
417: Make 'sizeof' unsigned (Rob Landley)
|
||||
397: Fix save_reg for longlongs (Daniel Glöckner)
|
||||
396: Fix "invalid relocation entry" problem on ubuntu - (Bernhard Fischer)
|
||||
|
||||
- ignore AS_NEEDED ld command
|
||||
- mark executable sections as executable when running in memory
|
||||
- added support for win32 wchar_t (Filip Navara)
|
||||
- segment override prefix support (Filip Navara)
|
||||
- normalized slashes in paths (Filip Navara)
|
||||
- windows style fastcall (Filip Navara)
|
||||
- support for empty input register section in asm (Filip Navara)
|
||||
- anonymous union/struct support (Filip Navara)
|
||||
- fixed parsing of function parameters
|
||||
- workaround for function pointers in conditional expressions (Dave Dodge)
|
||||
- initial '-E' option support to use the C preprocessor alone
|
||||
- discard type qualifiers when comparing function parameters (Dave Dodge)
|
||||
- Bug fix: A long long value used as a test expression ignores the
|
||||
upper 32 bits at runtime (Dave Dodge)
|
||||
- fixed multiple concatenation of PPNUM tokens (initial patch by Dave Dodge)
|
||||
- fixed multiple typedef specifiers handling
|
||||
- fixed sign extension in some type conversions (Dave Dodge)
|
||||
|
||||
version 0.9.23:
|
||||
|
||||
- initial PE executable format for windows version (grischka)
|
||||
|
||||
430
Makefile
430
Makefile
@@ -1,298 +1,272 @@
|
||||
#
|
||||
# Tiny C Compiler Makefile
|
||||
#
|
||||
include config.mak
|
||||
|
||||
CFLAGS=-O2 -g -Wall
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS=-ldl
|
||||
BCHECK_O=bcheck.o
|
||||
endif
|
||||
TOP ?= .
|
||||
include $(TOP)/config.mak
|
||||
|
||||
CFLAGS+=-g -Wall
|
||||
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
|
||||
LIBS_P=
|
||||
|
||||
ifneq ($(GCC_MAJOR),2)
|
||||
CFLAGS+=-fno-strict-aliasing
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS+=-mpreferred-stack-boundary=2
|
||||
ifeq ($(GCC_MAJOR),2)
|
||||
CFLAGS+=-m386 -malign-functions=0
|
||||
else
|
||||
CFLAGS+=-march=i386 -falign-functions=0 -fno-strict-aliasing
|
||||
CFLAGS+=-march=i386 -falign-functions=0
|
||||
ifneq ($(GCC_MAJOR),3)
|
||||
CFLAGS+=-Wno-pointer-sign -Wno-sign-compare -D_FORTIFY_SOURCE=0
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
DISAS=objdump -d
|
||||
INSTALL=install
|
||||
ifeq ($(ARCH),x86-64)
|
||||
CFLAGS+=-Wno-pointer-sign
|
||||
endif
|
||||
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_NOLDL
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
PROGS=tcc$(EXESUF)
|
||||
ifdef CONFIG_CROSS
|
||||
PROGS+=c67-tcc$(EXESUF) arm-tcc$(EXESUF)
|
||||
endif
|
||||
PROGS+=tiny_impdef$(EXESUF)
|
||||
NATIVE_TARGET=-DTCC_TARGET_PE
|
||||
LIBTCC1=libtcc1.a
|
||||
else
|
||||
ifeq ($(ARCH),i386)
|
||||
PROGS=tcc$(EXESUF)
|
||||
ifdef CONFIG_CROSS
|
||||
PROGS+=arm-tcc$(EXESUF)
|
||||
endif
|
||||
endif
|
||||
NATIVE_TARGET=-DTCC_TARGET_I386
|
||||
LIBTCC1=libtcc1.a
|
||||
BCHECK_O=bcheck.o
|
||||
else
|
||||
ifeq ($(ARCH),arm)
|
||||
NATIVE_TARGET=-DTCC_TARGET_ARM
|
||||
NATIVE_TARGET+=$(if $(wildcard /lib/ld-linux.so.3),-DTCC_ARM_EABI)
|
||||
NATIVE_TARGET+=$(if $(shell grep -l "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo),-DTCC_ARM_VFP)
|
||||
else
|
||||
ifeq ($(ARCH),x86-64)
|
||||
NATIVE_TARGET=-DTCC_TARGET_X86_64
|
||||
LIBTCC1=libtcc1.a
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard /lib/ld-uClibc.so.0),)
|
||||
NATIVE_TARGET+=-DTCC_UCLIBC
|
||||
BCHECK_O=
|
||||
endif
|
||||
|
||||
ifdef CONFIG_USE_LIBGCC
|
||||
LIBTCC1=
|
||||
endif
|
||||
|
||||
ifeq ($(TOP),.)
|
||||
|
||||
PROGS=tcc$(EXESUF)
|
||||
|
||||
I386_CROSS = i386-tcc$(EXESUF)
|
||||
WIN32_CROSS = i386-win32-tcc$(EXESUF)
|
||||
X64_CROSS = x86_64-tcc$(EXESUF)
|
||||
ARM_CROSS = arm-tcc-fpa$(EXESUF) arm-tcc-fpa-ld$(EXESUF) \
|
||||
arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF)
|
||||
C67_CROSS = c67-tcc$(EXESUF)
|
||||
|
||||
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c \
|
||||
tcc.h config.h libtcc.h tcctok.h
|
||||
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h
|
||||
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h tccpe.c
|
||||
X86_64_FILES = $(CORE_FILES) x86_64-gen.c
|
||||
ARM_FILES = $(CORE_FILES) arm-gen.c
|
||||
C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
|
||||
NATIVE_FILES=$(WIN32_FILES)
|
||||
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
else
|
||||
ifeq ($(ARCH),i386)
|
||||
NATIVE_FILES=$(I386_FILES)
|
||||
PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
else
|
||||
ifeq ($(ARCH),x86-64)
|
||||
NATIVE_FILES=$(X86_64_FILES)
|
||||
PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(ARM_CROSS) $(C67_CROSS)
|
||||
else
|
||||
ifeq ($(ARCH),arm)
|
||||
NATIVE_FILES=$(ARM_FILES)
|
||||
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(C67_CROSS)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CROSS
|
||||
PROGS+=i386-tcc$(EXESUF)
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_CROSS
|
||||
PROGS+=c67-tcc$(EXESUF) i386-win32-tcc$(EXESUF)
|
||||
endif
|
||||
PROGS+=$(PROGS_CROSS)
|
||||
endif
|
||||
|
||||
# run local version of tcc with local libraries and includes
|
||||
TCC=./tcc -B. -I.
|
||||
|
||||
all: $(PROGS) \
|
||||
libtcc1.a $(BCHECK_O) tcc-doc.html tcc.1 libtcc.a \
|
||||
libtcc_test$(EXESUF)
|
||||
|
||||
Makefile: config.mak
|
||||
|
||||
# auto test
|
||||
|
||||
test: test.ref test.out
|
||||
@if diff -u test.ref test.out ; then echo "Auto Test OK"; fi
|
||||
|
||||
tcctest.ref: tcctest.c
|
||||
$(CC) $(CFLAGS) -I. -o $@ $<
|
||||
|
||||
test.ref: tcctest.ref
|
||||
./tcctest.ref > $@
|
||||
|
||||
test.out: tcc tcctest.c
|
||||
$(TCC) -run tcctest.c > $@
|
||||
|
||||
run: tcc tcctest.c
|
||||
$(TCC) -run tcctest.c
|
||||
|
||||
# iterated test2 (compile tcc then compile tcctest.c !)
|
||||
test2: tcc tcc.c tcctest.c test.ref
|
||||
$(TCC) -run tcc.c -B. -I. -run tcctest.c > test.out2
|
||||
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
|
||||
|
||||
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
||||
test3: tcc tcc.c tcctest.c test.ref
|
||||
$(TCC) -run tcc.c -B. -I. -run tcc.c -B. -I. -run tcctest.c > test.out3
|
||||
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
|
||||
|
||||
# binary output test
|
||||
test4: tcc test.ref
|
||||
# dynamic output
|
||||
$(TCC) -o tcctest1 tcctest.c
|
||||
./tcctest1 > test1.out
|
||||
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
||||
# static output
|
||||
$(TCC) -static -o tcctest2 tcctest.c
|
||||
./tcctest2 > test2.out
|
||||
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
|
||||
# object + link output
|
||||
$(TCC) -c -o tcctest3.o tcctest.c
|
||||
$(TCC) -o tcctest3 tcctest3.o
|
||||
./tcctest3 > test3.out
|
||||
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
|
||||
# dynamic output + bound check
|
||||
$(TCC) -b -o tcctest4 tcctest.c
|
||||
./tcctest4 > test4.out
|
||||
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
||||
|
||||
# memory and bound check auto test
|
||||
BOUNDS_OK = 1 4 8 10
|
||||
BOUNDS_FAIL= 2 5 7 9 11 12 13
|
||||
|
||||
btest: boundtest.c tcc
|
||||
@for i in $(BOUNDS_OK); do \
|
||||
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||
/bin/true ; \
|
||||
else\
|
||||
echo Failed positive test $$i ; exit 1 ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
for i in $(BOUNDS_FAIL); do \
|
||||
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||
echo Failed negative test $$i ; exit 1 ;\
|
||||
else\
|
||||
/bin/true ; \
|
||||
fi\
|
||||
done ;\
|
||||
echo Bound test OK
|
||||
|
||||
# speed test
|
||||
speed: tcc ex2 ex3
|
||||
time ./ex2 1238 2 3 4 10 13 4
|
||||
time ./tcc -I. ./ex2.c 1238 2 3 4 10 13 4
|
||||
time ./ex3 35
|
||||
time ./tcc -I. ./ex3.c 35
|
||||
|
||||
ex2: ex2.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
ex3: ex3.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
all: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc-doc.html tcc.1 libtcc_test$(EXESUF)
|
||||
|
||||
# Host Tiny C Compiler
|
||||
ifdef CONFIG_WIN32
|
||||
tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h tccpe.c
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_PE -o $@ $< $(LIBS)
|
||||
else
|
||||
ifeq ($(ARCH),i386)
|
||||
tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
|
||||
endif
|
||||
ifeq ($(ARCH),arm)
|
||||
tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
|
||||
endif
|
||||
endif
|
||||
tcc$(EXESUF): $(NATIVE_FILES)
|
||||
$(CC) -o $@ $< $(NATIVE_TARGET) $(CFLAGS) $(LIBS)
|
||||
|
||||
# Cross Tiny C Compilers
|
||||
i386-tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
|
||||
i386-tcc$(EXESUF): $(I386_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_I386 $(CFLAGS) $(LIBS)
|
||||
|
||||
c67-tcc$(EXESUF): tcc.c c67-gen.c tccelf.c tccasm.c tcctok.h libtcc.h tcccoff.c
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_C67 -o $@ $< $(LIBS)
|
||||
i386-win32-tcc$(EXESUF): $(WIN32_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_PE $(CFLAGS) $(LIBS)
|
||||
|
||||
arm-tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
|
||||
x86_64-tcc$(EXESUF): $(X86_64_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_X86_64 $(CFLAGS) $(LIBS)
|
||||
|
||||
i386-win32-tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h tccpe.c
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_PE -o $@ $< $(LIBS)
|
||||
c67-tcc$(EXESUF): $(C67_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_C67 $(CFLAGS) $(LIBS)
|
||||
|
||||
arm-tcc-fpa$(EXESUF): $(ARM_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_ARM $(CFLAGS) $(LIBS)
|
||||
|
||||
arm-tcc-fpa-ld$(EXESUF): $(ARM_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 $(CFLAGS) $(LIBS)
|
||||
|
||||
arm-tcc-vfp$(EXESUF): $(ARM_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_ARM -DTCC_ARM_VFP $(CFLAGS) $(LIBS)
|
||||
|
||||
arm-tcc-vfp-eabi$(EXESUF): $(ARM_FILES)
|
||||
$(CC) -o $@ $< -DTCC_TARGET_ARM -DTCC_ARM_EABI $(CFLAGS) $(LIBS)
|
||||
|
||||
# libtcc generation and test
|
||||
libtcc.o: $(NATIVE_FILES)
|
||||
$(CC) -o $@ -c libtcc.c $(NATIVE_TARGET) $(CFLAGS)
|
||||
|
||||
libtcc.a: libtcc.o
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libtcc_test$(EXESUF): tests/libtcc_test.c libtcc.a
|
||||
$(CC) -o $@ $^ -I. $(CFLAGS) $(LIBS)
|
||||
|
||||
libtest: libtcc_test$(EXESUF) $(LIBTCC1)
|
||||
./libtcc_test$(EXESUF) lib_path=.
|
||||
|
||||
# profiling version
|
||||
tcc_p$(EXESUF): $(NATIVE_FILES)
|
||||
$(CC) -o $@ $< $(NATIVE_TARGET) $(CFLAGS_P) $(LIBS_P)
|
||||
|
||||
# windows utilities
|
||||
tiny_impdef$(EXESUF): tiny_impdef.c
|
||||
$(CC) $(CFLAGS) -o $@ $< -lkernel32
|
||||
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
|
||||
$(CC) -o $@ $< $(CFLAGS)
|
||||
tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c
|
||||
$(CC) -o $@ $< $(CFLAGS)
|
||||
|
||||
# TinyCC runtime libraries
|
||||
ifdef CONFIG_WIN32
|
||||
# for windows, we must use TCC because we generate ELF objects
|
||||
LIBTCC1_OBJS=$(addprefix win32/lib/, crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o) libtcc1.o
|
||||
LIBTCC1_CC=./tcc.exe -Bwin32
|
||||
else
|
||||
LIBTCC1_OBJS=libtcc1.o
|
||||
LIBTCC1_CC=$(CC)
|
||||
VPATH+=lib
|
||||
ifdef CONFIG_WIN32
|
||||
# for windows, we must use TCC because we generate ELF objects
|
||||
LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
|
||||
LIBTCC1_CC=./tcc.exe -Bwin32 -DTCC_TARGET_PE
|
||||
VPATH+=win32/lib
|
||||
endif
|
||||
ifeq ($(ARCH),i386)
|
||||
LIBTCC1_OBJS+=alloca86.o alloca86-bt.o
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(LIBTCC1_CC) -O2 -Wall -c -o $@ $<
|
||||
$(LIBTCC1_CC) -o $@ -c $< -O2 -Wall
|
||||
|
||||
%.o: %.S
|
||||
$(LIBTCC1_CC) -c -o $@ $<
|
||||
$(LIBTCC1_CC) -o $@ -c $<
|
||||
|
||||
libtcc1.a: $(LIBTCC1_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
bcheck.o: bcheck.c
|
||||
$(CC) -O2 -Wall -c -o $@ $<
|
||||
$(CC) -o $@ -c $< -O2 -Wall
|
||||
|
||||
install: tcc_install libinstall
|
||||
# install
|
||||
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
|
||||
INSTALL=install
|
||||
|
||||
tcc_install: $(PROGS) tcc.1 libtcc1.a $(BCHECK_O) tcc-doc.html tcc.1
|
||||
ifndef CONFIG_WIN32
|
||||
install: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc.1 tcc-doc.html
|
||||
mkdir -p "$(bindir)"
|
||||
$(INSTALL) -s -m755 $(PROGS) "$(bindir)"
|
||||
ifndef CONFIG_WIN32
|
||||
mkdir -p "$(mandir)/man1"
|
||||
$(INSTALL) tcc.1 "$(mandir)/man1"
|
||||
endif
|
||||
mkdir -p "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
ifdef CONFIG_WIN32
|
||||
mkdir -p "$(tccdir)/lib"
|
||||
$(INSTALL) -m644 libtcc1.a win32/lib/*.def "$(tccdir)/lib"
|
||||
cp -r win32/include/. "$(tccdir)/include"
|
||||
cp -r win32/examples/. "$(tccdir)/examples"
|
||||
else
|
||||
$(INSTALL) -m644 libtcc1.a $(BCHECK_O) "$(tccdir)"
|
||||
$(INSTALL) -m644 stdarg.h stddef.h stdbool.h float.h varargs.h \
|
||||
tcclib.h "$(tccdir)/include"
|
||||
ifneq ($(LIBTCC1),)
|
||||
$(INSTALL) -m644 $(LIBTCC1) "$(tccdir)"
|
||||
endif
|
||||
ifneq ($(BCHECK_O),)
|
||||
$(INSTALL) -m644 $(BCHECK_O) "$(tccdir)"
|
||||
endif
|
||||
$(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include"
|
||||
mkdir -p "$(docdir)"
|
||||
$(INSTALL) -m644 tcc-doc.html "$(docdir)"
|
||||
ifdef CONFIG_WIN32
|
||||
$(INSTALL) -m644 win32/readme.txt "$(docdir)"
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.a tcc tcc1 tcct tcc_g tcctest.ref *.bin *.i ex2 \
|
||||
core gmon.out test.out test.ref a.out tcc_p \
|
||||
*.exe *.lib tcc.pod libtcc_test \
|
||||
tcctest[1234] test[1234].out $(PROGS) win32/lib/*.o
|
||||
|
||||
distclean: clean
|
||||
rm -f config.h config.mak config.texi
|
||||
|
||||
# profiling version
|
||||
tcc_p: tcc.c Makefile
|
||||
$(CC) $(CFLAGS_P) -o $@ $< $(LIBS_P)
|
||||
|
||||
# libtcc generation and example
|
||||
libinstall: libtcc.a
|
||||
mkdir -p "$(libdir)"
|
||||
$(INSTALL) -m644 libtcc.a "$(libdir)"
|
||||
mkdir -p "$(includedir)"
|
||||
$(INSTALL) -m644 libtcc.h "$(includedir)"
|
||||
|
||||
libtcc.o: tcc.c i386-gen.c Makefile
|
||||
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
|
||||
uninstall:
|
||||
rm -fv $(foreach P,$(PROGS),"$(bindir)/$P")
|
||||
rm -fv $(foreach P,$(LIBTCC1) $(BCHECK_O),"$(tccdir)/$P")
|
||||
rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P")
|
||||
rm -fv "$(docdir)/tcc-doc.html" "$(mandir)/man1/tcc.1"
|
||||
rm -fv "$(libdir)/libtcc.a" "$(includedir)/libtcc.h"
|
||||
|
||||
libtcc.a: libtcc.o
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libtcc_test$(EXESUF): libtcc_test.c libtcc.a
|
||||
$(CC) $(CFLAGS) -o $@ $< libtcc.a $(LIBS)
|
||||
|
||||
libtest: libtcc_test
|
||||
./libtcc_test
|
||||
|
||||
# targets for development
|
||||
|
||||
%.bin: %.c tcc
|
||||
$(TCC) -g -o $@ $<
|
||||
$(DISAS) $@
|
||||
|
||||
instr: instr.o
|
||||
objdump -d instr.o
|
||||
|
||||
# tiny assembler testing
|
||||
|
||||
asmtest.ref: asmtest.S
|
||||
$(CC) -c -o asmtest.ref.o asmtest.S
|
||||
objdump -D asmtest.ref.o > $@
|
||||
|
||||
# XXX: we compute tcc.c to go faster during development !
|
||||
asmtest.out: asmtest.S tcc
|
||||
# ./tcc tcc.c -c asmtest.S
|
||||
#asmtest.out: asmtest.S tcc
|
||||
./tcc -c asmtest.S
|
||||
objdump -D asmtest.o > $@
|
||||
|
||||
asmtest: asmtest.out asmtest.ref
|
||||
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
|
||||
|
||||
instr.o: instr.S
|
||||
$(CC) -O2 -Wall -g -c -o $@ $<
|
||||
|
||||
cache: tcc_g
|
||||
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
|
||||
vg_annotate tcc.c > /tmp/linpack.cache.log
|
||||
else
|
||||
install: $(PROGS) $(LIBTCC1) libtcc.a tcc-doc.html
|
||||
mkdir -p "$(tccdir)"
|
||||
mkdir -p "$(tccdir)/lib"
|
||||
mkdir -p "$(tccdir)/include"
|
||||
mkdir -p "$(tccdir)/examples"
|
||||
mkdir -p "$(tccdir)/doc"
|
||||
mkdir -p "$(tccdir)/libtcc"
|
||||
$(INSTALL) -s -m755 $(PROGS) "$(tccdir)"
|
||||
$(INSTALL) -m644 $(LIBTCC1) win32/lib/*.def "$(tccdir)/lib"
|
||||
cp -r win32/include/. "$(tccdir)/include"
|
||||
cp -r win32/examples/. "$(tccdir)/examples"
|
||||
# $(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include"
|
||||
$(INSTALL) -m644 tcc-doc.html win32/tcc-win32.txt "$(tccdir)/doc"
|
||||
$(INSTALL) -m644 libtcc.a libtcc.h "$(tccdir)/libtcc"
|
||||
endif
|
||||
|
||||
# documentation and man page
|
||||
tcc-doc.html: tcc-doc.texi
|
||||
texi2html -monolithic -number $<
|
||||
-texi2html -monolithic -number $<
|
||||
|
||||
tcc.1: tcc-doc.texi
|
||||
./texi2pod.pl $< tcc.pod
|
||||
pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||
|
||||
FILE=tcc-$(shell cat VERSION)
|
||||
-./texi2pod.pl $< tcc.pod
|
||||
-pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
TCC-VERSION=tcc-$(shell cat VERSION)
|
||||
tar:
|
||||
rm -rf /tmp/$(FILE)
|
||||
cp -r . /tmp/$(FILE)
|
||||
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
|
||||
rm -rf /tmp/$(FILE)
|
||||
rm -rf /tmp/$(TCC-VERSION)
|
||||
cp -r . /tmp/$(TCC-VERSION)
|
||||
( cd /tmp ; tar zcvf ~/$(TCC-VERSION).tar.gz $(TCC-VERSION) --exclude CVS )
|
||||
rm -rf /tmp/$(TCC-VERSION)
|
||||
|
||||
# in tests subdir
|
||||
test clean :
|
||||
$(MAKE) -C tests $@
|
||||
|
||||
# clean
|
||||
clean: local_clean
|
||||
local_clean:
|
||||
rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.out libtcc_test$(EXESUF)
|
||||
|
||||
distclean: clean
|
||||
rm -vf config.h config.mak config.texi tcc.1 tcc-doc.html
|
||||
|
||||
endif # ifeq ($(TOP),.)
|
||||
|
||||
5
README
5
README
@@ -28,7 +28,7 @@ Features:
|
||||
Documentation:
|
||||
-------------
|
||||
|
||||
1) Installation on a i386 Linux host (for Windows read win32/readme.txt)
|
||||
1) Installation on a i386 Linux host (for Windows read tcc-win32.txt)
|
||||
|
||||
./configure
|
||||
make
|
||||
@@ -79,8 +79,7 @@ when doing 'make test'.
|
||||
|
||||
Please read tcc-doc.html to have all the features of TCC.
|
||||
|
||||
Additional information is available for the Windows port in
|
||||
win32/readme.txt.
|
||||
Additional information is available for the Windows port in tcc-win32.txt.
|
||||
|
||||
License:
|
||||
-------
|
||||
|
||||
82
TODO
82
TODO
@@ -1,61 +1,65 @@
|
||||
TODO list:
|
||||
|
||||
- bug with defines:
|
||||
#define spin_lock(lock) do { } while (0)
|
||||
#define wq_spin_lock spin_lock
|
||||
#define TEST() wq_spin_lock(a)
|
||||
- typedefs can be structure fields
|
||||
- see bugfixes.diff + improvement.diff from Daniel Glockner
|
||||
Bugs:
|
||||
|
||||
- fix macro substitution with nested definitions (ShangHongzhang)
|
||||
- FPU st(0) is left unclean (kwisatz haderach). Incompatible with
|
||||
optimized gcc/msc code
|
||||
|
||||
- constructors
|
||||
- cast bug (Peter Wang)
|
||||
- define incomplete type if defined several times (Peter Wang).
|
||||
- long long constant evaluation
|
||||
- configure --cc=tcc (still one bug in libtcc1.c)
|
||||
- disable-asm and disable-bcheck options
|
||||
- test binutils/gcc compile
|
||||
- add alloca(), __builtin_expect()
|
||||
- gcc '-E' option.
|
||||
- optimize VT_LOCAL + const
|
||||
- tci patch + argument.
|
||||
- '-b' bug.
|
||||
- atexit (Nigel Horne)
|
||||
- see -lxxx bug (Michael Charity).
|
||||
- see transparent union pb in /urs/include/sys/socket.h
|
||||
- precise behaviour of typeof with arrays ? (__put_user macro)
|
||||
- #include_next support for /usr/include/limits ?
|
||||
but should suffice for most cases)
|
||||
- handle '? x, y : z' in unsized variable initialization (',' is
|
||||
considered incorrectly as separator in preparser)
|
||||
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
||||
- transform functions to function pointers in function parameters (net/ipv4/ip_output.c)
|
||||
- transform functions to function pointers in function parameters
|
||||
(net/ipv4/ip_output.c)
|
||||
- fix function pointer type display
|
||||
- fix bound exit on RedHat 7.3
|
||||
- check lcc test suite -> fix bitfield binary operations
|
||||
- check section alignment in C
|
||||
- fix invalid cast in comparison 'if (v == (int8_t)v)'
|
||||
- packed attribute
|
||||
- finish varargs.h support (gcc 3.2 testsuite issue)
|
||||
- fix static functions declared inside block
|
||||
- fix multiple unions init
|
||||
- sizeof, alignof, typeof can still generate code in some cases.
|
||||
- Fix the remaining libtcc memory leaks.
|
||||
- make libtcc fully reentrant (except for the compilation stage itself).
|
||||
|
||||
Bound checking:
|
||||
|
||||
- '-b' bug.
|
||||
- fix bound exit on RedHat 7.3
|
||||
- setjmp is not supported properly in bound checking.
|
||||
- fix bound check code with '&' on local variables (currently done
|
||||
only for local arrays).
|
||||
- bound checking and float/long long/struct copy code. bound
|
||||
checking and symbol + offset optimization
|
||||
|
||||
Missing features:
|
||||
|
||||
- disable-asm and disable-bcheck options
|
||||
- __builtin_expect()
|
||||
- improve '-E' option.
|
||||
- add '-MD' option
|
||||
- atexit (Nigel Horne)
|
||||
- packed attribute
|
||||
- C99: add variable size arrays (gcc 3.2 testsuite issue)
|
||||
- C99: add complex types (gcc 3.2 testsuite issue)
|
||||
- postfix compound literals (see 20010124-1.c)
|
||||
- fix multiple unions init
|
||||
- setjmp is not supported properly in bound checking.
|
||||
- better local variables handling (needed for other targets)
|
||||
- fix bound check code with '&' on local variables (currently done
|
||||
only for local arrays).
|
||||
- sizeof, alignof, typeof can still generate code in some cases.
|
||||
- bound checking and float/long long/struct copy code. bound
|
||||
checking and symbol + offset optimization
|
||||
- Fix the remaining libtcc memory leaks.
|
||||
- make libtcc fully reentrant (except for the compilation stage itself).
|
||||
- '-MD' option
|
||||
|
||||
Optimizations:
|
||||
|
||||
- suppress specific anonymous symbol handling
|
||||
- more parse optimizations (=even faster compilation)
|
||||
- memory alloc optimizations (=even faster compilation)
|
||||
- optimize VT_LOCAL + const
|
||||
- better local variables handling (needed for other targets)
|
||||
|
||||
Not critical:
|
||||
|
||||
@@ -71,11 +75,21 @@ Not critical:
|
||||
- add portable byte code generator and interpreter for other
|
||||
unsupported architectures.
|
||||
- C++: variable declaration in for, minimal 'class' support.
|
||||
- win32: add __stdcall, __intxx. use resolve for bchecked malloc et
|
||||
al. check GetModuleHandle for dlls. check exception code (exception
|
||||
filter func).
|
||||
- win32: __intxx. use resolve for bchecked malloc et al.
|
||||
check exception code (exception filter func).
|
||||
- handle void (__attribute__() *ptr)()
|
||||
|
||||
Fixed (probably):
|
||||
|
||||
|
||||
|
||||
- bug with defines:
|
||||
#define spin_lock(lock) do { } while (0)
|
||||
#define wq_spin_lock spin_lock
|
||||
#define TEST() wq_spin_lock(a)
|
||||
- typedefs can be structure fields
|
||||
- see bugfixes.diff + improvement.diff from Daniel Glockner
|
||||
- long long constant evaluation
|
||||
- add alloca()
|
||||
- gcc '-E' option.
|
||||
- #include_next support for /usr/include/limits ?
|
||||
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
||||
- win32: add __stdcall, check GetModuleHandle for dlls.
|
||||
|
||||
552
arm-gen.c
552
arm-gen.c
@@ -20,8 +20,17 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
#define TCC_ARM_VFP
|
||||
#endif
|
||||
|
||||
|
||||
/* number of available registers */
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define NB_REGS 13
|
||||
#else
|
||||
#define NB_REGS 9
|
||||
#endif
|
||||
|
||||
/* a register can belong to several classes. The classes must be
|
||||
sorted from more general to more precise (see gv2() code which does
|
||||
@@ -37,6 +46,12 @@
|
||||
#define RC_F1 0x0100
|
||||
#define RC_F2 0x0200
|
||||
#define RC_F3 0x0400
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define RC_F4 0x0800
|
||||
#define RC_F5 0x1000
|
||||
#define RC_F6 0x2000
|
||||
#define RC_F7 0x4000
|
||||
#endif
|
||||
#define RC_IRET RC_R0 /* function return: integer register */
|
||||
#define RC_LRET RC_R1 /* function return: second integer register */
|
||||
#define RC_FRET RC_F0 /* function return: float register */
|
||||
@@ -52,6 +67,12 @@ enum {
|
||||
TREG_F1,
|
||||
TREG_F2,
|
||||
TREG_F3,
|
||||
#ifdef TCC_ARM_VFP
|
||||
TREG_F4,
|
||||
TREG_F5,
|
||||
TREG_F6,
|
||||
TREG_F7,
|
||||
#endif
|
||||
};
|
||||
|
||||
int reg_classes[NB_REGS] = {
|
||||
@@ -64,6 +85,12 @@ int reg_classes[NB_REGS] = {
|
||||
/* f1 */ RC_FLOAT | RC_F1,
|
||||
/* f2 */ RC_FLOAT | RC_F2,
|
||||
/* f3 */ RC_FLOAT | RC_F3,
|
||||
#ifdef TCC_ARM_VFP
|
||||
/* d4/s8 */ RC_FLOAT | RC_F4,
|
||||
/* d5/s10 */ RC_FLOAT | RC_F5,
|
||||
/* d6/s12 */ RC_FLOAT | RC_F6,
|
||||
/* d7/s14 */ RC_FLOAT | RC_F7,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int two2mask(int a,int b) {
|
||||
@@ -74,11 +101,22 @@ static int regmask(int r) {
|
||||
return reg_classes[r]&~(RC_INT|RC_FLOAT);
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
|
||||
#endif
|
||||
|
||||
/* return registers for function */
|
||||
#define REG_IRET TREG_R0 /* single word int return register */
|
||||
#define REG_LRET TREG_R1 /* second word return register (for long long) */
|
||||
#define REG_FRET TREG_F0 /* float return register */
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
#define TOK___divdi3 TOK___aeabi_ldivmod
|
||||
#define TOK___moddi3 TOK___aeabi_ldivmod
|
||||
#define TOK___udivdi3 TOK___aeabi_uldivmod
|
||||
#define TOK___umoddi3 TOK___aeabi_uldivmod
|
||||
#endif
|
||||
|
||||
/* defined if function parameters must be evaluated in reverse order */
|
||||
#define INVERT_FUNC_PARAMS
|
||||
|
||||
@@ -86,12 +124,33 @@ static int regmask(int r) {
|
||||
are directly pushed on stack. */
|
||||
//#define FUNC_STRUCT_PARAM_AS_PTR
|
||||
|
||||
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
|
||||
static CType float_type, double_type, func_float_type, func_double_type;
|
||||
#define func_ldouble_type func_double_type
|
||||
#else
|
||||
#define func_float_type func_old_type
|
||||
#define func_double_type func_old_type
|
||||
#define func_ldouble_type func_old_type
|
||||
#endif
|
||||
|
||||
/* pointer size, in bytes */
|
||||
#define PTR_SIZE 4
|
||||
|
||||
/* long double size and alignment, in bytes */
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define LDOUBLE_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef LDOUBLE_SIZE
|
||||
#define LDOUBLE_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
#define LDOUBLE_ALIGN 8
|
||||
#else
|
||||
#define LDOUBLE_ALIGN 4
|
||||
#endif
|
||||
|
||||
/* maximum alignment (for aligned attribute support) */
|
||||
#define MAX_ALIGN 8
|
||||
|
||||
@@ -112,6 +171,7 @@ static int regmask(int r) {
|
||||
|
||||
/******************************************************/
|
||||
static unsigned long func_sub_sp_offset,last_itod_magic;
|
||||
static int leaffunc;
|
||||
|
||||
void o(unsigned long i)
|
||||
{
|
||||
@@ -200,7 +260,7 @@ void stuff_const_harder(unsigned long op,unsigned long v) {
|
||||
for(i=1;i<16;i++)
|
||||
a[i]=(a[i-1]>>2)|(a[i-1]<<30);
|
||||
for(i=0;i<12;i++)
|
||||
for(j=i+4;i<13+i;i++)
|
||||
for(j=i<4?i+12:15;j>=i+4;j--)
|
||||
if((v&(a[i]|a[j]))==v) {
|
||||
o(stuff_const(op,v&a[i]));
|
||||
o(stuff_const(o2,v&a[j]));
|
||||
@@ -210,15 +270,15 @@ void stuff_const_harder(unsigned long op,unsigned long v) {
|
||||
n2=o2^0xC00000;
|
||||
nv=-v;
|
||||
for(i=0;i<12;i++)
|
||||
for(j=i+4;i<13+i;i++)
|
||||
for(j=i<4?i+12:15;j>=i+4;j--)
|
||||
if((nv&(a[i]|a[j]))==nv) {
|
||||
o(stuff_const(no,nv&a[i]));
|
||||
o(stuff_const(n2,nv&a[j]));
|
||||
return;
|
||||
}
|
||||
for(i=0;i<8;i++)
|
||||
for(j=i+4;i<12;i++)
|
||||
for(k=j+4;k<13+i;i++)
|
||||
for(j=i+4;j<12;j++)
|
||||
for(k=i<4?i+12:15;k>=j+4;k--)
|
||||
if((v&(a[i]|a[j]|a[k]))==v) {
|
||||
o(stuff_const(op,v&a[i]));
|
||||
o(stuff_const(o2,v&a[j]));
|
||||
@@ -228,8 +288,8 @@ void stuff_const_harder(unsigned long op,unsigned long v) {
|
||||
no=op^0xC00000;
|
||||
nv=-v;
|
||||
for(i=0;i<8;i++)
|
||||
for(j=i+4;i<12;i++)
|
||||
for(k=j+4;k<13+i;i++)
|
||||
for(j=i+4;j<12;j++)
|
||||
for(k=i<4?i+12:15;k>=j+4;k--)
|
||||
if((nv&(a[i]|a[j]|a[k]))==nv) {
|
||||
o(stuff_const(no,nv&a[i]));
|
||||
o(stuff_const(n2,nv&a[j]));
|
||||
@@ -287,19 +347,28 @@ void gsym(int t)
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
static unsigned long vfpr(int r)
|
||||
{
|
||||
if(r<TREG_F0 || r>TREG_F7)
|
||||
error("compiler error! register %i is no vfp register",r);
|
||||
return r-5;
|
||||
}
|
||||
#else
|
||||
static unsigned long fpr(int r)
|
||||
{
|
||||
if(r<TREG_F0 || r>TREG_F3)
|
||||
error("compiler error! register %i is no fp register\n",r);
|
||||
error("compiler error! register %i is no fpa register",r);
|
||||
return r-5;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long intr(int r)
|
||||
{
|
||||
if(r==4)
|
||||
return 12;
|
||||
if((r<0 || r>4) && r!=14)
|
||||
error("compiler error! register %i is no int register\n",r);
|
||||
error("compiler error! register %i is no int register",r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -335,28 +404,32 @@ static unsigned long mapcc(int cc)
|
||||
switch(cc)
|
||||
{
|
||||
case TOK_ULT:
|
||||
return 0x30000000;
|
||||
return 0x30000000; /* CC/LO */
|
||||
case TOK_UGE:
|
||||
return 0x20000000;
|
||||
return 0x20000000; /* CS/HS */
|
||||
case TOK_EQ:
|
||||
return 0x00000000;
|
||||
return 0x00000000; /* EQ */
|
||||
case TOK_NE:
|
||||
return 0x10000000;
|
||||
return 0x10000000; /* NE */
|
||||
case TOK_ULE:
|
||||
return 0x90000000;
|
||||
return 0x90000000; /* LS */
|
||||
case TOK_UGT:
|
||||
return 0x80000000;
|
||||
return 0x80000000; /* HI */
|
||||
case TOK_Nset:
|
||||
return 0x40000000; /* MI */
|
||||
case TOK_Nclear:
|
||||
return 0x50000000; /* PL */
|
||||
case TOK_LT:
|
||||
return 0xB0000000;
|
||||
return 0xB0000000; /* LT */
|
||||
case TOK_GE:
|
||||
return 0xA0000000;
|
||||
return 0xA0000000; /* GE */
|
||||
case TOK_LE:
|
||||
return 0xD0000000;
|
||||
return 0xD0000000; /* LE */
|
||||
case TOK_GT:
|
||||
return 0xC0000000;
|
||||
return 0xC0000000; /* GT */
|
||||
}
|
||||
error("unexpected condition code");
|
||||
return 0xE0000000;
|
||||
return 0xE0000000; /* AL */
|
||||
}
|
||||
|
||||
static int negcc(int cc)
|
||||
@@ -375,6 +448,10 @@ static int negcc(int cc)
|
||||
return TOK_UGT;
|
||||
case TOK_UGT:
|
||||
return TOK_ULE;
|
||||
case TOK_Nset:
|
||||
return TOK_Nclear;
|
||||
case TOK_Nclear:
|
||||
return TOK_Nset;
|
||||
case TOK_LT:
|
||||
return TOK_GE;
|
||||
case TOK_GE:
|
||||
@@ -432,6 +509,14 @@ void load(int r, SValue *sv)
|
||||
if(v == VT_LOCAL) {
|
||||
if(is_float(ft)) {
|
||||
calcaddr(&base,&fc,&sign,1020,2);
|
||||
#ifdef TCC_ARM_VFP
|
||||
op=0xED100A00; /* flds */
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
if ((ft & VT_BTYPE) != VT_FLOAT)
|
||||
op|=0x100; /* flds -> fldd */
|
||||
o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
#else
|
||||
op=0xED100100;
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
@@ -445,7 +530,9 @@ void load(int r, SValue *sv)
|
||||
op|=0x400000;
|
||||
#endif
|
||||
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
} else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) {
|
||||
#endif
|
||||
} else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE
|
||||
|| (ft & VT_BTYPE) == VT_SHORT) {
|
||||
calcaddr(&base,&fc,&sign,255,0);
|
||||
op=0xE1500090;
|
||||
if ((ft & VT_BTYPE) == VT_SHORT)
|
||||
@@ -504,7 +591,11 @@ void load(int r, SValue *sv)
|
||||
return;
|
||||
} else if (v < VT_CONST) {
|
||||
if(is_float(ft))
|
||||
#ifdef TCC_ARM_VFP
|
||||
o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */
|
||||
#else
|
||||
o(0xEE008180|(fpr(r)<<12)|fpr(v));
|
||||
#endif
|
||||
else
|
||||
o(0xE1A00000|(intr(r)<<12)|intr(v));
|
||||
return;
|
||||
@@ -550,6 +641,14 @@ void store(int r, SValue *sv)
|
||||
if(v == VT_LOCAL) {
|
||||
if(is_float(ft)) {
|
||||
calcaddr(&base,&fc,&sign,1020,2);
|
||||
#ifdef TCC_ARM_VFP
|
||||
op=0xED000A00; /* fsts */
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
if ((ft & VT_BTYPE) != VT_FLOAT)
|
||||
op|=0x100; /* fsts -> fstd */
|
||||
o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
#else
|
||||
op=0xED000100;
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
@@ -563,6 +662,7 @@ void store(int r, SValue *sv)
|
||||
op|=0x400000;
|
||||
#endif
|
||||
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
#endif
|
||||
return;
|
||||
} else if((ft & VT_BTYPE) == VT_SHORT) {
|
||||
calcaddr(&base,&fc,&sign,255,0);
|
||||
@@ -635,19 +735,44 @@ void gfunc_call(int nb_args)
|
||||
r = vtop->r & VT_VALMASK;
|
||||
if (r == VT_CMP || (r & ~1) == VT_JMP)
|
||||
gv(RC_INT);
|
||||
#ifdef TCC_ARM_EABI
|
||||
if((vtop[-nb_args].type.ref->type.t & VT_BTYPE) == VT_STRUCT
|
||||
&& type_size(&vtop[-nb_args].type, &align) <= 4) {
|
||||
SValue tmp;
|
||||
tmp=vtop[-nb_args];
|
||||
vtop[-nb_args]=vtop[-nb_args+1];
|
||||
vtop[-nb_args+1]=tmp;
|
||||
--nb_args;
|
||||
}
|
||||
|
||||
vpushi(0);
|
||||
vtop->type.t = VT_LLONG;
|
||||
args_size = 0;
|
||||
for(i = nb_args + 1 ; i-- ;) {
|
||||
size = type_size(&vtop[-i].type, &align);
|
||||
if(args_size & (align-1)) {
|
||||
vpushi(0);
|
||||
vtop->type.t = VT_VOID; /* padding */
|
||||
vrott(i+2);
|
||||
args_size += 4;
|
||||
++nb_args;
|
||||
}
|
||||
args_size += (size + 3) & -4;
|
||||
}
|
||||
vtop--;
|
||||
#endif
|
||||
args_size = 0;
|
||||
for(i = nb_args ; i-- && args_size < 16 ;) {
|
||||
if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
switch(vtop[-i].type.t & VT_BTYPE) {
|
||||
case VT_STRUCT:
|
||||
case VT_FLOAT:
|
||||
case VT_DOUBLE:
|
||||
case VT_LDOUBLE:
|
||||
size = type_size(&vtop[-i].type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
size = (size + 3) & -4;
|
||||
args_size += size;
|
||||
} else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT)
|
||||
args_size += 4;
|
||||
else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE)
|
||||
args_size += 8;
|
||||
else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE)
|
||||
args_size += LDOUBLE_SIZE;
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
plan[nb_args-1-i][0]=args_size/4;
|
||||
args_size += 4;
|
||||
if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) {
|
||||
@@ -662,7 +787,7 @@ void gfunc_call(int nb_args)
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
size = type_size(&vtop->type, &align);
|
||||
/* align to stack align size */
|
||||
size = (size + 3) & ~3;
|
||||
size = (size + 3) & -4;
|
||||
/* allocate the necessary size on stack */
|
||||
gadd_sp(-size);
|
||||
/* generate structure store */
|
||||
@@ -674,6 +799,16 @@ void gfunc_call(int nb_args)
|
||||
vtop--;
|
||||
args_size += size;
|
||||
} else if (is_float(vtop->type.t)) {
|
||||
#ifdef TCC_ARM_VFP
|
||||
r=vfpr(gv(RC_FLOAT))<<12;
|
||||
size=4;
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
|
||||
{
|
||||
size=8;
|
||||
r|=0x101; /* fstms -> fstmd */
|
||||
}
|
||||
o(0xED2D0A01+r);
|
||||
#else
|
||||
r=fpr(gv(RC_FLOAT))<<12;
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
|
||||
size = 4;
|
||||
@@ -688,6 +823,7 @@ void gfunc_call(int nb_args)
|
||||
r|=0x8000;
|
||||
|
||||
o(0xED2D0100|r|(size>>2));
|
||||
#endif
|
||||
vtop--;
|
||||
args_size += size;
|
||||
} else {
|
||||
@@ -718,7 +854,14 @@ void gfunc_call(int nb_args)
|
||||
s=regmask(plan[nb_args-i-1][0]);
|
||||
todo&=~(1<<plan[nb_args-i-1][0]);
|
||||
}
|
||||
if(s==RC_INT) {
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(vtop->type.t == VT_VOID) {
|
||||
if(s == RC_INT)
|
||||
o(0xE24DD004); /* sub sp,sp,#4 */
|
||||
vtop--;
|
||||
} else
|
||||
#endif
|
||||
if(s == RC_INT) {
|
||||
r = gv(s);
|
||||
o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
|
||||
vtop--;
|
||||
@@ -733,7 +876,7 @@ void gfunc_call(int nb_args)
|
||||
gv(plan2[i]);
|
||||
vrott(keep);
|
||||
}
|
||||
save_regs(keep); /* save used temporary registers */
|
||||
save_regs(keep); /* save used temporary registers */
|
||||
keep++;
|
||||
if(args_size) {
|
||||
int n;
|
||||
@@ -758,7 +901,26 @@ void gfunc_call(int nb_args)
|
||||
gcall_or_jmp(0);
|
||||
if (args_size)
|
||||
gadd_sp(args_size);
|
||||
#ifdef TCC_ARM_EABI
|
||||
if((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT
|
||||
&& type_size(&vtop->type.ref->type, &align) <= 4)
|
||||
{
|
||||
store(REG_IRET,vtop-keep);
|
||||
++keep;
|
||||
}
|
||||
#ifdef TCC_ARM_VFP
|
||||
else if(is_float(vtop->type.ref->type.t)) {
|
||||
if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
|
||||
o(0xEE000A10); /* fmsr s0,r0 */
|
||||
} else {
|
||||
o(0xEE000B10); /* fmdlr d0,r0 */
|
||||
o(0xEE201B10); /* fmdhr d0,r1 */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
vtop-=keep;
|
||||
leaffunc = 0;
|
||||
}
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
@@ -770,17 +932,18 @@ void gfunc_prolog(CType *func_type)
|
||||
sym = func_type->ref;
|
||||
func_vt = sym->type;
|
||||
|
||||
n=0;
|
||||
addr=12;
|
||||
if((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
n = 0;
|
||||
addr = 0;
|
||||
if((func_vt.t & VT_BTYPE) == VT_STRUCT
|
||||
&& type_size(&func_vt,&align) > 4)
|
||||
{
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
n++;
|
||||
}
|
||||
for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
|
||||
size = type_size(&sym2->type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
n+=size/4;
|
||||
n += (size + 3) / 4;
|
||||
}
|
||||
o(0xE1A0C00D); /* mov ip,sp */
|
||||
if(func_type->ref->c == FUNC_ELLIPSIS)
|
||||
@@ -788,40 +951,63 @@ void gfunc_prolog(CType *func_type)
|
||||
if(n) {
|
||||
if(n>4)
|
||||
n=4;
|
||||
#ifdef TCC_ARM_EABI
|
||||
n=(n+1)&-2;
|
||||
#endif
|
||||
o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
|
||||
}
|
||||
o(0xE92D5800); /* save fp, ip, lr*/
|
||||
o(0xE1A0B00D); /* mov fp,sp */
|
||||
o(0xE92D5800); /* save fp, ip, lr */
|
||||
o(0xE28DB00C); /* add fp, sp, #12 */
|
||||
func_sub_sp_offset = ind;
|
||||
o(0xE1A00000); /* nop, leave space for stack adjustment */
|
||||
while ((sym = sym->next)) {
|
||||
CType *type;
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
size = (size + 3) & -4;
|
||||
#ifdef TCC_ARM_EABI
|
||||
addr = (addr + align - 1) & -align;
|
||||
#endif
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
|
||||
addr += size;
|
||||
}
|
||||
last_itod_magic=0;
|
||||
loc = 0;
|
||||
leaffunc = 1;
|
||||
loc = -12;
|
||||
}
|
||||
|
||||
/* generate function epilog */
|
||||
void gfunc_epilog(void)
|
||||
{
|
||||
unsigned long x;
|
||||
o(0xE89BA800); /* restore fp, sp, pc */
|
||||
if(loc) {
|
||||
x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */
|
||||
int diff;
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(is_float(func_vt.t)) {
|
||||
if((func_vt.t & VT_BTYPE) == VT_FLOAT)
|
||||
o(0xEE100A10); /* fmrs r0, s0 */
|
||||
else {
|
||||
o(0xEE100B10); /* fmrdl r0, d0 */
|
||||
o(0xEE301B10); /* fmrdh r1, d0 */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
o(0xE91BA800); /* restore fp, sp, pc */
|
||||
diff = (-loc + 3) & -4;
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(!leaffunc)
|
||||
diff = (diff + 7) & -8;
|
||||
#endif
|
||||
if(diff > 12) {
|
||||
x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
|
||||
if(x)
|
||||
*(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x;
|
||||
else {
|
||||
unsigned long addr;
|
||||
addr=ind;
|
||||
o(0xE59FC004); /* ldr ip,[pc+4] */
|
||||
o(0xE04DD00C); /* sub sp,sp,ip */
|
||||
o(0xE04BD00C); /* sub sp,fp,ip */
|
||||
o(0xE1A0F00E); /* mov pc,lr */
|
||||
o((-loc + 3) & -4);
|
||||
o(diff);
|
||||
*(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
|
||||
}
|
||||
}
|
||||
@@ -879,7 +1065,12 @@ int gtst(int inv, int t)
|
||||
} else {
|
||||
if (is_float(vtop->type.t)) {
|
||||
r=gv(RC_FLOAT);
|
||||
o(0xEE90F118|fpr(r)<<16);
|
||||
#ifdef TCC_ARM_VFP
|
||||
o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */
|
||||
o(0xEEF1FA10); /* fmstat */
|
||||
#else
|
||||
o(0xEE90F118|(fpr(r)<<16));
|
||||
#endif
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = TOK_NE;
|
||||
return gtst(inv, t);
|
||||
@@ -904,6 +1095,7 @@ void gen_opi(int op)
|
||||
{
|
||||
int c, func = 0;
|
||||
unsigned long opc = 0,r,fr;
|
||||
unsigned short retreg = REG_IRET;
|
||||
|
||||
c=0;
|
||||
switch(op) {
|
||||
@@ -972,11 +1164,21 @@ void gen_opi(int op)
|
||||
c=3;
|
||||
break;
|
||||
case '%':
|
||||
#ifdef TCC_ARM_EABI
|
||||
func=TOK___aeabi_idivmod;
|
||||
retreg=REG_LRET;
|
||||
#else
|
||||
func=TOK___modsi3;
|
||||
#endif
|
||||
c=3;
|
||||
break;
|
||||
case TOK_UMOD:
|
||||
#ifdef TCC_ARM_EABI
|
||||
func=TOK___aeabi_uidivmod;
|
||||
retreg=REG_LRET;
|
||||
#else
|
||||
func=TOK___umodsi3;
|
||||
#endif
|
||||
c=3;
|
||||
break;
|
||||
case TOK_UMULL:
|
||||
@@ -1051,13 +1253,117 @@ done:
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
vtop->r = REG_IRET;
|
||||
vtop->r = retreg;
|
||||
break;
|
||||
default:
|
||||
error("gen_opi %i unimplemented!",op);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
static int is_zero(int i)
|
||||
{
|
||||
if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
|
||||
return 0;
|
||||
if (vtop[i].type.t == VT_FLOAT)
|
||||
return (vtop[i].c.f == 0.f);
|
||||
else if (vtop[i].type.t == VT_DOUBLE)
|
||||
return (vtop[i].c.d == 0.0);
|
||||
return (vtop[i].c.ld == 0.l);
|
||||
}
|
||||
|
||||
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
||||
* two operands are guaranted to have the same floating point type */
|
||||
void gen_opf(int op)
|
||||
{
|
||||
unsigned long x;
|
||||
int fneg=0,r;
|
||||
x=0xEE000A00|T2CPR(vtop->type.t);
|
||||
switch(op) {
|
||||
case '+':
|
||||
if(is_zero(-1))
|
||||
vswap();
|
||||
if(is_zero(0)) {
|
||||
vtop--;
|
||||
return;
|
||||
}
|
||||
x|=0x300000;
|
||||
break;
|
||||
case '-':
|
||||
x|=0x300040;
|
||||
if(is_zero(0)) {
|
||||
vtop--;
|
||||
return;
|
||||
}
|
||||
if(is_zero(-1)) {
|
||||
x|=0x810000; /* fsubX -> fnegX */
|
||||
vswap();
|
||||
vtop--;
|
||||
fneg=1;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
x|=0x200000;
|
||||
break;
|
||||
case '/':
|
||||
x|=0x800000;
|
||||
break;
|
||||
default:
|
||||
if(op < TOK_ULT && op > TOK_GT) {
|
||||
error("unknown fp op %x!",op);
|
||||
return;
|
||||
}
|
||||
if(is_zero(-1)) {
|
||||
vswap();
|
||||
switch(op) {
|
||||
case TOK_LT: op=TOK_GT; break;
|
||||
case TOK_GE: op=TOK_ULE; break;
|
||||
case TOK_LE: op=TOK_GE; break;
|
||||
case TOK_GT: op=TOK_ULT; break;
|
||||
}
|
||||
}
|
||||
x|=0xB40040; /* fcmpX */
|
||||
if(op!=TOK_EQ && op!=TOK_NE)
|
||||
x|=0x80; /* fcmpX -> fcmpeX */
|
||||
if(is_zero(0)) {
|
||||
vtop--;
|
||||
o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
|
||||
} else {
|
||||
x|=vfpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
o(x|(vfpr(gv(RC_FLOAT))<<12));
|
||||
vtop--;
|
||||
}
|
||||
o(0xEEF1FA10); /* fmstat */
|
||||
|
||||
switch(op) {
|
||||
case TOK_LE: op=TOK_ULE; break;
|
||||
case TOK_LT: op=TOK_ULT; break;
|
||||
case TOK_UGE: op=TOK_GE; break;
|
||||
case TOK_UGT: op=TOK_GT; break;
|
||||
}
|
||||
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
return;
|
||||
}
|
||||
r=gv(RC_FLOAT);
|
||||
x|=vfpr(r);
|
||||
r=regmask(r);
|
||||
if(!fneg) {
|
||||
int r2;
|
||||
vswap();
|
||||
r2=gv(RC_FLOAT);
|
||||
x|=vfpr(r2)<<16;
|
||||
r|=regmask(r2);
|
||||
}
|
||||
vtop->r=get_reg_ex(RC_FLOAT,r);
|
||||
if(!fneg)
|
||||
vtop--;
|
||||
o(x|(vfpr(vtop->r)<<12));
|
||||
}
|
||||
|
||||
#else
|
||||
static int is_fconst()
|
||||
{
|
||||
long double f;
|
||||
@@ -1193,24 +1499,20 @@ void gen_opf(int op)
|
||||
default:
|
||||
if(op >= TOK_ULT && op <= TOK_GT) {
|
||||
x|=0xd0f110; // cmfe
|
||||
/* bug (intention?) in Linux FPU emulator
|
||||
doesn't set carry if equal */
|
||||
switch(op) {
|
||||
case TOK_ULT:
|
||||
case TOK_UGE:
|
||||
case TOK_ULE:
|
||||
case TOK_UGT:
|
||||
fputs("unsigned comparision on floats?\n",stderr);
|
||||
error("unsigned comparision on floats?");
|
||||
break;
|
||||
case TOK_LT:
|
||||
op=TOK_ULT;
|
||||
break;
|
||||
case TOK_GE:
|
||||
op=TOK_UGE;
|
||||
op=TOK_Nset;
|
||||
break;
|
||||
case TOK_LE:
|
||||
op=TOK_ULE;
|
||||
break;
|
||||
case TOK_GT:
|
||||
op=TOK_UGT;
|
||||
op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
|
||||
break;
|
||||
case TOK_EQ:
|
||||
case TOK_NE:
|
||||
@@ -1221,26 +1523,20 @@ void gen_opf(int op)
|
||||
c2=c1;
|
||||
vswap();
|
||||
switch(op) {
|
||||
case TOK_ULT:
|
||||
op=TOK_UGT;
|
||||
case TOK_Nset:
|
||||
op=TOK_GT;
|
||||
break;
|
||||
case TOK_UGE:
|
||||
case TOK_GE:
|
||||
op=TOK_ULE;
|
||||
break;
|
||||
case TOK_ULE:
|
||||
op=TOK_UGE;
|
||||
op=TOK_GE;
|
||||
break;
|
||||
case TOK_UGT:
|
||||
op=TOK_ULT;
|
||||
case TOK_GT:
|
||||
op=TOK_Nset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// bug (intention?) in Linux FPU emulator
|
||||
// doesn't set carry if equal
|
||||
if(op==TOK_ULT)
|
||||
op=TOK_LT;
|
||||
else if(op==TOK_UGE)
|
||||
op=TOK_GE;
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
@@ -1254,7 +1550,7 @@ void gen_opf(int op)
|
||||
vtop[-1].r = VT_CMP;
|
||||
vtop[-1].c.i = op;
|
||||
} else {
|
||||
error("unknown fp op %x!\n",op);
|
||||
error("unknown fp op %x!",op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1270,20 +1566,34 @@ void gen_opf(int op)
|
||||
vtop--;
|
||||
o(x|(r<<16)|(c1<<12)|r2);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
|
||||
and 'long long' cases. */
|
||||
void gen_cvt_itof(int t)
|
||||
void gen_cvt_itof1(int t)
|
||||
{
|
||||
int r,r2,bt;
|
||||
bt=vtop->type.t & VT_BTYPE;
|
||||
if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
|
||||
#ifndef TCC_ARM_VFP
|
||||
unsigned int dsize=0;
|
||||
#endif
|
||||
r=intr(gv(RC_INT));
|
||||
#ifdef TCC_ARM_VFP
|
||||
r2=vfpr(vtop->r=get_reg(RC_FLOAT));
|
||||
o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
|
||||
r2<<=12;
|
||||
if(!(vtop->type.t & VT_UNSIGNED))
|
||||
r2|=0x80; /* fuitoX -> fsituX */
|
||||
o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
|
||||
#else
|
||||
r2=fpr(vtop->r=get_reg(RC_FLOAT));
|
||||
o(0xEE000190|(r2<<16)|(r<<12));
|
||||
if((t & VT_BTYPE) != VT_FLOAT)
|
||||
dsize=0x80; /* flts -> fltd */
|
||||
o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
|
||||
if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
|
||||
unsigned int off=0;
|
||||
o(0xE3500000|(r<<12));
|
||||
o(0xE3500000|(r<<12)); /* cmp */
|
||||
r=fpr(get_reg(RC_FLOAT));
|
||||
if(last_itod_magic) {
|
||||
off=ind+8-last_itod_magic;
|
||||
@@ -1291,28 +1601,50 @@ void gen_cvt_itof(int t)
|
||||
if(off>255)
|
||||
off=0;
|
||||
}
|
||||
o(0xBD1F8100|(r<<12)|off);
|
||||
o(0xBD1F0100|(r<<12)|off); /* ldflts */
|
||||
if(!off) {
|
||||
o(0xEA000001);
|
||||
o(0xEA000000); /* b */
|
||||
last_itod_magic=ind;
|
||||
o(0x41F00000);
|
||||
o(0);
|
||||
o(0x4F800000); /* 4294967296.0f */
|
||||
}
|
||||
o(0xBE000180|(r2<<16)|(r2<<12)|r);
|
||||
o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
} else if(bt == VT_LLONG) {
|
||||
int func;
|
||||
if(vtop->type.t & VT_UNSIGNED)
|
||||
func=TOK___ulltold;
|
||||
else
|
||||
func=TOK___slltold;
|
||||
vpush_global_sym(&func_old_type, func);
|
||||
vswap();
|
||||
gfunc_call(1);
|
||||
vpushi(0);
|
||||
vtop->r=TREG_F0;
|
||||
return;
|
||||
CType *func_type = 0;
|
||||
if((t & VT_BTYPE) == VT_FLOAT) {
|
||||
func_type = &func_float_type;
|
||||
if(vtop->type.t & VT_UNSIGNED)
|
||||
func=TOK___floatundisf;
|
||||
else
|
||||
func=TOK___floatdisf;
|
||||
#if LDOUBLE_SIZE != 8
|
||||
} else if((t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
func_type = &func_ldouble_type;
|
||||
if(vtop->type.t & VT_UNSIGNED)
|
||||
func=TOK___floatundixf;
|
||||
else
|
||||
func=TOK___floatdixf;
|
||||
} else if((t & VT_BTYPE) == VT_DOUBLE) {
|
||||
#else
|
||||
} else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
#endif
|
||||
func_type = &func_double_type;
|
||||
if(vtop->type.t & VT_UNSIGNED)
|
||||
func=TOK___floatundidf;
|
||||
else
|
||||
func=TOK___floatdidf;
|
||||
}
|
||||
if(func_type) {
|
||||
vpush_global_sym(func_type, func);
|
||||
vswap();
|
||||
gfunc_call(1);
|
||||
vpushi(0);
|
||||
vtop->r=TREG_F0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("unimplemented gen_cvt_itof %x!",vtop->type.t);
|
||||
}
|
||||
@@ -1325,35 +1657,44 @@ void gen_cvt_ftoi(int t)
|
||||
t&=VT_BTYPE;
|
||||
r2=vtop->type.t & VT_BTYPE;
|
||||
if(t==VT_INT) {
|
||||
#ifdef TCC_ARM_VFP
|
||||
r=vfpr(gv(RC_FLOAT));
|
||||
u=u?0:0x10000;
|
||||
o(0xEEBC0A40|(r<<12)|r|T2CPR(r2)); /* ftoXiY */
|
||||
r2=intr(vtop->r=get_reg(RC_INT));
|
||||
o(0xEE100A10|(r<<16)|(r2<<12));
|
||||
return;
|
||||
#else
|
||||
if(u) {
|
||||
if(r2 == VT_FLOAT)
|
||||
func=TOK___fixunssfsi;
|
||||
else if(r2 == VT_DOUBLE)
|
||||
func=TOK___fixunsdfsi;
|
||||
#if LDOUBLE_SIZE != 8
|
||||
else if(r2 == VT_LDOUBLE)
|
||||
#if LDOUBLE_SIZE == 8
|
||||
func=TOK___fixunsdfsi;
|
||||
#else
|
||||
func=TOK___fixunsxfsi;
|
||||
else if(r2 == VT_DOUBLE)
|
||||
#else
|
||||
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
|
||||
#endif
|
||||
func=TOK___fixunsdfsi;
|
||||
} else {
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
r2=intr(vtop->r=get_reg(RC_INT));
|
||||
o(0xEE100170|(r2<<12)|r);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
|
||||
if(r2 == VT_FLOAT)
|
||||
func=TOK___fixsfdi;
|
||||
else if(r2 == VT_DOUBLE)
|
||||
func=TOK___fixdfdi;
|
||||
#if LDOUBLE_SIZE != 8
|
||||
else if(r2 == VT_LDOUBLE)
|
||||
#if LDOUBLE_SIZE == 8
|
||||
func=TOK___fixdfdi;
|
||||
#else
|
||||
func=TOK___fixxfdi;
|
||||
else if(r2 == VT_DOUBLE)
|
||||
#else
|
||||
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
|
||||
#endif
|
||||
}
|
||||
func=TOK___fixdfdi;
|
||||
}
|
||||
if(func) {
|
||||
vpush_global_sym(&func_old_type, func);
|
||||
vswap();
|
||||
@@ -1370,8 +1711,15 @@ void gen_cvt_ftoi(int t)
|
||||
/* convert from one floating point type to another */
|
||||
void gen_cvt_ftof(int t)
|
||||
{
|
||||
/* all we have to do on i386 and ARM is to put the float in a register */
|
||||
#ifdef TCC_ARM_VFP
|
||||
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
|
||||
int r=vfpr(gv(RC_FLOAT));
|
||||
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
|
||||
}
|
||||
#else
|
||||
/* all we have to do on i386 and FPA ARM is to put the float in a register */
|
||||
gv(RC_FLOAT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* computed goto support */
|
||||
|
||||
@@ -1964,7 +1964,7 @@ void gfunc_prolog(CType * func_type)
|
||||
/* define parameters */
|
||||
while ((sym = sym->next) != NULL) {
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
|
||||
|
||||
69
configure
vendored
69
configure
vendored
@@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.h"
|
||||
|
||||
# default parameters
|
||||
build_cross="no"
|
||||
use_libgcc="no"
|
||||
prefix=""
|
||||
execprefix=""
|
||||
bindir=""
|
||||
@@ -26,17 +27,20 @@ libdir=""
|
||||
tccdir=""
|
||||
includedir=""
|
||||
mandir=""
|
||||
sysroot=""
|
||||
cross_prefix=""
|
||||
cc="gcc"
|
||||
host_cc="gcc"
|
||||
ar="ar"
|
||||
make="make"
|
||||
strip="strip"
|
||||
cpu=`uname -m`
|
||||
case "$cpu" in
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="x86"
|
||||
;;
|
||||
x86_64)
|
||||
cpu="x86-64"
|
||||
;;
|
||||
armv4l)
|
||||
cpu="armv4l"
|
||||
;;
|
||||
@@ -68,6 +72,12 @@ case $targetos in
|
||||
MINGW32*)
|
||||
mingw32="yes"
|
||||
;;
|
||||
DragonFly)
|
||||
noldl="yes"
|
||||
;;
|
||||
OpenBSD)
|
||||
noldl="yes"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
@@ -96,14 +106,14 @@ for opt do
|
||||
;;
|
||||
--mandir=*) mandir=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--sysroot=*) sysroot=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--make=*) make=`echo $opt | cut -d '=' -f 2`
|
||||
;;
|
||||
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
|
||||
;;
|
||||
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
|
||||
@@ -118,6 +128,8 @@ for opt do
|
||||
;;
|
||||
--enable-cross) build_cross="yes"
|
||||
;;
|
||||
--with-libgcc) use_libgcc="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -142,15 +154,15 @@ if test -z "$cross_prefix" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <inttypes.h>
|
||||
int main(int argc, char ** argv){
|
||||
volatile uint32_t i=0x01234567;
|
||||
return (*((uint8_t*)(&i))) == 0x67;
|
||||
volatile uint32_t i=0x01234567;
|
||||
return (*((uint8_t*)(&i))) == 0x67;
|
||||
}
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPE $TMPC 2>/dev/null ; then
|
||||
$TMPE && bigendian="yes"
|
||||
$TMPE && bigendian="yes"
|
||||
else
|
||||
echo big/little test failed
|
||||
echo big/little test failed
|
||||
fi
|
||||
|
||||
else
|
||||
@@ -175,7 +187,20 @@ EOF
|
||||
|
||||
gcc_major="2"
|
||||
if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="3"
|
||||
gcc_major="3"
|
||||
fi
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
#if __GNUC__ >= 4
|
||||
return 0;
|
||||
#else
|
||||
#error gcc < 4
|
||||
#endif
|
||||
}
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="4"
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
@@ -194,13 +219,14 @@ echo " --bindir=DIR user executables in DIR [EPREFIX/bin]"
|
||||
echo " --libdir=DIR object code libraries in DIR [EPREFIX/lib]"
|
||||
echo " --includedir=DIR C header files in DIR [PREFIX/include]"
|
||||
echo " --mandir=DIR man documentation in DIR [PREFIX/man]"
|
||||
echo " --build-cross build cross compilers"
|
||||
echo " --enable-cross build cross compilers"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
|
||||
echo " --sysroot=PREFIX prepend PREFIX to library/include paths []"
|
||||
echo " --cc=CC use C compiler CC [$cc]"
|
||||
echo " --make=MAKE use specified make [$make]"
|
||||
echo " --with-libgcc use /lib/libgcc_s.so.1 instead of libtcc1.a"
|
||||
echo ""
|
||||
#echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
@@ -208,7 +234,7 @@ fi
|
||||
|
||||
if test "$mingw32" = "yes" ; then
|
||||
if test -z "$prefix" ; then
|
||||
prefix="/c/Program Files/tcc"
|
||||
prefix="C:/Program Files/tcc"
|
||||
fi
|
||||
execprefix="$prefix"
|
||||
bindir="$prefix"
|
||||
@@ -248,13 +274,14 @@ echo "Library directory $libdir"
|
||||
echo "Include directory $includedir"
|
||||
echo "Manual directory $mandir"
|
||||
echo "Doc directory $docdir"
|
||||
echo "Target root prefix $sysroot"
|
||||
echo "Source path $source_path"
|
||||
echo "C compiler $cc"
|
||||
echo "make $make"
|
||||
echo "CPU $cpu"
|
||||
echo "Big Endian $bigendian"
|
||||
echo "gprof enabled $gprof"
|
||||
echo "cross compilers $build_cross"
|
||||
echo "use libgcc $use_libgcc"
|
||||
|
||||
echo "Creating config.mak and config.h"
|
||||
|
||||
@@ -268,8 +295,8 @@ echo "libdir=$libdir" >> config.mak
|
||||
echo "includedir=$includedir" >> config.mak
|
||||
echo "mandir=$mandir" >> config.mak
|
||||
echo "docdir=$docdir" >> config.mak
|
||||
echo "#define CONFIG_SYSROOT \"$sysroot\"" >> $TMPH
|
||||
echo "#define CONFIG_TCCDIR \"$tccdir\"" >> $TMPH
|
||||
echo "MAKE=$make" >> config.mak
|
||||
echo "CC=$cc" >> config.mak
|
||||
echo "GCC_MAJOR=$gcc_major" >> config.mak
|
||||
echo "#define GCC_MAJOR $gcc_major" >> $TMPH
|
||||
@@ -283,6 +310,9 @@ echo "EXESUF=$EXESUF" >> config.mak
|
||||
if test "$cpu" = "x86" ; then
|
||||
echo "ARCH=i386" >> config.mak
|
||||
echo "#define HOST_I386 1" >> $TMPH
|
||||
elif test "$cpu" = "x86-64" ; then
|
||||
echo "ARCH=x86-64" >> config.mak
|
||||
echo "#define HOST_X86_64 1" >> $TMPH
|
||||
elif test "$cpu" = "armv4l" ; then
|
||||
echo "ARCH=arm" >> config.mak
|
||||
echo "#define HOST_ARM 1" >> $TMPH
|
||||
@@ -302,6 +332,9 @@ else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$noldl" = "yes" ; then
|
||||
echo "CONFIG_NOLDL=yes" >> config.mak
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=yes" >> config.mak
|
||||
echo "#define CONFIG_WIN32 1" >> $TMPH
|
||||
@@ -317,6 +350,10 @@ fi
|
||||
if test "$build_cross" = "yes" ; then
|
||||
echo "CONFIG_CROSS=yes" >> config.mak
|
||||
fi
|
||||
if test "$use_libgcc" = "yes" ; then
|
||||
echo "#define CONFIG_USE_LIBGCC" >> $TMPH
|
||||
echo "CONFIG_USE_LIBGCC=yes" >> config.mak
|
||||
fi
|
||||
version=`head $source_path/VERSION`
|
||||
echo "VERSION=$version" >>config.mak
|
||||
echo "#define TCC_VERSION \"$version\"" >> $TMPH
|
||||
@@ -327,7 +364,7 @@ if test "$source_path_used" = "yes" ; then
|
||||
DIRS="tests"
|
||||
FILES="Makefile tests/Makefile"
|
||||
for dir in $DIRS ; do
|
||||
mkdir -p $dir
|
||||
mkdir -p $dir
|
||||
done
|
||||
for f in $FILES ; do
|
||||
ln -sf $source_path/$f $f
|
||||
@@ -337,9 +374,9 @@ echo "SRC_PATH=$source_path" >> config.mak
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
mv -f $TMPH config.h
|
||||
mv -f $TMPH config.h
|
||||
else
|
||||
echo "config.h is unchanged"
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /usr/local/bin/tcc -run
|
||||
#include <tcclib.h>
|
||||
|
||||
int main()
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "tcclib.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define N 20
|
||||
|
||||
@@ -23,7 +24,7 @@ int find(int n, int i1, int a, int b, int op)
|
||||
return 1;
|
||||
tab[i1] = n;
|
||||
}
|
||||
|
||||
|
||||
for(i=0;i<nb_num;i++) {
|
||||
for(j=i+1;j<nb_num;j++) {
|
||||
a = tab[i];
|
||||
@@ -52,7 +53,7 @@ int find(int n, int i1, int a, int b, int op)
|
||||
if (find(c, i, b, a, '/'))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
stack_ptr--;
|
||||
tab[i] = a;
|
||||
tab[j] = b;
|
||||
@@ -66,7 +67,7 @@ int find(int n, int i1, int a, int b, int op)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, res, p;
|
||||
|
||||
|
||||
if (argc < 3) {
|
||||
printf("usage: %s: result numbers...\n"
|
||||
"Try to find result from numbers with the 4 basic operations.\n", argv[0]);
|
||||
@@ -85,7 +86,7 @@ int main(int argc, char **argv)
|
||||
res = find(0, 0, 0, 0, ' ');
|
||||
if (res) {
|
||||
for(i=0;i<=stack_ptr;i++) {
|
||||
printf("%d %c %d = %d\n",
|
||||
printf("%d %c %d = %d\n",
|
||||
stack_res[3*i], stack_op[i],
|
||||
stack_res[3*i+1], stack_res[3*i+2]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <tcclib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int fib(n)
|
||||
{
|
||||
@@ -8,7 +9,7 @@ int fib(n)
|
||||
return fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n;
|
||||
if (argc < 2) {
|
||||
@@ -16,7 +17,7 @@ int main(int argc, char **argv)
|
||||
"Compute nth Fibonacci number\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
n = atoi(argv[1]);
|
||||
printf("fib(%d) = %d\n", n, fib(n, 2));
|
||||
return 0;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#!./tcc -run -L/usr/X11R6/lib -lX11
|
||||
#include <stdlib.h>
|
||||
/* Yes, TCC can use X11 too ! */
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
/* Yes, TCC can use X11 too ! */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Display *display;
|
||||
@@ -16,8 +17,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
printf("X11 display opened.\n");
|
||||
screen = XScreenOfDisplay(display, 0);
|
||||
printf("width = %d\nheight = %d\ndepth = %d\n",
|
||||
screen->width,
|
||||
printf("width = %d\nheight = %d\ndepth = %d\n",
|
||||
screen->width,
|
||||
screen->height,
|
||||
screen->root_depth);
|
||||
XCloseDisplay(display);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
|
||||
34
i386-asm.c
34
i386-asm.c
@@ -109,9 +109,12 @@ typedef struct Operand {
|
||||
} Operand;
|
||||
|
||||
static const uint8_t reg_to_size[5] = {
|
||||
/*
|
||||
[OP_REG8] = 0,
|
||||
[OP_REG16] = 1,
|
||||
[OP_REG32] = 2,
|
||||
*/
|
||||
0, 0, 1, 0, 2
|
||||
};
|
||||
|
||||
#define WORD_PREFIX_OPCODE 0x66
|
||||
@@ -151,6 +154,15 @@ static const uint8_t test_bits[NB_TEST_OPCODES] = {
|
||||
0x0f, /* g */
|
||||
};
|
||||
|
||||
static const uint8_t segment_prefixes[] = {
|
||||
0x26, /* es */
|
||||
0x2e, /* cs */
|
||||
0x36, /* ss */
|
||||
0x3e, /* ds */
|
||||
0x64, /* fs */
|
||||
0x65 /* gs */
|
||||
};
|
||||
|
||||
static const ASMInstr asm_instrs[] = {
|
||||
#define ALT(x) x
|
||||
#define DEF_ASM_OP0(name, opcode)
|
||||
@@ -311,8 +323,10 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||
if (tok != ',') {
|
||||
op->reg2 = asm_parse_reg();
|
||||
}
|
||||
skip(',');
|
||||
op->shift = get_reg_shift(s1);
|
||||
if (tok == ',') {
|
||||
next();
|
||||
op->shift = get_reg_shift(s1);
|
||||
}
|
||||
}
|
||||
skip(')');
|
||||
}
|
||||
@@ -410,7 +424,7 @@ static inline void asm_modrm(int reg, Operand *op)
|
||||
static void asm_opcode(TCCState *s1, int opcode)
|
||||
{
|
||||
const ASMInstr *pa;
|
||||
int i, modrm_index, reg, v, op1, is_short_jmp;
|
||||
int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;
|
||||
int nb_ops, s, ss;
|
||||
Operand ops[MAX_OPERANDS], *pop;
|
||||
int op_type[3]; /* decoded op type */
|
||||
@@ -418,6 +432,7 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
/* get operands */
|
||||
pop = ops;
|
||||
nb_ops = 0;
|
||||
seg_prefix = 0;
|
||||
for(;;) {
|
||||
if (tok == ';' || tok == TOK_LINEFEED)
|
||||
break;
|
||||
@@ -425,6 +440,17 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
error("incorrect number of operands");
|
||||
}
|
||||
parse_operand(s1, pop);
|
||||
if (tok == ':') {
|
||||
if (pop->type != OP_SEG || seg_prefix) {
|
||||
error("incorrect prefix");
|
||||
}
|
||||
seg_prefix = segment_prefixes[pop->reg];
|
||||
next();
|
||||
parse_operand(s1, pop);
|
||||
if (!(pop->type & OP_EA)) {
|
||||
error("segment prefix must be followed by memory reference");
|
||||
}
|
||||
}
|
||||
pop++;
|
||||
nb_ops++;
|
||||
if (tok != ',')
|
||||
@@ -538,6 +564,8 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
/* now generates the operation */
|
||||
if (pa->instr_type & OPC_FWAIT)
|
||||
g(0x9b);
|
||||
if (seg_prefix)
|
||||
g(seg_prefix);
|
||||
|
||||
v = pa->opcode;
|
||||
if (v == 0x69 || v == 0x69) {
|
||||
|
||||
39
i386-gen.c
39
i386-gen.c
@@ -321,6 +321,7 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
|
||||
|
||||
/* Generate function call. The function address is pushed first, then
|
||||
all the parameters in call order. This functions pops all the
|
||||
@@ -379,21 +380,29 @@ void gfunc_call(int nb_args)
|
||||
}
|
||||
save_regs(0); /* save used temporary registers */
|
||||
func_sym = vtop->type.ref;
|
||||
func_call = func_sym->r;
|
||||
func_call = FUNC_CALL(func_sym->r);
|
||||
/* fast call case */
|
||||
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
|
||||
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
|
||||
func_call == FUNC_FASTCALLW) {
|
||||
int fastcall_nb_regs;
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
uint8_t *fastcall_regs_ptr;
|
||||
if (func_call == FUNC_FASTCALLW) {
|
||||
fastcall_regs_ptr = fastcallw_regs;
|
||||
fastcall_nb_regs = 2;
|
||||
} else {
|
||||
fastcall_regs_ptr = fastcall_regs;
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
}
|
||||
for(i = 0;i < fastcall_nb_regs; i++) {
|
||||
if (args_size <= 0)
|
||||
break;
|
||||
o(0x58 + fastcall_regs[i]); /* pop r */
|
||||
o(0x58 + fastcall_regs_ptr[i]); /* pop r */
|
||||
/* XXX: incorrect for struct/floats */
|
||||
args_size -= 4;
|
||||
}
|
||||
}
|
||||
gcall_or_jmp(0);
|
||||
if (args_size && func_sym->r != FUNC_STDCALL)
|
||||
if (args_size && func_call != FUNC_STDCALL)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
}
|
||||
@@ -409,17 +418,23 @@ void gfunc_prolog(CType *func_type)
|
||||
{
|
||||
int addr, align, size, func_call, fastcall_nb_regs;
|
||||
int param_index, param_addr;
|
||||
uint8_t *fastcall_regs_ptr;
|
||||
Sym *sym;
|
||||
CType *type;
|
||||
|
||||
sym = func_type->ref;
|
||||
func_call = sym->r;
|
||||
func_call = FUNC_CALL(sym->r);
|
||||
addr = 8;
|
||||
loc = 0;
|
||||
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
fastcall_regs_ptr = fastcall_regs;
|
||||
} else if (func_call == FUNC_FASTCALLW) {
|
||||
fastcall_nb_regs = 2;
|
||||
fastcall_regs_ptr = fastcallw_regs;
|
||||
} else {
|
||||
fastcall_nb_regs = 0;
|
||||
fastcall_regs_ptr = NULL;
|
||||
}
|
||||
param_index = 0;
|
||||
|
||||
@@ -449,14 +464,14 @@ void gfunc_prolog(CType *func_type)
|
||||
/* save FASTCALL register */
|
||||
loc -= 4;
|
||||
o(0x89); /* movl */
|
||||
gen_modrm(fastcall_regs[param_index], VT_LOCAL, NULL, loc);
|
||||
gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
|
||||
param_addr = loc;
|
||||
} else {
|
||||
param_addr = addr;
|
||||
addr += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
VT_LOCAL | lvalue_type(type->t), param_addr);
|
||||
param_index++;
|
||||
}
|
||||
func_ret_sub = 0;
|
||||
@@ -465,7 +480,7 @@ void gfunc_prolog(CType *func_type)
|
||||
func_ret_sub = addr - 8;
|
||||
|
||||
/* leave some room for bound checking code */
|
||||
if (do_bounds_check) {
|
||||
if (tcc_state->do_bounds_check) {
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
@@ -478,7 +493,8 @@ void gfunc_epilog(void)
|
||||
int v, saved_ind;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) {
|
||||
if (tcc_state->do_bounds_check
|
||||
&& func_bound_offset != lbounds_section->data_offset) {
|
||||
int saved_ind;
|
||||
int *bounds_ptr;
|
||||
Sym *sym, *sym_data;
|
||||
@@ -585,7 +601,8 @@ int gtst(int inv, int t)
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
} else {
|
||||
if (is_float(vtop->type.t)) {
|
||||
if (is_float(vtop->type.t) ||
|
||||
(vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
||||
vpushi(0);
|
||||
gen_op(TOK_NE);
|
||||
}
|
||||
|
||||
24
il-gen.c
24
il-gen.c
@@ -3,19 +3,19 @@
|
||||
*
|
||||
* Copyright (c) 2002 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* number of available registers */
|
||||
@@ -449,7 +449,7 @@ void gfunc_prolog(int t)
|
||||
while ((sym = sym->next) != NULL) {
|
||||
u = sym->t;
|
||||
sym_push(sym->v & ~SYM_FIELD, u,
|
||||
VT_LOCAL | VT_LVAL, addr);
|
||||
VT_LOCAL | lvalue_type(sym->type.t), addr);
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
67
include/stdarg.h
Normal file
67
include/stdarg.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include <stdlib.h>
|
||||
|
||||
/* GCC compatible definition of va_list. */
|
||||
struct __va_list_struct {
|
||||
unsigned int gp_offset;
|
||||
unsigned int fp_offset;
|
||||
union {
|
||||
unsigned int overflow_offset;
|
||||
char *overflow_arg_area;
|
||||
};
|
||||
char *reg_save_area;
|
||||
};
|
||||
|
||||
typedef struct __va_list_struct *va_list;
|
||||
|
||||
/* we use __builtin_(malloc|free) to avoid #define malloc tcc_malloc */
|
||||
/* XXX: this lacks the support of aggregated types. */
|
||||
#define va_start(ap, last) \
|
||||
(ap = (va_list)__builtin_malloc(sizeof(struct __va_list_struct)), \
|
||||
*ap = *(struct __va_list_struct*)( \
|
||||
(char*)__builtin_frame_address(0) - 16), \
|
||||
ap->overflow_arg_area = ((char *)__builtin_frame_address(0) + \
|
||||
ap->overflow_offset), \
|
||||
ap->reg_save_area = (char *)__builtin_frame_address(0) - 176 - 16 \
|
||||
)
|
||||
#define va_arg(ap, type) \
|
||||
(*(type*)(__builtin_types_compatible_p(type, long double) \
|
||||
? (ap->overflow_arg_area += 16, \
|
||||
ap->overflow_arg_area - 16) \
|
||||
: __builtin_types_compatible_p(type, double) \
|
||||
? (ap->fp_offset < 128 + 48 \
|
||||
? (ap->fp_offset += 16, \
|
||||
ap->reg_save_area + ap->fp_offset - 16) \
|
||||
: (ap->overflow_arg_area += 8, \
|
||||
ap->overflow_arg_area - 8)) \
|
||||
: (ap->gp_offset < 48 \
|
||||
? (ap->gp_offset += 8, \
|
||||
ap->reg_save_area + ap->gp_offset - 8) \
|
||||
: (ap->overflow_arg_area += 8, \
|
||||
ap->overflow_arg_area - 8)) \
|
||||
))
|
||||
#define va_copy(dest, src) \
|
||||
((dest) = (va_list)malloc(sizeof(struct __va_list_struct)), \
|
||||
*(dest) = *(src))
|
||||
#define va_end(ap) __builtin_free(ap)
|
||||
|
||||
#else
|
||||
|
||||
typedef char *va_list;
|
||||
|
||||
/* only correct for i386 */
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
|
||||
#endif
|
||||
|
||||
/* fix a buggy dependency on GCC in libio.h */
|
||||
typedef va_list __gnuc_va_list;
|
||||
#define _VA_LIST_DEFINED
|
||||
|
||||
#endif /* _STDARG_H */
|
||||
@@ -7,15 +7,14 @@ typedef __WCHAR_TYPE__ wchar_t;
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
|
||||
/* need to do that because of glibc 2.1 bug (should have a way to test
|
||||
presence of 'long long' without __GNUC__, or TCC should define
|
||||
__GNUC__ ? */
|
||||
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
|
||||
#ifndef __int8_t_defined
|
||||
#define __int8_t_defined
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int int64_t;
|
||||
#endif
|
||||
|
||||
void *alloca(size_t size);
|
||||
|
||||
#endif
|
||||
@@ -18,6 +18,7 @@ void *realloc(void *ptr, size_t size);
|
||||
int atoi(const char *nptr);
|
||||
long int strtol(const char *nptr, char **endptr, int base);
|
||||
unsigned long int strtoul(const char *nptr, char **endptr, int base);
|
||||
void exit(int);
|
||||
|
||||
/* stdio.h */
|
||||
typedef struct __FILE FILE;
|
||||
45
lib/alloca86-bt.S
Normal file
45
lib/alloca86-bt.S
Normal file
@@ -0,0 +1,45 @@
|
||||
/* ---------------------------------------------- */
|
||||
/* alloca86b.S */
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
.globl __bound_alloca
|
||||
|
||||
__bound_alloca:
|
||||
pop %edx
|
||||
pop %eax
|
||||
mov %eax, %ecx
|
||||
add $3,%eax
|
||||
and $-4,%eax
|
||||
jz p6
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
p4:
|
||||
cmp $4096,%eax
|
||||
jle p5
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
test %eax,(%esp)
|
||||
jmp p4
|
||||
|
||||
p5:
|
||||
#endif
|
||||
|
||||
sub %eax,%esp
|
||||
mov %esp,%eax
|
||||
|
||||
push %edx
|
||||
push %eax
|
||||
push %ecx
|
||||
push %eax
|
||||
call __bound_new_region
|
||||
add $8, %esp
|
||||
pop %eax
|
||||
pop %edx
|
||||
|
||||
p6:
|
||||
push %edx
|
||||
push %edx
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
33
lib/alloca86.S
Normal file
33
lib/alloca86.S
Normal file
@@ -0,0 +1,33 @@
|
||||
/* ---------------------------------------------- */
|
||||
/* alloca86.S */
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
.globl alloca
|
||||
|
||||
alloca:
|
||||
pop %edx
|
||||
pop %eax
|
||||
add $3,%eax
|
||||
and $-4,%eax
|
||||
jz p3
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
p1:
|
||||
cmp $4096,%eax
|
||||
jle p2
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
test %eax,(%esp)
|
||||
jmp p1
|
||||
p2:
|
||||
#endif
|
||||
|
||||
sub %eax,%esp
|
||||
mov %esp,%eax
|
||||
p3:
|
||||
push %edx
|
||||
push %edx
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
@@ -3,25 +3,25 @@
|
||||
*
|
||||
* Copyright (c) 2002 Fabrice Bellard
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#ifndef __FreeBSD__
|
||||
#if !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
|
||||
#define HAVE_MEMALIGN
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__dietlibc__)
|
||||
#warning Bound checking not fully supported on FreeBSD
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__)
|
||||
#warning Bound checking not fully supported in this environment.
|
||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||
#undef HAVE_MEMALIGN
|
||||
#endif
|
||||
@@ -89,13 +89,13 @@ union double_long {
|
||||
double d;
|
||||
#if 1
|
||||
struct {
|
||||
unsigned long lower;
|
||||
long upper;
|
||||
unsigned int lower;
|
||||
int upper;
|
||||
} l;
|
||||
#else
|
||||
struct {
|
||||
long upper;
|
||||
unsigned long lower;
|
||||
int upper;
|
||||
unsigned int lower;
|
||||
} l;
|
||||
#endif
|
||||
long long ll;
|
||||
@@ -106,6 +106,9 @@ union float_long {
|
||||
long l;
|
||||
};
|
||||
|
||||
/* XXX: we don't support several builtin supports for now */
|
||||
#ifndef __x86_64__
|
||||
|
||||
/* XXX: use gcc/tcc intrinsic ? */
|
||||
#if defined(__i386__)
|
||||
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
|
||||
@@ -399,7 +402,7 @@ long long __moddi3(long long u, long long v)
|
||||
if (vv.s.high < 0)
|
||||
vv.ll = __negdi2 (vv.ll);
|
||||
|
||||
__udivmoddi4 (uu.ll, vv.ll, &w);
|
||||
__udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
|
||||
if (c)
|
||||
w = __negdi2 (w);
|
||||
return w;
|
||||
@@ -419,7 +422,7 @@ unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
|
||||
}
|
||||
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
long long __sardi3(long long a, int b)
|
||||
long long __ashrdi3(long long a, int b)
|
||||
{
|
||||
#ifdef __TINYC__
|
||||
DWunion u;
|
||||
@@ -438,7 +441,7 @@ long long __sardi3(long long a, int b)
|
||||
}
|
||||
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
unsigned long long __shrdi3(unsigned long long a, int b)
|
||||
unsigned long long __lshrdi3(unsigned long long a, int b)
|
||||
{
|
||||
#ifdef __TINYC__
|
||||
DWunion u;
|
||||
@@ -457,7 +460,7 @@ unsigned long long __shrdi3(unsigned long long a, int b)
|
||||
}
|
||||
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
long long __shldi3(long long a, int b)
|
||||
long long __ashldi3(long long a, int b)
|
||||
{
|
||||
#ifdef __TINYC__
|
||||
DWunion u;
|
||||
@@ -466,7 +469,7 @@ long long __shldi3(long long a, int b)
|
||||
u.s.high = (unsigned)u.s.low << (b - 32);
|
||||
u.s.low = 0;
|
||||
} else if (b != 0) {
|
||||
u.s.high = ((unsigned)u.s.high << b) | (u.s.low >> (32 - b));
|
||||
u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
|
||||
u.s.low = (unsigned)u.s.low << b;
|
||||
}
|
||||
return u.ll;
|
||||
@@ -482,8 +485,10 @@ unsigned short __tcc_fpu_control = 0x137f;
|
||||
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
|
||||
#endif
|
||||
|
||||
#endif /* !__x86_64__ */
|
||||
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
float __ulltof(unsigned long long a)
|
||||
float __floatundisf(unsigned long long a)
|
||||
{
|
||||
DWunion uu;
|
||||
XFtype r;
|
||||
@@ -498,7 +503,7 @@ float __ulltof(unsigned long long a)
|
||||
}
|
||||
}
|
||||
|
||||
double __ulltod(unsigned long long a)
|
||||
double __floatundidf(unsigned long long a)
|
||||
{
|
||||
DWunion uu;
|
||||
XFtype r;
|
||||
@@ -513,7 +518,7 @@ double __ulltod(unsigned long long a)
|
||||
}
|
||||
}
|
||||
|
||||
long double __ulltold(unsigned long long a)
|
||||
long double __floatundixf(unsigned long long a)
|
||||
{
|
||||
DWunion uu;
|
||||
XFtype r;
|
||||
55
libtcc.h
55
libtcc.h
@@ -1,6 +1,12 @@
|
||||
#ifndef LIBTCC_H
|
||||
#define LIBTCC_H
|
||||
|
||||
#ifdef LIBTCC_AS_DLL
|
||||
#define LIBTCCAPI __declspec(dllexport)
|
||||
#else
|
||||
#define LIBTCCAPI
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -10,46 +16,46 @@ struct TCCState;
|
||||
typedef struct TCCState TCCState;
|
||||
|
||||
/* create a new TCC compilation context */
|
||||
TCCState *tcc_new(void);
|
||||
LIBTCCAPI TCCState *tcc_new(void);
|
||||
|
||||
/* free a TCC compilation context */
|
||||
void tcc_delete(TCCState *s);
|
||||
LIBTCCAPI void tcc_delete(TCCState *s);
|
||||
|
||||
/* add debug information in the generated code */
|
||||
void tcc_enable_debug(TCCState *s);
|
||||
LIBTCCAPI void tcc_enable_debug(TCCState *s);
|
||||
|
||||
/* set error/warning display callback */
|
||||
void tcc_set_error_func(TCCState *s, void *error_opaque,
|
||||
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
|
||||
void (*error_func)(void *opaque, const char *msg));
|
||||
|
||||
/* set/reset a warning */
|
||||
int tcc_set_warning(TCCState *s, const char *warning_name, int value);
|
||||
LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value);
|
||||
|
||||
/*****************************/
|
||||
/* preprocessor */
|
||||
|
||||
/* add include path */
|
||||
int tcc_add_include_path(TCCState *s, const char *pathname);
|
||||
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
|
||||
|
||||
/* add in system include path */
|
||||
int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
|
||||
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
|
||||
|
||||
/* define preprocessor symbol 'sym'. Can put optional value */
|
||||
void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
|
||||
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
|
||||
|
||||
/* undefine preprocess symbol 'sym' */
|
||||
void tcc_undefine_symbol(TCCState *s, const char *sym);
|
||||
LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
|
||||
|
||||
/*****************************/
|
||||
/* compiling */
|
||||
|
||||
/* add a file (either a C file, dll, an object, a library or an ld
|
||||
script). Return -1 if error. */
|
||||
int tcc_add_file(TCCState *s, const char *filename);
|
||||
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
|
||||
|
||||
/* compile a string containing a C source. Return non zero if
|
||||
error. */
|
||||
int tcc_compile_string(TCCState *s, const char *buf);
|
||||
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
|
||||
|
||||
/*****************************/
|
||||
/* linking commands */
|
||||
@@ -60,35 +66,40 @@ int tcc_compile_string(TCCState *s, const char *buf);
|
||||
#define TCC_OUTPUT_EXE 1 /* executable file */
|
||||
#define TCC_OUTPUT_DLL 2 /* dynamic library */
|
||||
#define TCC_OUTPUT_OBJ 3 /* object file */
|
||||
int tcc_set_output_type(TCCState *s, int output_type);
|
||||
#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */
|
||||
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
|
||||
|
||||
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */
|
||||
#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
|
||||
#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */
|
||||
|
||||
/* equivalent to -Lpath option */
|
||||
int tcc_add_library_path(TCCState *s, const char *pathname);
|
||||
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
|
||||
|
||||
/* the library name is the same as the argument of the '-l' option */
|
||||
int tcc_add_library(TCCState *s, const char *libraryname);
|
||||
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
|
||||
|
||||
/* add a symbol to the compiled program */
|
||||
int tcc_add_symbol(TCCState *s, const char *name, unsigned long val);
|
||||
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, void *val);
|
||||
|
||||
/* output an executable, library or object file. DO NOT call
|
||||
tcc_relocate() before. */
|
||||
int tcc_output_file(TCCState *s, const char *filename);
|
||||
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
|
||||
|
||||
/* link and run main() function and return its value. DO NOT call
|
||||
tcc_relocate() before. */
|
||||
int tcc_run(TCCState *s, int argc, char **argv);
|
||||
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
|
||||
|
||||
/* do all relocations (needed before using tcc_get_symbol()). Return
|
||||
non zero if link error. */
|
||||
int tcc_relocate(TCCState *s);
|
||||
/* copy code into memory passed in by the caller and do all relocations
|
||||
(needed before using tcc_get_symbol()).
|
||||
returns -1 on error and required size if ptr is NULL */
|
||||
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
|
||||
|
||||
/* return symbol value. return 0 if OK, -1 if symbol not found */
|
||||
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
|
||||
/* return symbol value or NULL if not found */
|
||||
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
|
||||
|
||||
/* set CONFIG_TCCDIR at runtime */
|
||||
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
15
stdarg.h
15
stdarg.h
@@ -1,15 +0,0 @@
|
||||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
typedef char *va_list;
|
||||
|
||||
/* only correct for i386 */
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#define va_end(ap)
|
||||
|
||||
/* fix a buggy dependency on GCC in libio.h */
|
||||
typedef va_list __gnuc_va_list;
|
||||
#define _VA_LIST_DEFINED
|
||||
|
||||
#endif
|
||||
67
tcc-doc.texi
67
tcc-doc.texi
@@ -16,11 +16,8 @@
|
||||
@headings double
|
||||
@end iftex
|
||||
|
||||
@c @ifhtml
|
||||
@contents
|
||||
@c @end ifhtml
|
||||
|
||||
@ifnothtml
|
||||
@node Top, Introduction, (dir), (dir)
|
||||
@top Tiny C Compiler Reference Documentation
|
||||
|
||||
@@ -29,10 +26,14 @@ This manual documents version @value{VERSION} of the Tiny C Compiler.
|
||||
@menu
|
||||
* Introduction:: Introduction to tcc.
|
||||
* Invoke:: Invocation of tcc (command line, options).
|
||||
* Clang:: ANSI C and extensions.
|
||||
* asm:: Assembler syntax.
|
||||
* linker:: Output file generation and supported targets.
|
||||
* Bounds:: Automatic bounds-checking of C code.
|
||||
* Libtcc:: The libtcc library.
|
||||
* devel:: Guide for Developers.
|
||||
@end menu
|
||||
@end ifnothtml
|
||||
|
||||
|
||||
@node Introduction
|
||||
@chapter Introduction
|
||||
@@ -42,7 +43,7 @@ compilers, it is meant to be self-relying: you do not need an
|
||||
external assembler or linker because TCC does that for you.
|
||||
|
||||
TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may
|
||||
not be necessary.
|
||||
not be necessary.
|
||||
|
||||
TCC not only supports ANSI C, but also most of the new ISO C99
|
||||
standard and many GNUC extensions including inline assembly.
|
||||
@@ -63,11 +64,11 @@ ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets
|
||||
(@code{c67-tcc}). More information about the ARM port is available at
|
||||
@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}.
|
||||
|
||||
For usage on Windows, see also tcc-win32.txt.
|
||||
|
||||
@node Invoke
|
||||
@chapter Command line invocation
|
||||
|
||||
[This manual documents version @value{VERSION} of the Tiny C Compiler]
|
||||
|
||||
@section Quick start
|
||||
|
||||
@example
|
||||
@@ -94,9 +95,11 @@ the @code{main()} of a.c.
|
||||
|
||||
@item @samp{tcc a.c -run b.c arg1}
|
||||
Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given
|
||||
as first argument to the @code{main()} of the resulting program. Because
|
||||
multiple C files are specified, @option{--} are necessary to clearly separate the
|
||||
program arguments from the TCC options.
|
||||
as first argument to the @code{main()} of the resulting program.
|
||||
@ignore
|
||||
Because multiple C files are specified, @option{--} are necessary to clearly
|
||||
separate the program arguments from the TCC options.
|
||||
@end ignore
|
||||
|
||||
@item @samp{tcc -o myprog a.c b.c}
|
||||
Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}.
|
||||
@@ -135,6 +138,13 @@ int main()
|
||||
return 0;
|
||||
@}
|
||||
@end example
|
||||
|
||||
TCC can read C source code from @emph{standard input} when @option{-} is used in
|
||||
place of @option{infile}. Example:
|
||||
|
||||
@example
|
||||
echo 'main()@{puts("hello");@}' | tcc -run -
|
||||
@end example
|
||||
@c man end
|
||||
|
||||
@section Option summary
|
||||
@@ -144,7 +154,7 @@ General Options:
|
||||
@c man begin OPTIONS
|
||||
@table @option
|
||||
@item -v
|
||||
Display current TCC version.
|
||||
Display current TCC version, increase verbosity.
|
||||
|
||||
@item -c
|
||||
Generate an object file (@option{-o} option must also be given).
|
||||
@@ -160,7 +170,6 @@ Set the path where the tcc internal libraries can be found (default is
|
||||
Output compilation statistics.
|
||||
|
||||
@item -run source [args...]
|
||||
|
||||
Compile file @var{source} and run it with the command line arguments
|
||||
@var{args}. In order to be able to give more than one argument to a
|
||||
script, several TCC options can be given @emph{after} the
|
||||
@@ -338,6 +347,7 @@ Fabrice Bellard
|
||||
|
||||
@end ignore
|
||||
|
||||
@node Clang
|
||||
@chapter C language support
|
||||
|
||||
@section ANSI C
|
||||
@@ -406,13 +416,6 @@ is the same as writing
|
||||
@end itemize
|
||||
|
||||
@section GNU C extensions
|
||||
@cindex aligned attribute
|
||||
@cindex packed attribute
|
||||
@cindex section attribute
|
||||
@cindex unused attribute
|
||||
@cindex cdecl attribute
|
||||
@cindex stdcall attribute
|
||||
@cindex regparm attribute
|
||||
|
||||
TCC implements some GNU C extensions:
|
||||
|
||||
@@ -446,13 +449,22 @@ instead of
|
||||
@}
|
||||
@end example
|
||||
|
||||
@cindex aligned attribute
|
||||
@cindex packed attribute
|
||||
@cindex section attribute
|
||||
@cindex unused attribute
|
||||
@cindex cdecl attribute
|
||||
@cindex stdcall attribute
|
||||
@cindex regparm attribute
|
||||
@cindex dllexport attribute
|
||||
|
||||
@item The keyword @code{__attribute__} is handled to specify variable or
|
||||
function attributes. The following attributes are supported:
|
||||
@itemize
|
||||
|
||||
@item @code{aligned(n)}: align a variable or a structure field to n bytes
|
||||
(must be a power of two).
|
||||
|
||||
|
||||
@item @code{packed}: force alignment of a variable or a structure field to
|
||||
1.
|
||||
|
||||
@@ -470,6 +482,8 @@ section.
|
||||
between 1 and 3. The first @var{n} function parameters are respectively put in
|
||||
registers @code{%eax}, @code{%edx} and @code{%ecx}.
|
||||
|
||||
@item @code{dllexport}: export function from dll/executable (win32 only)
|
||||
|
||||
@end itemize
|
||||
|
||||
Here are some examples:
|
||||
@@ -565,6 +579,7 @@ indicate that you use TCC.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node asm
|
||||
@chapter TinyCC Assembler
|
||||
|
||||
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
|
||||
@@ -694,6 +709,7 @@ tries to guess it from the operand sizes.
|
||||
|
||||
Currently, MMX opcodes are supported but not SSE ones.
|
||||
|
||||
@node linker
|
||||
@chapter TinyCC Linker
|
||||
@cindex linker
|
||||
|
||||
@@ -721,14 +737,10 @@ libraries (.so).
|
||||
@section PE-i386 file generation
|
||||
@cindex PE-i386
|
||||
|
||||
TCC for Windows supports the native Win32 executable file format (PE-i386). It
|
||||
generates both EXE and DLL files. DLL symbols can be imported thru DEF files
|
||||
generated with the @code{tiny_impdef} tool.
|
||||
TCC for Windows supports the native Win32 executable file format (PE-i386). It
|
||||
generates EXE files (console and gui) and DLL files.
|
||||
|
||||
Currently TCC for Windows cannot generate nor read PE object files, so ELF
|
||||
object files are used for that purpose. It can be a problem if
|
||||
interoperability with MSVC is needed. Moreover, no leading underscore is
|
||||
currently generated in the ELF symbols.
|
||||
For usage on Windows, see also tcc-win32.txt.
|
||||
|
||||
@section GNU Linker Scripts
|
||||
@cindex scripts, linker
|
||||
@@ -839,6 +851,7 @@ The idea consists in giving a C string containing the program you want
|
||||
to compile directly to @code{libtcc}. Then you can access to any global
|
||||
symbol (function or variable) defined.
|
||||
|
||||
@node devel
|
||||
@chapter Developer's guide
|
||||
|
||||
This chapter gives some hints to understand how TCC works. You can skip
|
||||
|
||||
766
tcc.h
Normal file
766
tcc.h
Normal file
@@ -0,0 +1,766 @@
|
||||
/*
|
||||
* TCC - Tiny C Compiler
|
||||
*
|
||||
* Copyright (c) 2001-2004 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "config.h"
|
||||
|
||||
#ifdef CONFIG_TCCBOOT
|
||||
|
||||
#include "tccboot.h"
|
||||
#define CONFIG_TCC_STATIC
|
||||
|
||||
#else
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <setjmp.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <io.h> /* open, close etc. */
|
||||
#include <direct.h> /* getcwd */
|
||||
#define inline __inline
|
||||
#define inp next_inp
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#endif /* !CONFIG_TCCBOOT */
|
||||
|
||||
#ifndef PAGESIZE
|
||||
#define PAGESIZE 4096
|
||||
#endif
|
||||
|
||||
#include "elf.h"
|
||||
#include "stab.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#include "libtcc.h"
|
||||
|
||||
/* parser debug */
|
||||
//#define PARSE_DEBUG
|
||||
/* preprocessor debug */
|
||||
//#define PP_DEBUG
|
||||
/* include file debug */
|
||||
//#define INC_DEBUG
|
||||
|
||||
//#define MEM_DEBUG
|
||||
|
||||
/* assembler debug */
|
||||
//#define ASM_DEBUG
|
||||
|
||||
/* target selection */
|
||||
//#define TCC_TARGET_I386 /* i386 code generator */
|
||||
//#define TCC_TARGET_ARM /* ARMv4 code generator */
|
||||
//#define TCC_TARGET_C67 /* TMS320C67xx code generator */
|
||||
//#define TCC_TARGET_X86_64 /* x86-64 code generator */
|
||||
|
||||
/* default target is I386 */
|
||||
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
|
||||
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
|
||||
#define TCC_TARGET_I386
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
|
||||
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
|
||||
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(TCC_TARGET_PE)
|
||||
#define CONFIG_TCC_STATIC
|
||||
#endif
|
||||
|
||||
/* define it to include assembler support */
|
||||
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) && \
|
||||
!defined(TCC_TARGET_X86_64)
|
||||
#define CONFIG_TCC_ASM
|
||||
#endif
|
||||
|
||||
/* object format selection */
|
||||
#if defined(TCC_TARGET_C67)
|
||||
#define TCC_TARGET_COFF
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
|
||||
#define CONFIG_TCC_BACKTRACE
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define false 0
|
||||
#define TRUE 1
|
||||
#define true 1
|
||||
typedef int BOOL;
|
||||
|
||||
/* path to find crt1.o, crti.o and crtn.o. Only needed when generating
|
||||
executables or dlls */
|
||||
#define CONFIG_TCC_CRT_PREFIX CONFIG_SYSROOT "/usr/lib"
|
||||
|
||||
#define INCLUDE_STACK_SIZE 32
|
||||
#define IFDEF_STACK_SIZE 64
|
||||
#define VSTACK_SIZE 256
|
||||
#define STRING_MAX_SIZE 1024
|
||||
#define PACK_STACK_SIZE 8
|
||||
|
||||
#define TOK_HASH_SIZE 8192 /* must be a power of two */
|
||||
#define TOK_ALLOC_INCR 512 /* must be a power of two */
|
||||
#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */
|
||||
|
||||
/* token symbol management */
|
||||
typedef struct TokenSym {
|
||||
struct TokenSym *hash_next;
|
||||
struct Sym *sym_define; /* direct pointer to define */
|
||||
struct Sym *sym_label; /* direct pointer to label */
|
||||
struct Sym *sym_struct; /* direct pointer to structure */
|
||||
struct Sym *sym_identifier; /* direct pointer to identifier */
|
||||
int tok; /* token number */
|
||||
int len;
|
||||
char str[1];
|
||||
} TokenSym;
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
typedef unsigned short nwchar_t;
|
||||
#else
|
||||
typedef int nwchar_t;
|
||||
#endif
|
||||
|
||||
typedef struct CString {
|
||||
int size; /* size in bytes */
|
||||
void *data; /* either 'char *' or 'nwchar_t *' */
|
||||
int size_allocated;
|
||||
void *data_allocated; /* if non NULL, data has been malloced */
|
||||
} CString;
|
||||
|
||||
/* type definition */
|
||||
typedef struct CType {
|
||||
int t;
|
||||
struct Sym *ref;
|
||||
} CType;
|
||||
|
||||
/* constant value */
|
||||
typedef union CValue {
|
||||
long double ld;
|
||||
double d;
|
||||
float f;
|
||||
int i;
|
||||
unsigned int ui;
|
||||
unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */
|
||||
long long ll;
|
||||
unsigned long long ull;
|
||||
struct CString *cstr;
|
||||
void *ptr;
|
||||
int tab[1];
|
||||
} CValue;
|
||||
|
||||
/* value on stack */
|
||||
typedef struct SValue {
|
||||
CType type; /* type */
|
||||
unsigned short r; /* register + flags */
|
||||
unsigned short r2; /* second register, used for 'long long'
|
||||
type. If not used, set to VT_CONST */
|
||||
CValue c; /* constant, if VT_CONST */
|
||||
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */
|
||||
} SValue;
|
||||
|
||||
/* symbol management */
|
||||
typedef struct Sym {
|
||||
int v; /* symbol token */
|
||||
long r; /* associated register */
|
||||
long c; /* associated number */
|
||||
CType type; /* associated type */
|
||||
struct Sym *next; /* next related symbol */
|
||||
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 */
|
||||
unsigned long data_allocated; /* used for realloc() handling */
|
||||
int sh_name; /* elf section name (only used during output) */
|
||||
int sh_num; /* elf section number */
|
||||
int sh_type; /* elf section type */
|
||||
int sh_flags; /* elf section flags */
|
||||
int sh_info; /* elf section info */
|
||||
int sh_addralign; /* elf section alignment */
|
||||
int sh_entsize; /* elf entry size */
|
||||
unsigned long sh_size; /* section size (only used during output) */
|
||||
unsigned long sh_addr; /* address at which the section is relocated */
|
||||
unsigned long sh_offset; /* file offset */
|
||||
int nb_hashed_syms; /* used to resize the hash table */
|
||||
struct Section *link; /* link to another section */
|
||||
struct Section *reloc; /* corresponding section for relocation, if any */
|
||||
struct Section *hash; /* hash table for symbols */
|
||||
struct Section *next;
|
||||
char name[1]; /* section name */
|
||||
} Section;
|
||||
|
||||
typedef struct DLLReference {
|
||||
int level;
|
||||
void *handle;
|
||||
char name[1];
|
||||
} DLLReference;
|
||||
|
||||
/* GNUC attribute definition */
|
||||
typedef struct AttributeDef {
|
||||
int aligned;
|
||||
int packed;
|
||||
Section *section;
|
||||
int func_attr; /* calling convention, exports, ... */
|
||||
} AttributeDef;
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
/* gr: wrappers for casting sym->r for other purposes */
|
||||
typedef struct {
|
||||
unsigned
|
||||
func_call : 8,
|
||||
func_args : 8,
|
||||
func_export : 1;
|
||||
} func_attr_t;
|
||||
|
||||
#define FUNC_CALL(r) (((func_attr_t*)&(r))->func_call)
|
||||
#define FUNC_EXPORT(r) (((func_attr_t*)&(r))->func_export)
|
||||
#define FUNC_ARGS(r) (((func_attr_t*)&(r))->func_args)
|
||||
#define INLINE_DEF(r) (*(int **)&(r))
|
||||
/* -------------------------------------------------- */
|
||||
|
||||
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
|
||||
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
|
||||
#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
|
||||
|
||||
/* stored in 'Sym.c' 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 */
|
||||
#define FUNC_CDECL 0 /* standard c call */
|
||||
#define FUNC_STDCALL 1 /* pascal c call */
|
||||
#define FUNC_FASTCALL1 2 /* first param in %eax */
|
||||
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
|
||||
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
|
||||
#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */
|
||||
|
||||
/* field 'Sym.t' for macros */
|
||||
#define MACRO_OBJ 0 /* object like macro */
|
||||
#define MACRO_FUNC 1 /* function like macro */
|
||||
|
||||
/* field 'Sym.r' for C labels */
|
||||
#define LABEL_DEFINED 0 /* label is defined */
|
||||
#define LABEL_FORWARD 1 /* label is forward defined */
|
||||
#define LABEL_DECLARED 2 /* label is declared but never used */
|
||||
|
||||
/* type_decl() types */
|
||||
#define TYPE_ABSTRACT 1 /* type without variable */
|
||||
#define TYPE_DIRECT 2 /* type with variable */
|
||||
|
||||
#define IO_BUF_SIZE 8192
|
||||
|
||||
typedef struct BufferedFile {
|
||||
uint8_t *buf_ptr;
|
||||
uint8_t *buf_end;
|
||||
int fd;
|
||||
int line_num; /* current line number - here to simplify code */
|
||||
int ifndef_macro; /* #ifndef macro / #endif search */
|
||||
int ifndef_macro_saved; /* saved ifndef_macro */
|
||||
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
|
||||
char inc_type; /* type of include */
|
||||
char inc_filename[512]; /* filename specified by the user */
|
||||
char filename[1024]; /* current filename - here to simplify code */
|
||||
unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */
|
||||
} 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 {
|
||||
int *macro_ptr;
|
||||
int line_num;
|
||||
int tok;
|
||||
CValue tokc;
|
||||
} ParseState;
|
||||
|
||||
/* used to record tokens */
|
||||
typedef struct TokenString {
|
||||
int *str;
|
||||
int len;
|
||||
int allocated_len;
|
||||
int last_line_num;
|
||||
} TokenString;
|
||||
|
||||
/* include file cache, used to find files faster and also to eliminate
|
||||
inclusion if the include file is protected by #ifndef ... #endif */
|
||||
typedef struct CachedInclude {
|
||||
int ifndef_macro;
|
||||
int hash_next; /* -1 if none */
|
||||
char type; /* '"' or '>' to give include type */
|
||||
char filename[1]; /* path specified in #include */
|
||||
} CachedInclude;
|
||||
|
||||
#define CACHED_INCLUDES_HASH_SIZE 512
|
||||
|
||||
#ifdef CONFIG_TCC_ASM
|
||||
typedef struct ExprValue {
|
||||
uint32_t v;
|
||||
Sym *sym;
|
||||
} ExprValue;
|
||||
|
||||
#define MAX_ASM_OPERANDS 30
|
||||
typedef struct ASMOperand {
|
||||
int id; /* GCC 3 optionnal identifier (0 if number only supported */
|
||||
char *constraint;
|
||||
char asm_str[16]; /* computed asm string for operand */
|
||||
SValue *vt; /* C value of the expression */
|
||||
int ref_index; /* if >= 0, gives reference to a output constraint */
|
||||
int input_index; /* if >= 0, gives reference to an input constraint */
|
||||
int priority; /* priority, used to assign registers */
|
||||
int reg; /* if >= 0, register number used for this operand */
|
||||
int is_llong; /* true if double register value */
|
||||
int is_memory; /* true if memory operand */
|
||||
int is_rw; /* for '+' modifier */
|
||||
} ASMOperand;
|
||||
|
||||
#endif
|
||||
|
||||
struct TCCState {
|
||||
int output_type;
|
||||
|
||||
BufferedFile **include_stack_ptr;
|
||||
int *ifdef_stack_ptr;
|
||||
|
||||
/* include file handling */
|
||||
char **include_paths;
|
||||
int nb_include_paths;
|
||||
char **sysinclude_paths;
|
||||
int nb_sysinclude_paths;
|
||||
CachedInclude **cached_includes;
|
||||
int nb_cached_includes;
|
||||
|
||||
char **library_paths;
|
||||
int nb_library_paths;
|
||||
|
||||
/* array of all loaded dlls (including those referenced by loaded
|
||||
dlls) */
|
||||
DLLReference **loaded_dlls;
|
||||
int nb_loaded_dlls;
|
||||
|
||||
/* sections */
|
||||
Section **sections;
|
||||
int nb_sections; /* number of sections, including first dummy section */
|
||||
|
||||
Section **priv_sections;
|
||||
int nb_priv_sections; /* number of private sections */
|
||||
|
||||
/* got handling */
|
||||
Section *got;
|
||||
Section *plt;
|
||||
unsigned long *got_offsets;
|
||||
int nb_got_offsets;
|
||||
/* give the correspondance from symtab indexes to dynsym indexes */
|
||||
int *symtab_to_dynsym;
|
||||
|
||||
/* temporary dynamic symbol sections (for dll loading) */
|
||||
Section *dynsymtab_section;
|
||||
/* exported dynamic symbol section */
|
||||
Section *dynsym;
|
||||
|
||||
int nostdinc; /* if true, no standard headers are added */
|
||||
int nostdlib; /* if true, no standard libraries are added */
|
||||
int nocommon; /* if true, do not use common symbols for .bss data */
|
||||
|
||||
/* if true, static linking is performed */
|
||||
int static_link;
|
||||
|
||||
/* soname as specified on the command line (-soname) */
|
||||
const char *soname;
|
||||
|
||||
/* if true, all symbols are exported */
|
||||
int rdynamic;
|
||||
|
||||
/* if true, only link in referenced objects from archive */
|
||||
int alacarte_link;
|
||||
|
||||
/* address of text section */
|
||||
unsigned long text_addr;
|
||||
int has_text_addr;
|
||||
|
||||
/* output format, see TCC_OUTPUT_FORMAT_xxx */
|
||||
int output_format;
|
||||
|
||||
/* C language options */
|
||||
int char_is_unsigned;
|
||||
int leading_underscore;
|
||||
|
||||
/* warning switches */
|
||||
int warn_write_strings;
|
||||
int warn_unsupported;
|
||||
int warn_error;
|
||||
int warn_none;
|
||||
int warn_implicit_function_declaration;
|
||||
|
||||
/* display some information during compilation */
|
||||
int verbose;
|
||||
/* compile with debug symbol (and use them if error during execution) */
|
||||
int do_debug;
|
||||
/* compile with built-in memory and bounds checker */
|
||||
int do_bounds_check;
|
||||
/* give the path of the tcc libraries */
|
||||
const char *tcc_lib_path;
|
||||
|
||||
/* error handling */
|
||||
void *error_opaque;
|
||||
void (*error_func)(void *opaque, const char *msg);
|
||||
int error_set_jmp_enabled;
|
||||
jmp_buf error_jmp_buf;
|
||||
int nb_errors;
|
||||
|
||||
/* tiny assembler state */
|
||||
Sym *asm_labels;
|
||||
|
||||
/* see include_stack_ptr */
|
||||
BufferedFile *include_stack[INCLUDE_STACK_SIZE];
|
||||
|
||||
/* see ifdef_stack_ptr */
|
||||
int ifdef_stack[IFDEF_STACK_SIZE];
|
||||
|
||||
/* see cached_includes */
|
||||
int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE];
|
||||
|
||||
/* pack stack */
|
||||
int pack_stack[PACK_STACK_SIZE];
|
||||
int *pack_stack_ptr;
|
||||
|
||||
/* output file for preprocessing */
|
||||
FILE *outfile;
|
||||
|
||||
/* for tcc_relocate */
|
||||
int runtime_added;
|
||||
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
/* write PLT and GOT here */
|
||||
char *runtime_plt_and_got;
|
||||
unsigned int runtime_plt_and_got_offset;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The current value can be: */
|
||||
#define VT_VALMASK 0x00ff
|
||||
#define VT_CONST 0x00f0 /* constant in vc
|
||||
(must be first non register value) */
|
||||
#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */
|
||||
#define VT_LOCAL 0x00f2 /* offset on stack */
|
||||
#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */
|
||||
#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */
|
||||
#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */
|
||||
#define VT_LVAL 0x0100 /* var is an lvalue */
|
||||
#define VT_SYM 0x0200 /* a symbol value is added */
|
||||
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
|
||||
char/short stored in integer registers) */
|
||||
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
|
||||
dereferencing value */
|
||||
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
|
||||
bounding function call point is in vc */
|
||||
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
|
||||
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
|
||||
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
|
||||
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
|
||||
|
||||
/* types */
|
||||
#define VT_INT 0 /* integer type */
|
||||
#define VT_BYTE 1 /* signed byte type */
|
||||
#define VT_SHORT 2 /* short type */
|
||||
#define VT_VOID 3 /* void type */
|
||||
#define VT_PTR 4 /* pointer */
|
||||
#define VT_ENUM 5 /* enum definition */
|
||||
#define VT_FUNC 6 /* function type */
|
||||
#define VT_STRUCT 7 /* struct/union definition */
|
||||
#define VT_FLOAT 8 /* IEEE float */
|
||||
#define VT_DOUBLE 9 /* IEEE double */
|
||||
#define VT_LDOUBLE 10 /* IEEE long double */
|
||||
#define VT_BOOL 11 /* ISOC99 boolean type */
|
||||
#define VT_LLONG 12 /* 64 bit integer */
|
||||
#define VT_LONG 13 /* long integer (NEVER USED as type, only
|
||||
during parsing) */
|
||||
#define VT_BTYPE 0x000f /* mask for basic type */
|
||||
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
||||
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
|
||||
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
||||
#define VT_CONSTANT 0x0800 /* const modifier */
|
||||
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
||||
#define VT_SIGNED 0x2000 /* signed type */
|
||||
|
||||
/* 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_STRUCT_SHIFT 16 /* shift for bitfield shift values */
|
||||
|
||||
/* type mask (except storage) */
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
||||
#define VT_TYPE (~(VT_STORAGE))
|
||||
|
||||
/* token values */
|
||||
|
||||
/* warning: the following compare tokens depend on i386 asm code */
|
||||
#define TOK_ULT 0x92
|
||||
#define TOK_UGE 0x93
|
||||
#define TOK_EQ 0x94
|
||||
#define TOK_NE 0x95
|
||||
#define TOK_ULE 0x96
|
||||
#define TOK_UGT 0x97
|
||||
#define TOK_Nset 0x98
|
||||
#define TOK_Nclear 0x99
|
||||
#define TOK_LT 0x9c
|
||||
#define TOK_GE 0x9d
|
||||
#define TOK_LE 0x9e
|
||||
#define TOK_GT 0x9f
|
||||
|
||||
#define TOK_LAND 0xa0
|
||||
#define TOK_LOR 0xa1
|
||||
|
||||
#define TOK_DEC 0xa2
|
||||
#define TOK_MID 0xa3 /* inc/dec, to void constant */
|
||||
#define TOK_INC 0xa4
|
||||
#define TOK_UDIV 0xb0 /* unsigned division */
|
||||
#define TOK_UMOD 0xb1 /* unsigned modulo */
|
||||
#define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
|
||||
#define TOK_CINT 0xb3 /* number in tokc */
|
||||
#define TOK_CCHAR 0xb4 /* char constant in tokc */
|
||||
#define TOK_STR 0xb5 /* pointer to string in tokc */
|
||||
#define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
|
||||
#define TOK_LCHAR 0xb7
|
||||
#define TOK_LSTR 0xb8
|
||||
#define TOK_CFLOAT 0xb9 /* float constant */
|
||||
#define TOK_LINENUM 0xba /* line number info */
|
||||
#define TOK_CDOUBLE 0xc0 /* double constant */
|
||||
#define TOK_CLDOUBLE 0xc1 /* long double constant */
|
||||
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
|
||||
#define TOK_ADDC1 0xc3 /* add with carry generation */
|
||||
#define TOK_ADDC2 0xc4 /* add with carry use */
|
||||
#define TOK_SUBC1 0xc5 /* add with carry generation */
|
||||
#define TOK_SUBC2 0xc6 /* add with carry use */
|
||||
#define TOK_CUINT 0xc8 /* unsigned int constant */
|
||||
#define TOK_CLLONG 0xc9 /* long long constant */
|
||||
#define TOK_CULLONG 0xca /* unsigned long long constant */
|
||||
#define TOK_ARROW 0xcb
|
||||
#define TOK_DOTS 0xcc /* three dots */
|
||||
#define TOK_SHR 0xcd /* unsigned shift right */
|
||||
#define TOK_PPNUM 0xce /* preprocessor number */
|
||||
|
||||
#define TOK_SHL 0x01 /* shift left */
|
||||
#define TOK_SAR 0x02 /* signed shift right */
|
||||
|
||||
/* assignement operators : normal operator or 0x80 */
|
||||
#define TOK_A_MOD 0xa5
|
||||
#define TOK_A_AND 0xa6
|
||||
#define TOK_A_MUL 0xaa
|
||||
#define TOK_A_ADD 0xab
|
||||
#define TOK_A_SUB 0xad
|
||||
#define TOK_A_DIV 0xaf
|
||||
#define TOK_A_XOR 0xde
|
||||
#define TOK_A_OR 0xfc
|
||||
#define TOK_A_SHL 0x81
|
||||
#define TOK_A_SAR 0x82
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#ifndef countof
|
||||
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
|
||||
#endif
|
||||
|
||||
#define TOK_EOF (-1) /* end of file */
|
||||
#define TOK_LINEFEED 10 /* line feed */
|
||||
|
||||
/* all identificators and strings have token above that */
|
||||
#define TOK_IDENT 256
|
||||
|
||||
/* only used for i386 asm opcodes definitions */
|
||||
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
|
||||
|
||||
#define DEF_BWL(x) \
|
||||
DEF(TOK_ASM_ ## x ## b, #x "b") \
|
||||
DEF(TOK_ASM_ ## x ## w, #x "w") \
|
||||
DEF(TOK_ASM_ ## x ## l, #x "l") \
|
||||
DEF(TOK_ASM_ ## x, #x)
|
||||
|
||||
#define DEF_WL(x) \
|
||||
DEF(TOK_ASM_ ## x ## w, #x "w") \
|
||||
DEF(TOK_ASM_ ## x ## l, #x "l") \
|
||||
DEF(TOK_ASM_ ## x, #x)
|
||||
|
||||
#define DEF_FP1(x) \
|
||||
DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \
|
||||
DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \
|
||||
DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \
|
||||
DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s")
|
||||
|
||||
#define DEF_FP(x) \
|
||||
DEF(TOK_ASM_ ## f ## x, "f" #x ) \
|
||||
DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \
|
||||
DEF_FP1(x)
|
||||
|
||||
#define DEF_ASMTEST(x) \
|
||||
DEF_ASM(x ## o) \
|
||||
DEF_ASM(x ## no) \
|
||||
DEF_ASM(x ## b) \
|
||||
DEF_ASM(x ## c) \
|
||||
DEF_ASM(x ## nae) \
|
||||
DEF_ASM(x ## nb) \
|
||||
DEF_ASM(x ## nc) \
|
||||
DEF_ASM(x ## ae) \
|
||||
DEF_ASM(x ## e) \
|
||||
DEF_ASM(x ## z) \
|
||||
DEF_ASM(x ## ne) \
|
||||
DEF_ASM(x ## nz) \
|
||||
DEF_ASM(x ## be) \
|
||||
DEF_ASM(x ## na) \
|
||||
DEF_ASM(x ## nbe) \
|
||||
DEF_ASM(x ## a) \
|
||||
DEF_ASM(x ## s) \
|
||||
DEF_ASM(x ## ns) \
|
||||
DEF_ASM(x ## p) \
|
||||
DEF_ASM(x ## pe) \
|
||||
DEF_ASM(x ## np) \
|
||||
DEF_ASM(x ## po) \
|
||||
DEF_ASM(x ## l) \
|
||||
DEF_ASM(x ## nge) \
|
||||
DEF_ASM(x ## nl) \
|
||||
DEF_ASM(x ## ge) \
|
||||
DEF_ASM(x ## le) \
|
||||
DEF_ASM(x ## ng) \
|
||||
DEF_ASM(x ## nle) \
|
||||
DEF_ASM(x ## g)
|
||||
|
||||
#define TOK_ASM_int TOK_INT
|
||||
|
||||
enum tcc_token {
|
||||
TOK_LAST = TOK_IDENT - 1,
|
||||
#define DEF(id, str) id,
|
||||
#include "tcctok.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
#define TOK_UIDENT TOK_DEFINE
|
||||
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#ifndef __GNUC__
|
||||
#define strtold (long double)strtod
|
||||
#define strtof (float)strtod
|
||||
#define strtoll (long long)strtol
|
||||
#endif
|
||||
#elif defined(TCC_UCLIBC) || defined(__FreeBSD__) || defined(__DragonFly__) \
|
||||
|| defined(__OpenBSD__)
|
||||
/* currently incorrect */
|
||||
long double strtold(const char *nptr, char **endptr)
|
||||
{
|
||||
return (long double)strtod(nptr, endptr);
|
||||
}
|
||||
float strtof(const char *nptr, char **endptr)
|
||||
{
|
||||
return (float)strtod(nptr, endptr);
|
||||
}
|
||||
#else
|
||||
/* 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);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define IS_PATHSEP(c) (c == '/' || c == '\\')
|
||||
#define IS_ABSPATH(p) (IS_PATHSEP(p[0]) || (p[0] && p[1] == ':' && IS_PATHSEP(p[2])))
|
||||
#define PATHCMP stricmp
|
||||
#else
|
||||
#define IS_PATHSEP(c) (c == '/')
|
||||
#define IS_ABSPATH(p) IS_PATHSEP(p[0])
|
||||
#define PATHCMP strcmp
|
||||
#endif
|
||||
|
||||
void error(const char *fmt, ...);
|
||||
void error_noabort(const char *fmt, ...);
|
||||
void warning(const char *fmt, ...);
|
||||
|
||||
void tcc_set_lib_path_w32(TCCState *s);
|
||||
int tcc_set_flag(TCCState *s, const char *flag_name, int value);
|
||||
void tcc_print_stats(TCCState *s, int64_t total_time);
|
||||
|
||||
void tcc_free(void *ptr);
|
||||
void *tcc_malloc(unsigned long size);
|
||||
void *tcc_mallocz(unsigned long size);
|
||||
void *tcc_realloc(void *ptr, unsigned long size);
|
||||
char *tcc_strdup(const char *str);
|
||||
|
||||
char *tcc_basename(const char *name);
|
||||
char *tcc_fileextension (const char *name);
|
||||
char *pstrcpy(char *buf, int buf_size, const char *s);
|
||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
void dynarray_add(void ***ptab, int *nb_ptr, void *data);
|
||||
void dynarray_reset(void *pp, int *n);
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
extern int num_callers;
|
||||
extern const char **rt_bound_error_msg;
|
||||
#endif
|
||||
|
||||
/* true if float/double/long double type */
|
||||
static inline int is_float(int t)
|
||||
{
|
||||
int bt;
|
||||
bt = t & VT_BTYPE;
|
||||
return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT;
|
||||
}
|
||||
|
||||
/* space exlcuding newline */
|
||||
static inline int is_space(int ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r';
|
||||
}
|
||||
|
||||
30
tccasm.c
30
tccasm.c
@@ -806,7 +806,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
||||
sv = *op->vt;
|
||||
if (op->reg >= 0) {
|
||||
sv.r = op->reg;
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL)
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
|
||||
sv.r |= VT_LVAL;
|
||||
}
|
||||
subst_asm_operand(out_str, &sv, modifier);
|
||||
@@ -916,21 +916,23 @@ static void asm_instr(void)
|
||||
nb_outputs = nb_operands;
|
||||
if (tok == ':') {
|
||||
next();
|
||||
/* input args */
|
||||
parse_asm_operands(operands, &nb_operands, 0);
|
||||
if (tok == ':') {
|
||||
/* clobber list */
|
||||
/* XXX: handle registers */
|
||||
next();
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
asm_clobber(clobber_regs, tokc.cstr->data);
|
||||
if (tok != ')') {
|
||||
/* input args */
|
||||
parse_asm_operands(operands, &nb_operands, 0);
|
||||
if (tok == ':') {
|
||||
/* clobber list */
|
||||
/* XXX: handle registers */
|
||||
next();
|
||||
if (tok == ',') {
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
asm_clobber(clobber_regs, tokc.cstr->data);
|
||||
next();
|
||||
} else {
|
||||
break;
|
||||
if (tok == ',') {
|
||||
next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
tcccoff.c
16
tcccoff.c
@@ -84,6 +84,8 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
Section *stext, *sdata, *sbss;
|
||||
int i, NSectionsToOutput = 0;
|
||||
|
||||
Coff_str_table = pCoff_str_table = NULL;
|
||||
|
||||
stext = FindSection(s1, ".text");
|
||||
sdata = FindSection(s1, ".data");
|
||||
sbss = FindSection(s1, ".bss");
|
||||
@@ -183,7 +185,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
coff_sec->s_nlnno = 0;
|
||||
coff_sec->s_lnnoptr = 0;
|
||||
|
||||
if (do_debug && tcc_sect == stext) {
|
||||
if (s1->do_debug && tcc_sect == stext) {
|
||||
// count how many line nos data
|
||||
|
||||
// also find association between source file name and function
|
||||
@@ -311,7 +313,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
|
||||
file_hdr.f_symptr = file_pointer; /* file pointer to symtab */
|
||||
|
||||
if (do_debug)
|
||||
if (s1->do_debug)
|
||||
file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */
|
||||
else
|
||||
file_hdr.f_nsyms = 0;
|
||||
@@ -362,7 +364,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
// group the symbols in order of filename, func1, func2, etc
|
||||
// finally global symbols
|
||||
|
||||
if (do_debug)
|
||||
if (s1->do_debug)
|
||||
SortSymbolTable();
|
||||
|
||||
// write line no data
|
||||
@@ -371,7 +373,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
coff_sec = §ion_header[i];
|
||||
tcc_sect = s1->sections[i];
|
||||
|
||||
if (do_debug && tcc_sect == stext) {
|
||||
if (s1->do_debug && tcc_sect == stext) {
|
||||
// count how many line nos data
|
||||
|
||||
|
||||
@@ -499,7 +501,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
}
|
||||
|
||||
// write symbol table
|
||||
if (do_debug) {
|
||||
if (s1->do_debug) {
|
||||
int k;
|
||||
struct syment csym;
|
||||
AUXFUNC auxfunc;
|
||||
@@ -670,7 +672,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
|
||||
}
|
||||
}
|
||||
|
||||
if (do_debug) {
|
||||
if (s1->do_debug) {
|
||||
// write string table
|
||||
|
||||
// first write the size
|
||||
@@ -940,7 +942,7 @@ int tcc_load_coff(TCCState * s1, int fd)
|
||||
if (name[0] == '_' && strcmp(name, "_main") != 0)
|
||||
name++;
|
||||
|
||||
tcc_add_symbol(s1, name, csym.n_value);
|
||||
tcc_add_symbol(s1, name, (void*)csym.n_value);
|
||||
}
|
||||
// skip any aux records
|
||||
|
||||
|
||||
84
tcctok.h
84
tcctok.h
@@ -101,11 +101,21 @@
|
||||
DEF(TOK_STDCALL1, "stdcall")
|
||||
DEF(TOK_STDCALL2, "__stdcall")
|
||||
DEF(TOK_STDCALL3, "__stdcall__")
|
||||
DEF(TOK_FASTCALL1, "fastcall")
|
||||
DEF(TOK_FASTCALL2, "__fastcall")
|
||||
DEF(TOK_FASTCALL3, "__fastcall__")
|
||||
DEF(TOK_DLLEXPORT, "dllexport")
|
||||
DEF(TOK_NORETURN1, "noreturn")
|
||||
DEF(TOK_NORETURN2, "__noreturn__")
|
||||
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
|
||||
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
||||
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
DEF(TOK_builtin_malloc, "__builtin_malloc")
|
||||
DEF(TOK_builtin_free, "__builtin_free")
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
#endif
|
||||
DEF(TOK_REGPARM1, "regparm")
|
||||
DEF(TOK_REGPARM2, "__regparm__")
|
||||
|
||||
@@ -118,28 +128,48 @@
|
||||
#endif
|
||||
|
||||
/* builtin functions or variables */
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK_memcpy, "__aeabi_memcpy")
|
||||
DEF(TOK_memcpy4, "__aeabi_memcpy4")
|
||||
DEF(TOK_memcpy8, "__aeabi_memcpy8")
|
||||
DEF(TOK_memset, "__aeabi_memset")
|
||||
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
|
||||
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
|
||||
#else
|
||||
DEF(TOK_memcpy, "memcpy")
|
||||
DEF(TOK_memset, "memset")
|
||||
DEF(TOK_alloca, "alloca")
|
||||
DEF(TOK___divdi3, "__divdi3")
|
||||
DEF(TOK___moddi3, "__moddi3")
|
||||
DEF(TOK___udivdi3, "__udivdi3")
|
||||
DEF(TOK___umoddi3, "__umoddi3")
|
||||
#endif
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
|
||||
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
|
||||
DEF(TOK___divsi3, "__aeabi_idiv")
|
||||
DEF(TOK___udivsi3, "__aeabi_uidiv")
|
||||
DEF(TOK___floatdisf, "__aeabi_l2f")
|
||||
DEF(TOK___floatdidf, "__aeabi_l2d")
|
||||
DEF(TOK___fixsfdi, "__aeabi_f2lz")
|
||||
DEF(TOK___fixdfdi, "__aeabi_d2lz")
|
||||
#else
|
||||
DEF(TOK___modsi3, "__modsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___umodsi3, "__umodsi3")
|
||||
DEF(TOK___sardi3, "__ashrdi3")
|
||||
DEF(TOK___shrdi3, "__lshrdi3")
|
||||
DEF(TOK___shldi3, "__ashldi3")
|
||||
DEF(TOK___slltold, "__slltold")
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___floatdisf, "__floatdisf")
|
||||
DEF(TOK___floatdidf, "__floatdidf")
|
||||
#ifndef TCC_ARM_VFP
|
||||
DEF(TOK___floatdixf, "__floatdixf")
|
||||
DEF(TOK___fixunssfsi, "__fixunssfsi")
|
||||
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
|
||||
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#endif
|
||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#endif
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
DEF(TOK__divi, "_divi")
|
||||
DEF(TOK__divu, "_divu")
|
||||
@@ -147,24 +177,35 @@
|
||||
DEF(TOK__divd, "_divd")
|
||||
DEF(TOK__remi, "_remi")
|
||||
DEF(TOK__remu, "_remu")
|
||||
DEF(TOK___sardi3, "__sardi3")
|
||||
DEF(TOK___shrdi3, "__shrdi3")
|
||||
DEF(TOK___shldi3, "__shldi3")
|
||||
#else
|
||||
/* XXX: same names on i386 ? */
|
||||
DEF(TOK___sardi3, "__sardi3")
|
||||
DEF(TOK___shrdi3, "__shrdi3")
|
||||
DEF(TOK___shldi3, "__shldi3")
|
||||
#endif
|
||||
#ifdef TCC_TARGET_I386
|
||||
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
|
||||
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
|
||||
DEF(TOK___ulltof, "__ulltof")
|
||||
DEF(TOK___ulltod, "__ulltod")
|
||||
DEF(TOK___ulltold, "__ulltold")
|
||||
#endif
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK___ashrdi3, "__aeabi_lasr")
|
||||
DEF(TOK___lshrdi3, "__aeabi_llsr")
|
||||
DEF(TOK___ashldi3, "__aeabi_llsl")
|
||||
DEF(TOK___floatundisf, "__aeabi_ul2f")
|
||||
DEF(TOK___floatundidf, "__aeabi_ul2d")
|
||||
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
|
||||
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
|
||||
#else
|
||||
DEF(TOK___ashrdi3, "__ashrdi3")
|
||||
DEF(TOK___lshrdi3, "__lshrdi3")
|
||||
DEF(TOK___ashldi3, "__ashldi3")
|
||||
DEF(TOK___floatundisf, "__floatundisf")
|
||||
DEF(TOK___floatundidf, "__floatundidf")
|
||||
#ifndef TCC_ARM_VFP
|
||||
DEF(TOK___floatundixf, "__floatundixf")
|
||||
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
||||
#endif
|
||||
DEF(TOK___fixunssfdi, "__fixunssfdi")
|
||||
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
|
||||
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
||||
#endif
|
||||
#ifdef TCC_TARGET_PE
|
||||
DEF(TOK___chkstk, "__chkstk")
|
||||
#endif
|
||||
|
||||
/* bound checking symbols */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
@@ -177,14 +218,17 @@
|
||||
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
|
||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
#if 0
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
DEF(TOK_realloc, "realloc")
|
||||
DEF(TOK_memalign, "memalign")
|
||||
DEF(TOK_calloc, "calloc")
|
||||
#endif
|
||||
DEF(TOK_memmove, "memmove")
|
||||
DEF(TOK_strlen, "strlen")
|
||||
DEF(TOK_strcpy, "strcpy")
|
||||
DEF(TOK_alloca, "alloca")
|
||||
#endif
|
||||
|
||||
/* Tiny Assembler */
|
||||
|
||||
145
tests/Makefile
Normal file
145
tests/Makefile
Normal file
@@ -0,0 +1,145 @@
|
||||
#
|
||||
# Tiny C Compiler Makefile - tests
|
||||
#
|
||||
|
||||
# what tests to run
|
||||
TESTS = libtest test3
|
||||
|
||||
# these should work too
|
||||
# TESTS += test1 test2 speed
|
||||
|
||||
# these don't work as they should
|
||||
# TESTS += test4 btest asmtest
|
||||
|
||||
|
||||
TOP = ..
|
||||
include $(TOP)/Makefile
|
||||
|
||||
# run local version of tcc with local libraries and includes
|
||||
TCC = ../tcc -B..
|
||||
RUN_TCC = $(NATIVE_TARGET) -run ../tcc.c -B..
|
||||
DISAS=objdump -d
|
||||
|
||||
all test : $(TESTS)
|
||||
|
||||
# make sure that tcc exists
|
||||
$(TESTS) : ../tcc
|
||||
../tcc ../libtcc.a :
|
||||
$(MAKE) -C ..
|
||||
|
||||
# libtcc test
|
||||
libtest: libtcc_test$(EXESUF)
|
||||
@echo ------------ $@ ------------
|
||||
./libtcc_test lib_path=..
|
||||
|
||||
libtcc_test$(EXESUF): libtcc_test.c ../libtcc.a
|
||||
$(CC) -o $@ $^ -I.. $(CFLAGS) $(LIBS)
|
||||
|
||||
# test.ref - generate using gcc
|
||||
test.ref: tcctest.c
|
||||
cp -u ../include/tcclib.h .
|
||||
$(CC) -o tcctest.gcc $< -I. -w $(CFLAGS)
|
||||
./tcctest.gcc > $@
|
||||
|
||||
# auto test
|
||||
test1: test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -run tcctest.c > test.out1
|
||||
@if diff -u test.ref test.out1 ; then echo "Auto Test OK"; fi
|
||||
|
||||
# iterated test2 (compile tcc then compile tcctest.c !)
|
||||
test2: test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out2
|
||||
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
|
||||
|
||||
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
||||
test3: test.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out3
|
||||
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
|
||||
|
||||
# binary output test
|
||||
test4: test.ref
|
||||
@echo ------------ $@ ------------
|
||||
# dynamic output
|
||||
$(TCC) -o tcctest1 tcctest.c
|
||||
./tcctest1 > test1.out
|
||||
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
||||
# object + link output
|
||||
$(TCC) -c -o tcctest3.o tcctest.c
|
||||
$(TCC) -o tcctest3 tcctest3.o
|
||||
./tcctest3 > test3.out
|
||||
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
|
||||
# static output
|
||||
$(TCC) -static -o tcctest2 tcctest.c
|
||||
./tcctest2 > test2.out
|
||||
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
|
||||
# dynamic output + bound check
|
||||
$(TCC) -b -o tcctest4 tcctest.c
|
||||
./tcctest4 > test4.out
|
||||
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
||||
|
||||
# memory and bound check auto test
|
||||
BOUNDS_OK = 1 4 8 10
|
||||
BOUNDS_FAIL= 2 5 7 9 11 12 13
|
||||
|
||||
btest: boundtest.c
|
||||
@echo ------------ $@ ------------
|
||||
@for i in $(BOUNDS_OK); do \
|
||||
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||
/bin/true ; \
|
||||
else\
|
||||
echo Failed positive test $$i ; exit 1 ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
for i in $(BOUNDS_FAIL); do \
|
||||
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||
echo Failed negative test $$i ; exit 1 ;\
|
||||
else\
|
||||
/bin/true ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
echo Bound test OK
|
||||
|
||||
# speed test
|
||||
speed: ex2 ex3
|
||||
@echo ------------ $@ ------------
|
||||
time ./ex2 1238 2 3 4 10 13 4
|
||||
time $(TCC) -run ../examples/ex2.c 1238 2 3 4 10 13 4
|
||||
time ./ex3 35
|
||||
time $(TCC) -run ../examples/ex3.c 35
|
||||
|
||||
ex%: ../examples/ex%.c
|
||||
$(CC) -o $@ $< $(CFLAGS)
|
||||
|
||||
# tiny assembler testing
|
||||
asmtest.ref: asmtest.S
|
||||
$(CC) -o asmtest.ref.o -c asmtest.S
|
||||
objdump -D asmtest.ref.o > $@
|
||||
|
||||
asmtest: asmtest.ref
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -c asmtest.S
|
||||
objdump -D asmtest.o > $@
|
||||
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
|
||||
|
||||
# targets for development
|
||||
%.bin: %.c tcc
|
||||
$(TCC) -g -o $@ $<
|
||||
$(DISAS) $@
|
||||
|
||||
instr: instr.o
|
||||
objdump -d instr.o
|
||||
|
||||
instr.o: instr.S
|
||||
$(CC) -o $@ -c $< -O2 -Wall -g
|
||||
|
||||
cache: tcc_g
|
||||
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
|
||||
vg_annotate tcc.c > /tmp/linpack.cache.log
|
||||
|
||||
# clean
|
||||
clean:
|
||||
rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.gcc \
|
||||
tcctest[1234] ex? libtcc_test$(EXESUF) tcc_g tcclib.h
|
||||
0
gcctestsuite.sh → tests/gcctestsuite.sh
Executable file → Normal file
0
gcctestsuite.sh → tests/gcctestsuite.sh
Executable file → Normal file
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libtcc.h"
|
||||
|
||||
@@ -14,7 +15,7 @@ int add(int a, int b)
|
||||
return a + b;
|
||||
}
|
||||
|
||||
char my_program[] =
|
||||
char my_program[] =
|
||||
"int fib(int n)\n"
|
||||
"{\n"
|
||||
" if (n <= 2)\n"
|
||||
@@ -35,31 +36,49 @@ int main(int argc, char **argv)
|
||||
{
|
||||
TCCState *s;
|
||||
int (*func)(int);
|
||||
unsigned long val;
|
||||
|
||||
void *mem;
|
||||
int size;
|
||||
|
||||
s = tcc_new();
|
||||
if (!s) {
|
||||
fprintf(stderr, "Could not create tcc state\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* MUST BE CALLED before any compilation or file loading */
|
||||
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
||||
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
|
||||
tcc_set_lib_path(s, argv[1]+9);
|
||||
|
||||
/* MUST BE CALLED before any compilation */
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
|
||||
tcc_compile_string(s, my_program);
|
||||
if (tcc_compile_string(s, my_program) == -1)
|
||||
return 1;
|
||||
|
||||
/* as a test, we add a symbol that the compiled program can be
|
||||
linked with. You can have a similar result by opening a dll
|
||||
with tcc_add_dll(() and using its symbols directly. */
|
||||
tcc_add_symbol(s, "add", (unsigned long)&add);
|
||||
|
||||
tcc_relocate(s);
|
||||
/* as a test, we add a symbol that the compiled program can use.
|
||||
You may also open a dll with tcc_add_dll() and use symbols from that */
|
||||
tcc_add_symbol(s, "add", add);
|
||||
|
||||
tcc_get_symbol(s, &val, "foo");
|
||||
func = (void *)val;
|
||||
/* get needed size of the code */
|
||||
size = tcc_relocate(s, NULL);
|
||||
if (size == -1)
|
||||
return 1;
|
||||
|
||||
/* allocate memory and copy the code into it */
|
||||
mem = malloc(size);
|
||||
tcc_relocate(s, mem);
|
||||
|
||||
/* get entry symbol */
|
||||
func = tcc_get_symbol(s, "foo");
|
||||
if (!func)
|
||||
return 1;
|
||||
|
||||
/* delete the state */
|
||||
tcc_delete(s);
|
||||
|
||||
/* run the code */
|
||||
func(32);
|
||||
|
||||
tcc_delete(s);
|
||||
free(mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* TCC auto test program
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "../config.h"
|
||||
|
||||
#if GCC_MAJOR >= 3
|
||||
|
||||
@@ -70,10 +70,12 @@ void bitfield_test(void);
|
||||
void c99_bool_test(void);
|
||||
void float_test(void);
|
||||
void longlong_test(void);
|
||||
void manyarg_test(void);
|
||||
void stdarg_test(void);
|
||||
void whitespace_test(void);
|
||||
void relocation_test(void);
|
||||
void old_style_function(void);
|
||||
void alloca_test(void);
|
||||
void sizeof_test(void);
|
||||
void typeof_test(void);
|
||||
void local_label_test(void);
|
||||
@@ -223,7 +225,7 @@ void macro_test(void)
|
||||
#line 203 "test"
|
||||
printf("__LINE__=%d __FILE__=%s\n",
|
||||
__LINE__, __FILE__);
|
||||
#line 220 "tcctest.c"
|
||||
#line 227 "tcctest.c"
|
||||
|
||||
/* not strictly preprocessor, but we test it there */
|
||||
#ifdef C99_MACROS
|
||||
@@ -311,7 +313,7 @@ test\14\
|
||||
|
||||
void string_test()
|
||||
{
|
||||
int b;
|
||||
unsigned int b;
|
||||
printf("string:\n");
|
||||
printf("\141\1423\143\n");/* dezdez test */
|
||||
printf("\x41\x42\x43\x3a\n");
|
||||
@@ -441,14 +443,21 @@ void enum_test()
|
||||
|
||||
typedef int *my_ptr;
|
||||
|
||||
typedef int mytype1;
|
||||
typedef int mytype2;
|
||||
|
||||
void typedef_test()
|
||||
{
|
||||
my_ptr a;
|
||||
mytype1 mytype2;
|
||||
int b;
|
||||
|
||||
a = &b;
|
||||
*a = 1234;
|
||||
printf("typedef:\n");
|
||||
printf("a=%d\n", *a);
|
||||
mytype2 = 2;
|
||||
printf("mytype2=%d\n", mytype2);
|
||||
}
|
||||
|
||||
void forward_test()
|
||||
@@ -516,10 +525,12 @@ int main(int argc, char **argv)
|
||||
c99_bool_test();
|
||||
float_test();
|
||||
longlong_test();
|
||||
manyarg_test();
|
||||
stdarg_test();
|
||||
whitespace_test();
|
||||
relocation_test();
|
||||
old_style_function();
|
||||
alloca_test();
|
||||
sizeof_test();
|
||||
typeof_test();
|
||||
statement_expr_test();
|
||||
@@ -688,6 +699,7 @@ int tab4[10];
|
||||
void expr_ptr_test()
|
||||
{
|
||||
int *p, *q;
|
||||
int i = -1;
|
||||
|
||||
printf("expr_ptr:\n");
|
||||
p = tab4;
|
||||
@@ -703,6 +715,37 @@ void expr_ptr_test()
|
||||
printf("dec=%d\n", p - tab4);
|
||||
printf("add=%d\n", p + 3 - tab4);
|
||||
printf("add=%d\n", 3 + p - tab4);
|
||||
|
||||
/* check if 64bit support is ok */
|
||||
q = p = 0;
|
||||
q += i;
|
||||
printf("%p %p %ld\n", q, p, p-q);
|
||||
printf("%d %d %d %d %d %d\n",
|
||||
p == q, p != q, p < q, p <= q, p >= q, p > q);
|
||||
i = 0xf0000000;
|
||||
p += i;
|
||||
printf("%p %p %ld\n", q, p, p-q);
|
||||
printf("%d %d %d %d %d %d\n",
|
||||
p == q, p != q, p < q, p <= q, p >= q, p > q);
|
||||
p = (int *)((char *)p + 0xf0000000);
|
||||
printf("%p %p %ld\n", q, p, p-q);
|
||||
printf("%d %d %d %d %d %d\n",
|
||||
p == q, p != q, p < q, p <= q, p >= q, p > q);
|
||||
p += 0xf0000000;
|
||||
printf("%p %p %ld\n", q, p, p-q);
|
||||
printf("%d %d %d %d %d %d\n",
|
||||
p == q, p != q, p < q, p <= q, p >= q, p > q);
|
||||
{
|
||||
struct size12 {
|
||||
int i, j, k;
|
||||
};
|
||||
struct size12 s[2], *sp = s;
|
||||
int i, j;
|
||||
sp->i = 42;
|
||||
sp++;
|
||||
j = -1;
|
||||
printf("%d\n", sp[j].i);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_cmp_test()
|
||||
@@ -1066,6 +1109,10 @@ void cast_test()
|
||||
int a;
|
||||
char c;
|
||||
char tab[10];
|
||||
unsigned b,d;
|
||||
short s;
|
||||
char *p = NULL;
|
||||
p -= 0x700000000042;
|
||||
|
||||
printf("cast_test:\n");
|
||||
a = 0xfffff;
|
||||
@@ -1088,7 +1135,15 @@ void cast_test()
|
||||
printf("%d\n", a);
|
||||
|
||||
printf("sizeof(c) = %d, sizeof((int)c) = %d\n", sizeof(c), sizeof((int)c));
|
||||
|
||||
|
||||
/* test cast from unsigned to signed short to int */
|
||||
b = 0xf000;
|
||||
d = (short)b;
|
||||
printf("((unsigned)(short)0x%08x) = 0x%08x\n", b, d);
|
||||
b = 0xf0f0;
|
||||
d = (char)b;
|
||||
printf("((unsigned)(char)0x%08x) = 0x%08x\n", b, d);
|
||||
|
||||
/* test implicit int casting for array accesses */
|
||||
c = 0;
|
||||
tab[1] = 2;
|
||||
@@ -1099,6 +1154,16 @@ void cast_test()
|
||||
printf("sizeof(+(char)'a') = %d\n", sizeof(+(char)'a'));
|
||||
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
|
||||
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
|
||||
|
||||
/* from pointer to integer types */
|
||||
printf("%d %d %ld %ld %lld %lld\n",
|
||||
(int)p, (unsigned int)p,
|
||||
(long)p, (unsigned long)p,
|
||||
(long long)p, (unsigned long long)p);
|
||||
|
||||
/* from integers to pointers */
|
||||
printf("%p %p %p %p\n",
|
||||
(void *)a, (void *)b, (void *)c, (void *)d);
|
||||
}
|
||||
|
||||
/* initializers tests */
|
||||
@@ -1324,8 +1389,35 @@ void bitfield_test(void)
|
||||
printf("st1.f2 == -1\n");
|
||||
else
|
||||
printf("st1.f2 != -1\n");
|
||||
|
||||
/* bit sizes below must be bigger than 32 since GCC doesn't allow
|
||||
long-long bitfields whose size is not bigger than int */
|
||||
struct sbf2 {
|
||||
long long f1 : 45;
|
||||
long long : 2;
|
||||
long long f2 : 35;
|
||||
unsigned long long f3 : 38;
|
||||
} st2;
|
||||
st2.f1 = 0x123456789ULL;
|
||||
a = 120;
|
||||
st2.f2 = (long long)a << 25;
|
||||
st2.f3 = a;
|
||||
st2.f2++;
|
||||
printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3);
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define FLOAT_FMT "%f\n"
|
||||
#else
|
||||
/* x86's float isn't compatible with GCC */
|
||||
#define FLOAT_FMT "%.5f\n"
|
||||
#endif
|
||||
|
||||
/* declare strto* functions as they are C99 */
|
||||
double strtod(const char *nptr, char **endptr);
|
||||
float strtof(const char *nptr, char **endptr);
|
||||
long double strtold(const char *nptr, char **endptr);
|
||||
|
||||
#define FTEST(prefix, type, fmt)\
|
||||
void prefix ## cmp(type a, type b)\
|
||||
{\
|
||||
@@ -1347,6 +1439,8 @@ void prefix ## cmp(type a, type b)\
|
||||
printf(fmt "\n", ++a);\
|
||||
printf(fmt "\n", a++);\
|
||||
printf(fmt "\n", a);\
|
||||
b = 0;\
|
||||
printf("%d %d\n", !a, !b);\
|
||||
}\
|
||||
void prefix ## fcast(type a)\
|
||||
{\
|
||||
@@ -1371,6 +1465,18 @@ void prefix ## fcast(type a)\
|
||||
printf("utof: " fmt "\n", b);\
|
||||
}\
|
||||
\
|
||||
float prefix ## retf(type a) { return a; }\
|
||||
double prefix ## retd(type a) { return a; }\
|
||||
long double prefix ## retld(type a) { return a; }\
|
||||
\
|
||||
void prefix ## call(void)\
|
||||
{\
|
||||
printf("float: " FLOAT_FMT, prefix ## retf(42.123456789));\
|
||||
printf("double: %f\n", prefix ## retd(42.123456789));\
|
||||
printf("long double: %Lf\n", prefix ## retld(42.123456789));\
|
||||
printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\
|
||||
}\
|
||||
\
|
||||
void prefix ## test(void)\
|
||||
{\
|
||||
printf("testing '%s'\n", #type);\
|
||||
@@ -1379,6 +1485,7 @@ void prefix ## test(void)\
|
||||
prefix ## cmp(1, 1);\
|
||||
prefix ## fcast(234.6);\
|
||||
prefix ## fcast(-2334.6);\
|
||||
prefix ## call();\
|
||||
}
|
||||
|
||||
FTEST(f, float, "%f")
|
||||
@@ -1498,6 +1605,8 @@ void lloptest(long long a, long long b)
|
||||
printf("arith2: %Ld %Ld\n", a++, b++);
|
||||
printf("arith2: %Ld %Ld\n", --a, --b);
|
||||
printf("arith2: %Ld %Ld\n", a, b);
|
||||
b = ub = 0;
|
||||
printf("not: %d %d %d %d\n", !a, !ua, !b, !ub);
|
||||
}
|
||||
|
||||
void llshift(long long a, int b)
|
||||
@@ -1619,6 +1728,50 @@ void longlong_test(void)
|
||||
p[0]++;
|
||||
printf("%lld\n", *p);
|
||||
}
|
||||
|
||||
a = 68719476720LL;
|
||||
b = 4294967295LL;
|
||||
printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b);
|
||||
|
||||
printf("%Ld\n", 0x123456789LLU);
|
||||
}
|
||||
|
||||
void manyarg_test(void)
|
||||
{
|
||||
long double ld = 1234567891234LL;
|
||||
printf("manyarg_test:\n");
|
||||
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
|
||||
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%Ld %Ld %f %f\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0);
|
||||
printf("%Lf %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%Ld %Ld %f %f\n",
|
||||
ld, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0);
|
||||
/* XXX: known bug of x86-64 */
|
||||
#ifndef __x86_64__
|
||||
printf("%d %d %d %d %d %d %d %d %Lf\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, ld);
|
||||
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%Ld %Ld %f %f %Lf\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0, ld);
|
||||
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%Lf %Ld %Ld %f %f %Lf\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
ld, 1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0, ld);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vprintf1(const char *fmt, ...)
|
||||
@@ -1628,6 +1781,7 @@ void vprintf1(const char *fmt, ...)
|
||||
int c, i;
|
||||
double d;
|
||||
long long ll;
|
||||
long double ld;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
@@ -1654,6 +1808,10 @@ void vprintf1(const char *fmt, ...)
|
||||
ll = va_arg(ap, long long);
|
||||
printf("%Ld", ll);
|
||||
break;
|
||||
case 'F':
|
||||
ld = va_arg(ap, long double);
|
||||
printf("%Lf", ld);
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
} else {
|
||||
@@ -1667,9 +1825,48 @@ void vprintf1(const char *fmt, ...)
|
||||
|
||||
void stdarg_test(void)
|
||||
{
|
||||
long double ld = 1234567891234LL;
|
||||
vprintf1("%d %d %d\n", 1, 2, 3);
|
||||
vprintf1("%f %d %f\n", 1.0, 2, 3.0);
|
||||
vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0);
|
||||
vprintf1("%F %F %F\n", 1.2L, 2.3L, 3.4L);
|
||||
#ifdef __x86_64__
|
||||
/* a bug of x86's TCC */
|
||||
vprintf1("%d %f %l %F %d %f %l %F\n",
|
||||
1, 1.2, 3L, 4.5L, 6, 7.8, 9L, 0.1L);
|
||||
#endif
|
||||
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8);
|
||||
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
|
||||
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%l %l %f %f\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0);
|
||||
vprintf1("%F %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%l %l %f %f\n",
|
||||
ld, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0);
|
||||
vprintf1("%d %d %d %d %d %d %d %d %F\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8, ld);
|
||||
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%l %l %f %f %F\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0, ld);
|
||||
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
|
||||
"%F %l %l %f %f %F\n",
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
|
||||
ld, 1234567891234LL, 987654321986LL,
|
||||
42.0, 43.0, ld);
|
||||
}
|
||||
|
||||
void whitespace_test(void)
|
||||
@@ -1740,6 +1937,18 @@ void old_style_function(void)
|
||||
decl_func2(NULL);
|
||||
}
|
||||
|
||||
void alloca_test()
|
||||
{
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
char *p = alloca(16);
|
||||
strcpy(p,"123456789012345");
|
||||
printf("alloca: p is %s\n", p);
|
||||
char *demo = "This is only a test.\n";
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void sizeof_test(void)
|
||||
{
|
||||
int a;
|
||||
@@ -1747,6 +1956,8 @@ void sizeof_test(void)
|
||||
|
||||
printf("sizeof(int) = %d\n", sizeof(int));
|
||||
printf("sizeof(unsigned int) = %d\n", sizeof(unsigned int));
|
||||
printf("sizeof(long) = %d\n", sizeof(long));
|
||||
printf("sizeof(unsigned long) = %d\n", sizeof(unsigned long));
|
||||
printf("sizeof(short) = %d\n", sizeof(short));
|
||||
printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short));
|
||||
printf("sizeof(char) = %d\n", sizeof(char));
|
||||
@@ -1803,14 +2014,14 @@ void local_label_test(void)
|
||||
goto l1;
|
||||
l2:
|
||||
a = 1 + ({
|
||||
__label__ l1, l2, l3;
|
||||
goto l4;
|
||||
l5:
|
||||
printf("aa1\n");
|
||||
__label__ l1, l2, l3, l4;
|
||||
goto l1;
|
||||
l4:
|
||||
printf("aa1\n");
|
||||
goto l3;
|
||||
l2:
|
||||
printf("aa3\n");
|
||||
goto l3;
|
||||
goto l4;
|
||||
l1:
|
||||
printf("aa2\n");
|
||||
goto l2;
|
||||
@@ -1819,12 +2030,12 @@ void local_label_test(void)
|
||||
});
|
||||
printf("a=%d\n", a);
|
||||
return;
|
||||
l1:
|
||||
l4:
|
||||
printf("bb1\n");
|
||||
goto l2;
|
||||
l4:
|
||||
l1:
|
||||
printf("bb2\n");
|
||||
goto l5;
|
||||
goto l4;
|
||||
}
|
||||
|
||||
/* inline assembler test */
|
||||
@@ -1932,6 +2143,9 @@ void asm_test(void)
|
||||
goto label1;
|
||||
label2:
|
||||
__asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
|
||||
#ifdef __GNUC__ // works strange with GCC 4.3
|
||||
set=0x1080fd;
|
||||
#endif
|
||||
printf("set=0x%x\n", set);
|
||||
val = 0x01020304;
|
||||
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
|
||||
372
tiny_impdef.c
372
tiny_impdef.c
@@ -1,372 +0,0 @@
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
"tiny_impdef creates a .def file from a dll"
|
||||
|
||||
"Usage: tiny_impdef [-p] <library.dll> [-o outputfile]"
|
||||
"Options:"
|
||||
" -p print to stdout"
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Offset to PE file signature */
|
||||
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew))
|
||||
|
||||
/* MS-OS header identifies the NT PEFile signature dword;
|
||||
the PEFILE header exists just after that dword. */
|
||||
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE))
|
||||
|
||||
/* PE optional header is immediately after PEFile header. */
|
||||
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER)))
|
||||
|
||||
/* Section headers are immediately after PE optional header. */
|
||||
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER) + \
|
||||
sizeof (IMAGE_OPTIONAL_HEADER)))
|
||||
|
||||
|
||||
#define SIZE_OF_NT_SIGNATURE 4
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI NumOfSections (
|
||||
LPVOID lpFile)
|
||||
{
|
||||
/* Number of sections is indicated in file header. */
|
||||
return (int)
|
||||
((PIMAGE_FILE_HEADER)
|
||||
PEFHDROFFSET(lpFile))->NumberOfSections;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
LPVOID WINAPI ImageDirectoryOffset (
|
||||
LPVOID lpFile,
|
||||
DWORD dwIMAGE_DIRECTORY)
|
||||
{
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i = 0;
|
||||
LPVOID VAImageDir;
|
||||
|
||||
/* Retrieve offsets to optional and section headers. */
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
|
||||
|
||||
/* Must be 0 thru (NumberOfRvaAndSizes-1). */
|
||||
if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
|
||||
return NULL;
|
||||
|
||||
/* Locate image directory's relative virtual address. */
|
||||
VAImageDir = (LPVOID)poh->DataDirectory
|
||||
[dwIMAGE_DIRECTORY].VirtualAddress;
|
||||
|
||||
/* Locate section containing image directory. */
|
||||
while (i++<nSections)
|
||||
{
|
||||
if (psh->VirtualAddress <= (DWORD)VAImageDir
|
||||
&& psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
|
||||
break;
|
||||
psh++;
|
||||
}
|
||||
|
||||
if (i > nSections)
|
||||
return NULL;
|
||||
|
||||
/* Return image import directory offset. */
|
||||
return (LPVOID)(((int)lpFile +
|
||||
(int)VAImageDir - psh->VirtualAddress) +
|
||||
(int)psh->PointerToRawData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByName (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
char *szSection)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) !=
|
||||
NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (!strcmp (psh->Name, szSection))
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh,
|
||||
(LPVOID)psh,
|
||||
sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByAddress (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
DWORD addr)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) !=
|
||||
NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (addr >= psh->VirtualAddress && addr < psh->VirtualAddress + psh->SizeOfRawData)
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh,
|
||||
(LPVOID)psh,
|
||||
sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI GetExportFunctionNames (
|
||||
LPVOID lpFile,
|
||||
HANDLE hHeap,
|
||||
char **pszFunctions)
|
||||
{
|
||||
IMAGE_SECTION_HEADER sh;
|
||||
PIMAGE_EXPORT_DIRECTORY ped;
|
||||
int *pNames, *pCnt;
|
||||
char *pSrc, *pDest;
|
||||
int i, nCnt;
|
||||
DWORD VAImageDir;
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
char *pOffset;
|
||||
|
||||
/* Get section header and pointer to data directory
|
||||
for .edata section. */
|
||||
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
|
||||
(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
|
||||
return 0;
|
||||
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
|
||||
if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir)) return 0;
|
||||
|
||||
pOffset = (char *)lpFile + (sh.PointerToRawData - sh.VirtualAddress);
|
||||
|
||||
pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames);
|
||||
|
||||
/* Figure out how much memory to allocate for all strings. */
|
||||
nCnt = 1;
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc) nCnt += strlen(pSrc)+1;
|
||||
}
|
||||
|
||||
/* Allocate memory off heap for function names. */
|
||||
pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
|
||||
|
||||
/* Copy all strings to buffer. */
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc) { strcpy(pDest, pSrc); pDest += strlen(pSrc)+1; }
|
||||
}
|
||||
*pDest = 0;
|
||||
|
||||
return ped->NumberOfNames;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
HANDLE hHeap; HANDLE hFile; HANDLE hMapObject; VOID *pMem;
|
||||
int nCnt, ret, argind, std;
|
||||
char *pNames;
|
||||
char infile[MAX_PATH];
|
||||
char buffer[MAX_PATH];
|
||||
char outfile[MAX_PATH];
|
||||
char libname[80];
|
||||
|
||||
hHeap = NULL;
|
||||
hFile = NULL;
|
||||
hMapObject = NULL;
|
||||
pMem = NULL;
|
||||
infile[0] = 0;
|
||||
outfile[0] = 0;
|
||||
ret = 0;
|
||||
std = 0;
|
||||
|
||||
for (argind = 1; argind < argc; ++argind)
|
||||
{
|
||||
const char *a = argv[argind];
|
||||
if ('-' == a[0])
|
||||
{
|
||||
if (0 == strcmp(a, "-p"))
|
||||
std = 1;
|
||||
else
|
||||
if (0 == strcmp(a, "-o"))
|
||||
{
|
||||
if (++argind == argc) goto usage;
|
||||
strcpy(outfile, argv[argind]);
|
||||
}
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
else
|
||||
if (0 == infile[0])
|
||||
strcpy(infile, a);
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (0 == infile[0])
|
||||
{
|
||||
usage:
|
||||
fprintf(stderr,
|
||||
"tiny_impdef creates a .def file from a dll\n"
|
||||
"Usage: tiny_impdef [-p] <library.dll> [-o outputfile]\n"
|
||||
"Options:\n"
|
||||
" -p print to stdout\n"
|
||||
);
|
||||
error:
|
||||
ret = 1;
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL))
|
||||
strcpy(infile, buffer);
|
||||
|
||||
if (0 == outfile[0])
|
||||
{
|
||||
char *p;
|
||||
p = strrchr(strcpy(outfile, infile), '\\');
|
||||
if (NULL == p)
|
||||
p = strrchr(outfile, '/');
|
||||
if (p) strcpy(outfile, p+1);
|
||||
|
||||
p = strrchr(outfile, '.');
|
||||
if (NULL == p) p = strchr(outfile, 0);
|
||||
strcpy(p, ".def");
|
||||
}
|
||||
|
||||
hFile=CreateFile(
|
||||
infile,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "file not found: %s\n", infile);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!std) printf("--> %s\n", infile);
|
||||
|
||||
hMapObject = CreateFileMapping(
|
||||
hFile,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0, 0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (NULL == hMapObject)
|
||||
{
|
||||
fprintf(stderr, "could not create file mapping.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pMem = MapViewOfFile(
|
||||
hMapObject, // object to map view of
|
||||
FILE_MAP_READ, // read access
|
||||
0, // high offset: map from
|
||||
0, // low offset: beginning
|
||||
0); // default: map entire file
|
||||
|
||||
if (NULL == pMem)
|
||||
{
|
||||
fprintf(stderr, "could not map view of file.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hHeap = GetProcessHeap();
|
||||
nCnt = GetExportFunctionNames(pMem, hHeap, &pNames);
|
||||
{
|
||||
FILE *op; char *p; int n;
|
||||
if (!std) printf("<-- %s\n", outfile);
|
||||
|
||||
if (std)
|
||||
op = stdout;
|
||||
else
|
||||
op = fopen(outfile, "wt");
|
||||
|
||||
if (NULL == op)
|
||||
{
|
||||
fprintf(stderr, "could not create file: %s\n", outfile);
|
||||
goto error;
|
||||
}
|
||||
|
||||
p = strrchr(infile, '\\');
|
||||
if (NULL == p)
|
||||
p = strrchr(infile, '/');
|
||||
if (NULL == p) p = infile; else ++p;
|
||||
|
||||
fprintf(op, "LIBRARY %s\n\nEXPORTS", p);
|
||||
if (std) fprintf(op, " (%d)", nCnt);
|
||||
fprintf(op, "\n");
|
||||
for (n = 0, p = pNames; n < nCnt; ++n)
|
||||
{
|
||||
fprintf(op, "%s\n", p);
|
||||
while (*p++);
|
||||
}
|
||||
if (!std) fclose(op);
|
||||
}
|
||||
|
||||
the_end:
|
||||
if (pMem) UnmapViewOfFile(pMem);
|
||||
if (hMapObject) CloseHandle(hMapObject);
|
||||
if (hFile) CloseHandle(hFile);
|
||||
return ret;
|
||||
}
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
28
win32/build-tcc.bat
Normal file
28
win32/build-tcc.bat
Normal file
@@ -0,0 +1,28 @@
|
||||
@rem ----------------------------------------------------
|
||||
@rem batch file to build tcc using gcc and ar from mingw
|
||||
@rem ----------------------------------------------------
|
||||
:
|
||||
@echo>..\config.h #define TCC_VERSION "0.9.25"
|
||||
@echo>>..\config.h #define TCC_TARGET_PE 1
|
||||
@echo>>..\config.h #define CONFIG_TCCDIR "."
|
||||
@echo>>..\config.h #define CONFIG_SYSROOT ""
|
||||
:
|
||||
gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s
|
||||
gcc -Os -fno-strict-aliasing ../libtcc.c -c -o libtcc.o
|
||||
gcc -Os tools/tiny_impdef.c -o tiny_impdef.exe -s
|
||||
gcc -Os tools/tiny_libmaker.c -o tiny_libmaker.exe -s
|
||||
mkdir libtcc
|
||||
ar rcs libtcc/libtcc.a libtcc.o
|
||||
del libtcc.o
|
||||
copy ..\libtcc.h libtcc
|
||||
:
|
||||
.\tcc -c lib/crt1.c
|
||||
.\tcc -c lib/wincrt1.c
|
||||
.\tcc -c lib/dllcrt1.c
|
||||
.\tcc -c lib/dllmain.c
|
||||
.\tcc -c lib/chkstk.S
|
||||
.\tcc -c ../lib/libtcc1.c
|
||||
.\tcc -c ../lib/alloca86.S
|
||||
.\tcc -c ../lib/alloca86-bt.S
|
||||
ar rcs lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86.o alloca86-bt.o
|
||||
del *.o
|
||||
@@ -1,6 +0,0 @@
|
||||
; Windows DLL example - export definition for the DLL
|
||||
|
||||
LIBRARY dll.dll
|
||||
|
||||
EXPORTS
|
||||
HelloWorld
|
||||
@@ -18,25 +18,26 @@
|
||||
#ifndef __MINGW_H
|
||||
#define __MINGW_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define __int64 long long
|
||||
#define __int32 long
|
||||
#define __int16 short
|
||||
#define __int8 char
|
||||
#define __cdecl __attribute__((__cdecl__))
|
||||
#define __stdcall __attribute__((__stdcall__))
|
||||
#define __declspec(x) __attribute__((x))
|
||||
#define __int8 char
|
||||
#define __cdecl __attribute__((__cdecl__))
|
||||
#define __stdcall __attribute__((__stdcall__))
|
||||
#define __declspec(x) __attribute__((x))
|
||||
|
||||
#define __MINGW32_VERSION 2.0
|
||||
#define __MINGW32_MAJOR_VERSION 2
|
||||
#define __MINGW32_MINOR_VERSION 0
|
||||
|
||||
#define __MSVCRT__
|
||||
#define __MINGW_IMPORT extern
|
||||
#define __MSVCRT__ 1
|
||||
#define __MINGW_IMPORT extern
|
||||
#define _CRTIMP
|
||||
#define __CRT_INLINE extern __inline__
|
||||
#define __CRT_INLINE extern __inline__
|
||||
|
||||
#define _WIN32
|
||||
#define WIN32
|
||||
#define WIN32 1
|
||||
|
||||
#ifndef _WINT_T
|
||||
#define _WINT_T
|
||||
@@ -44,7 +45,8 @@ typedef unsigned int wint_t;
|
||||
#endif
|
||||
|
||||
/* for winapi */
|
||||
#define NONAMELESSUNION
|
||||
#define _ANONYMOUS_UNION
|
||||
#define _ANONYMOUS_STRUCT
|
||||
#define DECLSPEC_NORETURN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define DECLARE_STDCALL_P(type) __stdcall type
|
||||
|
||||
@@ -6,6 +6,7 @@ typedef char *va_list;
|
||||
/* only correct for i386 */
|
||||
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
#define va_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
|
||||
/* fix a buggy dependency on GCC in libio.h */
|
||||
|
||||
@@ -12,10 +12,12 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
__GNUC__ ? */
|
||||
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
|
||||
#define __int8_t_defined
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int int64_t;
|
||||
#endif
|
||||
|
||||
void *alloca(size_t);
|
||||
|
||||
#endif
|
||||
|
||||
115
win32/readme.txt
115
win32/readme.txt
@@ -1,115 +0,0 @@
|
||||
|
||||
TinyCC-PE
|
||||
---------
|
||||
|
||||
TinyCC (aka TCC) is a small but hyperfast C compiler,
|
||||
written by Fabrice Bellard,
|
||||
|
||||
|
||||
TinyCC-PE is the TinyCC compiler with an extension to
|
||||
write PE executables for MS-Windows.
|
||||
|
||||
|
||||
Features:
|
||||
---------
|
||||
|
||||
TinyCC-PE can produce console applications, native windows
|
||||
GUI programs and DLL's.
|
||||
|
||||
Most of the features pointed out by Fabrice Bellard for the
|
||||
original version are still valid, i.e:
|
||||
|
||||
- SMALL! The package with ~400kb includes a complete C-compiler
|
||||
with header files for console and GUI applications.
|
||||
|
||||
- With the -run switch you can run C-sources without any
|
||||
linking directly from the command line.
|
||||
|
||||
- TCC can of course compile itself.
|
||||
|
||||
|
||||
Compilation: (omit that if you use the binary ZIP package)
|
||||
------------
|
||||
|
||||
You must use the MinGW and MSYS tools available at
|
||||
http://www.mingw.org to compile TCC for Windows. Untar the TCC
|
||||
archive and type in the MSYS shell:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
TCC is installed in c:\Program Files\tcc
|
||||
|
||||
Installation: (from the binary ZIP package)
|
||||
-------------
|
||||
|
||||
Just unzip the package to a directory anywhere on your computer.
|
||||
|
||||
|
||||
Examples:
|
||||
---------
|
||||
|
||||
For the 'Fibonacci' console example type from the command line:
|
||||
|
||||
tcc examples\fib.c
|
||||
|
||||
|
||||
For the 'Hello Windows' GUI example:
|
||||
|
||||
tcc examples\hello_win.c
|
||||
|
||||
|
||||
For the 'Hello DLL' example:
|
||||
|
||||
tcc -shared examples\dll.c
|
||||
tcc examples\hello_dll.c examples\dll.def
|
||||
|
||||
|
||||
Import Definitions:
|
||||
-------------------
|
||||
|
||||
TinyCC-PE searches and reads import definition files similar
|
||||
to libraries.
|
||||
|
||||
The included 'tiny_impdef' program may be used to make .def files
|
||||
for any DLL, e.g for an 'opengl32.def':
|
||||
|
||||
tiny_impdef.exe opengl32.dll
|
||||
|
||||
or to the same effect:
|
||||
|
||||
tcc -lkernel32 -run tiny_impdef.c opengl32.dll
|
||||
|
||||
|
||||
Header Files:
|
||||
-------------
|
||||
|
||||
The system header files, except '_mingw.h', are from the
|
||||
2.0 mingw distribution. See also: http://www.mingw.org/
|
||||
|
||||
|
||||
Compile TCC:
|
||||
------------
|
||||
|
||||
With TCC itself just say:
|
||||
|
||||
tcc src\tcc.c -lkernel32 -o tcc.new.exe
|
||||
|
||||
Other compilers like mingw-gcc or msvc work as well.
|
||||
To make libtcc1.a, you need 'ar' from the mingw binutils.
|
||||
|
||||
|
||||
Documentation and License:
|
||||
--------------------------
|
||||
|
||||
TCC is distributed under the GNU Lesser General Public License
|
||||
(see COPYING file).
|
||||
|
||||
Please read the original tcc-doc.html to have all the features
|
||||
of TCC. Also visit: http://fabrice.bellard.free.fr/tcc/
|
||||
|
||||
|
||||
--------------------------------------------
|
||||
09.Apr.2005 - grischka@users.sourceforge.net
|
||||
|
||||
158
win32/tcc-win32.txt
Normal file
158
win32/tcc-win32.txt
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
TinyCC
|
||||
======
|
||||
|
||||
This file contains specific information for usage of TinyCC
|
||||
under MS-Windows. See tcc-doc.html to have all the features.
|
||||
|
||||
|
||||
|
||||
Compilation from source:
|
||||
------------------------
|
||||
* You can use the MinGW and MSYS tools available at
|
||||
|
||||
http://www.mingw.org
|
||||
|
||||
Untar the TCC archive and type in the MSYS shell:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
The default install location is c:\Program Files\tcc
|
||||
|
||||
|
||||
* Alternatively you can compile TCC with just GCC from MinGW using
|
||||
|
||||
win32\build-tcc.bat
|
||||
|
||||
To install, copy the entire contents of the win32 directory to
|
||||
where you want.
|
||||
|
||||
|
||||
|
||||
Installation from the binary ZIP package:
|
||||
-----------------------------------------
|
||||
Unzip the package to a directory of your choice.
|
||||
|
||||
(Note that the binary package does not include libtcc. If you
|
||||
want TCC as dynamic code generator, please use the source code
|
||||
distribution.)
|
||||
|
||||
|
||||
|
||||
Set the system PATH:
|
||||
--------------------
|
||||
To be able to invoke the compiler from everywhere on your computer by
|
||||
just typing "tcc", please add the directory containing tcc.exe to your
|
||||
system PATH.
|
||||
|
||||
|
||||
|
||||
Examples:
|
||||
---------
|
||||
Open a console window (DOS box) and 'cd' to the examples directory.
|
||||
|
||||
For the 'Fibonacci' example type:
|
||||
|
||||
tcc fib.c
|
||||
|
||||
For the 'Hello Windows' GUI example type:
|
||||
|
||||
tcc hello_win.c
|
||||
|
||||
for the 'Hello DLL' example type
|
||||
|
||||
tcc -shared dll.c
|
||||
tiny_impdef dll.dll (optional)
|
||||
tcc hello_dll.c dll.def
|
||||
|
||||
|
||||
|
||||
Import Definition Files:
|
||||
------------------------
|
||||
To link with Windows system DLLs, TCC uses import definition
|
||||
files (.def) instead of libraries.
|
||||
|
||||
The included 'tiny_impdef' program may be used to make additional
|
||||
.def files for any DLL. For example:
|
||||
|
||||
tiny_impdef.exe opengl32.dll
|
||||
|
||||
Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at
|
||||
the TCC commandline to link a program that uses opengl32.dll.
|
||||
|
||||
|
||||
|
||||
Header Files:
|
||||
-------------
|
||||
The system header files (except _mingw.h) are from the MinGW
|
||||
distribution:
|
||||
|
||||
http://www.mingw.org/
|
||||
|
||||
From the windows headers, only a minimal set is included. If you need
|
||||
more, get MinGW's "w32api" package.
|
||||
|
||||
|
||||
|
||||
Resource Files:
|
||||
---------------
|
||||
TCC can link windows resources in coff format as generated by MinGW's
|
||||
windres.exe. For example:
|
||||
|
||||
windres -O coff app.rc -o appres.o
|
||||
tcc app.c appres.o -o app.exe
|
||||
|
||||
|
||||
|
||||
Tiny Libmaker:
|
||||
--------------
|
||||
The included tiny_libmaker tool by Timovj Lahde can be used as
|
||||
'ar' replacement to make a library from several object files:
|
||||
|
||||
tiny_libmaker [rcs] library objectfiles ...
|
||||
|
||||
|
||||
|
||||
Limitations:
|
||||
------------
|
||||
- On the object file level, currently TCC supports only the ELF format,
|
||||
not COFF as used by MinGW and MSVC. It is not possible to exchange
|
||||
object files or libraries between TCC and these compilers. However
|
||||
libraries for TCC from objects by TCC can be made using tiny_libmaker
|
||||
or MinGW's ar.
|
||||
|
||||
- No leading underscore is generated in the ELF symbols.
|
||||
|
||||
- With DLLs, only functions (not data) can be im-/exported.
|
||||
|
||||
- Bounds checking (option -b) is not supported currently.
|
||||
|
||||
- 64-bit systems are not (yet) supported.
|
||||
|
||||
|
||||
|
||||
Documentation and License:
|
||||
--------------------------
|
||||
TCC is distributed under the GNU Lesser General Public License. (See
|
||||
COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)
|
||||
|
||||
TinyCC homepage is at:
|
||||
|
||||
http://fabrice.bellard.free.fr/tcc/
|
||||
|
||||
|
||||
|
||||
WinAPI Help and 3rd-party tools:
|
||||
--------------------------------
|
||||
The Windows API documentation (Win95) in a single .hlp file is
|
||||
available on the lcc-win32 site as "win32hlp.exe" or from other
|
||||
locations as "win32hlp_big.zip".
|
||||
|
||||
A nice RAD tool to create windows resources (dialog boxes etc.) is
|
||||
"ResEd", available at the RadASM website.
|
||||
|
||||
|
||||
|
||||
--- grischka
|
||||
393
win32/tools/tiny_impdef.c
Normal file
393
win32/tools/tiny_impdef.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
* tiny_impdef creates an export definition file (.def) from a dll
|
||||
* on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
|
||||
*
|
||||
* Copyright (c) 2005,2007 grischka
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Offset to PE file signature */
|
||||
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew))
|
||||
|
||||
/* MS-OS header identifies the NT PEFile signature dword;
|
||||
the PEFILE header exists just after that dword. */
|
||||
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE))
|
||||
|
||||
/* PE optional header is immediately after PEFile header. */
|
||||
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER)))
|
||||
|
||||
/* Section headers are immediately after PE optional header. */
|
||||
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER) + \
|
||||
sizeof (IMAGE_OPTIONAL_HEADER)))
|
||||
|
||||
|
||||
#define SIZE_OF_NT_SIGNATURE 4
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI NumOfSections (
|
||||
LPVOID lpFile)
|
||||
{
|
||||
/* Number of sections is indicated in file header. */
|
||||
return (int)
|
||||
((PIMAGE_FILE_HEADER)
|
||||
PEFHDROFFSET(lpFile))->NumberOfSections;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
LPVOID WINAPI ImageDirectoryOffset (
|
||||
LPVOID lpFile,
|
||||
DWORD dwIMAGE_DIRECTORY)
|
||||
{
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i = 0;
|
||||
LPVOID VAImageDir;
|
||||
|
||||
/* Retrieve offsets to optional and section headers. */
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
|
||||
|
||||
/* Must be 0 thru (NumberOfRvaAndSizes-1). */
|
||||
if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
|
||||
return NULL;
|
||||
|
||||
/* Locate image directory's relative virtual address. */
|
||||
VAImageDir = (LPVOID)poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;
|
||||
|
||||
/* Locate section containing image directory. */
|
||||
while (i++<nSections)
|
||||
{
|
||||
if (psh->VirtualAddress <= (DWORD)VAImageDir
|
||||
&& psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
|
||||
break;
|
||||
psh++;
|
||||
}
|
||||
|
||||
if (i > nSections)
|
||||
return NULL;
|
||||
|
||||
/* Return image import directory offset. */
|
||||
return (LPVOID)(((int)lpFile +
|
||||
(int)VAImageDir - psh->VirtualAddress) +
|
||||
(int)psh->PointerToRawData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByName (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
char *szSection)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (!strcmp (psh->Name, szSection))
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByAddress (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
DWORD addr)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (addr >= psh->VirtualAddress
|
||||
&& addr < psh->VirtualAddress + psh->SizeOfRawData)
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI GetExportFunctionNames (
|
||||
LPVOID lpFile,
|
||||
HANDLE hHeap,
|
||||
char **pszFunctions)
|
||||
{
|
||||
IMAGE_SECTION_HEADER sh;
|
||||
PIMAGE_EXPORT_DIRECTORY ped;
|
||||
int *pNames, *pCnt;
|
||||
char *pSrc, *pDest;
|
||||
int i, nCnt;
|
||||
DWORD VAImageDir;
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
char *pOffset;
|
||||
|
||||
/* Get section header and pointer to data directory
|
||||
for .edata section. */
|
||||
if (NULL == (ped = (PIMAGE_EXPORT_DIRECTORY)
|
||||
ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)))
|
||||
return 0;
|
||||
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
|
||||
if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir))
|
||||
return 0;
|
||||
|
||||
pOffset = (char *)lpFile + (sh.PointerToRawData - sh.VirtualAddress);
|
||||
|
||||
pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames);
|
||||
|
||||
/* Figure out how much memory to allocate for all strings. */
|
||||
nCnt = 1;
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc)
|
||||
nCnt += strlen(pSrc)+1;
|
||||
}
|
||||
|
||||
/* Allocate memory off heap for function names. */
|
||||
pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
|
||||
|
||||
/* Copy all strings to buffer. */
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc) {
|
||||
strcpy(pDest, pSrc);
|
||||
pDest += strlen(pSrc)+1;
|
||||
}
|
||||
}
|
||||
*pDest = 0;
|
||||
|
||||
return ped->NumberOfNames;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/* extract the basename of a file */
|
||||
|
||||
static char *file_basename(const char *name)
|
||||
{
|
||||
const char *p = strchr(name, 0);
|
||||
while (p > name
|
||||
&& p[-1] != '/'
|
||||
&& p[-1] != '\\'
|
||||
)
|
||||
--p;
|
||||
return (char*)p;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
HANDLE hHeap;
|
||||
HANDLE hFile;
|
||||
HANDLE hMapObject;
|
||||
VOID *pMem;
|
||||
|
||||
int nCnt, ret, n;
|
||||
char *pNames;
|
||||
char infile[MAX_PATH];
|
||||
char buffer[MAX_PATH];
|
||||
char outfile[MAX_PATH];
|
||||
FILE *op;
|
||||
char *p;
|
||||
|
||||
hHeap = NULL;
|
||||
hFile = NULL;
|
||||
hMapObject = NULL;
|
||||
pMem = NULL;
|
||||
infile[0] = 0;
|
||||
outfile[0] = 0;
|
||||
ret = 1;
|
||||
|
||||
for (n = 1; n < argc; ++n)
|
||||
{
|
||||
const char *a = argv[n];
|
||||
if ('-' == a[0]) {
|
||||
if (0 == strcmp(a, "-o")) {
|
||||
if (++n == argc)
|
||||
goto usage;
|
||||
strcpy(outfile, argv[n]);
|
||||
}
|
||||
else
|
||||
goto usage;
|
||||
|
||||
} else if (0 == infile[0])
|
||||
strcpy(infile, a);
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (0 == infile[0])
|
||||
{
|
||||
usage:
|
||||
fprintf(stderr,
|
||||
"tiny_impdef creates an export definition file (.def) from a dll\n"
|
||||
"Usage: tiny_impdef library.dll [-o outputfile]\n"
|
||||
);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL))
|
||||
strcpy(infile, buffer);
|
||||
|
||||
if (0 == outfile[0])
|
||||
{
|
||||
char *p;
|
||||
strcpy(outfile, file_basename(infile));
|
||||
p = strrchr(outfile, '.');
|
||||
if (NULL == p)
|
||||
p = strchr(outfile, 0);
|
||||
strcpy(p, ".def");
|
||||
}
|
||||
|
||||
hFile = CreateFile(
|
||||
infile,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "No such file: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
|
||||
hMapObject = CreateFileMapping(
|
||||
hFile,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0, 0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (NULL == hMapObject)
|
||||
{
|
||||
fprintf(stderr, "Could not create file mapping: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
pMem = MapViewOfFile(
|
||||
hMapObject, // object to map view of
|
||||
FILE_MAP_READ, // read access
|
||||
0, // high offset: map from
|
||||
0, // low offset: beginning
|
||||
0); // default: map entire file
|
||||
|
||||
if (NULL == pMem)
|
||||
{
|
||||
fprintf(stderr, "Could not map view of file: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (0 != strncmp(NTSIGNATURE(pMem), "PE", 2))
|
||||
{
|
||||
fprintf(stderr, "Not a PE file: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
|
||||
hHeap = GetProcessHeap();
|
||||
nCnt = GetExportFunctionNames(pMem, hHeap, &pNames);
|
||||
if (0 == nCnt) {
|
||||
fprintf(stderr, "Could not get exported function names: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
printf("--> %s\n", infile);
|
||||
|
||||
op = fopen(outfile, "w");
|
||||
if (NULL == op)
|
||||
{
|
||||
fprintf(stderr, "Could not create file: %s\n", outfile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
printf("<-- %s\n", outfile);
|
||||
|
||||
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(infile));
|
||||
for (n = 0, p = pNames; n < nCnt; ++n)
|
||||
{
|
||||
fprintf(op, "%s\n", p);
|
||||
while (*p++);
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
the_end:
|
||||
if (pMem)
|
||||
UnmapViewOfFile(pMem);
|
||||
|
||||
if (hMapObject)
|
||||
CloseHandle(hMapObject);
|
||||
|
||||
if (hFile)
|
||||
CloseHandle(hFile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
310
win32/tools/tiny_libmaker.c
Normal file
310
win32/tools/tiny_libmaker.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* This program is for making libtcc1.a without ar
|
||||
* tiny_libmaker - tiny elf lib maker
|
||||
* usage: tiny_libmaker [lib] files...
|
||||
* Copyright (c) 2007 Timppa
|
||||
*
|
||||
* This program is free software but WITHOUT ANY WARRANTY
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <io.h> /* for mktemp */
|
||||
#endif
|
||||
|
||||
/* #include "ar-elf.h" */
|
||||
/* "ar-elf.h" */
|
||||
/* ELF_v1.2.pdf */
|
||||
typedef unsigned short int Elf32_Half;
|
||||
typedef int Elf32_Sword;
|
||||
typedef unsigned int Elf32_Word;
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef unsigned short int Elf32_Section;
|
||||
|
||||
#define EI_NIDENT 16
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
} Elf32_Sym;
|
||||
|
||||
#define ELF32_ST_BIND(i) ((i)>>4)
|
||||
#define ELF32_ST_TYPE(i) ((i)&0xf)
|
||||
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
|
||||
|
||||
#define STT_NOTYPE 0
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
#define STT_SECTION 3
|
||||
#define STT_FILE 4
|
||||
#define STT_LOPROC 13
|
||||
#define STT_HIPROC 15
|
||||
|
||||
#define STB_LOCAL 0
|
||||
#define STB_GLOBAL 1
|
||||
#define STB_WEAK 2
|
||||
#define STB_LOPROC 13
|
||||
#define STB_HIPROC 15
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
} Elf32_Phdr;
|
||||
/* "ar-elf.h" ends */
|
||||
|
||||
#define ARMAG "!<arch>\n"
|
||||
#define ARFMAG "`\n"
|
||||
|
||||
typedef struct ArHdr {
|
||||
char ar_name[16];
|
||||
char ar_date[12];
|
||||
char ar_uid[6];
|
||||
char ar_gid[6];
|
||||
char ar_mode[8];
|
||||
char ar_size[10];
|
||||
char ar_fmag[2];
|
||||
} ArHdr;
|
||||
|
||||
|
||||
unsigned long le2belong(unsigned long ul) {
|
||||
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
|
||||
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
|
||||
}
|
||||
|
||||
ArHdr arhdr = {
|
||||
"/ ",
|
||||
" ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
" ",
|
||||
ARFMAG
|
||||
};
|
||||
|
||||
ArHdr arhdro = {
|
||||
" ",
|
||||
" ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
" ",
|
||||
ARFMAG
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fi, *fh, *fo;
|
||||
Elf32_Ehdr *ehdr;
|
||||
Elf32_Shdr *shdr;
|
||||
Elf32_Sym *sym;
|
||||
int i, fsize, iarg;
|
||||
char *buf, *shstr, *symtab = NULL, *strtab = NULL;
|
||||
int symtabsize = 0, strtabsize = 0;
|
||||
char *anames = NULL;
|
||||
int *afpos = NULL;
|
||||
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
|
||||
char afile[260], tfile[260], stmp[20];
|
||||
|
||||
|
||||
strcpy(afile, "ar_test.a");
|
||||
iarg = 1;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("usage: tiny_libmaker [lib] file...\n");
|
||||
return 1;
|
||||
}
|
||||
for (i=1; i<argc; i++) {
|
||||
istrlen = strlen(argv[i]);
|
||||
if (argv[i][istrlen-2] == '.') {
|
||||
if(argv[i][istrlen-1] == 'a')
|
||||
strcpy(afile, argv[i]);
|
||||
else if(argv[i][istrlen-1] == 'o') {
|
||||
iarg = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(tfile, "./XXXXXX");
|
||||
if (!mktemp(tfile) || (fo = fopen(tfile, "wb+")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open temporary file %s\n", tfile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ((fh = fopen(afile, "wb")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open file %s \n", afile);
|
||||
remove(tfile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
funcmax = 250;
|
||||
afpos = realloc(NULL, funcmax * sizeof *afpos); // 250 func
|
||||
memcpy(&arhdro.ar_mode, "100666", 6);
|
||||
|
||||
//iarg = 1;
|
||||
while (iarg < argc)
|
||||
{
|
||||
if (!strcmp(argv[iarg], "rcs")) {
|
||||
iarg++;
|
||||
continue;
|
||||
}
|
||||
if ((fi = fopen(argv[iarg], "rb")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open file %s \n", argv[iarg]);
|
||||
remove(tfile);
|
||||
return 2;
|
||||
}
|
||||
fseek(fi, 0, SEEK_END);
|
||||
fsize = ftell(fi);
|
||||
fseek(fi, 0, SEEK_SET);
|
||||
buf = malloc(fsize + 1);
|
||||
fread(buf, fsize, 1, fi);
|
||||
fclose(fi);
|
||||
|
||||
printf("%s:\n", argv[iarg]);
|
||||
// elf header
|
||||
ehdr = (Elf32_Ehdr *)buf;
|
||||
shdr = (Elf32_Shdr *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
|
||||
shstr = (char *)(buf + shdr->sh_offset);
|
||||
for (i = 0; i < ehdr->e_shnum; i++)
|
||||
{
|
||||
shdr = (Elf32_Shdr *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
|
||||
if (!shdr->sh_offset) continue;
|
||||
if (shdr->sh_type == SHT_SYMTAB)
|
||||
{
|
||||
symtab = (char *)(buf + shdr->sh_offset);
|
||||
symtabsize = shdr->sh_size;
|
||||
}
|
||||
if (shdr->sh_type == SHT_STRTAB)
|
||||
{
|
||||
if (!strcmp(shstr + shdr->sh_name, ".strtab"))
|
||||
{
|
||||
strtab = (char *)(buf + shdr->sh_offset);
|
||||
strtabsize = shdr->sh_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (symtab && symtabsize)
|
||||
{
|
||||
int nsym = symtabsize / sizeof(Elf32_Sym);
|
||||
//printf("symtab: info size shndx name\n");
|
||||
for (i = 1; i < nsym; i++)
|
||||
{
|
||||
sym = (Elf32_Sym *) (symtab + i * sizeof(Elf32_Sym));
|
||||
if (sym->st_shndx && (sym->st_info == 0x11 || sym->st_info == 0x12)) {
|
||||
//printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
|
||||
istrlen = strlen(strtab + sym->st_name)+1;
|
||||
anames = realloc(anames, strpos+istrlen);
|
||||
strcpy(anames + strpos, strtab + sym->st_name);
|
||||
strpos += istrlen;
|
||||
if (++funccnt >= funcmax) {
|
||||
funcmax += 250;
|
||||
afpos = realloc(afpos, funcmax * sizeof *afpos); // 250 func more
|
||||
}
|
||||
afpos[funccnt] = fpos;
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(&arhdro.ar_name, ' ', sizeof(arhdr.ar_name));
|
||||
strcpy(arhdro.ar_name, argv[iarg]);
|
||||
arhdro.ar_name[strlen(argv[iarg])] = '/';
|
||||
sprintf(stmp, "%-10d", fsize);
|
||||
memcpy(&arhdro.ar_size, stmp, 10);
|
||||
fwrite(&arhdro, sizeof(arhdro), 1, fo);
|
||||
fwrite(buf, fsize, 1, fo);
|
||||
free(buf);
|
||||
iarg++;
|
||||
fpos += (fsize + sizeof(arhdro));
|
||||
}
|
||||
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
|
||||
if ((hofs & 1)) { // align
|
||||
hofs++;
|
||||
fpos = 1;
|
||||
} else fpos = 0;
|
||||
// write header
|
||||
fwrite("!<arch>\n", 8, 1, fh);
|
||||
sprintf(stmp, "%-10d", strpos + (funccnt+1) * sizeof(int));
|
||||
memcpy(&arhdr.ar_size, stmp, 10);
|
||||
fwrite(&arhdr, sizeof(arhdr), 1, fh);
|
||||
afpos[0] = le2belong(funccnt);
|
||||
for (i=1; i<=funccnt; i++) {
|
||||
afpos[i] = le2belong(afpos[i] + hofs);
|
||||
}
|
||||
fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
|
||||
fwrite(anames, strpos, 1, fh);
|
||||
if (fpos) fwrite("", 1, 1, fh);
|
||||
// write objects
|
||||
fseek(fo, 0, SEEK_END);
|
||||
fsize = ftell(fo);
|
||||
fseek(fo, 0, SEEK_SET);
|
||||
buf = malloc(fsize + 1);
|
||||
fread(buf, fsize, 1, fo);
|
||||
fclose(fo);
|
||||
fwrite(buf, fsize, 1, fh);
|
||||
fclose(fh);
|
||||
free(buf);
|
||||
if (anames)
|
||||
free(anames);
|
||||
if (afpos)
|
||||
free(afpos);
|
||||
remove(tfile);
|
||||
return 0;
|
||||
}
|
||||
1419
x86_64-gen.c
Normal file
1419
x86_64-gen.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user