move parser/generator to tccgen.c
[tinycc.git] / tcc.c
blob8f18a8d1d0f917facfc32ecd862944208a19bd48
1 /*
2 * TCC - Tiny C Compiler
3 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "tcc.h"
23 #ifdef TCC_TARGET_I386
24 #include "i386-gen.c"
25 #endif
27 #ifdef TCC_TARGET_ARM
28 #include "arm-gen.c"
29 #endif
31 #ifdef TCC_TARGET_C67
32 #include "c67-gen.c"
33 #endif
35 #ifdef TCC_TARGET_X86_64
36 #include "x86_64-gen.c"
37 #endif
39 #ifdef CONFIG_TCC_STATIC
41 #define RTLD_LAZY 0x001
42 #define RTLD_NOW 0x002
43 #define RTLD_GLOBAL 0x100
44 #define RTLD_DEFAULT NULL
46 /* dummy function for profiling */
47 void *dlopen(const char *filename, int flag)
49 return NULL;
52 void dlclose(void *p)
56 const char *dlerror(void)
58 return "error";
61 typedef struct TCCSyms {
62 char *str;
63 void *ptr;
64 } TCCSyms;
66 #define TCCSYM(a) { #a, &a, },
68 /* add the symbol you want here if no dynamic linking is done */
69 static TCCSyms tcc_syms[] = {
70 #if !defined(CONFIG_TCCBOOT)
71 TCCSYM(printf)
72 TCCSYM(fprintf)
73 TCCSYM(fopen)
74 TCCSYM(fclose)
75 #endif
76 { NULL, NULL },
79 void *resolve_sym(TCCState *s1, const char *symbol, int type)
81 TCCSyms *p;
82 p = tcc_syms;
83 while (p->str != NULL) {
84 if (!strcmp(p->str, symbol))
85 return p->ptr;
86 p++;
88 return NULL;
91 #elif !defined(_WIN32)
93 #include <dlfcn.h>
95 void *resolve_sym(TCCState *s1, const char *sym, int type)
97 return dlsym(RTLD_DEFAULT, sym);
100 #endif
102 /********************************************************/
104 /* we use our own 'finite' function to avoid potential problems with
105 non standard math libs */
106 /* XXX: endianness dependent */
107 int ieee_finite(double d)
109 int *p = (int *)&d;
110 return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
113 /* copy a string and truncate it. */
114 static char *pstrcpy(char *buf, int buf_size, const char *s)
116 char *q, *q_end;
117 int c;
119 if (buf_size > 0) {
120 q = buf;
121 q_end = buf + buf_size - 1;
122 while (q < q_end) {
123 c = *s++;
124 if (c == '\0')
125 break;
126 *q++ = c;
128 *q = '\0';
130 return buf;
133 /* strcat and truncate. */
134 static char *pstrcat(char *buf, int buf_size, const char *s)
136 int len;
137 len = strlen(buf);
138 if (len < buf_size)
139 pstrcpy(buf + len, buf_size - len, s);
140 return buf;
143 #ifndef LIBTCC
144 static int strstart(const char *str, const char *val, const char **ptr)
146 const char *p, *q;
147 p = str;
148 q = val;
149 while (*q != '\0') {
150 if (*p != *q)
151 return 0;
152 p++;
153 q++;
155 if (ptr)
156 *ptr = p;
157 return 1;
159 #endif
161 #ifdef _WIN32
162 #define IS_PATHSEP(c) (c == '/' || c == '\\')
163 #define IS_ABSPATH(p) (IS_PATHSEP(p[0]) || (p[0] && p[1] == ':' && IS_PATHSEP(p[2])))
164 #define PATHCMP stricmp
165 #else
166 #define IS_PATHSEP(c) (c == '/')
167 #define IS_ABSPATH(p) IS_PATHSEP(p[0])
168 #define PATHCMP strcmp
169 #endif
171 /* extract the basename of a file */
172 static char *tcc_basename(const char *name)
174 char *p = strchr(name, 0);
175 while (p > name && !IS_PATHSEP(p[-1]))
176 --p;
177 return p;
180 static char *tcc_fileextension (const char *name)
182 char *b = tcc_basename(name);
183 char *e = strrchr(b, '.');
184 return e ? e : strchr(b, 0);
187 #ifdef _WIN32
188 char *normalize_slashes(char *path)
190 char *p;
191 for (p = path; *p; ++p)
192 if (*p == '\\')
193 *p = '/';
194 return path;
197 void tcc_set_lib_path_w32(TCCState *s)
199 /* on win32, we suppose the lib and includes are at the location
200 of 'tcc.exe' */
201 char path[1024], *p;
202 GetModuleFileNameA(NULL, path, sizeof path);
203 p = tcc_basename(normalize_slashes(strlwr(path)));
204 if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
205 p -= 5;
206 else if (p > path)
207 p--;
208 *p = 0;
209 tcc_set_lib_path(s, path);
211 #endif
213 void set_pages_executable(void *ptr, unsigned long length)
215 #ifdef _WIN32
216 unsigned long old_protect;
217 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
218 #else
219 unsigned long start, end;
220 start = (unsigned long)ptr & ~(PAGESIZE - 1);
221 end = (unsigned long)ptr + length;
222 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
223 mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
224 #endif
227 /* memory management */
228 #ifdef MEM_DEBUG
229 int mem_cur_size;
230 int mem_max_size;
231 unsigned malloc_usable_size(void*);
232 #endif
234 static inline void tcc_free(void *ptr)
236 #ifdef MEM_DEBUG
237 mem_cur_size -= malloc_usable_size(ptr);
238 #endif
239 free(ptr);
242 static void *tcc_malloc(unsigned long size)
244 void *ptr;
245 ptr = malloc(size);
246 if (!ptr && size)
247 error("memory full");
248 #ifdef MEM_DEBUG
249 mem_cur_size += malloc_usable_size(ptr);
250 if (mem_cur_size > mem_max_size)
251 mem_max_size = mem_cur_size;
252 #endif
253 return ptr;
256 static void *tcc_mallocz(unsigned long size)
258 void *ptr;
259 ptr = tcc_malloc(size);
260 memset(ptr, 0, size);
261 return ptr;
264 static inline void *tcc_realloc(void *ptr, unsigned long size)
266 void *ptr1;
267 #ifdef MEM_DEBUG
268 mem_cur_size -= malloc_usable_size(ptr);
269 #endif
270 ptr1 = realloc(ptr, size);
271 #ifdef MEM_DEBUG
272 /* NOTE: count not correct if alloc error, but not critical */
273 mem_cur_size += malloc_usable_size(ptr1);
274 if (mem_cur_size > mem_max_size)
275 mem_max_size = mem_cur_size;
276 #endif
277 return ptr1;
280 static char *tcc_strdup(const char *str)
282 char *ptr;
283 ptr = tcc_malloc(strlen(str) + 1);
284 strcpy(ptr, str);
285 return ptr;
288 #define free(p) use_tcc_free(p)
289 #define malloc(s) use_tcc_malloc(s)
290 #define realloc(p, s) use_tcc_realloc(p, s)
292 static void dynarray_add(void ***ptab, int *nb_ptr, void *data)
294 int nb, nb_alloc;
295 void **pp;
297 nb = *nb_ptr;
298 pp = *ptab;
299 /* every power of two we double array size */
300 if ((nb & (nb - 1)) == 0) {
301 if (!nb)
302 nb_alloc = 1;
303 else
304 nb_alloc = nb * 2;
305 pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
306 if (!pp)
307 error("memory full");
308 *ptab = pp;
310 pp[nb++] = data;
311 *nb_ptr = nb;
314 static void dynarray_reset(void *pp, int *n)
316 void **p;
317 for (p = *(void***)pp; *n; ++p, --*n)
318 if (*p)
319 tcc_free(*p);
320 tcc_free(*(void**)pp);
321 *(void**)pp = NULL;
324 /* symbol allocator */
325 static Sym *__sym_malloc(void)
327 Sym *sym_pool, *sym, *last_sym;
328 int i;
330 sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym));
331 dynarray_add(&sym_pools, &nb_sym_pools, sym_pool);
333 last_sym = sym_free_first;
334 sym = sym_pool;
335 for(i = 0; i < SYM_POOL_NB; i++) {
336 sym->next = last_sym;
337 last_sym = sym;
338 sym++;
340 sym_free_first = last_sym;
341 return last_sym;
344 static inline Sym *sym_malloc(void)
346 Sym *sym;
347 sym = sym_free_first;
348 if (!sym)
349 sym = __sym_malloc();
350 sym_free_first = sym->next;
351 return sym;
354 static inline void sym_free(Sym *sym)
356 sym->next = sym_free_first;
357 sym_free_first = sym;
360 Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
362 Section *sec;
364 sec = tcc_mallocz(sizeof(Section) + strlen(name));
365 strcpy(sec->name, name);
366 sec->sh_type = sh_type;
367 sec->sh_flags = sh_flags;
368 switch(sh_type) {
369 case SHT_HASH:
370 case SHT_REL:
371 case SHT_RELA:
372 case SHT_DYNSYM:
373 case SHT_SYMTAB:
374 case SHT_DYNAMIC:
375 sec->sh_addralign = 4;
376 break;
377 case SHT_STRTAB:
378 sec->sh_addralign = 1;
379 break;
380 default:
381 sec->sh_addralign = 32; /* default conservative alignment */
382 break;
385 if (sh_flags & SHF_PRIVATE) {
386 dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
387 } else {
388 sec->sh_num = s1->nb_sections;
389 dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
392 return sec;
395 static void free_section(Section *s)
397 tcc_free(s->data);
400 /* realloc section and set its content to zero */
401 static void section_realloc(Section *sec, unsigned long new_size)
403 unsigned long size;
404 unsigned char *data;
406 size = sec->data_allocated;
407 if (size == 0)
408 size = 1;
409 while (size < new_size)
410 size = size * 2;
411 data = tcc_realloc(sec->data, size);
412 if (!data)
413 error("memory full");
414 memset(data + sec->data_allocated, 0, size - sec->data_allocated);
415 sec->data = data;
416 sec->data_allocated = size;
419 /* reserve at least 'size' bytes in section 'sec' from
420 sec->data_offset. */
421 static void *section_ptr_add(Section *sec, unsigned long size)
423 unsigned long offset, offset1;
425 offset = sec->data_offset;
426 offset1 = offset + size;
427 if (offset1 > sec->data_allocated)
428 section_realloc(sec, offset1);
429 sec->data_offset = offset1;
430 return sec->data + offset;
433 /* return a reference to a section, and create it if it does not
434 exists */
435 Section *find_section(TCCState *s1, const char *name)
437 Section *sec;
438 int i;
439 for(i = 1; i < s1->nb_sections; i++) {
440 sec = s1->sections[i];
441 if (!strcmp(name, sec->name))
442 return sec;
444 /* sections are created as PROGBITS */
445 return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
448 #define SECTION_ABS ((void *)1)
450 /* update sym->c so that it points to an external symbol in section
451 'section' with value 'value' */
452 static void put_extern_sym2(Sym *sym, Section *section,
453 unsigned long value, unsigned long size,
454 int can_add_underscore)
456 int sym_type, sym_bind, sh_num, info, other, attr;
457 ElfW(Sym) *esym;
458 const char *name;
459 char buf1[256];
461 if (section == NULL)
462 sh_num = SHN_UNDEF;
463 else if (section == SECTION_ABS)
464 sh_num = SHN_ABS;
465 else
466 sh_num = section->sh_num;
468 other = attr = 0;
470 if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
471 sym_type = STT_FUNC;
472 #ifdef TCC_TARGET_PE
473 if (sym->type.ref)
474 attr = sym->type.ref->r;
475 if (FUNC_EXPORT(attr))
476 other |= 1;
477 if (FUNC_CALL(attr) == FUNC_STDCALL)
478 other |= 2;
479 #endif
480 } else {
481 sym_type = STT_OBJECT;
484 if (sym->type.t & VT_STATIC)
485 sym_bind = STB_LOCAL;
486 else
487 sym_bind = STB_GLOBAL;
489 if (!sym->c) {
490 name = get_tok_str(sym->v, NULL);
491 #ifdef CONFIG_TCC_BCHECK
492 if (do_bounds_check) {
493 char buf[32];
495 /* XXX: avoid doing that for statics ? */
496 /* if bound checking is activated, we change some function
497 names by adding the "__bound" prefix */
498 switch(sym->v) {
499 #if 0
500 /* XXX: we rely only on malloc hooks */
501 case TOK_malloc:
502 case TOK_free:
503 case TOK_realloc:
504 case TOK_memalign:
505 case TOK_calloc:
506 #endif
507 case TOK_memcpy:
508 case TOK_memmove:
509 case TOK_memset:
510 case TOK_strlen:
511 case TOK_strcpy:
512 case TOK__alloca:
513 strcpy(buf, "__bound_");
514 strcat(buf, name);
515 name = buf;
516 break;
519 #endif
521 #ifdef TCC_TARGET_PE
522 if ((other & 2) && can_add_underscore) {
523 sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr));
524 name = buf1;
525 } else
526 #endif
527 if (tcc_state->leading_underscore && can_add_underscore) {
528 buf1[0] = '_';
529 pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
530 name = buf1;
532 info = ELFW(ST_INFO)(sym_bind, sym_type);
533 sym->c = add_elf_sym(symtab_section, value, size, info, other, sh_num, name);
534 } else {
535 esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
536 esym->st_value = value;
537 esym->st_size = size;
538 esym->st_shndx = sh_num;
539 esym->st_other |= other;
543 static void put_extern_sym(Sym *sym, Section *section,
544 unsigned long value, unsigned long size)
546 put_extern_sym2(sym, section, value, size, 1);
549 /* add a new relocation entry to symbol 'sym' in section 's' */
550 static void greloc(Section *s, Sym *sym, unsigned long offset, int type)
552 if (!sym->c)
553 put_extern_sym(sym, NULL, 0, 0);
554 /* now we can add ELF relocation info */
555 put_elf_reloc(symtab_section, s, offset, type, sym->c);
558 static inline int isid(int c)
560 return (c >= 'a' && c <= 'z') ||
561 (c >= 'A' && c <= 'Z') ||
562 c == '_';
565 static inline int isnum(int c)
567 return c >= '0' && c <= '9';
570 static inline int isoct(int c)
572 return c >= '0' && c <= '7';
575 static inline int toup(int c)
577 if (c >= 'a' && c <= 'z')
578 return c - 'a' + 'A';
579 else
580 return c;
583 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
585 int len;
586 len = strlen(buf);
587 vsnprintf(buf + len, buf_size - len, fmt, ap);
590 static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
592 va_list ap;
593 va_start(ap, fmt);
594 strcat_vprintf(buf, buf_size, fmt, ap);
595 va_end(ap);
598 void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
600 char buf[2048];
601 BufferedFile **f;
603 buf[0] = '\0';
604 if (file) {
605 for(f = s1->include_stack; f < s1->include_stack_ptr; f++)
606 strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
607 (*f)->filename, (*f)->line_num);
608 if (file->line_num > 0) {
609 strcat_printf(buf, sizeof(buf),
610 "%s:%d: ", file->filename, file->line_num);
611 } else {
612 strcat_printf(buf, sizeof(buf),
613 "%s: ", file->filename);
615 } else {
616 strcat_printf(buf, sizeof(buf),
617 "tcc: ");
619 if (is_warning)
620 strcat_printf(buf, sizeof(buf), "warning: ");
621 strcat_vprintf(buf, sizeof(buf), fmt, ap);
623 if (!s1->error_func) {
624 /* default case: stderr */
625 fprintf(stderr, "%s\n", buf);
626 } else {
627 s1->error_func(s1->error_opaque, buf);
629 if (!is_warning || s1->warn_error)
630 s1->nb_errors++;
633 #ifdef LIBTCC
634 void tcc_set_error_func(TCCState *s, void *error_opaque,
635 void (*error_func)(void *opaque, const char *msg))
637 s->error_opaque = error_opaque;
638 s->error_func = error_func;
640 #endif
642 /* error without aborting current compilation */
643 void error_noabort(const char *fmt, ...)
645 TCCState *s1 = tcc_state;
646 va_list ap;
648 va_start(ap, fmt);
649 error1(s1, 0, fmt, ap);
650 va_end(ap);
653 void error(const char *fmt, ...)
655 TCCState *s1 = tcc_state;
656 va_list ap;
658 va_start(ap, fmt);
659 error1(s1, 0, fmt, ap);
660 va_end(ap);
661 /* better than nothing: in some cases, we accept to handle errors */
662 if (s1->error_set_jmp_enabled) {
663 longjmp(s1->error_jmp_buf, 1);
664 } else {
665 /* XXX: eliminate this someday */
666 exit(1);
670 void expect(const char *msg)
672 error("%s expected", msg);
675 void warning(const char *fmt, ...)
677 TCCState *s1 = tcc_state;
678 va_list ap;
680 if (s1->warn_none)
681 return;
683 va_start(ap, fmt);
684 error1(s1, 1, fmt, ap);
685 va_end(ap);
688 void skip(int c)
690 if (tok != c)
691 error("'%c' expected", c);
692 next();
695 static void test_lvalue(void)
697 if (!(vtop->r & VT_LVAL))
698 expect("lvalue");
701 /* allocate a new token */
702 static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
704 TokenSym *ts, **ptable;
705 int i;
707 if (tok_ident >= SYM_FIRST_ANOM)
708 error("memory full");
710 /* expand token table if needed */
711 i = tok_ident - TOK_IDENT;
712 if ((i % TOK_ALLOC_INCR) == 0) {
713 ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
714 if (!ptable)
715 error("memory full");
716 table_ident = ptable;
719 ts = tcc_malloc(sizeof(TokenSym) + len);
720 table_ident[i] = ts;
721 ts->tok = tok_ident++;
722 ts->sym_define = NULL;
723 ts->sym_label = NULL;
724 ts->sym_struct = NULL;
725 ts->sym_identifier = NULL;
726 ts->len = len;
727 ts->hash_next = NULL;
728 memcpy(ts->str, str, len);
729 ts->str[len] = '\0';
730 *pts = ts;
731 return ts;
734 #define TOK_HASH_INIT 1
735 #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c))
737 /* find a token and add it if not found */
738 static TokenSym *tok_alloc(const char *str, int len)
740 TokenSym *ts, **pts;
741 int i;
742 unsigned int h;
744 h = TOK_HASH_INIT;
745 for(i=0;i<len;i++)
746 h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]);
747 h &= (TOK_HASH_SIZE - 1);
749 pts = &hash_ident[h];
750 for(;;) {
751 ts = *pts;
752 if (!ts)
753 break;
754 if (ts->len == len && !memcmp(ts->str, str, len))
755 return ts;
756 pts = &(ts->hash_next);
758 return tok_alloc_new(pts, str, len);
761 /* CString handling */
763 static void cstr_realloc(CString *cstr, int new_size)
765 int size;
766 void *data;
768 size = cstr->size_allocated;
769 if (size == 0)
770 size = 8; /* no need to allocate a too small first string */
771 while (size < new_size)
772 size = size * 2;
773 data = tcc_realloc(cstr->data_allocated, size);
774 if (!data)
775 error("memory full");
776 cstr->data_allocated = data;
777 cstr->size_allocated = size;
778 cstr->data = data;
781 /* add a byte */
782 static inline void cstr_ccat(CString *cstr, int ch)
784 int size;
785 size = cstr->size + 1;
786 if (size > cstr->size_allocated)
787 cstr_realloc(cstr, size);
788 ((unsigned char *)cstr->data)[size - 1] = ch;
789 cstr->size = size;
792 static void cstr_cat(CString *cstr, const char *str)
794 int c;
795 for(;;) {
796 c = *str;
797 if (c == '\0')
798 break;
799 cstr_ccat(cstr, c);
800 str++;
804 /* add a wide char */
805 static void cstr_wccat(CString *cstr, int ch)
807 int size;
808 size = cstr->size + sizeof(nwchar_t);
809 if (size > cstr->size_allocated)
810 cstr_realloc(cstr, size);
811 *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
812 cstr->size = size;
815 static void cstr_new(CString *cstr)
817 memset(cstr, 0, sizeof(CString));
820 /* free string and reset it to NULL */
821 static void cstr_free(CString *cstr)
823 tcc_free(cstr->data_allocated);
824 cstr_new(cstr);
827 #define cstr_reset(cstr) cstr_free(cstr)
829 /* XXX: unicode ? */
830 static void add_char(CString *cstr, int c)
832 if (c == '\'' || c == '\"' || c == '\\') {
833 /* XXX: could be more precise if char or string */
834 cstr_ccat(cstr, '\\');
836 if (c >= 32 && c <= 126) {
837 cstr_ccat(cstr, c);
838 } else {
839 cstr_ccat(cstr, '\\');
840 if (c == '\n') {
841 cstr_ccat(cstr, 'n');
842 } else {
843 cstr_ccat(cstr, '0' + ((c >> 6) & 7));
844 cstr_ccat(cstr, '0' + ((c >> 3) & 7));
845 cstr_ccat(cstr, '0' + (c & 7));
850 /* XXX: buffer overflow */
851 /* XXX: float tokens */
852 char *get_tok_str(int v, CValue *cv)
854 static char buf[STRING_MAX_SIZE + 1];
855 static CString cstr_buf;
856 CString *cstr;
857 unsigned char *q;
858 char *p;
859 int i, len;
861 /* NOTE: to go faster, we give a fixed buffer for small strings */
862 cstr_reset(&cstr_buf);
863 cstr_buf.data = buf;
864 cstr_buf.size_allocated = sizeof(buf);
865 p = buf;
867 switch(v) {
868 case TOK_CINT:
869 case TOK_CUINT:
870 /* XXX: not quite exact, but only useful for testing */
871 sprintf(p, "%u", cv->ui);
872 break;
873 case TOK_CLLONG:
874 case TOK_CULLONG:
875 /* XXX: not quite exact, but only useful for testing */
876 sprintf(p, "%Lu", cv->ull);
877 break;
878 case TOK_LCHAR:
879 cstr_ccat(&cstr_buf, 'L');
880 case TOK_CCHAR:
881 cstr_ccat(&cstr_buf, '\'');
882 add_char(&cstr_buf, cv->i);
883 cstr_ccat(&cstr_buf, '\'');
884 cstr_ccat(&cstr_buf, '\0');
885 break;
886 case TOK_PPNUM:
887 cstr = cv->cstr;
888 len = cstr->size - 1;
889 for(i=0;i<len;i++)
890 add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
891 cstr_ccat(&cstr_buf, '\0');
892 break;
893 case TOK_LSTR:
894 cstr_ccat(&cstr_buf, 'L');
895 case TOK_STR:
896 cstr = cv->cstr;
897 cstr_ccat(&cstr_buf, '\"');
898 if (v == TOK_STR) {
899 len = cstr->size - 1;
900 for(i=0;i<len;i++)
901 add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
902 } else {
903 len = (cstr->size / sizeof(nwchar_t)) - 1;
904 for(i=0;i<len;i++)
905 add_char(&cstr_buf, ((nwchar_t *)cstr->data)[i]);
907 cstr_ccat(&cstr_buf, '\"');
908 cstr_ccat(&cstr_buf, '\0');
909 break;
910 case TOK_LT:
911 v = '<';
912 goto addv;
913 case TOK_GT:
914 v = '>';
915 goto addv;
916 case TOK_DOTS:
917 return strcpy(p, "...");
918 case TOK_A_SHL:
919 return strcpy(p, "<<=");
920 case TOK_A_SAR:
921 return strcpy(p, ">>=");
922 default:
923 if (v < TOK_IDENT) {
924 /* search in two bytes table */
925 q = tok_two_chars;
926 while (*q) {
927 if (q[2] == v) {
928 *p++ = q[0];
929 *p++ = q[1];
930 *p = '\0';
931 return buf;
933 q += 3;
935 addv:
936 *p++ = v;
937 *p = '\0';
938 } else if (v < tok_ident) {
939 return table_ident[v - TOK_IDENT]->str;
940 } else if (v >= SYM_FIRST_ANOM) {
941 /* special name for anonymous symbol */
942 sprintf(p, "L.%u", v - SYM_FIRST_ANOM);
943 } else {
944 /* should never happen */
945 return NULL;
947 break;
949 return cstr_buf.data;
952 /* push, without hashing */
953 static Sym *sym_push2(Sym **ps, int v, int t, long c)
955 Sym *s;
956 s = sym_malloc();
957 s->v = v;
958 s->type.t = t;
959 s->c = c;
960 s->next = NULL;
961 /* add in stack */
962 s->prev = *ps;
963 *ps = s;
964 return s;
967 /* find a symbol and return its associated structure. 's' is the top
968 of the symbol stack */
969 static Sym *sym_find2(Sym *s, int v)
971 while (s) {
972 if (s->v == v)
973 return s;
974 s = s->prev;
976 return NULL;
979 /* structure lookup */
980 static inline Sym *struct_find(int v)
982 v -= TOK_IDENT;
983 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
984 return NULL;
985 return table_ident[v]->sym_struct;
988 /* find an identifier */
989 static inline Sym *sym_find(int v)
991 v -= TOK_IDENT;
992 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
993 return NULL;
994 return table_ident[v]->sym_identifier;
997 /* push a given symbol on the symbol stack */
998 static Sym *sym_push(int v, CType *type, int r, int c)
1000 Sym *s, **ps;
1001 TokenSym *ts;
1003 if (local_stack)
1004 ps = &local_stack;
1005 else
1006 ps = &global_stack;
1007 s = sym_push2(ps, v, type->t, c);
1008 s->type.ref = type->ref;
1009 s->r = r;
1010 /* don't record fields or anonymous symbols */
1011 /* XXX: simplify */
1012 if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
1013 /* record symbol in token array */
1014 ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
1015 if (v & SYM_STRUCT)
1016 ps = &ts->sym_struct;
1017 else
1018 ps = &ts->sym_identifier;
1019 s->prev_tok = *ps;
1020 *ps = s;
1022 return s;
1025 /* push a global identifier */
1026 static Sym *global_identifier_push(int v, int t, int c)
1028 Sym *s, **ps;
1029 s = sym_push2(&global_stack, v, t, c);
1030 /* don't record anonymous symbol */
1031 if (v < SYM_FIRST_ANOM) {
1032 ps = &table_ident[v - TOK_IDENT]->sym_identifier;
1033 /* modify the top most local identifier, so that
1034 sym_identifier will point to 's' when popped */
1035 while (*ps != NULL)
1036 ps = &(*ps)->prev_tok;
1037 s->prev_tok = NULL;
1038 *ps = s;
1040 return s;
1043 /* pop symbols until top reaches 'b' */
1044 static void sym_pop(Sym **ptop, Sym *b)
1046 Sym *s, *ss, **ps;
1047 TokenSym *ts;
1048 int v;
1050 s = *ptop;
1051 while(s != b) {
1052 ss = s->prev;
1053 v = s->v;
1054 /* remove symbol in token array */
1055 /* XXX: simplify */
1056 if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
1057 ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
1058 if (v & SYM_STRUCT)
1059 ps = &ts->sym_struct;
1060 else
1061 ps = &ts->sym_identifier;
1062 *ps = s->prev_tok;
1064 sym_free(s);
1065 s = ss;
1067 *ptop = b;
1070 /* I/O layer */
1072 BufferedFile *tcc_open(TCCState *s1, const char *filename)
1074 int fd;
1075 BufferedFile *bf;
1077 if (strcmp(filename, "-") == 0)
1078 fd = 0, filename = "stdin";
1079 else
1080 fd = open(filename, O_RDONLY | O_BINARY);
1081 if ((verbose == 2 && fd >= 0) || verbose == 3)
1082 printf("%s %*s%s\n", fd < 0 ? "nf":"->",
1083 (s1->include_stack_ptr - s1->include_stack), "", filename);
1084 if (fd < 0)
1085 return NULL;
1086 bf = tcc_malloc(sizeof(BufferedFile));
1087 bf->fd = fd;
1088 bf->buf_ptr = bf->buffer;
1089 bf->buf_end = bf->buffer;
1090 bf->buffer[0] = CH_EOB; /* put eob symbol */
1091 pstrcpy(bf->filename, sizeof(bf->filename), filename);
1092 #ifdef _WIN32
1093 normalize_slashes(bf->filename);
1094 #endif
1095 bf->line_num = 1;
1096 bf->ifndef_macro = 0;
1097 bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
1098 // printf("opening '%s'\n", filename);
1099 return bf;
1102 void tcc_close(BufferedFile *bf)
1104 total_lines += bf->line_num;
1105 close(bf->fd);
1106 tcc_free(bf);
1109 #include "tccpp.c"
1110 #include "tccgen.c"
1112 /* better than nothing, but needs extension to handle '-E' option
1113 correctly too */
1114 static void preprocess_init(TCCState *s1)
1116 s1->include_stack_ptr = s1->include_stack;
1117 /* XXX: move that before to avoid having to initialize
1118 file->ifdef_stack_ptr ? */
1119 s1->ifdef_stack_ptr = s1->ifdef_stack;
1120 file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
1122 /* XXX: not ANSI compliant: bound checking says error */
1123 vtop = vstack - 1;
1124 s1->pack_stack[0] = 0;
1125 s1->pack_stack_ptr = s1->pack_stack;
1128 /* compile the C file opened in 'file'. Return non zero if errors. */
1129 static int tcc_compile(TCCState *s1)
1131 Sym *define_start;
1132 char buf[512];
1133 volatile int section_sym;
1135 #ifdef INC_DEBUG
1136 printf("%s: **** new file\n", file->filename);
1137 #endif
1138 preprocess_init(s1);
1140 cur_text_section = NULL;
1141 funcname = "";
1142 anon_sym = SYM_FIRST_ANOM;
1144 /* file info: full path + filename */
1145 section_sym = 0; /* avoid warning */
1146 if (do_debug) {
1147 section_sym = put_elf_sym(symtab_section, 0, 0,
1148 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1149 text_section->sh_num, NULL);
1150 getcwd(buf, sizeof(buf));
1151 #ifdef _WIN32
1152 normalize_slashes(buf);
1153 #endif
1154 pstrcat(buf, sizeof(buf), "/");
1155 put_stabs_r(buf, N_SO, 0, 0,
1156 text_section->data_offset, text_section, section_sym);
1157 put_stabs_r(file->filename, N_SO, 0, 0,
1158 text_section->data_offset, text_section, section_sym);
1160 /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
1161 symbols can be safely used */
1162 put_elf_sym(symtab_section, 0, 0,
1163 ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
1164 SHN_ABS, file->filename);
1166 /* define some often used types */
1167 int_type.t = VT_INT;
1169 char_pointer_type.t = VT_BYTE;
1170 mk_pointer(&char_pointer_type);
1172 func_old_type.t = VT_FUNC;
1173 func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
1175 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1176 float_type.t = VT_FLOAT;
1177 double_type.t = VT_DOUBLE;
1179 func_float_type.t = VT_FUNC;
1180 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
1181 func_double_type.t = VT_FUNC;
1182 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
1183 #endif
1185 #if 0
1186 /* define 'void *alloca(unsigned int)' builtin function */
1188 Sym *s1;
1190 p = anon_sym++;
1191 sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
1192 s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
1193 s1->next = NULL;
1194 sym->next = s1;
1195 sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
1197 #endif
1199 define_start = define_stack;
1200 nocode_wanted = 1;
1202 if (setjmp(s1->error_jmp_buf) == 0) {
1203 s1->nb_errors = 0;
1204 s1->error_set_jmp_enabled = 1;
1206 ch = file->buf_ptr[0];
1207 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
1208 parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
1209 next();
1210 decl(VT_CONST);
1211 if (tok != TOK_EOF)
1212 expect("declaration");
1214 /* end of translation unit info */
1215 if (do_debug) {
1216 put_stabs_r(NULL, N_SO, 0, 0,
1217 text_section->data_offset, text_section, section_sym);
1220 s1->error_set_jmp_enabled = 0;
1222 /* reset define stack, but leave -Dsymbols (may be incorrect if
1223 they are undefined) */
1224 free_defines(define_start);
1226 gen_inline_functions();
1228 sym_pop(&global_stack, NULL);
1229 sym_pop(&local_stack, NULL);
1231 return s1->nb_errors != 0 ? -1 : 0;
1234 /* Preprocess the current file */
1235 static int tcc_preprocess(TCCState *s1)
1237 Sym *define_start;
1238 BufferedFile *file_ref;
1239 int token_seen, line_ref;
1241 preprocess_init(s1);
1242 define_start = define_stack;
1243 ch = file->buf_ptr[0];
1244 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
1245 parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS |
1246 PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES;
1247 token_seen = 0;
1248 line_ref = 0;
1249 file_ref = NULL;
1251 for (;;) {
1252 next();
1253 if (tok == TOK_EOF) {
1254 break;
1255 } else if (tok == TOK_LINEFEED) {
1256 if (!token_seen)
1257 continue;
1258 ++line_ref;
1259 token_seen = 0;
1260 } else if (!token_seen) {
1261 int d = file->line_num - line_ref;
1262 if (file != file_ref || d < 0 || d >= 8)
1263 fprintf(s1->outfile, "# %d \"%s\"\n", file->line_num, file->filename);
1264 else
1265 while (d)
1266 fputs("\n", s1->outfile), --d;
1267 line_ref = (file_ref = file)->line_num;
1268 token_seen = 1;
1270 fputs(get_tok_str(tok, &tokc), s1->outfile);
1272 free_defines(define_start);
1273 return 0;
1276 #ifdef LIBTCC
1277 int tcc_compile_string(TCCState *s, const char *str)
1279 BufferedFile bf1, *bf = &bf1;
1280 int ret, len;
1281 char *buf;
1283 /* init file structure */
1284 bf->fd = -1;
1285 /* XXX: avoid copying */
1286 len = strlen(str);
1287 buf = tcc_malloc(len + 1);
1288 if (!buf)
1289 return -1;
1290 memcpy(buf, str, len);
1291 buf[len] = CH_EOB;
1292 bf->buf_ptr = buf;
1293 bf->buf_end = buf + len;
1294 pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
1295 bf->line_num = 1;
1296 file = bf;
1297 ret = tcc_compile(s);
1298 file = NULL;
1299 tcc_free(buf);
1301 /* currently, no need to close */
1302 return ret;
1304 #endif
1306 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
1307 void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
1309 BufferedFile bf1, *bf = &bf1;
1311 pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
1312 pstrcat(bf->buffer, IO_BUF_SIZE, " ");
1313 /* default value */
1314 if (!value)
1315 value = "1";
1316 pstrcat(bf->buffer, IO_BUF_SIZE, value);
1318 /* init file structure */
1319 bf->fd = -1;
1320 bf->buf_ptr = bf->buffer;
1321 bf->buf_end = bf->buffer + strlen(bf->buffer);
1322 *bf->buf_end = CH_EOB;
1323 bf->filename[0] = '\0';
1324 bf->line_num = 1;
1325 file = bf;
1327 s1->include_stack_ptr = s1->include_stack;
1329 /* parse with define parser */
1330 ch = file->buf_ptr[0];
1331 next_nomacro();
1332 parse_define();
1333 file = NULL;
1336 /* undefine a preprocessor symbol */
1337 void tcc_undefine_symbol(TCCState *s1, const char *sym)
1339 TokenSym *ts;
1340 Sym *s;
1341 ts = tok_alloc(sym, strlen(sym));
1342 s = define_find(ts->tok);
1343 /* undefine symbol by putting an invalid name */
1344 if (s)
1345 define_undef(s);
1348 #ifdef CONFIG_TCC_ASM
1350 #ifdef TCC_TARGET_I386
1351 #include "i386-asm.c"
1352 #endif
1353 #include "tccasm.c"
1355 #else
1356 static void asm_instr(void)
1358 error("inline asm() not supported");
1360 static void asm_global_instr(void)
1362 error("inline asm() not supported");
1364 #endif
1366 #include "tccelf.c"
1368 #ifdef TCC_TARGET_COFF
1369 #include "tcccoff.c"
1370 #endif
1372 #ifdef TCC_TARGET_PE
1373 #include "tccpe.c"
1374 #endif
1376 #ifdef CONFIG_TCC_BACKTRACE
1377 /* print the position in the source file of PC value 'pc' by reading
1378 the stabs debug information */
1379 static void rt_printline(unsigned long wanted_pc)
1381 Stab_Sym *sym, *sym_end;
1382 char func_name[128], last_func_name[128];
1383 unsigned long func_addr, last_pc, pc;
1384 const char *incl_files[INCLUDE_STACK_SIZE];
1385 int incl_index, len, last_line_num, i;
1386 const char *str, *p;
1388 fprintf(stderr, "0x%08lx:", wanted_pc);
1390 func_name[0] = '\0';
1391 func_addr = 0;
1392 incl_index = 0;
1393 last_func_name[0] = '\0';
1394 last_pc = 0xffffffff;
1395 last_line_num = 1;
1396 sym = (Stab_Sym *)stab_section->data + 1;
1397 sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
1398 while (sym < sym_end) {
1399 switch(sym->n_type) {
1400 /* function start or end */
1401 case N_FUN:
1402 if (sym->n_strx == 0) {
1403 /* we test if between last line and end of function */
1404 pc = sym->n_value + func_addr;
1405 if (wanted_pc >= last_pc && wanted_pc < pc)
1406 goto found;
1407 func_name[0] = '\0';
1408 func_addr = 0;
1409 } else {
1410 str = stabstr_section->data + sym->n_strx;
1411 p = strchr(str, ':');
1412 if (!p) {
1413 pstrcpy(func_name, sizeof(func_name), str);
1414 } else {
1415 len = p - str;
1416 if (len > sizeof(func_name) - 1)
1417 len = sizeof(func_name) - 1;
1418 memcpy(func_name, str, len);
1419 func_name[len] = '\0';
1421 func_addr = sym->n_value;
1423 break;
1424 /* line number info */
1425 case N_SLINE:
1426 pc = sym->n_value + func_addr;
1427 if (wanted_pc >= last_pc && wanted_pc < pc)
1428 goto found;
1429 last_pc = pc;
1430 last_line_num = sym->n_desc;
1431 /* XXX: slow! */
1432 strcpy(last_func_name, func_name);
1433 break;
1434 /* include files */
1435 case N_BINCL:
1436 str = stabstr_section->data + sym->n_strx;
1437 add_incl:
1438 if (incl_index < INCLUDE_STACK_SIZE) {
1439 incl_files[incl_index++] = str;
1441 break;
1442 case N_EINCL:
1443 if (incl_index > 1)
1444 incl_index--;
1445 break;
1446 case N_SO:
1447 if (sym->n_strx == 0) {
1448 incl_index = 0; /* end of translation unit */
1449 } else {
1450 str = stabstr_section->data + sym->n_strx;
1451 /* do not add path */
1452 len = strlen(str);
1453 if (len > 0 && str[len - 1] != '/')
1454 goto add_incl;
1456 break;
1458 sym++;
1461 /* second pass: we try symtab symbols (no line number info) */
1462 incl_index = 0;
1464 ElfW(Sym) *sym, *sym_end;
1465 int type;
1467 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
1468 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
1469 sym < sym_end;
1470 sym++) {
1471 type = ELFW(ST_TYPE)(sym->st_info);
1472 if (type == STT_FUNC) {
1473 if (wanted_pc >= sym->st_value &&
1474 wanted_pc < sym->st_value + sym->st_size) {
1475 pstrcpy(last_func_name, sizeof(last_func_name),
1476 strtab_section->data + sym->st_name);
1477 goto found;
1482 /* did not find any info: */
1483 fprintf(stderr, " ???\n");
1484 return;
1485 found:
1486 if (last_func_name[0] != '\0') {
1487 fprintf(stderr, " %s()", last_func_name);
1489 if (incl_index > 0) {
1490 fprintf(stderr, " (%s:%d",
1491 incl_files[incl_index - 1], last_line_num);
1492 for(i = incl_index - 2; i >= 0; i--)
1493 fprintf(stderr, ", included from %s", incl_files[i]);
1494 fprintf(stderr, ")");
1496 fprintf(stderr, "\n");
1499 #ifdef __i386__
1500 /* fix for glibc 2.1 */
1501 #ifndef REG_EIP
1502 #define REG_EIP EIP
1503 #define REG_EBP EBP
1504 #endif
1506 /* return the PC at frame level 'level'. Return non zero if not found */
1507 static int rt_get_caller_pc(unsigned long *paddr,
1508 ucontext_t *uc, int level)
1510 unsigned long fp;
1511 int i;
1513 if (level == 0) {
1514 #if defined(__FreeBSD__)
1515 *paddr = uc->uc_mcontext.mc_eip;
1516 #elif defined(__dietlibc__)
1517 *paddr = uc->uc_mcontext.eip;
1518 #else
1519 *paddr = uc->uc_mcontext.gregs[REG_EIP];
1520 #endif
1521 return 0;
1522 } else {
1523 #if defined(__FreeBSD__)
1524 fp = uc->uc_mcontext.mc_ebp;
1525 #elif defined(__dietlibc__)
1526 fp = uc->uc_mcontext.ebp;
1527 #else
1528 fp = uc->uc_mcontext.gregs[REG_EBP];
1529 #endif
1530 for(i=1;i<level;i++) {
1531 /* XXX: check address validity with program info */
1532 if (fp <= 0x1000 || fp >= 0xc0000000)
1533 return -1;
1534 fp = ((unsigned long *)fp)[0];
1536 *paddr = ((unsigned long *)fp)[1];
1537 return 0;
1540 #elif defined(__x86_64__)
1541 /* return the PC at frame level 'level'. Return non zero if not found */
1542 static int rt_get_caller_pc(unsigned long *paddr,
1543 ucontext_t *uc, int level)
1545 unsigned long fp;
1546 int i;
1548 if (level == 0) {
1549 /* XXX: only support linux */
1550 *paddr = uc->uc_mcontext.gregs[REG_RIP];
1551 return 0;
1552 } else {
1553 fp = uc->uc_mcontext.gregs[REG_RBP];
1554 for(i=1;i<level;i++) {
1555 /* XXX: check address validity with program info */
1556 if (fp <= 0x1000)
1557 return -1;
1558 fp = ((unsigned long *)fp)[0];
1560 *paddr = ((unsigned long *)fp)[1];
1561 return 0;
1564 #else
1565 #warning add arch specific rt_get_caller_pc()
1566 static int rt_get_caller_pc(unsigned long *paddr,
1567 ucontext_t *uc, int level)
1569 return -1;
1571 #endif
1573 /* emit a run time error at position 'pc' */
1574 void rt_error(ucontext_t *uc, const char *fmt, ...)
1576 va_list ap;
1577 unsigned long pc;
1578 int i;
1580 va_start(ap, fmt);
1581 fprintf(stderr, "Runtime error: ");
1582 vfprintf(stderr, fmt, ap);
1583 fprintf(stderr, "\n");
1584 for(i=0;i<num_callers;i++) {
1585 if (rt_get_caller_pc(&pc, uc, i) < 0)
1586 break;
1587 if (i == 0)
1588 fprintf(stderr, "at ");
1589 else
1590 fprintf(stderr, "by ");
1591 rt_printline(pc);
1593 exit(255);
1594 va_end(ap);
1597 /* signal handler for fatal errors */
1598 static void sig_error(int signum, siginfo_t *siginf, void *puc)
1600 ucontext_t *uc = puc;
1602 switch(signum) {
1603 case SIGFPE:
1604 switch(siginf->si_code) {
1605 case FPE_INTDIV:
1606 case FPE_FLTDIV:
1607 rt_error(uc, "division by zero");
1608 break;
1609 default:
1610 rt_error(uc, "floating point exception");
1611 break;
1613 break;
1614 case SIGBUS:
1615 case SIGSEGV:
1616 if (rt_bound_error_msg && *rt_bound_error_msg)
1617 rt_error(uc, *rt_bound_error_msg);
1618 else
1619 rt_error(uc, "dereferencing invalid pointer");
1620 break;
1621 case SIGILL:
1622 rt_error(uc, "illegal instruction");
1623 break;
1624 case SIGABRT:
1625 rt_error(uc, "abort() called");
1626 break;
1627 default:
1628 rt_error(uc, "caught signal %d", signum);
1629 break;
1631 exit(255);
1634 #endif
1636 /* copy code into memory passed in by the caller and do all relocations
1637 (needed before using tcc_get_symbol()).
1638 returns -1 on error and required size if ptr is NULL */
1639 int tcc_relocate(TCCState *s1, void *ptr)
1641 Section *s;
1642 unsigned long offset, length, mem;
1643 int i;
1645 if (0 == s1->runtime_added) {
1646 s1->runtime_added = 1;
1647 s1->nb_errors = 0;
1648 #ifdef TCC_TARGET_PE
1649 pe_add_runtime(s1);
1650 relocate_common_syms();
1651 tcc_add_linker_symbols(s1);
1652 #else
1653 tcc_add_runtime(s1);
1654 relocate_common_syms();
1655 tcc_add_linker_symbols(s1);
1656 build_got_entries(s1);
1657 #endif
1660 offset = 0, mem = (unsigned long)ptr;
1661 for(i = 1; i < s1->nb_sections; i++) {
1662 s = s1->sections[i];
1663 if (0 == (s->sh_flags & SHF_ALLOC))
1664 continue;
1665 length = s->data_offset;
1666 s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
1667 offset = (offset + length + 15) & ~15;
1670 /* relocate symbols */
1671 relocate_syms(s1, 1);
1672 if (s1->nb_errors)
1673 return -1;
1675 #ifdef TCC_TARGET_X86_64
1676 s1->runtime_plt_and_got_offset = 0;
1677 s1->runtime_plt_and_got = (char *)(mem + offset);
1678 /* double the size of the buffer for got and plt entries
1679 XXX: calculate exact size for them? */
1680 offset *= 2;
1681 #endif
1683 if (0 == mem)
1684 return offset + 15;
1686 /* relocate each section */
1687 for(i = 1; i < s1->nb_sections; i++) {
1688 s = s1->sections[i];
1689 if (s->reloc)
1690 relocate_section(s1, s);
1693 for(i = 1; i < s1->nb_sections; i++) {
1694 s = s1->sections[i];
1695 if (0 == (s->sh_flags & SHF_ALLOC))
1696 continue;
1697 length = s->data_offset;
1698 // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
1699 ptr = (void*)s->sh_addr;
1700 if (NULL == s->data || s->sh_type == SHT_NOBITS)
1701 memset(ptr, 0, length);
1702 else
1703 memcpy(ptr, s->data, length);
1704 /* mark executable sections as executable in memory */
1705 if (s->sh_flags & SHF_EXECINSTR)
1706 set_pages_executable(ptr, length);
1708 #ifdef TCC_TARGET_X86_64
1709 set_pages_executable(s1->runtime_plt_and_got,
1710 s1->runtime_plt_and_got_offset);
1711 #endif
1712 return 0;
1715 /* launch the compiled program with the given arguments */
1716 int tcc_run(TCCState *s1, int argc, char **argv)
1718 int (*prog_main)(int, char **);
1719 void *ptr;
1720 int ret;
1722 ret = tcc_relocate(s1, NULL);
1723 if (ret < 0)
1724 return -1;
1725 ptr = tcc_malloc(ret);
1726 tcc_relocate(s1, ptr);
1728 prog_main = tcc_get_symbol_err(s1, "main");
1730 if (do_debug) {
1731 #ifdef CONFIG_TCC_BACKTRACE
1732 struct sigaction sigact;
1733 /* install TCC signal handlers to print debug info on fatal
1734 runtime errors */
1735 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
1736 sigact.sa_sigaction = sig_error;
1737 sigemptyset(&sigact.sa_mask);
1738 sigaction(SIGFPE, &sigact, NULL);
1739 sigaction(SIGILL, &sigact, NULL);
1740 sigaction(SIGSEGV, &sigact, NULL);
1741 sigaction(SIGBUS, &sigact, NULL);
1742 sigaction(SIGABRT, &sigact, NULL);
1743 #else
1744 error("debug mode not available");
1745 #endif
1748 #ifdef CONFIG_TCC_BCHECK
1749 if (do_bounds_check) {
1750 void (*bound_init)(void);
1752 /* set error function */
1753 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
1755 /* XXX: use .init section so that it also work in binary ? */
1756 bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init");
1757 bound_init();
1759 #endif
1760 ret = (*prog_main)(argc, argv);
1761 tcc_free(ptr);
1762 return ret;
1765 void tcc_memstats(void)
1767 #ifdef MEM_DEBUG
1768 printf("memory in use: %d\n", mem_cur_size);
1769 #endif
1772 static void tcc_cleanup(void)
1774 int i, n;
1776 if (NULL == tcc_state)
1777 return;
1778 tcc_state = NULL;
1780 /* free -D defines */
1781 free_defines(NULL);
1783 /* free tokens */
1784 n = tok_ident - TOK_IDENT;
1785 for(i = 0; i < n; i++)
1786 tcc_free(table_ident[i]);
1787 tcc_free(table_ident);
1789 /* free sym_pools */
1790 dynarray_reset(&sym_pools, &nb_sym_pools);
1791 /* string buffer */
1792 cstr_free(&tokcstr);
1793 /* reset symbol stack */
1794 sym_free_first = NULL;
1795 /* cleanup from error/setjmp */
1796 macro_ptr = NULL;
1799 TCCState *tcc_new(void)
1801 const char *p, *r;
1802 TCCState *s;
1803 TokenSym *ts;
1804 int i, c;
1806 tcc_cleanup();
1808 s = tcc_mallocz(sizeof(TCCState));
1809 if (!s)
1810 return NULL;
1811 tcc_state = s;
1812 s->output_type = TCC_OUTPUT_MEMORY;
1814 /* init isid table */
1815 for(i=CH_EOF;i<256;i++)
1816 isidnum_table[i-CH_EOF] = isid(i) || isnum(i);
1818 /* add all tokens */
1819 table_ident = NULL;
1820 memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
1822 tok_ident = TOK_IDENT;
1823 p = tcc_keywords;
1824 while (*p) {
1825 r = p;
1826 for(;;) {
1827 c = *r++;
1828 if (c == '\0')
1829 break;
1831 ts = tok_alloc(p, r - p - 1);
1832 p = r;
1835 /* we add dummy defines for some special macros to speed up tests
1836 and to have working defined() */
1837 define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
1838 define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
1839 define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
1840 define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
1842 /* standard defines */
1843 tcc_define_symbol(s, "__STDC__", NULL);
1844 tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
1845 #if defined(TCC_TARGET_I386)
1846 tcc_define_symbol(s, "__i386__", NULL);
1847 #endif
1848 #if defined(TCC_TARGET_X86_64)
1849 tcc_define_symbol(s, "__x86_64__", NULL);
1850 #endif
1851 #if defined(TCC_TARGET_ARM)
1852 tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
1853 tcc_define_symbol(s, "__arm_elf__", NULL);
1854 tcc_define_symbol(s, "__arm_elf", NULL);
1855 tcc_define_symbol(s, "arm_elf", NULL);
1856 tcc_define_symbol(s, "__arm__", NULL);
1857 tcc_define_symbol(s, "__arm", NULL);
1858 tcc_define_symbol(s, "arm", NULL);
1859 tcc_define_symbol(s, "__APCS_32__", NULL);
1860 #endif
1861 #ifdef TCC_TARGET_PE
1862 tcc_define_symbol(s, "_WIN32", NULL);
1863 #else
1864 tcc_define_symbol(s, "__unix__", NULL);
1865 tcc_define_symbol(s, "__unix", NULL);
1866 #if defined(__linux)
1867 tcc_define_symbol(s, "__linux__", NULL);
1868 tcc_define_symbol(s, "__linux", NULL);
1869 #endif
1870 #endif
1871 /* tiny C specific defines */
1872 tcc_define_symbol(s, "__TINYC__", NULL);
1874 /* tiny C & gcc defines */
1875 tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
1876 tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
1877 #ifdef TCC_TARGET_PE
1878 tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
1879 #else
1880 tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
1881 #endif
1883 #ifndef TCC_TARGET_PE
1884 /* default library paths */
1885 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/local/lib");
1886 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/lib");
1887 tcc_add_library_path(s, CONFIG_SYSROOT "/lib");
1888 #endif
1890 /* no section zero */
1891 dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
1893 /* create standard sections */
1894 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1895 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1896 bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
1898 /* symbols are always generated for linking stage */
1899 symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
1900 ".strtab",
1901 ".hashtab", SHF_PRIVATE);
1902 strtab_section = symtab_section->link;
1904 /* private symbol table for dynamic symbols */
1905 s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
1906 ".dynstrtab",
1907 ".dynhashtab", SHF_PRIVATE);
1908 s->alacarte_link = 1;
1910 #ifdef CHAR_IS_UNSIGNED
1911 s->char_is_unsigned = 1;
1912 #endif
1913 #if defined(TCC_TARGET_PE) && 0
1914 /* XXX: currently the PE linker is not ready to support that */
1915 s->leading_underscore = 1;
1916 #endif
1917 return s;
1920 void tcc_delete(TCCState *s1)
1922 int i;
1924 tcc_cleanup();
1926 /* free all sections */
1927 for(i = 1; i < s1->nb_sections; i++)
1928 free_section(s1->sections[i]);
1929 dynarray_reset(&s1->sections, &s1->nb_sections);
1931 for(i = 0; i < s1->nb_priv_sections; i++)
1932 free_section(s1->priv_sections[i]);
1933 dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
1935 /* free any loaded DLLs */
1936 for ( i = 0; i < s1->nb_loaded_dlls; i++) {
1937 DLLReference *ref = s1->loaded_dlls[i];
1938 if ( ref->handle )
1939 dlclose(ref->handle);
1942 /* free loaded dlls array */
1943 dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
1945 /* free library paths */
1946 dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
1948 /* free include paths */
1949 dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
1950 dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
1951 dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
1953 tcc_free(s1);
1956 int tcc_add_include_path(TCCState *s1, const char *pathname)
1958 char *pathname1;
1960 pathname1 = tcc_strdup(pathname);
1961 dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1);
1962 return 0;
1965 int tcc_add_sysinclude_path(TCCState *s1, const char *pathname)
1967 char *pathname1;
1969 pathname1 = tcc_strdup(pathname);
1970 dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1);
1971 return 0;
1974 static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
1976 const char *ext;
1977 ElfW(Ehdr) ehdr;
1978 int fd, ret;
1979 BufferedFile *saved_file;
1981 /* find source file type with extension */
1982 ext = tcc_fileextension(filename);
1983 if (ext[0])
1984 ext++;
1986 /* open the file */
1987 saved_file = file;
1988 file = tcc_open(s1, filename);
1989 if (!file) {
1990 if (flags & AFF_PRINT_ERROR) {
1991 error_noabort("file '%s' not found", filename);
1993 ret = -1;
1994 goto fail1;
1997 if (flags & AFF_PREPROCESS) {
1998 ret = tcc_preprocess(s1);
1999 } else if (!ext[0] || !PATHCMP(ext, "c")) {
2000 /* C file assumed */
2001 ret = tcc_compile(s1);
2002 } else
2003 #ifdef CONFIG_TCC_ASM
2004 if (!strcmp(ext, "S")) {
2005 /* preprocessed assembler */
2006 ret = tcc_assemble(s1, 1);
2007 } else if (!strcmp(ext, "s")) {
2008 /* non preprocessed assembler */
2009 ret = tcc_assemble(s1, 0);
2010 } else
2011 #endif
2012 #ifdef TCC_TARGET_PE
2013 if (!PATHCMP(ext, "def")) {
2014 ret = pe_load_def_file(s1, file->fd);
2015 } else
2016 #endif
2018 fd = file->fd;
2019 /* assume executable format: auto guess file type */
2020 ret = read(fd, &ehdr, sizeof(ehdr));
2021 lseek(fd, 0, SEEK_SET);
2022 if (ret <= 0) {
2023 error_noabort("could not read header");
2024 goto fail;
2025 } else if (ret != sizeof(ehdr)) {
2026 goto try_load_script;
2029 if (ehdr.e_ident[0] == ELFMAG0 &&
2030 ehdr.e_ident[1] == ELFMAG1 &&
2031 ehdr.e_ident[2] == ELFMAG2 &&
2032 ehdr.e_ident[3] == ELFMAG3) {
2033 file->line_num = 0; /* do not display line number if error */
2034 if (ehdr.e_type == ET_REL) {
2035 ret = tcc_load_object_file(s1, fd, 0);
2036 } else if (ehdr.e_type == ET_DYN) {
2037 if (s1->output_type == TCC_OUTPUT_MEMORY) {
2038 #ifdef TCC_TARGET_PE
2039 ret = -1;
2040 #else
2041 void *h;
2042 h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
2043 if (h)
2044 ret = 0;
2045 else
2046 ret = -1;
2047 #endif
2048 } else {
2049 ret = tcc_load_dll(s1, fd, filename,
2050 (flags & AFF_REFERENCED_DLL) != 0);
2052 } else {
2053 error_noabort("unrecognized ELF file");
2054 goto fail;
2056 } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
2057 file->line_num = 0; /* do not display line number if error */
2058 ret = tcc_load_archive(s1, fd);
2059 } else
2060 #ifdef TCC_TARGET_COFF
2061 if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
2062 ret = tcc_load_coff(s1, fd);
2063 } else
2064 #endif
2065 #ifdef TCC_TARGET_PE
2066 if (pe_test_res_file(&ehdr, ret)) {
2067 ret = pe_load_res_file(s1, fd);
2068 } else
2069 #endif
2071 /* as GNU ld, consider it is an ld script if not recognized */
2072 try_load_script:
2073 ret = tcc_load_ldscript(s1);
2074 if (ret < 0) {
2075 error_noabort("unrecognized file type");
2076 goto fail;
2080 the_end:
2081 tcc_close(file);
2082 fail1:
2083 file = saved_file;
2084 return ret;
2085 fail:
2086 ret = -1;
2087 goto the_end;
2090 int tcc_add_file(TCCState *s, const char *filename)
2092 return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR);
2095 int tcc_add_library_path(TCCState *s, const char *pathname)
2097 char *pathname1;
2099 pathname1 = tcc_strdup(pathname);
2100 dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1);
2101 return 0;
2104 /* find and load a dll. Return non zero if not found */
2105 /* XXX: add '-rpath' option support ? */
2106 static int tcc_add_dll(TCCState *s, const char *filename, int flags)
2108 char buf[1024];
2109 int i;
2111 for(i = 0; i < s->nb_library_paths; i++) {
2112 snprintf(buf, sizeof(buf), "%s/%s",
2113 s->library_paths[i], filename);
2114 if (tcc_add_file_internal(s, buf, flags) == 0)
2115 return 0;
2117 return -1;
2120 /* the library name is the same as the argument of the '-l' option */
2121 int tcc_add_library(TCCState *s, const char *libraryname)
2123 char buf[1024];
2124 int i;
2126 /* first we look for the dynamic library if not static linking */
2127 if (!s->static_link) {
2128 #ifdef TCC_TARGET_PE
2129 snprintf(buf, sizeof(buf), "%s.def", libraryname);
2130 #else
2131 snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
2132 #endif
2133 if (tcc_add_dll(s, buf, 0) == 0)
2134 return 0;
2137 /* then we look for the static library */
2138 for(i = 0; i < s->nb_library_paths; i++) {
2139 snprintf(buf, sizeof(buf), "%s/lib%s.a",
2140 s->library_paths[i], libraryname);
2141 if (tcc_add_file_internal(s, buf, 0) == 0)
2142 return 0;
2144 return -1;
2147 int tcc_add_symbol(TCCState *s, const char *name, void *val)
2149 add_elf_sym(symtab_section, (unsigned long)val, 0,
2150 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
2151 SHN_ABS, name);
2152 return 0;
2155 int tcc_set_output_type(TCCState *s, int output_type)
2157 char buf[1024];
2159 s->output_type = output_type;
2161 if (!s->nostdinc) {
2162 /* default include paths */
2163 /* XXX: reverse order needed if -isystem support */
2164 #ifndef TCC_TARGET_PE
2165 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/local/include");
2166 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/include");
2167 #endif
2168 snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path);
2169 tcc_add_sysinclude_path(s, buf);
2170 #ifdef TCC_TARGET_PE
2171 snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path);
2172 tcc_add_sysinclude_path(s, buf);
2173 #endif
2176 /* if bound checking, then add corresponding sections */
2177 #ifdef CONFIG_TCC_BCHECK
2178 if (do_bounds_check) {
2179 /* define symbol */
2180 tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
2181 /* create bounds sections */
2182 bounds_section = new_section(s, ".bounds",
2183 SHT_PROGBITS, SHF_ALLOC);
2184 lbounds_section = new_section(s, ".lbounds",
2185 SHT_PROGBITS, SHF_ALLOC);
2187 #endif
2189 if (s->char_is_unsigned) {
2190 tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
2193 /* add debug sections */
2194 if (do_debug) {
2195 /* stab symbols */
2196 stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
2197 stab_section->sh_entsize = sizeof(Stab_Sym);
2198 stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
2199 put_elf_str(stabstr_section, "");
2200 stab_section->link = stabstr_section;
2201 /* put first entry */
2202 put_stabs("", 0, 0, 0, 0);
2205 /* add libc crt1/crti objects */
2206 #ifndef TCC_TARGET_PE
2207 if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
2208 !s->nostdlib) {
2209 if (output_type != TCC_OUTPUT_DLL)
2210 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
2211 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
2213 #endif
2215 #ifdef TCC_TARGET_PE
2216 snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path);
2217 tcc_add_library_path(s, buf);
2218 #endif
2220 return 0;
2223 #define WD_ALL 0x0001 /* warning is activated when using -Wall */
2224 #define FD_INVERT 0x0002 /* invert value before storing */
2226 typedef struct FlagDef {
2227 uint16_t offset;
2228 uint16_t flags;
2229 const char *name;
2230 } FlagDef;
2232 static const FlagDef warning_defs[] = {
2233 { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
2234 { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
2235 { offsetof(TCCState, warn_error), 0, "error" },
2236 { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
2237 "implicit-function-declaration" },
2240 static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
2241 const char *name, int value)
2243 int i;
2244 const FlagDef *p;
2245 const char *r;
2247 r = name;
2248 if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
2249 r += 3;
2250 value = !value;
2252 for(i = 0, p = flags; i < nb_flags; i++, p++) {
2253 if (!strcmp(r, p->name))
2254 goto found;
2256 return -1;
2257 found:
2258 if (p->flags & FD_INVERT)
2259 value = !value;
2260 *(int *)((uint8_t *)s + p->offset) = value;
2261 return 0;
2265 /* set/reset a warning */
2266 int tcc_set_warning(TCCState *s, const char *warning_name, int value)
2268 int i;
2269 const FlagDef *p;
2271 if (!strcmp(warning_name, "all")) {
2272 for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
2273 if (p->flags & WD_ALL)
2274 *(int *)((uint8_t *)s + p->offset) = 1;
2276 return 0;
2277 } else {
2278 return set_flag(s, warning_defs, countof(warning_defs),
2279 warning_name, value);
2283 static const FlagDef flag_defs[] = {
2284 { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
2285 { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
2286 { offsetof(TCCState, nocommon), FD_INVERT, "common" },
2287 { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
2290 /* set/reset a flag */
2291 int tcc_set_flag(TCCState *s, const char *flag_name, int value)
2293 return set_flag(s, flag_defs, countof(flag_defs),
2294 flag_name, value);
2297 /* set CONFIG_TCCDIR at runtime */
2298 void tcc_set_lib_path(TCCState *s, const char *path)
2300 tcc_lib_path = tcc_strdup(path);
2303 #if !defined(LIBTCC)
2305 static int64_t getclock_us(void)
2307 #ifdef _WIN32
2308 struct _timeb tb;
2309 _ftime(&tb);
2310 return (tb.time * 1000LL + tb.millitm) * 1000LL;
2311 #else
2312 struct timeval tv;
2313 gettimeofday(&tv, NULL);
2314 return tv.tv_sec * 1000000LL + tv.tv_usec;
2315 #endif
2318 void help(void)
2320 printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
2321 "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
2322 " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n"
2323 " [-static] [infile1 infile2...] [-run infile args...]\n"
2324 "\n"
2325 "General options:\n"
2326 " -v display current version, increase verbosity\n"
2327 " -c compile only - generate an object file\n"
2328 " -o outfile set output filename\n"
2329 " -Bdir set tcc internal library path\n"
2330 " -bench output compilation statistics\n"
2331 " -run run compiled source\n"
2332 " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
2333 " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
2334 " -w disable all warnings\n"
2335 "Preprocessor options:\n"
2336 " -E preprocess only\n"
2337 " -Idir add include path 'dir'\n"
2338 " -Dsym[=val] define 'sym' with value 'val'\n"
2339 " -Usym undefine 'sym'\n"
2340 "Linker options:\n"
2341 " -Ldir add library path 'dir'\n"
2342 " -llib link with dynamic or static library 'lib'\n"
2343 " -shared generate a shared library\n"
2344 " -soname set name for shared library to be used at runtime\n"
2345 " -static static linking\n"
2346 " -rdynamic export all global symbols to dynamic linker\n"
2347 " -r generate (relocatable) object file\n"
2348 "Debugger options:\n"
2349 " -g generate runtime debug info\n"
2350 #ifdef CONFIG_TCC_BCHECK
2351 " -b compile with built-in memory and bounds checker (implies -g)\n"
2352 #endif
2353 #ifdef CONFIG_TCC_BACKTRACE
2354 " -bt N show N callers in stack traces\n"
2355 #endif
2359 #define TCC_OPTION_HAS_ARG 0x0001
2360 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
2362 typedef struct TCCOption {
2363 const char *name;
2364 uint16_t index;
2365 uint16_t flags;
2366 } TCCOption;
2368 enum {
2369 TCC_OPTION_HELP,
2370 TCC_OPTION_I,
2371 TCC_OPTION_D,
2372 TCC_OPTION_U,
2373 TCC_OPTION_L,
2374 TCC_OPTION_B,
2375 TCC_OPTION_l,
2376 TCC_OPTION_bench,
2377 TCC_OPTION_bt,
2378 TCC_OPTION_b,
2379 TCC_OPTION_g,
2380 TCC_OPTION_c,
2381 TCC_OPTION_static,
2382 TCC_OPTION_shared,
2383 TCC_OPTION_soname,
2384 TCC_OPTION_o,
2385 TCC_OPTION_r,
2386 TCC_OPTION_Wl,
2387 TCC_OPTION_W,
2388 TCC_OPTION_O,
2389 TCC_OPTION_m,
2390 TCC_OPTION_f,
2391 TCC_OPTION_nostdinc,
2392 TCC_OPTION_nostdlib,
2393 TCC_OPTION_print_search_dirs,
2394 TCC_OPTION_rdynamic,
2395 TCC_OPTION_run,
2396 TCC_OPTION_v,
2397 TCC_OPTION_w,
2398 TCC_OPTION_pipe,
2399 TCC_OPTION_E,
2402 static const TCCOption tcc_options[] = {
2403 { "h", TCC_OPTION_HELP, 0 },
2404 { "?", TCC_OPTION_HELP, 0 },
2405 { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
2406 { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
2407 { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
2408 { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
2409 { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
2410 { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2411 { "bench", TCC_OPTION_bench, 0 },
2412 { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
2413 #ifdef CONFIG_TCC_BCHECK
2414 { "b", TCC_OPTION_b, 0 },
2415 #endif
2416 { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2417 { "c", TCC_OPTION_c, 0 },
2418 { "static", TCC_OPTION_static, 0 },
2419 { "shared", TCC_OPTION_shared, 0 },
2420 { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
2421 { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
2422 { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2423 { "rdynamic", TCC_OPTION_rdynamic, 0 },
2424 { "r", TCC_OPTION_r, 0 },
2425 { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2426 { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2427 { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2428 { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
2429 { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2430 { "nostdinc", TCC_OPTION_nostdinc, 0 },
2431 { "nostdlib", TCC_OPTION_nostdlib, 0 },
2432 { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
2433 { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2434 { "w", TCC_OPTION_w, 0 },
2435 { "pipe", TCC_OPTION_pipe, 0},
2436 { "E", TCC_OPTION_E, 0},
2437 { NULL },
2440 /* convert 'str' into an array of space separated strings */
2441 static int expand_args(char ***pargv, const char *str)
2443 const char *s1;
2444 char **argv, *arg;
2445 int argc, len;
2447 argc = 0;
2448 argv = NULL;
2449 for(;;) {
2450 while (is_space(*str))
2451 str++;
2452 if (*str == '\0')
2453 break;
2454 s1 = str;
2455 while (*str != '\0' && !is_space(*str))
2456 str++;
2457 len = str - s1;
2458 arg = tcc_malloc(len + 1);
2459 memcpy(arg, s1, len);
2460 arg[len] = '\0';
2461 dynarray_add((void ***)&argv, &argc, arg);
2463 *pargv = argv;
2464 return argc;
2467 static char **files;
2468 static int nb_files, nb_libraries;
2469 static int multiple_files;
2470 static int print_search_dirs;
2471 static int output_type;
2472 static int reloc_output;
2473 static const char *outfile;
2475 int parse_args(TCCState *s, int argc, char **argv)
2477 int optind;
2478 const TCCOption *popt;
2479 const char *optarg, *p1, *r1;
2480 char *r;
2482 optind = 0;
2483 while (optind < argc) {
2485 r = argv[optind++];
2486 if (r[0] != '-' || r[1] == '\0') {
2487 /* add a new file */
2488 dynarray_add((void ***)&files, &nb_files, r);
2489 if (!multiple_files) {
2490 optind--;
2491 /* argv[0] will be this file */
2492 break;
2494 } else {
2495 /* find option in table (match only the first chars */
2496 popt = tcc_options;
2497 for(;;) {
2498 p1 = popt->name;
2499 if (p1 == NULL)
2500 error("invalid option -- '%s'", r);
2501 r1 = r + 1;
2502 for(;;) {
2503 if (*p1 == '\0')
2504 goto option_found;
2505 if (*r1 != *p1)
2506 break;
2507 p1++;
2508 r1++;
2510 popt++;
2512 option_found:
2513 if (popt->flags & TCC_OPTION_HAS_ARG) {
2514 if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) {
2515 optarg = r1;
2516 } else {
2517 if (optind >= argc)
2518 error("argument to '%s' is missing", r);
2519 optarg = argv[optind++];
2521 } else {
2522 if (*r1 != '\0')
2523 return 0;
2524 optarg = NULL;
2527 switch(popt->index) {
2528 case TCC_OPTION_HELP:
2529 return 0;
2531 case TCC_OPTION_I:
2532 if (tcc_add_include_path(s, optarg) < 0)
2533 error("too many include paths");
2534 break;
2535 case TCC_OPTION_D:
2537 char *sym, *value;
2538 sym = (char *)optarg;
2539 value = strchr(sym, '=');
2540 if (value) {
2541 *value = '\0';
2542 value++;
2544 tcc_define_symbol(s, sym, value);
2546 break;
2547 case TCC_OPTION_U:
2548 tcc_undefine_symbol(s, optarg);
2549 break;
2550 case TCC_OPTION_L:
2551 tcc_add_library_path(s, optarg);
2552 break;
2553 case TCC_OPTION_B:
2554 /* set tcc utilities path (mainly for tcc development) */
2555 tcc_set_lib_path(s, optarg);
2556 break;
2557 case TCC_OPTION_l:
2558 dynarray_add((void ***)&files, &nb_files, r);
2559 nb_libraries++;
2560 break;
2561 case TCC_OPTION_bench:
2562 do_bench = 1;
2563 break;
2564 #ifdef CONFIG_TCC_BACKTRACE
2565 case TCC_OPTION_bt:
2566 num_callers = atoi(optarg);
2567 break;
2568 #endif
2569 #ifdef CONFIG_TCC_BCHECK
2570 case TCC_OPTION_b:
2571 do_bounds_check = 1;
2572 do_debug = 1;
2573 break;
2574 #endif
2575 case TCC_OPTION_g:
2576 do_debug = 1;
2577 break;
2578 case TCC_OPTION_c:
2579 multiple_files = 1;
2580 output_type = TCC_OUTPUT_OBJ;
2581 break;
2582 case TCC_OPTION_static:
2583 s->static_link = 1;
2584 break;
2585 case TCC_OPTION_shared:
2586 output_type = TCC_OUTPUT_DLL;
2587 break;
2588 case TCC_OPTION_soname:
2589 s->soname = optarg;
2590 break;
2591 case TCC_OPTION_o:
2592 multiple_files = 1;
2593 outfile = optarg;
2594 break;
2595 case TCC_OPTION_r:
2596 /* generate a .o merging several output files */
2597 reloc_output = 1;
2598 output_type = TCC_OUTPUT_OBJ;
2599 break;
2600 case TCC_OPTION_nostdinc:
2601 s->nostdinc = 1;
2602 break;
2603 case TCC_OPTION_nostdlib:
2604 s->nostdlib = 1;
2605 break;
2606 case TCC_OPTION_print_search_dirs:
2607 print_search_dirs = 1;
2608 break;
2609 case TCC_OPTION_run:
2611 int argc1;
2612 char **argv1;
2613 argc1 = expand_args(&argv1, optarg);
2614 if (argc1 > 0) {
2615 parse_args(s, argc1, argv1);
2617 multiple_files = 0;
2618 output_type = TCC_OUTPUT_MEMORY;
2620 break;
2621 case TCC_OPTION_v:
2622 do {
2623 if (0 == verbose++)
2624 printf("tcc version %s\n", TCC_VERSION);
2625 } while (*optarg++ == 'v');
2626 break;
2627 case TCC_OPTION_f:
2628 if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
2629 goto unsupported_option;
2630 break;
2631 case TCC_OPTION_W:
2632 if (tcc_set_warning(s, optarg, 1) < 0 &&
2633 s->warn_unsupported)
2634 goto unsupported_option;
2635 break;
2636 case TCC_OPTION_w:
2637 s->warn_none = 1;
2638 break;
2639 case TCC_OPTION_rdynamic:
2640 s->rdynamic = 1;
2641 break;
2642 case TCC_OPTION_Wl:
2644 const char *p;
2645 if (strstart(optarg, "-Ttext,", &p)) {
2646 s->text_addr = strtoul(p, NULL, 16);
2647 s->has_text_addr = 1;
2648 } else if (strstart(optarg, "--oformat,", &p)) {
2649 if (strstart(p, "elf32-", NULL)) {
2650 s->output_format = TCC_OUTPUT_FORMAT_ELF;
2651 } else if (!strcmp(p, "binary")) {
2652 s->output_format = TCC_OUTPUT_FORMAT_BINARY;
2653 } else
2654 #ifdef TCC_TARGET_COFF
2655 if (!strcmp(p, "coff")) {
2656 s->output_format = TCC_OUTPUT_FORMAT_COFF;
2657 } else
2658 #endif
2660 error("target %s not found", p);
2662 } else {
2663 error("unsupported linker option '%s'", optarg);
2666 break;
2667 case TCC_OPTION_E:
2668 output_type = TCC_OUTPUT_PREPROCESS;
2669 break;
2670 default:
2671 if (s->warn_unsupported) {
2672 unsupported_option:
2673 warning("unsupported option '%s'", r);
2675 break;
2679 return optind + 1;
2682 int main(int argc, char **argv)
2684 int i;
2685 TCCState *s;
2686 int nb_objfiles, ret, optind;
2687 char objfilename[1024];
2688 int64_t start_time = 0;
2690 s = tcc_new();
2691 #ifdef _WIN32
2692 tcc_set_lib_path_w32(s);
2693 #endif
2694 output_type = TCC_OUTPUT_EXE;
2695 outfile = NULL;
2696 multiple_files = 1;
2697 files = NULL;
2698 nb_files = 0;
2699 nb_libraries = 0;
2700 reloc_output = 0;
2701 print_search_dirs = 0;
2702 ret = 0;
2704 optind = parse_args(s, argc - 1, argv + 1);
2705 if (print_search_dirs) {
2706 /* enough for Linux kernel */
2707 printf("install: %s/\n", tcc_lib_path);
2708 return 0;
2710 if (optind == 0 || nb_files == 0) {
2711 if (optind && verbose)
2712 return 0;
2713 help();
2714 return 1;
2717 nb_objfiles = nb_files - nb_libraries;
2719 /* if outfile provided without other options, we output an
2720 executable */
2721 if (outfile && output_type == TCC_OUTPUT_MEMORY)
2722 output_type = TCC_OUTPUT_EXE;
2724 /* check -c consistency : only single file handled. XXX: checks file type */
2725 if (output_type == TCC_OUTPUT_OBJ && !reloc_output) {
2726 /* accepts only a single input file */
2727 if (nb_objfiles != 1)
2728 error("cannot specify multiple files with -c");
2729 if (nb_libraries != 0)
2730 error("cannot specify libraries with -c");
2734 if (output_type == TCC_OUTPUT_PREPROCESS) {
2735 if (!outfile) {
2736 s->outfile = stdout;
2737 } else {
2738 s->outfile = fopen(outfile, "w");
2739 if (!s->outfile)
2740 error("could not open '%s", outfile);
2742 } else if (output_type != TCC_OUTPUT_MEMORY) {
2743 if (!outfile) {
2744 /* compute default outfile name */
2745 char *ext;
2746 const char *name =
2747 strcmp(files[0], "-") == 0 ? "a" : tcc_basename(files[0]);
2748 pstrcpy(objfilename, sizeof(objfilename), name);
2749 ext = tcc_fileextension(objfilename);
2750 #ifdef TCC_TARGET_PE
2751 if (output_type == TCC_OUTPUT_DLL)
2752 strcpy(ext, ".dll");
2753 else
2754 if (output_type == TCC_OUTPUT_EXE)
2755 strcpy(ext, ".exe");
2756 else
2757 #endif
2758 if (output_type == TCC_OUTPUT_OBJ && !reloc_output && *ext)
2759 strcpy(ext, ".o");
2760 else
2761 pstrcpy(objfilename, sizeof(objfilename), "a.out");
2762 outfile = objfilename;
2766 if (do_bench) {
2767 start_time = getclock_us();
2770 tcc_set_output_type(s, output_type);
2772 /* compile or add each files or library */
2773 for(i = 0; i < nb_files && ret == 0; i++) {
2774 const char *filename;
2776 filename = files[i];
2777 if (output_type == TCC_OUTPUT_PREPROCESS) {
2778 if (tcc_add_file_internal(s, filename,
2779 AFF_PRINT_ERROR | AFF_PREPROCESS) < 0)
2780 ret = 1;
2781 } else if (filename[0] == '-' && filename[1]) {
2782 if (tcc_add_library(s, filename + 2) < 0)
2783 error("cannot find %s", filename);
2784 } else {
2785 if (1 == verbose)
2786 printf("-> %s\n", filename);
2787 if (tcc_add_file(s, filename) < 0)
2788 ret = 1;
2792 /* free all files */
2793 tcc_free(files);
2795 if (ret)
2796 goto the_end;
2798 if (do_bench) {
2799 double total_time;
2800 total_time = (double)(getclock_us() - start_time) / 1000000.0;
2801 if (total_time < 0.001)
2802 total_time = 0.001;
2803 if (total_bytes < 1)
2804 total_bytes = 1;
2805 printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n",
2806 tok_ident - TOK_IDENT, total_lines, total_bytes,
2807 total_time, (int)(total_lines / total_time),
2808 total_bytes / total_time / 1000000.0);
2811 if (s->output_type == TCC_OUTPUT_PREPROCESS) {
2812 if (outfile)
2813 fclose(s->outfile);
2814 } else if (s->output_type == TCC_OUTPUT_MEMORY) {
2815 ret = tcc_run(s, argc - optind, argv + optind);
2816 } else
2817 ret = tcc_output_file(s, outfile) ? 1 : 0;
2818 the_end:
2819 /* XXX: cannot do it with bound checking because of the malloc hooks */
2820 if (!do_bounds_check)
2821 tcc_delete(s);
2823 #ifdef MEM_DEBUG
2824 if (do_bench) {
2825 printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
2827 #endif
2828 return ret;
2831 #endif