Added OS specific files. Builds now on Cygwin.
[tinycc/k1w1.git] / libtcc.c
blobe72e68ae7df795ea54746ee80f3de925baa74ef9
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 struct BufferedFile *file;
32 int ch, tok;
33 CValue tokc;
34 CString tokcstr; /* current parsed string, if any */
35 /* additional informations about token */
36 int tok_flags;
37 int *macro_ptr, *macro_ptr_allocated;
38 int *unget_saved_macro_ptr;
39 int unget_saved_buffer[TOK_MAX_SIZE + 1];
40 int unget_buffer_enabled;
41 int parse_flags;
42 Section *text_section, *data_section, *bss_section; /* predefined sections */
43 Section *cur_text_section; /* current section where function code is
44 generated */
45 #ifdef CONFIG_TCC_ASM
46 Section *last_text_section; /* to handle .previous asm directive */
47 #endif
48 /* bound check related sections */
49 Section *bounds_section; /* contains global data bound description */
50 Section *lbounds_section; /* contains local data bound description */
51 /* symbol sections */
52 Section *symtab_section, *strtab_section;
54 /* debug sections */
55 Section *stab_section, *stabstr_section;
57 /* loc : local variable index
58 ind : output code index
59 rsym: return symbol
60 anon_sym: anonymous symbol index
62 int rsym, anon_sym, ind, loc;
63 /* expression generation modifiers */
64 int const_wanted; /* true if constant wanted */
65 int nocode_wanted; /* true if no code generation wanted for an expression */
66 int global_expr; /* true if compound literals must be allocated
67 globally (used during initializers parsing */
68 CType func_vt; /* current function return type (used by return
69 instruction) */
70 int func_vc;
71 int last_line_num, last_ind, func_ind; /* debug last line number and pc */
72 int tok_ident;
73 TokenSym **table_ident;
74 TokenSym *hash_ident[TOK_HASH_SIZE];
75 char token_buf[STRING_MAX_SIZE + 1];
76 char *funcname;
77 Sym *global_stack, *local_stack;
78 Sym *define_stack;
79 Sym *global_label_stack, *local_label_stack;
80 /* symbol allocator */
81 Sym *sym_free_first;
82 void **sym_pools;
83 int nb_sym_pools;
85 SValue vstack[VSTACK_SIZE], *vtop;
86 /* some predefined types */
87 CType char_pointer_type, func_old_type, int_type;
89 /* use GNU C extensions */
90 int gnu_ext = 1;
92 /* use Tiny C extensions */
93 int tcc_ext = 1;
95 /* max number of callers shown if error */
96 #ifdef CONFIG_TCC_BACKTRACE
97 int num_callers = 6;
98 const char **rt_bound_error_msg;
99 unsigned long rt_prog_main;
100 #endif
102 /* XXX: get rid of this ASAP */
103 struct TCCState *tcc_state;
105 /********************************************************/
107 #ifdef TCC_TARGET_I386
108 //#include "i386-gen.c"
109 #endif
111 #ifdef TCC_TARGET_ARM
112 //#include "arm-gen.c"
113 #endif
115 #ifdef TCC_TARGET_C67
116 //#include "c67-gen.c"
117 #endif
119 #ifdef TCC_TARGET_X86_64
120 //#include "x86_64-gen.c"
121 #endif
123 #ifdef CONFIG_TCC_ASM
125 #ifdef TCC_TARGET_I386
126 //#include "i386-asm.c"
127 #endif
129 #ifdef TCC_TARGET_X86_64
130 //#include "x86_64-asm.c"
131 #endif
133 //#include "tccasm.c"
135 #else
136 void asm_instr(void)
138 error("inline asm() not supported");
140 void asm_global_instr(void)
142 error("inline asm() not supported");
144 #endif
146 /********************************************************/
147 #ifdef _WIN32
148 char *normalize_slashes(char *path)
150 char *p;
151 for (p = path; *p; ++p)
152 if (*p == '\\')
153 *p = '/';
154 return path;
157 HMODULE tcc_module;
159 /* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */
160 void tcc_set_lib_path_w32(TCCState *s)
162 char path[1024], *p;
163 GetModuleFileNameA(tcc_module, path, sizeof path);
164 p = tcc_basename(normalize_slashes(strlwr(path)));
165 if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
166 p -= 5;
167 else if (p > path)
168 p--;
169 *p = 0;
170 tcc_set_lib_path(s, path);
173 #ifdef LIBTCC_AS_DLL
174 BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
176 if (DLL_PROCESS_ATTACH == dwReason)
177 tcc_module = hDll;
178 return TRUE;
180 #endif
181 #endif
183 /********************************************************/
184 /********************************************************/
189 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
191 int len;
192 len = strlen(buf);
193 vsnprintf(buf + len, buf_size - len, fmt, ap);
196 static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
198 va_list ap;
199 va_start(ap, fmt);
200 strcat_vprintf(buf, buf_size, fmt, ap);
201 va_end(ap);
204 void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
206 char buf[2048];
207 BufferedFile **f;
209 buf[0] = '\0';
210 if (file) {
211 for(f = s1->include_stack; f < s1->include_stack_ptr; f++)
212 strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
213 (*f)->filename, (*f)->line_num);
214 if (file->line_num > 0) {
215 strcat_printf(buf, sizeof(buf),
216 "%s:%d: ", file->filename, file->line_num);
217 } else {
218 strcat_printf(buf, sizeof(buf),
219 "%s: ", file->filename);
221 } else {
222 strcat_printf(buf, sizeof(buf),
223 "tcc: ");
225 if (is_warning)
226 strcat_printf(buf, sizeof(buf), "warning: ");
227 else
228 strcat_printf(buf, sizeof(buf), "error: ");
229 strcat_vprintf(buf, sizeof(buf), fmt, ap);
231 if (!s1->error_func) {
232 /* default case: stderr */
233 fprintf(stderr, "%s\n", buf);
234 } else {
235 s1->error_func(s1->error_opaque, buf);
237 if (!is_warning || s1->warn_error)
238 s1->nb_errors++;
241 void tcc_set_error_func(TCCState *s, void *error_opaque,
242 void (*error_func)(void *opaque, const char *msg))
244 s->error_opaque = error_opaque;
245 s->error_func = error_func;
248 /* error without aborting current compilation */
249 void error_noabort(const char *fmt, ...)
251 TCCState *s1 = tcc_state;
252 va_list ap;
254 va_start(ap, fmt);
255 error1(s1, 0, fmt, ap);
256 va_end(ap);
259 void error(const char *fmt, ...)
261 TCCState *s1 = tcc_state;
262 va_list ap;
264 va_start(ap, fmt);
265 error1(s1, 0, fmt, ap);
266 va_end(ap);
267 /* better than nothing: in some cases, we accept to handle errors */
268 if (s1->error_set_jmp_enabled) {
269 longjmp(s1->error_jmp_buf, 1);
270 } else {
271 /* XXX: eliminate this someday */
272 exit(1);
276 void expect(const char *msg)
278 error("%s expected", msg);
281 void warning(const char *fmt, ...)
283 TCCState *s1 = tcc_state;
284 va_list ap;
286 if (s1->warn_none)
287 return;
289 va_start(ap, fmt);
290 error1(s1, 1, fmt, ap);
291 va_end(ap);
294 void skip(int c)
296 if (tok != c)
297 error("'%c' expected", c);
298 next();
301 void test_lvalue(void)
303 if (!(vtop->r & VT_LVAL))
304 expect("lvalue");
308 /* I/O layer */
310 BufferedFile *tcc_open(TCCState *s1, const char *filename)
312 int fd;
313 BufferedFile *bf;
315 if (strcmp(filename, "-") == 0)
316 fd = 0, filename = "stdin";
317 else
318 fd = open(filename, O_RDONLY | O_BINARY);
319 if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
320 printf("%s %*s%s\n", fd < 0 ? "nf":"->",
321 (int)(s1->include_stack_ptr - s1->include_stack), "", filename);
322 if (fd < 0)
323 return NULL;
324 bf = tcc_malloc(sizeof(BufferedFile));
325 bf->fd = fd;
326 bf->buf_ptr = bf->buffer;
327 bf->buf_end = bf->buffer;
328 bf->buffer[0] = CH_EOB; /* put eob symbol */
329 pstrcpy(bf->filename, sizeof(bf->filename), filename);
330 #ifdef _WIN32
331 normalize_slashes(bf->filename);
332 #endif
333 bf->line_num = 1;
334 bf->ifndef_macro = 0;
335 bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
336 // printf("opening '%s'\n", filename);
337 return bf;
340 void tcc_close(BufferedFile *bf)
342 total_lines += bf->line_num;
343 close(bf->fd);
344 tcc_free(bf);
347 /* compile the C file opened in 'file'. Return non zero if errors. */
348 static int tcc_compile(TCCState *s1)
350 Sym *define_start;
351 char buf[512];
352 volatile int section_sym;
354 #ifdef INC_DEBUG
355 printf("%s: **** new file\n", file->filename);
356 #endif
357 preprocess_init(s1);
359 cur_text_section = NULL;
360 funcname = "";
361 anon_sym = SYM_FIRST_ANOM;
363 /* file info: full path + filename */
364 section_sym = 0; /* avoid warning */
365 if (s1->do_debug) {
366 section_sym = put_elf_sym(symtab_section, 0, 0,
367 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
368 text_section->sh_num, NULL);
369 getcwd(buf, sizeof(buf));
370 #ifdef _WIN32
371 normalize_slashes(buf);
372 #endif
373 pstrcat(buf, sizeof(buf), "/");
374 put_stabs_r(buf, N_SO, 0, 0,
375 text_section->data_offset, text_section, section_sym);
376 put_stabs_r(file->filename, N_SO, 0, 0,
377 text_section->data_offset, text_section, section_sym);
379 /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
380 symbols can be safely used */
381 put_elf_sym(symtab_section, 0, 0,
382 ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
383 SHN_ABS, file->filename);
385 /* define some often used types */
386 int_type.t = VT_INT;
388 char_pointer_type.t = VT_BYTE;
389 mk_pointer(&char_pointer_type);
391 func_old_type.t = VT_FUNC;
392 func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
394 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
395 float_type.t = VT_FLOAT;
396 double_type.t = VT_DOUBLE;
398 func_float_type.t = VT_FUNC;
399 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
400 func_double_type.t = VT_FUNC;
401 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
402 #endif
404 #if 0
405 /* define 'void *alloca(unsigned int)' builtin function */
407 Sym *s1;
409 p = anon_sym++;
410 sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
411 s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
412 s1->next = NULL;
413 sym->next = s1;
414 sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
416 #endif
418 define_start = define_stack;
419 nocode_wanted = 1;
421 if (setjmp(s1->error_jmp_buf) == 0) {
422 s1->nb_errors = 0;
423 s1->error_set_jmp_enabled = 1;
425 ch = file->buf_ptr[0];
426 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
427 parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
428 next();
429 decl(VT_CONST);
430 if (tok != TOK_EOF)
431 expect("declaration");
433 /* end of translation unit info */
434 if (s1->do_debug) {
435 put_stabs_r(NULL, N_SO, 0, 0,
436 text_section->data_offset, text_section, section_sym);
439 s1->error_set_jmp_enabled = 0;
441 /* reset define stack, but leave -Dsymbols (may be incorrect if
442 they are undefined) */
443 free_defines(define_start);
445 gen_inline_functions();
447 sym_pop(&global_stack, NULL);
448 sym_pop(&local_stack, NULL);
450 return s1->nb_errors != 0 ? -1 : 0;
453 int tcc_compile_string(TCCState *s, const char *str)
455 BufferedFile bf1, *bf = &bf1;
456 int ret, len;
457 char *buf;
459 /* init file structure */
460 bf->fd = -1;
461 /* XXX: avoid copying */
462 len = strlen(str);
463 buf = tcc_malloc(len + 1);
464 if (!buf)
465 return -1;
466 memcpy(buf, str, len);
467 buf[len] = CH_EOB;
468 bf->buf_ptr = buf;
469 bf->buf_end = buf + len;
470 pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
471 bf->line_num = 1;
472 file = bf;
473 ret = tcc_compile(s);
474 file = NULL;
475 tcc_free(buf);
477 /* currently, no need to close */
478 return ret;
481 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
482 void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
484 BufferedFile bf1, *bf = &bf1;
486 pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
487 pstrcat(bf->buffer, IO_BUF_SIZE, " ");
488 /* default value */
489 if (!value)
490 value = "1";
491 pstrcat(bf->buffer, IO_BUF_SIZE, value);
493 /* init file structure */
494 bf->fd = -1;
495 bf->buf_ptr = bf->buffer;
496 bf->buf_end = bf->buffer + strlen(bf->buffer);
497 *bf->buf_end = CH_EOB;
498 bf->filename[0] = '\0';
499 bf->line_num = 1;
500 file = bf;
502 s1->include_stack_ptr = s1->include_stack;
504 /* parse with define parser */
505 ch = file->buf_ptr[0];
506 next_nomacro();
507 parse_define();
508 file = NULL;
511 /* undefine a preprocessor symbol */
512 void tcc_undefine_symbol(TCCState *s1, const char *sym)
514 TokenSym *ts;
515 Sym *s;
516 ts = tok_alloc(sym, strlen(sym));
517 s = define_find(ts->tok);
518 /* undefine symbol by putting an invalid name */
519 if (s)
520 define_undef(s);
524 #ifdef CONFIG_TCC_BACKTRACE
525 /* print the position in the source file of PC value 'pc' by reading
526 the stabs debug information */
527 unsigned long rt_printline(unsigned long wanted_pc)
529 Stab_Sym *sym, *sym_end;
530 char func_name[128], last_func_name[128];
531 unsigned long func_addr, last_pc, pc;
532 const char *incl_files[INCLUDE_STACK_SIZE];
533 int incl_index, len, last_line_num, i;
534 const char *str, *p;
536 fprintf(stderr, "0x%08lx:", wanted_pc);
538 func_name[0] = '\0';
539 func_addr = 0;
540 incl_index = 0;
541 last_func_name[0] = '\0';
542 last_pc = 0xffffffff;
543 last_line_num = 1;
544 sym = (Stab_Sym *)stab_section->data + 1;
545 sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
546 while (sym < sym_end) {
547 switch(sym->n_type) {
548 /* function start or end */
549 case N_FUN:
550 if (sym->n_strx == 0) {
551 /* we test if between last line and end of function */
552 pc = sym->n_value + func_addr;
553 if (wanted_pc >= last_pc && wanted_pc < pc)
554 goto found;
555 func_name[0] = '\0';
556 func_addr = 0;
557 } else {
558 str = stabstr_section->data + sym->n_strx;
559 p = strchr(str, ':');
560 if (!p) {
561 pstrcpy(func_name, sizeof(func_name), str);
562 } else {
563 len = p - str;
564 if (len > sizeof(func_name) - 1)
565 len = sizeof(func_name) - 1;
566 memcpy(func_name, str, len);
567 func_name[len] = '\0';
569 func_addr = sym->n_value;
571 break;
572 /* line number info */
573 case N_SLINE:
574 pc = sym->n_value + func_addr;
575 if (wanted_pc >= last_pc && wanted_pc < pc)
576 goto found;
577 last_pc = pc;
578 last_line_num = sym->n_desc;
579 /* XXX: slow! */
580 strcpy(last_func_name, func_name);
581 break;
582 /* include files */
583 case N_BINCL:
584 str = stabstr_section->data + sym->n_strx;
585 add_incl:
586 if (incl_index < INCLUDE_STACK_SIZE) {
587 incl_files[incl_index++] = str;
589 break;
590 case N_EINCL:
591 if (incl_index > 1)
592 incl_index--;
593 break;
594 case N_SO:
595 if (sym->n_strx == 0) {
596 incl_index = 0; /* end of translation unit */
597 } else {
598 str = stabstr_section->data + sym->n_strx;
599 /* do not add path */
600 len = strlen(str);
601 if (len > 0 && str[len - 1] != '/')
602 goto add_incl;
604 break;
606 sym++;
609 /* second pass: we try symtab symbols (no line number info) */
610 incl_index = 0;
612 ElfW(Sym) *sym, *sym_end;
613 int type;
615 sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
616 for(sym = (ElfW(Sym) *)symtab_section->data + 1;
617 sym < sym_end;
618 sym++) {
619 type = ELFW(ST_TYPE)(sym->st_info);
620 if (type == STT_FUNC) {
621 if (wanted_pc >= sym->st_value &&
622 wanted_pc < sym->st_value + sym->st_size) {
623 pstrcpy(last_func_name, sizeof(last_func_name),
624 strtab_section->data + sym->st_name);
625 func_addr = sym->st_value;
626 goto found;
631 /* did not find any info: */
632 fprintf(stderr, " ???\n");
633 return 0;
634 found:
635 if (last_func_name[0] != '\0') {
636 fprintf(stderr, " %s()", last_func_name);
638 if (incl_index > 0) {
639 fprintf(stderr, " (%s:%d",
640 incl_files[incl_index - 1], last_line_num);
641 for(i = incl_index - 2; i >= 0; i--)
642 fprintf(stderr, ", included from %s", incl_files[i]);
643 fprintf(stderr, ")");
645 fprintf(stderr, "\n");
646 return func_addr;
649 #endif
651 /* copy code into memory passed in by the caller and do all relocations
652 (needed before using tcc_get_symbol()).
653 returns -1 on error and required size if ptr is NULL */
654 int tcc_relocate(TCCState *s1, void *ptr)
656 Section *s;
657 unsigned long offset, length;
658 uplong mem;
659 int i;
661 if (0 == s1->runtime_added) {
662 s1->runtime_added = 1;
663 s1->nb_errors = 0;
664 #ifdef TCC_TARGET_PE
665 pe_output_file(s1, NULL);
666 #else
667 tcc_add_runtime(s1);
668 relocate_common_syms();
669 tcc_add_linker_symbols(s1);
670 build_got_entries(s1);
671 #endif
672 if (s1->nb_errors)
673 return -1;
676 offset = 0, mem = (uplong)ptr;
677 for(i = 1; i < s1->nb_sections; i++) {
678 s = s1->sections[i];
679 if (0 == (s->sh_flags & SHF_ALLOC))
680 continue;
681 length = s->data_offset;
682 s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
683 offset = (offset + length + 15) & ~15;
686 /* relocate symbols */
687 relocate_syms(s1, 1);
688 if (s1->nb_errors)
689 return -1;
691 #ifndef TCC_TARGET_PE
692 #ifdef TCC_TARGET_X86_64
693 s1->runtime_plt_and_got_offset = 0;
694 s1->runtime_plt_and_got = (char *)(mem + offset);
695 /* double the size of the buffer for got and plt entries
696 XXX: calculate exact size for them? */
697 offset *= 2;
698 #endif
699 #endif
701 if (0 == mem)
702 return offset + 15;
704 /* relocate each section */
705 for(i = 1; i < s1->nb_sections; i++) {
706 s = s1->sections[i];
707 if (s->reloc)
708 relocate_section(s1, s);
711 for(i = 1; i < s1->nb_sections; i++) {
712 s = s1->sections[i];
713 if (0 == (s->sh_flags & SHF_ALLOC))
714 continue;
715 length = s->data_offset;
716 // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
717 ptr = (void*)(uplong)s->sh_addr;
718 if (NULL == s->data || s->sh_type == SHT_NOBITS)
719 memset(ptr, 0, length);
720 else
721 memcpy(ptr, s->data, length);
722 /* mark executable sections as executable in memory */
723 if (s->sh_flags & SHF_EXECINSTR)
724 set_pages_executable(ptr, length);
726 #ifndef TCC_TARGET_PE
727 #ifdef TCC_TARGET_X86_64
728 set_pages_executable(s1->runtime_plt_and_got,
729 s1->runtime_plt_and_got_offset);
730 #endif
731 #endif
732 return 0;
735 /* launch the compiled program with the given arguments */
736 int tcc_run(TCCState *s1, int argc, char **argv)
738 int (*prog_main)(int, char **);
739 void *ptr;
740 int ret;
742 ret = tcc_relocate(s1, NULL);
743 if (ret < 0)
744 return -1;
745 ptr = tcc_malloc(ret);
746 tcc_relocate(s1, ptr);
748 prog_main = tcc_get_symbol_err(s1, "main");
750 if (s1->do_debug) {
751 #ifdef CONFIG_TCC_BACKTRACE
752 handle_cpu_exception();
753 #else
754 error("debug mode not available");
755 #endif
758 #ifdef CONFIG_TCC_BCHECK
759 if (s1->do_bounds_check) {
760 void (*bound_init)(void);
761 void (*bound_exit)(void);
762 /* set error function */
763 rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
764 rt_prog_main = (unsigned long)prog_main;
765 /* XXX: use .init section so that it also work in binary ? */
766 bound_init = tcc_get_symbol_err(s1, "__bound_init");
767 bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
768 bound_init();
769 ret = (*prog_main)(argc, argv);
770 bound_exit();
771 } else
772 #endif
773 ret = (*prog_main)(argc, argv);
774 tcc_free(ptr);
775 return ret;
778 void tcc_memstats(void)
780 #ifdef MEM_DEBUG
781 printf("memory in use: %d\n", mem_cur_size);
782 #endif
785 static void tcc_cleanup(void)
787 int i, n;
789 if (NULL == tcc_state)
790 return;
791 tcc_state = NULL;
793 /* free -D defines */
794 free_defines(NULL);
796 /* free tokens */
797 n = tok_ident - TOK_IDENT;
798 for(i = 0; i < n; i++)
799 tcc_free(table_ident[i]);
800 tcc_free(table_ident);
802 /* free sym_pools */
803 dynarray_reset(&sym_pools, &nb_sym_pools);
804 /* string buffer */
805 cstr_free(&tokcstr);
806 /* reset symbol stack */
807 sym_free_first = NULL;
808 /* cleanup from error/setjmp */
809 macro_ptr = NULL;
812 TCCState *tcc_new(void)
814 TCCState *s;
815 char buffer[100];
816 int a,b,c;
818 tcc_cleanup();
820 s = tcc_mallocz(sizeof(TCCState));
821 if (!s)
822 return NULL;
823 tcc_state = s;
824 #ifdef _WIN32
825 tcc_set_lib_path_w32(s);
826 #else
827 tcc_set_lib_path(s, CONFIG_TCCDIR);
828 #endif
829 s->output_type = TCC_OUTPUT_MEMORY;
830 preprocess_new();
832 /* we add dummy defines for some special macros to speed up tests
833 and to have working defined() */
834 define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
835 define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
836 define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
837 define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
839 /* standard defines */
840 tcc_define_symbol(s, "__STDC__", NULL);
841 tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
842 #if defined(TCC_TARGET_I386)
843 tcc_define_symbol(s, "__i386__", "1");
844 tcc_define_symbol(s, "__i386", "1");
845 tcc_define_symbol(s, "i386", "1");
846 #endif
847 #if defined(TCC_TARGET_X86_64)
848 tcc_define_symbol(s, "__x86_64__", NULL);
849 #endif
850 #if defined(TCC_TARGET_ARM)
851 tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
852 tcc_define_symbol(s, "__arm_elf__", NULL);
853 tcc_define_symbol(s, "__arm_elf", NULL);
854 tcc_define_symbol(s, "arm_elf", NULL);
855 tcc_define_symbol(s, "__arm__", NULL);
856 tcc_define_symbol(s, "__arm", NULL);
857 tcc_define_symbol(s, "arm", NULL);
858 tcc_define_symbol(s, "__APCS_32__", NULL);
859 #endif
860 #ifdef TCC_TARGET_PE
861 tcc_define_symbol(s, "_WIN32", NULL);
862 #ifdef TCC_TARGET_X86_64
863 tcc_define_symbol(s, "_WIN64", NULL);
864 #endif
865 #else
866 tcc_define_symbol(s, "__unix__", "1");
867 tcc_define_symbol(s, "__unix", "1");
868 tcc_define_symbol(s, "unix", "1");
869 #if defined(__FreeBSD__)
870 #define str(s) #s
871 tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__));
872 tcc_define_symbol(s, "__INTEL_COMPILER", "1");
873 #undef str
874 #endif
875 #if defined(__linux)
876 tcc_define_symbol(s, "__linux__", NULL);
877 tcc_define_symbol(s, "__linux", NULL);
878 #endif
879 #endif
880 /* tiny C specific defines */
881 sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c);
882 sprintf(buffer, "%d", a*10000 + b*100 + c);
883 tcc_define_symbol(s, "__TINYC__", buffer);
885 /* tiny C & gcc defines */
886 tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
887 tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
888 #ifdef TCC_TARGET_PE
889 tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
890 #else
891 tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
892 #endif
894 #ifndef TCC_TARGET_PE
895 /* default library paths */
896 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/local/lib");
897 tcc_add_library_path(s, CONFIG_SYSROOT "/usr/lib");
898 tcc_add_library_path(s, CONFIG_SYSROOT "/lib");
899 #endif
901 /* no section zero */
902 dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
904 /* create standard sections */
905 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
906 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
907 bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
909 /* symbols are always generated for linking stage */
910 symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
911 ".strtab",
912 ".hashtab", SHF_PRIVATE);
913 strtab_section = symtab_section->link;
915 /* private symbol table for dynamic symbols */
916 s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
917 ".dynstrtab",
918 ".dynhashtab", SHF_PRIVATE);
919 s->alacarte_link = 1;
921 #ifdef CHAR_IS_UNSIGNED
922 s->char_is_unsigned = 1;
923 #endif
924 #if defined(TCC_TARGET_PE) && 0
925 /* XXX: currently the PE linker is not ready to support that */
926 s->leading_underscore = 1;
927 #endif
929 if (s->section_align == 0)
930 s->section_align = ELF_PAGE_SIZE;
932 #ifdef TCC_TARGET_I386
933 s->seg_size = 32;
934 #endif
935 return s;
938 void tcc_delete(TCCState *s1)
940 int i;
942 tcc_cleanup();
944 /* free all sections */
945 for(i = 1; i < s1->nb_sections; i++)
946 free_section(s1->sections[i]);
947 dynarray_reset(&s1->sections, &s1->nb_sections);
949 for(i = 0; i < s1->nb_priv_sections; i++)
950 free_section(s1->priv_sections[i]);
951 dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
953 /* free any loaded DLLs */
954 for ( i = 0; i < s1->nb_loaded_dlls; i++) {
955 DLLReference *ref = s1->loaded_dlls[i];
956 if ( ref->handle )
957 dlclose(ref->handle);
960 /* free loaded dlls array */
961 dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
963 /* free library paths */
964 dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
966 /* free include paths */
967 dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
968 dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
969 dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
971 tcc_free(s1->tcc_lib_path);
972 tcc_free(s1);
975 int tcc_add_include_path(TCCState *s1, const char *pathname)
977 char *pathname1;
979 pathname1 = tcc_strdup(pathname);
980 dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1);
981 return 0;
984 int tcc_add_sysinclude_path(TCCState *s1, const char *pathname)
986 char *pathname1;
988 pathname1 = tcc_strdup(pathname);
989 dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1);
990 return 0;
993 static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
995 const char *ext;
996 ElfW(Ehdr) ehdr;
997 int fd, ret, size;
998 BufferedFile *saved_file;
1000 ret = -1;
1002 /* find source file type with extension */
1003 ext = tcc_fileextension(filename);
1004 if (ext[0])
1005 ext++;
1007 /* open the file */
1008 saved_file = file;
1009 file = tcc_open(s1, filename);
1010 if (!file) {
1011 if (flags & AFF_PRINT_ERROR)
1012 error_noabort("file '%s' not found", filename);
1013 goto the_end;
1016 if (flags & AFF_PREPROCESS) {
1017 ret = tcc_preprocess(s1);
1018 goto the_end;
1021 if (!ext[0] || !PATHCMP(ext, "c")) {
1022 /* C file assumed */
1023 ret = tcc_compile(s1);
1024 goto the_end;
1027 #ifdef CONFIG_TCC_ASM
1028 if (!strcmp(ext, "S")) {
1029 /* preprocessed assembler */
1030 ret = tcc_assemble(s1, 1);
1031 goto the_end;
1034 if (!strcmp(ext, "s")) {
1035 /* non preprocessed assembler */
1036 ret = tcc_assemble(s1, 0);
1037 goto the_end;
1039 #endif
1041 fd = file->fd;
1042 /* assume executable format: auto guess file type */
1043 size = read(fd, &ehdr, sizeof(ehdr));
1044 lseek(fd, 0, SEEK_SET);
1045 if (size <= 0) {
1046 error_noabort("could not read header");
1047 goto the_end;
1050 if (size == sizeof(ehdr) &&
1051 ehdr.e_ident[0] == ELFMAG0 &&
1052 ehdr.e_ident[1] == ELFMAG1 &&
1053 ehdr.e_ident[2] == ELFMAG2 &&
1054 ehdr.e_ident[3] == ELFMAG3) {
1056 /* do not display line number if error */
1057 file->line_num = 0;
1058 if (ehdr.e_type == ET_REL) {
1059 ret = tcc_load_object_file(s1, fd, 0);
1060 goto the_end;
1063 #ifndef TCC_TARGET_PE
1064 if (ehdr.e_type == ET_DYN) {
1065 if (s1->output_type == TCC_OUTPUT_MEMORY) {
1066 void *h;
1067 h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
1068 if (h)
1069 ret = 0;
1070 } else {
1071 ret = tcc_load_dll(s1, fd, filename,
1072 (flags & AFF_REFERENCED_DLL) != 0);
1074 goto the_end;
1076 #endif
1077 error_noabort("unrecognized ELF file");
1078 goto the_end;
1081 if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
1082 file->line_num = 0; /* do not display line number if error */
1083 ret = tcc_load_archive(s1, fd);
1084 goto the_end;
1087 #ifdef TCC_TARGET_COFF
1088 if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
1089 ret = tcc_load_coff(s1, fd);
1090 goto the_end;
1092 #endif
1094 #ifdef TCC_TARGET_PE
1095 ret = pe_load_file(s1, filename, fd);
1096 #else
1097 /* as GNU ld, consider it is an ld script if not recognized */
1098 ret = tcc_load_ldscript(s1);
1099 #endif
1100 if (ret < 0)
1101 error_noabort("unrecognized file type");
1103 the_end:
1104 if (file)
1105 tcc_close(file);
1106 file = saved_file;
1107 return ret;
1110 int tcc_add_file(TCCState *s, const char *filename)
1112 if (s->output_type == TCC_OUTPUT_PREPROCESS)
1113 return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS);
1114 else
1115 return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR);
1118 int tcc_add_library_path(TCCState *s, const char *pathname)
1120 char *pathname1;
1122 pathname1 = tcc_strdup(pathname);
1123 dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1);
1124 return 0;
1127 /* find and load a dll. Return non zero if not found */
1128 /* XXX: add '-rpath' option support ? */
1129 int tcc_add_dll(TCCState *s, const char *filename, int flags)
1131 char buf[1024];
1132 int i;
1134 for(i = 0; i < s->nb_library_paths; i++) {
1135 snprintf(buf, sizeof(buf), "%s/%s",
1136 s->library_paths[i], filename);
1137 if (tcc_add_file_internal(s, buf, flags) == 0)
1138 return 0;
1140 return -1;
1143 /* the library name is the same as the argument of the '-l' option */
1144 int tcc_add_library(TCCState *s, const char *libraryname)
1146 char buf[1024];
1147 int i;
1149 /* first we look for the dynamic library if not static linking */
1150 if (!s->static_link) {
1151 #ifdef TCC_TARGET_PE
1152 if (pe_add_dll(s, libraryname) == 0)
1153 return 0;
1154 #else
1155 snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
1156 if (tcc_add_dll(s, buf, 0) == 0)
1157 return 0;
1158 #endif
1160 /* then we look for the static library */
1161 for(i = 0; i < s->nb_library_paths; i++) {
1162 snprintf(buf, sizeof(buf), "%s/lib%s.a",
1163 s->library_paths[i], libraryname);
1164 if (tcc_add_file_internal(s, buf, 0) == 0)
1165 return 0;
1167 return -1;
1170 int tcc_add_symbol(TCCState *s, const char *name, void *val)
1172 add_elf_sym(symtab_section, (uplong)val, 0,
1173 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1174 SHN_ABS, name);
1175 return 0;
1178 int tcc_set_output_type(TCCState *s, int output_type)
1180 char buf[1024];
1182 s->output_type = output_type;
1184 if (!s->nostdinc) {
1185 /* default include paths */
1186 /* XXX: reverse order needed if -isystem support */
1187 #ifndef TCC_TARGET_PE
1188 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/local/include");
1189 tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/include");
1190 #endif
1191 snprintf(buf, sizeof(buf), "%s/include", s->tcc_lib_path);
1192 tcc_add_sysinclude_path(s, buf);
1193 #ifdef TCC_TARGET_PE
1194 snprintf(buf, sizeof(buf), "%s/include/winapi", s->tcc_lib_path);
1195 tcc_add_sysinclude_path(s, buf);
1196 #endif
1199 /* if bound checking, then add corresponding sections */
1200 #ifdef CONFIG_TCC_BCHECK
1201 if (s->do_bounds_check) {
1202 /* define symbol */
1203 tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
1204 /* create bounds sections */
1205 bounds_section = new_section(s, ".bounds",
1206 SHT_PROGBITS, SHF_ALLOC);
1207 lbounds_section = new_section(s, ".lbounds",
1208 SHT_PROGBITS, SHF_ALLOC);
1210 #endif
1212 if (s->char_is_unsigned) {
1213 tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
1216 /* add debug sections */
1217 if (s->do_debug) {
1218 /* stab symbols */
1219 stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
1220 stab_section->sh_entsize = sizeof(Stab_Sym);
1221 stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
1222 put_elf_str(stabstr_section, "");
1223 stab_section->link = stabstr_section;
1224 /* put first entry */
1225 put_stabs("", 0, 0, 0, 0);
1228 /* add libc crt1/crti objects */
1229 #ifndef TCC_TARGET_PE
1230 if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
1231 !s->nostdlib) {
1232 if (output_type != TCC_OUTPUT_DLL)
1233 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
1234 tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
1236 #endif
1238 #ifdef TCC_TARGET_PE
1239 snprintf(buf, sizeof(buf), "%s/lib", s->tcc_lib_path);
1240 tcc_add_library_path(s, buf);
1241 #ifdef _WIN32
1242 if (GetSystemDirectory(buf, sizeof buf))
1243 tcc_add_library_path(s, buf);
1244 #endif
1245 #endif
1247 return 0;
1250 #define WD_ALL 0x0001 /* warning is activated when using -Wall */
1251 #define FD_INVERT 0x0002 /* invert value before storing */
1253 typedef struct FlagDef {
1254 uint16_t offset;
1255 uint16_t flags;
1256 const char *name;
1257 } FlagDef;
1259 static const FlagDef warning_defs[] = {
1260 { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
1261 { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
1262 { offsetof(TCCState, warn_error), 0, "error" },
1263 { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
1264 "implicit-function-declaration" },
1267 static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
1268 const char *name, int value)
1270 int i;
1271 const FlagDef *p;
1272 const char *r;
1274 r = name;
1275 if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
1276 r += 3;
1277 value = !value;
1279 for(i = 0, p = flags; i < nb_flags; i++, p++) {
1280 if (!strcmp(r, p->name))
1281 goto found;
1283 return -1;
1284 found:
1285 if (p->flags & FD_INVERT)
1286 value = !value;
1287 *(int *)((uint8_t *)s + p->offset) = value;
1288 return 0;
1292 /* set/reset a warning */
1293 int tcc_set_warning(TCCState *s, const char *warning_name, int value)
1295 int i;
1296 const FlagDef *p;
1298 if (!strcmp(warning_name, "all")) {
1299 for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
1300 if (p->flags & WD_ALL)
1301 *(int *)((uint8_t *)s + p->offset) = 1;
1303 return 0;
1304 } else {
1305 return set_flag(s, warning_defs, countof(warning_defs),
1306 warning_name, value);
1310 static const FlagDef flag_defs[] = {
1311 { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
1312 { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
1313 { offsetof(TCCState, nocommon), FD_INVERT, "common" },
1314 { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
1317 /* set/reset a flag */
1318 int tcc_set_flag(TCCState *s, const char *flag_name, int value)
1320 return set_flag(s, flag_defs, countof(flag_defs),
1321 flag_name, value);
1324 /* set CONFIG_TCCDIR at runtime */
1325 void tcc_set_lib_path(TCCState *s, const char *path)
1327 tcc_free(s->tcc_lib_path);
1328 s->tcc_lib_path = tcc_strdup(path);
1331 void tcc_print_stats(TCCState *s, int64_t total_time)
1333 double tt;
1334 tt = (double)total_time / 1000000.0;
1335 if (tt < 0.001)
1336 tt = 0.001;
1337 if (total_bytes < 1)
1338 total_bytes = 1;
1339 printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n",
1340 tok_ident - TOK_IDENT, total_lines, total_bytes,
1341 tt, (int)(total_lines / tt),
1342 total_bytes / tt / 1000000.0);
1346 void tcc_set_options(TCCState *s, int argc, char **argv)
1348 TCCConfig config;
1349 init_tcc_config(&config);
1350 parse_args(&config, s, argc, argv);
1351 /* The config structure is ignored. It has no effect in library mode. */