65 Commits

Author SHA1 Message Date
bellard
0b8d7f44b4 update 2004-11-08 20:52:04 +00:00
bellard
27feb1adac gcc 3.4 fix 2004-11-07 18:08:15 +00:00
bellard
1c1919072b update 2004-11-07 15:51:57 +00:00
bellard
be5e9cb962 pool for symbol allocation 2004-11-07 15:45:40 +00:00
bellard
48c85f1b15 optimisations: hash table for include file search, pool for symbol allocation - sympler token string allocation - '-b' fix with '-run' option 2004-11-07 15:45:19 +00:00
bellard
398e22c541 gcc 3.4 compile fix 2004-11-07 15:43:33 +00:00
bellard
6bbfb8f610 removed warnings 2004-11-07 15:43:15 +00:00
bellard
1d0e5e8b01 stack full fix 2004-11-02 21:55:13 +00:00
bellard
1e1d3ff687 packed attribute support 2004-10-29 23:55:13 +00:00
bellard
736b565766 fixed const and volatile function parameters typing - fixed string parsing when skipping code 2004-10-28 21:14:30 +00:00
bellard
c2ec76a41f gcc 3.3 compatibility fix for multi-line string literals 2004-10-28 21:13:47 +00:00
bellard
6b52984ce4 added _Bool in bit-fields 2004-10-27 21:42:06 +00:00
bellard
c9c05ca5f0 copyright update 2004-10-27 21:38:03 +00:00
bellard
32ba2eadf6 compile fix 2004-10-27 21:29:50 +00:00
bellard
3e74b91de6 correct libtcc1 link order 2004-10-27 21:24:42 +00:00
bellard
e657dfb491 added .quad asm directive 2004-10-25 18:54:29 +00:00
bellard
2a6c104722 update 2004-10-23 23:11:05 +00:00
bellard
38e8a23025 fixed linker symbol generation - output format support 2004-10-23 22:53:42 +00:00
bellard
bb07bf31aa update 2004-10-23 22:52:58 +00:00
bellard
eb79471184 added .ascii and .asciz directives 2004-10-23 22:52:42 +00:00
bellard
59c3563827 do not generate code for unused inline functions - fixed long long code gen bug - added --oformat linker option 2004-10-23 22:52:05 +00:00
bellard
45466d2df6 output format support 2004-10-23 22:49:08 +00:00
bellard
807321efba update 2004-10-18 00:20:41 +00:00
bellard
ff3a5daf25 _end symbol definition fix - fixed section alignment logic 2004-10-18 00:20:26 +00:00
bellard
0bd402d2eb absolute symbols support - .org, .fill and .previous directives 2004-10-18 00:19:51 +00:00
bellard
9668499b9f primitive fastcall functions support - -fno-common option - -Ttext linker option - bit field fixes - section alignment fixes 2004-10-18 00:18:20 +00:00
bellard
72a88fbab0 primitive fastcall functions support 2004-10-18 00:14:40 +00:00
bellard
4d9f6d2bcf push/pop fixes - added fxsave and fxrstor 2004-10-18 00:14:16 +00:00
bellard
d65463809c fixed 'no base' modrm generation - better asm constraints handling 2004-10-18 00:13:39 +00:00
bellard
62f99adb71 update 2004-10-18 00:12:31 +00:00
bellard
aa7ef7919e copy paste abuse 2004-10-08 22:02:01 +00:00
bellard
13affef3f1 win32 configure 2004-10-07 21:11:43 +00:00
bellard
c50af8399d fixed __LINE__ token type 2004-10-07 20:15:50 +00:00
bellard
ec7d36326d C67 COFF executable format support (TK) 2004-10-05 22:33:55 +00:00
bellard
bf45336afb initial TMS320C67xx support (TK) 2004-10-05 17:55:18 +00:00
bellard
6e5b1cc43a ARM fixes (Daniel Glockner) 2004-10-04 22:19:21 +00:00
bellard
3bd3c71fd1 faster (Daniel Glöckner) 2004-10-04 22:06:22 +00:00
bellard
79c72b2419 initial TMS320C67xx support (TK) 2004-10-04 21:57:35 +00:00
bellard
df36de6507 fixes for dietlibc 2004-10-02 14:11:28 +00:00
bellard
c52df4de38 dietlibc support 2004-10-02 14:03:39 +00:00
bellard
8da6027e73 both .globl and .global directives are accepted by as 2004-10-02 14:01:26 +00:00
bellard
c1265d1616 update 2004-10-02 13:50:47 +00:00
bellard
22d8df96c6 comment parsing fix - bitfields partial fix 2004-10-02 13:48:50 +00:00
bellard
8da2d689df install fix 2004-10-02 13:46:33 +00:00
bellard
fe203057c2 fixed assignment of const struct in struct 2003-10-17 20:59:15 +00:00
bellard
114883e078 added -funsigned-char, -fsigned-char and -Wimplicit-function-declaration 2003-10-17 20:43:47 +00:00
bellard
7a5123a770 update 2003-10-14 22:22:54 +00:00
bellard
4df5bd2eb0 ARM target support (Daniel Glockner) - allow unsigned char as default on ARM (Daniel Glockner) - fixed small ld script support (Daniel Glockner) 2003-10-14 22:15:56 +00:00
bellard
44cea6aee9 update 2003-10-05 10:21:28 +00:00
bellard
77a19bf50e update 2003-10-05 09:48:53 +00:00
bellard
b7f12dfbdf update 2003-10-04 21:29:04 +00:00
bellard
9890ea1233 added examples 2003-10-04 21:25:32 +00:00
bellard
feed3262c9 fixed libc linking when running in memory 2003-10-04 21:24:46 +00:00
bellard
bef8703f77 added arguments to -run - fixed libc linking when running in memory - output a warning instead of an error if invalid escaped sequence in character 2003-10-04 21:23:51 +00:00
bellard
46169b92d9 .gnu.linkonce section support (useful to link with recent glibc) 2003-10-04 14:45:23 +00:00
bellard
d369a77647 unbounded section name (might be useful when section name contains function name for g++ linkonce sections) 2003-10-04 14:41:18 +00:00
bellard
c5ce5eaeda fixed -w option - doc update (thanx to Romain Francoise) 2003-10-04 13:04:47 +00:00
bellard
9c1106d854 added -w option 2003-09-19 20:35:50 +00:00
bellard
f8d0241764 changed tcc_get_symbol() prototype 2003-07-20 19:19:58 +00:00
bellard
c5959b77b4 fixed typdefed type parsing (Mauro Persano) 2003-07-20 18:44:29 +00:00
bellard
7b940fcb1b reject abstract declarators in function definition (Mauro Persano) 2003-07-20 12:40:53 +00:00
bellard
21d2d99bdc suppressed warning for const function parameters 2003-06-02 20:32:30 +00:00
bellard
277e01cd64 const warning test 2003-06-02 20:31:46 +00:00
bellard
9d95be78c8 added init_array defines for new ld compatibility 2003-05-29 22:52:53 +00:00
bellard
370f5e571c added missing texi2pod.pl 2003-05-24 18:31:27 +00:00
32 changed files with 7648 additions and 697 deletions

View File

@@ -2,8 +2,6 @@ tcc_g
tcc
tc2.c
ex3
ex1.c
ex2.c
otcc1.c
doc
tc3s.c
@@ -11,14 +9,11 @@ p3.c
tc1.c
error.c
i386-gen1.c
ex4.c
test.out2
test.out3
web.sh
ex3.c
memdebug.c
bench
ex5.c
tcc-newparse.c
p1.c
Makefile.uClibc

View File

@@ -1,3 +1,42 @@
version 0.9.22:
- simple memory optimisations: kernel compilation is 30% faster
- linker symbol definitions fixes
- gcc 3.4 fixes
- fixed value stack full error
- 'packed' attribute support for variables and structure fields
- ignore 'const' and 'volatile' in function prototypes
- allow '_Bool' in bit fields
version 0.9.21:
- ARM target support (Daniel Glöckner)
- added '-funsigned-char, '-fsigned-char' and
'-Wimplicit-function-declaration'
- fixed assignment of const struct in struct
- line comment fix (reported by Bertram Felgenhauer)
- initial TMS320C67xx target support (TK)
- win32 configure
- regparm() attribute
- many built-in assembler fixes
- added '.org', '.fill' and '.previous' assembler directives
- '-fno-common' option
- '-Ttext' linker option
- section alignment fixes
- bit fields fixes
- do not generate code for unused inline functions
- '-oformat' linker option.
- added 'binary' output format.
version 0.9.20:
- added '-w' option
- added '.gnu.linkonce' ELF sections support
- fixed libc linking when running in memory (avoid 'stat' function
errors).
- extended '-run' option to be able to give several arguments to a C
script.
version 0.9.19:
- "alacarte" linking (Dave Long)

View File

@@ -4,7 +4,10 @@
include config.mak
CFLAGS=-O2 -g -Wall
ifndef CONFIG_WIN32
LIBS=-ldl
BCHECK_O=bcheck.o
endif
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
LIBS_P=
@@ -12,16 +15,18 @@ CFLAGS+=-mpreferred-stack-boundary=2
ifeq ($(GCC_MAJOR),2)
CFLAGS+=-m386 -malign-functions=0
else
CFLAGS+=-march=i386 -falign-functions=0
CFLAGS+=-march=i386 -falign-functions=0 -fno-strict-aliasing
endif
DISAS=objdump -d
INSTALL=install
PROGS=tcc$(EXESUF) c67-tcc$(EXESUF) arm-tcc$(EXESUF)
# run local version of tcc with local libraries and includes
TCC=./tcc -B. -I.
all: tcc libtcc1.a bcheck.o tcc-doc.html tcc.1 libtcc.a libtcc_test
all: $(PROGS) \
libtcc1$(LIBSUF) $(BCHECK_O) tcc-doc.html tcc.1 libtcc$(LIBSUF) \
libtcc_test$(EXESUF)
Makefile: config.mak
@@ -108,17 +113,23 @@ ex3: ex3.c
# Native Tiny C Compiler
tcc_g: tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h Makefile
tcc_g$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h Makefile
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
tcc: tcc_g Makefile
strip -s -R .comment -R .note -o $@ $<
tcc$(EXESUF): tcc_g$(EXESUF) Makefile
$(STRIP) -o $@ $<
c67-tcc$(EXESUF): tcc.c c67-gen.c tccelf.c tccasm.c tcctok.h libtcc.h tcccoff.c Makefile
$(CC) $(CFLAGS) -DTCC_TARGET_C67 -o $@ $< $(LIBS)
arm-tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h Makefile
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
# TinyCC runtime libraries
libtcc1.o: libtcc1.c
$(CC) -O2 -Wall -c -o $@ $<
libtcc1.a: libtcc1.o
libtcc1$(LIBSUF): libtcc1.o
$(AR) rcs $@ $^
bcheck.o: bcheck.c
@@ -126,48 +137,49 @@ bcheck.o: bcheck.c
install: tcc_install libinstall
tcc_install: tcc tcc.1 libtcc1.a bcheck.o
$(INSTALL) -m755 tcc $(bindir)
$(INSTALL) tcc.1 $(mandir)/man1
mkdir -p $(libdir)/tcc
mkdir -p $(libdir)/tcc/include
$(INSTALL) -m644 libtcc1.a bcheck.o $(libdir)/tcc
tcc_install: $(PROGS) tcc.1 libtcc1$(LIBSUF) $(BCHECK_O) tcc-doc.html tcc.1
mkdir -p "$(bindir)"
$(INSTALL) -s -m755 $(PROGS) "$(bindir)"
ifndef CONFIG_WIN32
mkdir -p "$(mandir)/man1"
$(INSTALL) tcc.1 "$(mandir)/man1"
endif
mkdir -p "$(libdir)/tcc"
mkdir -p "$(libdir)/tcc/include"
$(INSTALL) -m644 libtcc1$(LIBSUF) $(BCHECK_O) "$(libdir)/tcc"
$(INSTALL) -m644 stdarg.h stddef.h stdbool.h float.h varargs.h \
tcclib.h $(libdir)/tcc/include
tcclib.h "$(libdir)/tcc/include"
mkdir -p "$(docdir)"
$(INSTALL) -m644 tcc-doc.html "$(docdir)"
clean:
rm -f *~ *.o tcc tcc1 tcct tcc_g tcctest.ref *.bin *.i ex2 \
core gmon.out test.out test.ref a.out tcc_p \
*.exe tcc-doc.html tcc.pod tcc.1 libtcc.a libtcc_test \
tcctest[1234] test[1234].out
*.exe tcc-doc.html tcc.pod tcc.1 libtcc$(LIBSUF) libtcc_test \
tcctest[1234] test[1234].out c67-tcc arm-tcc
distclean: clean
rm -f config.h config.mak config.texi
# win32 TCC
tcc_g.exe: tcc.c i386-gen.c bcheck.c Makefile
i386-mingw32msvc-gcc $(CFLAGS) -DCONFIG_TCC_STATIC -o $@ $<
tcc.exe: tcc_g.exe
i386-mingw32msvc-strip -o $@ $<
# profiling version
tcc_p: tcc.c Makefile
$(CC) $(CFLAGS_P) -o $@ $< $(LIBS_P)
# libtcc generation and example
libinstall: libtcc.a
$(INSTALL) -m644 libtcc.a $(libdir)
$(INSTALL) -m644 libtcc.h $(includedir)
libinstall: libtcc$(LIBSUF)
mkdir -p "$(libdir)"
$(INSTALL) -m644 libtcc$(LIBSUF) "$(libdir)"
mkdir -p "$(includedir)"
$(INSTALL) -m644 libtcc.h "$(includedir)"
libtcc.o: tcc.c i386-gen.c bcheck.c Makefile
libtcc.o: tcc.c i386-gen.c Makefile
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
libtcc.a: libtcc.o
libtcc$(LIBSUF): libtcc.o
$(AR) rcs $@ $^
libtcc_test: libtcc_test.c libtcc.a
$(CC) $(CFLAGS) -I. -o $@ $< -L. -ltcc -ldl
libtcc_test$(EXESUF): libtcc_test.c libtcc$(LIBSUF)
$(CC) $(CFLAGS) -o $@ $< libtcc$(LIBSUF) $(LIBS)
libtest: libtcc_test
./libtcc_test
@@ -216,13 +228,15 @@ FILES= Makefile Makefile.uClibc configure VERSION \
README TODO COPYING \
Changelog tcc-doc.texi tcc-doc.html \
tcc.1 \
tcc.c i386-gen.c tccelf.c tcctok.h tccasm.c i386-asm.c i386-asm.h\
tcc.c tccelf.c tcctok.h tccasm.c i386-asm.c i386-asm.h \
tcccoff.c coff.h \
i386-gen.c c67-gen.c arm-gen.c \
bcheck.c libtcc1.c \
elf.h stab.h stab.def \
stddef.h stdarg.h stdbool.h float.h varargs.h \
tcclib.h libtcc.h libtcc_test.c \
ex1.c ex2.c ex3.c ex4.c ex5.c \
tcctest.c boundtest.c gcctestsuite.sh
tcctest.c boundtest.c gcctestsuite.sh texi2pod.pl
FILE=tcc-$(VERSION)

2
README
View File

@@ -50,7 +50,7 @@ The include file <tcclib.h> 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
You can begin your C script with '#!/usr/local/bin/tcc -run' 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

12
TODO
View File

