2 * TCC - Tiny C Compiler
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
23 #ifdef TCC_TARGET_I386
35 #ifdef TCC_TARGET_X86_64
36 #include "x86_64-gen.c"
39 #ifdef CONFIG_TCC_STATIC
41 #define RTLD_LAZY 0x001
42 #define RTLD_NOW 0x002
43 #define RTLD_GLOBAL 0x100
44 #define RTLD_DEFAULT NULL
46 /* dummy function for profiling */
47 void *dlopen(const char *filename
, int flag
)
56 const char *dlerror(void)
61 typedef struct TCCSyms
{
66 #define TCCSYM(a) { #a, &a, },
68 /* add the symbol you want here if no dynamic linking is done */
69 static TCCSyms tcc_syms
[] = {
70 #if !defined(CONFIG_TCCBOOT)
79 void *resolve_sym(TCCState
*s1
, const char *symbol
, int type
)
83 while (p
->str
!= NULL
) {
84 if (!strcmp(p
->str
, symbol
))
91 #elif !defined(_WIN32)
95 void *resolve_sym(TCCState
*s1
, const char *sym
, int type
)
97 return dlsym(RTLD_DEFAULT
, sym
);
102 /********************************************************/
104 /* we use our own 'finite' function to avoid potential problems with
105 non standard math libs */
106 /* XXX: endianness dependent */
107 int ieee_finite(double d
)
110 return ((unsigned)((p
[1] | 0x800fffff) + 1)) >> 31;
113 /* copy a string and truncate it. */
114 static char *pstrcpy(char *buf
, int buf_size
, const char *s
)
121 q_end
= buf
+ buf_size
- 1;
133 /* strcat and truncate. */
134 static char *pstrcat(char *buf
, int buf_size
, const char *s
)
139 pstrcpy(buf
+ len
, buf_size
- len
, s
);
144 static int strstart(const char *str
, const char *val
, const char **ptr
)
162 #define IS_PATHSEP(c) (c == '/' || c == '\\')
163 #define IS_ABSPATH(p) (IS_PATHSEP(p[0]) || (p[0] && p[1] == ':' && IS_PATHSEP(p[2])))
164 #define PATHCMP stricmp
166 #define IS_PATHSEP(c) (c == '/')
167 #define IS_ABSPATH(p) IS_PATHSEP(p[0])
168 #define PATHCMP strcmp
171 /* extract the basename of a file */
172 static char *tcc_basename(const char *name
)
174 char *p
= strchr(name
, 0);
175 while (p
> name
&& !IS_PATHSEP(p
[-1]))
180 static char *tcc_fileextension (const char *name
)
182 char *b
= tcc_basename(name
);
183 char *e
= strrchr(b
, '.');
184 return e
? e
: strchr(b
, 0);
188 char *normalize_slashes(char *path
)
191 for (p
= path
; *p
; ++p
)
197 void tcc_set_lib_path_w32(TCCState
*s
)
199 /* on win32, we suppose the lib and includes are at the location
202 GetModuleFileNameA(NULL
, path
, sizeof path
);
203 p
= tcc_basename(normalize_slashes(strlwr(path
)));
204 if (p
- 5 > path
&& 0 == strncmp(p
- 5, "/bin/", 5))
209 tcc_set_lib_path(s
, path
);
213 void set_pages_executable(void *ptr
, unsigned long length
)
216 unsigned long old_protect
;
217 VirtualProtect(ptr
, length
, PAGE_EXECUTE_READWRITE
, &old_protect
);
219 unsigned long start
, end
;
220 start
= (unsigned long)ptr
& ~(PAGESIZE
- 1);
221 end
= (unsigned long)ptr
+ length
;
222 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
223 mprotect((void *)start
, end
- start
, PROT_READ
| PROT_WRITE
| PROT_EXEC
);
227 /* memory management */
231 unsigned malloc_usable_size(void*);
234 static inline void tcc_free(void *ptr
)
237 mem_cur_size
-= malloc_usable_size(ptr
);
242 static void *tcc_malloc(unsigned long size
)
247 error("memory full");
249 mem_cur_size
+= malloc_usable_size(ptr
);
250 if (mem_cur_size
> mem_max_size
)
251 mem_max_size
= mem_cur_size
;
256 static void *tcc_mallocz(unsigned long size
)
259 ptr
= tcc_malloc(size
);
260 memset(ptr
, 0, size
);
264 static inline void *tcc_realloc(void *ptr
, unsigned long size
)
268 mem_cur_size
-= malloc_usable_size(ptr
);
270 ptr1
= realloc(ptr
, size
);
272 /* NOTE: count not correct if alloc error, but not critical */
273 mem_cur_size
+= malloc_usable_size(ptr1
);
274 if (mem_cur_size
> mem_max_size
)
275 mem_max_size
= mem_cur_size
;
280 static char *tcc_strdup(const char *str
)
283 ptr
= tcc_malloc(strlen(str
) + 1);
288 #define free(p) use_tcc_free(p)
289 #define malloc(s) use_tcc_malloc(s)
290 #define realloc(p, s) use_tcc_realloc(p, s)
292 static void dynarray_add(void ***ptab
, int *nb_ptr
, void *data
)
299 /* every power of two we double array size */
300 if ((nb
& (nb
- 1)) == 0) {
305 pp
= tcc_realloc(pp
, nb_alloc
* sizeof(void *));
307 error("memory full");
314 static void dynarray_reset(void *pp
, int *n
)
317 for (p
= *(void***)pp
; *n
; ++p
, --*n
)
320 tcc_free(*(void**)pp
);
324 /* symbol allocator */
325 static Sym
*__sym_malloc(void)
327 Sym
*sym_pool
, *sym
, *last_sym
;
330 sym_pool
= tcc_malloc(SYM_POOL_NB
* sizeof(Sym
));
331 dynarray_add(&sym_pools
, &nb_sym_pools
, sym_pool
);
333 last_sym
= sym_free_first
;
335 for(i
= 0; i
< SYM_POOL_NB
; i
++) {
336 sym
->next
= last_sym
;
340 sym_free_first
= last_sym
;
344 static inline Sym
*sym_malloc(void)
347 sym
= sym_free_first
;
349 sym
= __sym_malloc();
350 sym_free_first
= sym
->next
;
354 static inline void sym_free(Sym
*sym
)
356 sym
->next
= sym_free_first
;
357 sym_free_first
= sym
;
360 Section
*new_section(TCCState
*s1
, const char *name
, int sh_type
, int sh_flags
)
364 sec
= tcc_mallocz(sizeof(Section
) + strlen(name
));
365 strcpy(sec
->name
, name
);
366 sec
->sh_type
= sh_type
;
367 sec
->sh_flags
= sh_flags
;
375 sec
->sh_addralign
= 4;
378 sec
->sh_addralign
= 1;
381 sec
->sh_addralign
= 32; /* default conservative alignment */
385 if (sh_flags
& SHF_PRIVATE
) {
386 dynarray_add((void ***)&s1
->priv_sections
, &s1
->nb_priv_sections
, sec
);
388 sec
->sh_num
= s1
->nb_sections
;
389 dynarray_add((void ***)&s1
->sections
, &s1
->nb_sections
, sec
);
395 static void free_section(Section
*s
)
400 /* realloc section and set its content to zero */
401 static void section_realloc(Section
*sec
, unsigned long new_size
)
406 size
= sec
->data_allocated
;
409 while (size
< new_size
)
411 data
= tcc_realloc(sec
->data
, size
);
413 error("memory full");
414 memset(data
+ sec
->data_allocated
, 0, size
- sec
->data_allocated
);
416 sec
->data_allocated
= size
;
419 /* reserve at least 'size' bytes in section 'sec' from
421 static void *section_ptr_add(Section
*sec
, unsigned long size
)
423 unsigned long offset
, offset1
;
425 offset
= sec
->data_offset
;
426 offset1
= offset
+ size
;
427 if (offset1
> sec
->data_allocated
)
428 section_realloc(sec
, offset1
);
429 sec
->data_offset
= offset1
;
430 return sec
->data
+ offset
;
433 /* return a reference to a section, and create it if it does not
435 Section
*find_section(TCCState
*s1
, const char *name
)
439 for(i
= 1; i
< s1
->nb_sections
; i
++) {
440 sec
= s1
->sections
[i
];
441 if (!strcmp(name
, sec
->name
))
444 /* sections are created as PROGBITS */
445 return new_section(s1
, name
, SHT_PROGBITS
, SHF_ALLOC
);
448 #define SECTION_ABS ((void *)1)
450 /* update sym->c so that it points to an external symbol in section
451 'section' with value 'value' */
452 static void put_extern_sym2(Sym
*sym
, Section
*section
,
453 unsigned long value
, unsigned long size
,
454 int can_add_underscore
)
456 int sym_type
, sym_bind
, sh_num
, info
, other
, attr
;
463 else if (section
== SECTION_ABS
)
466 sh_num
= section
->sh_num
;
470 if ((sym
->type
.t
& VT_BTYPE
) == VT_FUNC
) {
474 attr
= sym
->type
.ref
->r
;
475 if (FUNC_EXPORT(attr
))
477 if (FUNC_CALL(attr
) == FUNC_STDCALL
)
481 sym_type
= STT_OBJECT
;
484 if (sym
->type
.t
& VT_STATIC
)
485 sym_bind
= STB_LOCAL
;
487 sym_bind
= STB_GLOBAL
;
490 name
= get_tok_str(sym
->v
, NULL
);
491 #ifdef CONFIG_TCC_BCHECK
492 if (do_bounds_check
) {
495 /* XXX: avoid doing that for statics ? */
496 /* if bound checking is activated, we change some function
497 names by adding the "__bound" prefix */
500 /* XXX: we rely only on malloc hooks */
513 strcpy(buf
, "__bound_");
522 if ((other
& 2) && can_add_underscore
) {
523 sprintf(buf1
, "_%s@%d", name
, FUNC_ARGS(attr
));
527 if (tcc_state
->leading_underscore
&& can_add_underscore
) {
529 pstrcpy(buf1
+ 1, sizeof(buf1
) - 1, name
);
532 info
= ELFW(ST_INFO
)(sym_bind
, sym_type
);
533 sym
->c
= add_elf_sym(symtab_section
, value
, size
, info
, other
, sh_num
, name
);
535 esym
= &((ElfW(Sym
) *)symtab_section
->data
)[sym
->c
];
536 esym
->st_value
= value
;
537 esym
->st_size
= size
;
538 esym
->st_shndx
= sh_num
;
539 esym
->st_other
|= other
;
543 static void put_extern_sym(Sym
*sym
, Section
*section
,
544 unsigned long value
, unsigned long size
)
546 put_extern_sym2(sym
, section
, value
, size
, 1);
549 /* add a new relocation entry to symbol 'sym' in section 's' */
550 static void greloc(Section
*s
, Sym
*sym
, unsigned long offset
, int type
)
553 put_extern_sym(sym
, NULL
, 0, 0);
554 /* now we can add ELF relocation info */
555 put_elf_reloc(symtab_section
, s
, offset
, type
, sym
->c
);
558 static inline int isid(int c
)
560 return (c
>= 'a' && c
<= 'z') ||
561 (c
>= 'A' && c
<= 'Z') ||
565 static inline int isnum(int c
)
567 return c
>= '0' && c
<= '9';
570 static inline int isoct(int c
)
572 return c
>= '0' && c
<= '7';
575 static inline int toup(int c
)
577 if (c
>= 'a' && c
<= 'z')
578 return c
- 'a' + 'A';
583 static void strcat_vprintf(char *buf
, int buf_size
, const char *fmt
, va_list ap
)
587 vsnprintf(buf
+ len
, buf_size
- len
, fmt
, ap
);
590 static void strcat_printf(char *buf
, int buf_size
, const char *fmt
, ...)
594 strcat_vprintf(buf
, buf_size
, fmt
, ap
);
598 void error1(TCCState
*s1
, int is_warning
, const char *fmt
, va_list ap
)
605 for(f
= s1
->include_stack
; f
< s1
->include_stack_ptr
; f
++)
606 strcat_printf(buf
, sizeof(buf
), "In file included from %s:%d:\n",
607 (*f
)->filename
, (*f
)->line_num
);
608 if (file
->line_num
> 0) {
609 strcat_printf(buf
, sizeof(buf
),
610 "%s:%d: ", file
->filename
, file
->line_num
);
612 strcat_printf(buf
, sizeof(buf
),
613 "%s: ", file
->filename
);
616 strcat_printf(buf
, sizeof(buf
),
620 strcat_printf(buf
, sizeof(buf
), "warning: ");
621 strcat_vprintf(buf
, sizeof(buf
), fmt
, ap
);
623 if (!s1
->error_func
) {
624 /* default case: stderr */
625 fprintf(stderr
, "%s\n", buf
);
627 s1
->error_func(s1
->error_opaque
, buf
);
629 if (!is_warning
|| s1
->warn_error
)
634 void tcc_set_error_func(TCCState
*s
, void *error_opaque
,
635 void (*error_func
)(void *opaque
, const char *msg
))
637 s
->error_opaque
= error_opaque
;
638 s
->error_func
= error_func
;
642 /* error without aborting current compilation */
643 void error_noabort(const char *fmt
, ...)
645 TCCState
*s1
= tcc_state
;
649 error1(s1
, 0, fmt
, ap
);
653 void error(const char *fmt
, ...)
655 TCCState
*s1
= tcc_state
;
659 error1(s1
, 0, fmt
, ap
);
661 /* better than nothing: in some cases, we accept to handle errors */
662 if (s1
->error_set_jmp_enabled
) {
663 longjmp(s1
->error_jmp_buf
, 1);
665 /* XXX: eliminate this someday */
670 void expect(const char *msg
)
672 error("%s expected", msg
);
675 void warning(const char *fmt
, ...)
677 TCCState
*s1
= tcc_state
;
684 error1(s1
, 1, fmt
, ap
);
691 error("'%c' expected", c
);
695 static void test_lvalue(void)
697 if (!(vtop
->r
& VT_LVAL
))
701 /* allocate a new token */
702 static TokenSym
*tok_alloc_new(TokenSym
**pts
, const char *str
, int len
)
704 TokenSym
*ts
, **ptable
;
707 if (tok_ident
>= SYM_FIRST_ANOM
)
708 error("memory full");
710 /* expand token table if needed */
711 i
= tok_ident
- TOK_IDENT
;
712 if ((i
% TOK_ALLOC_INCR
) == 0) {
713 ptable
= tcc_realloc(table_ident
, (i
+ TOK_ALLOC_INCR
) * sizeof(TokenSym
*));
715 error("memory full");
716 table_ident
= ptable
;
719 ts
= tcc_malloc(sizeof(TokenSym
) + len
);
721 ts
->tok
= tok_ident
++;
722 ts
->sym_define
= NULL
;
723 ts
->sym_label
= NULL
;
724 ts
->sym_struct
= NULL
;
725 ts
->sym_identifier
= NULL
;
727 ts
->hash_next
= NULL
;
728 memcpy(ts
->str
, str
, len
);
734 #define TOK_HASH_INIT 1
735 #define TOK_HASH_FUNC(h, c) ((h) * 263 + (c))
737 /* find a token and add it if not found */
738 static TokenSym
*tok_alloc(const char *str
, int len
)
746 h
= TOK_HASH_FUNC(h
, ((unsigned char *)str
)[i
]);
747 h
&= (TOK_HASH_SIZE
- 1);
749 pts
= &hash_ident
[h
];
754 if (ts
->len
== len
&& !memcmp(ts
->str
, str
, len
))
756 pts
= &(ts
->hash_next
);
758 return tok_alloc_new(pts
, str
, len
);
761 /* CString handling */
763 static void cstr_realloc(CString
*cstr
, int new_size
)
768 size
= cstr
->size_allocated
;
770 size
= 8; /* no need to allocate a too small first string */
771 while (size
< new_size
)
773 data
= tcc_realloc(cstr
->data_allocated
, size
);
775 error("memory full");
776 cstr
->data_allocated
= data
;
777 cstr
->size_allocated
= size
;
782 static inline void cstr_ccat(CString
*cstr
, int ch
)
785 size
= cstr
->size
+ 1;
786 if (size
> cstr
->size_allocated
)
787 cstr_realloc(cstr
, size
);
788 ((unsigned char *)cstr
->data
)[size
- 1] = ch
;
792 static void cstr_cat(CString
*cstr
, const char *str
)
804 /* add a wide char */
805 static void cstr_wccat(CString
*cstr
, int ch
)
808 size
= cstr
->size
+ sizeof(nwchar_t
);
809 if (size
> cstr
->size_allocated
)
810 cstr_realloc(cstr
, size
);
811 *(nwchar_t
*)(((unsigned char *)cstr
->data
) + size
- sizeof(nwchar_t
)) = ch
;
815 static void cstr_new(CString
*cstr
)
817 memset(cstr
, 0, sizeof(CString
));
820 /* free string and reset it to NULL */
821 static void cstr_free(CString
*cstr
)
823 tcc_free(cstr
->data_allocated
);
827 #define cstr_reset(cstr) cstr_free(cstr)
830 static void add_char(CString
*cstr
, int c
)
832 if (c
== '\'' || c
== '\"' || c
== '\\') {
833 /* XXX: could be more precise if char or string */
834 cstr_ccat(cstr
, '\\');
836 if (c
>= 32 && c
<= 126) {
839 cstr_ccat(cstr
, '\\');
841 cstr_ccat(cstr
, 'n');
843 cstr_ccat(cstr
, '0' + ((c
>> 6) & 7));
844 cstr_ccat(cstr
, '0' + ((c
>> 3) & 7));
845 cstr_ccat(cstr
, '0' + (c
& 7));
850 /* XXX: buffer overflow */
851 /* XXX: float tokens */
852 char *get_tok_str(int v
, CValue
*cv
)
854 static char buf
[STRING_MAX_SIZE
+ 1];
855 static CString cstr_buf
;
861 /* NOTE: to go faster, we give a fixed buffer for small strings */
862 cstr_reset(&cstr_buf
);
864 cstr_buf
.size_allocated
= sizeof(buf
);
870 /* XXX: not quite exact, but only useful for testing */
871 sprintf(p
, "%u", cv
->ui
);
875 /* XXX: not quite exact, but only useful for testing */
876 sprintf(p
, "%Lu", cv
->ull
);
879 cstr_ccat(&cstr_buf
, 'L');
881 cstr_ccat(&cstr_buf
, '\'');
882 add_char(&cstr_buf
, cv
->i
);
883 cstr_ccat(&cstr_buf
, '\'');
884 cstr_ccat(&cstr_buf
, '\0');
888 len
= cstr
->size
- 1;
890 add_char(&cstr_buf
, ((unsigned char *)cstr
->data
)[i
]);
891 cstr_ccat(&cstr_buf
, '\0');
894 cstr_ccat(&cstr_buf
, 'L');
897 cstr_ccat(&cstr_buf
, '\"');
899 len
= cstr
->size
- 1;
901 add_char(&cstr_buf
, ((unsigned char *)cstr
->data
)[i
]);
903 len
= (cstr
->size
/ sizeof(nwchar_t
)) - 1;
905 add_char(&cstr_buf
, ((nwchar_t
*)cstr
->data
)[i
]);
907 cstr_ccat(&cstr_buf
, '\"');
908 cstr_ccat(&cstr_buf
, '\0');
917 return strcpy(p
, "...");
919 return strcpy(p
, "<<=");
921 return strcpy(p
, ">>=");
924 /* search in two bytes table */
938 } else if (v
< tok_ident
) {
939 return table_ident
[v
- TOK_IDENT
]->str
;
940 } else if (v
>= SYM_FIRST_ANOM
) {
941 /* special name for anonymous symbol */
942 sprintf(p
, "L.%u", v
- SYM_FIRST_ANOM
);
944 /* should never happen */
949 return cstr_buf
.data
;
952 /* push, without hashing */
953 static Sym
*sym_push2(Sym
**ps
, int v
, int t
, long c
)
967 /* find a symbol and return its associated structure. 's' is the top
968 of the symbol stack */
969 static Sym
*sym_find2(Sym
*s
, int v
)
979 /* structure lookup */
980 static inline Sym
*struct_find(int v
)
983 if ((unsigned)v
>= (unsigned)(tok_ident
- TOK_IDENT
))
985 return table_ident
[v
]->sym_struct
;
988 /* find an identifier */
989 static inline Sym
*sym_find(int v
)
992 if ((unsigned)v
>= (unsigned)(tok_ident
- TOK_IDENT
))
994 return table_ident
[v
]->sym_identifier
;
997 /* push a given symbol on the symbol stack */
998 static Sym
*sym_push(int v
, CType
*type
, int r
, int c
)
1007 s
= sym_push2(ps
, v
, type
->t
, c
);
1008 s
->type
.ref
= type
->ref
;
1010 /* don't record fields or anonymous symbols */
1012 if (!(v
& SYM_FIELD
) && (v
& ~SYM_STRUCT
) < SYM_FIRST_ANOM
) {
1013 /* record symbol in token array */
1014 ts
= table_ident
[(v
& ~SYM_STRUCT
) - TOK_IDENT
];
1016 ps
= &ts
->sym_struct
;
1018 ps
= &ts
->sym_identifier
;
1025 /* push a global identifier */
1026 static Sym
*global_identifier_push(int v
, int t
, int c
)
1029 s
= sym_push2(&global_stack
, v
, t
, c
);
1030 /* don't record anonymous symbol */
1031 if (v
< SYM_FIRST_ANOM
) {
1032 ps
= &table_ident
[v
- TOK_IDENT
]->sym_identifier
;
1033 /* modify the top most local identifier, so that
1034 sym_identifier will point to 's' when popped */
1036 ps
= &(*ps
)->prev_tok
;
1043 /* pop symbols until top reaches 'b' */
1044 static void sym_pop(Sym
**ptop
, Sym
*b
)
1054 /* remove symbol in token array */
1056 if (!(v
& SYM_FIELD
) && (v
& ~SYM_STRUCT
) < SYM_FIRST_ANOM
) {
1057 ts
= table_ident
[(v
& ~SYM_STRUCT
) - TOK_IDENT
];
1059 ps
= &ts
->sym_struct
;
1061 ps
= &ts
->sym_identifier
;
1072 BufferedFile
*tcc_open(TCCState
*s1
, const char *filename
)
1077 if (strcmp(filename
, "-") == 0)
1078 fd
= 0, filename
= "stdin";
1080 fd
= open(filename
, O_RDONLY
| O_BINARY
);
1081 if ((verbose
== 2 && fd
>= 0) || verbose
== 3)
1082 printf("%s %*s%s\n", fd
< 0 ? "nf":"->",
1083 (s1
->include_stack_ptr
- s1
->include_stack
), "", filename
);
1086 bf
= tcc_malloc(sizeof(BufferedFile
));
1088 bf
->buf_ptr
= bf
->buffer
;
1089 bf
->buf_end
= bf
->buffer
;
1090 bf
->buffer
[0] = CH_EOB
; /* put eob symbol */
1091 pstrcpy(bf
->filename
, sizeof(bf
->filename
), filename
);
1093 normalize_slashes(bf
->filename
);
1096 bf
->ifndef_macro
= 0;
1097 bf
->ifdef_stack_ptr
= s1
->ifdef_stack_ptr
;
1098 // printf("opening '%s'\n", filename);
1102 void tcc_close(BufferedFile
*bf
)
1104 total_lines
+= bf
->line_num
;
1112 /* better than nothing, but needs extension to handle '-E' option
1114 static void preprocess_init(TCCState
*s1
)
1116 s1
->include_stack_ptr
= s1
->include_stack
;
1117 /* XXX: move that before to avoid having to initialize
1118 file->ifdef_stack_ptr ? */
1119 s1
->ifdef_stack_ptr
= s1
->ifdef_stack
;
1120 file
->ifdef_stack_ptr
= s1
->ifdef_stack_ptr
;
1122 /* XXX: not ANSI compliant: bound checking says error */
1124 s1
->pack_stack
[0] = 0;
1125 s1
->pack_stack_ptr
= s1
->pack_stack
;
1128 /* compile the C file opened in 'file'. Return non zero if errors. */
1129 static int tcc_compile(TCCState
*s1
)
1133 volatile int section_sym
;
1136 printf("%s: **** new file\n", file
->filename
);
1138 preprocess_init(s1
);
1140 cur_text_section
= NULL
;
1142 anon_sym
= SYM_FIRST_ANOM
;
1144 /* file info: full path + filename */
1145 section_sym
= 0; /* avoid warning */
1147 section_sym
= put_elf_sym(symtab_section
, 0, 0,
1148 ELFW(ST_INFO
)(STB_LOCAL
, STT_SECTION
), 0,
1149 text_section
->sh_num
, NULL
);
1150 getcwd(buf
, sizeof(buf
));
1152 normalize_slashes(buf
);
1154 pstrcat(buf
, sizeof(buf
), "/");
1155 put_stabs_r(buf
, N_SO
, 0, 0,
1156 text_section
->data_offset
, text_section
, section_sym
);
1157 put_stabs_r(file
->filename
, N_SO
, 0, 0,
1158 text_section
->data_offset
, text_section
, section_sym
);
1160 /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
1161 symbols can be safely used */
1162 put_elf_sym(symtab_section
, 0, 0,
1163 ELFW(ST_INFO
)(STB_LOCAL
, STT_FILE
), 0,
1164 SHN_ABS
, file
->filename
);
1166 /* define some often used types */
1167 int_type
.t
= VT_INT
;
1169 char_pointer_type
.t
= VT_BYTE
;
1170 mk_pointer(&char_pointer_type
);
1172 func_old_type
.t
= VT_FUNC
;
1173 func_old_type
.ref
= sym_push(SYM_FIELD
, &int_type
, FUNC_CDECL
, FUNC_OLD
);
1175 #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1176 float_type
.t
= VT_FLOAT
;
1177 double_type
.t
= VT_DOUBLE
;
1179 func_float_type
.t
= VT_FUNC
;
1180 func_float_type
.ref
= sym_push(SYM_FIELD
, &float_type
, FUNC_CDECL
, FUNC_OLD
);
1181 func_double_type
.t
= VT_FUNC
;
1182 func_double_type
.ref
= sym_push(SYM_FIELD
, &double_type
, FUNC_CDECL
, FUNC_OLD
);
1186 /* define 'void *alloca(unsigned int)' builtin function */
1191 sym
= sym_push(p
, mk_pointer(VT_VOID
), FUNC_CDECL
, FUNC_NEW
);
1192 s1
= sym_push(SYM_FIELD
, VT_UNSIGNED
| VT_INT
, 0, 0);
1195 sym_push(TOK_alloca
, VT_FUNC
| (p
<< VT_STRUCT_SHIFT
), VT_CONST
, 0);
1199 define_start
= define_stack
;
1202 if (setjmp(s1
->error_jmp_buf
) == 0) {
1204 s1
->error_set_jmp_enabled
= 1;
1206 ch
= file
->buf_ptr
[0];
1207 tok_flags
= TOK_FLAG_BOL
| TOK_FLAG_BOF
;
1208 parse_flags
= PARSE_FLAG_PREPROCESS
| PARSE_FLAG_TOK_NUM
;
1212 expect("declaration");
1214 /* end of translation unit info */
1216 put_stabs_r(NULL
, N_SO
, 0, 0,
1217 text_section
->data_offset
, text_section
, section_sym
);
1220 s1
->error_set_jmp_enabled
= 0;
1222 /* reset define stack, but leave -Dsymbols (may be incorrect if
1223 they are undefined) */
1224 free_defines(define_start
);
1226 gen_inline_functions();
1228 sym_pop(&global_stack
, NULL
);
1229 sym_pop(&local_stack
, NULL
);
1231 return s1
->nb_errors
!= 0 ? -1 : 0;
1234 /* Preprocess the current file */
1235 static int tcc_preprocess(TCCState
*s1
)
1238 BufferedFile
*file_ref
;
1239 int token_seen
, line_ref
;
1241 preprocess_init(s1
);
1242 define_start
= define_stack
;
1243 ch
= file
->buf_ptr
[0];
1244 tok_flags
= TOK_FLAG_BOL
| TOK_FLAG_BOF
;
1245 parse_flags
= PARSE_FLAG_ASM_COMMENTS
| PARSE_FLAG_PREPROCESS
|
1246 PARSE_FLAG_LINEFEED
| PARSE_FLAG_SPACES
;
1253 if (tok
== TOK_EOF
) {
1255 } else if (tok
== TOK_LINEFEED
) {
1260 } else if (!token_seen
) {
1261 int d
= file
->line_num
- line_ref
;
1262 if (file
!= file_ref
|| d
< 0 || d
>= 8)
1263 fprintf(s1
->outfile
, "# %d \"%s\"\n", file
->line_num
, file
->filename
);
1266 fputs("\n", s1
->outfile
), --d
;
1267 line_ref
= (file_ref
= file
)->line_num
;
1270 fputs(get_tok_str(tok
, &tokc
), s1
->outfile
);
1272 free_defines(define_start
);
1277 int tcc_compile_string(TCCState
*s
, const char *str
)
1279 BufferedFile bf1
, *bf
= &bf1
;
1283 /* init file structure */
1285 /* XXX: avoid copying */
1287 buf
= tcc_malloc(len
+ 1);
1290 memcpy(buf
, str
, len
);
1293 bf
->buf_end
= buf
+ len
;
1294 pstrcpy(bf
->filename
, sizeof(bf
->filename
), "<string>");
1297 ret
= tcc_compile(s
);
1301 /* currently, no need to close */
1306 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
1307 void tcc_define_symbol(TCCState
*s1
, const char *sym
, const char *value
)
1309 BufferedFile bf1
, *bf
= &bf1
;
1311 pstrcpy(bf
->buffer
, IO_BUF_SIZE
, sym
);
1312 pstrcat(bf
->buffer
, IO_BUF_SIZE
, " ");
1316 pstrcat(bf
->buffer
, IO_BUF_SIZE
, value
);
1318 /* init file structure */
1320 bf
->buf_ptr
= bf
->buffer
;
1321 bf
->buf_end
= bf
->buffer
+ strlen(bf
->buffer
);
1322 *bf
->buf_end
= CH_EOB
;
1323 bf
->filename
[0] = '\0';
1327 s1
->include_stack_ptr
= s1
->include_stack
;
1329 /* parse with define parser */
1330 ch
= file
->buf_ptr
[0];
1336 /* undefine a preprocessor symbol */
1337 void tcc_undefine_symbol(TCCState
*s1
, const char *sym
)
1341 ts
= tok_alloc(sym
, strlen(sym
));
1342 s
= define_find(ts
->tok
);
1343 /* undefine symbol by putting an invalid name */
1348 #ifdef CONFIG_TCC_ASM
1350 #ifdef TCC_TARGET_I386
1351 #include "i386-asm.c"
1356 static void asm_instr(void)
1358 error("inline asm() not supported");
1360 static void asm_global_instr(void)
1362 error("inline asm() not supported");
1368 #ifdef TCC_TARGET_COFF
1369 #include "tcccoff.c"
1372 #ifdef TCC_TARGET_PE
1376 #ifdef CONFIG_TCC_BACKTRACE
1377 /* print the position in the source file of PC value 'pc' by reading
1378 the stabs debug information */
1379 static void rt_printline(unsigned long wanted_pc
)
1381 Stab_Sym
*sym
, *sym_end
;
1382 char func_name
[128], last_func_name
[128];
1383 unsigned long func_addr
, last_pc
, pc
;
1384 const char *incl_files
[INCLUDE_STACK_SIZE
];
1385 int incl_index
, len
, last_line_num
, i
;
1386 const char *str
, *p
;
1388 fprintf(stderr
, "0x%08lx:", wanted_pc
);
1390 func_name
[0] = '\0';
1393 last_func_name
[0] = '\0';
1394 last_pc
= 0xffffffff;
1396 sym
= (Stab_Sym
*)stab_section
->data
+ 1;
1397 sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
1398 while (sym
< sym_end
) {
1399 switch(sym
->n_type
) {
1400 /* function start or end */
1402 if (sym
->n_strx
== 0) {
1403 /* we test if between last line and end of function */
1404 pc
= sym
->n_value
+ func_addr
;
1405 if (wanted_pc
>= last_pc
&& wanted_pc
< pc
)
1407 func_name
[0] = '\0';
1410 str
= stabstr_section
->data
+ sym
->n_strx
;
1411 p
= strchr(str
, ':');
1413 pstrcpy(func_name
, sizeof(func_name
), str
);
1416 if (len
> sizeof(func_name
) - 1)
1417 len
= sizeof(func_name
) - 1;
1418 memcpy(func_name
, str
, len
);
1419 func_name
[len
] = '\0';
1421 func_addr
= sym
->n_value
;
1424 /* line number info */
1426 pc
= sym
->n_value
+ func_addr
;
1427 if (wanted_pc
>= last_pc
&& wanted_pc
< pc
)
1430 last_line_num
= sym
->n_desc
;
1432 strcpy(last_func_name
, func_name
);
1436 str
= stabstr_section
->data
+ sym
->n_strx
;
1438 if (incl_index
< INCLUDE_STACK_SIZE
) {
1439 incl_files
[incl_index
++] = str
;
1447 if (sym
->n_strx
== 0) {
1448 incl_index
= 0; /* end of translation unit */
1450 str
= stabstr_section
->data
+ sym
->n_strx
;
1451 /* do not add path */
1453 if (len
> 0 && str
[len
- 1] != '/')
1461 /* second pass: we try symtab symbols (no line number info) */
1464 ElfW(Sym
) *sym
, *sym_end
;
1467 sym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
1468 for(sym
= (ElfW(Sym
) *)symtab_section
->data
+ 1;
1471 type
= ELFW(ST_TYPE
)(sym
->st_info
);
1472 if (type
== STT_FUNC
) {
1473 if (wanted_pc
>= sym
->st_value
&&
1474 wanted_pc
< sym
->st_value
+ sym
->st_size
) {
1475 pstrcpy(last_func_name
, sizeof(last_func_name
),
1476 strtab_section
->data
+ sym
->st_name
);
1482 /* did not find any info: */
1483 fprintf(stderr
, " ???\n");
1486 if (last_func_name
[0] != '\0') {
1487 fprintf(stderr
, " %s()", last_func_name
);
1489 if (incl_index
> 0) {
1490 fprintf(stderr
, " (%s:%d",
1491 incl_files
[incl_index
- 1], last_line_num
);
1492 for(i
= incl_index
- 2; i
>= 0; i
--)
1493 fprintf(stderr
, ", included from %s", incl_files
[i
]);
1494 fprintf(stderr
, ")");
1496 fprintf(stderr
, "\n");
1500 /* fix for glibc 2.1 */
1506 /* return the PC at frame level 'level'. Return non zero if not found */
1507 static int rt_get_caller_pc(unsigned long *paddr
,
1508 ucontext_t
*uc
, int level
)
1514 #if defined(__FreeBSD__)
1515 *paddr
= uc
->uc_mcontext
.mc_eip
;
1516 #elif defined(__dietlibc__)
1517 *paddr
= uc
->uc_mcontext
.eip
;
1519 *paddr
= uc
->uc_mcontext
.gregs
[REG_EIP
];
1523 #if defined(__FreeBSD__)
1524 fp
= uc
->uc_mcontext
.mc_ebp
;
1525 #elif defined(__dietlibc__)
1526 fp
= uc
->uc_mcontext
.ebp
;
1528 fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
1530 for(i
=1;i
<level
;i
++) {
1531 /* XXX: check address validity with program info */
1532 if (fp
<= 0x1000 || fp
>= 0xc0000000)
1534 fp
= ((unsigned long *)fp
)[0];
1536 *paddr
= ((unsigned long *)fp
)[1];
1540 #elif defined(__x86_64__)
1541 /* return the PC at frame level 'level'. Return non zero if not found */
1542 static int rt_get_caller_pc(unsigned long *paddr
,
1543 ucontext_t
*uc
, int level
)
1549 /* XXX: only support linux */
1550 *paddr
= uc
->uc_mcontext
.gregs
[REG_RIP
];
1553 fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
1554 for(i
=1;i
<level
;i
++) {
1555 /* XXX: check address validity with program info */
1558 fp
= ((unsigned long *)fp
)[0];
1560 *paddr
= ((unsigned long *)fp
)[1];
1565 #warning add arch specific rt_get_caller_pc()
1566 static int rt_get_caller_pc(unsigned long *paddr
,
1567 ucontext_t
*uc
, int level
)
1573 /* emit a run time error at position 'pc' */
1574 void rt_error(ucontext_t
*uc
, const char *fmt
, ...)
1581 fprintf(stderr
, "Runtime error: ");
1582 vfprintf(stderr
, fmt
, ap
);
1583 fprintf(stderr
, "\n");
1584 for(i
=0;i
<num_callers
;i
++) {
1585 if (rt_get_caller_pc(&pc
, uc
, i
) < 0)
1588 fprintf(stderr
, "at ");
1590 fprintf(stderr
, "by ");
1597 /* signal handler for fatal errors */
1598 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
1600 ucontext_t
*uc
= puc
;
1604 switch(siginf
->si_code
) {
1607 rt_error(uc
, "division by zero");
1610 rt_error(uc
, "floating point exception");
1616 if (rt_bound_error_msg
&& *rt_bound_error_msg
)
1617 rt_error(uc
, *rt_bound_error_msg
);
1619 rt_error(uc
, "dereferencing invalid pointer");
1622 rt_error(uc
, "illegal instruction");
1625 rt_error(uc
, "abort() called");
1628 rt_error(uc
, "caught signal %d", signum
);
1636 /* copy code into memory passed in by the caller and do all relocations
1637 (needed before using tcc_get_symbol()).
1638 returns -1 on error and required size if ptr is NULL */
1639 int tcc_relocate(TCCState
*s1
, void *ptr
)
1642 unsigned long offset
, length
, mem
;
1645 if (0 == s1
->runtime_added
) {
1646 s1
->runtime_added
= 1;
1648 #ifdef TCC_TARGET_PE
1650 relocate_common_syms();
1651 tcc_add_linker_symbols(s1
);
1653 tcc_add_runtime(s1
);
1654 relocate_common_syms();
1655 tcc_add_linker_symbols(s1
);
1656 build_got_entries(s1
);
1660 offset
= 0, mem
= (unsigned long)ptr
;
1661 for(i
= 1; i
< s1
->nb_sections
; i
++) {
1662 s
= s1
->sections
[i
];
1663 if (0 == (s
->sh_flags
& SHF_ALLOC
))
1665 length
= s
->data_offset
;
1666 s
->sh_addr
= mem
? (mem
+ offset
+ 15) & ~15 : 0;
1667 offset
= (offset
+ length
+ 15) & ~15;
1670 /* relocate symbols */
1671 relocate_syms(s1
, 1);
1675 #ifdef TCC_TARGET_X86_64
1676 s1
->runtime_plt_and_got_offset
= 0;
1677 s1
->runtime_plt_and_got
= (char *)(mem
+ offset
);
1678 /* double the size of the buffer for got and plt entries
1679 XXX: calculate exact size for them? */
1686 /* relocate each section */
1687 for(i
= 1; i
< s1
->nb_sections
; i
++) {
1688 s
= s1
->sections
[i
];
1690 relocate_section(s1
, s
);
1693 for(i
= 1; i
< s1
->nb_sections
; i
++) {
1694 s
= s1
->sections
[i
];
1695 if (0 == (s
->sh_flags
& SHF_ALLOC
))
1697 length
= s
->data_offset
;
1698 // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
1699 ptr
= (void*)s
->sh_addr
;
1700 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
1701 memset(ptr
, 0, length
);
1703 memcpy(ptr
, s
->data
, length
);
1704 /* mark executable sections as executable in memory */
1705 if (s
->sh_flags
& SHF_EXECINSTR
)
1706 set_pages_executable(ptr
, length
);
1708 #ifdef TCC_TARGET_X86_64
1709 set_pages_executable(s1
->runtime_plt_and_got
,
1710 s1
->runtime_plt_and_got_offset
);
1715 /* launch the compiled program with the given arguments */
1716 int tcc_run(TCCState
*s1
, int argc
, char **argv
)
1718 int (*prog_main
)(int, char **);
1722 ret
= tcc_relocate(s1
, NULL
);
1725 ptr
= tcc_malloc(ret
);
1726 tcc_relocate(s1
, ptr
);
1728 prog_main
= tcc_get_symbol_err(s1
, "main");
1731 #ifdef CONFIG_TCC_BACKTRACE
1732 struct sigaction sigact
;
1733 /* install TCC signal handlers to print debug info on fatal
1735 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
1736 sigact
.sa_sigaction
= sig_error
;
1737 sigemptyset(&sigact
.sa_mask
);
1738 sigaction(SIGFPE
, &sigact
, NULL
);
1739 sigaction(SIGILL
, &sigact
, NULL
);
1740 sigaction(SIGSEGV
, &sigact
, NULL
);
1741 sigaction(SIGBUS
, &sigact
, NULL
);
1742 sigaction(SIGABRT
, &sigact
, NULL
);
1744 error("debug mode not available");
1748 #ifdef CONFIG_TCC_BCHECK
1749 if (do_bounds_check
) {
1750 void (*bound_init
)(void);
1752 /* set error function */
1753 rt_bound_error_msg
= tcc_get_symbol_err(s1
, "__bound_error_msg");
1755 /* XXX: use .init section so that it also work in binary ? */
1756 bound_init
= (void *)tcc_get_symbol_err(s1
, "__bound_init");
1760 ret
= (*prog_main
)(argc
, argv
);
1765 void tcc_memstats(void)
1768 printf("memory in use: %d\n", mem_cur_size
);
1772 static void tcc_cleanup(void)
1776 if (NULL
== tcc_state
)
1780 /* free -D defines */
1784 n
= tok_ident
- TOK_IDENT
;
1785 for(i
= 0; i
< n
; i
++)
1786 tcc_free(table_ident
[i
]);
1787 tcc_free(table_ident
);
1789 /* free sym_pools */
1790 dynarray_reset(&sym_pools
, &nb_sym_pools
);
1792 cstr_free(&tokcstr
);
1793 /* reset symbol stack */
1794 sym_free_first
= NULL
;
1795 /* cleanup from error/setjmp */
1799 TCCState
*tcc_new(void)
1808 s
= tcc_mallocz(sizeof(TCCState
));
1812 s
->output_type
= TCC_OUTPUT_MEMORY
;
1814 /* init isid table */
1815 for(i
=CH_EOF
;i
<256;i
++)
1816 isidnum_table
[i
-CH_EOF
] = isid(i
) || isnum(i
);
1818 /* add all tokens */
1820 memset(hash_ident
, 0, TOK_HASH_SIZE
* sizeof(TokenSym
*));
1822 tok_ident
= TOK_IDENT
;
1831 ts
= tok_alloc(p
, r
- p
- 1);
1835 /* we add dummy defines for some special macros to speed up tests
1836 and to have working defined() */
1837 define_push(TOK___LINE__
, MACRO_OBJ
, NULL
, NULL
);
1838 define_push(TOK___FILE__
, MACRO_OBJ
, NULL
, NULL
);
1839 define_push(TOK___DATE__
, MACRO_OBJ
, NULL
, NULL
);
1840 define_push(TOK___TIME__
, MACRO_OBJ
, NULL
, NULL
);
1842 /* standard defines */
1843 tcc_define_symbol(s
, "__STDC__", NULL
);
1844 tcc_define_symbol(s
, "__STDC_VERSION__", "199901L");
1845 #if defined(TCC_TARGET_I386)
1846 tcc_define_symbol(s
, "__i386__", NULL
);
1848 #if defined(TCC_TARGET_X86_64)
1849 tcc_define_symbol(s
, "__x86_64__", NULL
);
1851 #if defined(TCC_TARGET_ARM)
1852 tcc_define_symbol(s
, "__ARM_ARCH_4__", NULL
);
1853 tcc_define_symbol(s
, "__arm_elf__", NULL
);
1854 tcc_define_symbol(s
, "__arm_elf", NULL
);
1855 tcc_define_symbol(s
, "arm_elf", NULL
);
1856 tcc_define_symbol(s
, "__arm__", NULL
);
1857 tcc_define_symbol(s
, "__arm", NULL
);
1858 tcc_define_symbol(s
, "arm", NULL
);
1859 tcc_define_symbol(s
, "__APCS_32__", NULL
);
1861 #ifdef TCC_TARGET_PE
1862 tcc_define_symbol(s
, "_WIN32", NULL
);
1864 tcc_define_symbol(s
, "__unix__", NULL
);
1865 tcc_define_symbol(s
, "__unix", NULL
);
1866 #if defined(__linux)
1867 tcc_define_symbol(s
, "__linux__", NULL
);
1868 tcc_define_symbol(s
, "__linux", NULL
);
1871 /* tiny C specific defines */
1872 tcc_define_symbol(s
, "__TINYC__", NULL
);
1874 /* tiny C & gcc defines */
1875 tcc_define_symbol(s
, "__SIZE_TYPE__", "unsigned int");
1876 tcc_define_symbol(s
, "__PTRDIFF_TYPE__", "int");
1877 #ifdef TCC_TARGET_PE
1878 tcc_define_symbol(s
, "__WCHAR_TYPE__", "unsigned short");
1880 tcc_define_symbol(s
, "__WCHAR_TYPE__", "int");
1883 #ifndef TCC_TARGET_PE
1884 /* default library paths */
1885 tcc_add_library_path(s
, CONFIG_SYSROOT
"/usr/local/lib");
1886 tcc_add_library_path(s
, CONFIG_SYSROOT
"/usr/lib");
1887 tcc_add_library_path(s
, CONFIG_SYSROOT
"/lib");
1890 /* no section zero */
1891 dynarray_add((void ***)&s
->sections
, &s
->nb_sections
, NULL
);
1893 /* create standard sections */
1894 text_section
= new_section(s
, ".text", SHT_PROGBITS
, SHF_ALLOC
| SHF_EXECINSTR
);
1895 data_section
= new_section(s
, ".data", SHT_PROGBITS
, SHF_ALLOC
| SHF_WRITE
);
1896 bss_section
= new_section(s
, ".bss", SHT_NOBITS
, SHF_ALLOC
| SHF_WRITE
);
1898 /* symbols are always generated for linking stage */
1899 symtab_section
= new_symtab(s
, ".symtab", SHT_SYMTAB
, 0,
1901 ".hashtab", SHF_PRIVATE
);
1902 strtab_section
= symtab_section
->link
;
1904 /* private symbol table for dynamic symbols */
1905 s
->dynsymtab_section
= new_symtab(s
, ".dynsymtab", SHT_SYMTAB
, SHF_PRIVATE
,
1907 ".dynhashtab", SHF_PRIVATE
);
1908 s
->alacarte_link
= 1;
1910 #ifdef CHAR_IS_UNSIGNED
1911 s
->char_is_unsigned
= 1;
1913 #if defined(TCC_TARGET_PE) && 0
1914 /* XXX: currently the PE linker is not ready to support that */
1915 s
->leading_underscore
= 1;
1920 void tcc_delete(TCCState
*s1
)
1926 /* free all sections */
1927 for(i
= 1; i
< s1
->nb_sections
; i
++)
1928 free_section(s1
->sections
[i
]);
1929 dynarray_reset(&s1
->sections
, &s1
->nb_sections
);
1931 for(i
= 0; i
< s1
->nb_priv_sections
; i
++)
1932 free_section(s1
->priv_sections
[i
]);
1933 dynarray_reset(&s1
->priv_sections
, &s1
->nb_priv_sections
);
1935 /* free any loaded DLLs */
1936 for ( i
= 0; i
< s1
->nb_loaded_dlls
; i
++) {
1937 DLLReference
*ref
= s1
->loaded_dlls
[i
];
1939 dlclose(ref
->handle
);
1942 /* free loaded dlls array */
1943 dynarray_reset(&s1
->loaded_dlls
, &s1
->nb_loaded_dlls
);
1945 /* free library paths */
1946 dynarray_reset(&s1
->library_paths
, &s1
->nb_library_paths
);
1948 /* free include paths */
1949 dynarray_reset(&s1
->cached_includes
, &s1
->nb_cached_includes
);
1950 dynarray_reset(&s1
->include_paths
, &s1
->nb_include_paths
);
1951 dynarray_reset(&s1
->sysinclude_paths
, &s1
->nb_sysinclude_paths
);
1956 int tcc_add_include_path(TCCState
*s1
, const char *pathname
)
1960 pathname1
= tcc_strdup(pathname
);
1961 dynarray_add((void ***)&s1
->include_paths
, &s1
->nb_include_paths
, pathname1
);
1965 int tcc_add_sysinclude_path(TCCState
*s1
, const char *pathname
)
1969 pathname1
= tcc_strdup(pathname
);
1970 dynarray_add((void ***)&s1
->sysinclude_paths
, &s1
->nb_sysinclude_paths
, pathname1
);
1974 static int tcc_add_file_internal(TCCState
*s1
, const char *filename
, int flags
)
1979 BufferedFile
*saved_file
;
1981 /* find source file type with extension */
1982 ext
= tcc_fileextension(filename
);
1988 file
= tcc_open(s1
, filename
);
1990 if (flags
& AFF_PRINT_ERROR
) {
1991 error_noabort("file '%s' not found", filename
);
1997 if (flags
& AFF_PREPROCESS
) {
1998 ret
= tcc_preprocess(s1
);
1999 } else if (!ext
[0] || !PATHCMP(ext
, "c")) {
2000 /* C file assumed */
2001 ret
= tcc_compile(s1
);
2003 #ifdef CONFIG_TCC_ASM
2004 if (!strcmp(ext
, "S")) {
2005 /* preprocessed assembler */
2006 ret
= tcc_assemble(s1
, 1);
2007 } else if (!strcmp(ext
, "s")) {
2008 /* non preprocessed assembler */
2009 ret
= tcc_assemble(s1
, 0);
2012 #ifdef TCC_TARGET_PE
2013 if (!PATHCMP(ext
, "def")) {
2014 ret
= pe_load_def_file(s1
, file
->fd
);
2019 /* assume executable format: auto guess file type */
2020 ret
= read(fd
, &ehdr
, sizeof(ehdr
));
2021 lseek(fd
, 0, SEEK_SET
);
2023 error_noabort("could not read header");
2025 } else if (ret
!= sizeof(ehdr
)) {
2026 goto try_load_script
;
2029 if (ehdr
.e_ident
[0] == ELFMAG0
&&
2030 ehdr
.e_ident
[1] == ELFMAG1
&&
2031 ehdr
.e_ident
[2] == ELFMAG2
&&
2032 ehdr
.e_ident
[3] == ELFMAG3
) {
2033 file
->line_num
= 0; /* do not display line number if error */
2034 if (ehdr
.e_type
== ET_REL
) {
2035 ret
= tcc_load_object_file(s1
, fd
, 0);
2036 } else if (ehdr
.e_type
== ET_DYN
) {
2037 if (s1
->output_type
== TCC_OUTPUT_MEMORY
) {
2038 #ifdef TCC_TARGET_PE
2042 h
= dlopen(filename
, RTLD_GLOBAL
| RTLD_LAZY
);
2049 ret
= tcc_load_dll(s1
, fd
, filename
,
2050 (flags
& AFF_REFERENCED_DLL
) != 0);
2053 error_noabort("unrecognized ELF file");
2056 } else if (memcmp((char *)&ehdr
, ARMAG
, 8) == 0) {
2057 file
->line_num
= 0; /* do not display line number if error */
2058 ret
= tcc_load_archive(s1
, fd
);
2060 #ifdef TCC_TARGET_COFF
2061 if (*(uint16_t *)(&ehdr
) == COFF_C67_MAGIC
) {
2062 ret
= tcc_load_coff(s1
, fd
);
2065 #ifdef TCC_TARGET_PE
2066 if (pe_test_res_file(&ehdr
, ret
)) {
2067 ret
= pe_load_res_file(s1
, fd
);
2071 /* as GNU ld, consider it is an ld script if not recognized */
2073 ret
= tcc_load_ldscript(s1
);
2075 error_noabort("unrecognized file type");
2090 int tcc_add_file(TCCState
*s
, const char *filename
)
2092 return tcc_add_file_internal(s
, filename
, AFF_PRINT_ERROR
);
2095 int tcc_add_library_path(TCCState
*s
, const char *pathname
)
2099 pathname1
= tcc_strdup(pathname
);
2100 dynarray_add((void ***)&s
->library_paths
, &s
->nb_library_paths
, pathname1
);
2104 /* find and load a dll. Return non zero if not found */
2105 /* XXX: add '-rpath' option support ? */
2106 static int tcc_add_dll(TCCState
*s
, const char *filename
, int flags
)
2111 for(i
= 0; i
< s
->nb_library_paths
; i
++) {
2112 snprintf(buf
, sizeof(buf
), "%s/%s",
2113 s
->library_paths
[i
], filename
);
2114 if (tcc_add_file_internal(s
, buf
, flags
) == 0)
2120 /* the library name is the same as the argument of the '-l' option */
2121 int tcc_add_library(TCCState
*s
, const char *libraryname
)
2126 /* first we look for the dynamic library if not static linking */
2127 if (!s
->static_link
) {
2128 #ifdef TCC_TARGET_PE
2129 snprintf(buf
, sizeof(buf
), "%s.def", libraryname
);
2131 snprintf(buf
, sizeof(buf
), "lib%s.so", libraryname
);
2133 if (tcc_add_dll(s
, buf
, 0) == 0)
2137 /* then we look for the static library */
2138 for(i
= 0; i
< s
->nb_library_paths
; i
++) {
2139 snprintf(buf
, sizeof(buf
), "%s/lib%s.a",
2140 s
->library_paths
[i
], libraryname
);
2141 if (tcc_add_file_internal(s
, buf
, 0) == 0)
2147 int tcc_add_symbol(TCCState
*s
, const char *name
, void *val
)
2149 add_elf_sym(symtab_section
, (unsigned long)val
, 0,
2150 ELFW(ST_INFO
)(STB_GLOBAL
, STT_NOTYPE
), 0,
2155 int tcc_set_output_type(TCCState
*s
, int output_type
)
2159 s
->output_type
= output_type
;
2162 /* default include paths */
2163 /* XXX: reverse order needed if -isystem support */
2164 #ifndef TCC_TARGET_PE
2165 tcc_add_sysinclude_path(s
, CONFIG_SYSROOT
"/usr/local/include");
2166 tcc_add_sysinclude_path(s
, CONFIG_SYSROOT
"/usr/include");
2168 snprintf(buf
, sizeof(buf
), "%s/include", tcc_lib_path
);
2169 tcc_add_sysinclude_path(s
, buf
);
2170 #ifdef TCC_TARGET_PE
2171 snprintf(buf
, sizeof(buf
), "%s/include/winapi", tcc_lib_path
);
2172 tcc_add_sysinclude_path(s
, buf
);
2176 /* if bound checking, then add corresponding sections */
2177 #ifdef CONFIG_TCC_BCHECK
2178 if (do_bounds_check
) {
2180 tcc_define_symbol(s
, "__BOUNDS_CHECKING_ON", NULL
);
2181 /* create bounds sections */
2182 bounds_section
= new_section(s
, ".bounds",
2183 SHT_PROGBITS
, SHF_ALLOC
);
2184 lbounds_section
= new_section(s
, ".lbounds",
2185 SHT_PROGBITS
, SHF_ALLOC
);
2189 if (s
->char_is_unsigned
) {
2190 tcc_define_symbol(s
, "__CHAR_UNSIGNED__", NULL
);
2193 /* add debug sections */
2196 stab_section
= new_section(s
, ".stab", SHT_PROGBITS
, 0);
2197 stab_section
->sh_entsize
= sizeof(Stab_Sym
);
2198 stabstr_section
= new_section(s
, ".stabstr", SHT_STRTAB
, 0);
2199 put_elf_str(stabstr_section
, "");
2200 stab_section
->link
= stabstr_section
;
2201 /* put first entry */
2202 put_stabs("", 0, 0, 0, 0);
2205 /* add libc crt1/crti objects */
2206 #ifndef TCC_TARGET_PE
2207 if ((output_type
== TCC_OUTPUT_EXE
|| output_type
== TCC_OUTPUT_DLL
) &&
2209 if (output_type
!= TCC_OUTPUT_DLL
)
2210 tcc_add_file(s
, CONFIG_TCC_CRT_PREFIX
"/crt1.o");
2211 tcc_add_file(s
, CONFIG_TCC_CRT_PREFIX
"/crti.o");
2215 #ifdef TCC_TARGET_PE
2216 snprintf(buf
, sizeof(buf
), "%s/lib", tcc_lib_path
);
2217 tcc_add_library_path(s
, buf
);
2223 #define WD_ALL 0x0001 /* warning is activated when using -Wall */
2224 #define FD_INVERT 0x0002 /* invert value before storing */
2226 typedef struct FlagDef
{
2232 static const FlagDef warning_defs
[] = {
2233 { offsetof(TCCState
, warn_unsupported
), 0, "unsupported" },
2234 { offsetof(TCCState
, warn_write_strings
), 0, "write-strings" },
2235 { offsetof(TCCState
, warn_error
), 0, "error" },
2236 { offsetof(TCCState
, warn_implicit_function_declaration
), WD_ALL
,
2237 "implicit-function-declaration" },
2240 static int set_flag(TCCState
*s
, const FlagDef
*flags
, int nb_flags
,
2241 const char *name
, int value
)
2248 if (r
[0] == 'n' && r
[1] == 'o' && r
[2] == '-') {
2252 for(i
= 0, p
= flags
; i
< nb_flags
; i
++, p
++) {
2253 if (!strcmp(r
, p
->name
))
2258 if (p
->flags
& FD_INVERT
)
2260 *(int *)((uint8_t *)s
+ p
->offset
) = value
;
2265 /* set/reset a warning */
2266 int tcc_set_warning(TCCState
*s
, const char *warning_name
, int value
)
2271 if (!strcmp(warning_name
, "all")) {
2272 for(i
= 0, p
= warning_defs
; i
< countof(warning_defs
); i
++, p
++) {
2273 if (p
->flags
& WD_ALL
)
2274 *(int *)((uint8_t *)s
+ p
->offset
) = 1;
2278 return set_flag(s
, warning_defs
, countof(warning_defs
),
2279 warning_name
, value
);
2283 static const FlagDef flag_defs
[] = {
2284 { offsetof(TCCState
, char_is_unsigned
), 0, "unsigned-char" },
2285 { offsetof(TCCState
, char_is_unsigned
), FD_INVERT
, "signed-char" },
2286 { offsetof(TCCState
, nocommon
), FD_INVERT
, "common" },
2287 { offsetof(TCCState
, leading_underscore
), 0, "leading-underscore" },
2290 /* set/reset a flag */
2291 int tcc_set_flag(TCCState
*s
, const char *flag_name
, int value
)
2293 return set_flag(s
, flag_defs
, countof(flag_defs
),
2297 /* set CONFIG_TCCDIR at runtime */
2298 void tcc_set_lib_path(TCCState
*s
, const char *path
)
2300 tcc_lib_path
= tcc_strdup(path
);
2303 #if !defined(LIBTCC)
2305 static int64_t getclock_us(void)
2310 return (tb
.time
* 1000LL + tb
.millitm
) * 1000LL;
2313 gettimeofday(&tv
, NULL
);
2314 return tv
.tv_sec
* 1000000LL + tv
.tv_usec
;
2320 printf("tcc version " TCC_VERSION
" - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
2321 "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
2322 " [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n"
2323 " [-static] [infile1 infile2...] [-run infile args...]\n"
2325 "General options:\n"
2326 " -v display current version, increase verbosity\n"
2327 " -c compile only - generate an object file\n"
2328 " -o outfile set output filename\n"
2329 " -Bdir set tcc internal library path\n"
2330 " -bench output compilation statistics\n"
2331 " -run run compiled source\n"
2332 " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n"
2333 " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n"
2334 " -w disable all warnings\n"
2335 "Preprocessor options:\n"
2336 " -E preprocess only\n"
2337 " -Idir add include path 'dir'\n"
2338 " -Dsym[=val] define 'sym' with value 'val'\n"
2339 " -Usym undefine 'sym'\n"
2341 " -Ldir add library path 'dir'\n"
2342 " -llib link with dynamic or static library 'lib'\n"
2343 " -shared generate a shared library\n"
2344 " -soname set name for shared library to be used at runtime\n"
2345 " -static static linking\n"
2346 " -rdynamic export all global symbols to dynamic linker\n"
2347 " -r generate (relocatable) object file\n"
2348 "Debugger options:\n"
2349 " -g generate runtime debug info\n"
2350 #ifdef CONFIG_TCC_BCHECK
2351 " -b compile with built-in memory and bounds checker (implies -g)\n"
2353 #ifdef CONFIG_TCC_BACKTRACE
2354 " -bt N show N callers in stack traces\n"
2359 #define TCC_OPTION_HAS_ARG 0x0001
2360 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
2362 typedef struct TCCOption
{
2391 TCC_OPTION_nostdinc
,
2392 TCC_OPTION_nostdlib
,
2393 TCC_OPTION_print_search_dirs
,
2394 TCC_OPTION_rdynamic
,
2402 static const TCCOption tcc_options
[] = {
2403 { "h", TCC_OPTION_HELP
, 0 },
2404 { "?", TCC_OPTION_HELP
, 0 },
2405 { "I", TCC_OPTION_I
, TCC_OPTION_HAS_ARG
},
2406 { "D", TCC_OPTION_D
, TCC_OPTION_HAS_ARG
},
2407 { "U", TCC_OPTION_U
, TCC_OPTION_HAS_ARG
},
2408 { "L", TCC_OPTION_L
, TCC_OPTION_HAS_ARG
},
2409 { "B", TCC_OPTION_B
, TCC_OPTION_HAS_ARG
},
2410 { "l", TCC_OPTION_l
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2411 { "bench", TCC_OPTION_bench
, 0 },
2412 { "bt", TCC_OPTION_bt
, TCC_OPTION_HAS_ARG
},
2413 #ifdef CONFIG_TCC_BCHECK
2414 { "b", TCC_OPTION_b
, 0 },
2416 { "g", TCC_OPTION_g
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2417 { "c", TCC_OPTION_c
, 0 },
2418 { "static", TCC_OPTION_static
, 0 },
2419 { "shared", TCC_OPTION_shared
, 0 },
2420 { "soname", TCC_OPTION_soname
, TCC_OPTION_HAS_ARG
},
2421 { "o", TCC_OPTION_o
, TCC_OPTION_HAS_ARG
},
2422 { "run", TCC_OPTION_run
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2423 { "rdynamic", TCC_OPTION_rdynamic
, 0 },
2424 { "r", TCC_OPTION_r
, 0 },
2425 { "Wl,", TCC_OPTION_Wl
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2426 { "W", TCC_OPTION_W
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2427 { "O", TCC_OPTION_O
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2428 { "m", TCC_OPTION_m
, TCC_OPTION_HAS_ARG
},
2429 { "f", TCC_OPTION_f
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2430 { "nostdinc", TCC_OPTION_nostdinc
, 0 },
2431 { "nostdlib", TCC_OPTION_nostdlib
, 0 },
2432 { "print-search-dirs", TCC_OPTION_print_search_dirs
, 0 },
2433 { "v", TCC_OPTION_v
, TCC_OPTION_HAS_ARG
| TCC_OPTION_NOSEP
},
2434 { "w", TCC_OPTION_w
, 0 },
2435 { "pipe", TCC_OPTION_pipe
, 0},
2436 { "E", TCC_OPTION_E
, 0},
2440 /* convert 'str' into an array of space separated strings */
2441 static int expand_args(char ***pargv
, const char *str
)
2450 while (is_space(*str
))
2455 while (*str
!= '\0' && !is_space(*str
))
2458 arg
= tcc_malloc(len
+ 1);
2459 memcpy(arg
, s1
, len
);
2461 dynarray_add((void ***)&argv
, &argc
, arg
);
2467 static char **files
;
2468 static int nb_files
, nb_libraries
;
2469 static int multiple_files
;
2470 static int print_search_dirs
;
2471 static int output_type
;
2472 static int reloc_output
;
2473 static const char *outfile
;
2475 int parse_args(TCCState
*s
, int argc
, char **argv
)
2478 const TCCOption
*popt
;
2479 const char *optarg
, *p1
, *r1
;
2483 while (optind
< argc
) {
2486 if (r
[0] != '-' || r
[1] == '\0') {
2487 /* add a new file */
2488 dynarray_add((void ***)&files
, &nb_files
, r
);
2489 if (!multiple_files
) {
2491 /* argv[0] will be this file */
2495 /* find option in table (match only the first chars */
2500 error("invalid option -- '%s'", r
);
2513 if (popt
->flags
& TCC_OPTION_HAS_ARG
) {
2514 if (*r1
!= '\0' || (popt
->flags
& TCC_OPTION_NOSEP
)) {
2518 error("argument to '%s' is missing", r
);
2519 optarg
= argv
[optind
++];
2527 switch(popt
->index
) {
2528 case TCC_OPTION_HELP
:
2532 if (tcc_add_include_path(s
, optarg
) < 0)
2533 error("too many include paths");
2538 sym
= (char *)optarg
;
2539 value
= strchr(sym
, '=');
2544 tcc_define_symbol(s
, sym
, value
);
2548 tcc_undefine_symbol(s
, optarg
);
2551 tcc_add_library_path(s
, optarg
);
2554 /* set tcc utilities path (mainly for tcc development) */
2555 tcc_set_lib_path(s
, optarg
);
2558 dynarray_add((void ***)&files
, &nb_files
, r
);
2561 case TCC_OPTION_bench
:
2564 #ifdef CONFIG_TCC_BACKTRACE
2566 num_callers
= atoi(optarg
);
2569 #ifdef CONFIG_TCC_BCHECK
2571 do_bounds_check
= 1;
2580 output_type
= TCC_OUTPUT_OBJ
;
2582 case TCC_OPTION_static
:
2585 case TCC_OPTION_shared
:
2586 output_type
= TCC_OUTPUT_DLL
;
2588 case TCC_OPTION_soname
:
2596 /* generate a .o merging several output files */
2598 output_type
= TCC_OUTPUT_OBJ
;
2600 case TCC_OPTION_nostdinc
:
2603 case TCC_OPTION_nostdlib
:
2606 case TCC_OPTION_print_search_dirs
:
2607 print_search_dirs
= 1;
2609 case TCC_OPTION_run
:
2613 argc1
= expand_args(&argv1
, optarg
);
2615 parse_args(s
, argc1
, argv1
);
2618 output_type
= TCC_OUTPUT_MEMORY
;
2624 printf("tcc version %s\n", TCC_VERSION
);
2625 } while (*optarg
++ == 'v');
2628 if (tcc_set_flag(s
, optarg
, 1) < 0 && s
->warn_unsupported
)
2629 goto unsupported_option
;
2632 if (tcc_set_warning(s
, optarg
, 1) < 0 &&
2633 s
->warn_unsupported
)
2634 goto unsupported_option
;
2639 case TCC_OPTION_rdynamic
:
2645 if (strstart(optarg
, "-Ttext,", &p
)) {
2646 s
->text_addr
= strtoul(p
, NULL
, 16);
2647 s
->has_text_addr
= 1;
2648 } else if (strstart(optarg
, "--oformat,", &p
)) {
2649 if (strstart(p
, "elf32-", NULL
)) {
2650 s
->output_format
= TCC_OUTPUT_FORMAT_ELF
;
2651 } else if (!strcmp(p
, "binary")) {
2652 s
->output_format
= TCC_OUTPUT_FORMAT_BINARY
;
2654 #ifdef TCC_TARGET_COFF
2655 if (!strcmp(p
, "coff")) {
2656 s
->output_format
= TCC_OUTPUT_FORMAT_COFF
;
2660 error("target %s not found", p
);
2663 error("unsupported linker option '%s'", optarg
);
2668 output_type
= TCC_OUTPUT_PREPROCESS
;
2671 if (s
->warn_unsupported
) {
2673 warning("unsupported option '%s'", r
);
2682 int main(int argc
, char **argv
)
2686 int nb_objfiles
, ret
, optind
;
2687 char objfilename
[1024];
2688 int64_t start_time
= 0;
2692 tcc_set_lib_path_w32(s
);
2694 output_type
= TCC_OUTPUT_EXE
;
2701 print_search_dirs
= 0;
2704 optind
= parse_args(s
, argc
- 1, argv
+ 1);
2705 if (print_search_dirs
) {
2706 /* enough for Linux kernel */
2707 printf("install: %s/\n", tcc_lib_path
);
2710 if (optind
== 0 || nb_files
== 0) {
2711 if (optind
&& verbose
)
2717 nb_objfiles
= nb_files
- nb_libraries
;
2719 /* if outfile provided without other options, we output an
2721 if (outfile
&& output_type
== TCC_OUTPUT_MEMORY
)
2722 output_type
= TCC_OUTPUT_EXE
;
2724 /* check -c consistency : only single file handled. XXX: checks file type */
2725 if (output_type
== TCC_OUTPUT_OBJ
&& !reloc_output
) {
2726 /* accepts only a single input file */
2727 if (nb_objfiles
!= 1)
2728 error("cannot specify multiple files with -c");
2729 if (nb_libraries
!= 0)
2730 error("cannot specify libraries with -c");
2734 if (output_type
== TCC_OUTPUT_PREPROCESS
) {
2736 s
->outfile
= stdout
;
2738 s
->outfile
= fopen(outfile
, "w");
2740 error("could not open '%s", outfile
);
2742 } else if (output_type
!= TCC_OUTPUT_MEMORY
) {
2744 /* compute default outfile name */
2747 strcmp(files
[0], "-") == 0 ? "a" : tcc_basename(files
[0]);
2748 pstrcpy(objfilename
, sizeof(objfilename
), name
);
2749 ext
= tcc_fileextension(objfilename
);
2750 #ifdef TCC_TARGET_PE
2751 if (output_type
== TCC_OUTPUT_DLL
)
2752 strcpy(ext
, ".dll");
2754 if (output_type
== TCC_OUTPUT_EXE
)
2755 strcpy(ext
, ".exe");
2758 if (output_type
== TCC_OUTPUT_OBJ
&& !reloc_output
&& *ext
)
2761 pstrcpy(objfilename
, sizeof(objfilename
), "a.out");
2762 outfile
= objfilename
;
2767 start_time
= getclock_us();
2770 tcc_set_output_type(s
, output_type
);
2772 /* compile or add each files or library */
2773 for(i
= 0; i
< nb_files
&& ret
== 0; i
++) {
2774 const char *filename
;
2776 filename
= files
[i
];
2777 if (output_type
== TCC_OUTPUT_PREPROCESS
) {
2778 if (tcc_add_file_internal(s
, filename
,
2779 AFF_PRINT_ERROR
| AFF_PREPROCESS
) < 0)
2781 } else if (filename
[0] == '-' && filename
[1]) {
2782 if (tcc_add_library(s
, filename
+ 2) < 0)
2783 error("cannot find %s", filename
);
2786 printf("-> %s\n", filename
);
2787 if (tcc_add_file(s
, filename
) < 0)
2792 /* free all files */
2800 total_time
= (double)(getclock_us() - start_time
) / 1000000.0;
2801 if (total_time
< 0.001)
2803 if (total_bytes
< 1)
2805 printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n",
2806 tok_ident
- TOK_IDENT
, total_lines
, total_bytes
,
2807 total_time
, (int)(total_lines
/ total_time
),
2808 total_bytes
/ total_time
/ 1000000.0);
2811 if (s
->output_type
== TCC_OUTPUT_PREPROCESS
) {
2814 } else if (s
->output_type
== TCC_OUTPUT_MEMORY
) {
2815 ret
= tcc_run(s
, argc
- optind
, argv
+ optind
);
2817 ret
= tcc_output_file(s
, outfile
) ? 1 : 0;
2819 /* XXX: cannot do it with bound checking because of the malloc hooks */
2820 if (!do_bounds_check
)
2825 printf("memory: %d bytes, max = %d bytes\n", mem_cur_size
, mem_max_size
);