mirror of
https://github.com/mirror/tinycc.git
synced 2026-08-26 11:43:27 +08:00
Compare commits
65 Commits
release_0_
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b8d7f44b4 | ||
|
|
27feb1adac | ||
|
|
1c1919072b | ||
|
|
be5e9cb962 | ||
|
|
48c85f1b15 | ||
|
|
398e22c541 | ||
|
|
6bbfb8f610 | ||
|
|
1d0e5e8b01 | ||
|
|
1e1d3ff687 | ||
|
|
736b565766 | ||
|
|
c2ec76a41f | ||
|
|
6b52984ce4 | ||
|
|
c9c05ca5f0 | ||
|
|
32ba2eadf6 | ||
|
|
3e74b91de6 | ||
|
|
e657dfb491 | ||
|
|
2a6c104722 | ||
|
|
38e8a23025 | ||
|
|
bb07bf31aa | ||
|
|
eb79471184 | ||
|
|
59c3563827 | ||
|
|
45466d2df6 | ||
|
|
807321efba | ||
|
|
ff3a5daf25 | ||
|
|
0bd402d2eb | ||
|
|
9668499b9f | ||
|
|
72a88fbab0 | ||
|
|
4d9f6d2bcf | ||
|
|
d65463809c | ||
|
|
62f99adb71 | ||
|
|
aa7ef7919e | ||
|
|
13affef3f1 | ||
|
|
c50af8399d | ||
|
|
ec7d36326d | ||
|
|
bf45336afb | ||
|
|
6e5b1cc43a | ||
|
|
3bd3c71fd1 | ||
|
|
79c72b2419 | ||
|
|
df36de6507 | ||
|
|
c52df4de38 | ||
|
|
8da6027e73 | ||
|
|
c1265d1616 | ||
|
|
22d8df96c6 | ||
|
|
8da2d689df | ||
|
|
fe203057c2 | ||
|
|
114883e078 | ||
|
|
7a5123a770 | ||
|
|
4df5bd2eb0 | ||
|
|
44cea6aee9 | ||
|
|
77a19bf50e | ||
|
|
b7f12dfbdf | ||
|
|
9890ea1233 | ||
|
|
feed3262c9 | ||
|
|
bef8703f77 | ||
|
|
46169b92d9 | ||
|
|
d369a77647 | ||
|
|
c5ce5eaeda | ||
|
|
9c1106d854 | ||
|
|
f8d0241764 | ||
|
|
c5959b77b4 | ||
|
|
7b940fcb1b | ||
|
|
21d2d99bdc | ||
|
|
277e01cd64 | ||
|
|
9d95be78c8 | ||
|
|
370f5e571c |
@@ -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
|
||||
|
||||
39
Changelog
39
Changelog
@@ -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)
|
||||
|
||||
78
Makefile
78
Makefile
@@ -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
2
README
@@ -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
12
TODO
@@ -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
|
||||
|
||||
16
asmtest.S
16
asmtest.S
@@ -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
|
||||
|
||||
26
bcheck.c
26
bcheck.c
@@ -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);
|
||||
|
||||
446
coff.h
Normal file
446
coff.h
Normal 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
59
configure
vendored
@@ -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
18
elf.h
@@ -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
8
ex1.c
Executable 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
97
ex2.c
Normal 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
23
ex3.c
Normal 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
25
ex4.c
Executable 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
8
ex5.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
}
|
||||
33
gcctestsuite.sh
Executable file
33
gcctestsuite.sh
Executable 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."
|
||||
241
i386-asm.c
241
i386-asm.c
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
i386-asm.h
10
i386-asm.h
@@ -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)
|
||||
|
||||
72
i386-gen.c
72
i386-gen.c
@@ -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 */
|
||||
|
||||
8
libtcc.h
8
libtcc.h
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
2
stddef.h
2
stddef.h
@@ -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;
|
||||
|
||||
88
tcc-doc.texi
88
tcc-doc.texi
@@ -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
|
||||
|
||||
284
tccasm.c
284
tccasm.c
@@ -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
967
tcccoff.c
Normal 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 = §ion_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 = §ion_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 = §ion_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 = §ion_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 = §ion_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 = §ion_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 = §ion_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 = §ion_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
532
tccelf.c
@@ -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;
|
||||
}
|
||||
|
||||
35
tcctest.c
35
tcctest.c
@@ -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)
|
||||
{
|
||||
|
||||
39
tcctok.h
39
tcctok.h
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user