@@ -1,5 +1,14 @@
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
- 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
@@ -11,7 +20,6 @@ TODO list:
- '-b' bug.
- atexit (Nigel Horne)
- see -lxxx bug (Michael Charity).
- handle inline functions as macros.
- 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 ?
@@ -26,14 +34,12 @@ TODO list:
- check section alignment in C
- fix invalid cast in comparison 'if (v == (int8_t)v)'
- packed attribute
- support link once trick (gcc 3.2 / glibc compilation issue)
- finish varargs.h support (gcc 3.2 testsuite issue)
- fix static functions declared inside block
- 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
- look at GCC 3.2 compatibility problems.
- 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

View File

@@ -1 +1 @@
0.9.19
0.9.22

1386
arm-gen.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,8 @@ movl $2, 0x100(%ebx,%edx,2)
movl %eax, 0x100(%ebx,%edx,2)
movl 0x100(%ebx,%edx,2), %edx
movw %ax, 0x100(%ebx,%edx,2)
mov %eax, 0x12(,%edx,2)
mov %cr3, %edx
mov %ecx, %cr3
@@ -520,6 +522,8 @@ int $0x10
bts %edx, 0x1000
btsl $2, 0x1000
boundl %edx, 0x10000
boundw %bx, 0x1000
@@ -540,3 +544,15 @@ int $0x10
verr 0x1000
verw 0x1000
push %ds
pushw %ds
pushl %ds
pop %ds
popw %ds
popl %ds
fxsave 1(%ebx)
fxrstor 1(%ecx)
pushl $1
pushw $1
push $1

View File

@@ -36,7 +36,7 @@
#define HAVE_MEMALIGN
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__dietlibc__)
#warning Bound checking not fully supported on FreeBSD
#undef CONFIG_TCC_MALLOC_HOOKS
#undef HAVE_MEMALIGN
@@ -74,19 +74,7 @@ void __bound_init(void);
void __bound_new_region(void *p, unsigned long size);
int __bound_delete_region(void *p);
/* currently, tcc cannot compile that because we use unsupported GNU C
extensions */
#if !defined(__TINYC__)
void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir1(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir2(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir4(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir8(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir12(void *p, int offset) __attribute__((regparm(2)));
void *__bound_ptr_indir16(void *p, int offset) __attribute__((regparm(2)));
void __bound_local_new(void *p) __attribute__((regparm(1)));
void __bound_local_delete(void *p) __attribute__((regparm(1)));
#endif
#define FASTCALL __attribute__((regparm(3)))
void *__bound_malloc(size_t size, const void *caller);
void *__bound_memalign(size_t size, size_t align, const void *caller);
@@ -168,7 +156,7 @@ static void bound_alloc_error(void)
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */
void *__bound_ptr_add(void *p, int offset)
void * FASTCALL __bound_ptr_add(void *p, int offset)
{
unsigned long addr = (unsigned long)p;
BoundEntry *e;
@@ -194,7 +182,7 @@ void *__bound_ptr_add(void *p, int offset)
/* return '(p + offset)' for pointer indirection (the resulting must
be strictly inside the region */
#define BOUND_PTR_INDIR(dsize) \
void *__bound_ptr_indir ## dsize (void *p, int offset) \
void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
{ \
unsigned long addr = (unsigned long)p; \
BoundEntry *e; \
@@ -227,7 +215,7 @@ void *__bound_ptr_indir ## dsize (void *p, int offset) \
#endif
/* called when entering a function to add all the local regions */
void __bound_local_new(void *p1)
void FASTCALL __bound_local_new(void *p1)
{
unsigned long addr, size, fp, *p = p1;
GET_CALLER_FP(fp);
@@ -243,7 +231,7 @@ void __bound_local_new(void *p1)
}
/* called when leaving a function to delete all the local regions */
void __bound_local_delete(void *p1)
void FASTCALL __bound_local_delete(void *p1)
{
unsigned long addr, fp, *p = p1;
GET_CALLER_FP(fp);
@@ -782,7 +770,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
{
void *ptr;
size = size * nmemb;
ptr = __bound_malloc(size);
ptr = __bound_malloc(size, NULL);
if (!ptr)
return NULL;
memset(ptr, 0, size);

2548
c67-gen.c Normal file

File diff suppressed because it is too large Load Diff

446
coff.h Normal file
View File

@@ -0,0 +1,446 @@
/**************************************************************************/
/* COFF.H */
/* COFF data structures and related definitions used by the linker */
/**************************************************************************/
/*------------------------------------------------------------------------*/
/* COFF FILE HEADER */
/*------------------------------------------------------------------------*/
struct filehdr {
unsigned short f_magic; /* magic number */
unsigned short f_nscns; /* number of sections */
long f_timdat; /* time & date stamp */
long f_symptr; /* file pointer to symtab */
long f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
unsigned short f_TargetID; /* for C6x = 0x0099 */
};
/*------------------------------------------------------------------------*/
/* File header flags */
/*------------------------------------------------------------------------*/
#define F_RELFLG 0x01 /* relocation info stripped from file */
#define F_EXEC 0x02 /* file is executable (no unresolved refs) */
#define F_LNNO 0x04 /* line nunbers stripped from file */
#define F_LSYMS 0x08 /* local symbols stripped from file */
#define F_GSP10 0x10 /* 34010 version */
#define F_GSP20 0x20 /* 34020 version */
#define F_SWABD 0x40 /* bytes swabbed (in names) */
#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */
#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */
#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */
#define F_PATCH 0x400 /* contains "patch" list in optional header */
#define F_NODF 0x400
#define F_VERSION (F_GSP10 | F_GSP20)
#define F_BYTE_ORDER (F_LITTLE | F_BIG)
#define FILHDR struct filehdr
//#define FILHSZ sizeof(FILHDR)
#define FILHSZ 22 // above rounds to align on 4 bytes which causes problems
#define COFF_C67_MAGIC 0x00c2
/*------------------------------------------------------------------------*/
/* Macros to recognize magic numbers */
/*------------------------------------------------------------------------*/
#define ISMAGIC(x) (((unsigned short)(x))==(unsigned short)magic)
#define ISARCHIVE(x) ((((unsigned short)(x))==(unsigned short)ARTYPE))
#define BADMAGIC(x) (((unsigned short)(x) & 0x8080) && !ISMAGIC(x))
/*------------------------------------------------------------------------*/
/* OPTIONAL FILE HEADER */
/*------------------------------------------------------------------------*/
typedef struct aouthdr {
short magic; /* see magic.h */
short vstamp; /* version stamp */
long tsize; /* text size in bytes, padded to FW bdry*/
long dsize; /* initialized data " " */
long bsize; /* uninitialized data " " */
long entrypt; /* entry pt. */
long text_start; /* base of text used for this file */
long data_start; /* base of data used for this file */
} AOUTHDR;
#define AOUTSZ sizeof(AOUTHDR)
/*----------------------------------------------------------------------*/
/* When a UNIX aout header is to be built in the optional header, */
/* the following magic numbers can appear in that header: */
/* */
/* AOUT1MAGIC : default : readonly sharable text segment */
/* AOUT2MAGIC: : writable text segment */
/* PAGEMAGIC : : configured for paging */
/*----------------------------------------------------------------------*/
#define AOUT1MAGIC 0410
#define AOUT2MAGIC 0407
#define PAGEMAGIC 0413
/*------------------------------------------------------------------------*/
/* COMMON ARCHIVE FILE STRUCTURES */
/* */
/* ARCHIVE File Organization: */
/* _______________________________________________ */
/* |__________ARCHIVE_MAGIC_STRING_______________| */
/* |__________ARCHIVE_FILE_MEMBER_1______________| */
/* | | */
/* | Archive File Header "ar_hdr" | */
/* |.............................................| */
/* | Member Contents | */
/* | 1. External symbol directory | */
/* | 2. Text file | */
/* |_____________________________________________| */
/* |________ARCHIVE_FILE_MEMBER_2________________| */
/* | "ar_hdr" | */
/* |.............................................| */
/* | Member Contents (.o or text file) | */
/* |_____________________________________________| */
/* | . . . | */
/* | . . . | */
/* | . . . | */
/* |_____________________________________________| */
/* |________ARCHIVE_FILE_MEMBER_n________________| */
/* | "ar_hdr" | */
/* |.............................................| */
/* | Member Contents | */
/* |_____________________________________________| */
/* */
/*------------------------------------------------------------------------*/
#define COFF_ARMAG "!<arch>\n"
#define SARMAG 8
#define ARFMAG "`\n"
struct ar_hdr /* archive file member header - printable ascii */
{
char ar_name[16]; /* file member name - `/' terminated */
char ar_date[12]; /* file member date - decimal */
char ar_uid[6]; /* file member user id - decimal */
char ar_gid[6]; /* file member group id - decimal */
char ar_mode[8]; /* file member mode - octal */
char ar_size[10]; /* file member size - decimal */
char ar_fmag[2]; /* ARFMAG - string to end header */
};
/*------------------------------------------------------------------------*/
/* SECTION HEADER */
/*------------------------------------------------------------------------*/
struct scnhdr {
char s_name[8]; /* section name */
long s_paddr; /* physical address */
long s_vaddr; /* virtual address */
long s_size; /* section size */
long s_scnptr; /* file ptr to raw data for section */
long s_relptr; /* file ptr to relocation */
long s_lnnoptr; /* file ptr to line numbers */
unsigned int s_nreloc; /* number of relocation entries */
unsigned int s_nlnno; /* number of line number entries */
unsigned int s_flags; /* flags */
unsigned short s_reserved; /* reserved byte */
unsigned short s_page; /* memory page id */
};
#define SCNHDR struct scnhdr
#define SCNHSZ sizeof(SCNHDR)
/*------------------------------------------------------------------------*/
/* Define constants for names of "special" sections */
/*------------------------------------------------------------------------*/
//#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
#define _CINIT ".cinit"
#define _TV ".tv"
/*------------------------------------------------------------------------*/
/* The low 4 bits of s_flags is used as a section "type" */
/*------------------------------------------------------------------------*/
#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */
#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */
#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */
#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */
#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */
#define STYP_COPY 0x10 /* "copy" : used for C init tables -
not allocated, relocated,
loaded; reloc & lineno
entries processed normally */
#define STYP_TEXT 0x20 /* section contains text only */
#define STYP_DATA 0x40 /* section contains data only */
#define STYP_BSS 0x80 /* section contains bss only */
#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */
#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */
#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8))
/*------------------------------------------------------------------------*/
/* RELOCATION ENTRIES */
/*------------------------------------------------------------------------*/
struct reloc
{
long r_vaddr; /* (virtual) address of reference */
short r_symndx; /* index into symbol table */
unsigned short r_disp; /* additional bits for address calculation */
unsigned short r_type; /* relocation type */
};
#define RELOC struct reloc
#define RELSZ 10 /* sizeof(RELOC) */
/*--------------------------------------------------------------------------*/
/* define all relocation types */
/*--------------------------------------------------------------------------*/
#define R_ABS 0 /* absolute address - no relocation */
#define R_DIR16 01 /* UNUSED */
#define R_REL16 02 /* UNUSED */
#define R_DIR24 04 /* UNUSED */
#define R_REL24 05 /* 24 bits, direct */
#define R_DIR32 06 /* UNUSED */
#define R_RELBYTE 017 /* 8 bits, direct */
#define R_RELWORD 020 /* 16 bits, direct */
#define R_RELLONG 021 /* 32 bits, direct */
#define R_PCRBYTE 022 /* 8 bits, PC-relative */
#define R_PCRWORD 023 /* 16 bits, PC-relative */
#define R_PCRLONG 024 /* 32 bits, PC-relative */
#define R_OCRLONG 030 /* GSP: 32 bits, one's complement direct */
#define R_GSPPCR16 031 /* GSP: 16 bits, PC relative (in words) */
#define R_GSPOPR32 032 /* GSP: 32 bits, direct big-endian */
#define R_PARTLS16 040 /* Brahma: 16 bit offset of 24 bit address*/
#define R_PARTMS8 041 /* Brahma: 8 bit page of 24 bit address */
#define R_PARTLS7 050 /* DSP: 7 bit offset of 16 bit address */
#define R_PARTMS9 051 /* DSP: 9 bit page of 16 bit address */
#define R_REL13 052 /* DSP: 13 bits, direct */
/*------------------------------------------------------------------------*/
/* LINE NUMBER ENTRIES */
/*------------------------------------------------------------------------*/
struct lineno
{
union
{
long l_symndx ; /* sym. table index of function name
iff l_lnno == 0 */
long l_paddr ; /* (physical) address of line number */
} l_addr ;
unsigned short l_lnno ; /* line number */
};
#define LINENO struct lineno
#define LINESZ 6 /* sizeof(LINENO) */
/*------------------------------------------------------------------------*/
/* STORAGE CLASSES */
/*------------------------------------------------------------------------*/
#define C_EFCN -1 /* physical end of function */
#define C_NULL 0
#define C_AUTO 1 /* automatic variable */
#define C_EXT 2 /* external symbol */
#define C_STAT 3 /* static */
#define C_REG 4 /* register variable */
#define C_EXTDEF 5 /* external definition */
#define C_LABEL 6 /* label */
#define C_ULABEL 7 /* undefined label */
#define C_MOS 8 /* member of structure */
#define C_ARG 9 /* function argument */
#define C_STRTAG 10 /* structure tag */
#define C_MOU 11 /* member of union */
#define C_UNTAG 12 /* union tag */
#define C_TPDEF 13 /* type definition */
#define C_USTATIC 14 /* undefined static */
#define C_ENTAG 15 /* enumeration tag */
#define C_MOE 16 /* member of enumeration */
#define C_REGPARM 17 /* register parameter */
#define C_FIELD 18 /* bit field */
#define C_BLOCK 100 /* ".bb" or ".eb" */
#define C_FCN 101 /* ".bf" or ".ef" */
#define C_EOS 102 /* end of structure */
#define C_FILE 103 /* file name */
#define C_LINE 104 /* dummy sclass for line number entry */
#define C_ALIAS 105 /* duplicate tag */
#define C_HIDDEN 106 /* special storage class for external */
/* symbols in dmert public libraries */
/*------------------------------------------------------------------------*/
/* SYMBOL TABLE ENTRIES */
/*------------------------------------------------------------------------*/
#define SYMNMLEN 8 /* Number of characters in a symbol name */
#define FILNMLEN 14 /* Number of characters in a file name */
#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */
struct syment
{
union
{
char _n_name[SYMNMLEN]; /* old COFF version */
struct
{
long _n_zeroes; /* new == 0 */
long _n_offset; /* offset into string table */
} _n_n;
char *_n_nptr[2]; /* allows for overlaying */
} _n;
long n_value; /* value of symbol */
short n_scnum; /* section number */
unsigned short n_type; /* type and derived type */
char n_sclass; /* storage class */
char n_numaux; /* number of aux. entries */
};
#define n_name _n._n_name
#define n_nptr _n._n_nptr[1]
#define n_zeroes _n._n_n._n_zeroes
#define n_offset _n._n_n._n_offset
/*------------------------------------------------------------------------*/
/* Relocatable symbols have a section number of the */
/* section in which they are defined. Otherwise, section */
/* numbers have the following meanings: */
/*------------------------------------------------------------------------*/
#define N_UNDEF 0 /* undefined symbol */
#define N_ABS -1 /* value of symbol is absolute */
#define N_DEBUG -2 /* special debugging symbol */
#define N_TV (unsigned short)-3 /* needs transfer vector (preload) */
#define P_TV (unsigned short)-4 /* needs transfer vector (postload) */
/*------------------------------------------------------------------------*/
/* The fundamental type of a symbol packed into the low */
/* 4 bits of the word. */
/*------------------------------------------------------------------------*/
#define _EF ".ef"
#define T_NULL 0 /* no type info */
#define T_ARG 1 /* function argument (only used by compiler) */
#define T_CHAR 2 /* character */
#define T_SHORT 3 /* short integer */
#define T_INT 4 /* integer */
#define T_LONG 5 /* long integer */
#define T_FLOAT 6 /* floating point */
#define T_DOUBLE 7 /* double word */
#define T_STRUCT 8 /* structure */
#define T_UNION 9 /* union */
#define T_ENUM 10 /* enumeration */
#define T_MOE 11 /* member of enumeration */
#define T_UCHAR 12 /* unsigned character */
#define T_USHORT 13 /* unsigned short */
#define T_UINT 14 /* unsigned integer */
#define T_ULONG 15 /* unsigned long */
/*------------------------------------------------------------------------*/
/* derived types are: */
/*------------------------------------------------------------------------*/
#define DT_NON 0 /* no derived type */
#define DT_PTR 1 /* pointer */
#define DT_FCN 2 /* function */
#define DT_ARY 3 /* array */
#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \
((basic) | ((d1) << 4) | ((d2) << 6) | ((d3) << 8) |\
((d4) << 10) | ((d5) << 12) | ((d6) << 14))
/*------------------------------------------------------------------------*/
/* type packing constants and macros */
/*------------------------------------------------------------------------*/
#define N_BTMASK_COFF 017
#define N_TMASK_COFF 060
#define N_TMASK1_COFF 0300
#define N_TMASK2_COFF 0360
#define N_BTSHFT_COFF 4
#define N_TSHIFT_COFF 2
#define BTYPE_COFF(x) ((x) & N_BTMASK_COFF)
#define ISINT(x) (((x) >= T_CHAR && (x) <= T_LONG) || \
((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM)
#define ISFLT_COFF(x) ((x) == T_DOUBLE || (x) == T_FLOAT)
#define ISPTR_COFF(x) (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF))
#define ISFCN_COFF(x) (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF))
#define ISARY_COFF(x) (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF))
#define ISTAG_COFF(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG)
#define INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<<N_TSHIFT_COFF)|(DT_PTR<<N_BTSHFT_COFF)|(x&N_BTMASK_COFF))
#define DECREF_COFF(x) ((((x)>>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF))
/*------------------------------------------------------------------------*/
/* AUXILIARY SYMBOL ENTRY */
/*------------------------------------------------------------------------*/
union auxent
{
struct
{
long x_tagndx; /* str, un, or enum tag indx */
union
{
struct
{
unsigned short x_lnno; /* declaration line number */
unsigned short x_size; /* str, union, array size */
} x_lnsz;
long x_fsize; /* size of function */
} x_misc;
union
{
struct /* if ISFCN, tag, or .bb */
{
long x_lnnoptr; /* ptr to fcn line # */
long x_endndx; /* entry ndx past block end */
} x_fcn;
struct /* if ISARY, up to 4 dimen. */
{
unsigned short x_dimen[DIMNUM];
} x_ary;
} x_fcnary;
unsigned short x_regcount; /* number of registers used by func */
} x_sym;
struct
{
char x_fname[FILNMLEN];
} x_file;
struct
{
long x_scnlen; /* section length */
unsigned short x_nreloc; /* number of relocation entries */
unsigned short x_nlinno; /* number of line numbers */
} x_scn;
};
#define SYMENT struct syment
#define SYMESZ 18 /* sizeof(SYMENT) */
#define AUXENT union auxent
#define AUXESZ 18 /* sizeof(AUXENT) */
/*------------------------------------------------------------------------*/
/* NAMES OF "SPECIAL" SYMBOLS */
/*------------------------------------------------------------------------*/
#define _STEXT ".text"
#define _ETEXT "etext"
#define _SDATA ".data"
#define _EDATA "edata"
#define _SBSS ".bss"
#define _END "end"
#define _CINITPTR "cinit"
/*--------------------------------------------------------------------------*/
/* ENTRY POINT SYMBOLS */
/*--------------------------------------------------------------------------*/
#define _START "_start"
#define _MAIN "_main"
/* _CSTART "_c_int00" (defined in params.h) */
#define _TVORIG "_tvorig"
#define _TORIGIN "_torigin"
#define _DORIGIN "_dorigin"
#define _SORIGIN "_sorigin"

59
configure vendored
View File

@@ -18,7 +18,7 @@ TMPS="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.S"
TMPH="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
prefix="/usr/local"
prefix=""
execprefix=""
bindir=""
libdir=""
@@ -56,10 +56,16 @@ case "$cpu" in
esac
gprof="no"
bigendian="no"
mingw32="no"
LIBSUF=".a"
EXESUF=""
# OS specific
targetos=`uname -s`
case $targetos in
MINGW32*)
mingw32="yes"
;;
*) ;;
esac
@@ -106,6 +112,8 @@ for opt do
;;
--enable-gprof) gprof="yes"
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
;;
esac
done
@@ -118,6 +126,11 @@ cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
if test "$mingw32" = "yes" ; then
LIBSUF=".lib"
EXESUF=".exe"
fi
if test -z "$cross_prefix" ; then
# ---
@@ -188,26 +201,43 @@ echo ""
exit 1
fi
if test x"$execprefix" = x""; then
execprefix="${prefix}"
fi
if test x"$bindir" = x""; then
bindir="${execprefix}/bin"
fi
if test "$mingw32" = "yes" ; then
if test -z "$prefix" ; then
prefix="/c/Program Files/tcc"
fi
execprefix="$prefix"
bindir="$prefix"
docdir="$prefix/doc"
else
if test -z "$prefix" ; then
prefix="/usr/local"
fi
if test x"$execprefix" = x""; then
execprefix="${prefix}"
fi
if test x"$bindir" = x""; then
bindir="${execprefix}/bin"
fi
if test x"$docdir" = x""; then
docdir="$prefix/share/doc/tcc"
fi
fi # mingw32
if test x"$libdir" = x""; then
libdir="${execprefix}/lib"
fi
if test x"$includedir" = x""; then
includedir="${prefix}/include"
fi
if test x"$mandir" = x""; then
mandir="${prefix}/man"
fi
if test x"$includedir" = x""; then
includedir="${prefix}/include"
fi
echo "Binary directory $bindir"
echo "Library directory $libdir"
echo "Include directory $includedir"
echo "Manual directory $mandir"
echo "Manual directory $mandir"
echo "Doc directory $docdir"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
@@ -225,6 +255,7 @@ echo "bindir=$bindir" >> config.mak
echo "libdir=$libdir" >> config.mak
echo "includedir=$includedir" >> config.mak
echo "mandir=$mandir" >> config.mak
echo "docdir=$docdir" >> config.mak
echo "#define CONFIG_TCC_LIBDIR \"$libdir\"" >> $TMPH
echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak
@@ -235,6 +266,8 @@ echo "AR=$ar" >> config.mak
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
echo "CFLAGS=$CFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
echo "LIBSUF=$LIBSUF" >> config.mak
echo "EXESUF=$EXESUF" >> config.mak
if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
@@ -257,6 +290,10 @@ else
echo "Unsupported CPU"
exit 1
fi
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> config.mak
echo "#define CONFIG_WIN32 1" >> $TMPH
fi
if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> config.mak
echo "#define WORDS_BIGENDIAN 1" >> $TMPH

18
elf.h
View File

@@ -217,6 +217,7 @@ typedef struct
chances of collision with official or non-GNU unofficial values. */
#define EM_ALPHA 0x9026
#define EM_C60 0x9c60
/* Legal values for e_version (version). */
@@ -1592,4 +1593,21 @@ typedef Elf32_Addr Elf32_Conflict;
/* Keep this the last entry. */
#define R_ARM_NUM 256
/* TMS320C67xx specific declarations */
/* XXX: no ELF standard yet */
/* TMS320C67xx relocs. */
#define R_C60_32 1
#define R_C60_GOT32 3 /* 32 bit GOT entry */
#define R_C60_PLT32 4 /* 32 bit PLT address */
#define R_C60_COPY 5 /* Copy symbol at runtime */
#define R_C60_GLOB_DAT 6 /* Create GOT entry */
#define R_C60_JMP_SLOT 7 /* Create PLT entry */
#define R_C60_RELATIVE 8 /* Adjust by program base */
#define R_C60_GOTOFF 9 /* 32 bit offset to GOT */
#define R_C60_GOTPC 10 /* 32 bit PC relative offset to GOT */
#define R_C60HI16 0x55 // high 16 bit MVKH embedded
#define R_C60LO16 0x54 // low 16 bit MVKL embedded
#endif /* elf.h */

8
ex1.c Executable file
View File

@@ -0,0 +1,8 @@
#! /usr/local/bin/tcc -run
#include <tcclib.h>
int main()
{
printf("Hello World\n");
return 0;
}

97
ex2.c Normal file
View File

@@ -0,0 +1,97 @@
#include "tcclib.h"
#define N 20
int nb_num;
int tab[N];
int stack_ptr;
int stack_op[N];
int stack_res[60];
int result;
int find(int n, int i1, int a, int b, int op)
{
int i, j;
int c;
if (stack_ptr >= 0) {
stack_res[3*stack_ptr] = a;
stack_op[stack_ptr] = op;
stack_res[3*stack_ptr+1] = b;
stack_res[3*stack_ptr+2] = n;
if (n == result)
return 1;
tab[i1] = n;
}
for(i=0;i<nb_num;i++) {
for(j=i+1;j<nb_num;j++) {
a = tab[i];
b = tab[j];
if (a != 0 && b != 0) {
tab[j] = 0;
stack_ptr++;
if (find(a + b, i, a, b, '+'))
return 1;
if (find(a - b, i, a, b, '-'))
return 1;
if (find(b - a, i, b, a, '-'))
return 1;
if (find(a * b, i, a, b, '*'))
return 1;
if (b != 0) {
c = a / b;
if (find(c, i, a, b, '/'))
return 1;
}
if (a != 0) {
c = b / a;
if (find(c, i, b, a, '/'))
return 1;
}
stack_ptr--;
tab[i] = a;
tab[j] = b;
}
}
}
return 0;
}
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]);
exit(1);
}
p = 1;
result = atoi(argv[p]);
printf("result=%d\n", result);
nb_num = 0;
for(i=p+1;i<argc;i++) {
tab[nb_num++] = atoi(argv[i]);
}
stack_ptr = -1;
res = find(0, 0, 0, 0, ' ');
if (res) {
for(i=0;i<=stack_ptr;i++) {
printf("%d %c %d = %d\n",
stack_res[3*i], stack_op[i],
stack_res[3*i+1], stack_res[3*i+2]);
}
return 0;
} else {
printf("Impossible\n");
return 1;
}
}

23
ex3.c Normal file
View File

@@ -0,0 +1,23 @@
#include <tcclib.h>
int fib(n)
{
if (n <= 2)
return 1;
else
return fib(n-1) + fib(n-2);
}
int main(int argc, char **argv)
{
int n;
if (argc < 2) {
printf("usage: fib n\n"
"Compute nth Fibonacci number\n");
return 1;
}
n = atoi(argv[1]);
printf("fib(%d) = %d\n", n, fib(n, 2));
return 0;
}

25
ex4.c Executable file
View File

@@ -0,0 +1,25 @@
#!./tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
/* Yes, TCC can use X11 too ! */
#include <stdio.h>
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
Display *display;
Screen *screen;
display = XOpenDisplay("");
if (!display) {
fprintf(stderr, "Could not open X11 display\n");
exit(1);
}
printf("X11 display opened.\n");
screen = XScreenOfDisplay(display, 0);
printf("width = %d\nheight = %d\ndepth = %d\n",
screen->width,
screen->height,
screen->root_depth);
XCloseDisplay(display);
return 0;
}

8
ex5.c Normal file
View File

@@ -0,0 +1,8 @@
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}

