tccpe: load dll on the fly
[tinycc/miki.git] / libtcc.c
blob3494ee20babb6e34839a4f18dc3001e7964c3e48
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 /********************************************************/
24 /* global variables */
26 /* display benchmark infos */
27 int total_lines;
28 int total_bytes;
30 /* parser */
31 static struct BufferedFile *file;
32 static int ch, tok;
33 static CValue tokc;
34 static CString tokcstr; /* current parsed string, if any */
35 /* additional informations about token */
36 static int tok_flags;
37 #define TOK_FLAG_BOL 0x0001 /* beginning of line before */
38 #define TOK_FLAG_BOF 0x0002 /* beginning of file before */
39 #define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */
40 #define TOK_FLAG_EOF 0x0008 /* end of file */
42 static int *macro_ptr, *macro_ptr_allocated;
43 static int *unget_saved_macro_ptr;
44 static int unget_saved_buffer[TOK_MAX_SIZE + 1];
45 static int unget_buffer_enabled;
46 static int parse_flags;
47 #define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */
48 #define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */
49 #define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a
50 token. line feed is also
51 returned at eof */
52 #define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */
53 #define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */
55 static Section *text_section, *data_section, *bss_section; /* predefined sections */
56 static Section *cur_text_section; /* current section where function code is
57 generated */
58 #ifdef CONFIG_TCC_ASM
59 static Section *last_text_section; /* to handle .previous asm directive */
60 #endif
61 /* bound check related sections */
62 static Section *bounds_section; /* contains global data bound description */
63 static Section *lbounds_section; /* contains local data bound description */
64 /* symbol sections */
65 static Section *symtab_section, *strtab_section;
67 /* debug sections */
68 static Section *stab_section, *stabstr_section;
70 /* loc : local variable index
71 ind : output code index
72 rsym: return symbol
73 anon_sym: anonymous symbol index
75 static int rsym, anon_sym, ind, loc;
76 /* expression generation modifiers */
77 static int const_wanted; /* true if constant wanted */
78 static int nocode_wanted; /* true if no code generation wanted for an expression */
79 static int global_expr; /* true if compound literals must be allocated
80 globally (used during initializers parsing */
81 static CType func_vt; /* current function return type (used by return
82 instruction) */
83 static int func_vc;
84 static int last_line_num, last_ind, func_ind; /* debug last line number and pc */
85 static int tok_ident;
86 static TokenSym **table_ident;
87 static TokenSym *hash_ident[TOK_HASH_SIZE];
88 static char token_buf[STRING_MAX_SIZE + 1];
89 static char *funcname;
90 static Sym *global_stack, *local_stack;
91 static Sym *define_stack;
92 static Sym *global_label_stack, *local_label_stack;
93 /* symbol allocator */
94 #define SYM_POOL_NB (8192 / sizeof(Sym))
95 static Sym *sym_free_first;
96 static void **sym_pools;
97 static int nb_sym_pools;
99 static SValue vstack[VSTACK_SIZE], *vtop;
100 /* some predefined types */
101 static CType char_pointer_type, func_old_type, int_type;
103 /* use GNU C extensions */
104 static int gnu_ext = 1;
106 /* use Tiny C extensions */
107 static int tcc_ext = 1;
109 /* max number of callers shown if error */
110 #ifdef CONFIG_TCC_BACKTRACE
111 int num_callers = 6;
112 const char **rt_bound_error_msg;
113 unsigned long rt_prog_main;
114 #endif
116 /* XXX: get rid of this ASAP */
117 static struct TCCState *tcc_state;
119 /********************************************************/
120 /* function prototypes */
122 /* tccpp.c */
123 static void next(void);
124 char *get_tok_str(int v, CValue *cv);
126 /* tccgen.c */
127 static void parse_expr_type(CType *type);
128 static void expr_type(CType *type);
129 static void unary_type(CType *type);
130 static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
131 int case_reg, int is_expr);
132 static int expr_const(void);
133 static void expr_eq(void);
134 static void gexpr(void);
135 static void gen_inline_functions(void);
136 static void decl(int l);
137 static void decl_initializer(CType *type, Section *sec, unsigned long c,
138 int first, int size_only);
139 static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
140 int has_init, int v, int scope);
141 int gv(int rc);
142 void gv2(int rc1, int rc2);
143 void move_reg(int r, int s);
144 void save_regs(int n);
145 void save_reg(int r);
146 void vpop(void);
147 void vswap(void);
148 void vdup(void);
149 int get_reg(int rc);
150 int get_reg_ex(int rc,int rc2);
152 void gen_op(int op);
153 void force_charshort_cast(int t);
154 static void gen_cast(CType *type);
155 void vstore(void);
156 static Sym *sym_find(int v);
157 static Sym *sym_push(int v, CType *type, int r, int c);
159 /* type handling */
160 static int type_size(CType *type, int *a);
161 static inline CType *pointed_type(CType *type);
162 static int pointed_size(CType *type);
163 static int lvalue_type(int t);
164 static int parse_btype(CType *type, AttributeDef *ad);
165 static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
166 static int compare_types(CType *type1, CType *type2, int unqualified);
167 static int is_compatible_types(CType *type1, CType *type2);
168 static int is_compatible_parameter_types(CType *type1, CType *type2);
170 int ieee_finite(double d);
171 void vpushi(int v);
172 void vpushll(long long v);
173 void vrott(int n);
174 void vnrott(int n);
175 void lexpand_nr(void);
176 static void vpush_global_sym(CType *type, int v);
177 void vset(CType *type, int r, int v);
178 void type_to_str(char *buf, int buf_size,
179 CType *type, const char *varstr);
180 static Sym *get_sym_ref(CType *type, Section *sec,
181 unsigned long offset, unsigned long size);
182 static Sym *external_global_sym(int v, CType *type, int r);
184 /* section generation */
185 static void section_realloc(Section *sec, unsigned long new_size);
186 static void *section_ptr_add(Section *sec, unsigned long size);
187 static void put_extern_sym(Sym *sym, Section *section,
188 unsigned long value, unsigned long size);
189 static void greloc(Section *s, Sym *sym, unsigned long addr, int type);
190 static int put_elf_str(Section *s, const char *sym);
191 static int put_elf_sym(Section *s,
192 unsigned long value, unsigned long size,
193 int info, int other, int shndx, const char *name);
194 static int add_elf_sym(Section *s, uplong value, unsigned long size,
195 int info, int other, int sh_num, const char *name);
196 static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
197 int type, int symbol);
198 static void put_stabs(const char *str, int type, int other, int desc,
199 unsigned long value);
200 static void put_stabs_r(const char *str, int type, int other, int desc,
201 unsigned long value, Section *sec, int sym_index);
202 static void put_stabn(int type, int other, int desc, int value);
203 static void put_stabd(int type, int other, int desc);
204 static int tcc_add_dll(TCCState *s, const char *filename, int flags);
206 #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */
207 #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */
208 #define AFF_PREPROCESS 0x0004 /* preprocess file */
209 static int tcc_add_file_internal(TCCState *s, const char *filename, int flags);
211 /* tcccoff.c */
212 int tcc_output_coff(TCCState *s1, FILE *f);
214 /* tccpe.c */
215 int pe_load_file(struct TCCState *s1, const char *filename, int fd);
216 int pe_output_file(struct TCCState *s1, const char *filename);
218 /* tccasm.c */
219 #ifdef CONFIG_TCC_ASM
220 static void asm_expr(TCCState *s1, ExprValue *pe);
221 static int asm_int_expr(TCCState *s1);
222 static int find_constraint(ASMOperand *operands, int nb_operands,
223 const char *name, const char **pp);
225 static int tcc_assemble(TCCState *s1, int do_preprocess);
226 #endif
228 static void asm_instr(void);
229 static void asm_global_instr(void);
231 /********************************************************/
232 /* libtcc.c */
234 static Sym *__sym_malloc(void);
235 static inline Sym *sym_malloc(void);
236 static inline void sym_free(Sym *sym);
237 Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
238 static void free_section(Section *s);
239 static void section_realloc(Section *sec, unsigned long new_size);
240 static void *section_ptr_add(Section *sec, unsigned long size);
241 Section *find_section(TCCState *s1, const char *name);
242 static void put_extern_sym2(
243 Sym *sym, Section *section,
244 unsigned long value, unsigned long size, int can_add_underscore);
245 static void put_extern_sym(
246 Sym *sym, Section *section,
247 unsigned long value, unsigned long size);
248 static void greloc(Section *s, Sym *sym, unsigned long offset, int type);
250 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap);
251 static void strcat_printf(char *buf, int buf_size, const char *fmt, ...);
253 /* CString handling */
254 static void cstr_realloc(CString *cstr, int new_size);
255 static inline void cstr_ccat(CString *cstr, int ch);
256 static void cstr_cat(CString *cstr, const char *str);
257 static void cstr_wccat(CString *cstr, int ch);
258 static void cstr_new(CString *cstr);
259 static void cstr_free(CString *cstr);
260 #define cstr_reset(cstr) cstr_free(cstr)
261 static void add_char(CString *cstr, int c);
263 static Sym *sym_push2(Sym **ps, int v, int t, long c);
264 static Sym *sym_find2(Sym *s, int v);
265 static inline Sym *struct_find(int v);
266 static inline Sym *sym_find(int v);
267 static Sym *sym_push(int v, CType *type, int r, int c);
268 static Sym *global_identifier_push(int v, int t, int c);
269 static void sym_pop(Sym **ptop, Sym *b);
271 BufferedFile *tcc_open(TCCState *s1, const char *filename);
272 void tcc_close(BufferedFile *bf);
273 static int tcc_compile(TCCState *s1);
275 void expect(const char *msg);
276 void skip(int c);
277 static void test_lvalue(void);
278 void *resolve_sym(TCCState *s1, const char *sym);
280 static inline int isid(int c)
282 return (c >= 'a' && c <= 'z')
283 || (c >= 'A' && c <= 'Z')
284 || c == '_';
287 static inline int isnum(int c)
289 return c >= '0' && c <= '9';
292 static inline int isoct(int c)
294 return c >= '0' && c <= '7';
297 static inline int toup(int c)
299 if (c >= 'a' && c <= 'z')
300 return c - 'a' + 'A';
301 else
302 return c;
305 /********************************************************/
307 #ifdef TCC_TARGET_I386
308 #include "i386-gen.c"
309 #endif
311 #ifdef TCC_TARGET_ARM
312 #include "arm-gen.c"
313 #endif
315 #ifdef TCC_TARGET_C67
316 #include "c67-gen.c"
317 #endif
319 #ifdef TCC_TARGET_X86_64
320 #include "x86_64-gen.c"
321 #endif
323 #include "tccpp.c"
324 #include "tccgen.c"
326 #ifdef CONFIG_TCC_ASM
327 #ifdef TCC_TARGET_I386
328 #include "i386-asm.c"
329 #endif
330 #include "tccasm.c"
331 #else
332 static void asm_instr(void)
334 error("inline asm() not supported");
336 static void asm_global_instr(void)
338 error("inline asm() not supported");
340 #endif
342 #include "tccelf.c"
344 #ifdef TCC_TARGET_COFF
345 #include "tcccoff.c"
346 #endif
348 #ifdef TCC_TARGET_PE
349 #include "tccpe.c"
350 #endif
352 /********************************************************/
353 #ifdef _WIN32
354 char *normalize_slashes(char *path)
356 char *p;
357 for (p = path; *p; ++p)
358 if (*p == '\\')
359 *p = '/';
360 return path;
363 HMODULE tcc_module;
365 /* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */
366 void tcc_set_lib_path_w32(TCCState *s)
368 char path[1024], *p;
369 GetModuleFileNameA(tcc_module, path, sizeof path);
370 p = tcc_basename(normalize_slashes(strlwr(path)));
371 if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
372 p -= 5;
373 else if (p > path)
374 p--;
375 *p = 0;
376 tcc_set_lib_path(s, path);
379 #ifdef LIBTCC_AS_DLL
380 BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
382 if (DLL_PROCESS_ATTACH == dwReason)
383 tcc_module = hDll;
384 return TRUE;
386 #endif
387 #endif
389 /********************************************************/
390 #ifdef CONFIG_TCC_STATIC
392 #define RTLD_LAZY 0x001
393 #define RTLD_NOW 0x002
394 #define RTLD_GLOBAL 0x100
395 #define RTLD_DEFAULT NULL
397 /* dummy function for profiling */
398 void *dlopen(const char *filename, int flag)
400 return NULL;
403 void dlclose(void *p)
407 const char *dlerror(void)
409 return "error";
412 typedef struct TCCSyms {
413 char *str;
414 void *ptr;
415 } TCCSyms;
417 #define TCCSYM(a) { #a, &a, },
419 /* add the symbol you want here if no dynamic linking is done */
420 static TCCSyms tcc_syms[] = {
421 #if !defined(CONFIG_TCCBOOT)
422 TCCSYM(printf)
423 TCCSYM(fprintf)
424 TCCSYM(fopen)
425 TCCSYM(fclose)
426 #endif
427 { NULL, NULL },
430 void *resolve_sym(TCCState *s1, const char *symbol)
432 TCCSyms *p;
433 p = tcc_syms;
434 while (p->str != NULL) {
435 if (!strcmp(p->str, symbol))
436 return p->ptr;
437 p++;
439 return NULL;
442 #elif defined(_WIN32)
443 #define dlclose FreeLibrary
445 #else
446 #include <dlfcn.h>
448 void *resolve_sym(TCCState *s1, const char *sym)
450 return dlsym(RTLD_DEFAULT, sym);
453 #endif
455 /********************************************************/
457 /* we use our own 'finite' function to avoid potential problems with
458 non standard math libs */
459 /* XXX: endianness dependent */
460 int ieee_finite(double d)
462 int *p = (int *)&d;
463 return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
466 /* copy a string and truncate it. */
467 char *pstrcpy(char *buf, int buf_size, const char *s)
469 char *q, *q_end;
470 int c;
472 if (buf_size > 0) {
473 q = buf;
474 q_end = buf + buf_size - 1;
475 while (q < q_end) {
476 c = *s++;
477 if (c == '\0')
478 break;
479 *q++ = c;
481 *q = '\0';
483 return buf;
486 /* strcat and truncate. */
487 char *pstrcat(char *buf, int buf_size, const char *s)
489 int len;
490 len = strlen(buf);
491 if (len < buf_size)
492 pstrcpy(buf + len, buf_size - len, s);
493 return buf;
496 /* extract the basename of a file */
497 char *tcc_basename(const char *name)
499 char *p = strchr(name, 0);
500 while (p > name && !IS_PATHSEP(p[-1]))
501 --p;
502 return p;
505 char *tcc_fileextension (const char *name)
507 char *b = tcc_basename(name);
508 char *e = strrchr(b, '.');
509 return e ? e : strchr(b, 0);
512 #ifdef _WIN32
513 char *normalize_slashes(char *path)
515 char *p;
516 for (p = path; *p; ++p)
517 if (*p == '\\')
518 *p = '/';
519 return path;
522 void tcc_set_lib_path_w32(TCCState *s)
524 /* on win32, we suppose the lib and includes are at the location
525 of 'tcc.exe' */
526 char path[1024], *p;
527 GetModuleFileNameA(NULL, path, sizeof path);
528 p = tcc_basename(normalize_slashes(strlwr(path)));
529 if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
530 p -= 5;
531 else if (p > path)
532 p--;
533 *p = 0;
534 tcc_set_lib_path(s, path);
536 #endif
538 void set_pages_executable(void *ptr, unsigned long length)
540 #ifdef _WIN32
541 unsigned long old_protect;
542 VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
543 #else
544 unsigned long start, end;
545 start = (unsigned long)ptr & ~(PAGESIZE - 1);
546 end = (unsigned long)ptr + length;
547 end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
548 mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
549 #endif
552 /* memory management */
553 #ifdef MEM_DEBUG
554 int mem_cur_size;
555 int mem_max_size;
556 unsigned malloc_usable_size(void*);
557 #endif
559 void tcc_free(void *ptr)
561 #ifdef MEM_DEBUG
562 mem_cur_size -= malloc_usable_size(ptr);
563 #endif
564 free(ptr);
567 void *tcc_malloc(unsigned long size)
569 void *ptr;
570 ptr = malloc(size);
571 if (!ptr && size)
572 error("memory full");
573 #ifdef MEM_DEBUG
574 mem_cur_size += malloc_usable_size(ptr);
575 if (mem_cur_size > mem_max_size)
576 mem_max_size = mem_cur_size;
577 #endif
578 return ptr;
581 void *tcc_mallocz(unsigned long size)
583 void *ptr;
584 ptr = tcc_malloc(size);
585 memset(ptr, 0, size);
586 return ptr;
589 void *tcc_realloc(void *ptr, unsigned long size)
591 void *ptr1;
592 #ifdef MEM_DEBUG
593 mem_cur_size -= malloc_usable_size(ptr);
594 #endif
595 ptr1 = realloc(ptr, size);
596 #ifdef MEM_DEBUG
597 /* NOTE: count not correct if alloc error, but not critical */
598 mem_cur_size += malloc_usable_size(ptr1);
599 if (mem_cur_size > mem_max_size)
600 mem_max_size = mem_cur_size;
601 #endif
602 return ptr1;
605 char *tcc_strdup(const char *str)
607 char *ptr;
608 ptr = tcc_malloc(strlen(str) + 1);
609 strcpy(ptr, str);
610 return ptr;
613 #define free(p) use_tcc_free(p)
614 #define malloc(s) use_tcc_malloc(s)
615 #define realloc(p, s) use_tcc_realloc(p, s)
617 void dynarray_add(void ***ptab, int *nb_ptr, void *data)
619 int nb, nb_alloc;
620 void **pp;
622 nb = *nb_ptr;
623 pp = *ptab;
624 /* every power of two we double array size */
625 if ((nb & (nb - 1)) == 0) {
626 if (!nb)
627 nb_alloc = 1;
628 else
629 nb_alloc = nb * 2;
630 pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
631 if (!pp)
632 error("memory full");
633 *ptab = pp;
635 pp[nb++] = data;
636 *nb_ptr = nb;
639 void dynarray_reset(void *pp, int *n)
641 void **p;
642 for (p = *(void***)pp; *n; ++p, --*n)
643 if (*p)
644 tcc_free(*p);
645 tcc_free(*(void**)pp);
646 *(void**)pp = NULL;
649 /* symbol allocator */
650 static Sym *__sym_malloc(void)
652 Sym *sym_pool, *sym, *last_sym;
653 int i;
655 sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym));
656 dynarray_add(&sym_pools, &nb_sym_pools, sym_pool);
658 last_sym = sym_free_first;
659 sym = sym_pool;
660 for(i = 0; i < SYM_POOL_NB; i++) {
661 sym->next = last_sym;
662 last_sym = sym;
663 sym++;
665 sym_free_first = last_sym;
666 return last_sym;
669 static inline Sym *sym_malloc(void)
671 Sym *sym;
672 sym = sym_free_first;
673 if (!sym)
674 sym = __sym_malloc();
675 sym_free_first = sym->next;
676 return sym;
679 static inline void sym_free(Sym *sym)
681 sym->next = sym_free_first;
682 sym_free_first = sym;
685 Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
687 Section *sec;
689 sec = tcc_mallocz(sizeof(Section) + strlen(name));
690 strcpy(sec->name, name);
691 sec->sh_type = sh_type;
692 sec->sh_flags = sh_flags;
693 switch(sh_type) {
694 case SHT_HASH:
695 case SHT_REL:
696 case SHT_RELA:
697 case SHT_DYNSYM:
698 case SHT_SYMTAB:
699 case SHT_DYNAMIC:
700 sec->sh_addralign = 4;
701 break;
702 case SHT_STRTAB:
703 sec->sh_addralign = 1;
704 break;
705 default:
706 sec->sh_addralign = 32; /* default conservative alignment */
707 break;
710 if (sh_flags & SHF_PRIVATE) {
711 dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
712 } else {
713 sec->sh_num = s1->nb_sections;
714 dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
717 return sec;
720 static void free_section(Section *s)
722 tcc_free(s->data);
725 /* realloc section and set its content to zero */
726 static void section_realloc(Section *sec, unsigned long new_size)
728 unsigned long size;
729 unsigned char *data;
731 size = sec->data_allocated;
732 if (size == 0)
733 size = 1;
734 while (size < new_size)
735 size = size * 2;
736 data = tcc_realloc(sec->data, size);
737 if (!data)
738 error("memory full");
739 memset(data + sec->data_allocated, 0, size - sec->data_allocated);
740 sec->data = data;
741 sec->data_allocated = size;
744 /* reserve at least 'size' bytes in section 'sec' from
745 sec->data_offset. */
746 static void *section_ptr_add(Section *sec, unsigned long size)
748 unsigned long offset, offset1;
750 offset = sec->data_offset;
751 offset1 = offset + size;
752 if (offset1 > sec->data_allocated)
753 section_realloc(sec, offset1);
754 sec->data_offset = offset1;
755 return sec->data + offset;
758 /* return a reference to a section, and create it if it does not
759 exists */
760 Section *find_section(TCCState *s1, const char *name)
762 Section *sec;
763 int i;
764 for(i = 1; i < s1->nb_sections; i++) {
765 sec = s1->sections[i];
766 if (!strcmp(name, sec->name))
767 return sec;
769 /* sections are created as PROGBITS */
770 return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
773 /* update sym->c so that it points to an external symbol in section
774 'section' with value 'value' */
775 static void put_extern_sym2(Sym *sym, Section *section,
776 unsigned long value, unsigned long size,
777 int can_add_underscore)
779 int sym_type, sym_bind, sh_num, info, other, attr;
780 ElfW(Sym) *esym;
781 const char *name;
782 char buf1[256];
784 if (section == NULL)
785 sh_num = SHN_UNDEF;
786 else if (section == SECTION_ABS)
787 sh_num = SHN_ABS;
788 else
789 sh_num = section->sh_num;
791 other = attr = 0;
793 if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
794 sym_type = STT_FUNC;
795 #ifdef TCC_TARGET_PE
796 if (sym->type.ref)
797 attr = sym->type.ref->r;
798 if (FUNC_EXPORT(attr))
799 other |= 1;
800 if (FUNC_CALL(attr) == FUNC_STDCALL)
801 other |= 2;
802 #endif
803 } else {
804 sym_type = STT_OBJECT;
807 if (sym->type.t & VT_STATIC)
808 sym_bind = STB_LOCAL;
809 else
810 sym_bind = STB_GLOBAL;
812 if (!sym->c) {
813 name = get_tok_str(sym->v, NULL);
814 #ifdef CONFIG_TCC_BCHECK
815 if (tcc_state->do_bounds_check) {
816 char buf[32];
818 /* XXX: avoid doing that for statics ? */
819 /* if bound checking is activated, we change some function
820 names by adding the "__bound" prefix */
821 switch(sym->v) {
822 #if 0
823 /* XXX: we rely only on malloc hooks */
824 case TOK_malloc:
825 case TOK_free:
826 case TOK_realloc:
827 case TOK_memalign:
828 case TOK_calloc:
829 #endif
830 case TOK_memcpy:
831 case TOK_memmove:
832 case TOK_memset:
833 case TOK_strlen:
834 case TOK_strcpy:
835 case TOK_alloca:
836 strcpy(buf, "__bound_");
837 strcat(buf, name);
838 name = buf;
839 break;
842 #endif
844 #ifdef TCC_TARGET_PE
845 if ((other & 2) && can_add_underscore) {
846 sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr));
847 name = buf1;
848 } else
849 #endif
850 if (tcc_state->leading_underscore && can_add_underscore) {
851 buf1[0] = '_';
852 pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
853 name = buf1;
855 info = ELFW(ST_INFO)(sym_bind, sym_type);
856 sym->c = add_elf_sym(symtab_section, value, size, info, other, sh_num, name);
857 } else {
858 esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
859 esym->st_value = value;
860 esym->st_size = size;
861 esym->st_shndx = sh_num;
862 esym->st_other |= other;
866 static void put_extern_sym(Sym *sym, Section *section,
867 unsigned long value, unsigned long size)
869 put_extern_sym2(sym, section, value, size, 1);
872 /* add a new relocation entry to symbol 'sym' in section 's' */
873 static void greloc(Section *s, Sym *sym, unsigned long offset, int type)
875 if (!sym->c)
876 put_extern_sym(sym, NULL, 0, 0);
877 /* now we can add ELF relocation info */
878 put_elf_reloc(symtab_section, s, offset, type, sym->c);
881 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
883 int len;
884 len = strlen(buf);
885 vsnprintf(buf + len, buf_size - len, fmt, ap);
888 static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
890 va_list ap;
891 va_start(ap, fmt);
892 strcat_vprintf(buf, buf_size, fmt, ap);
893 va_end(ap);
896 void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
898 char buf[2048];
899 BufferedFile **f;
901 buf[0] = '\0';
902 if (file) {
903 for(f = s1->include_stack; f < s1->include_stack_ptr; f++)
904 strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
905 (*f)->filename, (*f)->line_num);
906 if (file->line_num > 0) {
907 strcat_printf(buf, sizeof(buf),
908 "%s:%d: ", file->filename, file->line_num);
909 } else {
910 strcat_printf(buf, sizeof(buf),
911 "%s: ", file->filename);
913 } else {
914 strcat_printf(buf, sizeof(buf),
915 "tcc: ");
917 if (is_warning)
918 strcat_printf(buf, sizeof(buf), "warning: ");
919 else
920 strcat_printf(buf, sizeof(buf), "error: ");
921 strcat_vprintf(buf, sizeof(buf), fmt, ap);
923 if (!s1->error_func) {
924 /* default case: stderr */
925 fprintf(stderr, "%s\n", buf);
926 } else {
927 s1->error_func(s1->error_opaque, buf);
929 if (!is_warning || s1->warn_error)
930 s1->nb_errors++;
933 void tcc_set_error_func(TCCState *s, void *error_opaque,
934 void (*error_func)(void *opaque, const char *msg))
936 s->error_opaque = error_opaque;
937 s->error_func = error_func;
940 /* error without aborting current compilation */
941 void error_noabort(const char *fmt, ...)
943 TCCState *s1 = tcc_state;
944 va_list ap;
946 va_start(ap, fmt);
947 error1(s1, 0, fmt, ap);
948 va_end(ap);
951 void error(const char *fmt, ...)
953 TCCState *s1 = tcc_state;
954 va_list ap;
956 va_start(ap, fmt);
957 error1(s1, 0, fmt, ap);
958 va_end(ap);
959 /* better than nothing: in some cases, we accept to handle errors */
960 if (s1->error_set_jmp_enabled) {
961 longjmp(s1->error_jmp_buf, 1);
962 } else {
963 /* XXX: eliminate this someday */
964 exit(1);
968 void expect(const char *msg)
970 error("%s expected", msg);
973 void warning(const char *fmt, ...)
975 TCCState *s1 = tcc_state;
976 va_list ap;
978 if (s1->warn_none)
979 return;
981 va_start(ap, fmt);
982 error1(s1, 1, fmt, ap);
983 va_end(ap);
986 void skip(int c)
988 if (tok != c)
989 error("'%c' expected", c);
990 next();
993 static void test_lvalue(void)
995 if (!(vtop->r & VT_LVAL))
996 expect("lvalue");
999 /* CString handling */
1001 static void cstr_realloc(CString *cstr, int new_size)
1003 int size;
1004 void *data;
1006 size = cstr->size_allocated;
1007 if (size == 0)
1008 size = 8; /* no need to allocate a too small first string */
1009 while (size < new_size)
1010 size = size * 2;
1011 data = tcc_realloc(cstr->data_allocated, size);
1012 if (!data)
1013 error("memory full");
1014 cstr->data_allocated = data;
1015 cstr->size_allocated = size;
1016 cstr->data = data;
1019 /* add a byte */
1020 static inline void cstr_ccat(CString *cstr, int ch)
1022 int size;
1023 size = cstr->size + 1;
1024 if (size > cstr->size_allocated)
1025 cstr_realloc(cstr, size);
1026 ((unsigned char *)cstr->data)[size - 1] = ch;
1027 cstr->size = size;
1030 static void cstr_cat(CString *cstr, const char *str)
1032 int c;
1033 for(;;) {
1034 c = *str;
1035 if (c == '\0')
1036 break;
1037 cstr_ccat(cstr, c);
1038 str++;
1042 /* add a wide char */
1043 static void cstr_wccat(CString *cstr, int ch)
1045 int size;
1046 size = cstr->size + sizeof(nwchar_t);
1047 if (size > cstr->size_allocated)
1048 cstr_realloc(cstr, size);
1049 *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
1050 cstr->size = size;
1053 static void cstr_new(CString *cstr)
1055 memset(cstr, 0, sizeof(CString));
1058 /* free string and reset it to NULL */
1059 static void cstr_free(CString *cstr)
1061 tcc_free(cstr->data_allocated);
1062 cstr_new(cstr);
1065 #define cstr_reset(cstr) cstr_free(cstr)
1067 /* XXX: unicode ? */
1068 static void add_char(CString *cstr, int c)
1070 if (c == '\'' || c == '\"' || c == '\\') {
1071 /* XXX: could be more precise if char or string */
1072 cstr_ccat(cstr, '\\');
1074 if (c >= 32 && c <= 126) {
1075 cstr_ccat(cstr, c);
1076 } else {
1077 cstr_ccat(cstr, '\\');
1078 if (c == '\n') {
1079 cstr_ccat(cstr, 'n');
1080 } else {
1081 cstr_ccat(cstr, '0' + ((c >> 6) & 7));
1082 cstr_ccat(cstr, '0' + ((c >> 3) & 7));
1083 cstr_ccat(cstr, '0' + (c & 7));
1088 /* push, without hashing */
1089 static Sym *sym_push2(Sym **ps, int v, int t, long c)
1091 Sym *s;
1092 s = sym_malloc();
1093 s->v = v;
1094 s->type.t = t;
1095 #ifdef _WIN64
1096 s->d = NULL;
1097 #endif
1098 s->c = c;
1099 s->next = NULL;
1100 /* add in stack */
1101 s->prev = *ps;
1102 *ps = s;
1103 return s;
1106 /* find a symbol and return its associated structure. 's' is the top
1107 of the symbol stack */
1108 static Sym *sym_find2(Sym *s, int v)
1110 while (s) {
1111 if (s->v == v)
1112 return s;
1113 s = s->prev;
1115 return NULL;
1118 /* structure lookup */
1119 static inline Sym *struct_find(int v)
1121 v -= TOK_IDENT;
1122 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1123 return NULL;
1124 return table_ident[v]->sym_struct;
1127 /* find an identifier */
1128 static inline Sym *sym_find(int v)
1130 v -= TOK_IDENT;
1131 if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
1132 return NULL;
1133 return table_ident[v]->sym_identifier;
1136 /* push a given symbol on the symbol stack */
1137 static Sym *sym_push(int v, CType *type, int r, int c)
1139 Sym *s, **ps;
1140 TokenSym *ts;
1142 if (local_stack)
1143 ps = &local_stack;
1144 else
1145 ps = &global_stack;
1146 s = sym_push2(ps, v, type->t, c);
1147 s->type.ref = type->ref;
1148 s->r = r;
1149 /* don't record fields or anonymous symbols */
1150 /* XXX: simplify */
1151 if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
1152 /* record symbol in token array */
1153 ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
1154 if (v & SYM_STRUCT)
1155 ps = &ts->sym_struct;
1156 else
1157 ps = &ts->sym_identifier;
1158 s->prev_tok = *ps;
1159 *ps = s;
1161 return s;
1164 /* push a global identifier */
1165 static Sym *global_identifier_push(int v, int t, int c)
1167 Sym *s, **ps;
1168 s = sym_push2(&global_stack, v, t, c);
1169 /* don't record anonymous symbol */
1170 if (v < SYM_FIRST_ANOM) {
1171 ps = &table_ident[v - TOK_IDENT]->sym_identifier;
1172 /* modify the top most local identifier, so that
1173 sym_identifier will point to 's' when popped */
1174 while (*ps != NULL)
1175 ps = &(*ps)->prev_tok;
1176 s->prev_tok = NULL;
1177 *ps = s;
1179 return s;
1182 /* pop symbols until top reaches 'b' */
1183 static void sym_pop(Sym **ptop, Sym *b)
1185 Sym *s, *ss, **ps;
1186 TokenSym *ts;
1187 int v;
1189 s = *ptop;
1190 while(s != b) {
1191 ss = s->prev;
1192 v = s->v;
1193 /* remove symbol in token array */
1194 /* XXX: simplify */
1195 if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
1196 ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
1197 if (v & SYM_STRUCT)
1198 ps = &ts->sym_struct;
1199 else
1200 ps = &ts->sym_identifier;
1201 *ps = s->prev_tok;
1203 sym_free(s);
1204 s = ss;
1206 *ptop = b;
1209 /* I/O layer */
1211 BufferedFile *tcc_open(TCCState *s1, const char *filename)
1213 int fd;
1214 BufferedFile *bf;
1216 if (strcmp(filename, "-") == 0)
1217 fd = 0, filename = "stdin";
1218 else
1219 fd = open(filename, O_RDONLY | O_BINARY);
1220 if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
1221 printf("%s %*s%s\n", fd < 0 ? "nf":"->",
1222 (int)(s1->include_stack_ptr - s1->include_stack), "", filename);
1223 if (fd < 0)
1224 return NULL;
1225 bf = tcc_malloc(sizeof(BufferedFile));
1226 bf->fd = fd;
1227 bf->buf_ptr = bf->buffer;
1228 bf->buf_end = bf->buffer;
1229 bf->buffer[0] = CH_EOB; /* put eob symbol */
1230 pstrcpy(bf->filename, sizeof(bf->filename), filename);
1231 #ifdef _WIN32
1232 normalize_slashes(bf->filename);
1233 #endif
1234 bf->line_num = 1;
1235 bf->ifndef_macro = 0;
1236 bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
1237 // printf("opening '%s'\n", filename);
1238 return bf;
1241 void tcc_close(BufferedFile *bf)
1243 total_lines += bf->line_num;
1244 close(bf->fd);
1245 tcc_free(bf);
1248 /* compile the C file opened in 'file'. Return non zero if errors. */
1249 static int tcc_compile(TCCState *s1)
1251 Sym *define_start;
1252 char buf[512];
1253 volatile int section_sym;
1255 #ifdef INC_DEBUG
1256 printf("%s: **** new file\n", file->filename);
1257 #endif
1258 preprocess_init(s1);
1260 cur_text_section = NULL;
1261 funcname = "";
1262 anon_sym = SYM_FIRST_ANOM;
1264 /* file info: full path + filename */
1265 section_sym = 0; /* avoid warning */
1266 if (s1->do_debug) {
1267 section_sym = put_elf_sym(symtab_section, 0, 0,
1268 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1269 text_section->sh_num, NULL);
1270 getcwd(buf, sizeof(buf));
1271 #ifdef _WIN32
1272 normalize_slashes(buf);
1273 #endif
1274 pstrcat(buf, sizeof(buf), "/");
1275 put_stabs_r(buf, N_SO, 0, 0,
1276 text_section->data_offset, text_section, section_sym);
1277 put_stabs_r(file->filename, N_SO, 0, 0,
1278 text_section->data_offset, text_section, section_sym);
1280 /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
1281 symbols can be safely used */
1282 put_elf_sym(symtab_section, 0, 0,
1283 ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
1284 SHN_ABS, file->filename);
1286 /* define some often used types */
1287 int_type.t = VT_INT;
1289 char_pointer_type.t = VT_BYTE;
1290 mk_pointer(&char_pointer_type);
1292 func_old_type.t = VT_FUNC;
1293 func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
1295 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1296 float_type.t = VT_FLOAT;
1297 double_type.t = VT_DOUBLE;
1299 func_float_type.t = VT_FUNC;
1300 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
1301 func_double_type.t = VT_FUNC;
1302 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
1303 #endif
1305 #if 0
1306 /* define 'void *alloca(unsigned int)' builtin function */
1308 Sym *s1;
1310 p = anon_sym++;
1311 sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
1312 s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
1313 s1->next = NULL;
1314 sym->next = s1;
1315 sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
1317 #endif
1319 define_start = define_stack;
1320 nocode_wanted = 1;
1322 if (setjmp(s1->error_jmp_buf) == 0) {
1323 s1->nb_errors = 0;
1324 s1->error_set_jmp_enabled = 1;
1326 ch = file->buf_ptr[0];
1327 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
1328 parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
1329 next();
1330 decl(VT_CONST);
1331 if (tok != TOK_EOF)
1332 expect("declaration");
1334 /* end of translation unit info */
1335 if (s1->do_debug) {
1336 put_stabs_r(NULL, N_SO, 0, 0,
1337 text_section->data_offset, text_section, section_sym);
1340 s1->error_set_jmp_enabled = 0;
1342 /* reset define stack, but leave -Dsymbols (may be incorrect if
1343 they are undefined) */
1344 free_defines(define_start);
1346 gen_inline_functions();
1348 sym_pop(&global_stack, NULL);
1349 sym_pop(&local_stack, NULL);
1351 return s1->nb_errors != 0 ? -1 : 0;
1354 int tcc_compile_string(TCCState *s, const char *str)
1356 BufferedFile bf1, *bf = &bf1;
1357 int ret, len;
1358 char *buf;
1360 /* init file structure */
1361 bf->fd = -1;
1362 /* XXX: avoid copying */
1363 len = strlen(str);
1364 buf = tcc_malloc(len + 1);
1365 if (!buf)
1366 return -1;
1367 memcpy(buf, str, len);
1368 buf[len] = CH_EOB;
1369 bf->buf_ptr = buf;
1370 bf->buf_end = buf + len;
1371 pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
1372 bf->line_num = 1;
1373 file = bf;
1374 ret = tcc_compile(s);
1375 file = NULL;
1376 tcc_free(buf);
1378 /* currently, no need to close */
1379 return ret;
1382 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
1383 void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
1385 BufferedFile bf1, *bf = &bf1;
1387 pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
1388 pstrcat(bf->buffer, IO_BUF_SIZE, " ");
1389 /* default value */
1390 if (!value)
1391 value = "1";
1392 pstrcat(bf->buffer, IO_BUF_SIZE, value);
1394 /* init file structure */
1395 bf->fd = -1;
1396 bf->buf_ptr = bf->buffer;
1397 bf->buf_end = bf->buffer + strlen(bf->buffer);
1398 *bf->buf_end = CH_EOB;
1399 bf->filename[0] = '\0';
1400 bf->line_num = 1;
1401 file = bf;
1403 s1->include_stack_ptr = s1->include_stack;
1405 /* parse with define parser */
1406 ch = file->buf_ptr[0];
1407 next_nomacro();
1408 parse_define();
1409 file = NULL;
1412 /* undefine a preprocessor symbol */
1413 void tcc_undefine_symbol(TCCState *s1, const char *sym)
1415 TokenSym *ts;
1416 Sym *s;
1417 ts = tok_alloc(sym, strlen(sym));
1418 s = define_find(ts->tok);
1419 /* undefine symbol by putting an invalid name */
1420 if (s)
1421 define_undef(s);
1425 #ifdef CONFIG_TCC_BACKTRACE
1426 /* print the position in the source file of PC value 'pc' by reading
1427 the stabs debug information */
1428 static unsigned long rt_printline(unsigned long wanted_pc)
1430 Stab_Sym *sym, *sym_end;
1431 char func_name[128], last_func_name[128];
1432 unsigned long func_addr, last_pc, pc;
1433 const char *incl_files[INCLUDE_STACK_SIZE];
1434 int incl_index, len, last_line_num, i;
1435 const char *str, *p;
1437 fprintf(stderr, "0x%08lx:", wanted_pc);
1439 func_name[0] = '\0';
1440 func_addr = 0;
1441 incl_index = 0;
1442 last_func_name[0] = '\0';
1443 last_pc = 0xffffffff;
1444 last_line_num = 1;
1445 sym = (Stab_Sym *)stab_section->data + 1;
1446 sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
1447 while (sym < sym_end) {
1448 switch(sym->n_type) {
1449 /* function start or end */
1450 case N_FUN:
1451 if (sym->n_strx == 0) {
1452 /* we test if between last line and end of function */
1453 pc = sym->n_value + func_addr;
1454 if (wanted_pc >= last_pc && wanted_pc < pc)
1455 goto found;
1456 func_name[0] = '\0';
1457 func_addr = 0;
1458 } else {
1459 str = stabstr_section->data + sym->n_strx;
1460 p = strchr(str, ':');
1461 if (!p) {
1462 pstrcpy(func_name, sizeof(func_name), str);
1463 } else {
1464 len = p - str;
1465 if (len > sizeof(func_name) - 1)
1466 len = sizeof(func_name) - 1;
1467 memcpy(func_name, str, len);
1468 func_name[len] = '\0';
1470 func_addr = sym->n_value;
1472 break;
1473 /* line number info */
1474 case N_SLINE:
1475 pc = sym->n_value + func_addr;
1476 if (wanted_pc >= last_pc && wanted_pc < pc)
1477 goto found;
1478 last_pc = pc;
1479 last_line_num = sym->n_desc;
1480 /* XXX: slow! */
1481 strcpy(last_func_name, func_name);
1482 break;
1483 /* include files */
1484 case N_BINCL:
1485 str = stabstr_section->data + sym->n_strx;
1486 add_incl:
1487 if (incl_index < INCLUDE_STACK_SIZE) {
1488 incl_files[incl_index++] = str;
1490 break;
1491 case N_EINCL:
1492 if (incl_index > 1)
1493 incl_index--;
1494 break;
1495 case N_SO:
1496 if (sym->n_strx == 0) {
1497 incl_index = 0; /* end of translation unit */
1498 } else {
1499 str = stabstr_section->data + sym->n_strx;
1500 /* do not add path */
1501 len = strlen(str);
1502 if (len > 0 && str[len - 1] != '/')
1503 goto add_incl;
1505 break;
1507 sym++;
1510 /* second pass: we try symtab symbols (no line number info) */
1511 incl_index = 0;
1513 ElfW(Sym) *sym, *sym_end;
1514 int type;
1516 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
1517 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
1518 sym < sym_end;
1519 sym++) {
1520 type = ELFW(ST_TYPE)(sym->st_info);
1521 if (type == STT_FUNC) {
1522 if (wanted_pc >= sym->st_value &&
1523 wanted_pc < sym->st_value + sym->st_size) {
1524 pstrcpy(last_func_name, sizeof(last_func_name),
1525 strtab_section->data + sym->st_name);
1526 func_addr = sym->st_value;
1527 goto found;
1532 /* did not find any info: */
1533 fprintf(stderr, " ???\n");
1534 return 0;
1535 found:
1536 if (last_func_name[0] != '\0') {
1537 fprintf(stderr, " %s()", last_func_name);
1539 if (incl_index > 0) {
1540 fprintf(stderr, " (%s:%d",
1541 incl_files[incl_index - 1], last_line_num);
1542 for(i = incl_index - 2; i >= 0; i--)
1543 fprintf(stderr, ", included from %s", incl_files[i]);
1544 fprintf(stderr, ")");
1546 fprintf(stderr, "\n");
1547 return func_addr;
1550 #ifdef __i386__
1551 /* fix for glibc 2.1 */
1552 #ifndef REG_EIP
1553 #define REG_EIP EIP
1554 #define REG_EBP EBP
1555 #endif
1557 /* return the PC at frame level 'level'. Return non zero if not found */
1558 static int rt_get_caller_pc(unsigned long *paddr,
1559 ucontext_t *uc, int level)
1561 unsigned long fp;
1562 int i;
1564 if (level == 0) {
1565 #if defined(__FreeBSD__)
1566 *paddr = uc->uc_mcontext.mc_eip;
1567 #elif defined(__dietlibc__)
1568 *paddr = uc->uc_mcontext.eip;
1569 #else
1570 *paddr = uc->uc_mcontext.gregs[REG_EIP];
1571 #endif
1572 return 0;
1573 } else {
1574 #if defined(__FreeBSD__)
1575 fp = uc->uc_mcontext.mc_ebp;
1576 #elif defined(__dietlibc__)
1577 fp = uc->uc_mcontext.ebp;
1578 #else
1579 fp = uc->uc_mcontext.gregs[REG_EBP];
1580 #endif
1581 for(i=1;i<level;i++) {
1582 /* XXX: check address validity with program info */
1583 if (fp <= 0x1000 || fp >= 0xc0000000)
1584 return -1;
1585 fp = ((unsigned long *)fp)[0];
1587 *paddr = ((unsigned long *)fp)[1];
1588 return 0;
1591 #elif defined(__x86_64__)
1592 /* return the PC at frame level 'level'. Return non zero if not found */
1593 static int rt_get_caller_pc(unsigned long *paddr,
1594 ucontext_t *uc, int level)
1596 unsigned long fp;
1597 int i;
1599 if (level == 0) {
1600 /* XXX: only support linux */
1601 *paddr = uc->uc_mcontext.gregs[REG_RIP];
1602 return 0;
1603 } else {
1604 fp = uc->uc_mcontext.gregs[REG_RBP];
1605 for(i=1;i<level;i++) {
1606 /* XXX: check address validity with program info */
1607 if (fp <= 0x1000)
1608 return -1;
1609 fp = ((unsigned long *)fp)[0];
1611 *paddr = ((unsigned long *)fp)[1];
1612 return 0;
1615 #else
1616 #warning add arch specific rt_get_caller_pc()
1617 static int rt_get_caller_pc(unsigned long *paddr,
1618 ucontext_t *uc, int level)
1620 return -1;
1622 #endif
1624 /* emit a run time error at position 'pc' */
1625 void rt_error(ucontext_t *uc, const char *fmt, ...)
1627 va_list ap;
1628 unsigned long pc;
1629 int i;
1631 va_start(ap, fmt);
1632 fprintf(stderr, "Runtime error: ");
1633 vfprintf(stderr, fmt, ap);
1634 fprintf(stderr, "\n");
1635 for(i=0;i<num_callers;i++) {
1636 if (rt_get_caller_pc(&pc, uc, i) < 0)
1637 break;
1638 if (i == 0)
1639 fprintf(stderr, "at ");
1640 else
1641 fprintf(stderr, "by ");
1642 pc = rt_printline(pc);
1643 if (pc == rt_prog_main && pc)
1644 break;
1646 exit(255);
1647 va_end(ap);
1650 /* signal handler for fatal errors */
1651 static void sig_error(int signum, siginfo_t *siginf, void *puc)
1653 ucontext_t *uc = puc;
1655 switch(signum) {
1656 case SIGFPE:
1657 switch(siginf->si_code) {
1658 case FPE_INTDIV:
1659 case FPE_FLTDIV:
1660 rt_error(uc, "division by zero");
1661 break;
1662 default:
1663 rt_error(uc, "floating point exception");
1664 break;
1666 break;
1667 case SIGBUS:
1668 case SIGSEGV:
1669 if (rt_bound_error_msg && *rt_bound_error_msg)
1670 rt_error(uc, *rt_bound_error_msg);
1671 else
1672 rt_error(uc, "dereferencing invalid pointer");
1673 break;
1674 case SIGILL:
1675 rt_error(uc, "illegal instruction");
1676 break;
1677 case SIGABRT:
1678 rt_error(uc, "abort() called");
1679 break;
1680 default:
1681 rt_error(uc, "caught signal %d", signum);
1682 break;
1684 exit(255);
1687 #endif
1689 /* copy code into memory passed in by the caller and do all relocations
1690 (needed before using tcc_get_symbol()).
1691 returns -1 on error and required size if ptr is NULL */
1692 int tcc_relocate(TCCState *s1, void *ptr)
1694 Section *s;
1695 unsigned long offset, length;
1696 uplong mem;
1697 int i;
1699 if (0 == s1->runtime_added) {
1700 s1->runtime_added = 1;
1701 s1->nb_errors = 0;
1702 #ifdef TCC_TARGET_PE
1703 pe_output_file(s1, NULL);
1704 #else
1705 tcc_add_runtime(s1);
1706 relocate_common_syms();
1707 tcc_add_linker_symbols(s1);
1708 build_got_entries(s1);
1709 #endif
1710 if (s1->nb_errors)
1711 return -1;
1714 offset = 0, mem = (uplong)ptr;
1715 for(i = 1; i < s1->nb_sections; i++) {
1716 s = s1->sections[i];
1717 if (0 == (s->sh_flags & SHF_ALLOC))
1718 continue;
1719 length = s->data_offset;
1720 s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
1721 offset = (offset + length + 15) & ~15;
1724 /* relocate symbols */
1725 relocate_syms(s1, 1);
1726 if (s1->nb_errors)
1727 return -1;
1729 #ifndef TCC_TARGET_PE
1730 #ifdef TCC_TARGET_X86_64
1731 s1->runtime_plt_and_got_offset = 0;
1732 s1->runtime_plt_and_got = (char *)(mem + offset);
1733 /* double the size of the buffer for got and plt entries
1734 XXX: calculate exact size for them? */
1735 offset *= 2;
1736 #endif
1737 #endif
1739 if (0 == mem)
1740 return offset + 15;
1742 /* relocate each section */
1743 for(i = 1; i < s1->nb_sections; i++) {
1744 s = s1->sections[i];
1745 if (s->reloc)
1746 relocate_section(s1, s);
1749 for(i = 1; i < s1->nb_sections; i++) {
1750 s = s1->sections[i];
1751 if (0 == (s->sh_flags & SHF_ALLOC))
1752 continue;
1753 length = s->data_offset;
1754 // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
1755 ptr = (void*)(uplong)s->sh_addr;
1756 if (NULL == s->data || s->sh_type == SHT_NOBITS)
1757 memset(ptr, 0, length);
1758 else
1759 memcpy(ptr, s->data, length);
1760 /* mark executable sections as executable in memory */
1761 if (s->sh_flags & SHF_EXECINSTR)
1762 set_pages_executable(ptr, length);
1764 #ifndef TCC_TARGET_PE
1765 #ifdef TCC_TARGET_X86_64
1766 set_pages_executable(s1->runtime_plt_and_got,
1767 s1->runtime_plt_and_got_offset);
1768 #endif
1769 #endif
1770 return 0;
1773 /* launch the compiled program with the given arguments */
1774 int tcc_run(TCCState *s1, int argc, char **argv)
1776 int (*prog_main)(int, char **);
1777 void *ptr;
1778 int ret;
1780 ret = tcc_relocate(s1, NULL);
1781 if (ret < 0)
1782 return -1;
1783 ptr = tcc_malloc(ret);
1784 tcc_relocate(s1, ptr);
1786 prog_main = tcc_get_symbol_err(s1, "main");
1788 if (s1->do_debug) {
1789 #ifdef CONFIG_TCC_BACKTRACE
1790 struct sigaction sigact;
1791 /* install TCC signal handlers to print debug info on fatal
1792 runtime errors */
1793 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
1794 sigact.sa_sigaction = sig_error;
1795 sigemptyset(&sigact.sa_mask);
1796 sigaction(SIGFPE, &sigact, NULL);
1797 sigaction(SIGILL, &sigact, NULL);
1798 sigaction(SIGSEGV, &sigact, NULL);
1799 sigaction(SIGBUS, &sigact, NULL);
1800 sigaction(SIGABRT, &sigact, NULL);
1801 #else
1802 error("debug mode not available");
1803 #endif
1806 #ifdef CONFIG_TCC_BCHECK
1807 if (s1->do_bounds_check) {
1808 void (*bound_init)(void);
1809 void (*bound_exit)(void);
1810 /* set error function */
1811 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
1812 rt_prog_main = (unsigned long)prog_main;
1813 /* XXX: use .init section so that it also work in binary ? */
1814 bound_init = tcc_get_symbol_err(s1, "__bound_init");
1815 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
1816 bound_init();
1817 ret = (*prog_main)(argc, argv);
1818 bound_exit();
1819 } else
1820 #endif
1821 ret = (*prog_main)(argc, argv);
1822 tcc_free(ptr);
1823 return ret;
1826 void tcc_memstats(void)
1828 #ifdef MEM_DEBUG
1829 printf("memory in use: %d\n", mem_cur_size);
1830 #endif
1833 static void tcc_cleanup(void)
1835 int i, n;
1837 if (NULL == tcc_state)
1838 return;
1839 tcc_state = NULL;
1841 /* free -D defines */
1842 free_defines(NULL);
1844 /* free tokens */
1845 n = tok_ident - TOK_IDENT;
1846 for(i = 0; i < n; i++)
1847 tcc_free(table_ident[i]);
1848 tcc_free(table_ident);
1850 /* free sym_pools */
1851 dynarray_reset(&sym_pools, &nb_sym_pools);
1852 /* string buffer */
1853 cstr_free(&tokcstr);
1854 /* reset symbol stack */
1855 sym_free_first = NULL;
1856 /* cleanup from error/setjmp */
1857 macro_ptr = NULL;
1860 TCCState *tcc_new(void)
1862 TCCState *s;
1864 tcc_cleanup();
1866 s = tcc_mallocz(sizeof(TCCState));
1867 if (!s)
1868 return NULL;
1869 tcc_state = s;
1870 s->output_type = TCC_OUTPUT_MEMORY;
1871 s->tcc_lib_path = CONFIG_TCCDIR;
1873 preprocess_new();
1875 /* we add dummy defines for some special macros to speed up tests
1876 and to have working defined() */
1877 define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
1878 define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
1879 define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
1880 define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
1882 /* standard defines */
1883 tcc_define_symbol(s, "__STDC__", NULL);
1884 tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
1885 #if defined(TCC_TARGET_I386)
1886 tcc_define_symbol(s, "__i386__", NULL);
1887 #endif
1888 #if defined(TCC_TARGET_X86_64)
1889 tcc_define_symbol(s, "__x86_64__", NULL);
1890 #endif
1891 #if defined(TCC_TARGET_ARM)
1892 tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
1893 tcc_define_symbol(s, "__arm_elf__", NULL);
1894 tcc_define_symbol(s, "__arm_elf", NULL);
1895 tcc_define_symbol(s, "arm_elf", NULL);
1896 tcc_define_symbol(s, "__arm__", NULL);
1897 tcc_define_symbol(s, "__arm", NULL);
1898 tcc_define_symbol(s, "arm", NULL);
1899 tcc_define_symbol(s, "__APCS_32__", NULL);
1900 #endif
1901 #ifdef TCC_TARGET_PE
1902 tcc_define_symbol(s, "_WIN32", NULL);
1903 #ifdef TCC_TARGET_X86_64
1904 tcc_define_symbol(s, "_WIN64", NULL);
1905 #endif
1906 #else
1907 tcc_define_symbol(s, "__unix__", NULL);
1908 tcc_define_symbol(s, "__unix", NULL);
1909 #if defined(__linux)
1910 tcc_define_symbol(s, "__linux__", NULL);
1911 tcc_define_symbol(s, "__linux", NULL);
1912 #endif
1913 #endif
1914 /* tiny C specific defines */
1915 tcc_define_symbol(s, "__TINYC__", NULL);
1917 /* tiny C & gcc defines */
1918 tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
1919 tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
1920 #ifdef TCC_TARGET_PE
1921 tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
1922 #else
1923 tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
1924 #endif
1926 #ifndef TCC_TARGET_PE
1927 /* default library paths */
1928 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/local/lib");
1929 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/lib");
1930 tcc_add_library_path(s, CONFIG_SYSROOT "/lib");
1931 #endif
1933 /* no section zero */
1934 dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
1936 /* create standard sections */
1937 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1938 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1939 bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
1941 /* symbols are always generated for linking stage */
1942 symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
1943 ".strtab",
1944 ".hashtab", SHF_PRIVATE);
1945 strtab_section = symtab_section->link;
1947 /* private symbol table for dynamic symbols */
1948 s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
1949 ".dynstrtab",
1950 ".dynhashtab", SHF_PRIVATE);
1951 s->alacarte_link = 1;
1953 #ifdef CHAR_IS_UNSIGNED
1954 s->char_is_unsigned = 1;
1955 #endif
1956 #if defined(TCC_TARGET_PE) && 0
1957 /* XXX: currently the PE linker is not ready to support that */
1958 s->leading_underscore = 1;
1959 #endif
1960 return s;
1963 void tcc_delete(TCCState *s1)
1965 int i;
1967 tcc_cleanup();
1969 /* free all sections */
1970 for(i = 1; i < s1->nb_sections; i++)
1971 free_section(s1->sections[i]);
1972 dynarray_reset(&s1->sections, &s1->nb_sections);
1974 for(i = 0; i < s1->nb_priv_sections; i++)
1975 free_section(s1->priv_sections[i]);
1976 dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
1978 /* free any loaded DLLs */
1979 for ( i = 0; i < s1->nb_loaded_dlls; i++) {
1980 DLLReference *ref = s1->loaded_dlls[i];
1981 if ( ref->handle )
1982 dlclose(ref->handle);
1985 /* free loaded dlls array */
1986 dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
1988 /* free library paths */
1989 dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
1991 /* free include paths */
1992 dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
1993 dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
1994 dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
1996 tcc_free(s1);
1999 int tcc_add_include_path(TCCState *s1, const char *pathname)
2001 char *pathname1;
2003 pathname1 = tcc_strdup(pathname);
2004 dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1);
2005 return 0;
2008 int tcc_add_sysinclude_path(TCCState *s1, const char *pathname)
2010 char *pathname1;
2012 pathname1 = tcc_strdup(pathname);
2013 dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1);
2014 return 0;
2017 static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
2019 const char *ext;
2020 ElfW(Ehdr) ehdr;
2021 int fd, ret, size;
2022 BufferedFile *saved_file;
2024 ret = -1;
2026 /* find source file type with extension */
2027 ext = tcc_fileextension(filename);
2028 if (ext[0])
2029 ext++;
2031 /* open the file */
2032 saved_file = file;
2033 file = tcc_open(s1, filename);
2034 if (!file) {
2035 if (flags & AFF_PRINT_ERROR)
2036 error_noabort("file '%s' not found", filename);
2037 goto the_end;
2040 if (flags & AFF_PREPROCESS) {
2041 ret = tcc_preprocess(s1);
2042 goto the_end;
2045 if (!ext[0] || !PATHCMP(ext, "c")) {
2046 /* C file assumed */
2047 ret = tcc_compile(s1);
2048 goto the_end;
2051 #ifdef CONFIG_TCC_ASM
2052 if (!strcmp(ext, "S")) {
2053 /* preprocessed assembler */
2054 ret = tcc_assemble(s1, 1);
2055 goto the_end;
2058 if (!strcmp(ext, "s")) {
2059 /* non preprocessed assembler */
2060 ret = tcc_assemble(s1, 0);
2061 goto the_end;
2063 #endif
2065 fd = file->fd;
2066 /* assume executable format: auto guess file type */
2067 size = read(fd, &ehdr, sizeof(ehdr));
2068 lseek(fd, 0, SEEK_SET);
2069 if (size <= 0) {
2070 error_noabort("could not read header");
2071 goto the_end;
2074 if (size == sizeof(ehdr) &&
2075 ehdr.e_ident[0] == ELFMAG0 &&
2076 ehdr.e_ident[1] == ELFMAG1 &&
2077 ehdr.e_ident[2] == ELFMAG2 &&
2078 ehdr.e_ident[3] == ELFMAG3) {
2080 /* do not display line number if error */
2081 file->line_num = 0;
2082 if (ehdr.e_type == ET_REL) {
2083 ret = tcc_load_object_file(s1, fd, 0);
2084 goto the_end;
2087 #ifndef TCC_TARGET_PE
2088 if (ehdr.e_type == ET_DYN) {
2089 if (s1->output_type == TCC_OUTPUT_MEMORY) {
2090 void *h;
2091 h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
2092 if (h)
2093 ret = 0;
2094 } else {
2095 ret = tcc_load_dll(s1, fd, filename,
2096 (flags & AFF_REFERENCED_DLL) != 0);
2098 goto the_end;
2100 #endif
2101 error_noabort("unrecognized ELF file");
2102 goto the_end;
2105 if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
2106 file->line_num = 0; /* do not display line number if error */
2107 ret = tcc_load_archive(s1, fd);
2108 goto the_end;
2111 #ifdef TCC_TARGET_COFF
2112 if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
2113 ret = tcc_load_coff(s1, fd);
2114 goto the_end;
2116 #endif
2118 #ifdef TCC_TARGET_PE
2119 ret = pe_load_file(s1, filename, fd);
2120 #else
2121 /* as GNU ld, consider it is an ld script if not recognized */
2122 ret = tcc_load_ldscript(s1);
2123 #endif
2124 if (ret < 0)
2125 error_noabort("unrecognized file type");
2127 the_end:
2128 if (file)
2129 tcc_close(file);
2130 file = saved_file;
2131 return ret;
2134 int tcc_add_file(TCCState *s, const char *filename)
2136 if (s->output_type == TCC_OUTPUT_PREPROCESS)
2137 return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS);
2138 else
2139 return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR);
2142 int tcc_add_library_path(TCCState *s, const char *pathname)
2144 char *pathname1;
2146 pathname1 = tcc_strdup(pathname);
2147 dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1);
2148 return 0;
2151 /* find and load a dll. Return non zero if not found */
2152 /* XXX: add '-rpath' option support ? */
2153 static int tcc_add_dll(TCCState *s, const char *filename, int flags)
2155 char buf[1024];
2156 int i;
2158 for(i = 0; i < s->nb_library_paths; i++) {
2159 snprintf(buf, sizeof(buf), "%s/%s",
2160 s->library_paths[i], filename);
2161 if (tcc_add_file_internal(s, buf, flags) == 0)
2162 return 0;
2164 return -1;
2167 /* the library name is the same as the argument of the '-l' option */
2168 int tcc_add_library(TCCState *s, const char *libraryname)
2170 char buf[1024];
2171 int i;
2173 /* first we look for the dynamic library if not static linking */
2174 if (!s->static_link) {
2175 #ifdef TCC_TARGET_PE
2176 if (pe_add_dll(s, libraryname) == 0)
2177 return 0;
2178 #else
2179 snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
2180 if (tcc_add_dll(s, buf, 0) == 0)
2181 return 0;
2182 #endif
2184 /* then we look for the static library */
2185 for(i = 0; i < s->nb_library_paths; i++) {
2186 snprintf(buf, sizeof(buf), "%s/lib%s.a",
2187 s->library_paths[i], libraryname);
2188 if (tcc_add_file_internal(s, buf, 0) == 0)
2189 return 0;
2191 return -1;
2194 int tcc_add_symbol(TCCState *s, const char *name, void *val)
2196 add_elf_sym(symtab_section, (uplong)val, 0,
2197 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
2198 SHN_ABS, name);
2199 return 0;
2202 int tcc_set_output_type(TCCState *s, int output_type)
2204 char buf[1024];
2206 s->output_type = output_type;
2208 if (!s->nostdinc) {
2209 /* default include paths */
2210 /* XXX: reverse order needed if -isystem support */
2211 #ifndef TCC_TARGET_PE
2212 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/local/include");
2213 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/include");
2214 #endif
2215 snprintf(buf, sizeof(buf), "%s/include", s->tcc_lib_path);
2216 tcc_add_sysinclude_path(s, buf);
2217 #ifdef TCC_TARGET_PE
2218 snprintf(buf, sizeof(buf), "%s/include/winapi", s->tcc_lib_path);
2219 tcc_add_sysinclude_path(s, buf);
2220 #endif
2223 /* if bound checking, then add corresponding sections */
2224 #ifdef CONFIG_TCC_BCHECK
2225 if (s->do_bounds_check) {
2226 /* define symbol */
2227 tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
2228 /* create bounds sections */
2229 bounds_section = new_section(s, ".bounds",
2230 SHT_PROGBITS, SHF_ALLOC);
2231 lbounds_section = new_section(s, ".lbounds",
2232 SHT_PROGBITS, SHF_ALLOC);
2234 #endif
2236 if (s->char_is_unsigned) {
2237 tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
2240 /* add debug sections */
2241 if (s->do_debug) {
2242 /* stab symbols */
2243 stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
2244 stab_section->sh_entsize = sizeof(Stab_Sym);
2245 stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
2246 put_elf_str(stabstr_section, "");
2247 stab_section->link = stabstr_section;
2248 /* put first entry */
2249 put_stabs("", 0, 0, 0, 0);
2252 /* add libc crt1/crti objects */
2253 #ifndef TCC_TARGET_PE
2254 if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
2255 !s->nostdlib) {
2256 if (output_type != TCC_OUTPUT_DLL)
2257 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
2258 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
2260 #endif
2262 #ifdef TCC_TARGET_PE
2263 snprintf(buf, sizeof(buf), "%s/lib", s->tcc_lib_path);
2264 tcc_add_library_path(s, buf);
2265 #ifdef _WIN32
2266 if (GetSystemDirectory(buf, sizeof buf))
2267 tcc_add_library_path(s, buf);
2268 #endif
2269 #endif
2271 return 0;
2274 #define WD_ALL 0x0001 /* warning is activated when using -Wall */
2275 #define FD_INVERT 0x0002 /* invert value before storing */
2277 typedef struct FlagDef {
2278 uint16_t offset;
2279 uint16_t flags;
2280 const char *name;
2281 } FlagDef;
2283 static const FlagDef warning_defs[] = {
2284 { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
2285 { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
2286 { offsetof(TCCState, warn_error), 0, "error" },
2287 { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
2288 "implicit-function-declaration" },
2291 static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
2292 const char *name, int value)
2294 int i;
2295 const FlagDef *p;
2296 const char *r;
2298 r = name;
2299 if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
2300 r += 3;
2301 value = !value;
2303 for(i = 0, p = flags; i < nb_flags; i++, p++) {
2304 if (!strcmp(r, p->name))
2305 goto found;
2307 return -1;
2308 found:
2309 if (p->flags & FD_INVERT)
2310 value = !value;
2311 *(int *)((uint8_t *)s + p->offset) = value;
2312 return 0;
2316 /* set/reset a warning */
2317 int tcc_set_warning(TCCState *s, const char *warning_name, int value)
2319 int i;
2320 const FlagDef *p;
2322 if (!strcmp(warning_name, "all")) {
2323 for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
2324 if (p->flags & WD_ALL)
2325 *(int *)((uint8_t *)s + p->offset) = 1;
2327 return 0;
2328 } else {
2329 return set_flag(s, warning_defs, countof(warning_defs),
2330 warning_name, value);
2334 static const FlagDef flag_defs[] = {
2335 { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
2336 { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
2337 { offsetof(TCCState, nocommon), FD_INVERT, "common" },
2338 { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
2341 /* set/reset a flag */
2342 int tcc_set_flag(TCCState *s, const char *flag_name, int value)
2344 return set_flag(s, flag_defs, countof(flag_defs),
2345 flag_name, value);
2348 /* set CONFIG_TCCDIR at runtime */
2349 void tcc_set_lib_path(TCCState *s, const char *path)
2351 s->tcc_lib_path = tcc_strdup(path);
2354 void tcc_print_stats(TCCState *s, int64_t total_time)
2356 double tt;
2357 tt = (double)total_time / 1000000.0;
2358 if (tt < 0.001)
2359 tt = 0.001;
2360 if (total_bytes < 1)
2361 total_bytes = 1;
2362 printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n",
2363 tok_ident - TOK_IDENT, total_lines, total_bytes,
2364 tt, (int)(total_lines / tt),
2365 total_bytes / tt / 1000000.0);