diff --git a/Makefile b/Makefile index 34203318..efa6c008 100644 --- a/Makefile +++ b/Makefile @@ -1,61 +1,92 @@ -all: test cvt +# +# Tiny C Compiler Makefile +# +prefix=/usr/local -test: prog.bin - cmp -l prog.bin prog.bin.ref +CFLAGS=-O2 -g -Wall -Wno-parentheses -I. +LIBS=-ldl +#CFLAGS=-O2 -g -Wall -Wno-parentheses -I. -pg -static -DPROFILE +#LIBS= + +CFLAGS+=-m386 -malign-functions=0 +DISAS=objdump -D -b binary -m i386 +INSTALL=install +VERSION=0.9 + +all: tcc + +# auto test + +test: test.ref test.out + @if diff -u test.ref test.out ; then echo "Auto Test OK"; fi + +prog.ref: prog.c + gcc $(CFLAGS) -o $@ $< + +test.ref: prog.ref + ./prog.ref > $@ + +test.out: tcc prog.c + ./tcc -I. prog.c > $@ run: tcc prog.c - ./tcc prog.c + ./tcc -I. prog.c -run2: tcc tcc1.c prog.c - ./tcc tcc1.c prog.c +run2: tcc tcc.c prog.c + ./tcc -I. tcc.c -I. prog.c -run3: tcc tcc1.c prog.c - ./tcc tcc1.c tcc1.c prog.c +run3: tcc tcc.c prog.c + ./tcc -I. tcc.c -I. tcc.c -I. prog.c -prog.bin: prog.c tcc - ./tc prog.c $@ - ndisasm -b 32 $@ +# 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 -p2.bin: p2.c tcc - ./tcc $< $@ - ndisasm -b 32 $@ +ex2: ex2.c + gcc $(CFLAGS) -o $@ $< + +ex3: ex3.c + gcc $(CFLAGS) -o $@ $< # Tiny C Compiler -tcc: tcc.c - gcc -O2 -Wall -g -o $@ $< -ldl +tcc_g: tcc.c Makefile + gcc $(CFLAGS) -o $@ $< $(LIBS) -tcc1: tcc1.c - gcc -O2 -Wall -g -o $@ $< +tcc: tcc_g + strip -s -R .comment -R .note -o $@ $< -tcc1.i: tcc.c Makefile - gcc -E -P -o $@ $< +install: tcc + $(INSTALL) -m755 tcc $(prefix)/bin + mkdir -p $(prefix)/lib/tcc + $(INSTALL) -m644 stdarg.h stddef.h tcclib.h $(prefix)/lib/tcc -tcc1.c: tcc1.i cvt Makefile - ./cvt -d $< $@ - @ls -l $@ +clean: + rm -f *~ *.o tcc tcc1 tcct tcc_g prog.ref *.bin *.i ex2 \ + core gmon.out test.out test.ref a.out -# obfuscated C compiler -otcc: otcc.c - gcc -O2 -Wall -g -o $@ $< -ldl +# target for development -otcc.i: otcc.c Makefile - gcc -E -P -DTINY -o $@ $< +%.bin: %.c tcct + ./tcct -I. $< $@ + $(DISAS) $@ -otcc1.c: otcc.i cvt Makefile - ./cvt $< $@ - @ls -l $@ - -orun: otcc otcc1.c - ./otcc otcc1.c ex1.c - -# misc - -cvt: cvt.c - gcc -O2 -Wall -g -o $@ $< +tcct: tcc.c + gcc -DTEST $(CFLAGS) -o $@ $< -ldl instr.o: instr.S gcc -O2 -Wall -g -c -o $@ $< -clean: - rm -f *~ *.o tcc tcc1 cvt +FILE=tcc-$(VERSION) + +tar: + rm -rf /tmp/$(FILE) + cp -r ../tcc /tmp/$(FILE) + ( cd /tmp ; tar zcvf ~/$(FILE).tar.gz \ + $(FILE)/Makefile $(FILE)/README $(FILE)/TODO $(FILE)/COPYING \ + $(FILE)/tcc.c $(FILE)/stddef.h $(FILE)/stdarg.h $(FILE)/tcclib.h \ + $(FILE)/ex*.c $(FILE)/prog.c ) + rm -rf /tmp/$(FILE) diff --git a/README b/README index 77695992..76fe675a 100644 --- a/README +++ b/README @@ -1,23 +1,5 @@ -Tiny C Compiler - Make the best x86 Linux C compiler in less than 8192 bytes. ------------------------------------------------------------------------------ - -Differences with ANSI C: ------------------------ - -- Preprocessor: only '#define xx yy' is supported. Recursive defined - supported. All other directives are not supported. - -- Types: int, char, void, pointers and functions are - supported. Function pointers are also supported. struct, union and - typedef not supported. - -- Operations: 'x=' not supported. - -- Keywords: the following keywords are supported: int void char if - else while break return for. - -- Symbol scope: local variables supported, but they cannot have the - same name as global variables. +Tiny C Compiler - C Scripting Everywhere - The Smallest ANSI C compiler +----------------------------------------------------------------------- Features: -------- @@ -25,25 +7,123 @@ Features: - SMALL! You can compile and execute C code everywhere, for example on rescue disks. -- FAST! tcc generate x86 code. No byte code overhead. +- FAST! tcc generates optimized x86 code. No byte code overhead. -- Compile and execute C source directly. No linking necessary. +- UNLIMITED! Any C dynamic library can be used directly. TCC is + heading torwards full ANSI C compliance. TCC can of course compile + itself. -- C script supported : just add '#!/usr/bin/tcc' at the first line of - your C source, and execute it directly from the command line ! +- Compile and execute C source directly. No linking or assembly + necessary. Full C preprocessor included. -- All C library functions can be used via dynamic linking. +- C script supported : just add '#!/usr/local/bin/tcc' at the first + line of your C source, and execute it directly from the command line ! -------------------------------------------------------------------------- -An even smaller compiler can be build from tcc by activating the -define 'TINY'. The following changes from tcc: +- For adventurers, tcc is conceived to be able to generate code for + other targets. -- Comments are not supported. +Documentation: +------------- -- Parsing: No char constants. No '\r' and '\t' in strings. Only base - 10 numbers are supported. +1) Installation -- no 'for' loops. +***TCC currently only work on Linux x86***. -- Operations: '?:', ',', 'x=', shifts, '&&', '||', '!', '~' not supported. +Type 'make install' to compile and install tcc in /usr/local and +/usr/local/lib/tcc. +2) Introduction + +We assume here that you know ANSI C. Look at the example ex1.c to know +what the programs look like. + +The main limitations of tcc are that you cannot use floats. + +The include file can be used if you want a small basic libc +include support (especially useful for floppy disks). Of course, you +can also use standard headers, although they are slower to compile. + +You can begin your C script with '#!/usr/local/bin/tcc' on the first +line and set its execute bits (chmod a+x your_script). Then, you can +launch the C code as a shell or perl script :-) The command line +arguments are put in 'argc' and 'argv' of the main functions, as in +ANSI C. + +3) Invokation + +'-Idir' : specify an additionnal include path. The +default ones are: /usr/include, /usr/lib/tcc, /usr/local/lib/tcc. + +'-Dsym' : define preprocessor symbol 'sym' to 1. + +'-lxxx' : dynamically link your program with library +libxxx.so. Standard library paths are checked, including those +specificed with LD_LIBRARY_PATH. + +Only one source code can be compiled. If you have multiple source +files, add one which includes all your sources. + +4) Examples + +ex1.c: simplest example (hello world). Can also be launched directly +as a script: ./ex2.c. + +ex2.c: more complicated example: find a number with the four +operations given a list of numbers (benchmark). + +ex3.c: compute fibonacci numbers (benchmark). + +ex4.c: more complicated: X11 program. Very complicated test in fact +because standard headers are being used ! Currently slow because +parsing does not use hash tables. + +ex5.c: 'hello world' with standard glibc headers. + +tcc.c: TCC can compile itself. Used to check the code generator. + +prog.c: auto test for TCC which tests many subtle possible bugs. Used +when doing 'make test'. + +Exact differences with ANSI C: +----------------------------- + +1) Preprocessor + + - the preprocessor tokens are the same as C. It means that in some + rare cases, preprocessed numbers are not handled exactly as in ANSI + C. This approach has the advantage of being simpler and FAST! + + - __LINE__, __FILE__, __DATE__, __TIME__ are currently not handled. + + - #line not handled + +2) C language + +- Parsing: variables cannot be initialized ('int a = 1' or 'int tab[2] = + {1, 2}' not supported). + +- Cannot pass struct/union as value. Cannot assign struct/union (use + memcpy instead). + +- Types: floating point numbers are not supported. + +- (BUG) 'char' and 'short' casts do not truncate correctly. + +- 'sizeof' may not work if too complex expression is given. + +Supported C extensions: +---------------------- + +- 'inline' keyword is ignored. + + +License: +------- + +TCC is distributed under the GNU Generic Public License (see COPYING +file). + +I accept only patches where you give your copyright explictely to me +to simplify licensing issues. + +Fabrice Bellard - Nov 11, 2001. \ No newline at end of file diff --git a/TODO b/TODO index 1c2ce0db..78e442a1 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,15 @@ +TODO list: -- static arrays -- external symbols (vars) -- continue/do while/switch/case/goto -- 'x'= -- constant propagation for '+', '-' and []. -- verify function types +Critical: + +- add hash tables for symbols (useful for long programs) +- 0 is pointer - fix type compare +- add message if external function or variable not found. + +Not critical: + +- fix preprocessor symbol redefinition +- better constant opt (&&, ||, ?:) +- function pointers to forward reference (patch code generator) +- add PowerPC code generator. +- add portable byte code generator and interpreter. diff --git a/stdarg.h b/stdarg.h index 67b9c717..5e5d0286 100644 --- a/stdarg.h +++ b/stdarg.h @@ -4,8 +4,12 @@ typedef char *va_list; /* only correct for i386 */ -#define va_start(ap,last) ap=(char *)&(last); -#define va_arg(ap,type) (ap-=sizeof (type), *(type *)(ap)) +/* XXX: incorrect for type size different than 4 bytes*/ +#define va_start(ap,last) ap = ((char *)&(last)) + sizeof(int); +#define va_arg(ap,type) (ap += sizeof(int), *(type *)(ap - sizeof(int))) #define va_end(ap) +/* fix a buggy dependency on GCC in libio.h */ +typedef va_list __gnuc_va_list; + #endif diff --git a/stddef.h b/stddef.h index 48560373..5e7a8671 100644 --- a/stddef.h +++ b/stddef.h @@ -3,7 +3,7 @@ /* TCC include file */ #define NULL ((void *)0) - typedef unsigned int size_t; +typedef int wchar_t; #endif diff --git a/tcclib.h b/tcclib.h index 67deeecd..d269434d 100644 --- a/tcclib.h +++ b/tcclib.h @@ -19,6 +19,9 @@ unsigned long int strtoul(const char *nptr, char **endptr, int base); /* stdio.h */ typedef struct __FILE FILE; #define EOF (-1) +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; FILE *fopen(const char *path, const char *mode); FILE *fdopen(int fildes, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *stream); @@ -58,6 +61,10 @@ void *memset(void *s, int c, size_t n); char *strdup(const char *s); /* dlfcn.h */ +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 + void *dlopen(const char *filename, int flag); const char *dlerror(void); void *dlsym(void *handle, char *symbol);