33
gcctestsuite.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/sh
TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
rm -f tcc.sum tcc.log
nb_failed="0"
for src in $TESTSUITE_PATH/compile/*.c ; do
echo $TCC -o /tmp/test.o -c $src
$TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
if [ "$?" == "0" ] ; then
result="PASS"
else
result="FAIL"
nb_failed=$[ $nb_failed + 1 ]
fi
echo "$result: $src" >> tcc.sum
done
for src in $TESTSUITE_PATH/execute/*.c ; do
echo $TCC $src
$TCC $src >> tcc.log 2>&1
if [ "$?" == "0" ] ; then
result="PASS"
else
result="FAIL"
nb_failed=$[ $nb_failed + 1 ]
fi
echo "$result: $src" >> tcc.sum
done
echo "$nb_failed test(s) failed." >> tcc.sum
echo "$nb_failed test(s) failed."

View File

@@ -364,7 +364,7 @@ static void gen_le16(int v)
/* generate the modrm operand */
static inline void asm_modrm(int reg, Operand *op)
{
int mod, reg1, reg2;
int mod, reg1, reg2, sib_reg1;
if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
g(0xc0 + (reg << 3) + op->reg);
@@ -373,8 +373,12 @@ static inline void asm_modrm(int reg, Operand *op)
g(0x05 + (reg << 3));
gen_expr32(&op->e);
} else {
sib_reg1 = op->reg;
/* fist compute displacement encoding */
if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
if (sib_reg1 == -1) {
sib_reg1 = 5;
mod = 0x00;
} else if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
mod = 0x00;
} else if (op->e.v == (int8_t)op->e.v && !op->e.sym) {
mod = 0x40;
@@ -391,13 +395,13 @@ static inline void asm_modrm(int reg, Operand *op)
reg2 = op->reg2;
if (reg2 == -1)
reg2 = 4; /* indicate no index */
g((op->shift << 6) + (reg2 << 3) + op->reg);
g((op->shift << 6) + (reg2 << 3) + sib_reg1);
}
/* add offset */
if (mod == 0x40) {
g(op->e.v);
} else if (mod == 0x80) {
} else if (mod == 0x80 || op->reg == -1) {
gen_expr32(&op->e);
}
}
@@ -517,7 +521,11 @@ static void asm_opcode(TCCState *s1, int opcode)
s = reg_to_size[ops[i].type & OP_REG];
}
if (s == 3) {
error("cannot infer opcode suffix");
if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
(ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
s = 2;
else
error("cannot infer opcode suffix");
}
}
@@ -752,50 +760,56 @@ static const char *skip_constraint_modifiers(const char *p)
return p;
}
static void asm_compute_constraints(uint8_t *regs_allocated,
ASMOperand *operands,
int nb_operands1, int nb_outputs,
int is_output,
uint8_t *input_regs_allocated)
#define REG_OUT_MASK 0x01
#define REG_IN_MASK 0x02
#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
static void asm_compute_constraints(ASMOperand *operands,
int nb_operands, int nb_outputs,
const uint8_t *clobber_regs,
int *pout_reg)
{
ASMOperand *op;
int sorted_op[MAX_ASM_OPERANDS];
int i, j, k, p1, p2, tmp, reg, c, base, nb_operands;
int i, j, k, p1, p2, tmp, reg, c, reg_mask;
const char *str;
uint8_t regs_allocated[NB_ASM_REGS];
if (is_output) {
base = 0;
nb_operands = nb_outputs;
} else {
base = nb_outputs;
nb_operands = nb_operands1 - nb_outputs;
/* init fields */
for(i=0;i<nb_operands;i++) {
op = &operands[i];
op->input_index = -1;
op->ref_index = -1;
op->reg = -1;
op->is_memory = 0;
op->is_rw = 0;
}
/* compute constraint priority and evaluate references to output
constraints if input constraints */
for(i=0;i<nb_operands;i++) {
j = base + i;
op = &operands[j];
op = &operands[i];
str = op->constraint;
op->ref_index = -1;
op->reg = -1;
str = skip_constraint_modifiers(str);
if (!is_output && (isnum(*str) || *str == '[')) {
if (isnum(*str) || *str == '[') {
/* this is a reference to another constraint */
k = find_constraint(operands, nb_operands1, str, NULL);
if ((unsigned)k >= j)
k = find_constraint(operands, nb_operands, str, NULL);
if ((unsigned)k >= i || i < nb_outputs)
error("invalid reference in constraint %d ('%s')",
j, str);
i, str);
op->ref_index = k;
str = operands[k].constraint;
str = skip_constraint_modifiers(str);
if (operands[k].input_index >= 0)
error("cannot reference twice the same operand");
operands[k].input_index = i;
op->priority = 5;
} else {
op->priority = constraint_priority(str);
}
op->priority = constraint_priority(str);
}
/* sort operands according to their priority */
for(i=0;i<nb_operands;i++)
sorted_op[i] = base + i;
sorted_op[i] = i;
for(i=0;i<nb_operands - 1;i++) {
for(j=i+1;j<nb_operands;j++) {
p1 = operands[sorted_op[i]].priority;
@@ -808,32 +822,55 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
}
}
memset(regs_allocated, 0, NB_ASM_REGS);
regs_allocated[4] = 1; /* esp cannot be used */
regs_allocated[5] = 1; /* ebp cannot be used yet */
for(i = 0;i < NB_ASM_REGS; i++) {
if (clobber_regs[i])
regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
else
regs_allocated[i] = 0;
}
/* esp cannot be used */
regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK;
/* ebp cannot be used yet */
regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK;
/* allocate registers and generate corresponding asm moves */
for(i=0;i<nb_operands;i++) {
j = sorted_op[i];
op = &operands[j];
str = op->constraint;
if (op->ref_index >= 0) {
str = operands[op->ref_index].constraint;
/* no need to allocate references */
if (op->ref_index >= 0)
continue;
/* select if register is used for output, input or both */
if (op->input_index >= 0) {
reg_mask = REG_IN_MASK | REG_OUT_MASK;
} else if (j < nb_outputs) {
reg_mask = REG_OUT_MASK;
} else {
reg_mask = REG_IN_MASK;
}
str = skip_constraint_modifiers(str);
try_next:
c = *str++;
switch(c) {
case '=':
goto try_next;
case '+':
op->is_rw = 1;
/* FALL THRU */
case '&':
if (j >= nb_outputs)
error("'%c' modifier can only be applied to outputs", c);
reg_mask = REG_IN_MASK | REG_OUT_MASK;
goto try_next;
case 'A':
/* allocate both eax and edx */
if (regs_allocated[TREG_EAX] || regs_allocated[TREG_EDX])
if (is_reg_allocated(TREG_EAX) ||
is_reg_allocated(TREG_EDX))
goto try_next;
op->is_llong = 1;
op->reg = TREG_EAX;
regs_allocated[TREG_EAX] = 1;
regs_allocated[TREG_EDX] = 1;
regs_allocated[TREG_EAX] |= reg_mask;
regs_allocated[TREG_EDX] |= reg_mask;
break;
case 'a':
reg = TREG_EAX;
@@ -853,20 +890,20 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
case 'D':
reg = 7;
alloc_reg:
if (regs_allocated[reg])
if (is_reg_allocated(reg))
goto try_next;
goto reg_found;
case 'q':
/* eax, ebx, ecx or edx */
for(reg = 0; reg < 4; reg++) {
if (!regs_allocated[reg])
if (!is_reg_allocated(reg))
goto reg_found;
}
goto try_next;
case 'r':
/* any general register */
for(reg = 0; reg < 8; reg++) {
if (!regs_allocated[reg])
if (!is_reg_allocated(reg))
goto reg_found;
}
goto try_next;
@@ -874,7 +911,7 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
/* now we can reload in the register */
op->is_llong = 0;
op->reg = reg;
regs_allocated[reg] = 1;
regs_allocated[reg] |= reg_mask;
break;
case 'i':
if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
@@ -888,25 +925,27 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
break;
case 'm':
case 'g':
/* nothing special to do because the operand is
already in memory */
/* nothing special to do because the operand is already in
memory, except if the pointer itself is stored in a
memory variable (VT_LLOCAL case) */
/* XXX: fix constant case */
if (is_output) {
/* if it is a reference to a memory zone, it must lie
in a register, so we reserve the register in the
input registers and a load will be generated
later */
/* if it is a reference to a memory zone, it must lie
in a register, so we reserve the register in the
input registers and a load will be generated
later */
if (j < nb_outputs || c == 'm') {
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
/* any general register */
for(reg = 0; reg < 8; reg++) {
if (!input_regs_allocated[reg])
if (!(regs_allocated[reg] & REG_IN_MASK))
goto reg_found1;
}
goto try_next;
reg_found1:
/* now we can reload in the register */
input_regs_allocated[reg] = 1;
regs_allocated[reg] |= REG_IN_MASK;
op->reg = reg;
op->is_memory = 1;
}
}
break;
@@ -915,14 +954,34 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
j, op->constraint);
break;
}
/* if a reference is present for that operand, we assign it too */
if (op->input_index >= 0) {
operands[op->input_index].reg = op->reg;
operands[op->input_index].is_llong = op->is_llong;
}
}
/* compute out_reg. It is used to store outputs registers to memory
locations references by pointers (VT_LLOCAL case) */
*pout_reg = -1;
for(i=0;i<nb_operands;i++) {
op = &operands[i];
if (op->reg >= 0 &&
(op->vt->r & VT_VALMASK) == VT_LLOCAL &&
!op->is_memory) {
for(reg = 0; reg < 8; reg++) {
if (!(regs_allocated[reg] & REG_OUT_MASK))
goto reg_found2;
}
error("could not find free output register for reloading");
reg_found2:
*pout_reg = reg;
break;
}
}
/* print sorted constraints */
#ifdef ASM_DEBUG
if (is_output)
printf("outputs=\n");
else
printf("inputs=\n");
for(i=0;i<nb_operands;i++) {
j = sorted_op[i];
op = &operands[j];
@@ -933,6 +992,8 @@ static void asm_compute_constraints(uint8_t *regs_allocated,
op->vt->r,
op->reg);
}
if (*pout_reg >= 0)
printf("out_reg=%d\n", *pout_reg);
#endif
}
@@ -1019,7 +1080,8 @@ static void subst_asm_operand(CString *add_str,
/* generate prolog and epilog code for asm statment */
static void asm_gen_code(ASMOperand *operands, int nb_operands,
int nb_outputs, int is_output,
uint8_t *clobber_regs)
uint8_t *clobber_regs,
int out_reg)
{
uint8_t regs_allocated[NB_ASM_REGS];
ASMOperand *op;
@@ -1042,39 +1104,52 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
}
/* generate load code */
for(i = nb_outputs ; i < nb_operands; i++) {
for(i = 0; i < nb_operands; i++) {
op = &operands[i];
if (op->reg >= 0) {
load(op->reg, op->vt);
if (op->is_llong) {
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
op->is_memory) {
/* memory reference case (for both input and
output cases) */
SValue sv;
sv = *op->vt;
sv.c.ul += 4;
load(TREG_EDX, &sv);
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
load(op->reg, &sv);
} else if (i >= nb_outputs || op->is_rw) {
/* load value in register */
load(op->reg, op->vt);
if (op->is_llong) {
SValue sv;
sv = *op->vt;
sv.c.ul += 4;
load(TREG_EDX, &sv);
}
}
}
}
/* generate load code for output memory references */
for(i = 0 ; i < nb_outputs; i++) {
op = &operands[i];
if (op->reg >= 0 && ((op->vt->r & VT_VALMASK) == VT_LLOCAL)) {
SValue sv;
sv = *op->vt;
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
load(op->reg, &sv);
}
}
} else {
/* generate save code */
for(i = 0 ; i < nb_outputs; i++) {
op = &operands[i];
if (op->reg >= 0 && ((op->vt->r & VT_VALMASK) != VT_LLOCAL)) {
store(op->reg, op->vt);
if (op->is_llong) {
SValue sv;
sv = *op->vt;
sv.c.ul += 4;
store(TREG_EDX, &sv);
if (op->reg >= 0) {
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
if (!op->is_memory) {
SValue sv;
sv = *op->vt;
sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
load(out_reg, &sv);
sv.r = (sv.r & ~VT_VALMASK) | out_reg;
store(op->reg, &sv);
}
} else {
store(op->reg, op->vt);
if (op->is_llong) {
SValue sv;
sv = *op->vt;
sv.c.ul += 4;
store(TREG_EDX, &sv);
}
}
}
}

View File

@@ -120,13 +120,13 @@ ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S))
ALT(DEF_ASM_OP1(push, 0x68, 0, 0, OPT_IM32))
ALT(DEF_ASM_OP1(push, 0x06, 0, 0, OPT_SEG))
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
ALT(DEF_ASM_OP1(pop, 0x07, 0, 0, OPT_SEG))
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WL, OPT_SEG))
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_REG, OPT_EAX))
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_EAX, OPT_REG))
@@ -330,6 +330,8 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA )
DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST )
DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST )
DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA )
DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA )
/* segments */
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)

