move global variables to libtcc.c
[tinycc/k1w1.git] / libtcc.c
blob383e5a50f4022aa7160e9dcf0f0e6f3784f59d11
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 /* parser */
24 static struct BufferedFile *file;
25 static int ch, tok;
26 static CValue tokc;
27 static CString tokcstr; /* current parsed string, if any */
28 /* additional informations about token */
29 static int tok_flags;
30 #define TOK_FLAG_BOL 0x0001 /* beginning of line before */
31 #define TOK_FLAG_BOF 0x0002 /* beginning of file before */
32 #define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */
33 #define TOK_FLAG_EOF 0x0008 /* end of file */
35 static int *macro_ptr, *macro_ptr_allocated;
36 static int *unget_saved_macro_ptr;
37 static int unget_saved_buffer[TOK_MAX_SIZE + 1];
38 static int unget_buffer_enabled;
39 static int parse_flags;
40 #define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */
41 #define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */
42 #define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a
43 token. line feed is also
44 returned at eof */
45 #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */
46 #define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */
48 static Section *text_section, *data_section, *bss_section; /* predefined sections */
49 static Section *cur_text_section; /* current section where function code is
50 generated */
51 #ifdef CONFIG_TCC_ASM
52 static Section *last_text_section; /* to handle .previous asm directive */
53 #endif
54 /* bound check related sections */
55 static Section *bounds_section; /* contains global data bound description */
56 static Section *lbounds_section; /* contains local data bound description */
57 /* symbol sections */
58 static Section *symtab_section, *strtab_section;
60 /* debug sections */
61 static Section *stab_section, *stabstr_section;
63 /* loc : local variable index
64 ind : output code index
65 rsym: return symbol
66 anon_sym: anonymous symbol index
68 static int rsym, anon_sym, ind, loc;
69 /* expression generation modifiers */
70 static int const_wanted; /* true if constant wanted */
71 static int nocode_wanted; /* true if no code generation wanted for an expression */
72 static int global_expr; /* true if compound literals must be allocated
73 globally (used during initializers parsing */
74 static CType func_vt; /* current function return type (used by return
75 instruction) */
76 static int func_vc;
77 static int last_line_num, last_ind, func_ind; /* debug last line number and pc */
78 static int tok_ident;
79 static TokenSym **table_ident;
80 static TokenSym *hash_ident[TOK_HASH_SIZE];
81 static char token_buf[STRING_MAX_SIZE + 1];
82 static char *funcname;
83 static Sym *global_stack, *local_stack;
84 static Sym *define_stack;
85 static Sym *global_label_stack, *local_label_stack;
86 /* symbol allocator */
87 #define SYM_POOL_NB (8192 / sizeof(Sym))
88 static Sym *sym_free_first;
89 static void **sym_pools;
90 static int nb_sym_pools;
92 static SValue vstack[VSTACK_SIZE], *vtop;
93 /* some predefined types */
94 static CType char_pointer_type, func_old_type, int_type;
95 /* true if isid(c) || isnum(c) */
96 static unsigned char isidnum_table[256-CH_EOF];
98 /* display some information during compilation */
99 static int verbose = 0;
101 /* compile with debug symbol (and use them if error during execution) */
102 static int do_debug = 0;
104 /* compile with built-in memory and bounds checker */
105 static int do_bounds_check = 0;
107 /* display benchmark infos */
108 #if !defined(LIBTCC)
109 static int do_bench = 0;
110 #endif
111 static int total_lines;
112 static int total_bytes;
114 /* use GNU C extensions */
115 static int gnu_ext = 1;
117 /* use Tiny C extensions */
118 static int tcc_ext = 1;
120 /* max number of callers shown if error */
121 #ifdef CONFIG_TCC_BACKTRACE
122 static int num_callers = 6;
123 static const char **rt_bound_error_msg;
124 #endif
126 /* XXX: get rid of this ASAP */
127 static struct TCCState *tcc_state;
129 /* give the path of the tcc libraries */
130 static const char *tcc_lib_path = CONFIG_TCCDIR;
134 #ifdef TCC_TARGET_I386
135 #include "i386-gen.c"
136 #endif
138 #ifdef TCC_TARGET_ARM
139 #include "arm-gen.c"
140 #endif
142 #ifdef TCC_TARGET_C67
143 #include "c67-gen.c"
144 #endif
146 #ifdef TCC_TARGET_X86_64
147 #include "x86_64-gen.c"
148 #endif
150 #ifdef CONFIG_TCC_STATIC
152 #define RTLD_LAZY 0x001
153 #define RTLD_NOW 0x002
154 #define RTLD_GLOBAL 0x100
155 #define RTLD_DEFAULT NULL
157 /* dummy function for profiling */
158 void *dlopen(const char *filename, int flag)
160 return NULL;
163 void dlclose(void *p)
167 const char *dlerror(void)
169 return "error";
172 typedef struct TCCSyms {
173 char *str;
174 void *ptr;
175 } TCCSyms;
177 #define TCCSYM(a) { #a, &a, },
179 /* add the symbol you want here if no dynamic linking is done */
180 static TCCSyms tcc_syms[] = {
181 #if !defined(CONFIG_TCCBOOT)
182 TCCSYM(printf)
183 TCCSYM(fprintf)
184 TCCSYM(fopen)
185 TCCSYM(fclose)
186 #endif
187 { NULL, NULL },
190 void *resolve_sym(TCCState *s1, const char *symbol, int type)
192 TCCSyms *p;
193 p = tcc_syms;
194 while (p->str != NULL) {
195 if (!strcmp(p->str, symbol))
196 return p->ptr;
197 p++;
199 return NULL;
202 #elif !defined(_WIN32)
204 #include <dlfcn.h>
206 void *resolve_sym(TCCState *s1, const char *sym, int type)
208 return dlsym(RTLD_DEFAULT, sym);
211 #endif
213 /********************************************************/
215 /* we use our own 'finite' function to avoid potential problems with
216 non standard math libs */
217 /* XXX: endianness dependent */
218 int ieee_finite(double d)
220 int *p = (int *)&d;
221 return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
224 /* copy a string and truncate it. */
225 static char *pstrcpy(char *buf, int buf_size, const char *s)
227 char *q, *q_end;
228 int c;
230 if (buf_size > 0) {
231 q = buf;
232 q_end = buf + buf_size - 1;
233 while (q < q_end) {
234 c = *s++;
235 if (c == '\0')
236 break;
237 *q++ = c;
239 *q = '\0';
241 return buf;
244 /* strcat and truncate. */
245 static char *pstrcat(char *buf, int buf_size, const char *s)
247 int len;
248 len = strlen(buf);
249 if (len < buf_size)
250 pstrcpy(buf + len, buf_size - len, s);
251 return buf;
254 #ifndef LIBTCC
255 static int strstart(const char *str, const char *val, const char **ptr)
257 const char *p, *q;
258 p = str;
259 q = val;
260 while (*q != '\0') {
261 if (*p != *q)
262 return 0;
263 p++;
264 q++;
266 if (ptr)
267 *ptr = p;
268 return 1;
270 #endif
272 #ifdef _WIN32
273 #define IS_PATHSEP(c) (c == '/' || c == '\\')
274 #define IS_ABSPATH(p) (IS_PATHSEP(p[0]) || (p[0] && p[1] == ':' && IS_PATHSEP(p[2])))
275 #define PATHCMP stricmp
276 #else
277 #define IS_PATHSEP(c) (c == '/')
278 #define IS_ABSPATH(p) IS_PATHSEP(p[0])
279 #define PATHCMP strcmp
280 #endif
282 /* extract the basename of a file */
283 static char *tcc_basename(const char *name)
285 char *p = strchr(name, 0);
286 while (p > name && !IS_PATHSEP(p[-1]))
287 --p;
288 return p;
291 static char *tcc_fileextension (const char *name)
293 char *b = tcc_basename(name);
294 char *e = strrchr(b, '.');
295 return e ? e : strchr(b, 0);
298 #ifdef _WIN32
299 char *normalize_slashes(char *path)
301 char *p;
302 for (p = path; *p; ++p)
303 if (*p == '\\')
304 *p = '/';
305 return path;
308 void tcc_set_lib_path_w32(TCCState *s)
310 /* on win32, we suppose the lib and includes are at the location
311 of 'tcc.exe' */
312 char path[1024], *p;
313 GetModuleFileNameA(NULL, path, sizeof path);
314 p = tcc_basename(normalize_slashes(strlwr(path)));
315 if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
316 p -= 5;
317 else if (p > path)
318 p--;
319 *p = 0;
320 tcc_set_lib_path(s, path);
322 #endif
324 void set_pages_executable(void *ptr, unsigned long length)
326 #ifdef _WIN32
327 unsigned long old_protect;
328 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
329 #else
330 unsigned long start, end;
331 start = (unsigned long)ptr & ~(PAGESIZE - 1);
332 end = (unsigned long)ptr + length;
333 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
334 mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
335 #endif
338 /* memory management */
339 #ifdef MEM_DEBUG
340 int mem_cur_size;
341 int mem_max_size;
342 unsigned malloc_usable_size(void*);
343 #endif
345 static inline void tcc_free(void *ptr)
347 #ifdef MEM_DEBUG
348 mem_cur_size -= malloc_usable_size(ptr);
349 #endif
350 free(ptr);
353 static void *tcc_malloc(unsigned long size)
355 void *ptr;
356 ptr = malloc(size);
357 if (!ptr && size)
358 error("memory full");
359 #ifdef MEM_DEBUG
360 mem_cur_size += malloc_usable_size(ptr);
361 if (mem_cur_size > mem_max_size)
362 mem_max_size = mem_cur_size;
363 #endif
364 return ptr;
367 static void *tcc_mallocz(unsigned long size)
369 void *ptr;
370 ptr = tcc_malloc(size);
371 memset(ptr, 0, size);
372 return ptr;
375 static inline void *tcc_realloc(void *ptr, unsigned long size)
377 void *ptr1;
378 #ifdef MEM_DEBUG
379 mem_cur_size -= malloc_usable_size(ptr);
380 #endif
381 ptr1 = realloc(ptr, size);
382 #ifdef MEM_DEBUG
383 /* NOTE: count not correct if alloc error, but not critical */
384 mem_cur_size += malloc_usable_size(ptr1);
385 if (mem_cur_size > mem_max_size)
386 mem_max_size = mem_cur_size;
387 #endif
388 return ptr1;
391 static char *tcc_strdup(const char *str)
393 char *ptr;
394 ptr = tcc_malloc(strlen(str) + 1);
395 strcpy(ptr, str);
396 return ptr;
399 #define free(p) use_tcc_free(p)
400 #define malloc(s) use_tcc_malloc(s)
401 #define realloc(p, s) use_tcc_realloc(p, s)
403 static void dynarray_add(void ***ptab, int *nb_ptr, void *data)
405 int nb, nb_alloc;
406 void **pp;
408 nb = *nb_ptr;
409 pp = *ptab;
410 /* every power of two we double array size */
411 if ((nb & (nb - 1)) == 0) {
412 if (!nb)
413 nb_alloc = 1;
414 else
415 nb_alloc = nb * 2;
416 pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
417 if (!pp)
418 error("memory full");
419 *ptab = pp;
421 pp[nb++] = data;
422 *nb_ptr = nb;
425 static void dynarray_reset(void *pp, int *n)
427 void **p;
428 for (p = *(void***)pp; *n; ++p, --*n)
429 if (*p)
430 tcc_free(*p);
431 tcc_free(*(void**)pp);
432 *(void**)pp = NULL;
435 /* symbol allocator */
436 static Sym *__sym_malloc(void)
438 Sym *sym_pool, *sym, *last_sym;
439 int i;
441 sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym));
442 dynarray_add(&sym_pools, &nb_sym_pools, sym_pool);
444 last_sym = sym_free_first;
445 sym = sym_pool;
446 for(i = 0; i < SYM_POOL_NB; i++) {
447 sym->next = last_sym;
448 last_sym = sym;
449 sym++;
451 sym_free_first = last_sym;
452 return last_sym;
455 static inline Sym *sym_malloc(void)
457 Sym *sym;
458 sym = sym_free_first;
459 if (!sym)
460 sym = __sym_malloc();
461 sym_free_first = sym->next;
462 return sym;
465 static inline void sym_free(Sym *sym)
467 sym->next = sym_free_first;
468 sym_free_first = sym;
471 Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
473 Section *sec;
475 sec = tcc_mallocz(sizeof(Section) + strlen(name));
476 strcpy(sec->name, name);
477 sec->sh_type = sh_type;
478 sec->sh_flags = sh_flags;
479 switch(sh_type) {
480 case SHT_HASH:
481 case SHT_REL:
482 case SHT_RELA:
483 case SHT_DYNSYM:
484 case SHT_SYMTAB:
485 case SHT_DYNAMIC:
486 sec->sh_addralign = 4;
487 break;
488 case SHT_STRTAB:
489 sec->sh_addralign = 1;
490 break;
491 default:
492 sec->sh_addralign = 32; /* default conservative alignment */
493 break;
496 if (sh_flags & SHF_PRIVATE) {
497 dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
498 } else {
499 sec->sh_num = s1->nb_sections;
500 dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
503 return sec;
506 static void free_section(Section *s)
508 tcc_free(s->data);
511 /* realloc section and set its content to zero */
512 static void section_realloc(Section *sec, unsigned long new_size)
514 unsigned long size;
515 unsigned char *data;
517 size = sec->data_allocated;
518 if (size == 0)
519 size = 1;
520 while (size < new_size)
521 size = size * 2;
522 data = tcc_realloc(sec->data, size);
523 if (!data)
524 error("memory full");
525 memset(data + sec->data_allocated, 0, size - sec->data_allocated);
526 sec->data = data;
527 sec->data_allocated = size;
530 /* reserve at least 'size' bytes in section 'sec' from
531 sec->data_offset. */
532 static void *section_ptr_add(Section *sec, unsigned long size)
534 unsigned long offset, offset1;
536 offset = sec->data_offset;
537 offset1 = offset + size;
538 if (offset1 > sec->data_allocated)
539 section_realloc(sec, offset1);
540 sec->data_offset = offset1;
541 return sec->data + offset;
544 /* return a reference to a section, and create it if it does not
545 exists */
546 Section *find_section(TCCState *s1, const char *name)
548 Section *sec;
549 int i;
550 for(i = 1; i < s1->nb_sections; i++) {
551 sec = s1->sections[i];
552 if (!strcmp(name, sec->name))
553 return sec;
555 /* sections are created as PROGBITS */
556 return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
559 #define SECTION_ABS ((void *)1)
561 /* update sym->c so that it points to an external symbol in section
562 'section' with value 'value' */
563 static void put_extern_sym2(Sym *sym, Section *section,
564 unsigned long value, unsigned long size,
565 int can_add_underscore)
567 int sym_type, sym_bind, sh_num, info, other, attr;
568 ElfW(Sym) *esym;
569 const char *name;
570 char buf1[256];
572 if (section == NULL)
573 sh_num = SHN_UNDEF;
574 else if (section == SECTION_ABS)
575 sh_num = SHN_ABS;
576 else
577 sh_num = section->sh_num;
579 other = attr = 0;
581 if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
582 sym_type = STT_FUNC;
583 #ifdef TCC_TARGET_PE
584 if (sym->type.ref)
585 attr = sym->type.ref->r;
586 if (FUNC_EXPORT(attr))
587 other |= 1;
588 if (FUNC_CALL(attr) == FUNC_STDCALL)
589 other |= 2;
590 #endif
591 } else {
592 sym_type = STT_OBJECT;
595 if (sym->type.t & VT_STATIC)
596 sym_bind = STB_LOCAL;
597 else
598 sym_bind = STB_GLOBAL;
600 if (!sym->c) {
601 name = get_tok_str(sym->v, NULL);
602 #ifdef CONFIG_TCC_BCHECK
603 if (do_bounds_check) {
604 char buf[32];
606 /* XXX: avoid doing that for statics ? */
607 /* if bound checking is activated, we change some function
608 names by adding the "__bound" prefix */
609 switch(sym->v) {
610 #if 0
611 /* XXX: we rely only on malloc hooks */
612 case TOK_malloc:
613 case TOK_free:
614 case TOK_realloc:
615 case TOK_memalign:
616 case TOK_calloc:
617 #endif
618 case TOK_memcpy:
619 case TOK_memmove:
620 case TOK_memset:
621 case TOK_strlen:
622 case TOK_strcpy:
623 case TOK__alloca:
624 strcpy(buf, "__bound_");
625 strcat(buf, name);
626 name = buf;
627 break;
630 #endif
632 #ifdef TCC_TARGET_PE
633 if ((other & 2) && can_add_underscore) {
634 sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr));
635 name = buf1;
636 } else
637 #endif
638 if (tcc_state->leading_underscore && can_add_underscore) {
639 buf1[0] = '_';
640 pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
641 name = buf1;
643 info = ELFW(ST_INFO)(sym_bind, sym_type);
644 sym->c = add_elf_sym(symtab_section, value, size, info, other, sh_num, name);
645 } else {
646 esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
647 esym->st_value = value;
648 esym->st_size = size;
649 esym->st_shndx = sh_num;
650 esym->st_other |= other;
654 static void put_extern_sym(Sym *sym, Section *section,
655 unsigned long value, unsigned long size)
657 put_extern_sym2(sym, section, value, size, 1);
660 /* add a new relocation entry to symbol 'sym' in section 's' */
661 static void greloc(Section *s, Sym *sym, unsigned long offset, int type)
663 if (!sym->c)
664 put_extern_sym(sym, NULL, 0, 0);
665 /* now we can add ELF relocation info */
666 put_elf_reloc(symtab_section, s, offset, type, sym->c);
669 static inline int isid(int c)
671 return (c >= 'a' && c <= 'z') ||
672 (c >= 'A' && c <= 'Z') ||
673 c == '_';
676 static inline int isnum(int c)
678 return c >= '0' && c <= '9';
681 static inline int isoct(int c)
683 return c >= '0' && c <= '7';
686 static inline int toup(int c)
688 if (c >= 'a' && c <= 'z')
689 return c - 'a' + 'A';
690 else
691 return c;
694 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
696 int len;
697 len = strlen(buf);
698 vsnprintf(buf + len, buf_size - len, fmt, ap);
701 static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
703 va_list ap;
704 va_start(ap, fmt);
705 strcat_vprintf(buf, buf_size, fmt, ap);
706 va_end(ap);
709 void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
711 char buf[2048];
712 BufferedFile **f;
714 buf[0] = '\0';
715 if (file) {
716 for(f = s1->include_stack; f < s1->include_stack_ptr; f++)
717 strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
718 (*f)->filename, (*f)->line_num);
719 if (file->line_num > 0) {
720 strcat_printf(buf, sizeof(buf),
721 "%s:%d: ", file->filename, file->line_num);
722 } else {
723 strcat_printf(buf, sizeof(buf),
724 "%s: ", file->filename);
726 } else {
727 strcat_printf(buf, sizeof(buf),
728 "tcc: ");
730 if (is_warning)
731 strcat_printf(buf, sizeof(buf), "warning: ");
732 strcat_vprintf(buf, sizeof(buf), fmt, ap);
734 if (!s1->error_func) {
735 /* default case: stderr */
736 fprintf(stderr, "%s\n", buf);
737 } else {
738 s1->error_func(s1->error_opaque, buf);
740 if (!is_warning || s1->warn_error)
741 s1->nb_errors++;
744 #ifdef LIBTCC
745 void tcc_set_error_func(TCCState *s, void *error_opaque,
746 void (*error_func)(void *opaque, const char *msg))
748 s->error_opaque = error_opaque;
749 s->error_func = error_func;
751 #endif
753 /* error without aborting current compilation */
754 void error_noabort(const char *fmt, ...)
756 TCCState *s1 = tcc_state;
757 va_list ap;
759 va_start(ap, fmt);
760 error1(s1, 0, fmt, ap);
761 va_end(ap);
764 void error(const char *fmt, ...)
766 TCCState *s1 = tcc_state;
767 va_list ap;
769 va_start(ap, fmt);
770 error1(s1, 0, fmt, ap);
771 va_end(ap);
772 /* better than nothing: in some cases, we accept to handle errors */
773 if (s1->error_set_jmp_enabled) {
774 longjmp(s1->error_jmp_buf, 1);
775 } else {
776 /* XXX: eliminate this someday */
777 exit(1);
781 void expect(const char *msg)
783 error("%s expected", msg);
786 void warning(const char *fmt, ...)
788 TCCState *s1 = tcc_state;
789 va_list ap;
791 if (s1->warn_none)
792 return;
794 va_start(ap, fmt);
795 error1(s1, 1, fmt, ap);
796 va_end(ap);
799 void skip(int c)
801 if (tok != c)
802 error("'%c' expected", c);
803 next();
806 static void test_lvalue(void)
808 if (!(vtop->r & VT_LVAL))
809 expect("lvalue");
812 /* allocate a new token */
813 static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
815 TokenSym *ts, **ptable;
816 int i;
818 if (tok_ident >= SYM_FIRST_ANOM)
819 error("memory full");
821 /* expand token table if needed */
822 i = tok_ident - TOK_IDENT;
823 if ((i % TOK_ALLOC_INCR) == 0) {
824 ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
825 if (!ptable)
826 error("memory full");
827 table_ident = ptable;
830 ts = tcc_malloc(sizeof(TokenSym) + len);
831 table_ident[i] = ts;
832 ts->tok = tok_ident++;
833 ts->sym_define = NULL;
834 ts->sym_label = NULL;
835 ts->sym_struct = NULL;
836 ts->sym_identifier = NULL;
837 ts->len = len;
838 ts->hash_next = NULL;
839 memcpy(ts->str, str, len);
840 ts->str[len] = '\0';
841 *pts = ts;
842 return ts;
845 #define TOK_HASH_INIT 1
846 #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c))
848 /* find a token and add it if not found */
849 static TokenSym *tok_alloc(const char *str, int len)
851 TokenSym *ts, **pts;
852 int i;
853 unsigned int h;
855 h = TOK_HASH_INIT;
856 for(i=0;i<len;i++)
857 h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]);
858 h &= (TOK_HASH_SIZE - 1);
860 pts = &hash_ident[h];
861 for(;;) {
862 ts = *pts;
863 if (!ts)
864 break;
865 if (ts->len == len && !memcmp(ts->str, str, len))
866 return ts;
867 pts = &(ts->hash_next);
869 return tok_alloc_new(pts, str, len);
872 /* CString handling */
874 static void cstr_realloc(CString *cstr, int new_size)
876 int size;
877 void *data;
879 size = cstr->size_allocated;
880 if (size == 0)
881 size = 8; /* no need to allocate a too small first string */
882 while (size < new_size)
883 size = size * 2;
884 data = tcc_realloc(cstr->data_allocated, size);
885 if (!data)
886 error("memory full");
887 cstr->data_allocated = data;
888 cstr->size_allocated = size;
889 cstr->data = data;
892 /* add a byte */
893 static inline void cstr_ccat(CString *cstr, int ch)
895 int size;
896 size = cstr->size + 1;
897 if (size > cstr->size_allocated)
898 cstr_realloc(cstr, size);
899 ((unsigned char *)cstr->data)[size - 1] = ch;
900 cstr->size = size;
903 static void cstr_cat(CString *cstr, const char *str)
905 int c;
906 for(;;) {
907 c = *str;
908 if (c == '\0')
909 break;
910 cstr_ccat(cstr, c);
911 str++;
915 /* add a wide char */
916 static void cstr_wccat(CString *cstr, int ch)
918 int size;
919 size = cstr->size + sizeof(nwchar_t);
920 if (size > cstr->size_allocated)
921 cstr_realloc(cstr, size);
922 *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
923 cstr->size = size;
926 static void cstr_new(CString *cstr)
928 memset(cstr, 0, sizeof(CString));
931 /* free string and reset it to NULL */
932 static void cstr_free(CString *cstr)
934 tcc_free(cstr->data_allocated);
935 cstr_new(cstr);
938 #define cstr_reset(cstr) cstr_free(cstr)
940 /* XXX: unicode ? */
941 static void add_char(CString *cstr, int c)
943 if (c == '\'' || c == '\"' || c == '\\') {
944 /* XXX: could be more precise if char or string */
945 cstr_ccat(cstr, '\\');
947 if (c >= 32 && c <= 126) {
948 cstr_ccat(cstr, c);
949 } else {
950 cstr_ccat(cstr, '\\');
951 if (c == '\n') {
952 cstr_ccat(cstr, 'n');
953 } else {
954 cstr_ccat(cstr, '0' + ((c >> 6) & 7));
955 cstr_ccat(cstr, '0' + ((c >> 3) & 7));
956 cstr_ccat(cstr, '0' + (c & 7));
961 /* XXX: buffer overflow */
962 /* XXX: float tokens */
963 char *get_tok_str(int v, CValue *cv)
965 static char buf[STRING_MAX_SIZE + 1];
966 static CString cstr_buf;
967 CString *cstr;
968 unsigned char *q;
969 char *p;
970 int i, len;
972 /* NOTE: to go faster, we give a fixed buffer for small strings */
973 cstr_reset(&cstr_buf);
974 cstr_buf.data = buf;
975 cstr_buf.size_allocated = sizeof(buf);
976 p = buf;
978 switch(v) {
979 case TOK_CINT:
980 case TOK_CUINT:
981 /* XXX: not quite exact, but only useful for testing */
982 sprintf(p, "%u", cv->ui);
983 break;
984 case TOK_CLLONG:
985 case TOK_CULLONG:
986 /* XXX: not quite exact, but only useful for testing */
987 sprintf(p, "%Lu", cv->ull);
988 break;
989 case TOK_LCHAR:
990 cstr_ccat(&cstr_buf, 'L');
991 case TOK_CCHAR:
992 cstr_ccat(&cstr_buf, '\'');
993 add_char(&cstr_buf, cv->i);
994 cstr_ccat(&cstr_buf, '\'');
995 cstr_ccat(&cstr_buf, '\0');
996 break;
997 case TOK_PPNUM:
998 cstr = cv->cstr;
999 len = cstr->size - 1;
1000 for(i=0;i<len;i++)
1001 add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
1002 cstr_ccat(&cstr_buf, '\0');
1003 break;
1004 case TOK_LSTR:
1005 cstr_ccat(&cstr_buf, 'L');
1006 case TOK_STR:
1007 cstr = cv->cstr;
1008 cstr_ccat(&cstr_buf, '\"');
1009 if (v == TOK_STR) {
1010 len = cstr->size - 1;
1011 for(i=0;i<len;i++)
1012 add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
1013 } else {
1014 len = (cstr->size / sizeof(nwchar_t)) - 1;
1015 for(i=0;i<len;i++)
1016 add_char(&cstr_buf, ((nwchar_t *)cstr->data)[i]);
1018 cstr_ccat(&cstr_buf, '\"');
1019 cstr_ccat(&cstr_buf, '\0');
1020 break;
1021 case TOK_LT:
1022 v = '<';
1023 goto addv;
1024 case TOK_GT:
1025 v = '>';
1026 goto addv;
1027 case TOK_DOTS:
1028 return strcpy(p, "...");
1029 case TOK_A_SHL:
1030 return strcpy(p, "<<=");
1031 case TOK_A_SAR:
1032 return strcpy(p, ">>=");
1033 default:
1034 if (v < TOK_IDENT) {
1035 /* search in two bytes table */
1036 q = tok_two_chars;
1037 while (*q) {
1038 if (q[2] == v) {
1039 *p++ = q[0];
1040 *p++ = q[1];
1041 *p = '\0';
1042 return buf;
1044 q += 3;
1046 addv:
1047 *p++ = v;
1048 *p = '\0';
1049 } else if (v < tok_ident) {
1050 return table_ident[v - TOK_IDENT]->str;
1051 } else if (v >= SYM_FIRST_ANOM) {
1052 /* special name for anonymous symbol */
1053 sprintf(p, "L.%u", v - SYM_FIRST_ANOM);
1054 } else {
1055 /* should never happen */
1056 return NULL;
1058 break;
1060 return cstr_buf.data;
1063 /* push, without hashing */
1064 static Sym *sym_push2(Sym **ps, int v, int t, long c)
1066 Sym *s;
1067 s = sym_malloc();
1068 s->v = v;
1069 s->type.t = t;
1070 s->c = c;
1071 s->next = NULL;
1072 /* add in stack */
1073 s->prev = *ps;
1074 *ps = s;
1075 return s;
1078 /* find a symbol and return its associated structure. 's' is the top
1079 of the symbol stack */
1080 static Sym *sym_find2(Sym *s, int v)
1082 while (s) {
1083 if (s->v == v)
1084 return s;
1085 s = s->prev;
1087 return NULL;
1090 /* structure lookup */
1091 static inline Sym *struct_find(int v)
1093 v -= TOK_IDENT;
1094 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1095 return NULL;
1096 return table_ident[v]->sym_struct;
1099 /* find an identifier */
1100 static inline Sym *sym_find(int v)
1102 v -= TOK_IDENT;
1103 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1104 return NULL;
1105 return table_ident[v]->sym_identifier;
1108 /* push a given symbol on the symbol stack */
1109 static Sym *sym_push(int v, CType *type, int r, int c)
1111 Sym *s, **ps;
1112 TokenSym *ts;
1114 if (local_stack)
1115 ps = &local_stack;
1116 else
1117 ps = &global_stack;
1118 s = sym_push2(ps, v, type->t, c);
1119 s->type.ref = type->ref;
1120 s->r = r;
1121 /* don't record fields or anonymous symbols */
1122 /* XXX: simplify */
1123 if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
1124 /* record symbol in token array */
1125 ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
1126 if (v & SYM_STRUCT)
1127 ps = &ts->sym_struct;
1128 else
1129 ps = &ts->sym_identifier;
1130 s->prev_tok = *ps;
1131 *ps = s;
1133 return s;
1136 /* push a global identifier */
1137 static Sym *global_identifier_push(int v, int t, int c)
1139 Sym *s, **ps;
1140 s = sym_push2(&global_stack, v, t, c);
1141 /* don't record anonymous symbol */
1142 if (v < SYM_FIRST_ANOM) {
1143 ps = &table_ident[v - TOK_IDENT]->sym_identifier;
1144 /* modify the top most local identifier, so that
1145 sym_identifier will point to 's' when popped */
1146 while (*ps != NULL)
1147 ps = &(*ps)->prev_tok;
1148 s->prev_tok = NULL;
1149 *ps = s;
1151 return s;
1154 /* pop symbols until top reaches 'b' */
1155 static void sym_pop(Sym **ptop, Sym *b)
1157 Sym *s, *ss, **ps;
1158 TokenSym *ts;
1159 int v;
1161 s = *ptop;
1162 while(s != b) {
1163 ss = s->prev;
1164 v = s->v;
1165 /* remove symbol in token array */
1166 /* XXX: simplify */
1167 if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
1168 ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
1169 if (v & SYM_STRUCT)
1170 ps = &ts->sym_struct;
1171 else
1172 ps = &ts->sym_identifier;
1173 *ps = s->prev_tok;
1175 sym_free(s);
1176 s = ss;
1178 *ptop = b;
1181 /* I/O layer */
1183 BufferedFile *tcc_open(TCCState *s1, const char *filename)
1185 int fd;
1186 BufferedFile *bf;
1188 if (strcmp(filename, "-") == 0)
1189 fd = 0, filename = "stdin";
1190 else
1191 fd = open(filename, O_RDONLY | O_BINARY);
1192 if ((verbose == 2 && fd >= 0) || verbose == 3)
1193 printf("%s %*s%s\n", fd < 0 ? "nf":"->",
1194 (s1->include_stack_ptr - s1->include_stack), "", filename);
1195 if (fd < 0)
1196 return NULL;
1197 bf = tcc_malloc(sizeof(BufferedFile));
1198 bf->fd = fd;
1199 bf->buf_ptr = bf->buffer;
1200 bf->buf_end = bf->buffer;
1201 bf->buffer[0] = CH_EOB; /* put eob symbol */
1202 pstrcpy(bf->filename, sizeof(bf->filename), filename);
1203 #ifdef _WIN32
1204 normalize_slashes(bf->filename);
1205 #endif
1206 bf->line_num = 1;
1207 bf->ifndef_macro = 0;
1208 bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
1209 // printf("opening '%s'\n", filename);
1210 return bf;
1213 void tcc_close(BufferedFile *bf)
1215 total_lines += bf->line_num;
1216 close(bf->fd);
1217 tcc_free(bf);
1220 #include "tccpp.c"
1221 #include "tccgen.c"
1223 /* better than nothing, but needs extension to handle '-E' option
1224 correctly too */
1225 static void preprocess_init(TCCState *s1)
1227 s1->include_stack_ptr = s1->include_stack;
1228 /* XXX: move that before to avoid having to initialize
1229 file->ifdef_stack_ptr ? */
1230 s1->ifdef_stack_ptr = s1->ifdef_stack;
1231 file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
1233 /* XXX: not ANSI compliant: bound checking says error */
1234 vtop = vstack - 1;
1235 s1->pack_stack[0] = 0;
1236 s1->pack_stack_ptr = s1->pack_stack;
1239 /* compile the C file opened in 'file'. Return non zero if errors. */
1240 static int tcc_compile(TCCState *s1)
1242 Sym *define_start;
1243 char buf[512];
1244 volatile int section_sym;
1246 #ifdef INC_DEBUG
1247 printf("%s: **** new file\n", file->filename);
1248 #endif
1249 preprocess_init(s1);
1251 cur_text_section = NULL;
1252 funcname = "";
1253 anon_sym = SYM_FIRST_ANOM;
1255 /* file info: full path + filename */
1256 section_sym = 0; /* avoid warning */
1257 if (do_debug) {
1258 section_sym = put_elf_sym(symtab_section, 0, 0,
1259 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1260 text_section->sh_num, NULL);
1261 getcwd(buf, sizeof(buf));
1262 #ifdef _WIN32
1263 normalize_slashes(buf);
1264 #endif
1265 pstrcat(buf, sizeof(buf), "/");
1266 put_stabs_r(buf, N_SO, 0, 0,
1267 text_section->data_offset, text_section, section_sym);
1268 put_stabs_r(file->filename, N_SO, 0, 0,
1269 text_section->data_offset, text_section, section_sym);
1271 /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
1272 symbols can be safely used */
1273 put_elf_sym(symtab_section, 0, 0,
1274 ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
1275 SHN_ABS, file->filename);
1277 /* define some often used types */
1278 int_type.t = VT_INT;
1280 char_pointer_type.t = VT_BYTE;
1281 mk_pointer(&char_pointer_type);
1283 func_old_type.t = VT_FUNC;
1284 func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
1286 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1287 float_type.t = VT_FLOAT;
1288 double_type.t = VT_DOUBLE;
1290 func_float_type.t = VT_FUNC;
1291 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
1292 func_double_type.t = VT_FUNC;
1293 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
1294 #endif
1296 #if 0
1297 /* define 'void *alloca(unsigned int)' builtin function */
1299 Sym *s1;
1301 p = anon_sym++;
1302 sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
1303 s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
1304 s1->next = NULL;
1305 sym->next = s1;
1306 sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
1308 #endif
1310 define_start = define_stack;
1311 nocode_wanted = 1;
1313 if (setjmp(s1->error_jmp_buf) == 0) {
1314 s1->nb_errors = 0;
1315 s1->error_set_jmp_enabled = 1;
1317 ch = file->buf_ptr[0];
1318 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
1319 parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
1320 next();
1321 decl(VT_CONST);
1322 if (tok != TOK_EOF)
1323 expect("declaration");
1325 /* end of translation unit info */
1326 if (do_debug) {
1327 put_stabs_r(NULL, N_SO, 0, 0,
1328 text_section->data_offset, text_section, section_sym);
1331 s1->error_set_jmp_enabled = 0;
1333 /* reset define stack, but leave -Dsymbols (may be incorrect if
1334 they are undefined) */
1335 free_defines(define_start);
1337 gen_inline_functions();
1339 sym_pop(&global_stack, NULL);
1340 sym_pop(&local_stack, NULL);
1342 return s1->nb_errors != 0 ? -1 : 0;
1345 /* Preprocess the current file */
1346 static int tcc_preprocess(TCCState *s1)
1348 Sym *define_start;
1349 BufferedFile *file_ref;
1350 int token_seen, line_ref;
1352 preprocess_init(s1);
1353 define_start = define_stack;
1354 ch = file->buf_ptr[0];
1355 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
1356 parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS |
1357 PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES;
1358 token_seen = 0;
1359 line_ref = 0;
1360 file_ref = NULL;
1362 for (;;) {
1363 next();
1364 if (tok == TOK_EOF) {
1365 break;
1366 } else if (tok == TOK_LINEFEED) {
1367 if (!token_seen)
1368 continue;
1369 ++line_ref;
1370 token_seen = 0;
1371 } else if (!token_seen) {
1372 int d = file->line_num - line_ref;
1373 if (file != file_ref || d < 0 || d >= 8)
1374 fprintf(s1->outfile, "# %d \"%s\"\n", file->line_num, file->filename);
1375 else
1376 while (d)
1377 fputs("\n", s1->outfile), --d;
1378 line_ref = (file_ref = file)->line_num;
1379 token_seen = 1;
1381 fputs(get_tok_str(tok, &tokc), s1->outfile);
1383 free_defines(define_start);
1384 return 0;
1387 #ifdef LIBTCC
1388 int tcc_compile_string(TCCState *s, const char *str)
1390 BufferedFile bf1, *bf = &bf1;
1391 int ret, len;
1392 char *buf;
1394 /* init file structure */
1395 bf->fd = -1;
1396 /* XXX: avoid copying */
1397 len = strlen(str);
1398 buf = tcc_malloc(len + 1);
1399 if (!buf)
1400 return -1;
1401 memcpy(buf, str, len);
1402 buf[len] = CH_EOB;
1403 bf->buf_ptr = buf;
1404 bf->buf_end = buf + len;
1405 pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
1406 bf->line_num = 1;
1407 file = bf;
1408 ret = tcc_compile(s);
1409 file = NULL;
1410 tcc_free(buf);
1412 /* currently, no need to close */
1413 return ret;
1415 #endif
1417 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
1418 void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
1420 BufferedFile bf1, *bf = &bf1;
1422 pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
1423 pstrcat(bf->buffer, IO_BUF_SIZE, " ");
1424 /* default value */
1425 if (!value)
1426 value = "1";
1427 pstrcat(bf->buffer, IO_BUF_SIZE, value);
1429 /* init file structure */
1430 bf->fd = -1;
1431 bf->buf_ptr = bf->buffer;
1432 bf->buf_end = bf->buffer + strlen(bf->buffer);
1433 *bf->buf_end = CH_EOB;
1434 bf->filename[0] = '\0';
1435 bf->line_num = 1;
1436 file = bf;
1438 s1->include_stack_ptr = s1->include_stack;
1440 /* parse with define parser */
1441 ch = file->buf_ptr[0];
1442 next_nomacro();
1443 parse_define();
1444 file = NULL;
1447 /* undefine a preprocessor symbol */
1448 void tcc_undefine_symbol(TCCState *s1, const char *sym)
1450 TokenSym *ts;
1451 Sym *s;
1452 ts = tok_alloc(sym, strlen(sym));
1453 s = define_find(ts->tok);
1454 /* undefine symbol by putting an invalid name */
1455 if (s)
1456 define_undef(s);
1459 #ifdef CONFIG_TCC_ASM
1461 #ifdef TCC_TARGET_I386
1462 #include "i386-asm.c"
1463 #endif
1464 #include "tccasm.c"
1466 #else
1467 static void asm_instr(void)
1469 error("inline asm() not supported");
1471 static void asm_global_instr(void)
1473 error("inline asm() not supported");
1475 #endif
1477 #include "tccelf.c"
1479 #ifdef TCC_TARGET_COFF
1480 #include "tcccoff.c"
1481 #endif
1483 #ifdef TCC_TARGET_PE
1484 #include "tccpe.c"
1485 #endif
1487 #ifdef CONFIG_TCC_BACKTRACE
1488 /* print the position in the source file of PC value 'pc' by reading
1489 the stabs debug information */
1490 static void rt_printline(unsigned long wanted_pc)
1492 Stab_Sym *sym, *sym_end;
1493 char func_name[128], last_func_name[128];
1494 unsigned long func_addr, last_pc, pc;
1495 const char *incl_files[INCLUDE_STACK_SIZE];
1496 int incl_index, len, last_line_num, i;
1497 const char *str, *p;
1499 fprintf(stderr, "0x%08lx:", wanted_pc);
1501 func_name[0] = '\0';
1502 func_addr = 0;
1503 incl_index = 0;
1504 last_func_name[0] = '\0';
1505 last_pc = 0xffffffff;
1506 last_line_num = 1;
1507 sym = (Stab_Sym *)stab_section->data + 1;
1508 sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
1509 while (sym < sym_end) {
1510 switch(sym->n_type) {
1511 /* function start or end */
1512 case N_FUN:
1513 if (sym->n_strx == 0) {
1514 /* we test if between last line and end of function */
1515 pc = sym->n_value + func_addr;
1516 if (wanted_pc >= last_pc && wanted_pc < pc)
1517 goto found;
1518 func_name[0] = '\0';
1519 func_addr = 0;
1520 } else {
1521 str = stabstr_section->data + sym->n_strx;
1522 p = strchr(str, ':');
1523 if (!p) {
1524 pstrcpy(func_name, sizeof(func_name), str);
1525 } else {
1526 len = p - str;
1527 if (len > sizeof(func_name) - 1)
1528 len = sizeof(func_name) - 1;
1529 memcpy(func_name, str, len);
1530 func_name[len] = '\0';
1532 func_addr = sym->n_value;
1534 break;
1535 /* line number info */
1536 case N_SLINE:
1537 pc = sym->n_value + func_addr;
1538 if (wanted_pc >= last_pc && wanted_pc < pc)
1539 goto found;
1540 last_pc = pc;
1541 last_line_num = sym->n_desc;
1542 /* XXX: slow! */
1543 strcpy(last_func_name, func_name);
1544 break;
1545 /* include files */
1546 case N_BINCL:
1547 str = stabstr_section->data + sym->n_strx;
1548 add_incl:
1549 if (incl_index < INCLUDE_STACK_SIZE) {
1550 incl_files[incl_index++] = str;
1552 break;
1553 case N_EINCL:
1554 if (incl_index > 1)
1555 incl_index--;
1556 break;
1557 case N_SO:
1558 if (sym->n_strx == 0) {
1559 incl_index = 0; /* end of translation unit */
1560 } else {
1561 str = stabstr_section->data + sym->n_strx;
1562 /* do not add path */
1563 len = strlen(str);
1564 if (len > 0 && str[len - 1] != '/')
1565 goto add_incl;
1567 break;
1569 sym++;
1572 /* second pass: we try symtab symbols (no line number info) */
1573 incl_index = 0;
1575 ElfW(Sym) *sym, *sym_end;
1576 int type;
1578 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
1579 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
1580 sym < sym_end;
1581 sym++) {
1582 type = ELFW(ST_TYPE)(sym->st_info);
1583 if (type == STT_FUNC) {
1584 if (wanted_pc >= sym->st_value &&
1585 wanted_pc < sym->st_value + sym->st_size) {
1586 pstrcpy(last_func_name, sizeof(last_func_name),
1587 strtab_section->data + sym->st_name);
1588 goto found;
1593 /* did not find any info: */
1594 fprintf(stderr, " ???\n");
1595 return;
1596 found:
1597 if (last_func_name[0] != '\0') {
1598 fprintf(stderr, " %s()", last_func_name);
1600 if (incl_index > 0) {
1601 fprintf(stderr, " (%s:%d",
1602 incl_files[incl_index - 1], last_line_num);
1603 for(i = incl_index - 2; i >= 0; i--)
1604 fprintf(stderr, ", included from %s", incl_files[i]);
1605 fprintf(stderr, ")");
1607 fprintf(stderr, "\n");
1610 #ifdef __i386__
1611 /* fix for glibc 2.1 */
1612 #ifndef REG_EIP
1613 #define REG_EIP EIP
1614 #define REG_EBP EBP
1615 #endif
1617 /* return the PC at frame level 'level'. Return non zero if not found */
1618 static int rt_get_caller_pc(unsigned long *paddr,
1619 ucontext_t *uc, int level)
1621 unsigned long fp;
1622 int i;
1624 if (level == 0) {
1625 #if defined(__FreeBSD__)
1626 *paddr = uc->uc_mcontext.mc_eip;
1627 #elif defined(__dietlibc__)
1628 *paddr = uc->uc_mcontext.eip;
1629 #else
1630 *paddr = uc->uc_mcontext.gregs[REG_EIP];
1631 #endif
1632 return 0;
1633 } else {
1634 #if defined(__FreeBSD__)
1635 fp = uc->uc_mcontext.mc_ebp;
1636 #elif defined(__dietlibc__)
1637 fp = uc->uc_mcontext.ebp;
1638 #else
1639 fp = uc->uc_mcontext.gregs[REG_EBP];
1640 #endif
1641 for(i=1;i<level;i++) {
1642 /* XXX: check address validity with program info */
1643 if (fp <= 0x1000 || fp >= 0xc0000000)
1644 return -1;
1645 fp = ((unsigned long *)fp)[0];
1647 *paddr = ((unsigned long *)fp)[1];
1648 return 0;
1651 #elif defined(__x86_64__)
1652 /* return the PC at frame level 'level'. Return non zero if not found */
1653 static int rt_get_caller_pc(unsigned long *paddr,
1654 ucontext_t *uc, int level)
1656 unsigned long fp;
1657 int i;
1659 if (level == 0) {
1660 /* XXX: only support linux */
1661 *paddr = uc->uc_mcontext.gregs[REG_RIP];
1662 return 0;
1663 } else {
1664 fp = uc->uc_mcontext.gregs[REG_RBP];
1665 for(i=1;i<level;i++) {
1666 /* XXX: check address validity with program info */
1667 if (fp <= 0x1000)
1668 return -1;
1669 fp = ((unsigned long *)fp)[0];
1671 *paddr = ((unsigned long *)fp)[1];
1672 return 0;
1675 #else
1676 #warning add arch specific rt_get_caller_pc()
1677 static int rt_get_caller_pc(unsigned long *paddr,
1678 ucontext_t *uc, int level)
1680 return -1;
1682 #endif
1684 /* emit a run time error at position 'pc' */
1685 void rt_error(ucontext_t *uc, const char *fmt, ...)
1687 va_list ap;
1688 unsigned long pc;
1689 int i;
1691 va_start(ap, fmt);
1692 fprintf(stderr, "Runtime error: ");
1693 vfprintf(stderr, fmt, ap);
1694 fprintf(stderr, "\n");
1695 for(i=0;i<num_callers;i++) {
1696 if (rt_get_caller_pc(&pc, uc, i) < 0)
1697 break;
1698 if (i == 0)
1699 fprintf(stderr, "at ");
1700 else
1701 fprintf(stderr, "by ");
1702 rt_printline(pc);
1704 exit(255);
1705 va_end(ap);
1708 /* signal handler for fatal errors */
1709 static void sig_error(int signum, siginfo_t *siginf, void *puc)
1711 ucontext_t *uc = puc;
1713 switch(signum) {
1714 case SIGFPE:
1715 switch(siginf->si_code) {
1716 case FPE_INTDIV:
1717 case FPE_FLTDIV:
1718 rt_error(uc, "division by zero");
1719 break;
1720 default:
1721 rt_error(uc, "floating point exception");
1722 break;
1724 break;
1725 case SIGBUS:
1726 case SIGSEGV:
1727 if (rt_bound_error_msg && *rt_bound_error_msg)
1728 rt_error(uc, *rt_bound_error_msg);
1729 else
1730 rt_error(uc, "dereferencing invalid pointer");
1731 break;
1732 case SIGILL:
1733 rt_error(uc, "illegal instruction");
1734 break;
1735 case SIGABRT:
1736 rt_error(uc, "abort() called");
1737 break;
1738 default:
1739 rt_error(uc, "caught signal %d", signum);
1740 break;
1742 exit(255);
1745 #endif
1747 /* copy code into memory passed in by the caller and do all relocations
1748 (needed before using tcc_get_symbol()).
1749 returns -1 on error and required size if ptr is NULL */
1750 int tcc_relocate(TCCState *s1, void *ptr)
1752 Section *s;
1753 unsigned long offset, length, mem;
1754 int i;
1756 if (0 == s1->runtime_added) {
1757 s1->runtime_added = 1;
1758 s1->nb_errors = 0;
1759 #ifdef TCC_TARGET_PE
1760 pe_add_runtime(s1);
1761 relocate_common_syms();
1762 tcc_add_linker_symbols(s1);
1763 #else
1764 tcc_add_runtime(s1);
1765 relocate_common_syms();
1766 tcc_add_linker_symbols(s1);
1767 build_got_entries(s1);
1768 #endif
1771 offset = 0, mem = (unsigned long)ptr;
1772 for(i = 1; i < s1->nb_sections; i++) {
1773 s = s1->sections[i];
1774 if (0 == (s->sh_flags & SHF_ALLOC))
1775 continue;
1776 length = s->data_offset;
1777 s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
1778 offset = (offset + length + 15) & ~15;
1781 /* relocate symbols */
1782 relocate_syms(s1, 1);
1783 if (s1->nb_errors)
1784 return -1;
1786 #ifdef TCC_TARGET_X86_64
1787 s1->runtime_plt_and_got_offset = 0;
1788 s1->runtime_plt_and_got = (char *)(mem + offset);
1789 /* double the size of the buffer for got and plt entries
1790 XXX: calculate exact size for them? */
1791 offset *= 2;
1792 #endif
1794 if (0 == mem)
1795 return offset + 15;
1797 /* relocate each section */
1798 for(i = 1; i < s1->nb_sections; i++) {
1799 s = s1->sections[i];
1800 if (s->reloc)
1801 relocate_section(s1, s);
1804 for(i = 1; i < s1->nb_sections; i++) {
1805 s = s1->sections[i];
1806 if (0 == (s->sh_flags & SHF_ALLOC))
1807 continue;
1808 length = s->data_offset;
1809 // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
1810 ptr = (void*)s->sh_addr;
1811 if (NULL == s->data || s->sh_type == SHT_NOBITS)
1812 memset(ptr, 0, length);
1813 else
1814 memcpy(ptr, s->data, length);
1815 /* mark executable sections as executable in memory */
1816 if (s->sh_flags & SHF_EXECINSTR)
1817 set_pages_executable(ptr, length);
1819 #ifdef TCC_TARGET_X86_64
1820 set_pages_executable(s1->runtime_plt_and_got,
1821 s1->runtime_plt_and_got_offset);
1822 #endif
1823 return 0;
1826 /* launch the compiled program with the given arguments */
1827 int tcc_run(TCCState *s1, int argc, char **argv)
1829 int (*prog_main)(int, char **);
1830 void *ptr;
1831 int ret;
1833 ret = tcc_relocate(s1, NULL);
1834 if (ret < 0)
1835 return -1;
1836 ptr = tcc_malloc(ret);
1837 tcc_relocate(s1, ptr);
1839 prog_main = tcc_get_symbol_err(s1, "main");
1841 if (do_debug) {
1842 #ifdef CONFIG_TCC_BACKTRACE
1843 struct sigaction sigact;
1844 /* install TCC signal handlers to print debug info on fatal
1845 runtime errors */
1846 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
1847 sigact.sa_sigaction = sig_error;
1848 sigemptyset(&sigact.sa_mask);
1849 sigaction(SIGFPE, &sigact, NULL);
1850 sigaction(SIGILL, &sigact, NULL);
1851 sigaction(SIGSEGV, &sigact, NULL);
1852 sigaction(SIGBUS, &sigact, NULL);
1853 sigaction(SIGABRT, &sigact, NULL);
1854 #else
1855 error("debug mode not available");
1856 #endif
1859 #ifdef CONFIG_TCC_BCHECK
1860 if (do_bounds_check) {
1861 void (*bound_init)(void);
1863 /* set error function */
1864 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
1866 /* XXX: use .init section so that it also work in binary ? */
1867 bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init");
1868 bound_init();
1870 #endif
1871 ret = (*prog_main)(argc, argv);
1872 tcc_free(ptr);
1873 return ret;
1876 void tcc_memstats(void)
1878 #ifdef MEM_DEBUG
1879 printf("memory in use: %d\n", mem_cur_size);
1880 #endif
1883 static void tcc_cleanup(void)
1885 int i, n;
1887 if (NULL == tcc_state)
1888 return;
1889 tcc_state = NULL;
1891 /* free -D defines */
1892 free_defines(NULL);
1894 /* free tokens */
1895 n = tok_ident - TOK_IDENT;
1896 for(i = 0; i < n; i++)
1897 tcc_free(table_ident[i]);
1898 tcc_free(table_ident);
1900 /* free sym_pools */
1901 dynarray_reset(&sym_pools, &nb_sym_pools);
1902 /* string buffer */
1903 cstr_free(&tokcstr);
1904 /* reset symbol stack */
1905 sym_free_first = NULL;
1906 /* cleanup from error/setjmp */
1907 macro_ptr = NULL;
1910 TCCState *tcc_new(void)
1912 const char *p, *r;
1913 TCCState *s;
1914 TokenSym *ts;
1915 int i, c;
1917 tcc_cleanup();
1919 s = tcc_mallocz(sizeof(TCCState));
1920 if (!s)
1921 return NULL;
1922 tcc_state = s;
1923 s->output_type = TCC_OUTPUT_MEMORY;
1925 /* init isid table */
1926 for(i=CH_EOF;i<256;i++)
1927 isidnum_table[i-CH_EOF] = isid(i) || isnum(i);
1929 /* add all tokens */
1930 table_ident = NULL;
1931 memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
1933 tok_ident = TOK_IDENT;
1934 p = tcc_keywords;
1935 while (*p) {
1936 r = p;
1937 for(;;) {
1938 c = *r++;
1939 if (c == '\0')
1940 break;
1942 ts = tok_alloc(p, r - p - 1);
1943 p = r;
1946 /* we add dummy defines for some special macros to speed up tests
1947 and to have working defined() */
1948 define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
1949 define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
1950 define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
1951 define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
1953 /* standard defines */
1954 tcc_define_symbol(s, "__STDC__", NULL);
1955 tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
1956 #if defined(TCC_TARGET_I386)
1957 tcc_define_symbol(s, "__i386__", NULL);
1958 #endif
1959 #if defined(TCC_TARGET_X86_64)
1960 tcc_define_symbol(s, "__x86_64__", NULL);
1961 #endif
1962 #if defined(TCC_TARGET_ARM)
1963 tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
1964 tcc_define_symbol(s, "__arm_elf__", NULL);
1965 tcc_define_symbol(s, "__arm_elf", NULL);
1966 tcc_define_symbol(s, "arm_elf", NULL);
1967 tcc_define_symbol(s, "__arm__", NULL);
1968 tcc_define_symbol(s, "__arm", NULL);
1969 tcc_define_symbol(s, "arm", NULL);
1970 tcc_define_symbol(s, "__APCS_32__", NULL);
1971 #endif
1972 #ifdef TCC_TARGET_PE
1973 tcc_define_symbol(s, "_WIN32", NULL);
1974 #else
1975 tcc_define_symbol(s, "__unix__", NULL);
1976 tcc_define_symbol(s, "__unix", NULL);
1977 #if defined(__linux)
1978 tcc_define_symbol(s, "__linux__", NULL);
1979 tcc_define_symbol(s, "__linux", NULL);
1980 #endif
1981 #endif
1982 /* tiny C specific defines */
1983 tcc_define_symbol(s, "__TINYC__", NULL);
1985 /* tiny C & gcc defines */
1986 tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
1987 tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
1988 #ifdef TCC_TARGET_PE
1989 tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
1990 #else
1991 tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
1992 #endif
1994 #ifndef TCC_TARGET_PE
1995 /* default library paths */
1996 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/local/lib");
1997 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/lib");
1998 tcc_add_library_path(s, CONFIG_SYSROOT "/lib");
1999 #endif
2001 /* no section zero */
2002 dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
2004 /* create standard sections */
2005 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
2006 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
2007 bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
2009 /* symbols are always generated for linking stage */
2010 symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
2011 ".strtab",
2012 ".hashtab", SHF_PRIVATE);
2013 strtab_section = symtab_section->link;
2015 /* private symbol table for dynamic symbols */
2016 s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
2017 ".dynstrtab",
2018 ".dynhashtab", SHF_PRIVATE);
2019 s->alacarte_link = 1;
2021 #ifdef CHAR_IS_UNSIGNED
2022 s->char_is_unsigned = 1;
2023 #endif
2024 #if defined(TCC_TARGET_PE) && 0
2025 /* XXX: currently the PE linker is not ready to support that */
2026 s->leading_underscore = 1;
2027 #endif
2028 return s;
2031 void tcc_delete(TCCState *s1)
2033 int i;
2035 tcc_cleanup();
2037 /* free all sections */
2038 for(i = 1; i < s1->nb_sections; i++)
2039 free_section(s1->sections[i]);
2040 dynarray_reset(&s1->sections, &s1->nb_sections);
2042 for(i = 0; i < s1->nb_priv_sections; i++)
2043 free_section(s1->priv_sections[i]);
2044 dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
2046 /* free any loaded DLLs */
2047 for ( i = 0; i < s1->nb_loaded_dlls; i++) {
2048 DLLReference *ref = s1->loaded_dlls[i];
2049 if ( ref->handle )
2050 dlclose(ref->handle);
2053 /* free loaded dlls array */
2054 dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
2056 /* free library paths */
2057 dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
2059 /* free include paths */
2060 dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
2061 dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
2062 dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
2064 tcc_free(s1);
2067 int tcc_add_include_path(TCCState *s1, const char *pathname)
2069 char *pathname1;
2071 pathname1 = tcc_strdup(pathname);
2072 dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1);
2073 return 0;
2076 int tcc_add_sysinclude_path(TCCState *s1, const char *pathname)
2078 char *pathname1;
2080 pathname1 = tcc_strdup(pathname);
2081 dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1);
2082 return 0;
2085 static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
2087 const char *ext;
2088 ElfW(Ehdr) ehdr;
2089 int fd, ret;
2090 BufferedFile *saved_file;
2092 /* find source file type with extension */
2093 ext = tcc_fileextension(filename);
2094 if (ext[0])
2095 ext++;
2097 /* open the file */
2098 saved_file = file;
2099 file = tcc_open(s1, filename);
2100 if (!file) {
2101 if (flags & AFF_PRINT_ERROR) {
2102 error_noabort("file '%s' not found", filename);
2104 ret = -1;
2105 goto fail1;
2108 if (flags & AFF_PREPROCESS) {
2109 ret = tcc_preprocess(s1);
2110 } else if (!ext[0] || !PATHCMP(ext, "c")) {
2111 /* C file assumed */
2112 ret = tcc_compile(s1);
2113 } else
2114 #ifdef CONFIG_TCC_ASM
2115 if (!strcmp(ext, "S")) {
2116 /* preprocessed assembler */
2117 ret = tcc_assemble(s1, 1);
2118 } else if (!strcmp(ext, "s")) {
2119 /* non preprocessed assembler */
2120 ret = tcc_assemble(s1, 0);
2121 } else
2122 #endif
2123 #ifdef TCC_TARGET_PE
2124 if (!PATHCMP(ext, "def")) {
2125 ret = pe_load_def_file(s1, file->fd);
2126 } else
2127 #endif
2129 fd = file->fd;
2130 /* assume executable format: auto guess file type */
2131 ret = read(fd, &ehdr, sizeof(ehdr));
2132 lseek(fd, 0, SEEK_SET);
2133 if (ret <= 0) {
2134 error_noabort("could not read header");
2135 goto fail;
2136 } else if (ret != sizeof(ehdr)) {
2137 goto try_load_script;
2140 if (ehdr.e_ident[0] == ELFMAG0 &&
2141 ehdr.e_ident[1] == ELFMAG1 &&
2142 ehdr.e_ident[2] == ELFMAG2 &&
2143 ehdr.e_ident[3] == ELFMAG3) {
2144 file->line_num = 0; /* do not display line number if error */
2145 if (ehdr.e_type == ET_REL) {
2146 ret = tcc_load_object_file(s1, fd, 0);
2147 } else if (ehdr.e_type == ET_DYN) {
2148 if (s1->output_type == TCC_OUTPUT_MEMORY) {
2149 #ifdef TCC_TARGET_PE
2150 ret = -1;
2151 #else
2152 void *h;
2153 h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
2154 if (h)
2155 ret = 0;
2156 else
2157 ret = -1;
2158 #endif
2159 } else {
2160 ret = tcc_load_dll(s1, fd, filename,
2161 (flags & AFF_REFERENCED_DLL) != 0);
2163 } else {
2164 error_noabort("unrecognized ELF file");
2165 goto fail;
2167 } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
2168 file->line_num = 0; /* do not display line number if error */
2169 ret = tcc_load_archive(s1, fd);
2170 } else
2171 #ifdef TCC_TARGET_COFF
2172 if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
2173 ret = tcc_load_coff(s1, fd);
2174 } else
2175 #endif
2176 #ifdef TCC_TARGET_PE
2177 if (pe_test_res_file(&ehdr, ret)) {
2178 ret = pe_load_res_file(s1, fd);
2179 } else
2180 #endif
2182 /* as GNU ld, consider it is an ld script if not recognized */
2183 try_load_script:
2184 ret = tcc_load_ldscript(s1);
2185 if (ret < 0) {
2186 error_noabort("unrecognized file type");
2187 goto fail;
2191 the_end:
2192 tcc_close(file);
2193 fail1:
2194 file = saved_file;
2195 return ret;
2196 fail:
2197 ret = -1;
2198 goto the_end;
2201 int tcc_add_file(TCCState *s, const char *filename)
2203 return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR);
2206 int tcc_add_library_path(TCCState *s, const char *pathname)
2208 char *pathname1;
2210 pathname1 = tcc_strdup(pathname);
2211 dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1);
2212 return 0;
2215 /* find and load a dll. Return non zero if not found */
2216 /* XXX: add '-rpath' option support ? */
2217 static int tcc_add_dll(TCCState *s, const char *filename, int flags)
2219 char buf[1024];
2220 int i;
2222 for(i = 0; i < s->nb_library_paths; i++) {
2223 snprintf(buf, sizeof(buf), "%s/%s",
2224 s->library_paths[i], filename);
2225 if (tcc_add_file_internal(s, buf, flags) == 0)
2226 return 0;
2228 return -1;
2231 /* the library name is the same as the argument of the '-l' option */
2232 int tcc_add_library(TCCState *s, const char *libraryname)
2234 char buf[1024];
2235 int i;
2237 /* first we look for the dynamic library if not static linking */
2238 if (!s->static_link) {
2239 #ifdef TCC_TARGET_PE
2240 snprintf(buf, sizeof(buf), "%s.def", libraryname);
2241 #else
2242 snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
2243 #endif
2244 if (tcc_add_dll(s, buf, 0) == 0)
2245 return 0;
2248 /* then we look for the static library */
2249 for(i = 0; i < s->nb_library_paths; i++) {
2250 snprintf(buf, sizeof(buf), "%s/lib%s.a",
2251 s->library_paths[i], libraryname);
2252 if (tcc_add_file_internal(s, buf, 0) == 0)
2253 return 0;
2255 return -1;
2258 int tcc_add_symbol(TCCState *s, const char *name, void *val)
2260 add_elf_sym(symtab_section, (unsigned long)val, 0,
2261 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
2262 SHN_ABS, name);
2263 return 0;
2266 int tcc_set_output_type(TCCState *s, int output_type)
2268 char buf[1024];
2270 s->output_type = output_type;
2272 if (!s->nostdinc) {
2273 /* default include paths */
2274 /* XXX: reverse order needed if -isystem support */
2275 #ifndef TCC_TARGET_PE
2276 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/local/include");
2277 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/include");
2278 #endif
2279 snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path);
2280 tcc_add_sysinclude_path(s, buf);
2281 #ifdef TCC_TARGET_PE
2282 snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path);
2283 tcc_add_sysinclude_path(s, buf);
2284 #endif
2287 /* if bound checking, then add corresponding sections */
2288 #ifdef CONFIG_TCC_BCHECK
2289 if (do_bounds_check) {
2290 /* define symbol */
2291 tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
2292 /* create bounds sections */
2293 bounds_section = new_section(s, ".bounds",
2294 SHT_PROGBITS, SHF_ALLOC);
2295 lbounds_section = new_section(s, ".lbounds",
2296 SHT_PROGBITS, SHF_ALLOC);
2298 #endif
2300 if (s->char_is_unsigned) {
2301 tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
2304 /* add debug sections */
2305 if (do_debug) {
2306 /* stab symbols */
2307 stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
2308 stab_section->sh_entsize = sizeof(Stab_Sym);
2309 stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
2310 put_elf_str(stabstr_section, "");
2311 stab_section->link = stabstr_section;
2312 /* put first entry */
2313 put_stabs("", 0, 0, 0, 0);
2316 /* add libc crt1/crti objects */
2317 #ifndef TCC_TARGET_PE
2318 if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
2319 !s->nostdlib) {
2320 if (output_type != TCC_OUTPUT_DLL)
2321 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
2322 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
2324 #endif
2326 #ifdef TCC_TARGET_PE
2327 snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path);
2328 tcc_add_library_path(s, buf);
2329 #endif
2331 return 0;
2334 #define WD_ALL 0x0001 /* warning is activated when using -Wall */
2335 #define FD_INVERT 0x0002 /* invert value before storing */
2337 typedef struct FlagDef {
2338 uint16_t offset;
2339 uint16_t flags;
2340 const char *name;
2341 } FlagDef;
2343 static const FlagDef warning_defs[] = {
2344 { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
2345 { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
2346 { offsetof(TCCState, warn_error), 0, "error" },
2347 { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
2348 "implicit-function-declaration" },
2351 static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
2352 const char *name, int value)
2354 int i;
2355 const FlagDef *p;
2356 const char *r;
2358 r = name;
2359 if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
2360 r += 3;
2361 value = !value;
2363 for(i = 0, p = flags; i < nb_flags; i++, p++) {
2364 if (!strcmp(r, p->name))
2365 goto found;
2367 return -1;
2368 found:
2369 if (p->flags & FD_INVERT)
2370 value = !value;
2371 *(int *)((uint8_t *)s + p->offset) = value;
2372 return 0;
2376 /* set/reset a warning */
2377 int tcc_set_warning(TCCState *s, const char *warning_name, int value)
2379 int i;
2380 const FlagDef *p;
2382 if (!strcmp(warning_name, "all")) {
2383 for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
2384 if (p->flags & WD_ALL)
2385 *(int *)((uint8_t *)s + p->offset) = 1;
2387 return 0;
2388 } else {
2389 return set_flag(s, warning_defs, countof(warning_defs),
2390 warning_name, value);
2394 static const FlagDef flag_defs[] = {
2395 { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
2396 { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
2397 { offsetof(TCCState, nocommon), FD_INVERT, "common" },
2398 { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
2401 /* set/reset a flag */
2402 int tcc_set_flag(TCCState *s, const char *flag_name, int value)
2404 return set_flag(s, flag_defs, countof(flag_defs),
2405 flag_name, value);
2408 /* set CONFIG_TCCDIR at runtime */
2409 void tcc_set_lib_path(TCCState *s, const char *path)
2411 tcc_lib_path = tcc_strdup(path);