From 05108a3b0a8eff70739b253b8995999b1861f9f2 Mon Sep 17 00:00:00 2001 From: grischka Date: Tue, 12 Feb 2013 19:13:28 +0100 Subject: [PATCH] libtcc: new LIBTCCAPI tcc_set_options(TCCState*, const char*str) This replaces -> use instead: ----------------------------------- - tcc_set_linker -> tcc_set_options(s, "-Wl,..."); - tcc_set_warning -> tcc_set_options(s, "-W..."); - tcc_enable_debug -> tcc_set_options(s, "-g"); parse_args is moved to libtcc.c (now tcc_parse_args). Also some cleanups: - reorder TCCState members - add some comments here and there - do not use argv's directly, make string copies - use const char* in tcc_set_linker - tccpe: use fd instead of fp tested with -D MEM_DEBUG: 0 bytes left --- Changelog | 3 +- libtcc.c | 633 ++++++++++++++++++---------- libtcc.h | 41 +- tcc.c | 978 ++++++++++++++++---------------------------- tcc.h | 328 +++++++-------- tccelf.c | 2 +- tccpe.c | 58 +-- tccpp.c | 18 +- tccrun.c | 78 ++-- win32/tcc-win32.txt | 44 +- win32/tools/tiny_impdef.c | 33 +- win32/tools/tiny_libmaker.c | 4 +- 12 files changed, 1071 insertions(+), 1149 deletions(-) rewrite tcc.c (66%) diff --git a/Changelog b/Changelog index 44b96e12..bab887ca 100644 --- a/Changelog +++ b/Changelog @@ -4,7 +4,8 @@ User interface: - -MD/-MF (automatically generate dependencies for make) - -pthread option (same as -D_REENTRANT -lpthread) (Henry Kroll III) - -m32/-m64 to re-exec cross compiler (Henry Kroll III) -- Mimic all GNU -option forms supported by ld (Kirill Smelkov) +- -Wl, Mimic all GNU -option forms supported by ld (Kirill Smelkov) +- new LIBTCCAPI tcc_set_options() (grischka) Platforms: - Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka) diff --git a/libtcc.c b/libtcc.c index 968c6e4a..cd5f13b7 100644 --- a/libtcc.c +++ b/libtcc.c @@ -197,8 +197,8 @@ PUB_FUNC char *tcc_fileextension (const char *name) #undef realloc #ifdef MEM_DEBUG -int mem_cur_size; -int mem_max_size; +ST_DATA int mem_cur_size; +ST_DATA int mem_max_size; unsigned malloc_usable_size(void*); #endif @@ -261,7 +261,7 @@ PUB_FUNC char *tcc_strdup(const char *str) PUB_FUNC void tcc_memstats(void) { #ifdef MEM_DEBUG - printf("memory in use: %d\n", mem_cur_size); + printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); #endif } @@ -272,7 +272,7 @@ PUB_FUNC void tcc_memstats(void) /********************************************************/ /* dynarrays */ -PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data) +ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data) { int nb, nb_alloc; void **pp; @@ -292,7 +292,7 @@ PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data) *nb_ptr = nb; } -PUB_FUNC void dynarray_reset(void *pp, int *n) +ST_FUNC void dynarray_reset(void *pp, int *n) { void **p; for (p = *(void***)pp; *n; ++p, --*n) @@ -860,10 +860,10 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) define_undef(s); } +/* cleanup all static data used during compilation */ static void tcc_cleanup(void) { int i, n; - if (NULL == tcc_state) return; tcc_state = NULL; @@ -915,18 +915,23 @@ LIBTCCAPI TCCState *tcc_new(void) define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); + /* define __TINYC__ 92X */ + sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c); + sprintf(buffer, "%d", a*10000 + b*100 + c); + tcc_define_symbol(s, "__TINYC__", buffer); + /* standard defines */ tcc_define_symbol(s, "__STDC__", NULL); tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); + + /* target defines */ #if defined(TCC_TARGET_I386) tcc_define_symbol(s, "__i386__", NULL); tcc_define_symbol(s, "__i386", NULL); tcc_define_symbol(s, "i386", NULL); -#endif -#if defined(TCC_TARGET_X86_64) +#elif defined(TCC_TARGET_X86_64) tcc_define_symbol(s, "__x86_64__", NULL); -#endif -#if defined(TCC_TARGET_ARM) +#elif defined(TCC_TARGET_ARM) tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); tcc_define_symbol(s, "__arm_elf__", NULL); tcc_define_symbol(s, "__arm_elf", NULL); @@ -936,34 +941,31 @@ LIBTCCAPI TCCState *tcc_new(void) tcc_define_symbol(s, "arm", NULL); tcc_define_symbol(s, "__APCS_32__", NULL); #endif + #ifdef TCC_TARGET_PE tcc_define_symbol(s, "_WIN32", NULL); -#ifdef TCC_TARGET_X86_64 +# ifdef TCC_TARGET_X86_64 tcc_define_symbol(s, "_WIN64", NULL); -#endif +# endif #else tcc_define_symbol(s, "__unix__", NULL); tcc_define_symbol(s, "__unix", NULL); tcc_define_symbol(s, "unix", NULL); -#if defined(__FreeBSD__) -#define str(s) #s - tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__)); -#undef str -#endif -#if defined(__FreeBSD_kernel__) - tcc_define_symbol(s, "__FreeBSD_kernel__", NULL); -#endif -#if defined(__linux) +# if defined(__linux) tcc_define_symbol(s, "__linux__", NULL); tcc_define_symbol(s, "__linux", NULL); +# endif +# if defined(__FreeBSD__) +# define str(s) #s + tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__)); +# undef str +# endif +# if defined(__FreeBSD_kernel__) + tcc_define_symbol(s, "__FreeBSD_kernel__", NULL); +# endif #endif -#endif - /* tiny C specific defines */ - sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c); - sprintf(buffer, "%d", a*10000 + b*100 + c); - tcc_define_symbol(s, "__TINYC__", buffer); - /* tiny C & gcc defines */ + /* TinyCC & gcc defines */ #if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long"); tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long"); @@ -978,11 +980,10 @@ LIBTCCAPI TCCState *tcc_new(void) tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); #endif +#ifndef TCC_TARGET_PE /* glibc defines */ tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", "name proto __asm__ (#alias)"); tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW"); - -#ifndef TCC_TARGET_PE /* default library paths */ tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); /* paths for crt objects */ @@ -1010,16 +1011,15 @@ LIBTCCAPI TCCState *tcc_new(void) ".dynhashtab", SHF_PRIVATE); s->alacarte_link = 1; s->nocommon = 1; + s->section_align = ELF_PAGE_SIZE; #ifdef CHAR_IS_UNSIGNED s->char_is_unsigned = 1; #endif /* enable this if you want symbols with leading underscore on windows: */ -#if defined(TCC_TARGET_PE) && 0 +#if 0 //def TCC_TARGET_PE s->leading_underscore = 1; #endif - if (s->section_align == 0) - s->section_align = ELF_PAGE_SIZE; #ifdef TCC_TARGET_I386 s->seg_size = 32; #endif @@ -1060,16 +1060,25 @@ LIBTCCAPI void tcc_delete(TCCState *s1) dynarray_reset(&s1->include_paths, &s1->nb_include_paths); dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); - dynarray_reset(&s1->target_deps, &s1->nb_target_deps); - tcc_free(s1->tcc_lib_path); + tcc_free(s1->soname); + tcc_free(s1->rpath); + tcc_free(s1->init_symbol); + tcc_free(s1->fini_symbol); + tcc_free(s1->outfile); + tcc_free(s1->deps_outfile); + dynarray_reset(&s1->files, &s1->nb_files); + dynarray_reset(&s1->target_deps, &s1->nb_target_deps); -#ifdef HAVE_SELINUX +#ifdef TCC_IS_NATIVE +# ifdef HAVE_SELINUX munmap (s1->write_mem, s1->mem_size); munmap (s1->runtime_mem, s1->mem_size); -#else +# else tcc_free(s1->runtime_mem); +# endif #endif + tcc_free(s1); } @@ -1236,7 +1245,6 @@ static int tcc_add_library_internal(TCCState *s, const char *fmt, return -1; } -#ifndef TCC_TARGET_PE /* find and load a dll. Return non zero if not found */ /* XXX: add '-rpath' option support ? */ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) @@ -1244,7 +1252,6 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) return tcc_add_library_internal(s, "%s/%s", filename, flags, s->library_paths, s->nb_library_paths); } -#endif ST_FUNC int tcc_add_crt(TCCState *s, const char *filename) { @@ -1276,11 +1283,15 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val) { #ifdef TCC_TARGET_PE -pe_putimport(s, 0, name, (uintptr_t)val); + /* On x86_64 'val' might not be reachable with a 32bit offset. + So it is handled here as if it were in a DLL. */ + pe_putimport(s, 0, name, (uintptr_t)val); #else -add_elf_sym(symtab_section, (uintptr_t)val, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_ABS, name); + /* XXX: Same problem on linux but currently "solved" elsewhere + via the rather dirty 'runtime_plt_and_got' hack. */ + add_elf_sym(symtab_section, (uintptr_t)val, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_ABS, name); #endif return 0; } @@ -1341,6 +1352,12 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) return 0; } +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) +{ + tcc_free(s->tcc_lib_path); + s->tcc_lib_path = tcc_strdup(path); +} + #define WD_ALL 0x0001 /* warning is activated when using -Wall */ #define FD_INVERT 0x0002 /* invert value before storing */ @@ -1382,14 +1399,8 @@ ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, return 0; } -/* enable debug */ -LIBTCCAPI void tcc_enable_debug(TCCState *s) -{ - s->do_debug = 1; -} - /* set/reset a warning */ -LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value) +static int tcc_set_warning(TCCState *s, const char *warning_name, int value) { int i; const FlagDef *p; @@ -1414,30 +1425,28 @@ static const FlagDef flag_defs[] = { }; /* set/reset a flag */ -PUB_FUNC int tcc_set_flag(TCCState *s, const char *flag_name, int value) +static int tcc_set_flag(TCCState *s, const char *flag_name, int value) { return set_flag(s, flag_defs, countof(flag_defs), flag_name, value); } -static int strstart(const char *str, const char *val, char **ptr) +static int strstart(const char *val, const char **str) { const char *p, *q; - p = str; + p = *str; q = val; - while (*q != '\0') { + while (*q) { if (*p != *q) return 0; p++; q++; } - if (ptr) - *ptr = (char *) p; + *str = p; return 1; } - /* Like strstart, but automatically takes into account that ld options can * * - start with double or single dash (e.g. '--soname' or '-soname') @@ -1446,7 +1455,7 @@ static int strstart(const char *str, const char *val, char **ptr) * * you provide `val` always in 'option[=]' form (no leading -) */ -static int link_option(const char *str, const char *val, char **ptr) +static int link_option(const char *str, const char *val, const char **ptr) { const char *p, *q; @@ -1476,64 +1485,72 @@ static int link_option(const char *str, const char *val, char **ptr) } if (ptr) - *ptr = (char *) p; + *ptr = p; return 1; } +static const char *skip_linker_arg(const char **str) +{ + const char *s1 = *str; + const char *s2 = strchr(s1, ','); + *str = s2 ? s2++ : (s2 = s1 + strlen(s1)); + return s2; +} -/* set linker options */ -PUB_FUNC const char * tcc_set_linker(TCCState *s, char *option, int multi) +static char *copy_linker_arg(const char *p) { - char *p = option; - char *end; + const char *q = p; + skip_linker_arg(&q); + return pstrncpy(tcc_malloc(q - p + 1), p, q - p); +} +/* set linker options */ +static int tcc_set_linker(TCCState *s, const char *option) +{ while (option && *option) { - end = NULL; + + const char *p = option; + char *end = NULL; + int ignoring = 0; + if (link_option(option, "Bsymbolic", &p)) { s->symbolic = 1; } else if (link_option(option, "nostdlib", &p)) { s->nostdlib = 1; } else if (link_option(option, "fini=", &p)) { - s->fini_symbol = p; - if (s->warn_unsupported) - tcc_warning("ignoring -fini %s", p); - } else if (link_option(option, "image-base=", &p)) { + s->fini_symbol = copy_linker_arg(p); + ignoring = 1; + } else if (link_option(option, "image-base=", &p) + || link_option(option, "Ttext=", &p)) { s->text_addr = strtoull(p, &end, 16); s->has_text_addr = 1; } else if (link_option(option, "init=", &p)) { - s->init_symbol = p; - if (s->warn_unsupported) - tcc_warning("ignoring -init %s", p); + s->init_symbol = copy_linker_arg(p); + ignoring = 1; } else if (link_option(option, "oformat=", &p)) { #if defined(TCC_TARGET_PE) - if (strstart(p, "pe-", NULL)) { -#else -#if defined(TCC_TARGET_X86_64) - if (strstart(p, "elf64-", NULL)) { + if (strstart("pe-", &p)) { +#elif defined(TCC_TARGET_X86_64) + if (strstart("elf64-", &p)) { #else - if (strstart(p, "elf32-", NULL)) { -#endif + if (strstart("elf32-", &p)) { #endif s->output_format = TCC_OUTPUT_FORMAT_ELF; } else if (!strcmp(p, "binary")) { s->output_format = TCC_OUTPUT_FORMAT_BINARY; - } else #ifdef TCC_TARGET_COFF - if (!strcmp(p, "coff")) { + } else if (!strcmp(p, "coff")) { s->output_format = TCC_OUTPUT_FORMAT_COFF; - } else #endif - { - return p; - } + } else + goto err; } else if (link_option(option, "rpath=", &p)) { - s->rpath = p; + s->rpath = copy_linker_arg(p); } else if (link_option(option, "section-alignment=", &p)) { s->section_align = strtoul(p, &end, 16); } else if (link_option(option, "soname=", &p)) { - s->soname = p; - multi = 0; + s->soname = copy_linker_arg(p); #ifdef TCC_TARGET_PE } else if (link_option(option, "file-alignment=", &p)) { s->pe_file_align = strtoul(p, &end, 16); @@ -1561,98 +1578,346 @@ PUB_FUNC const char * tcc_set_linker(TCCState *s, char *option, int multi) if (!strcmp(p, "wince")) { s->pe_subsystem = 9; #endif - } else { - return p; - } + } else + goto err; #endif - - } else if (link_option(option, "Ttext=", &p)) { - s->text_addr = strtoull(p, &end, 16); - s->has_text_addr = 1; - } else { - char *comma_ptr = strchr(option, ','); - if (comma_ptr) - *comma_ptr = '\0'; - return option; - } - - if (multi) { - option = NULL; - p = strchr( (end) ? end : p, ','); - if (p) { - *p = 0; /* terminate last option */ - option = ++p; - } } else - option = NULL; + goto err; + + if (ignoring && s->warn_unsupported) err: { + char buf[100], *e; + pstrcpy(buf, sizeof buf, e = copy_linker_arg(option)), tcc_free(e); + if (ignoring) + tcc_warning("unsupported linker option '%s'", buf); + else + tcc_error("unsupported linker option '%s'", buf); + } + option = skip_linker_arg(&p); } - return NULL; + return 0; } -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) +typedef struct TCCOption { + const char *name; + uint16_t index; + uint16_t flags; +} TCCOption; + +enum { + TCC_OPTION_HELP, + TCC_OPTION_I, + TCC_OPTION_D, + TCC_OPTION_U, + TCC_OPTION_L, + TCC_OPTION_B, + TCC_OPTION_l, + TCC_OPTION_bench, + TCC_OPTION_bt, + TCC_OPTION_b, + TCC_OPTION_g, + TCC_OPTION_c, + TCC_OPTION_static, + TCC_OPTION_shared, + TCC_OPTION_soname, + TCC_OPTION_o, + TCC_OPTION_r, + TCC_OPTION_s, + TCC_OPTION_Wl, + TCC_OPTION_W, + TCC_OPTION_O, + TCC_OPTION_m, + TCC_OPTION_f, + TCC_OPTION_isystem, + TCC_OPTION_nostdinc, + TCC_OPTION_nostdlib, + TCC_OPTION_print_search_dirs, + TCC_OPTION_rdynamic, + TCC_OPTION_pedantic, + TCC_OPTION_pthread, + TCC_OPTION_run, + TCC_OPTION_v, + TCC_OPTION_w, + TCC_OPTION_pipe, + TCC_OPTION_E, + TCC_OPTION_MD, + TCC_OPTION_MF, + TCC_OPTION_x, +}; + +#define TCC_OPTION_HAS_ARG 0x0001 +#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ + +static const TCCOption tcc_options[] = { + { "h", TCC_OPTION_HELP, 0 }, + { "-help", TCC_OPTION_HELP, 0 }, + { "?", TCC_OPTION_HELP, 0 }, + { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, + { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, + { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, + { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, + { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, + { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "bench", TCC_OPTION_bench, 0 }, +#ifdef CONFIG_TCC_BACKTRACE + { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, +#endif +#ifdef CONFIG_TCC_BCHECK + { "b", TCC_OPTION_b, 0 }, +#endif + { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "c", TCC_OPTION_c, 0 }, + { "static", TCC_OPTION_static, 0 }, + { "shared", TCC_OPTION_shared, 0 }, + { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG }, + { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, + { "pedantic", TCC_OPTION_pedantic, 0}, + { "pthread", TCC_OPTION_pthread, 0}, + { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "rdynamic", TCC_OPTION_rdynamic, 0 }, + { "r", TCC_OPTION_r, 0 }, + { "s", TCC_OPTION_s, 0 }, + { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, + { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG }, + { "nostdinc", TCC_OPTION_nostdinc, 0 }, + { "nostdlib", TCC_OPTION_nostdlib, 0 }, + { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, + { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "w", TCC_OPTION_w, 0 }, + { "pipe", TCC_OPTION_pipe, 0}, + { "E", TCC_OPTION_E, 0}, + { "MD", TCC_OPTION_MD, 0}, + { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, + { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, + { NULL, 0, 0 }, +}; + +static void parse_option_D(TCCState *s1, const char *optarg) { - tcc_free(s->tcc_lib_path); - s->tcc_lib_path = tcc_strdup(path); + char *sym = tcc_strdup(optarg); + char *value = strchr(sym, '='); + if (value) + *value++ = '\0'; + tcc_define_symbol(s1, sym, value); + tcc_free(sym); } -PUB_FUNC char *tcc_default_target(TCCState *s, const char *default_file) +PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) { - char buf[1024]; - char *ext; - const char *name = "a"; + const TCCOption *popt; + const char *optarg, *r; + int run = 0; + int pthread = 0; + int optind = 0; - if (default_file && strcmp(default_file, "-")) - name = tcc_basename(default_file); - pstrcpy(buf, sizeof(buf), name); - ext = tcc_fileextension(buf); -#ifdef TCC_TARGET_PE - if (s->output_type == TCC_OUTPUT_DLL) - strcpy(ext, ".dll"); - else - if (s->output_type == TCC_OUTPUT_EXE) - strcpy(ext, ".exe"); - else -#endif - if (( (s->output_type == TCC_OUTPUT_OBJ && !s->reloc_output) || - (s->output_type == TCC_OUTPUT_PREPROCESS) ) - && *ext) - strcpy(ext, ".o"); - else - strcpy(buf, "a.out"); + /* collect -Wl options for input such as "-Wl,-rpath -Wl," */ + CString linker_arg; + cstr_new(&linker_arg); - return tcc_strdup(buf); -} + while (optind < argc) { + r = argv[optind++]; + if (r[0] != '-' || r[1] == '\0') { + /* add a new file */ + dynarray_add((void ***)&s->files, &s->nb_files, tcc_strdup(r)); + if (run) { + optind--; + /* argv[0] will be this file */ + break; + } + continue; + } -PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename) -{ - FILE *depout; - char buf[1024], *ext; - int i; + /* find option in table */ + for(popt = tcc_options; ; ++popt) { + const char *p1 = popt->name; + const char *r1 = r + 1; + if (p1 == NULL) + tcc_error("invalid option -- '%s'", r); + if (!strstart(p1, &r1)) + continue; + optarg = r1; + if (popt->flags & TCC_OPTION_HAS_ARG) { + if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) { + if (optind >= argc) + tcc_error("argument to '%s' is missing", r); + optarg = argv[optind++]; + } + } else if (*r1 != '\0') + continue; + break; + } - if (!filename) { - /* compute filename automatically - * dir/file.o -> dir/file.d */ - pstrcpy(buf, sizeof(buf), target); - ext = tcc_fileextension(buf); - pstrcpy(ext, sizeof(buf) - (ext-buf), ".d"); - filename = buf; + switch(popt->index) { + case TCC_OPTION_HELP: + return 0; + case TCC_OPTION_I: + if (tcc_add_include_path(s, optarg) < 0) + tcc_error("too many include paths"); + break; + case TCC_OPTION_D: + parse_option_D(s, optarg); + break; + case TCC_OPTION_U: + tcc_undefine_symbol(s, optarg); + break; + case TCC_OPTION_L: + tcc_add_library_path(s, optarg); + break; + case TCC_OPTION_B: + /* set tcc utilities path (mainly for tcc development) */ + tcc_set_lib_path(s, optarg); + break; + case TCC_OPTION_l: + dynarray_add((void ***)&s->files, &s->nb_files, tcc_strdup(r)); + s->nb_libraries++; + break; + case TCC_OPTION_pthread: + parse_option_D(s, "_REENTRANT"); + pthread = 1; + break; + case TCC_OPTION_bench: + s->do_bench = 1; + break; +#ifdef CONFIG_TCC_BACKTRACE + case TCC_OPTION_bt: + tcc_set_num_callers(atoi(optarg)); + break; +#endif +#ifdef CONFIG_TCC_BCHECK + case TCC_OPTION_b: + s->do_bounds_check = 1; + s->do_debug = 1; + break; +#endif + case TCC_OPTION_g: + s->do_debug = 1; + break; + case TCC_OPTION_c: + s->output_type = TCC_OUTPUT_OBJ; + break; + case TCC_OPTION_static: + s->static_link = 1; + break; + case TCC_OPTION_shared: + s->output_type = TCC_OUTPUT_DLL; + break; + case TCC_OPTION_soname: + s->soname = tcc_strdup(optarg); + break; + case TCC_OPTION_m: + s->option_m = tcc_strdup(optarg); + break; + case TCC_OPTION_o: + s->outfile = tcc_strdup(optarg); + break; + case TCC_OPTION_r: + /* generate a .o merging several output files */ + s->option_r = 1; + s->output_type = TCC_OUTPUT_OBJ; + break; + case TCC_OPTION_isystem: + tcc_add_sysinclude_path(s, optarg); + break; + case TCC_OPTION_nostdinc: + s->nostdinc = 1; + break; + case TCC_OPTION_nostdlib: + s->nostdlib = 1; + break; + case TCC_OPTION_print_search_dirs: + s->print_search_dirs = 1; + break; + case TCC_OPTION_run: + s->output_type = TCC_OUTPUT_MEMORY; + tcc_set_options(s, optarg); + run = 1; + break; + case TCC_OPTION_v: + do ++s->verbose; while (*optarg++ == 'v'); + break; + case TCC_OPTION_f: + if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) + goto unsupported_option; + break; + case TCC_OPTION_W: + if (tcc_set_warning(s, optarg, 1) < 0 && + s->warn_unsupported) + goto unsupported_option; + break; + case TCC_OPTION_w: + s->warn_none = 1; + break; + case TCC_OPTION_rdynamic: + s->rdynamic = 1; + break; + case TCC_OPTION_Wl: + if (linker_arg.size) + --linker_arg.size, cstr_ccat(&linker_arg, ','); + cstr_cat(&linker_arg, optarg); + cstr_ccat(&linker_arg, '\0'); + break; + case TCC_OPTION_E: + s->output_type = TCC_OUTPUT_PREPROCESS; + break; + case TCC_OPTION_MD: + s->gen_deps = 1; + break; + case TCC_OPTION_MF: + s->deps_outfile = tcc_strdup(optarg); + break; + case TCC_OPTION_O: + case TCC_OPTION_pedantic: + case TCC_OPTION_pipe: + case TCC_OPTION_s: + case TCC_OPTION_x: + /* ignored */ + break; + default: + if (s->warn_unsupported) { + unsupported_option: + tcc_warning("unsupported option '%s'", r); + } + break; + } } - if (s->verbose) - printf("<- %s\n", filename); + if (pthread && s->output_type != TCC_OUTPUT_OBJ) + tcc_set_options(s, "-lpthread"); - /* XXX return err codes instead of error() ? */ - depout = fopen(filename, "w"); - if (!depout) - tcc_error("could not open '%s'", filename); + tcc_set_linker(s, (const char *)linker_arg.data); + cstr_free(&linker_arg); - fprintf(depout, "%s : \\\n", target); - for (i=0; inb_target_deps; ++i) - fprintf(depout, " %s \\\n", s->target_deps[i]); - fprintf(depout, "\n"); - fclose(depout); + return optind; +} + +LIBTCCAPI int tcc_set_options(TCCState *s, const char *str) +{ + const char *s1; + char **argv, *arg; + int argc, len; + int ret; + + argc = 0, argv = NULL; + for(;;) { + while (is_space(*str)) + str++; + if (*str == '\0') + break; + s1 = str; + while (*str != '\0' && !is_space(*str)) + str++; + len = str - s1; + arg = tcc_malloc(len + 1); + pstrncpy(arg, s1, len); + dynarray_add((void ***)&argv, &argc, arg); + } + ret = tcc_parse_args(s, argc, argv); + dynarray_reset(&argv, &argc); + return ret; } PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time) @@ -1668,53 +1933,3 @@ PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time) tt, (int)(total_lines / tt), total_bytes / tt / 1000000.0); } - -static void print_paths(const char *msg, char **paths, int nb_paths) -{ - int i; - printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); - for(i = 0; i < nb_paths; i++) - printf(" %s\n", paths[i]); -} - -PUB_FUNC void tcc_display_info(TCCState *s, int what) -{ - switch (what) { - case 0: - printf("tcc version %s (" -#ifdef TCC_TARGET_I386 - "i386" -# ifdef TCC_TARGET_PE - " Win32" -# endif -#elif defined TCC_TARGET_X86_64 - "x86-64" -# ifdef TCC_TARGET_PE - " Win64" -# endif -#elif defined TCC_TARGET_ARM - "ARM" -# ifdef TCC_ARM_HARDFLOAT - " Hard Float" -# endif -# ifdef TCC_TARGET_PE - " WinCE" -# endif -#endif -#ifndef TCC_TARGET_PE -# ifdef __linux - " Linux" -# endif -#endif - ")\n", TCC_VERSION); - break; - case 1: - printf("install: %s/\n", s->tcc_lib_path); - /* print_paths("programs", NULL, 0); */ - print_paths("crt", s->crt_paths, s->nb_crt_paths); - print_paths("libraries", s->library_paths, s->nb_library_paths); - print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths); - break; - } -} - diff --git a/libtcc.h b/libtcc.h index 278dca30..e69cc6b3 100644 --- a/libtcc.h +++ b/libtcc.h @@ -19,18 +19,15 @@ LIBTCCAPI TCCState *tcc_new(void); /* free a TCC compilation context */ LIBTCCAPI void tcc_delete(TCCState *s); -/* add debug information in the generated code */ -LIBTCCAPI void tcc_enable_debug(TCCState *s); +/* set CONFIG_TCCDIR at runtime */ +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); /* set error/warning display callback */ LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, - void (*error_func)(void *opaque, const char *msg)); - -/* set/reset a warning */ -LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value); + void (*error_func)(void *opaque, const char *msg)); -/* set linker option */ -LIBTCCAPI const char * tcc_set_linker(TCCState *s, char *option, int multi); +/* set options as from command line (multiple supported) */ +LIBTCCAPI int tcc_set_options(TCCState *s, const char *str); /*****************************/ /* preprocessor */ @@ -50,29 +47,22 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); /*****************************/ /* compiling */ -/* add a file (either a C file, dll, an object, a library or an ld - script). Return -1 if error. */ +/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); -/* compile a string containing a C source. Return non zero if - error. */ +/* compile a string containing a C source. Return -1 if error. */ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); /*****************************/ /* linking commands */ /* set output type. MUST BE CALLED before any compilation */ -#define TCC_OUTPUT_MEMORY 0 /* output will be ran in memory (no - output file) (default) */ +LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); +#define TCC_OUTPUT_MEMORY 0 /* output will be run in memory (default) */ #define TCC_OUTPUT_EXE 1 /* executable file */ #define TCC_OUTPUT_DLL 2 /* dynamic library */ #define TCC_OUTPUT_OBJ 3 /* object file */ -#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */ -LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); - -#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ -#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ -#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ +#define TCC_OUTPUT_PREPROCESS 4 /* only preprocess (used internally) */ /* equivalent to -Lpath option */ LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); @@ -91,21 +81,18 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); tcc_relocate() before. */ LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); -/* do all relocations (needed before using tcc_get_symbol()) - possible values for 'ptr': +/* do all relocations (needed before using tcc_get_symbol()) */ +LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); +/* possible values for 'ptr': - TCC_RELOCATE_AUTO : Allocate and manage memory internally - NULL : return required memory size for the step below - memory address : copy code to memory passed by the caller - returns -1 on error. */ -LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); + returns -1 if error. */ #define TCC_RELOCATE_AUTO (void*)1 /* return symbol value or NULL if not found */ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); -/* set CONFIG_TCCDIR at runtime */ -LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); - #ifdef __cplusplus } #endif diff --git a/tcc.c b/tcc.c dissimilarity index 66% index 7fabe8b7..f4ff3f84 100644 --- a/tcc.c +++ b/tcc.c @@ -1,628 +1,350 @@ -/* - * TCC - Tiny C Compiler - * - * Copyright (c) 2001-2004 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef ONE_SOURCE -#include "libtcc.c" -#else -#include "tcc.h" -#endif - -static char **files; -static int nb_files, nb_libraries; -static int multiple_files; -static int print_search_dirs; -static int output_type; -static int reloc_output; -static char *outfile; -static int do_bench = 0; -static int gen_deps; -static const char *deps_outfile; -static const char *m_option; -static CString linker_arg; - -#define TCC_OPTION_HAS_ARG 0x0001 -#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ - -static void help(void) -{ - printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n" - "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" - " tcc [options...] -run infile [arguments...]\n" - "General options:\n" - " -c compile only - generate an object file\n" - " -o outfile set output filename\n" - " -run run compiled source\n" - " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" - " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" - " -w disable all warnings\n" - " -v show version\n" - " -vv show included files (as sole argument: show search paths)\n" - " -bench show compilation statistics\n" - "Preprocessor options:\n" - " -E preprocess only\n" - " -Idir add include path 'dir'\n" - " -Dsym[=val] define 'sym' with value 'val'\n" - " -Usym undefine 'sym'\n" - " -nostdinc do not use standard system include paths\n" - "Linker options:\n" - " -Ldir add library path 'dir'\n" - " -llib link with dynamic or static library 'lib'\n" - " -Bdir use 'dir' as tcc internal library and include path\n" - " -nostdlib do not link with standard crt and libraries\n" - " -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n" - " -r generate (relocatable) object file\n" - " -rdynamic export all global symbols to dynamic linker\n" - " -shared generate a shared library\n" - " -soname set name for shared library to be used at runtime\n" - " -static static linking\n" - " -Wl,opt[=val] set linker option 'opt' (see manual)\n" - "Debugger options:\n" - " -g generate runtime debug info\n" -#ifdef CONFIG_TCC_BCHECK - " -b compile with built-in memory and bounds checker (implies -g)\n" -#endif -#ifdef CONFIG_TCC_BACKTRACE - " -bt N show N callers in stack traces\n" -#endif - "Misc options:\n" - " -MD generate target dependencies for make\n" - " -MF depfile put generated dependencies here\n" - ); -} - -typedef struct TCCOption { - const char *name; - uint16_t index; - uint16_t flags; -} TCCOption; - -enum { - TCC_OPTION_HELP, - TCC_OPTION_I, - TCC_OPTION_D, - TCC_OPTION_U, - TCC_OPTION_L, - TCC_OPTION_B, - TCC_OPTION_l, - TCC_OPTION_bench, - TCC_OPTION_bt, - TCC_OPTION_b, - TCC_OPTION_g, - TCC_OPTION_c, - TCC_OPTION_static, - TCC_OPTION_shared, - TCC_OPTION_soname, - TCC_OPTION_o, - TCC_OPTION_r, - TCC_OPTION_s, - TCC_OPTION_Wl, - TCC_OPTION_W, - TCC_OPTION_O, - TCC_OPTION_m, - TCC_OPTION_f, - TCC_OPTION_isystem, - TCC_OPTION_nostdinc, - TCC_OPTION_nostdlib, - TCC_OPTION_print_search_dirs, - TCC_OPTION_rdynamic, - TCC_OPTION_pedantic, - TCC_OPTION_pthread, - TCC_OPTION_run, - TCC_OPTION_v, - TCC_OPTION_w, - TCC_OPTION_pipe, - TCC_OPTION_E, - TCC_OPTION_MD, - TCC_OPTION_MF, - TCC_OPTION_x, -}; - -static const TCCOption tcc_options[] = { - { "h", TCC_OPTION_HELP, 0 }, - { "-help", TCC_OPTION_HELP, 0 }, - { "?", TCC_OPTION_HELP, 0 }, - { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, - { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, - { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, - { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, - { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, - { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "bench", TCC_OPTION_bench, 0 }, -#ifdef CONFIG_TCC_BACKTRACE - { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, -#endif -#ifdef CONFIG_TCC_BCHECK - { "b", TCC_OPTION_b, 0 }, -#endif - { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "c", TCC_OPTION_c, 0 }, - { "static", TCC_OPTION_static, 0 }, - { "shared", TCC_OPTION_shared, 0 }, - { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG }, - { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, - { "pedantic", TCC_OPTION_pedantic, 0}, - { "pthread", TCC_OPTION_pthread, 0}, - { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "rdynamic", TCC_OPTION_rdynamic, 0 }, - { "r", TCC_OPTION_r, 0 }, - { "s", TCC_OPTION_s, 0 }, - { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, - { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG }, - { "nostdinc", TCC_OPTION_nostdinc, 0 }, - { "nostdlib", TCC_OPTION_nostdlib, 0 }, - { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, - { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, - { "w", TCC_OPTION_w, 0 }, - { "pipe", TCC_OPTION_pipe, 0}, - { "E", TCC_OPTION_E, 0}, - { "MD", TCC_OPTION_MD, 0}, - { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, - { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, - { NULL, 0, 0 }, -}; - -static int64_t getclock_us(void) -{ -#ifdef _WIN32 - struct _timeb tb; - _ftime(&tb); - return (tb.time * 1000LL + tb.millitm) * 1000LL; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000LL + tv.tv_usec; -#endif -} - -/* convert 'str' into an array of space separated strings */ -static int expand_args(char ***pargv, const char *str) -{ - const char *s1; - char **argv, *arg; - int argc, len; - - argc = 0; - argv = NULL; - for(;;) { - while (is_space(*str)) - str++; - if (*str == '\0') - break; - s1 = str; - while (*str != '\0' && !is_space(*str)) - str++; - len = str - s1; - arg = tcc_malloc(len + 1); - memcpy(arg, s1, len); - arg[len] = '\0'; - dynarray_add((void ***)&argv, &argc, arg); - } - *pargv = argv; - return argc; -} - -/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ -#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 -#ifdef _WIN32 -#include -static int execvp_win32(const char *prog, char **argv) -{ - int ret = spawnvp(P_NOWAIT, prog, (char const*const*)argv); - if (-1 == ret) - return ret; - cwait(&ret, ret, WAIT_CHILD); - exit(ret); -} -#define execvp execvp_win32 -#endif -static void exec_other_tcc(TCCState *s, char **argv, const char *optarg) -{ - char child_path[4096], *child_name; const char *target; - switch (atoi(optarg)) { -#ifdef TCC_TARGET_I386 - case 32: break; - case 64: target = "x86_64"; -#else - case 64: break; - case 32: target = "i386"; -#endif - pstrcpy(child_path, sizeof child_path - 40, argv[0]); - child_name = tcc_basename(child_path); - strcpy(child_name, target); -#ifdef TCC_TARGET_PE - strcat(child_name, "-win32"); -#endif - strcat(child_name, "-tcc"); - if (strcmp(argv[0], child_path)) { - if (s->verbose > 0) - printf("tcc: using '%s'\n", child_name), fflush(stdout); - execvp(argv[0] = child_path, argv); - } - tcc_error("'%s' not found", child_name); - case 0: /* ignore -march etc. */ - break; - default: - tcc_warning("unsupported option \"-m%s\"", optarg); - } -} -#endif - -static void parse_option_D(TCCState *s1, const char *optarg) -{ - char *sym = tcc_strdup(optarg); - char *value = strchr(sym, '='); - if (value) - *value++ = '\0'; - tcc_define_symbol(s1, sym, value); - tcc_free(sym); -} - -static int parse_args(TCCState *s, int argc, char **argv) -{ - int optind; - const TCCOption *popt; - const char *optarg, *p1, *r1; - char *r; - int was_pthread; - - was_pthread = 0; /* is set if commandline contains -pthread key */ - optind = 0; - cstr_new(&linker_arg); - - while (optind < argc) { - - r = argv[optind++]; - if (r[0] != '-' || r[1] == '\0') { - /* add a new file */ - dynarray_add((void ***)&files, &nb_files, r); - if (!multiple_files) { - optind--; - /* argv[0] will be this file */ - break; - } - } else { - /* find option in table (match only the first chars */ - popt = tcc_options; - for(;;) { - p1 = popt->name; - if (p1 == NULL) - tcc_error("invalid option -- '%s'", r); - r1 = r + 1; - for(;;) { - if (*p1 == '\0') - goto option_found; - if (*r1 != *p1) - break; - p1++; - r1++; - } - popt++; - } - option_found: - if (popt->flags & TCC_OPTION_HAS_ARG) { - if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) { - optarg = r1; - } else { - if (optind >= argc) - tcc_error("argument to '%s' is missing", r); - optarg = argv[optind++]; - } - } else { - if (*r1 != '\0') - return 0; - optarg = NULL; - } - - switch(popt->index) { - case TCC_OPTION_HELP: - return 0; - - case TCC_OPTION_I: - if (tcc_add_include_path(s, optarg) < 0) - tcc_error("too many include paths"); - break; - case TCC_OPTION_D: - parse_option_D(s, optarg); - break; - case TCC_OPTION_U: - tcc_undefine_symbol(s, optarg); - break; - case TCC_OPTION_L: - tcc_add_library_path(s, optarg); - break; - case TCC_OPTION_B: - /* set tcc utilities path (mainly for tcc development) */ - tcc_set_lib_path(s, optarg); - break; - case TCC_OPTION_l: - dynarray_add((void ***)&files, &nb_files, r); - nb_libraries++; - break; - case TCC_OPTION_pthread: - was_pthread = 1; - parse_option_D(s, "_REENTRANT"); - break; - case TCC_OPTION_bench: - do_bench = 1; - break; -#ifdef CONFIG_TCC_BACKTRACE - case TCC_OPTION_bt: - tcc_set_num_callers(atoi(optarg)); - break; -#endif -#ifdef CONFIG_TCC_BCHECK - case TCC_OPTION_b: - s->do_bounds_check = 1; - s->do_debug = 1; - break; -#endif - case TCC_OPTION_g: - s->do_debug = 1; - break; - case TCC_OPTION_c: - multiple_files = 1; - output_type = TCC_OUTPUT_OBJ; - break; - case TCC_OPTION_static: - s->static_link = 1; - break; - case TCC_OPTION_shared: - output_type = TCC_OUTPUT_DLL; - break; - case TCC_OPTION_soname: - s->soname = optarg; - break; - case TCC_OPTION_m: - m_option = optarg; - break; - case TCC_OPTION_o: - multiple_files = 1; - outfile = tcc_strdup(optarg); - break; - case TCC_OPTION_r: - /* generate a .o merging several output files */ - reloc_output = 1; - output_type = TCC_OUTPUT_OBJ; - break; - case TCC_OPTION_isystem: - tcc_add_sysinclude_path(s, optarg); - break; - case TCC_OPTION_nostdinc: - s->nostdinc = 1; - break; - case TCC_OPTION_nostdlib: - s->nostdlib = 1; - break; - case TCC_OPTION_print_search_dirs: - print_search_dirs = 1; - break; - case TCC_OPTION_run: - { - int argc1; - char **argv1; - argc1 = expand_args(&argv1, optarg); - if (argc1 > 0) { - parse_args(s, argc1, argv1); - } - multiple_files = 0; - output_type = TCC_OUTPUT_MEMORY; - break; - } - case TCC_OPTION_v: - do ++s->verbose; while (*optarg++ == 'v'); - break; - case TCC_OPTION_f: - if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) - goto unsupported_option; - break; - case TCC_OPTION_W: - if (tcc_set_warning(s, optarg, 1) < 0 && - s->warn_unsupported) - goto unsupported_option; - break; - case TCC_OPTION_w: - s->warn_none = 1; - break; - case TCC_OPTION_rdynamic: - s->rdynamic = 1; - break; - case TCC_OPTION_Wl: - if (linker_arg.size) - --linker_arg.size, cstr_ccat(&linker_arg, ','); - cstr_cat(&linker_arg, optarg); - cstr_ccat(&linker_arg, '\0'); - break; - case TCC_OPTION_E: - output_type = TCC_OUTPUT_PREPROCESS; - break; - case TCC_OPTION_MD: - gen_deps = 1; - break; - case TCC_OPTION_MF: - deps_outfile = optarg; - break; - case TCC_OPTION_O: - case TCC_OPTION_pedantic: - case TCC_OPTION_pipe: - case TCC_OPTION_s: - case TCC_OPTION_x: - /* ignored */ - break; - default: - if (s->warn_unsupported) { - unsupported_option: - tcc_warning("unsupported option '%s'", r); - } - break; - } - } - } - if (NULL != (r1 = tcc_set_linker(s, (char *) linker_arg.data, 1))) - tcc_error("unsupported linker option '%s'", r1); - /* fixme: these options could be different on your platform */ - if (was_pthread && output_type != TCC_OUTPUT_OBJ) { - dynarray_add((void ***)&files, &nb_files, "-lpthread"); - nb_libraries++; - } - return optind; -} - -int main(int argc, char **argv) -{ - int i; - TCCState *s; - int nb_objfiles, ret, optind; - int64_t start_time = 0; - const char *default_file = NULL; - - s = tcc_new(); - - output_type = TCC_OUTPUT_EXE; - outfile = NULL; - multiple_files = 1; - files = NULL; - nb_files = 0; - nb_libraries = 0; - reloc_output = 0; - print_search_dirs = 0; - m_option = NULL; - ret = 0; - - optind = parse_args(s, argc - 1, argv + 1); - -#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386 - if (m_option) - exec_other_tcc(s, argv, m_option); -#endif - - if (print_search_dirs) { -psd: - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - tcc_display_info(s, 1); - return 0; - } - - if (s->verbose) - tcc_display_info(s, 0); - - if (optind == 0 || nb_files == 0) { - if (optind && s->verbose) { - if (s->verbose == 2) - goto psd; - return 0; - } - help(); - return 1; - } - - nb_objfiles = nb_files - nb_libraries; - - /* if outfile provided without other options, we output an - executable */ - if (outfile && output_type == TCC_OUTPUT_MEMORY) - output_type = TCC_OUTPUT_EXE; - - /* check -c consistency : only single file handled. XXX: checks file type */ - if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { - /* accepts only a single input file */ - if (nb_objfiles != 1) - tcc_error("cannot specify multiple files with -c"); - if (nb_libraries != 0) - tcc_error("cannot specify libraries with -c"); - } - - if (output_type == TCC_OUTPUT_PREPROCESS) { - if (!outfile) { - s->outfile = stdout; - } else { - s->outfile = fopen(outfile, "w"); - if (!s->outfile) - tcc_error("could not open '%s'", outfile); - } - } - - if (do_bench) { - start_time = getclock_us(); - } - - tcc_set_output_type(s, output_type); - s->reloc_output = reloc_output; - - /* compile or add each files or library */ - for(i = 0; i < nb_files && ret == 0; i++) { - const char *filename; - - filename = files[i]; - if (filename[0] == '-' && filename[1] == 'l') { - if (tcc_add_library(s, filename + 2) < 0) { - tcc_error_noabort("cannot find %s", filename); - ret = 1; - } - } else { - if (1 == s->verbose) - printf("-> %s\n", filename); - if (tcc_add_file(s, filename) < 0) - ret = 1; - if (!default_file) - default_file = filename; - } - } - - /* free all files */ - tcc_free(files); - - if (0 == ret) { - if (do_bench) - tcc_print_stats(s, getclock_us() - start_time); - - if (s->output_type == TCC_OUTPUT_MEMORY) { -#ifdef TCC_IS_NATIVE - ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); -#else - tcc_error_noabort("-run is not available in a cross compiler"); -#endif - } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { - if (s->outfile) - fclose(s->outfile); - } else { - if (!outfile) - outfile = tcc_default_target(s, default_file); - ret = !!tcc_output_file(s, outfile); - /* dump collected dependencies */ - if (gen_deps && !ret) - tcc_gen_makedeps(s, outfile, deps_outfile); - } - } - - tcc_delete(s); - cstr_free(&linker_arg); - tcc_free(outfile); - -#ifdef MEM_DEBUG - if (do_bench) { - printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); - } -#endif - return ret; -} +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef ONE_SOURCE +#include "libtcc.c" +#else +#include "tcc.h" +#endif + +static void help(void) +{ + printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n" + "Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" + " tcc [options...] -run infile [arguments...]\n" + "General options:\n" + " -c compile only - generate an object file\n" + " -o outfile set output filename\n" + " -run run compiled source\n" + " -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" + " -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" + " -w disable all warnings\n" + " -v show version\n" + " -vv show included files (as sole argument: show search paths)\n" + " -bench show compilation statistics\n" + "Preprocessor options:\n" + " -E preprocess only\n" + " -Idir add include path 'dir'\n" + " -Dsym[=val] define 'sym' with value 'val'\n" + " -Usym undefine 'sym'\n" + "Linker options:\n" + " -Ldir add library path 'dir'\n" + " -llib link with dynamic or static library 'lib'\n" + " -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n" + " -r generate (relocatable) object file\n" + " -rdynamic export all global symbols to dynamic linker\n" + " -shared generate a shared library\n" + " -soname set name for shared library to be used at runtime\n" + " -static static linking\n" + " -Wl,-opt[=val] set linker option (see manual)\n" + "Debugger options:\n" + " -g generate runtime debug info\n" +#ifdef CONFIG_TCC_BCHECK + " -b compile with built-in memory and bounds checker (implies -g)\n" +#endif +#ifdef CONFIG_TCC_BACKTRACE + " -bt N show N callers in stack traces\n" +#endif + "Misc options:\n" + " -nostdinc do not use standard system include paths\n" + " -nostdlib do not link with standard crt and libraries\n" + " -Bdir use 'dir' as tcc internal library and include path\n" + " -MD generate target dependencies for make\n" + " -MF depfile put generated dependencies here\n" + ); +} + +/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 +#ifdef _WIN32 +#include +static int execvp_win32(const char *prog, char **argv) +{ + int ret = spawnvp(P_NOWAIT, prog, (char const*const*)argv); + if (-1 == ret) + return ret; + cwait(&ret, ret, WAIT_CHILD); + exit(ret); +} +#define execvp execvp_win32 +#endif +static void exec_other_tcc(TCCState *s, char **argv, const char *optarg) +{ + char child_path[4096], *child_name; const char *target; + switch (atoi(optarg)) { +#ifdef TCC_TARGET_I386 + case 32: break; + case 64: target = "x86_64"; +#else + case 64: break; + case 32: target = "i386"; +#endif + pstrcpy(child_path, sizeof child_path - 40, argv[0]); + child_name = tcc_basename(child_path); + strcpy(child_name, target); +#ifdef TCC_TARGET_PE + strcat(child_name, "-win32"); +#endif + strcat(child_name, "-tcc"); + if (strcmp(argv[0], child_path)) { + if (s->verbose > 0) + printf("tcc: using '%s'\n", child_name), fflush(stdout); + execvp(argv[0] = child_path, argv); + } + tcc_error("'%s' not found", child_name); + case 0: /* ignore -march etc. */ + break; + default: + tcc_warning("unsupported option \"-m%s\"", optarg); + } +} +#else +#define exec_other_tcc(s, argv, optarg) +#endif + +static void gen_makedeps(TCCState *s, const char *target, const char *filename) +{ + FILE *depout; + char buf[1024], *ext; + int i; + + if (!filename) { + /* compute filename automatically + * dir/file.o -> dir/file.d */ + pstrcpy(buf, sizeof(buf), target); + ext = tcc_fileextension(buf); + pstrcpy(ext, sizeof(buf) - (ext-buf), ".d"); + filename = buf; + } + + if (s->verbose) + printf("<- %s\n", filename); + + /* XXX return err codes instead of error() ? */ + depout = fopen(filename, "w"); + if (!depout) + tcc_error("could not open '%s'", filename); + + fprintf(depout, "%s : \\\n", target); + for (i=0; inb_target_deps; ++i) + fprintf(depout, " %s \\\n", s->target_deps[i]); + fprintf(depout, "\n"); + fclose(depout); +} + +static char *default_outputfile(TCCState *s, const char *first_file) +{ + char buf[1024]; + char *ext; + const char *name = "a"; + + if (first_file && strcmp(first_file, "-")) + name = tcc_basename(first_file); + pstrcpy(buf, sizeof(buf), name); + ext = tcc_fileextension(buf); +#ifdef TCC_TARGET_PE + if (s->output_type == TCC_OUTPUT_DLL) + strcpy(ext, ".dll"); + else + if (s->output_type == TCC_OUTPUT_EXE) + strcpy(ext, ".exe"); + else +#endif + if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) || + (s->output_type == TCC_OUTPUT_PREPROCESS) ) + && *ext) + strcpy(ext, ".o"); + else + strcpy(buf, "a.out"); + + return tcc_strdup(buf); +} + +static void print_paths(const char *msg, char **paths, int nb_paths) +{ + int i; + printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); + for(i = 0; i < nb_paths; i++) + printf(" %s\n", paths[i]); +} + +static void display_info(TCCState *s, int what) +{ + switch (what) { + case 0: + printf("tcc version %s (" +#ifdef TCC_TARGET_I386 + "i386" +# ifdef TCC_TARGET_PE + " Win32" +# endif +#elif defined TCC_TARGET_X86_64 + "x86-64" +# ifdef TCC_TARGET_PE + " Win64" +# endif +#elif defined TCC_TARGET_ARM + "ARM" +# ifdef TCC_ARM_HARDFLOAT + " Hard Float" +# endif +# ifdef TCC_TARGET_PE + " WinCE" +# endif +#endif +#ifndef TCC_TARGET_PE +# ifdef __linux + " Linux" +# endif +#endif + ")\n", TCC_VERSION); + break; + case 1: + printf("install: %s/\n", s->tcc_lib_path); + /* print_paths("programs", NULL, 0); */ + print_paths("crt", s->crt_paths, s->nb_crt_paths); + print_paths("libraries", s->library_paths, s->nb_library_paths); + print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths); + break; + } +} + +static int64_t getclock_us(void) +{ +#ifdef _WIN32 + struct _timeb tb; + _ftime(&tb); + return (tb.time * 1000LL + tb.millitm) * 1000LL; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000LL + tv.tv_usec; +#endif +} + +int main(int argc, char **argv) +{ + TCCState *s; + int ret, optind, i, bench; + int64_t start_time = 0; + const char *first_file = NULL; + + s = tcc_new(); + s->output_type = TCC_OUTPUT_EXE; + + optind = tcc_parse_args(s, argc - 1, argv + 1); + + if (optind == 0) { + help(); + return 1; + } + + if (s->option_m) + exec_other_tcc(s, argv, s->option_m); + + if (s->verbose) + display_info(s, 0); + + if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) { + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + display_info(s, 1); + return 0; + } + + if (s->verbose && optind == 1) + return 0; + + if (s->nb_files == 0) + tcc_error("no input files\n"); + + /* check -c consistency : only single file handled. XXX: checks file type */ + if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { + if (s->nb_libraries != 0) + tcc_error("cannot specify libraries with -c"); + /* accepts only a single input file */ + if (s->nb_files != 1) + tcc_error("cannot specify multiple files with -c"); + } + + if (s->output_type == TCC_OUTPUT_PREPROCESS) { + if (!s->outfile) { + s->ppfp = stdout; + } else { + s->ppfp = fopen(s->outfile, "w"); + if (!s->ppfp) + tcc_error("could not write '%s'", s->outfile); + } + } + + bench = s->do_bench; + if (bench) + start_time = getclock_us(); + + tcc_set_output_type(s, s->output_type); + + /* compile or add each files or library */ + for(i = ret = 0; i < s->nb_files && ret == 0; i++) { + const char *filename; + + filename = s->files[i]; + if (filename[0] == '-' && filename[1] == 'l') { + if (tcc_add_library(s, filename + 2) < 0) { + tcc_error_noabort("cannot find '%s'", filename); + ret = 1; + } + } else { + if (1 == s->verbose) + printf("-> %s\n", filename); + if (tcc_add_file(s, filename) < 0) + ret = 1; + if (!first_file) + first_file = filename; + } + } + + if (0 == ret) { + if (bench) + tcc_print_stats(s, getclock_us() - start_time); + + if (s->output_type == TCC_OUTPUT_MEMORY) { +#ifdef TCC_IS_NATIVE + ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); +#else + tcc_error_noabort("-run is not available in a cross compiler"); + ret = 1; +#endif + } else if (s->output_type == TCC_OUTPUT_PREPROCESS) { + if (s->outfile) + fclose(s->ppfp); + } else { + if (!s->outfile) + s->outfile = default_outputfile(s, first_file); + ret = !!tcc_output_file(s, s->outfile); + /* dump collected dependencies */ + if (s->gen_deps && !ret) + gen_makedeps(s, s->outfile, s->deps_outfile); + } + } + + tcc_delete(s); + if (bench) + tcc_memstats(); + return ret; +} diff --git a/tcc.h b/tcc.h index 460c4170..fa09434c 100644 --- a/tcc.h +++ b/tcc.h @@ -25,10 +25,8 @@ #include "config.h" #ifdef CONFIG_TCCBOOT - #include "tccboot.h" #define CONFIG_TCC_STATIC - #else #include @@ -70,16 +68,8 @@ #endif /* !CONFIG_TCCBOOT */ -#ifndef PAGESIZE -#define PAGESIZE 4096 -#endif - #ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifndef SA_SIGINFO -#define SA_SIGINFO 0x00000004u +# define O_BINARY 0 #endif #include "elf.h" @@ -516,82 +506,22 @@ struct sym_attr { }; struct TCCState { - unsigned output_type : 8; - unsigned reloc_output : 1; - - BufferedFile **include_stack_ptr; - int *ifdef_stack_ptr; - - /* include file handling */ - char **include_paths; - int nb_include_paths; - char **sysinclude_paths; - int nb_sysinclude_paths; - CachedInclude **cached_includes; - int nb_cached_includes; - - char **library_paths; - int nb_library_paths; - char **crt_paths; - int nb_crt_paths; - - /* array of all loaded dlls (including those referenced by loaded - dlls) */ - DLLReference **loaded_dlls; - int nb_loaded_dlls; - - /* sections */ - Section **sections; - int nb_sections; /* number of sections, including first dummy section */ - - Section **priv_sections; - int nb_priv_sections; /* number of private sections */ - - /* got & plt handling */ - Section *got; - Section *plt; - struct sym_attr *sym_attrs; - int nb_sym_attrs; - /* give the correspondance from symtab indexes to dynsym indexes */ - int *symtab_to_dynsym; - - /* temporary dynamic symbol sections (for dll loading) */ - Section *dynsymtab_section; - /* exported dynamic symbol section */ - Section *dynsym; - - /* copy of the gobal symtab_section variable */ - Section *symtab; + int verbose; /* if true, display some information during compilation */ int nostdinc; /* if true, no standard headers are added */ int nostdlib; /* if true, no standard libraries are added */ int nocommon; /* if true, do not use common symbols for .bss data */ + int static_link; /* if true, static linking is performed */ + int rdynamic; /* if true, all symbols are exported */ + int symbolic; /* if true, resolve symbols in the current module first */ + int alacarte_link; /* if true, only link in referenced objects from archive */ - /* if true, static linking is performed */ - int static_link; - - /* soname as specified on the command line (-soname) */ - const char *soname; - /* rpath as specified on the command line (-Wl,-rpath=) */ - const char *rpath; - - /* if true, all symbols are exported */ - int rdynamic; - - /* if true, resolve symbols in the current module first (-Wl,Bsymbolic) */ - int symbolic; - - /* if true, only link in referenced objects from archive */ - int alacarte_link; - - /* address of text section */ - addr_t text_addr; - int has_text_addr; + char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */ + char *soname; /* as specified on the command line (-soname) */ + char *rpath; /* as specified on the command line (-Wl,-rpath=) */ - /* symbols to call at load-time / unload-time */ - const char *init_symbol; - const char *fini_symbol; - + /* output type, see TCC_OUTPUT_XXX */ + int output_type; /* output format, see TCC_OUTPUT_FORMAT_xxx */ int output_format; @@ -606,16 +536,43 @@ struct TCCState { int warn_none; int warn_implicit_function_declaration; - /* display some information during compilation */ - int verbose; /* compile with debug symbol (and use them if error during execution) */ int do_debug; #ifdef CONFIG_TCC_BCHECK /* compile with built-in memory and bounds checker */ int do_bounds_check; #endif - /* give the path of the tcc libraries */ - char *tcc_lib_path; + + addr_t text_addr; /* address of text section */ + int has_text_addr; + + unsigned long section_align; /* section alignment */ + + char *init_symbol; /* symbols to call at load-time (not used currently) */ + char *fini_symbol; /* symbols to call at unload-time (not used currently) */ + +#ifdef TCC_TARGET_I386 + int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */ +#endif + + /* array of all loaded dlls (including those referenced by loaded dlls) */ + DLLReference **loaded_dlls; + int nb_loaded_dlls; + + /* include paths */ + char **include_paths; + int nb_include_paths; + + char **sysinclude_paths; + int nb_sysinclude_paths; + + /* library paths */ + char **library_paths; + int nb_library_paths; + + /* crt?.o object path */ + char **crt_paths; + int nb_crt_paths; /* error handling */ void *error_opaque; @@ -624,72 +581,101 @@ struct TCCState { jmp_buf error_jmp_buf; int nb_errors; - /* tiny assembler state */ - Sym *asm_labels; + /* output file for preprocessing (-E) */ + FILE *ppfp; - /* see include_stack_ptr */ + /* for -MD/-MF: collected dependencies for this compilation */ + char **target_deps; + int nb_target_deps; + + /* compilation */ BufferedFile *include_stack[INCLUDE_STACK_SIZE]; + BufferedFile **include_stack_ptr; - /* see ifdef_stack_ptr */ int ifdef_stack[IFDEF_STACK_SIZE]; + int *ifdef_stack_ptr; - /* see cached_includes */ + /* included files enclosed with #ifndef MACRO */ int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; + CachedInclude **cached_includes; + int nb_cached_includes; - /* pack stack */ + /* #pragma pack stack */ int pack_stack[PACK_STACK_SIZE]; int *pack_stack_ptr; - /* output file for preprocessing */ - FILE *outfile; - - /* automatically collected dependencies for this compilation */ - char **target_deps; - int nb_target_deps; - - /* for tcc_relocate */ - int runtime_added; - void *runtime_mem; -#ifdef HAVE_SELINUX - void *write_mem; - unsigned long mem_size; -#endif - + /* inline functions are stored as token lists and compiled last + only if referenced */ struct InlineFunc **inline_fns; int nb_inline_fns; -#ifdef TCC_TARGET_I386 - int seg_size; -#endif + /* sections */ + Section **sections; + int nb_sections; /* number of sections, including first dummy section */ + + Section **priv_sections; + int nb_priv_sections; /* number of private sections */ + + /* got & plt handling */ + Section *got; + Section *plt; + struct sym_attr *sym_attrs; + int nb_sym_attrs; + /* give the correspondance from symtab indexes to dynsym indexes */ + int *symtab_to_dynsym; - /* section alignment */ - unsigned long section_align; + /* temporary dynamic symbol sections (for dll loading) */ + Section *dynsymtab_section; + /* exported dynamic symbol section */ + Section *dynsym; + /* copy of the gobal symtab_section variable */ + Section *symtab; + /* tiny assembler state */ + Sym *asm_labels; #ifdef TCC_TARGET_PE /* PE info */ int pe_subsystem; - unsigned long pe_file_align; - unsigned long pe_stack_size; -#ifdef TCC_TARGET_X86_64 + unsigned pe_file_align; + unsigned pe_stack_size; +# ifdef TCC_TARGET_X86_64 Section *uw_pdata; int uw_sym; unsigned uw_offs; -#endif +# endif #endif -#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE \ - && (defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM) +#ifdef TCC_IS_NATIVE + /* for tcc_relocate */ + void *runtime_mem; +# ifdef HAVE_SELINUX + void *write_mem; + unsigned long mem_size; +# endif +# if !defined TCC_TARGET_PE && (defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM) /* write PLT and GOT here */ char *runtime_plt_and_got; - unsigned int runtime_plt_and_got_offset; -# define TCC_HAS_RUNTIME_PLTGOT + unsigned runtime_plt_and_got_offset; +# define TCC_HAS_RUNTIME_PLTGOT +# endif #endif + + /* used by main and tcc_parse_args only */ + char **files; /* files seen on command line */ + int nb_files; /* number thereof */ + int nb_libraries; /* number of libs thereof */ + char *outfile; /* output filename */ + char *option_m; /* only -m32/-m64 handled */ + int print_search_dirs; /* option */ + int option_r; /* option -r */ + int do_bench; /* option -bench */ + int gen_deps; /* option -MD */ + char *deps_outfile; /* option -MF */ }; /* The current value can be: */ -#define VT_VALMASK 0x003f -#define VT_CONST 0x0030 /* constant in vc - (must be first non register value) */ +#define VT_VALMASK 0x003f /* mask for value location, register or: */ +#define VT_CONST 0x0030 /* constant in vc (must be first non register value) */ #define VT_LLOCAL 0x0031 /* lvalue, offset on stack */ #define VT_LOCAL 0x0032 /* offset on stack */ #define VT_CMP 0x0033 /* the value is stored in processor flags (in vc) */ @@ -710,29 +696,29 @@ struct TCCState { #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) /* types */ -#define VT_INT 0 /* integer type */ -#define VT_BYTE 1 /* signed byte type */ -#define VT_SHORT 2 /* short type */ -#define VT_VOID 3 /* void type */ -#define VT_PTR 4 /* pointer */ -#define VT_ENUM 5 /* enum definition */ -#define VT_FUNC 6 /* function type */ -#define VT_STRUCT 7 /* struct/union definition */ -#define VT_FLOAT 8 /* IEEE float */ -#define VT_DOUBLE 9 /* IEEE double */ -#define VT_LDOUBLE 10 /* IEEE long double */ -#define VT_BOOL 11 /* ISOC99 boolean type */ -#define VT_LLONG 12 /* 64 bit integer */ -#define VT_LONG 13 /* long integer (NEVER USED as type, only - during parsing) */ -#define VT_BTYPE 0x000f /* mask for basic type */ -#define VT_UNSIGNED 0x0010 /* unsigned type */ -#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ -#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */ -#define VT_BITFIELD 0x0040 /* bitfield modifier */ -#define VT_CONSTANT 0x0800 /* const modifier */ -#define VT_VOLATILE 0x1000 /* volatile modifier */ -#define VT_SIGNED 0x2000 /* signed type */ +#define VT_BTYPE 0x000f /* mask for basic type */ +#define VT_INT 0 /* integer type */ +#define VT_BYTE 1 /* signed byte type */ +#define VT_SHORT 2 /* short type */ +#define VT_VOID 3 /* void type */ +#define VT_PTR 4 /* pointer */ +#define VT_ENUM 5 /* enum definition */ +#define VT_FUNC 6 /* function type */ +#define VT_STRUCT 7 /* struct/union definition */ +#define VT_FLOAT 8 /* IEEE float */ +#define VT_DOUBLE 9 /* IEEE double */ +#define VT_LDOUBLE 10 /* IEEE long double */ +#define VT_BOOL 11 /* ISOC99 boolean type */ +#define VT_LLONG 12 /* 64 bit integer */ +#define VT_LONG 13 /* long integer (NEVER USED as type, only + during parsing) */ +#define VT_UNSIGNED 0x0010 /* unsigned type */ +#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ +#define VT_BITFIELD 0x0040 /* bitfield modifier */ +#define VT_CONSTANT 0x0800 /* const modifier */ +#define VT_VOLATILE 0x1000 /* volatile modifier */ +#define VT_SIGNED 0x2000 /* signed type */ +#define VT_VLA 0x00020000 /* VLA type (also has VT_PTR and VT_ARRAY) */ /* storage */ #define VT_EXTERN 0x00000080 /* extern definition */ @@ -741,13 +727,13 @@ struct TCCState { #define VT_INLINE 0x00000400 /* inline definition */ #define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */ #define VT_EXPORT 0x00008000 /* win32: data exported from dll */ -#define VT_WEAK 0x00010000 /* win32: data exported from dll */ +#define VT_WEAK 0x00010000 /* weak symbol */ -#define VT_STRUCT_SHIFT 18 /* shift for bitfield shift values */ +#define VT_STRUCT_SHIFT 18 /* shift for bitfield shift values (max: 32 - 2*6) */ /* type mask (except storage) */ #define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK) -#define VT_TYPE (~(VT_STORAGE)) +#define VT_TYPE (~(VT_STORAGE)) /* token values */ @@ -999,6 +985,11 @@ ST_DATA int tcc_ext; /* XXX: get rid of this ASAP */ ST_DATA struct TCCState *tcc_state; +#ifdef MEM_DEBUG +ST_DATA int mem_cur_size; +ST_DATA int mem_max_size; +#endif + #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ #define AFF_PREPROCESS 0x0004 /* preprocess file */ @@ -1020,19 +1011,19 @@ PUB_FUNC char *tcc_strdup(const char *str); #undef strdup #define strdup(s) use_tcc_strdup(s) PUB_FUNC void tcc_memstats(void); -PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data); -PUB_FUNC void dynarray_reset(void *pp, int *n); PUB_FUNC void tcc_error_noabort(const char *fmt, ...); PUB_FUNC void tcc_error(const char *fmt, ...); PUB_FUNC void tcc_warning(const char *fmt, ...); /* other utilities */ -PUB_FUNC void cstr_ccat(CString *cstr, int ch); -PUB_FUNC void cstr_cat(CString *cstr, const char *str); -PUB_FUNC void cstr_wccat(CString *cstr, int ch); -PUB_FUNC void cstr_new(CString *cstr); -PUB_FUNC void cstr_free(CString *cstr); -PUB_FUNC void cstr_reset(CString *cstr); +ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data); +ST_FUNC void dynarray_reset(void *pp, int *n); +ST_FUNC void cstr_ccat(CString *cstr, int ch); +ST_FUNC void cstr_cat(CString *cstr, const char *str); +ST_FUNC void cstr_wccat(CString *cstr, int ch); +ST_FUNC void cstr_new(CString *cstr); +ST_FUNC void cstr_free(CString *cstr); +ST_FUNC void cstr_reset(CString *cstr); ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); ST_FUNC void section_realloc(Section *sec, unsigned long new_size); @@ -1059,15 +1050,10 @@ ST_FUNC void tcc_close(void); ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); -#ifndef TCC_TARGET_PE ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); -#endif -PUB_FUNC int tcc_set_flag(TCCState *s, const char *flag_name, int value); PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time); -PUB_FUNC char *tcc_default_target(TCCState *s, const char *default_file); -PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename); -PUB_FUNC void tcc_display_info(TCCState *s, int what); +PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv); /* ------------ tccpp.c ------------ */ @@ -1208,6 +1194,10 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign /* ------------ tccelf.c ------------ */ +#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ +#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ +#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ + #define ARMAG "!\012" /* For COFF and a.out archives */ typedef struct { @@ -1259,11 +1249,11 @@ ST_FUNC int handle_eob(void); /* ------------ xxx-gen.c ------------ */ -ST_DATA const int reg_classes[NB_REGS #ifdef TCC_TARGET_X86_64 - + 7 +ST_DATA const int reg_classes[NB_REGS+7]; +#else +ST_DATA const int reg_classes[NB_REGS]; #endif -]; ST_FUNC void gsym_addr(int t, int a); ST_FUNC void gsym(int t); @@ -1329,7 +1319,6 @@ ST_FUNC int tcc_load_coff(TCCState * s1, int fd); /* ------------ tccasm.c ------------ */ ST_FUNC void asm_instr(void); ST_FUNC void asm_global_instr(void); - #ifdef CONFIG_TCC_ASM ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); @@ -1343,14 +1332,13 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier); ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); #endif + /* ------------ tccpe.c -------------- */ #ifdef TCC_TARGET_PE ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd); ST_FUNC int pe_output_file(TCCState * s1, const char *filename); ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value); ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); -/* tiny_impdef.c */ -ST_FUNC char *get_export_names(FILE *fp); #ifdef TCC_TARGET_X86_64 ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); #endif @@ -1366,7 +1354,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); /* dummy function for profiling */ ST_FUNC void *dlopen(const char *filename, int flag); ST_FUNC void dlclose(void *p); -//ST_FUNC const char *dlerror(void); +ST_FUNC const char *dlerror(void); ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol); #elif !defined _WIN32 ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol); @@ -1376,7 +1364,7 @@ ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol); ST_DATA int rt_num_callers; ST_DATA const char **rt_bound_error_msg; ST_DATA void *rt_prog_main; -PUB_FUNC void tcc_set_num_callers(int n); +ST_FUNC void tcc_set_num_callers(int n); #endif #endif diff --git a/tccelf.c b/tccelf.c index 41bd1a54..500ea189 100644 --- a/tccelf.c +++ b/tccelf.c @@ -240,7 +240,7 @@ ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size, } else if (s == tcc_state->dynsymtab_section) { /* we accept that two DLL define the same symbol */ } else { -#if 1 +#if 0 printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis); #endif diff --git a/tccpe.c b/tccpe.c index 120dc4e8..79be6f3a 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1505,10 +1505,10 @@ static int add_dllref(TCCState *s1, const char *dllname) /* ------------------------------------------------------------- */ -static int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len) +static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) { - fseek(fp, offset, 0); - return len == fread(buffer, 1, len, fp); + lseek(fd, offset, SEEK_SET); + return len == read(fd, buffer, len); } /* ------------------------------------------------------------- @@ -1516,7 +1516,7 @@ static int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len) * as generated by 'windres.exe -O coff ...'. */ -static int pe_load_res(TCCState *s1, FILE *fp) +static int pe_load_res(TCCState *s1, int fd) { struct pe_rsrc_header hdr; Section *rsrc_section; @@ -1524,7 +1524,7 @@ static int pe_load_res(TCCState *s1, FILE *fp) BYTE *ptr; unsigned offs; - if (!read_mem(fp, 0, &hdr, sizeof hdr)) + if (!read_mem(fd, 0, &hdr, sizeof hdr)) goto quit; if (hdr.filehdr.Machine != 0x014C @@ -1535,13 +1535,13 @@ static int pe_load_res(TCCState *s1, FILE *fp) rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); offs = hdr.sectionhdr.PointerToRawData; - if (!read_mem(fp, offs, ptr, hdr.sectionhdr.SizeOfRawData)) + if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) goto quit; offs = hdr.sectionhdr.PointerToRelocations; for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) { struct pe_rsrc_reloc rel; - if (!read_mem(fp, offs, &rel, sizeof rel)) + if (!read_mem(fd, offs, &rel, sizeof rel)) goto quit; // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type); if (rel.type != 7) /* DIR32NB */ @@ -1571,22 +1571,26 @@ static char *trimback(char *a, char *e) return a; } -static char *get_line(char *line, int size, FILE *fp) +static char *get_line(char *line, int size, int fd) { - if (NULL == fgets(line, size, fp)) + int n; + for (n = 0; n < size - 1; ) + if (read(fd, line + n, 1) < 1 || line[n++] == '\n') + break; + if (0 == n) return NULL; - trimback(line, strchr(line, 0)); + trimback(line, line + n); return trimfront(line); } /* ------------------------------------------------------------- */ -static int pe_load_def(TCCState *s1, FILE *fp) +static int pe_load_def(TCCState *s1, int fd) { int state = 0, ret = -1, dllindex = 0; char line[400], dllname[80], *p; for (;;) { - p = get_line(line, sizeof line, fp); + p = get_line(line, sizeof line, fd); if (NULL == p) break; if (0 == *p || ';' == *p) @@ -1623,11 +1627,11 @@ quit: #define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY #include "win32/tools/tiny_impdef.c" -static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp) +static int pe_load_dll(TCCState *s1, const char *dllname, int fd) { char *p, *q; int index; - p = get_export_names(fp); + p = get_export_names(fd); if (!p) return -1; index = add_dllref(s1, dllname); @@ -1640,18 +1644,14 @@ static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp) /* ------------------------------------------------------------- */ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) { - FILE *fp = fdopen(dup(fd), "rb"); int ret = -1; char buf[10]; - if (fp) { - if (0 == strcmp(tcc_fileextension(filename), ".def")) - ret = pe_load_def(s1, fp); - else if (pe_load_res(s1, fp) == 0) - ret = 0; - else if (read_mem(fp, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2)) - ret = pe_load_dll(s1, tcc_basename(filename), fp); - fclose(fp); - } + if (0 == strcmp(tcc_fileextension(filename), ".def")) + ret = pe_load_def(s1, fd); + else if (pe_load_res(s1, fd) == 0) + ret = 0; + else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2)) + ret = pe_load_dll(s1, tcc_basename(filename), fd); return ret; } @@ -1723,7 +1723,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) #define PE_STDSYM(n,s) "_" n s #endif -static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe) +static void pe_add_runtime(TCCState *s1, struct pe_info *pe) { const char *start_symbol; ADDR3264 addr = 0; @@ -1762,15 +1762,17 @@ static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe) if (0 == s1->nostdlib) { static const char *libs[] = { - "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL + "libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL }; const char **pp, *p; for (pp = libs; 0 != (p = *pp); ++pp) { if (0 == *p) { if (PE_DLL != pe_type && PE_GUI != pe_type) break; - } else if (tcc_add_library(s1, p) < 0) + } else if (pp == libs ? tcc_add_dll(s1, p, 0) : tcc_add_library(s1, p)) { tcc_error_noabort("cannot find library: %s", p); + break; + } } } @@ -1802,7 +1804,7 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename) pe.s1 = s1; tcc_add_bcheck(s1); - pe_add_runtime_ex(s1, &pe); + pe_add_runtime(s1, &pe); relocate_common_syms(); /* assign bss adresses */ tcc_add_linker_symbols(s1); diff --git a/tccpp.c b/tccpp.c index c0c7aecc..ac01d83e 100644 --- a/tccpp.c +++ b/tccpp.c @@ -118,7 +118,7 @@ static void cstr_realloc(CString *cstr, int new_size) } /* add a byte */ -PUB_FUNC void cstr_ccat(CString *cstr, int ch) +ST_FUNC void cstr_ccat(CString *cstr, int ch) { int size; size = cstr->size + 1; @@ -128,7 +128,7 @@ PUB_FUNC void cstr_ccat(CString *cstr, int ch) cstr->size = size; } -PUB_FUNC void cstr_cat(CString *cstr, const char *str) +ST_FUNC void cstr_cat(CString *cstr, const char *str) { int c; for(;;) { @@ -141,7 +141,7 @@ PUB_FUNC void cstr_cat(CString *cstr, const char *str) } /* add a wide char */ -PUB_FUNC void cstr_wccat(CString *cstr, int ch) +ST_FUNC void cstr_wccat(CString *cstr, int ch) { int size; size = cstr->size + sizeof(nwchar_t); @@ -151,20 +151,20 @@ PUB_FUNC void cstr_wccat(CString *cstr, int ch) cstr->size = size; } -PUB_FUNC void cstr_new(CString *cstr) +ST_FUNC void cstr_new(CString *cstr) { memset(cstr, 0, sizeof(CString)); } /* free string and reset it to NULL */ -PUB_FUNC void cstr_free(CString *cstr) +ST_FUNC void cstr_free(CString *cstr) { tcc_free(cstr->data_allocated); cstr_new(cstr); } /* reset string to empty */ -PUB_FUNC void cstr_reset(CString *cstr) +ST_FUNC void cstr_reset(CString *cstr) { cstr->size = 0; } @@ -3112,17 +3112,17 @@ print_line: : "" ; iptr = iptr_new; - fprintf(s1->outfile, "# %d \"%s\"%s\n", file->line_num, file->filename, s); + fprintf(s1->ppfp, "# %d \"%s\"%s\n", file->line_num, file->filename, s); } else { while (d) - fputs("\n", s1->outfile), --d; + fputs("\n", s1->ppfp), --d; } line_ref = (file_ref = file)->line_num; token_seen = tok != TOK_LINEFEED; if (!token_seen) continue; } - fputs(get_tok_str(tok, &tokc), s1->outfile); + fputs(get_tok_str(tok, &tokc), s1->ppfp); } free_defines(define_start); return 0; diff --git a/tccrun.c b/tccrun.c index b647962c..50178a81 100644 --- a/tccrun.c +++ b/tccrun.c @@ -54,33 +54,36 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr) if (TCC_RELOCATE_AUTO != ptr) return tcc_relocate_ex(s1, ptr); + ret = tcc_relocate_ex(s1, NULL); + if (ret < 0) + return ret; + #ifdef HAVE_SELINUX - /* Use mmap instead of malloc for Selinux - Ref http://www.gnu.org/s/libc/manual/html_node/File-Size.html */ - char tmpfname[] = "/tmp/.tccrunXXXXXX"; - int fd = mkstemp (tmpfname); - if ((ret= tcc_relocate_ex(s1,NULL)) < 0)return -1; - s1->mem_size=ret; - unlink (tmpfname); ftruncate (fd, s1->mem_size); - s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE, - MAP_SHARED, fd, 0); - if(s1->write_mem == MAP_FAILED){ - tcc_error("/tmp not writeable"); - return -1; - } - s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC, - MAP_SHARED, fd, 0); - if(s1->runtime_mem == MAP_FAILED){ - tcc_error("/tmp not executable"); - return -1; + { /* Use mmap instead of malloc for Selinux. Ref: + http://www.gnu.org/s/libc/manual/html_node/File-Size.html */ + + char tmpfname[] = "/tmp/.tccrunXXXXXX"; + int fd = mkstemp (tmpfname); + + s1->mem_size = ret; + unlink (tmpfname); + ftruncate (fd, s1->mem_size); + + s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0); + if (s1->write_mem == MAP_FAILED) + tcc_error("/tmp not writeable"); + + s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC, + MAP_SHARED, fd, 0); + if (s1->runtime_mem == MAP_FAILED) + tcc_error("/tmp not executable"); + + ret = tcc_relocate_ex(s1, s1->write_mem); } - ret = tcc_relocate_ex(s1, s1->write_mem); #else - ret = tcc_relocate_ex(s1, NULL); - if (-1 != ret) { - s1->runtime_mem = tcc_malloc(ret); - ret = tcc_relocate_ex(s1, s1->runtime_mem); - } + s1->runtime_mem = tcc_malloc(ret); + ret = tcc_relocate_ex(s1, s1->runtime_mem); #endif return ret; } @@ -130,8 +133,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr) addr_t mem; int i; - if (0 == s1->runtime_added) { - s1->runtime_added = 1; + if (NULL == ptr) { s1->nb_errors = 0; #ifdef TCC_TARGET_PE pe_output_file(s1, NULL); @@ -215,6 +217,9 @@ static void set_pages_executable(void *ptr, unsigned long length) unsigned long old_protect; VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); #else +#ifndef PAGESIZE +# define PAGESIZE 4096 +#endif addr_t start, end; start = (addr_t)ptr & ~(PAGESIZE - 1); end = (addr_t)ptr + length; @@ -226,7 +231,7 @@ static void set_pages_executable(void *ptr, unsigned long length) /* ------------------------------------------------------------- */ #ifdef CONFIG_TCC_BACKTRACE -PUB_FUNC void tcc_set_num_callers(int n) +ST_FUNC void tcc_set_num_callers(int n) { rt_num_callers = n; } @@ -436,6 +441,10 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc) exit(255); } +#ifndef SA_SIGINFO +# define SA_SIGINFO 0x00000004u +#endif + /* Generate a stack backtrace when a CPU exception occurs. */ static void set_exception_handler(void) { @@ -663,14 +672,8 @@ static int rt_get_caller_pc(addr_t *paddr, CONTEXT *uc, int level) #endif /* _WIN32 */ #endif /* CONFIG_TCC_BACKTRACE */ /* ------------------------------------------------------------- */ - #ifdef CONFIG_TCC_STATIC -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 -#define RTLD_DEFAULT NULL - /* dummy function for profiling */ ST_FUNC void *dlopen(const char *filename, int flag) { @@ -680,26 +683,27 @@ ST_FUNC void *dlopen(const char *filename, int flag) ST_FUNC void dlclose(void *p) { } -/* -const char *dlerror(void) + +ST_FUNC const char *dlerror(void) { return "error"; } -*/ + typedef struct TCCSyms { char *str; void *ptr; } TCCSyms; -#define TCCSYM(a) { #a, &a, }, /* add the symbol you want here if no dynamic linking is done */ static TCCSyms tcc_syms[] = { #if !defined(CONFIG_TCCBOOT) +#define TCCSYM(a) { #a, &a, }, TCCSYM(printf) TCCSYM(fprintf) TCCSYM(fopen) TCCSYM(fclose) +#undef TCCSYM #endif { NULL, NULL }, }; diff --git a/win32/tcc-win32.txt b/win32/tcc-win32.txt index 12f6ae72..dc06b8f5 100644 --- a/win32/tcc-win32.txt +++ b/win32/tcc-win32.txt @@ -6,13 +6,11 @@ under MS-Windows. See tcc-doc.html to have all the features. - Installation from the binary ZIP package: ----------------------------------------- Unzip the package to a directory of your choice. - Set the system PATH: -------------------- To be able to invoke the compiler from everywhere on your computer by @@ -20,7 +18,6 @@ system PATH. - Examples: --------- Open a console window (DOS box) and 'cd' to the examples directory. @@ -39,9 +36,23 @@ tiny_impdef dll.dll (optional) tcc hello_dll.c dll.def - For the 'libtcc_test' example type - tcc examples/libtcc_test.c -I libtcc -L libtcc -ltcc + Using libtcc as JIT compiler in your program + -------------------------------------------- + Check out the 'libtcc_test' example: + + - Running it from source: + tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c + + - Compiling with TCC: + tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def + + - Compiling with MinGW: + gcc examples/libtcc_test.c -I libtcc libtcc.dll + + - Compiling with MSVC: + lib /def:libtcc\libtcc.def /out:libtcc.lib + cl /MD examples/libtcc_test.c -I libtcc libtcc.lib Import Definition Files: @@ -58,7 +69,6 @@ the TCC commandline to link a program that uses opengl32.dll. - Header Files: ------------- The system header files (except _mingw.h) are from the MinGW @@ -71,7 +81,6 @@ into your "tcc/include/winapi" directory. - Resource Files: --------------- TCC can link windows resources in coff format as generated by MinGW's @@ -81,7 +90,6 @@ tcc app.c appres.o -o app.exe - Tiny Libmaker: -------------- The included tiny_libmaker tool by Timovj Lahde can be used as @@ -90,29 +98,26 @@ tiny_libmaker [rcs] library objectfiles ... - Compilation from source: ------------------------ * You can use the MinGW and MSYS tools available at http://www.mingw.org - Untar the TCC archive and type in the MSYS shell: + Untar the TCC archive and type in the MSYS shell: - ./configure - make - make install + ./configure [--prefix installpath] + make + make install The default install location is c:\Program Files\tcc - * Alternatively you can compile TCC with just GCC from MinGW using - win32\build-tcc.bat - - To install, copy the entire contents of the win32 directory to - where you want. + build-tcc.bat (from the win32 directory) + To install, copy the entire contents of the win32 directory to + where you want. Limitations: @@ -128,7 +133,6 @@ - Bounds checking (option -b) is not supported on 64-bit OS. - Documentation and License: -------------------------- TCC is distributed under the GNU Lesser General Public License. (See @@ -139,7 +143,6 @@ http://fabrice.bellard.free.fr/tcc/ - WinAPI Help and 3rd-party tools: -------------------------------- The Windows API documentation (Win95) in a single .hlp file is @@ -150,5 +153,4 @@ "ResEd", available at the RadASM website. - --- grischka diff --git a/win32/tools/tiny_impdef.c b/win32/tools/tiny_impdef.c index 586c49d3..1739549f 100644 --- a/win32/tools/tiny_impdef.c +++ b/win32/tools/tiny_impdef.c @@ -25,9 +25,10 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include #include -char *get_export_names(FILE *fp); +char *get_export_names(int fd); #define tcc_free free #define tcc_realloc realloc @@ -114,7 +115,7 @@ usage: if (v) printf("--> %s\n", file); - p = get_export_names(fp); + p = get_export_names(fileno(fp)); if (NULL == p) { fprintf(stderr, "tiny_impdef: could not get exported function names.\n"); goto the_end; @@ -149,18 +150,18 @@ the_end: return ret; } -/* -------------------------------------------------------------- */ - -int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len) +int read_mem(int fd, unsigned offset, void *buffer, unsigned len) { - fseek(fp, offset, 0); - return len == fread(buffer, 1, len, fp); + lseek(fd, offset, SEEK_SET); + return len == read(fd, buffer, len); } /* -------------------------------------------------------------- */ + +/* -------------------------------------------------------------- */ #endif -char *get_export_names(FILE *fp) +char *get_export_names(int fd) { int l, i, n, n0; char *p; @@ -182,20 +183,20 @@ char *get_export_names(FILE *fp) n = n0 = 0; p = NULL; - if (!read_mem(fp, 0, &dh, sizeof dh)) + if (!read_mem(fd, 0, &dh, sizeof dh)) goto the_end; - if (!read_mem(fp, dh.e_lfanew, &sig, sizeof sig)) + if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig)) goto the_end; if (sig != 0x00004550) goto the_end; pef_hdroffset = dh.e_lfanew + sizeof sig; - if (!read_mem(fp, pef_hdroffset, &ih, sizeof ih)) + if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih)) goto the_end; if (MACHINE != ih.Machine) goto the_end; opt_hdroffset = pef_hdroffset + sizeof ih; sec_hdroffset = opt_hdroffset + sizeof oh; - if (!read_mem(fp, opt_hdroffset, &oh, sizeof oh)) + if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) goto the_end; if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) @@ -204,7 +205,7 @@ char *get_export_names(FILE *fp) addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; //printf("addr: %08x\n", addr); for (i = 0; i < ih.NumberOfSections; ++i) { - if (!read_mem(fp, sec_hdroffset + i * sizeof ish, &ish, sizeof ish)) + if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish)) goto the_end; //printf("vaddr: %08x\n", ish.VirtualAddress); if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData) @@ -214,18 +215,18 @@ char *get_export_names(FILE *fp) found: ref = ish.VirtualAddress - ish.PointerToRawData; - if (!read_mem(fp, addr - ref, &ied, sizeof ied)) + if (!read_mem(fd, addr - ref, &ied, sizeof ied)) goto the_end; namep = ied.AddressOfNames - ref; for (i = 0; i < ied.NumberOfNames; ++i) { - if (!read_mem(fp, namep, &ptr, sizeof ptr)) + if (!read_mem(fd, namep, &ptr, sizeof ptr)) goto the_end; namep += sizeof ptr; for (l = 0;;) { if (n+1 >= n0) p = tcc_realloc(p, n0 = n0 ? n0 * 2 : 256); - if (!read_mem(fp, ptr - ref + l, p + n, 1) || ++l >= 80) { + if (!read_mem(fd, ptr - ref + l, p + n, 1) || ++l >= 80) { tcc_free(p), p = NULL; goto the_end; } diff --git a/win32/tools/tiny_libmaker.c b/win32/tools/tiny_libmaker.c index a85c685b..62d2a2e0 100644 --- a/win32/tools/tiny_libmaker.c +++ b/win32/tools/tiny_libmaker.c @@ -79,7 +79,7 @@ int main(int argc, char **argv) ElfW(Sym) *sym; int i, fsize, iarg; char *buf, *shstr, *symtab = NULL, *strtab = NULL; - int symtabsize = 0, strtabsize = 0; + int symtabsize = 0;//, strtabsize = 0; char *anames = NULL; int *afpos = NULL; int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; @@ -171,7 +171,7 @@ int main(int argc, char **argv) if (!strcmp(shstr + shdr->sh_name, ".strtab")) { strtab = (char *)(buf + shdr->sh_offset); - strtabsize = shdr->sh_size; + //strtabsize = shdr->sh_size; } } } -- 2.11.4.GIT