View File

@@ -1,7 +1,7 @@
/*
* X86 code generator for TCC
*
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard
* 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
@@ -70,8 +70,18 @@ int reg_classes[NB_REGS] = {
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_386
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_386_32
#define R_DATA_32 R_386_32
#define R_JMP_SLOT R_386_JMP_SLOT
#define R_COPY R_386_COPY
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
@@ -90,11 +100,11 @@ void g(int c)
ind = ind1;
}
void o(int c)
void o(unsigned int c)
{
while (c) {
g(c);
c = c / 256;
c = c >> 8;
}
}
@@ -310,12 +320,14 @@ static void gcall_or_jmp(int is_jmp)
}
}
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
void gfunc_call(int nb_args)
{
int size, align, r, args_size, i;
int size, align, r, args_size, i, func_call;
Sym *func_sym;
args_size = 0;
@@ -367,8 +379,21 @@ void gfunc_call(int nb_args)
}
save_regs(0); /* save used temporary registers */
func_sym = vtop->type.ref;
func_call = func_sym->r;
/* fast call case */
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
int fastcall_nb_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 */
/* XXX: incorrect for struct/floats */
args_size -= 4;
}
}
gcall_or_jmp(0);
if (args_size && func_sym->r == FUNC_CDECL)
if (args_size && func_sym->r != FUNC_STDCALL)
gadd_sp(args_size);
vtop--;
}
@@ -376,25 +401,37 @@ void gfunc_call(int nb_args)
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
{
int addr, align, size, func_call;
int addr, align, size, func_call, fastcall_nb_regs;
int param_index, param_addr;
Sym *sym;
CType *type;
sym = func_type->ref;
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;
} else {
fastcall_nb_regs = 0;
}
param_index = 0;
o(0xe58955); /* push %ebp, mov %esp, %ebp */
func_sub_sp_offset = oad(0xec81, 0); /* sub $xxx, %esp */
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->type;
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
/* XXX: fastcall case ? */
func_vc = addr;
addr += 4;
param_index++;
}
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | VT_LVAL, addr);
size = type_size(type, &align);
size = (size + 3) & ~3;
#ifdef FUNC_STRUCT_PARAM_AS_PTR
@@ -403,14 +440,25 @@ void gfunc_prolog(CType *func_type)
size = 4;
}
#endif
addr += size;
if (param_index < fastcall_nb_regs) {
/* save FASTCALL register */
loc -= 4;
o(0x89); /* movl */
gen_modrm(fastcall_regs[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);
param_index++;
}
func_ret_sub = 0;
/* pascal type call ? */
if (func_call == FUNC_STDCALL)
func_ret_sub = addr - 8;
o(0xe58955); /* push %ebp, mov %esp, %ebp */
func_sub_sp_offset = oad(0xec81, 0); /* sub $xxx, %esp */
/* leave some room for bound checking code */
if (do_bounds_check) {
oad(0xb8, 0); /* lbound section pointer */

View File

@@ -62,6 +62,10 @@ int tcc_compile_string(TCCState *s, const char *buf);
#define TCC_OUTPUT_OBJ 3 /* object file */
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);
@@ -83,8 +87,8 @@ int tcc_run(TCCState *s, int argc, char **argv);
non zero if link error. */
int tcc_relocate(TCCState *s);
/* return symbol value or error */
void *tcc_get_symbol(TCCState *s, const char *name);
/* return symbol value. return 0 if OK, -1 if symbol not found */
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
#ifdef __cplusplus
}

View File

@@ -6,7 +6,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <libtcc.h>
#include "libtcc.h"
/* this function is called by the generated code */
int add(int a, int b)
@@ -35,7 +35,8 @@ int main(int argc, char **argv)
{
TCCState *s;
int (*func)(int);
unsigned long val;
s = tcc_new();
if (!s) {
fprintf(stderr, "Could not create tcc state\n");
@@ -54,8 +55,9 @@ int main(int argc, char **argv)
tcc_relocate(s);
func = tcc_get_symbol(s, "foo");
tcc_get_symbol(s, &val, "foo");
func = (void *)val;
func(32);
tcc_delete(s);

View File

@@ -10,7 +10,7 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
/* 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__ ? */
#ifndef __int8_t_defined
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
#define __int8_t_defined
typedef char int8_t;
typedef short int int16_t;

View File

@@ -58,6 +58,11 @@ these checks even if non patched libraries are used.
With @code{libtcc}, you can use TCC as a backend for dynamic code
generation (@pxref{Libtcc}).
TCC mainly supports the i386 target. There are alpha 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}.
@node Invoke
@chapter Command line invocation
@@ -154,8 +159,28 @@ Set the path where the tcc internal libraries can be found (default is
@item -bench
Output compilation statistics.
@item -run
Run compiled source.
@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
@option{-run} option, separated by spaces. Example:
@example
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
@end example
In a script, it gives the following header:
@example
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
int main(int argc, char **argv)
@{
...
@}
@end example
@end table
Preprocessor options:
@@ -179,16 +204,43 @@ also be defined: @option{-DF(a)=a+1}
Undefine preprocessor symbol @samp{sym}.
@end table
Warning options:
Compilation flags:
Note: each warning option has a negative form beginning with @option{-Wno-}.
Note: each of the following warning options has a negative form beginning with
@option{-fno-}.
@table @option
@item -funsigned-char
Let the @code{char} type be unsigned.
@item -fsigned-char
Let the @code{char} type be signed.
@item -fno-common
Do not generate common symbols for uninitialized data.
@end table
Warning options:
@table @option
@item -w
Disable all warnings.
@end table
Note: each of the following warning options has a negative form beginning with
@option{-Wno-}.
@table @option
@item -Wimplicit-function-declaration
Warn about implicit function declaration.
@item -Wunsupported
Warn about unsupported GCC features that are ignored by TCC.
@item -Wwrite-strings
Make string constants being of type @code{const char *} intead of @code{char
Make string constants be of type @code{const char *} instead of @code{char
*}.
@item -Werror
@@ -196,7 +248,7 @@ Abort compilation if warnings are issued.
@item -Wall
Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and
@option{-Wwrite-strings} (currently not useful).
@option{-Wwrite-strings}.
@end table
@@ -228,6 +280,20 @@ opened with @code{dlopen()} needs to access executable symbols.
Generate an object file combining all input files (@option{-o} option must
also be given).
@item -Wl,-Ttext,address
Set the start of the .text section to @var{address}.
@item -Wl,--oformat,fmt
Use @var{fmt} as output format. The supported output formats are:
@table @code
@item elf32-i386
ELF output format (default)
@item binary
Binary image (only for executable output)
@item coff
COFF output format (only for executable output for TMS320C67xx target)
@end table
@end table
Debugger options:
@@ -559,6 +625,7 @@ They can be defined several times in the same source. Use 'b'
@cindex .long
@cindex .string
@cindex .globl
@cindex .global
@cindex .section
@cindex .text
@cindex .data
@@ -577,11 +644,18 @@ supported:
@item .int value1[,value2...]
@item .long value1[,value2...]
@item .string string
@item .globl symbol
@item .global symbol
@item .section section
@item .text
@item .data
@item .bss
@item .fill repeat[,size[,value]]
@item .org n
@item .previous
@item .string string[,...]
@item .asciz string[,...]
@item .ascii string[,...]
@end itemize
@section X86 Assembler
@@ -604,7 +678,7 @@ executable ELF files and dynamic ELF libraries without relying on an
external linker.
Dynamic ELF libraries can be output but the C compiler does not generate
position independent code (PIC). It means that the dynamic librairy
position independent code (PIC). It means that the dynamic library
code generated by TCC cannot be factorized among processes yet.
TCC linker eliminates unreferenced object code in libraries. A single pass is

1226
tcc.c

File diff suppressed because it is too large Load Diff

284
tccasm.c
View File

@@ -1,7 +1,7 @@
/*
* GAS like assembler for TCC
*
* Copyright (c) 2001, 2002 Fabrice Bellard
* 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
@@ -28,6 +28,8 @@ static int asm_get_local_label_name(TCCState *s1, unsigned int n)
return ts->tok;
}
static void asm_expr(TCCState *s1, ExprValue *pe);
/* We do not use the C expression parser to handle symbols. Maybe the
C expression parser could be tweaked to do so. */
@@ -91,6 +93,11 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
pe->sym = NULL;
next();
break;
case '(':
next();
asm_expr(s1, pe);
skip(')');
break;
default:
if (tok >= TOK_IDENT) {
/* label case : if the label was not found, add one */
@@ -100,8 +107,14 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
/* NOTE: by default, the symbol is global */
sym->type.t = VT_VOID;
}
pe->v = 0;
pe->sym = sym;
if (sym->r == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
pe->v = (long)sym->next;
pe->sym = NULL;
} else {
pe->v = 0;
pe->sym = sym;
}
next();
} else {
error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
@@ -241,7 +254,8 @@ static int asm_int_expr(TCCState *s1)
/* NOTE: the same name space as C labels is used to avoid using too
much memory when storing labels in TokenStrings */
static void asm_new_label(TCCState *s1, int label, int is_local)
static void asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
@@ -262,33 +276,49 @@ static void asm_new_label(TCCState *s1, int label, int is_local)
sym = label_push(&s1->asm_labels, label, 0);
sym->type.t = VT_STATIC | VT_VOID;
}
sym->r = cur_text_section->sh_num;
sym->next = (void *)ind;
sym->r = sh_num;
sym->next = (void *)value;
}
static void asm_new_label(TCCState *s1, int label, int is_local)
{
asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
}
static void asm_free_labels(TCCState *st)
{
Sym *s, *s1;
Section *sec;
for(s = st->asm_labels; s != NULL; s = s1) {
s1 = s->prev;
/* define symbol value in object file */
if (s->r) {
put_extern_sym(s, st->sections[s->r], (long)s->next, 0);
if (s->r == SHN_ABS)
sec = SECTION_ABS;
else
sec = st->sections[s->r];
put_extern_sym(s, sec, (long)s->next, 0);
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
tcc_free(s);
sym_free(s);
}
st->asm_labels = NULL;
}
static void use_section1(TCCState *s1, Section *sec)
{
cur_text_section->data_offset = ind;
cur_text_section = sec;
ind = cur_text_section->data_offset;
}
static void use_section(TCCState *s1, const char *name)
{
Section *sec;
sec = find_section(s1, name);
cur_text_section->data_offset = ind;
cur_text_section = sec;
ind = cur_text_section->data_offset;
use_section1(s1, sec);
}
static void asm_parse_directive(TCCState *s1)
@@ -312,6 +342,9 @@ static void asm_parse_directive(TCCState *s1)
error("alignment must be a positive power of two");
offset = (ind + n - 1) & -n;
size = offset - ind;
/* the section must have a compatible alignment */
if (sec->sh_addralign < n)
sec->sh_addralign = n;
} else {
size = n;
}
@@ -320,6 +353,7 @@ static void asm_parse_directive(TCCState *s1)
next();
v = asm_int_expr(s1);
}
zero_pad:
if (sec->sh_type != SHT_NOBITS) {
sec->data_offset = ind;
ptr = section_ptr_add(sec, size);
@@ -327,6 +361,33 @@ static void asm_parse_directive(TCCState *s1)
}
ind += size;
break;
case TOK_ASM_quad:
next();
for(;;) {
uint64_t vl;
const char *p;
p = tokc.cstr->data;
if (tok != TOK_PPNUM) {
error_constant:
error("64 bit constant");
}
vl = strtoll(p, (char **)&p, 0);
if (*p != '\0')
goto error_constant;
next();
if (sec->sh_type != SHT_NOBITS) {
/* XXX: endianness */
gen_le32(vl);
gen_le32(vl >> 32);
} else {
ind += 8;
}
if (tok != ',')
break;
next();
}
break;
case TOK_ASM_byte:
size = 1;
goto asm_data;
@@ -361,7 +422,63 @@ static void asm_parse_directive(TCCState *s1)
next();
}
break;
case TOK_ASM_fill:
{
int repeat, size, val, i, j;
uint8_t repeat_buf[8];
next();
repeat = asm_int_expr(s1);
if (repeat < 0) {
error("repeat < 0; .fill ignored");
break;
}
size = 1;
val = 0;
if (tok == ',') {
next();
size = asm_int_expr(s1);
if (size < 0) {
error("size < 0; .fill ignored");
break;
}
if (size > 8)
size = 8;
if (tok == ',') {
next();
val = asm_int_expr(s1);
}
}
/* XXX: endianness */
repeat_buf[0] = val;
repeat_buf[1] = val >> 8;
repeat_buf[2] = val >> 16;
repeat_buf[3] = val >> 24;
repeat_buf[4] = 0;
repeat_buf[5] = 0;
repeat_buf[6] = 0;
repeat_buf[7] = 0;
for(i = 0; i < repeat; i++) {
for(j = 0; j < size; j++) {
g(repeat_buf[j]);
}
}
}
break;
case TOK_ASM_org:
{
unsigned long n;
next();
/* XXX: handle section symbols too */
n = asm_int_expr(s1);
if (n < ind)
error("attempt to .org backwards");
v = 0;
size = n - ind;
goto zero_pad;
}
break;
case TOK_ASM_globl:
case TOK_ASM_global:
{
Sym *sym;
@@ -376,17 +493,30 @@ static void asm_parse_directive(TCCState *s1)
}
break;
case TOK_ASM_string:
case TOK_ASM_ascii:
case TOK_ASM_asciz:
{
const uint8_t *p;
int i;
int i, size, t;
t = tok;
next();
if (tok != TOK_STR)
expect("string constant");
p = tokc.cstr->data;
for(i = 0; i < tokc.cstr->size; i++)
g(p[i]);
next();
for(;;) {
if (tok != TOK_STR)
expect("string constant");
p = tokc.cstr->data;
size = tokc.cstr->size;
if (t == TOK_ASM_ascii && size > 0)
size--;
for(i = 0; i < size; i++)
g(p[i]);
next();
if (tok == ',') {
next();
} else if (tok != TOK_STR) {
break;
}
}
}
break;
case TOK_ASM_text:
@@ -419,9 +549,28 @@ static void asm_parse_directive(TCCState *s1)
pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
next();
}
if (tok == ',') {
/* skip section options */
next();
if (tok != TOK_STR)
expect("string constant");
next();
}
last_text_section = cur_text_section;
use_section(s1, sname);
}
break;
case TOK_ASM_previous:
{
Section *sec;
next();
if (!last_text_section)
error("no previous section referenced");
sec = cur_text_section;
use_section1(s1, last_text_section);
last_text_section = sec;
}
break;
default:
error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
break;
@@ -470,7 +619,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = 0;
parse_flags = PARSE_FLAG_ASM_COMMENTS;
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
next();
@@ -506,6 +655,12 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
asm_new_label(s1, opcode, 0);
next();
goto redo;
} else if (tok == '=') {
int n;
next();
n = asm_int_expr(s1);
asm_new_label1(s1, opcode, 0, SHN_ABS, n);
goto redo;
} else {
asm_opcode(s1, opcode);
}
@@ -526,6 +681,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
/* Assemble the current file */
static int tcc_assemble(TCCState *s1, int do_preprocess)
{
Sym *define_start;
int ret;
preprocess_init(s1);
@@ -534,9 +690,14 @@ static int tcc_assemble(TCCState *s1, int do_preprocess)
cur_text_section = text_section;
ind = cur_text_section->data_offset;
define_start = define_stack;
ret = tcc_assemble_internal(s1, do_preprocess);
cur_text_section->data_offset = ind;
free_defines(define_start);
return ret;
}
@@ -690,12 +851,14 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
if (is_output) {
test_lvalue();
} else {
/* we want to avoid LLOCAL case. note that it may come
from register storage, so we need to convert (reg)
/* we want to avoid LLOCAL case, except when the 'm'
constraint is used. Note that it may come from
register storage, so we need to convert (reg)
case */
if ((vtop->r & VT_LVAL) &&
((vtop->r & VT_VALMASK) == VT_LLOCAL ||
(vtop->r & VT_VALMASK) < VT_CONST)) {
(vtop->r & VT_VALMASK) < VT_CONST) &&
!strchr(op->constraint, 'm')) {
gv(RC_INT);
}
}
@@ -711,14 +874,27 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
}
}
static void parse_asm_str(CString *astr)
{
skip('(');
/* read the string */
if (tok != TOK_STR)
expect("string constant");
cstr_new(astr);
while (tok == TOK_STR) {
/* XXX: add \0 handling too ? */
cstr_cat(astr, tokc.cstr->data);
next();
}
cstr_ccat(astr, '\0');
}
/* parse the GCC asm() instruction */
static void asm_instr(void)
{
CString astr, astr1;
ASMOperand operands[MAX_ASM_OPERANDS];
int nb_inputs, nb_outputs, nb_operands, i;
uint8_t input_regs_allocated[NB_ASM_REGS];
uint8_t output_regs_allocated[NB_ASM_REGS];
int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg;
uint8_t clobber_regs[NB_ASM_REGS];
next();
@@ -727,22 +903,14 @@ static void asm_instr(void)
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
next();
}
skip('(');
/* read the string */
if (tok != TOK_STR)
expect("string constant");
cstr_new(&astr);
while (tok == TOK_STR) {
/* XXX: add \0 handling too ? */
cstr_cat(&astr, tokc.cstr->data);
next();
}
cstr_ccat(&astr, '\0');
parse_asm_str(&astr);
nb_operands = 0;
nb_outputs = 0;
must_subst = 0;
memset(clobber_regs, 0, sizeof(clobber_regs));
if (tok == ':') {
next();
must_subst = 1;
/* output args */
parse_asm_operands(operands, &nb_operands, 1);
nb_outputs = nb_operands;
@@ -779,19 +947,15 @@ static void asm_instr(void)
save_regs(0);
/* compute constraints */
asm_compute_constraints(input_regs_allocated,
operands, nb_operands, nb_outputs, 0,
NULL);
asm_compute_constraints(output_regs_allocated,
operands, nb_operands, nb_outputs, 1,
input_regs_allocated);
asm_compute_constraints(operands, nb_operands, nb_outputs,
clobber_regs, &out_reg);
/* substitute the operands in the asm string. No substitution is
done if no operands (GCC behaviour) */
#ifdef ASM_DEBUG
printf("asm: \"%s\"\n", (char *)astr.data);
#endif
if (nb_operands > 0) {
if (must_subst) {
subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
cstr_free(&astr);
} else {
@@ -802,7 +966,8 @@ static void asm_instr(void)
#endif
/* generate loads */
asm_gen_code(operands, nb_operands, nb_outputs, 0, clobber_regs);
asm_gen_code(operands, nb_operands, nb_outputs, 0,
clobber_regs, out_reg);
/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
@@ -811,7 +976,8 @@ static void asm_instr(void)
next();
/* store the output values if needed */
asm_gen_code(operands, nb_operands, nb_outputs, 1, clobber_regs);
asm_gen_code(operands, nb_operands, nb_outputs, 1,
clobber_regs, out_reg);
/* free everything */
for(i=0;i<nb_operands;i++) {
@@ -823,3 +989,31 @@ static void asm_instr(void)
cstr_free(&astr1);
}
static void asm_global_instr(void)
{
CString astr;
next();
parse_asm_str(&astr);
skip(')');
/* NOTE: we do not eat the ';' so that we can restore the current
token after the assembler parsing */
if (tok != ';')
expect("';'");
#ifdef ASM_DEBUG
printf("asm_global: \"%s\"\n", (char *)astr.data);
#endif
cur_text_section = text_section;
ind = cur_text_section->data_offset;
/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
cur_text_section->data_offset = ind;
/* restore the current C token */
next();
cstr_free(&astr);
}

967
tcccoff.c Normal file
View File

@@ -0,0 +1,967 @@
/*
* COFF file handling for TCC
*
* Copyright (c) 2003, 2004 TK
* Copyright (c) 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
*/
#include "coff.h"
#define MAXNSCNS 255 /* MAXIMUM NUMBER OF SECTIONS */
#define MAX_STR_TABLE 1000000
AOUTHDR o_filehdr; /* OPTIONAL (A.OUT) FILE HEADER */
SCNHDR section_header[MAXNSCNS];
#define MAX_FUNCS 1000
#define MAX_FUNC_NAME_LENGTH 128
int nFuncs;
char Func[MAX_FUNCS][MAX_FUNC_NAME_LENGTH];
char AssociatedFile[MAX_FUNCS][MAX_FUNC_NAME_LENGTH];
int LineNoFilePtr[MAX_FUNCS];
int EndAddress[MAX_FUNCS];
int LastLineNo[MAX_FUNCS];
int FuncEntries[MAX_FUNCS];
BOOL OutputTheSection(Section * sect);
short int GetCoffFlags(const char *s);
void SortSymbolTable(void);
Section *FindSection(TCCState * s1, const char *sname);
int C67_main_entry_point;
int FindCoffSymbolIndex(const char *func_name);
int nb_syms;
typedef struct {
long tag;
long size;
long fileptr;
long nextsym;
short int dummy;
} AUXFUNC;
typedef struct {
long regmask;
unsigned short lineno;
unsigned short nentries;
int localframe;
int nextentry;
short int dummy;
} AUXBF;
typedef struct {
long dummy;
unsigned short lineno;
unsigned short dummy1;
int dummy2;
int dummy3;
unsigned short dummy4;
} AUXEF;
int tcc_output_coff(TCCState *s1, FILE *f)
{
Section *tcc_sect;
SCNHDR *coff_sec;
int file_pointer;
char *Coff_str_table, *pCoff_str_table;
int CoffTextSectionNo, coff_nb_syms;
FILHDR file_hdr; /* FILE HEADER STRUCTURE */
Section *stext, *sdata, *sbss;
int i, NSectionsToOutput = 0;
stext = FindSection(s1, ".text");
sdata = FindSection(s1, ".data");
sbss = FindSection(s1, ".bss");
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1");
file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */
file_hdr.f_timdat = 0; /* time & date stamp */
file_hdr.f_opthdr = sizeof(AOUTHDR); /* sizeof(optional hdr) */
file_hdr.f_flags = 0x1143; /* flags (copied from what code composer does) */
file_hdr.f_TargetID = 0x99; /* for C6x = 0x0099 */
o_filehdr.magic = 0x0108; /* see magic.h */
o_filehdr.vstamp = 0x0190; /* version stamp */
o_filehdr.tsize = stext->data_offset; /* text size in bytes, padded to FW bdry */
o_filehdr.dsize = sdata->data_offset; /* initialized data " " */
o_filehdr.bsize = sbss->data_offset; /* uninitialized data " " */
o_filehdr.entrypt = C67_main_entry_point; /* entry pt. */
o_filehdr.text_start = stext->sh_addr; /* base of text used for this file */
o_filehdr.data_start = sdata->sh_addr; /* base of data used for this file */
// create all the section headers
file_pointer = FILHSZ + sizeof(AOUTHDR);
CoffTextSectionNo = -1;
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
NSectionsToOutput++;
if (CoffTextSectionNo == -1 && tcc_sect == stext)
CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is
strcpy(coff_sec->s_name, tcc_sect->name); /* section name */
coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */
coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */
coff_sec->s_size = tcc_sect->data_offset; /* section size */
coff_sec->s_scnptr = 0; /* file ptr to raw data for section */
coff_sec->s_relptr = 0; /* file ptr to relocation */
coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */
coff_sec->s_nreloc = 0; /* number of relocation entries */
coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */
coff_sec->s_reserved = 0; /* reserved byte */
coff_sec->s_page = 0; /* memory page id */
file_pointer += sizeof(SCNHDR);
}
}
file_hdr.f_nscns = NSectionsToOutput; /* number of sections */
// now loop through and determine file pointer locations
// for the raw data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
// put raw data
coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */
file_pointer += coff_sec->s_size;
}
}
// now loop through and determine file pointer locations
// for the relocation data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
// put relocations data
if (coff_sec->s_nreloc > 0) {
coff_sec->s_relptr = file_pointer; /* file ptr to relocation */
file_pointer += coff_sec->s_nreloc * sizeof(struct reloc);
}
}
}
// now loop through and determine file pointer locations
// for the line number data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
coff_sec->s_nlnno = 0;
coff_sec->s_lnnoptr = 0;
if (do_debug && tcc_sect == stext) {
// count how many line nos data
// also find association between source file name and function
// so we can sort the symbol table
Stab_Sym *sym, *sym_end;
char func_name[MAX_FUNC_NAME_LENGTH],
last_func_name[MAX_FUNC_NAME_LENGTH];
unsigned long func_addr, last_pc, pc;
const char *incl_files[INCLUDE_STACK_SIZE];
int incl_index, len, last_line_num;
const char *str, *p;
coff_sec->s_lnnoptr = file_pointer; /* file ptr to linno */
func_name[0] = '\0';
func_addr = 0;
incl_index = 0;
last_func_name[0] = '\0';
last_pc = 0xffffffff;
last_line_num = 1;
sym = (Stab_Sym *) stab_section->data + 1;
sym_end =
(Stab_Sym *) (stab_section->data +
stab_section->data_offset);
nFuncs = 0;
while (sym < sym_end) {
switch (sym->n_type) {
/* function start or end */
case N_FUN:
if (sym->n_strx == 0) {
// end of function
coff_sec->s_nlnno++;
file_pointer += LINESZ;
pc = sym->n_value + func_addr;
func_name[0] = '\0';
func_addr = 0;
EndAddress[nFuncs] = pc;
FuncEntries[nFuncs] =
(file_pointer -
LineNoFilePtr[nFuncs]) / LINESZ - 1;
LastLineNo[nFuncs++] = last_line_num + 1;
} else {
// beginning of function
LineNoFilePtr[nFuncs] = file_pointer;
coff_sec->s_nlnno++;
file_pointer += LINESZ;
str =
(const char *) stabstr_section->data +
sym->n_strx;
p = strchr(str, ':');
if (!p) {
pstrcpy(func_name, sizeof(func_name), str);
pstrcpy(Func[nFuncs], sizeof(func_name), str);
} else {
len = p - str;
if (len > sizeof(func_name) - 1)
len = sizeof(func_name) - 1;
memcpy(func_name, str, len);
memcpy(Func[nFuncs], str, len);
func_name[len] = '\0';
}
// save the file that it came in so we can sort later
pstrcpy(AssociatedFile[nFuncs], sizeof(func_name),
incl_files[incl_index - 1]);
func_addr = sym->n_value;
}
break;
/* line number info */
case N_SLINE:
pc = sym->n_value + func_addr;
last_pc = pc;
last_line_num = sym->n_desc;
/* XXX: slow! */
strcpy(last_func_name, func_name);
coff_sec->s_nlnno++;
file_pointer += LINESZ;
break;
/* include files */
case N_BINCL:
str =
(const char *) stabstr_section->data + sym->n_strx;
add_incl:
if (incl_index < INCLUDE_STACK_SIZE) {
incl_files[incl_index++] = str;
}
break;
case N_EINCL:
if (incl_index > 1)
incl_index--;
break;
case N_SO:
if (sym->n_strx == 0) {
incl_index = 0; /* end of translation unit */
} else {
str =
(const char *) stabstr_section->data +
sym->n_strx;
/* do not add path */
len = strlen(str);
if (len > 0 && str[len - 1] != '/')
goto add_incl;
}
break;
}
sym++;
}
}
}
file_hdr.f_symptr = file_pointer; /* file pointer to symtab */
if (do_debug)
file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */
else
file_hdr.f_nsyms = 0;
file_pointer += file_hdr.f_nsyms * SYMNMLEN;
// OK now we are all set to write the file
fwrite(&file_hdr, FILHSZ, 1, f);
fwrite(&o_filehdr, sizeof(o_filehdr), 1, f);
// write section headers
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
fwrite(coff_sec, sizeof(SCNHDR), 1, f);
}
}
// write raw data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f);
}
}
// write relocation data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
// put relocations data
if (coff_sec->s_nreloc > 0) {
fwrite(tcc_sect->reloc,
coff_sec->s_nreloc * sizeof(struct reloc), 1, f);
}
}
}
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
if (do_debug)
SortSymbolTable();
// write line no data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (do_debug && tcc_sect == stext) {
// count how many line nos data
Stab_Sym *sym, *sym_end;
char func_name[128], last_func_name[128];
unsigned long func_addr, last_pc, pc;
const char *incl_files[INCLUDE_STACK_SIZE];
int incl_index, len, last_line_num;
const char *str, *p;
LINENO CoffLineNo;
func_name[0] = '\0';
func_addr = 0;
incl_index = 0;
last_func_name[0] = '\0';
last_pc = 0;
last_line_num = 1;
sym = (Stab_Sym *) stab_section->data + 1;
sym_end =
(Stab_Sym *) (stab_section->data +
stab_section->data_offset);
while (sym < sym_end) {
switch (sym->n_type) {
/* function start or end */
case N_FUN:
if (sym->n_strx == 0) {
// end of function
CoffLineNo.l_addr.l_paddr = last_pc;
CoffLineNo.l_lnno = last_line_num + 1;
fwrite(&CoffLineNo, 6, 1, f);
pc = sym->n_value + func_addr;
func_name[0] = '\0';
func_addr = 0;
} else {
// beginning of function
str =
(const char *) stabstr_section->data +
sym->n_strx;
p = strchr(str, ':');
if (!p) {
pstrcpy(func_name, sizeof(func_name), str);
} else {
len = p - str;
if (len > sizeof(func_name) - 1)
len = sizeof(func_name) - 1;
memcpy(func_name, str, len);
func_name[len] = '\0';
}
func_addr = sym->n_value;
last_pc = func_addr;
last_line_num = -1;
// output a function begin
CoffLineNo.l_addr.l_symndx =
FindCoffSymbolIndex(func_name);
CoffLineNo.l_lnno = 0;
fwrite(&CoffLineNo, 6, 1, f);
}
break;
/* line number info */
case N_SLINE:
pc = sym->n_value + func_addr;
/* XXX: slow! */
strcpy(last_func_name, func_name);
// output a line reference
CoffLineNo.l_addr.l_paddr = last_pc;
if (last_line_num == -1) {
CoffLineNo.l_lnno = sym->n_desc;
} else {
CoffLineNo.l_lnno = last_line_num + 1;
}
fwrite(&CoffLineNo, 6, 1, f);
last_pc = pc;
last_line_num = sym->n_desc;
break;
/* include files */
case N_BINCL:
str =
(const char *) stabstr_section->data + sym->n_strx;
add_incl2:
if (incl_index < INCLUDE_STACK_SIZE) {
incl_files[incl_index++] = str;
}
break;
case N_EINCL:
if (incl_index > 1)
incl_index--;
break;
case N_SO:
if (sym->n_strx == 0) {
incl_index = 0; /* end of translation unit */
} else {
str =
(const char *) stabstr_section->data +
sym->n_strx;
/* do not add path */
len = strlen(str);
if (len > 0 && str[len - 1] != '/')
goto add_incl2;
}
break;
}
sym++;
}
}
}
// write symbol table
if (do_debug) {
int k;
struct syment csym;
AUXFUNC auxfunc;
AUXBF auxbf;
AUXEF auxef;
int i;
Elf32_Sym *p;
char *name;
char _name[MAX_FUNCS];
int nstr;
int n = 0;
Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE);
pCoff_str_table = Coff_str_table;
nstr = 0;
p = (Elf32_Sym *) symtab_section->data;
for (i = 0; i < nb_syms; i++) {
/* don't add underscores for Code Composer Version 2.xx */
#define ADD_UNDERSCORE 0
name = (char *) symtab_section->link->data + p->st_name;
#if ADD_UNDERSCORE
_name[0] = '_';
strcpy(_name + 1, name);
#else
strcpy(_name, name);
#endif
for (k = 0; k < 8; k++)
csym._n._n_name[k] = 0;
if (strlen(_name) <= 8) {
strcpy(csym._n._n_name, _name);
} else {
if (pCoff_str_table - Coff_str_table + strlen(_name) >
MAX_STR_TABLE - 1)
error("String table too large");
csym._n._n_n._n_zeroes = 0;
csym._n._n_n._n_offset =
pCoff_str_table - Coff_str_table + 4;
strcpy(pCoff_str_table, _name);
pCoff_str_table += strlen(_name) + 1; // skip over null
nstr++;
}
if (p->st_info == 4) {
// put a filename symbol
csym.n_value = 33; // ?????
csym.n_scnum = N_DEBUG;
csym.n_type = 0;
csym.n_sclass = C_FILE;
csym.n_numaux = 0;
fwrite(&csym, 18, 1, f);
n++;
} else if (p->st_info == 0x12) {
// find the function data
for (k = 0; k < nFuncs; k++) {
if (strcmp(name, Func[k]) == 0)
break;
}
if (k >= nFuncs) {
char s[256];
sprintf(s, "debug info can't find function: %s", name);
error(s);
}
// put a Function Name
csym.n_value = p->st_value; // physical address
csym.n_scnum = CoffTextSectionNo;
csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0);
csym.n_sclass = C_EXT;
csym.n_numaux = 1;
fwrite(&csym, 18, 1, f);
// now put aux info
auxfunc.tag = 0;
auxfunc.size = EndAddress[k] - p->st_value;
auxfunc.fileptr = LineNoFilePtr[k];
auxfunc.nextsym = n + 6; // tktk
auxfunc.dummy = 0;
fwrite(&auxfunc, 18, 1, f);
// put a .bf
strcpy(csym._n._n_name, ".bf");
csym.n_value = p->st_value; // physical address
csym.n_scnum = CoffTextSectionNo;
csym.n_type = 0;
csym.n_sclass = C_FCN;
csym.n_numaux = 1;
fwrite(&csym, 18, 1, f);
// now put aux info
auxbf.regmask = 0;
auxbf.lineno = 0;
auxbf.nentries = FuncEntries[k];
auxbf.localframe = 0;
auxbf.nextentry = n + 6;
auxbf.dummy = 0;
fwrite(&auxbf, 18, 1, f);
// put a .ef
strcpy(csym._n._n_name, ".ef");
csym.n_value = EndAddress[k]; // physical address
csym.n_scnum = CoffTextSectionNo;
csym.n_type = 0;
csym.n_sclass = C_FCN;
csym.n_numaux = 1;
fwrite(&csym, 18, 1, f);
// now put aux info
auxef.dummy = 0;
auxef.lineno = LastLineNo[k];
auxef.dummy1 = 0;
auxef.dummy2 = 0;
auxef.dummy3 = 0;
auxef.dummy4 = 0;
fwrite(&auxef, 18, 1, f);
n += 6;
} else {
// try an put some type info
if ((p->st_other & VT_BTYPE) == VT_DOUBLE) {
csym.n_type = T_DOUBLE; // int
csym.n_sclass = C_EXT;
} else if ((p->st_other & VT_BTYPE) == VT_FLOAT) {
csym.n_type = T_FLOAT;
csym.n_sclass = C_EXT;
} else if ((p->st_other & VT_BTYPE) == VT_INT) {
csym.n_type = T_INT; // int
csym.n_sclass = C_EXT;
} else if ((p->st_other & VT_BTYPE) == VT_SHORT) {
csym.n_type = T_SHORT;
csym.n_sclass = C_EXT;
} else if ((p->st_other & VT_BTYPE) == VT_BYTE) {
csym.n_type = T_CHAR;
csym.n_sclass = C_EXT;
} else {
csym.n_type = T_INT; // just mark as a label
csym.n_sclass = C_LABEL;
}
csym.n_value = p->st_value;
csym.n_scnum = 2;
csym.n_numaux = 1;
fwrite(&csym, 18, 1, f);
auxfunc.tag = 0;
auxfunc.size = 0x20;
auxfunc.fileptr = 0;
auxfunc.nextsym = 0;
auxfunc.dummy = 0;
fwrite(&auxfunc, 18, 1, f);
n++;
n++;
}
p++;
}
}
if (do_debug) {
// write string table
// first write the size
i = pCoff_str_table - Coff_str_table;
fwrite(&i, 4, 1, f);
// then write the strings
fwrite(Coff_str_table, i, 1, f);
tcc_free(Coff_str_table);
}
return 0;
}
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
void SortSymbolTable(void)
{
int i, j, k, n = 0;
Elf32_Sym *p, *p2, *NewTable;
char *name, *name2;
NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym));
p = (Elf32_Sym *) symtab_section->data;
// find a file symbol, copy it over
// then scan the whole symbol list and copy any function
// symbols that match the file association
for (i = 0; i < nb_syms; i++) {
if (p->st_info == 4) {
name = (char *) symtab_section->link->data + p->st_name;
// this is a file symbol, copy it over
NewTable[n++] = *p;
p2 = (Elf32_Sym *) symtab_section->data;
for (j = 0; j < nb_syms; j++) {
if (p2->st_info == 0x12) {
// this is a func symbol
name2 =
(char *) symtab_section->link->data + p2->st_name;
// find the function data index
for (k = 0; k < nFuncs; k++) {
if (strcmp(name2, Func[k]) == 0)
break;
}
if (k >= nFuncs) {
char s[256];
sprintf(s,
"debug (sort) info can't find function: %s",
name2);
error(s);
}
if (strcmp(AssociatedFile[k], name) == 0) {
// yes they match copy it over
NewTable[n++] = *p2;
}
}
p2++;
}
}
p++;
}
// now all the filename and func symbols should have been copied over
// copy all the rest over (all except file and funcs)
p = (Elf32_Sym *) symtab_section->data;
for (i = 0; i < nb_syms; i++) {
if (p->st_info != 4 && p->st_info != 0x12) {
NewTable[n++] = *p;
}
p++;
}
if (n != nb_syms)
error("Internal Compiler error, debug info");
// copy it all back
p = (Elf32_Sym *) symtab_section->data;
for (i = 0; i < nb_syms; i++) {
*p++ = NewTable[i];
}
tcc_free(NewTable);
}
int FindCoffSymbolIndex(const char *func_name)
{
int i, n = 0;
Elf32_Sym *p;
char *name;
p = (Elf32_Sym *) symtab_section->data;
for (i = 0; i < nb_syms; i++) {
name = (char *) symtab_section->link->data + p->st_name;
if (p->st_info == 4) {
// put a filename symbol
n++;
} else if (p->st_info == 0x12) {
if (strcmp(func_name, name) == 0)
return n;
n += 6;
// put a Function Name
// now put aux info
// put a .bf
// now put aux info
// put a .ef
// now put aux info
} else {
n += 2;
}
p++;
}
return n; // total number of symbols
}
BOOL OutputTheSection(Section * sect)
{
const char *s = sect->name;
if (!strcmp(s, ".text"))
return true;
else if (!strcmp(s, ".data"))
return true;
else
return 0;
}
short int GetCoffFlags(const char *s)
{
if (!strcmp(s, ".text"))
return STYP_TEXT | STYP_DATA | STYP_ALIGN | 0x400;
else if (!strcmp(s, ".data"))
return STYP_DATA;
else if (!strcmp(s, ".bss"))
return STYP_BSS;
else if (!strcmp(s, ".stack"))
return STYP_BSS | STYP_ALIGN | 0x200;
else if (!strcmp(s, ".cinit"))
return STYP_COPY | STYP_DATA | STYP_ALIGN | 0x200;
else
return 0;
}
Section *FindSection(TCCState * s1, const char *sname)
{
Section *s;
int i;
for (i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (!strcmp(sname, s->name))
return s;
}
error("could not find section %s", sname);
return 0;
}
int tcc_load_coff(TCCState * s1, int fd)
{
// tktk TokenSym *ts;
FILE *f;
unsigned int str_size;
char *Coff_str_table, *name;
int i, k;
struct syment csym;
char name2[9];
FILHDR file_hdr; /* FILE HEADER STRUCTURE */
f = fdopen(fd, "rb");
if (!f) {
error("Unable to open .out file for input");
}
if (fread(&file_hdr, FILHSZ, 1, f) != 1)
error("error reading .out file for input");
if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1)
error("error reading .out file for input");
// first read the string table
if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET))
error("error reading .out file for input");
if (fread(&str_size, sizeof(int), 1, f) != 1)
error("error reading .out file for input");
Coff_str_table = (char *) tcc_malloc(str_size);
if (fread(Coff_str_table, str_size - 4, 1, f) != 1)
error("error reading .out file for input");
// read/process all the symbols
// seek back to symbols
if (fseek(f, file_hdr.f_symptr, SEEK_SET))
error("error reading .out file for input");
for (i = 0; i < file_hdr.f_nsyms; i++) {
if (fread(&csym, SYMESZ, 1, f) != 1)
error("error reading .out file for input");
if (csym._n._n_n._n_zeroes == 0) {
name = Coff_str_table + csym._n._n_n._n_offset - 4;
} else {
name = csym._n._n_name;
if (name[7] != 0) {
for (k = 0; k < 8; k++)
name2[k] = name[k];
name2[8] = 0;
name = name2;
}
}
// if (strcmp("_DAC_Buffer",name)==0) // tktk
// name[0]=0;
if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) || // structures
(csym.n_type == 0x18 && csym.n_sclass == 0x2) || // pointer to structure
(csym.n_type == 0x7 && csym.n_sclass == 0x2) || // doubles
(csym.n_type == 0x6 && csym.n_sclass == 0x2)) // floats
{
// strip off any leading underscore (except for other main routine)
if (name[0] == '_' && strcmp(name, "_main") != 0)
name++;
tcc_add_symbol(s1, name, csym.n_value);
}
// skip any aux records
if (csym.n_numaux == 1) {
if (fread(&csym, SYMESZ, 1, f) != 1)
error("error reading .out file for input");
i++;
}
}
return 0;
}

532
tccelf.c
View File

@@ -1,7 +1,7 @@
/*
* ELF file handling for TCC
*
* Copyright (c) 2001, 2002 Fabrice Bellard
* 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
@@ -154,16 +154,25 @@ static int find_elf_sym(Section *s, const char *name)
}
/* return elf symbol value or error */
void *tcc_get_symbol(TCCState *s, const char *name)
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name)
{
int sym_index;
Elf32_Sym *sym;
sym_index = find_elf_sym(symtab_section, name);
if (!sym_index)
error("%s not defined", name);
return -1;
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
return (void *)sym->st_value;
*pval = sym->st_value;
return 0;
}
void *tcc_get_symbol_err(TCCState *s, const char *name)
{
unsigned long val;
if (tcc_get_symbol(s, &val, name) < 0)
error("%s not defined", name);
return (void *)val;
}
/* add an elf symbol : check if it is already defined and patch
@@ -439,9 +448,12 @@ static void relocate_section(TCCState *s1, Section *s)
Section *sr;
Elf32_Rel *rel, *rel_end, *qrel;
Elf32_Sym *sym;
int type, sym_index, esym_index;
int type, sym_index;
unsigned char *ptr;
unsigned long val, addr;
#if defined(TCC_TARGET_I386)
int esym_index;
#endif
sr = s->reloc;
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
@@ -459,6 +471,7 @@ static void relocate_section(TCCState *s1, Section *s)
/* CPU specific */
switch(type) {
#if defined(TCC_TARGET_I386)
case R_386_32:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = s1->symtab_to_dynsym[sym_index];
@@ -504,6 +517,69 @@ static void relocate_section(TCCState *s1, Section *s)
/* we load the got offset */
*(int *)ptr += s1->got_offsets[sym_index];
break;
#elif defined(TCC_TARGET_ARM)
case R_ARM_PC24:
case R_ARM_PLT32:
{
int x;
x = (*(int *)ptr)&0xffffff;
(*(int *)ptr) &= 0xff000000;
if (x & 0x800000)
x -= 0x1000000;
x *= 4;
x += val - addr;
if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000)
error("can't relocate value at %x",addr);
x >>= 2;
x &= 0xffffff;
(*(int *)ptr) |= x;
}
break;
case R_ARM_ABS32:
*(int *)ptr += val;
break;
case R_ARM_GOTPC:
*(int *)ptr += s1->got->sh_addr - addr;
break;
case R_ARM_GOT32:
/* we load the got offset */
*(int *)ptr += s1->got_offsets[sym_index];
break;
case R_ARM_COPY:
break;
default:
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
type,addr,(unsigned int )ptr,val);
break;
#elif defined(TCC_TARGET_C67)
case R_C60_32:
*(int *)ptr += val;
break;
case R_C60LO16:
{
uint32_t orig;
/* put the low 16 bits of the absolute address */
// add to what is already there
orig = ((*(int *)(ptr )) >> 7) & 0xffff;
orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16;
//patch both at once - assumes always in pairs Low - High
*(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7);
*(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7);
}
break;
case R_C60HI16:
break;
default:
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
type,addr,(unsigned int )ptr,val);
break;
#else
#error unsupported processor
#endif
}
}
/* if the relocation is allocated, we change its symbol table */
@@ -589,10 +665,12 @@ static void put32(unsigned char *p, uint32_t val)
p[3] = val >> 24;
}
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM)
static uint32_t get32(unsigned char *p)
{
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
#endif
static void build_got(TCCState *s1)
{
@@ -637,6 +715,7 @@ static void put_got_entry(TCCState *s1,
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
name = symtab_section->link->data + sym->st_name;
offset = sym->st_value;
#ifdef TCC_TARGET_I386
if (reloc_type == R_386_JMP_SLOT) {
Section *plt;
uint8_t *p;
@@ -675,6 +754,42 @@ static void put_got_entry(TCCState *s1,
if (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16;
}
#elif defined(TCC_TARGET_ARM)
if (reloc_type == R_ARM_JUMP_SLOT) {
Section *plt;
uint8_t *p;
/* if we build a DLL, we add a %ebx offset */
if (s1->output_type == TCC_OUTPUT_DLL)
error("DLLs unimplemented!");
/* add a PLT entry */
plt = s1->plt;
if (plt->data_offset == 0) {
/* first plt entry */
p = section_ptr_add(plt, 16);
put32(p , 0xe52de004);
put32(p + 4, 0xe59fe010);
put32(p + 8, 0xe08fe00e);
put32(p + 12, 0xe5bef008);
}
p = section_ptr_add(plt, 16);
put32(p , 0xe59fc004);
put32(p+4, 0xe08fc00c);
put32(p+8, 0xe59cf000);
put32(p+12, s1->got->data_offset);
/* the symbol is modified so that it will be relocated to
the PLT */
if (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16;
}
#elif defined(TCC_TARGET_C67)
error("C67 got not implemented");
#else
#error unsupported CPU
#endif
index = put_elf_sym(s1->dynsym, offset,
size, info, 0, sym->st_shndx, name);
/* put a got entry */
@@ -708,6 +823,7 @@ static void build_got_entries(TCCState *s1)
rel++) {
type = ELF32_R_TYPE(rel->r_info);
switch(type) {
#if defined(TCC_TARGET_I386)
case R_386_GOT32:
case R_386_GOTOFF:
case R_386_GOTPC:
@@ -726,6 +842,47 @@ static void build_got_entries(TCCState *s1)
sym_index);
}
break;
#elif defined(TCC_TARGET_ARM)
case R_ARM_GOT32:
case R_ARM_GOTOFF:
case R_ARM_GOTPC:
case R_ARM_PLT32:
if (!s1->got)
build_got(s1);
if (type == R_ARM_GOT32 || type == R_ARM_PLT32) {
sym_index = ELF32_R_SYM(rel->r_info);
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
/* look at the symbol got offset. If none, then add one */
if (type == R_ARM_GOT32)
reloc_type = R_ARM_GLOB_DAT;
else
reloc_type = R_ARM_JUMP_SLOT;
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
sym_index);
}
break;
#elif defined(TCC_TARGET_C67)
case R_C60_GOT32:
case R_C60_GOTOFF:
case R_C60_GOTPC:
case R_C60_PLT32:
if (!s1->got)
build_got(s1);
if (type == R_C60_GOT32 || type == R_C60_PLT32) {
sym_index = ELF32_R_SYM(rel->r_info);
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
/* look at the symbol got offset. If none, then add one */
if (type == R_C60_GOT32)
reloc_type = R_C60_GLOB_DAT;
else
reloc_type = R_C60_JMP_SLOT;
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
sym_index);
}
break;
#else
#error unsupported CPU
#endif
default:
break;
}
@@ -771,17 +928,39 @@ static void put_dt(Section *dynamic, int dt, unsigned long val)
dyn->d_un.d_val = val;
}
static void add_init_array_defines(TCCState *s1, const char *section_name)
{
Section *s;
long end_offset;
char sym_start[1024];
char sym_end[1024];
snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
s = find_section(s1, section_name);
if (!s) {
end_offset = 0;
s = data_section;
} else {
end_offset = s->data_offset;
}
add_elf_sym(symtab_section,
0, 0,
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
s->sh_num, sym_start);
add_elf_sym(symtab_section,
end_offset, 0,
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
s->sh_num, sym_end);
}
/* add tcc runtime libraries */
static void tcc_add_runtime(TCCState *s1)
{
char buf[1024];
int i;
Section *s;
if (!s1->nostdlib) {
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a");
tcc_add_file(s1, buf);
}
#ifdef CONFIG_TCC_BCHECK
if (do_bounds_check) {
unsigned long *ptr;
@@ -812,12 +991,28 @@ static void tcc_add_runtime(TCCState *s1)
#endif
}
#endif
/* add libc if not memory output */
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
/* add libc */
if (!s1->nostdlib) {
tcc_add_library(s1, "c");
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a");
tcc_add_file(s1, buf);
}
/* add crt end if not memory output */
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o");
}
/* add various standard linker symbols */
}
/* add various standard linker symbols (must be done after the
sections are filled (for example after allocating common
symbols)) */
static void tcc_add_linker_symbols(TCCState *s1)
{
char buf[1024];
int i;
Section *s;
add_elf_sym(symtab_section,
text_section->data_offset, 0,
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
@@ -830,6 +1025,11 @@ static void tcc_add_runtime(TCCState *s1)
bss_section->data_offset, 0,
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
bss_section->sh_num, "_end");
/* horrible new standard ldscript defines */
add_init_array_defines(s1, ".preinit_array");
add_init_array_defines(s1, ".init_array");
add_init_array_defines(s1, ".fini_array");
/* add start and stop symbols for sections whose name can be
expressed in C */
for(i = 1; i < s1->nb_sections; i++) {
@@ -871,8 +1071,27 @@ static char elf_interp[] = "/usr/libexec/ld-elf.so.1";
static char elf_interp[] = "/lib/ld-linux.so.2";
#endif
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
static void tcc_output_binary(TCCState *s1, FILE *f,
const int *section_order)
{
Section *s;
int i, offset, size;
offset = 0;
for(i=1;i<s1->nb_sections;i++) {
s = s1->sections[section_order[i]];
if (s->sh_type != SHT_NOBITS &&
(s->sh_flags & SHF_ALLOC)) {
while (offset < s->sh_offset) {
fputc(0, f);
offset++;
}
size = s->sh_size;
fwrite(s->data, 1, size, f);
offset += size;
}
}
}
/* output an ELF file */
/* XXX: suppress unneeded sections */
@@ -896,8 +1115,9 @@ int tcc_output_file(TCCState *s1, const char *filename)
file_type = s1->output_type;
s1->nb_errors = 0;
if (file_type != TCC_OUTPUT_OBJ)
if (file_type != TCC_OUTPUT_OBJ) {
tcc_add_runtime(s1);
}
phdr = NULL;
section_order = NULL;
@@ -907,9 +1127,10 @@ int tcc_output_file(TCCState *s1, const char *filename)
saved_dynamic_data_offset = 0; /* avoid warning */
if (file_type != TCC_OUTPUT_OBJ) {
relocate_common_syms();
tcc_add_linker_symbols(s1);
if (!s1->static_link) {
const char *name;
int sym_index, index;
@@ -960,7 +1181,7 @@ int tcc_output_file(TCCState *s1, const char *filename)
esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index];
type = ELF32_ST_TYPE(esym->st_info);
if (type == STT_FUNC) {
put_got_entry(s1, R_386_JMP_SLOT, esym->st_size,
put_got_entry(s1, R_JMP_SLOT, esym->st_size,
esym->st_info,
sym - (Elf32_Sym *)symtab_section->data);
} else if (type == STT_OBJECT) {
@@ -972,7 +1193,7 @@ int tcc_output_file(TCCState *s1, const char *filename)
esym->st_info, 0,
bss_section->sh_num, name);
put_elf_reloc(s1->dynsym, bss_section,
offset, R_386_COPY, index);
offset, R_COPY, index);
offset += esym->st_size;
bss_section->data_offset = offset;
}
@@ -1124,21 +1345,36 @@ int tcc_output_file(TCCState *s1, const char *filename)
/* allocate program segment headers */
phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr));
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
} else {
file_offset = 0;
}
if (phnum > 0) {
/* compute section to program header mapping */
if (file_type == TCC_OUTPUT_DLL)
addr = 0;
else
addr = ELF_START_ADDR;
if (s1->has_text_addr) {
int a_offset, p_offset;
addr = s1->text_addr;
/* we ensure that (addr % ELF_PAGE_SIZE) == file_offset %
ELF_PAGE_SIZE */
a_offset = addr & (ELF_PAGE_SIZE - 1);
p_offset = file_offset & (ELF_PAGE_SIZE - 1);
if (a_offset < p_offset)
a_offset += ELF_PAGE_SIZE;
file_offset += (a_offset - p_offset);
} else {
if (file_type == TCC_OUTPUT_DLL)
addr = 0;
else
addr = ELF_START_ADDR;
/* compute address after headers */
addr += (file_offset & (ELF_PAGE_SIZE - 1));
}
/* dynamic relocation table information, for .dynamic section */
rel_size = 0;
rel_addr = 0;
/* compute address after headers */
addr += (file_offset & (ELF_PAGE_SIZE - 1));
/* leave one program header for the program interpreter */
ph = &phdr[0];
if (interp)
@@ -1189,11 +1425,11 @@ int tcc_output_file(TCCState *s1, const char *filename)
section_order[sh_order_index++] = i;
/* section matches: we align it and add its size */
tmp = file_offset;
file_offset = (file_offset + s->sh_addralign - 1) &
tmp = addr;
addr = (addr + s->sh_addralign - 1) &
~(s->sh_addralign - 1);
file_offset += addr - tmp;
s->sh_offset = file_offset;
addr += file_offset - tmp;
s->sh_addr = addr;
/* update program header infos */
@@ -1216,10 +1452,18 @@ int tcc_output_file(TCCState *s1, const char *filename)
ph->p_filesz = file_offset - ph->p_offset;
ph->p_memsz = addr - ph->p_vaddr;
ph++;
/* if in the middle of a page, we duplicate the page in
memory so that one copy is RX and the other is RW */
if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
addr += ELF_PAGE_SIZE;
if (j == 0) {
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
/* if in the middle of a page, we duplicate the page in
memory so that one copy is RX and the other is RW */
if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
addr += ELF_PAGE_SIZE;
} else {
addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1);
file_offset = (file_offset + ELF_PAGE_SIZE - 1) &
~(ELF_PAGE_SIZE - 1);
}
}
}
/* if interpreter, then add corresponing program header */
@@ -1261,6 +1505,7 @@ int tcc_output_file(TCCState *s1, const char *filename)
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
#if defined(TCC_TARGET_I386)
put32(p + 2, get32(p + 2) + s1->got->sh_addr);
put32(p + 8, get32(p + 8) + s1->got->sh_addr);
p += 16;
@@ -1268,6 +1513,19 @@ int tcc_output_file(TCCState *s1, const char *filename)
put32(p + 2, get32(p + 2) + s1->got->sh_addr);
p += 16;
}
#elif defined(TCC_TARGET_ARM)
int x;
x=s1->got->sh_addr - s1->plt->sh_addr - 12;
p +=16;
while (p < p_end) {
put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
p += 16;
}
#elif defined(TCC_TARGET_C67)
/* XXX: TODO */
#else
#error unsupported CPU
#endif
}
}
@@ -1350,97 +1608,112 @@ int tcc_output_file(TCCState *s1, const char *filename)
/* get entry point address */
if (file_type == TCC_OUTPUT_EXE)
ehdr.e_entry = (unsigned long)tcc_get_symbol(s1, "_start");
ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start");
else
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
}
sort_syms(s1, symtab_section);
/* align to 4 */
file_offset = (file_offset + 3) & -4;
/* fill header */
ehdr.e_ident[0] = ELFMAG0;
ehdr.e_ident[1] = ELFMAG1;
ehdr.e_ident[2] = ELFMAG2;
ehdr.e_ident[3] = ELFMAG3;
ehdr.e_ident[4] = ELFCLASS32;
ehdr.e_ident[5] = ELFDATA2LSB;
ehdr.e_ident[6] = EV_CURRENT;
#ifdef __FreeBSD__
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
#endif
switch(file_type) {
default:
case TCC_OUTPUT_EXE:
ehdr.e_type = ET_EXEC;
break;
case TCC_OUTPUT_DLL:
ehdr.e_type = ET_DYN;
break;
case TCC_OUTPUT_OBJ:
ehdr.e_type = ET_REL;
break;
}
ehdr.e_machine = EM_386;
ehdr.e_version = EV_CURRENT;
ehdr.e_shoff = file_offset;
ehdr.e_ehsize = sizeof(Elf32_Ehdr);
ehdr.e_shentsize = sizeof(Elf32_Shdr);
ehdr.e_shnum = shnum;
ehdr.e_shstrndx = shnum - 1;
/* write elf file */
if (file_type == TCC_OUTPUT_OBJ)
mode = 0666;
else
mode = 0777;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
if (fd < 0) {
error_noabort("could not write '%s'", filename);
goto fail;
}
f = fdopen(fd, "w");
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
for(i=1;i<s1->nb_sections;i++) {
s = s1->sections[section_order[i]];
if (s->sh_type != SHT_NOBITS) {
while (offset < s->sh_offset) {
fputc(0, f);
offset++;
}
size = s->sh_size;
fwrite(s->data, 1, size, f);
offset += size;
}
}
while (offset < ehdr.e_shoff) {
fputc(0, f);
offset++;
}
f = fdopen(fd, "wb");
#ifdef TCC_TARGET_COFF
if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) {
tcc_output_coff(s1, f);
} else
#endif
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
sort_syms(s1, symtab_section);
/* align to 4 */
file_offset = (file_offset + 3) & -4;
/* output section headers */
for(i=0;i<s1->nb_sections;i++) {
sh = &shdr;
memset(sh, 0, sizeof(Elf32_Shdr));
s = s1->sections[i];
if (s) {
sh->sh_name = s->sh_name;
sh->sh_type = s->sh_type;
sh->sh_flags = s->sh_flags;
sh->sh_entsize = s->sh_entsize;
sh->sh_info = s->sh_info;
if (s->link)
sh->sh_link = s->link->sh_num;
sh->sh_addralign = s->sh_addralign;
sh->sh_addr = s->sh_addr;
sh->sh_offset = s->sh_offset;
sh->sh_size = s->sh_size;
/* fill header */
ehdr.e_ident[0] = ELFMAG0;
ehdr.e_ident[1] = ELFMAG1;
ehdr.e_ident[2] = ELFMAG2;
ehdr.e_ident[3] = ELFMAG3;
ehdr.e_ident[4] = ELFCLASS32;
ehdr.e_ident[5] = ELFDATA2LSB;
ehdr.e_ident[6] = EV_CURRENT;
#ifdef __FreeBSD__
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
#endif
#ifdef TCC_TARGET_ARM
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
#endif
switch(file_type) {
default:
case TCC_OUTPUT_EXE:
ehdr.e_type = ET_EXEC;
break;
case TCC_OUTPUT_DLL:
ehdr.e_type = ET_DYN;
break;
case TCC_OUTPUT_OBJ:
ehdr.e_type = ET_REL;
break;
}
fwrite(sh, 1, sizeof(Elf32_Shdr), f);
ehdr.e_machine = EM_TCC_TARGET;
ehdr.e_version = EV_CURRENT;
ehdr.e_shoff = file_offset;
ehdr.e_ehsize = sizeof(Elf32_Ehdr);
ehdr.e_shentsize = sizeof(Elf32_Shdr);
ehdr.e_shnum = shnum;
ehdr.e_shstrndx = shnum - 1;
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
for(i=1;i<s1->nb_sections;i++) {
s = s1->sections[section_order[i]];
if (s->sh_type != SHT_NOBITS) {
while (offset < s->sh_offset) {
fputc(0, f);
offset++;
}
size = s->sh_size;
fwrite(s->data, 1, size, f);
offset += size;
}
}
/* output section headers */
while (offset < ehdr.e_shoff) {
fputc(0, f);
offset++;
}
for(i=0;i<s1->nb_sections;i++) {
sh = &shdr;
memset(sh, 0, sizeof(Elf32_Shdr));
s = s1->sections[i];
if (s) {
sh->sh_name = s->sh_name;
sh->sh_type = s->sh_type;
sh->sh_flags = s->sh_flags;
sh->sh_entsize = s->sh_entsize;
sh->sh_info = s->sh_info;
if (s->link)
sh->sh_link = s->link->sh_num;
sh->sh_addralign = s->sh_addralign;
sh->sh_addr = s->sh_addr;
sh->sh_offset = s->sh_offset;
sh->sh_size = s->sh_size;
}
fwrite(sh, 1, sizeof(Elf32_Shdr), f);
}
} else {
tcc_output_binary(s1, f, section_order);
}
fclose(f);
@@ -1466,7 +1739,8 @@ static void *load_data(int fd, unsigned long file_offset, unsigned long size)
typedef struct SectionMergeInfo {
Section *s; /* corresponding existing section */
unsigned long offset; /* offset of the new section in the existing section */
int new_section; /* true if section 's' was added */
uint8_t new_section; /* true if section 's' was added */
uint8_t link_once; /* true if link once section */
} SectionMergeInfo;
/* load an object file and merge it with current files */
@@ -1497,7 +1771,7 @@ static int tcc_load_object_file(TCCState *s1,
goto fail1;
/* test CPU specific stuff */
if (ehdr.e_ident[5] != ELFDATA2LSB ||
ehdr.e_machine != EM_386) {
ehdr.e_machine != EM_TCC_TARGET) {
fail1:
error_noabort("invalid object file");
return -1;
@@ -1553,8 +1827,19 @@ static int tcc_load_object_file(TCCState *s1,
/* find corresponding section, if any */
for(j = 1; j < s1->nb_sections;j++) {
s = s1->sections[j];
if (!strcmp(s->name, sh_name))
goto found;
if (!strcmp(s->name, sh_name)) {
if (!strncmp(sh_name, ".gnu.linkonce",
sizeof(".gnu.linkonce") - 1)) {
/* if a 'linkonce' section is already present, we
do not add it again. It is a little tricky as
symbols can still be defined in
it. */
sm_table[i].link_once = 1;
goto next;
} else {
goto found;
}
}
}
/* not found: create new section */
s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags);
@@ -1588,6 +1873,7 @@ static int tcc_load_object_file(TCCState *s1,
} else {
s->data_offset += size;
}
next: ;
}
/* second short pass to update sh_link and sh_info fields of new
@@ -1615,6 +1901,18 @@ static int tcc_load_object_file(TCCState *s1,
if (sym->st_shndx != SHN_UNDEF &&
sym->st_shndx < SHN_LORESERVE) {
sm = &sm_table[sym->st_shndx];
if (sm->link_once) {
/* if a symbol is in a link once section, we use the
already defined symbol. It is very important to get
correct relocations */
if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
name = strtab + sym->st_name;
sym_index = find_elf_sym(symtab_section, name);
if (sym_index)
old_to_new_syms[i] = sym_index;
}
continue;
}
/* if no corresponding section added, no need to add symbol */
if (!sm->s)
continue;
@@ -1811,7 +2109,7 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
/* test CPU specific stuff */
if (ehdr.e_ident[5] != ELFDATA2LSB ||
ehdr.e_machine != EM_386) {
ehdr.e_machine != EM_TCC_TARGET) {
error_noabort("bad architecture");
return -1;
}

View File

@@ -16,6 +16,9 @@
#endif
/* deprecated and no longer supported in gcc 3.3 */
//#define ACCEPT_CR_IN_STRINGS
/* __VA_ARGS__ and __func__ support */
#define C99_MACROS
@@ -1303,6 +1306,16 @@ void bitfield_test(void)
st1.f5++;
printf("%d %d %d %d %d\n",
st1.f1, st1.f2, st1.f3, st1.f4, st1.f5);
st1.f1 = 7;
if (st1.f1 == -1)
printf("st1.f1 == -1\n");
else
printf("st1.f1 != -1\n");
if (st1.f2 == -1)
printf("st1.f2 == -1\n");
else
printf("st1.f2 != -1\n");
}
#define FTEST(prefix, type, fmt)\
@@ -1589,6 +1602,15 @@ void longlong_test(void)
printf("%lld\n", value(&a));
}
lloptest(0x80000000, 0);
/* another long long spill test */
{
long long *p, v;
v = 1;
p = &v;
p[0]++;
printf("%lld\n", *p);
}
}
void vprintf1(const char *fmt, ...)
@@ -1660,6 +1682,8 @@ ntf("aaa=%d\n", 3);
pri\
\
ntf("min=%d\n", 4);
#ifdef ACCEPT_CR_IN_STRINGS
printf("len1=%d\n", strlen("
"));
@@ -1669,6 +1693,7 @@ ntf("min=%d\n", 4);
printf("len1=%d str[0]=%d\n", strlen(str), str[0]);
#endif
printf("len1=%d\n", strlen("
a
"));
#endif /* ACCEPT_CR_IN_STRINGS */
}
@@ -1943,3 +1968,13 @@ void builtin_test(void)
printf("res = %d\n", __builtin_constant_p(1));
printf("res = %d\n", __builtin_constant_p(1 + 2));
printf("res = %d\n", __builtin_constant_p(&constant_p_var));
printf("res = %d\n", __builtin_constant_p(constant_p_var));
}
void const_func(const int a)
{
}
void const_warn_test(void)
{

View File

@@ -90,6 +90,8 @@
DEF(TOK_SECTION2, "__section__")
DEF(TOK_ALIGNED1, "aligned")
DEF(TOK_ALIGNED2, "__aligned__")
DEF(TOK_PACKED1, "packed")
DEF(TOK_PACKED2, "__packed__")
DEF(TOK_UNUSED1, "unused")
DEF(TOK_UNUSED2, "__unused__")
DEF(TOK_CDECL1, "cdecl")
@@ -102,6 +104,8 @@
DEF(TOK_NORETURN2, "__noreturn__")
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
/* builtin functions or variables */
DEF(TOK_memcpy, "memcpy")
@@ -111,9 +115,37 @@
DEF(TOK___moddi3, "__moddi3")
DEF(TOK___udivdi3, "__udivdi3")
DEF(TOK___umoddi3, "__umoddi3")
#if defined(TCC_TARGET_ARM)
DEF(TOK___divsi3, "__divsi3")
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___fixunssfsi, "__fixunssfsi")
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
DEF(TOK___fixxfdi, "__fixxfdi")
#elif defined(TCC_TARGET_C67)
DEF(TOK__divi, "_divi")
DEF(TOK__divu, "_divu")
DEF(TOK__divf, "_divf")
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
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
DEF(TOK___ulltof, "__ulltof")
@@ -151,10 +183,17 @@
DEF_ASM(skip)
DEF_ASM(space)
DEF_ASM(string)
DEF_ASM(asciz)
DEF_ASM(ascii)
DEF_ASM(globl)
DEF_ASM(global)
DEF_ASM(text)
DEF_ASM(data)
DEF_ASM(bss)
DEF_ASM(previous)
DEF_ASM(fill)
DEF_ASM(org)
DEF_ASM(quad)
#ifdef TCC_TARGET_I386