From 2d3b9559bf569f137cefb7f8386a0dc58e33c81f Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 18 Feb 2017 09:55:34 +0100 Subject: [PATCH] tcctools.c: integrate tiny_libmaker/_impdef usage: tcc -ar [rcsv] lib files... tcc -impdef lib.dll [-v] [-o lib.def] also: - support more files with -c: tcc -c f1.c f2.c ... - fix a bug which caused tcc f1.c f2.S to produce no asm - allow tcc -ar @listfile too - change prototype: _void_ tcc_set_options(...) - apply -Wl,-whole-archive when a librariy is given as libxxx.a also (not just for -lxxx) --- Changelog | 1 + Makefile | 20 +- TODO | 1 + conftest.c | 22 +- lib/Makefile | 30 +- libtcc.c | 212 ++++++++------ libtcc.h | 2 +- tcc.c | 341 ++++++++-------------- tcc.h | 34 ++- tccasm.c | 1 + tccpe.c | 122 +++++++- tcctools.c | 547 ++++++++++++++++++++++++++++++++++++ tests/tcctest.c | 2 +- win32/build-tcc.bat | 31 +- win32/tcc-win32.txt | 22 +- win32/tools/tiny_impdef.c | 249 ---------------- win32/tools/tiny_libmaker.c | 278 ------------------ 17 files changed, 998 insertions(+), 917 deletions(-) create mode 100644 tcctools.c delete mode 100644 win32/tools/tiny_impdef.c delete mode 100644 win32/tools/tiny_libmaker.c diff --git a/Changelog b/Changelog index a8928fc..8264d1d 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,7 @@ User interface: - -mms-bitfields option (David Mertens) - -include option (Michael Matz) - @listfile support (Vlad Vissoultchev) +- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka) - CPATH, C_INCLUDE_PATH and LD_LIBRARY_PATH environment variables support (Andrew Aladjev, Urs Janssen) diff --git a/Makefile b/Makefile index c13ce37..f9008ff 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ LIBS = ifdef CONFIG_WIN32 ifneq ($(DISABLE_STATIC),no) LIBTCC = libtcc.dll + LIBTCCDEF = libtcc.def endif else LIBS=-lm @@ -82,7 +83,7 @@ ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CRO ARM64_CROSS = arm64-tcc$(EXESUF) C67_CROSS = c67-tcc$(EXESUF) -CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c +CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c CORE_FILES += tcc.h config.h libtcc.h tcctok.h I386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h WIN32_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h tccpe.c @@ -94,7 +95,6 @@ ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c ifdef CONFIG_WIN32 - PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) ifeq ($(ARCH),x86-64) NATIVE_FILES=$(WIN64_FILES) PROGS_CROSS=$(WIN32_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) @@ -124,11 +124,7 @@ NATIVE_FILES=$(ARM64_FILES) PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) endif -ifeq ($(TARGETOS),Darwin) - PROGS += tiny_libmaker$(EXESUF) -endif - -TCCLIBS = $(LIBTCC1) $(LIBTCC) +TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF) TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info ifdef CONFIG_CROSS @@ -179,7 +175,7 @@ $(ARM64_CROSS): $(ARM64_FILES) # libtcc generation and test ifndef ONE_SOURCE -LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES)))) +LIBTCC_OBJ = $(filter-out tcc.o tcctools.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES)))) LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES) i386-asm.c,$(NATIVE_FILES)) else LIBTCC_OBJ = libtcc.o @@ -187,6 +183,8 @@ LIBTCC_INC = $(NATIVE_FILES) libtcc.o : NATIVE_DEFINES += -DONE_SOURCE endif +tcc.o : tcctools.c + $(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC) $(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CFLAGS) @@ -199,9 +197,11 @@ libtcc.so: $(LIBTCC_OBJ) libtcc.so: CFLAGS+=-fPIC # windows : libtcc.dll -libtcc.dll : $(LIBTCC_OBJ) tiny_impdef$(EXESUF) +libtcc.dll : $(LIBTCC_OBJ) $(CC) -shared $(LIBTCC_OBJ) -o $@ $(LDFLAGS) - ./tiny_impdef $@ + +libtcc.def : libtcc.dll tcc$(EXESUF) + ./tcc$(EXESUF) -impdef $< -o $@ libtcc.dll : NATIVE_DEFINES += -DLIBTCC_AS_DLL diff --git a/TODO b/TODO index 5e6f7bf..3adeef2 100644 --- a/TODO +++ b/TODO @@ -2,6 +2,7 @@ TODO list: Bugs: +- i386 fastcall is mostly wrong - FPU st(0) is left unclean (kwisatz haderach). Incompatible with optimized gcc/msc code - see transparent union pb in /urs/include/sys/socket.h diff --git a/conftest.c b/conftest.c index fa07a1b..2824cc8 100644 --- a/conftest.c +++ b/conftest.c @@ -1,9 +1,9 @@ #include /* Define architecture */ -#if defined(__i386__) +#if defined(__i386__) || defined _M_IX86 # define TRIPLET_ARCH "i386" -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined _M_AMD64 # define TRIPLET_ARCH "x86_64" #elif defined(__arm__) # define TRIPLET_ARCH "arm" @@ -18,6 +18,8 @@ # define TRIPLET_OS "linux" #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) # define TRIPLET_OS "kfreebsd" +#elif defined _WIN32 +# define TRIPLET_OS "win32" #elif !defined (__GNU__) # define TRIPLET_OS "unknown" #endif @@ -33,7 +35,9 @@ # define TRIPLET_ABI "gnu" #endif -#ifdef __GNU__ +#if defined _WIN32 +# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS +#elif defined __GNU__ # define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI #else # define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI @@ -59,6 +63,13 @@ int main(int argc, char *argv[]) case 'v': printf("%d\n", __GNUC__); break; +#elif defined __TINYC__ + case 'v': + puts("0"); + break; + case 'm': + printf("%d\n", __TINYC__); + break; #else case 'm': case 'v': @@ -68,9 +79,8 @@ int main(int argc, char *argv[]) case 't': puts(TRIPLET); break; - case -1: - /* to test -Wno-unused-result */ - fread(NULL, 1, 1, NULL); + + default: break; } return 0; diff --git a/lib/Makefile b/lib/Makefile index 4cc8093..85dc5cf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -20,9 +20,6 @@ ifndef TARGET TARGET = x86_64 else ifeq ($(ARCH),arm) TARGET = arm - # using gcc, need asm - XCC = $(CC) - XFLAGS = $(CFLAGS) -fPIC else ifeq ($(ARCH),arm64) TARGET = arm64 endif @@ -37,6 +34,9 @@ cross : $(DIR)/libtcc1.a native : TCC = $(TOP)/tcc$(EXESUF) cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF) +XCC = $(TCC) -B$(TOPSRC) +XAR = $(TCC) -ar + I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O) X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BCHECK_O) ARM_O = libtcc1.o armeabi.o alloca-arm.o @@ -47,53 +47,43 @@ ifeq "$(TARGET)" "i386-win32" OBJ = $(addprefix $(DIR)/,$(I386_O) $(WIN32_O)) TGT = -DTCC_TARGET_I386 -DTCC_TARGET_PE XCC = $(TCC) -B$(TOPSRC)/win32 -I$(TOPSRC)/include - XAR = $(DIR)/tiny_libmaker$(EXESUF) else ifeq "$(TARGET)" "x86_64-win32" OBJ = $(addprefix $(DIR)/,$(X86_64_O) $(WIN32_O)) TGT = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE XCC = $(TCC) -B$(TOPSRC)/win32 -I$(TOPSRC)/include - XAR = $(DIR)/tiny_libmaker$(EXESUF) else ifeq "$(TARGET)" "i386" OBJ = $(addprefix $(DIR)/,$(I386_O)) TGT = -DTCC_TARGET_I386 - XCC ?= $(TCC) -B$(TOPSRC) else ifeq "$(TARGET)" "x86_64" OBJ = $(addprefix $(DIR)/,$(X86_64_O)) TGT = -DTCC_TARGET_X86_64 - XCC ?= $(TCC) -B$(TOPSRC) else ifeq "$(TARGET)" "arm" OBJ = $(addprefix $(DIR)/,$(ARM_O)) TGT = -DTCC_TARGET_ARM - XCC ?= $(TCC) -B$(TOPSRC) + # using gcc, need asm + XCC = $(CC) + XFLAGS = $(CFLAGS) -fPIC + XAR = $(AR) else ifeq "$(TARGET)" "arm64" OBJ = $(addprefix $(DIR)/,$(ARM64_O)) TGT = -DTCC_TARGET_ARM64 - XCC ?= $(TCC) -B$(TOPSRC) else $(error libtcc1.a not supported on target '$(TARGET)') endif ifeq ($(TARGETOS),Darwin) - XAR = $(DIR)/tiny_libmaker$(EXESUF) XFLAGS += -D_ANSI_SOURCE BCHECK_O = endif -ifdef XAR -AR = $(XAR) -endif - -$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) $(XAR) - $(AR) rcs $@ $(OBJ) +$(DIR)/libtcc1.a ../libtcc1.a : $(OBJ) + $(XAR) rcs $@ $(OBJ) $(DIR)/%.o : %.c $(XCC) -c $< -o $@ $(TGT) $(XFLAGS) $(DIR)/%.o : %.S $(XCC) -c $< -o $@ $(TGT) $(XFLAGS) -# windows : utilities -$(DIR)/tiny_%$(EXESUF) : $(TOPSRC)/win32/tools/tiny_%.c - $(CC) -o $@ $< $(CFLAGS) $(LDFLAGS) $(TGT) -$(OBJ) $(XAR) : $(DIR)/exists +$(OBJ) : $(DIR)/exists %/exists : mkdir -p $(DIR) diff --git a/libtcc.c b/libtcc.c index 34e944c..3282c28 100644 --- a/libtcc.c +++ b/libtcc.c @@ -239,7 +239,7 @@ PUB_FUNC char *tcc_strdup(const char *str) return ptr; } -PUB_FUNC void tcc_memstats(int bench) +PUB_FUNC void tcc_memcheck(void) { } @@ -379,7 +379,7 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line) return ptr; } -PUB_FUNC void tcc_memstats(int bench) +PUB_FUNC void tcc_memcheck(void) { if (mem_cur_size) { mem_debug_header_t *header = mem_debug_chain; @@ -393,8 +393,7 @@ PUB_FUNC void tcc_memstats(int bench) #if MEM_DEBUG-0 == 2 exit(2); #endif - } else if (bench) - fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size); + } } #endif /* MEM_DEBUG */ @@ -435,7 +434,7 @@ ST_FUNC void dynarray_reset(void *pp, int *n) *(void**)pp = NULL; } -static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in) +static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in) { const char *p; do { @@ -878,18 +877,14 @@ LIBTCCAPI TCCState *tcc_new(void) tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW"); # endif -#endif /* ndef TCC_TARGET_PE */ - /* Some GCC builtins that are simple to express as macros. */ tcc_define_symbol(s, "__builtin_extract_return_addr(x)", "x"); - +#endif /* ndef TCC_TARGET_PE */ return s; } LIBTCCAPI void tcc_delete(TCCState *s1) { - int bench = s1->do_bench; - tcc_cleanup(); /* free sections */ @@ -915,6 +910,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1) dynarray_reset(&s1->files, &s1->nb_files); dynarray_reset(&s1->target_deps, &s1->nb_target_deps); dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs); + dynarray_reset(&s1->argv, &s1->argc); #ifdef TCC_IS_NATIVE /* free runtime memory */ @@ -923,7 +919,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1) tcc_free(s1); if (0 == --nb_states) - tcc_memstats(bench); + tcc_memcheck(); } LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) @@ -965,7 +961,7 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) # endif #else /* paths for crt objects */ - tcc_split_path(s, (void ***)&s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); + tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); /* add libc crt1/crti objects */ if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && !s->nostdlib) { @@ -979,13 +975,13 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) { - tcc_split_path(s, (void ***)&s->include_paths, &s->nb_include_paths, pathname); + tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname); return 0; } LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) { - tcc_split_path(s, (void ***)&s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); + tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); return 0; } @@ -1106,7 +1102,7 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) { - tcc_split_path(s, (void ***)&s->library_paths, &s->nb_library_paths, pathname); + tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname); return 0; } @@ -1440,6 +1436,7 @@ typedef struct TCCOption { enum { TCC_OPTION_HELP, + TCC_OPTION_v, TCC_OPTION_I, TCC_OPTION_D, TCC_OPTION_U, @@ -1480,13 +1477,14 @@ enum { 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 + TCC_OPTION_x, + TCC_OPTION_ar, + TCC_OPTION_impdef }; #define TCC_OPTION_HAS_ARG 0x0001 @@ -1496,6 +1494,7 @@ static const TCCOption tcc_options[] = { { "h", TCC_OPTION_HELP, 0 }, { "-help", TCC_OPTION_HELP, 0 }, { "?", TCC_OPTION_HELP, 0 }, + { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, @@ -1542,13 +1541,16 @@ static const TCCOption tcc_options[] = { { "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 }, + { "ar", TCC_OPTION_ar, 0}, +#ifdef TCC_TARGET_PE + { "impdef", TCC_OPTION_impdef, 0}, +#endif { NULL, 0, 0 }, }; @@ -1595,58 +1597,106 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype { struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); f->type = filetype; + f->alacarte = s->alacarte_link; strcpy(f->name, filename); dynarray_add(&s->files, &s->nb_files, f); } -/* read list file */ -static void args_parser_listfile(TCCState *s, const char *filename) +static int args_parser_make_argv(const char *r, int *argc, char ***argv) { - int fd; + int ret = 0, q, c; + CString str; + for(;;) { + while (c = (unsigned char)*r, c && c <= ' ') + ++r; + if (c == 0) + break; + q = 0; + cstr_new(&str); + while (c = (unsigned char)*r, c) { + ++r; + if (c == '\\' && (*r == '"' || *r == '\\')) { + c = *r++; + } else if (c == '"') { + q = !q; + continue; + } else if (q == 0 && c <= ' ') { + break; + } + cstr_ccat(&str, c); + } + cstr_ccat(&str, 0); + //printf("<%s>\n", str.data), fflush(stdout); + dynarray_add(argv, argc, tcc_strdup(str.data)); + cstr_free(&str); + ++ret; + } + return ret; +} + +/* read list file */ +static void args_parser_listfile(TCCState *s, + const char *filename, int optind, int *pargc, char ***pargv) +{ + int fd, i; size_t len; char *p; + int argc = 0; + char **argv = NULL; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) - tcc_error("file '%s' not found", filename); + tcc_error("listfile '%s' not found", filename); len = lseek(fd, 0, SEEK_END); p = tcc_malloc(len + 1), p[len] = 0; lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd); - tcc_set_options(s, p); + + for (i = 0; i < *pargc; ++i) + if (i == optind) + args_parser_make_argv(p, &argc, &argv); + else + dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i])); + tcc_free(p); + dynarray_reset(&s->argv, &s->argc); + *pargc = s->argc = argc, *pargv = s->argv = argv; } -PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) +PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind) { const TCCOption *popt; const char *optarg, *r; const char *run = NULL; - int optind = 0; - int x; int last_o = -1; + int x; CString linker_arg; /* collect -Wl options */ char buf[1024]; + int tool = 0, arg_start = 0, noaction = optind; + char **argv = *pargv; + int argc = *pargc; cstr_new(&linker_arg); while (optind < argc) { - - r = argv[optind++]; - -reparse: + r = argv[optind]; if (r[0] == '@' && r[1] != '\0') { - args_parser_listfile(s, r + 1); + args_parser_listfile(s, r + 1, optind, &argc, &argv); continue; } - + optind++; + if (tool) { + if (r[0] == '-' && r[1] == 'v' && r[2] == 0) + ++s->verbose; + continue; + } +reparse: if (r[0] != '-' || r[1] == '\0') { if (r[0] != '@') /* allow "tcc file(s) -run @ args ..." */ args_parser_add_file(s, r, s->filetype); if (run) { tcc_set_options(s, run); - optind--; - /* argv[0] will be this file */ + arg_start = optind - 1; break; } continue; @@ -1675,7 +1725,7 @@ reparse: switch(popt->index) { case TCC_OPTION_HELP: - return 0; + return OPT_HELP; case TCC_OPTION_I: tcc_add_include_path(s, optarg); break; @@ -1693,7 +1743,7 @@ reparse: tcc_set_lib_path(s, optarg); break; case TCC_OPTION_l: - args_parser_add_file(s, optarg, AFF_TYPE_LIBWH - s->alacarte_link); + args_parser_add_file(s, optarg, AFF_TYPE_LIB); s->nb_libraries++; break; case TCC_OPTION_pthread: @@ -1774,9 +1824,6 @@ reparse: case TCC_OPTION_nostdlib: s->nostdlib = 1; break; - case TCC_OPTION_print_search_dirs: - s->print_search_dirs = 1; - break; case TCC_OPTION_run: #ifndef TCC_IS_NATIVE tcc_error("-run is not available in a cross compiler"); @@ -1786,6 +1833,7 @@ reparse: goto set_output_type; case TCC_OPTION_v: do ++s->verbose; while (*optarg++ == 'v'); + ++noaction; break; case TCC_OPTION_f: if (set_flag(s, options_f, optarg) < 0) @@ -1804,12 +1852,13 @@ reparse: break; #endif case TCC_OPTION_m: - if (set_flag(s, options_m, optarg) == 0) - break; - else if (x = atoi(optarg), x == 32 || x == 64) - s->cross_target = x; - else - goto unsupported_option; + if (set_flag(s, options_m, optarg) < 0) { + if (x = atoi(optarg), x != 32 && x != 64) + goto unsupported_option; + if (PTR_SIZE != x/8) + return x; + ++noaction; + } break; case TCC_OPTION_W: if (set_flag(s, options_W, optarg) < 0) @@ -1860,6 +1909,20 @@ reparse: case TCC_OPTION_O: last_o = atoi(optarg); break; + case TCC_OPTION_print_search_dirs: + x = OPT_PRINT_DIRS; + goto extra_action; + case TCC_OPTION_impdef: + x = OPT_IMPDEF; + goto extra_action; + case TCC_OPTION_ar: + x = OPT_AR; + extra_action: + arg_start = optind - 1; + if (arg_start != noaction) + tcc_error("cannot parse %s here", r); + tool = x; + break; case TCC_OPTION_traditional: case TCC_OPTION_pedantic: case TCC_OPTION_pipe: @@ -1873,53 +1936,32 @@ unsupported_option: break; } } - if (last_o > 0) tcc_define_symbol(s, "__OPTIMIZE__", NULL); - if (linker_arg.size) { r = linker_arg.data; goto arg_err; } - - return optind; + *pargc = argc - arg_start; + *pargv = argv + arg_start; + if (tool) + return tool; + if (optind != noaction) + return 0; + if (s->verbose == 2) + return OPT_PRINT_DIRS; + if (s->verbose) + return OPT_V; + return OPT_HELP; } -LIBTCCAPI int tcc_set_options(TCCState *s, const char *r) +LIBTCCAPI void tcc_set_options(TCCState *s, const char *r) { - char **argv; - int argc; - int ret, q, c; - CString str; - - argc = 0, argv = NULL; - for(;;) { - while (c = (unsigned char)*r, c && c <= ' ') - ++r; - if (c == 0) - break; - q = 0; - cstr_new(&str); - while (c = (unsigned char)*r, c) { - ++r; - if (c == '\\' && (*r == '"' || *r == '\\')) { - c = *r++; - } else if (c == '"') { - q = !q; - continue; - } else if (q == 0 && c <= ' ') { - break; - } - cstr_ccat(&str, c); - } - cstr_ccat(&str, 0); - //printf("<%s>\n", str.data), fflush(stdout); - dynarray_add(&argv, &argc, tcc_strdup(str.data)); - cstr_free(&str); - } - ret = tcc_parse_args(s, argc, argv); + char **argv = NULL; + int argc = 0; + args_parser_make_argv(r, &argc, &argv); + tcc_parse_args(s, &argc, &argv, 0); dynarray_reset(&argv, &argc); - return ret; } PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time) @@ -1928,11 +1970,15 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time) total_time = 1; if (total_bytes < 1) total_bytes = 1; - fprintf(stderr, "%d idents, %d lines, %d bytes, %0.3f s, %u lines/s, %0.1f MB/s\n", + fprintf(stderr, "* %d idents, %d lines, %d bytes\n" + "* %0.3f s, %u lines/s, %0.1f MB/s\n", tok_ident - TOK_IDENT, total_lines, total_bytes, (double)total_time/1000, (unsigned)total_lines*1000/total_time, (double)total_bytes/1000/total_time); +#ifdef MEM_DEBUG + fprintf(stderr, "* %d bytes memory used\n", mem_max_size); +#endif } PUB_FUNC void tcc_set_environment(TCCState *s) diff --git a/libtcc.h b/libtcc.h index 799ffd8..a1b31e3 100644 --- a/libtcc.h +++ b/libtcc.h @@ -27,7 +27,7 @@ LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, void (*error_func)(void *opaque, const char *msg)); /* set options as from command line (multiple supported) */ -LIBTCCAPI int tcc_set_options(TCCState *s, const char *str); +LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); /*****************************/ /* preprocessor */ diff --git a/tcc.c b/tcc.c index c5a1f0e..2ca3bb8 100644 --- a/tcc.c +++ b/tcc.c @@ -23,69 +23,7 @@ #else #include "tcc.h" #endif - -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" -#elif defined TCC_TARGET_X86_64 - "x86-64" -#elif defined TCC_TARGET_C67 - "C67" -#elif defined TCC_TARGET_ARM - "ARM" -# ifdef TCC_ARM_HARDFLOAT - " Hard Float" -# endif -#elif defined TCC_TARGET_ARM64 - "AArch64" -# ifdef TCC_ARM_HARDFLOAT - " Hard Float" -# endif -#endif -#ifdef TCC_TARGET_PE - " Windows" -#elif defined(__APPLE__) - /* Current Apple OS name as of 2016 */ - " macOS" -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - " FreeBSD" -#elif defined(__DragonFly__) - " DragonFly BSD" -#elif defined(__NetBSD__) - " NetBSD" -#elif defined(__OpenBSD__) - " OpenBSD" -#elif defined(__linux__) - " Linux" -#else - " Unidentified system" -#endif - ")\n", TCC_VERSION); - break; - case 1: - printf("install: %s\n", s->tcc_lib_path); - /* print_paths("programs", NULL, 0); */ - print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths); - print_paths("libraries", s->library_paths, s->nb_library_paths); -#ifndef TCC_TARGET_PE - print_paths("crt", s->crt_paths, s->nb_crt_paths); - printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s)); -#endif - break; - } -} +#include "tcctools.c" static void help(void) { @@ -100,7 +38,8 @@ static void help(void) " -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" + " -vv show included files (as sole argument show search paths)\n" + " -h show this help\n" " -bench show compilation statistics\n" "Preprocessor options:\n" " -Idir add include path 'dir'\n" @@ -146,115 +85,75 @@ static void help(void) #endif #ifdef TCC_TARGET_X86_64 " -mno-sse disable floats on x86-64\n" +#endif + "Tools:\n" + " create library : tcc -ar [rcsv] lib.a files\n" +#ifdef TCC_TARGET_PE + " create .def file : tcc -impdef lib.dll [-v] [-o lib.def]\n" #endif ); } -/* 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 char *str_replace(const char *str, const char *p, const char *r) +static void version(void) { - const char *s, *s0; - char *d, *d0; - int sl, pl, rl; - - sl = strlen(str); - pl = strlen(p); - rl = strlen(r); - for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) { - for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) { - if (d) { - memcpy(d, s0, sl = s - s0), d += sl; - memcpy(d, r, rl), d += rl; - } else - sl += rl - pl; - } - if (d) { - strcpy(d, s0); - return d0; - } - } -} - -static int execvp_win32(const char *prog, char **argv) -{ - int ret; char **p; - /* replace all " by \" */ - for (p = argv; *p; ++p) - if (strchr(*p, '"')) - *p = str_replace(*p, "\"", "\\\""); - ret = _spawnvp(P_NOWAIT, prog, (const char *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, int option) -{ - char child_path[4096], *a0 = argv[0]; const char *target; - int l; - - switch (option) { - + printf("tcc version %s (" #ifdef TCC_TARGET_I386 - case 32: break; - case 64: target = "x86_64"; -#else - case 64: break; - case 32: target = "i386"; - + "i386" +#elif defined TCC_TARGET_X86_64 + "x86-64" +#elif defined TCC_TARGET_C67 + "C67" +#elif defined TCC_TARGET_ARM + "ARM" +# ifdef TCC_ARM_HARDFLOAT + " Hard Float" +# endif +#elif defined TCC_TARGET_ARM64 + "AArch64" +# ifdef TCC_ARM_HARDFLOAT + " Hard Float" +# endif #endif - l = tcc_basename(a0) - a0; - snprintf(child_path, sizeof child_path, #ifdef TCC_TARGET_PE - "%.*s%s-win32-tcc" + " Windows" +#elif defined(__APPLE__) + /* Current Apple OS name as of 2016 */ + " macOS" +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + " FreeBSD" +#elif defined(__DragonFly__) + " DragonFly BSD" +#elif defined(__NetBSD__) + " NetBSD" +#elif defined(__OpenBSD__) + " OpenBSD" +#elif defined(__linux__) + " Linux" #else - "%.*s%s-tcc" + " Unidentified system" #endif - , l, a0, target); - if (strcmp(a0, child_path)) { - if (s->verbose > 0) - printf("tcc: using '%s'\n", child_path + l), fflush(stdout); - execvp(argv[0] = child_path, argv); - } - tcc_error("'%s' not found", child_path + l); - } + ")\n", TCC_VERSION); } -#else -#define exec_other_tcc(s, argv, option) -#endif -static void gen_makedeps(TCCState *s, const char *target, const char *filename) +static void print_dirs(const char *msg, char **paths, int nb_paths) { - FILE *depout; - char buf[1024]; int i; + printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); + for(i = 0; i < nb_paths; i++) + printf(" %s\n", paths[i]); +} - if (!filename) { - /* compute filename automatically: dir/file.o -> dir/file.d */ - snprintf(buf, sizeof buf, "%.*s.d", - (int)(tcc_fileextension(target) - target), target); - 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 void print_search_dirs(TCCState *s) +{ + printf("install: %s\n", s->tcc_lib_path); + /* print_dirs("programs", NULL, 0); */ + print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths); + print_dirs("libraries", s->library_paths, s->nb_library_paths); +#ifndef TCC_TARGET_PE + print_dirs("crt", s->crt_paths, s->nb_crt_paths); + printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s)); +#endif } static char *default_outputfile(TCCState *s, const char *first_file) @@ -296,109 +195,113 @@ static unsigned getclock_ms(void) int main(int argc, char **argv) { TCCState *s; - int ret, optind, i; + int ret, opt, n = 0; unsigned start_time = 0; - const char *first_file = NULL; + const char *first_file; +redo: s = tcc_new(); + opt = tcc_parse_args(s, &argc, &argv, 1); - optind = tcc_parse_args(s, argc - 1, argv + 1); + if (n == 0) { + if (opt == OPT_HELP) + return help(), 1; + if (opt == OPT_M32 || opt == OPT_M64) + tcc_tool_cross(s, argv, opt); /* never returns */ + if (s->verbose) + version(); + if (opt == OPT_AR) + return tcc_tool_ar(s, argc, argv); +#ifdef TCC_TARGET_PE + if (opt == OPT_IMPDEF) + return tcc_tool_impdef(s, argc, argv); +#endif + if (opt == OPT_V) + return 0; - tcc_set_environment(s); + tcc_set_environment(s); - if (optind == 0) { - help(); - return 1; - } - - if (s->cross_target) - exec_other_tcc(s, argv, s->cross_target); - - if (s->verbose) - display_info(s, 0); - - if (s->nb_files == 0) { - if (optind == 1) { - if (s->print_search_dirs || s->verbose == 2) { - tcc_set_output_type(s, TCC_OUTPUT_MEMORY); - display_info(s, 1); - return 1; - } - if (s->verbose) - return 1; + if (opt == OPT_PRINT_DIRS) { + /* initialize search dirs */ + tcc_set_output_type(s, TCC_OUTPUT_MEMORY); + print_search_dirs(s); + return 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"); + n = s->nb_files; + if (n == 0) + tcc_error("no input files\n"); + + 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); + } + } else if (s->output_type == TCC_OUTPUT_OBJ) { + if (s->nb_libraries != 0 && !s->option_r) + tcc_error("cannot specify libraries with -c"); + if (n > 1 && s->outfile) + tcc_error("cannot specify output file with -c many files"); + } else { + if (s->option_pthread) + tcc_set_options(s, "-lpthread"); + } + + if (s->do_bench) + start_time = getclock_ms(); } if (s->output_type == 0) s->output_type = TCC_OUTPUT_EXE; tcc_set_output_type(s, s->output_type); - 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); - } - } else if (s->output_type != TCC_OUTPUT_OBJ) { - if (s->option_pthread) - tcc_set_options(s, "-lpthread"); - } - - if (s->do_bench) - start_time = getclock_ms(); - /* compile or add each files or library */ - for(i = ret = 0; i < s->nb_files && ret == 0; i++) { - struct filespec *f = s->files[i]; - if (f->type >= AFF_TYPE_LIB) { - s->alacarte_link = f->type == AFF_TYPE_LIB; + for (first_file = NULL, ret = 0;;) { + struct filespec *f = s->files[s->nb_files - n]; + s->filetype = f->type; + s->alacarte_link = f->alacarte; + if (f->type == AFF_TYPE_LIB) { if (tcc_add_library_err(s, f->name) < 0) ret = 1; } else { if (1 == s->verbose) printf("-> %s\n", f->name); - s->filetype = f->type; - if (tcc_add_file(s, f->name) < 0) - ret = 1; if (!first_file) first_file = f->name; + if (tcc_add_file(s, f->name) < 0) + ret = 1; } - s->filetype = AFF_TYPE_NONE; + s->filetype = 0; s->alacarte_link = 1; + if (ret || --n == 0 || s->output_type == TCC_OUTPUT_OBJ) + break; } if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (s->outfile) fclose(s->ppfp); - } else if (0 == ret) { if (s->output_type == TCC_OUTPUT_MEMORY) { #ifdef TCC_IS_NATIVE - ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); + ret = tcc_run(s, argc, argv); #endif } else { if (!s->outfile) s->outfile = default_outputfile(s, first_file); - ret = !!tcc_output_file(s, s->outfile); - if (s->gen_deps && !ret) + if (tcc_output_file(s, s->outfile)) + ret = 1; + else if (s->gen_deps) gen_makedeps(s, s->outfile, s->deps_outfile); } } - if (s->do_bench) + if (s->do_bench && ret == 0 && n == 0) tcc_print_stats(s, getclock_ms() - start_time); tcc_delete(s); + if (ret == 0 && n) + goto redo; /* compile more files with -c */ return ret; } diff --git a/tcc.h b/tcc.h index 3494836..fcf5780 100644 --- a/tcc.h +++ b/tcc.h @@ -767,17 +767,19 @@ struct TCCState { int nb_libraries; /* number of libs thereof */ int filetype; char *outfile; /* output filename */ - int cross_target; /* -m32/-m64 */ - 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 */ int option_pthread; /* -pthread option */ + int argc; + char **argv; }; struct filespec { - char type, name[1]; + char type; + char alacarte; + char name[1]; }; /* The current value can be: */ @@ -1091,7 +1093,7 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line); #define realloc(p, s) use_tcc_realloc(p, s) #undef strdup #define strdup(s) use_tcc_strdup(s) -PUB_FUNC void tcc_memstats(int bench); +PUB_FUNC void tcc_memcheck(void); PUB_FUNC void tcc_error_noabort(const char *fmt, ...); PUB_FUNC NORETURN void tcc_error(const char *fmt, ...); PUB_FUNC void tcc_warning(const char *fmt, ...); @@ -1131,14 +1133,12 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) #define AFF_TYPE_ASMPP 3 #define AFF_TYPE_BIN 4 #define AFF_TYPE_LIB 5 -#define AFF_TYPE_LIBWH 6 /* values from tcc_object_type(...) */ #define AFF_BINTYPE_REL 1 #define AFF_BINTYPE_DYN 2 #define AFF_BINTYPE_AR 3 #define AFF_BINTYPE_C67 4 - ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); #ifndef TCC_TARGET_PE @@ -1149,12 +1149,21 @@ ST_FUNC void tcc_add_pragma_libs(TCCState *s1); PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time); -PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv); +PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); PUB_FUNC void tcc_set_environment(TCCState *s); #ifdef _WIN32 ST_FUNC char *normalize_slashes(char *path); #endif +/* tcc_parse_args return codes: */ +#define OPT_HELP 1 +#define OPT_V 3 +#define OPT_PRINT_DIRS 4 +#define OPT_AR 5 +#define OPT_IMPDEF 6 +#define OPT_M32 32 +#define OPT_M64 64 + /* ------------ tccpp.c ------------ */ ST_DATA struct BufferedFile *file; @@ -1567,6 +1576,7 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); #ifdef TCC_TARGET_X86_64 ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack); #endif +PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); /* symbol properties stored in Elf32_Sym->st_other */ # define ST_PE_EXPORT 0x10 # define ST_PE_IMPORT 0x20 @@ -1595,6 +1605,16 @@ ST_FUNC void tcc_set_num_callers(int n); ST_FUNC void tcc_run_free(TCCState *s1); #endif +/* ------------ tcctools.c ----------------- */ +#if 0 /* included in tcc.c */ +ST_FUNC int tcc_tool_ar(TCCState *s, int argc, char **argv); +#ifdef TCC_TARGET_PE +ST_FUNC int tcc_tool_impdef(TCCState *s, int argc, char **argv); +#endif +ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option); +ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename); +#endif + /********************************************************/ #undef ST_DATA #ifdef ONE_SOURCE diff --git a/tccasm.c b/tccasm.c index b7d5881..0999a03 100644 --- a/tccasm.c +++ b/tccasm.c @@ -1005,6 +1005,7 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) /* default section is text */ cur_text_section = text_section; ind = cur_text_section->data_offset; + nocode_wanted = 0; /* an elf symbol of type STT_FILE must be put so that STB_LOCAL symbols can be safely used */ diff --git a/tccpe.c b/tccpe.c index cf2e475..50690df 100644 --- a/tccpe.c +++ b/tccpe.c @@ -962,7 +962,7 @@ static void pe_build_exports(struct pe_info *pe) } else { fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); if (pe->s1->verbose) - printf("<- %s (%d symbols)\n", buf, sym_count); + printf("<- %s (%d symbol%s)\n", buf, sym_count, "s" + (sym_count < 2)); } #endif @@ -1543,6 +1543,102 @@ static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) return len == read(fd, buffer, len); } +/* ------------------------------------------------------------- */ + +PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp) +{ + int l, i, n, n0, ret; + char *p; + int fd; + + IMAGE_SECTION_HEADER ish; + IMAGE_EXPORT_DIRECTORY ied; + IMAGE_DOS_HEADER dh; + IMAGE_FILE_HEADER ih; + DWORD sig, ref, addr, ptr, namep; +#ifdef TCC_TARGET_X86_64 + IMAGE_OPTIONAL_HEADER64 oh; +#else + IMAGE_OPTIONAL_HEADER32 oh; +#endif + int pef_hdroffset, opt_hdroffset, sec_hdroffset; + + n = n0 = 0; + p = NULL; + ret = -1; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + goto the_end_1; + ret = 1; + + if (!read_mem(fd, 0, &dh, sizeof dh)) + goto the_end; + 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(fd, pef_hdroffset, &ih, sizeof ih)) + goto the_end; + if (IMAGE_FILE_MACHINE != ih.Machine) { + if (ih.Machine == 0x014C) + ret = 32; + else if (ih.Machine == 0x8664) + ret = 64; + goto the_end; + } + opt_hdroffset = pef_hdroffset + sizeof ih; + sec_hdroffset = opt_hdroffset + sizeof oh; + if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) + goto the_end; + + if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) + goto the_end_0; + + addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + //printf("addr: %08x\n", addr); + for (i = 0; i < ih.NumberOfSections; ++i) { + 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) + goto found; + } + goto the_end_0; + +found: + ref = ish.VirtualAddress - ish.PointerToRawData; + 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(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(fd, ptr - ref + l++, p + n, 1)) { + tcc_free(p), p = NULL; + goto the_end; + } + if (p[n++] == 0) + break; + } + } + if (p) + p[n] = 0; +the_end_0: + ret = 0; +the_end: + close(fd); +the_end_1: + *pp = p; + return ret; +} + /* ------------------------------------------------------------- * This is for compiled windows resources in 'coff' format * as generated by 'windres.exe -O coff ...'. @@ -1660,20 +1756,20 @@ quit: } /* ------------------------------------------------------------- */ -#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY -#include "win32/tools/tiny_impdef.c" - -static int pe_load_dll(TCCState *s1, const char *dllname, int fd) +static int pe_load_dll(TCCState *s1, const char *filename) { char *p, *q; - int index; - p = get_export_names(fd); - if (!p) + int index, ret; + + ret = tcc_get_dllexports(filename, &p); + if (ret) { return -1; - index = add_dllref(s1, dllname); - for (q = p; *q; q += 1 + strlen(q)) - pe_putimport(s1, index, q, 0); - tcc_free(p); + } else if (p) { + index = add_dllref(s1, tcc_basename(filename)); + for (q = p; *q; q += 1 + strlen(q)) + pe_putimport(s1, index, q, 0); + tcc_free(p); + } return 0; } @@ -1687,7 +1783,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) else if (pe_load_res(s1, fd) == 0) ret = 0; else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4)) - ret = pe_load_dll(s1, tcc_basename(filename), fd); + ret = pe_load_dll(s1, filename); return ret; } diff --git a/tcctools.c b/tcctools.c new file mode 100644 index 0000000..235b783 --- /dev/null +++ b/tcctools.c @@ -0,0 +1,547 @@ +/* -------------------------------------------------------------- */ +/* + * TCC - Tiny C Compiler + * + * tcctools.c - extra tools and and -m32/64 support + * + */ + +/* -------------------------------------------------------------- */ +/* + * This program is for making libtcc1.a without ar + * tiny_libmaker - tiny elf lib maker + * usage: tiny_libmaker [lib] files... + * Copyright (c) 2007 Timppa + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "tcc.h" + +//#define ARMAG "!\n" +#define ARFMAG "`\n" + +typedef struct { + char ar_name[16]; + char ar_date[12]; + char ar_uid[6]; + char ar_gid[6]; + char ar_mode[8]; + char ar_size[10]; + char ar_fmag[2]; +} ArHdr; + +static unsigned long le2belong(unsigned long ul) { + return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) + + ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8); +} + +/* Returns 1 if s contains any of the chars of list, else 0 */ +static int contains_any(const char *s, const char *list) { + const char *l; + for (; *s; s++) { + for (l = list; *l; l++) { + if (*s == *l) + return 1; + } + } + return 0; +} + +static int ar_usage(int ret) { + fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n"); + fprintf(stderr, "create library ([abdioptxN] not supported).\n"); + return ret; +} + +ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv) +{ + static ArHdr arhdr = { + "/ ", + " ", + "0 ", + "0 ", + "0 ", + " ", + ARFMAG + }; + + static ArHdr arhdro = { + " ", + " ", + "0 ", + "0 ", + "0 ", + " ", + ARFMAG + }; + + FILE *fi, *fh = NULL, *fo = NULL; + ElfW(Ehdr) *ehdr; + ElfW(Shdr) *shdr; + ElfW(Sym) *sym; + int i, fsize, i_lib, i_obj; + char *buf, *shstr, *symtab = NULL, *strtab = NULL; + int symtabsize = 0;//, strtabsize = 0; + char *anames = NULL; + int *afpos = NULL; + int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; + char tfile[260], stmp[20]; + char *file, *name; + int ret = 2; + char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored. + int verbose = 0; + + i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj + for (i = 1; i < argc; i++) { + const char *a = argv[i]; + if (*a == '-' && strstr(a, ".")) + ret = 1; // -x.y is always invalid (same as gnu ar) + if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument + if (contains_any(a, ops_conflict)) + ret = 1; + if (strstr(a, "v")) + verbose = 1; + } else { // lib or obj files: don't abort - keep validating all args. + if (!i_lib) // first file is the lib + i_lib = i; + else if (!i_obj) // second file is the first obj + i_obj = i; + } + } + + if (!i_obj) // i_obj implies also i_lib. we require both. + ret = 1; + + if (ret == 1) + return ar_usage(ret); + + if ((fh = fopen(argv[i_lib], "wb")) == NULL) + { + fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]); + goto the_end; + } + + sprintf(tfile, "%s.tmp", argv[i_lib]); + if ((fo = fopen(tfile, "wb+")) == NULL) + { + fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile); + goto the_end; + } + + funcmax = 250; + afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func + memcpy(&arhdro.ar_mode, "100666", 6); + + // i_obj = first input object file + while (i_obj < argc) + { + if (*argv[i_obj] == '-') { // by now, all options start with '-' + i_obj++; + continue; + } + if ((fi = fopen(argv[i_obj], "rb")) == NULL) { + fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]); + goto the_end; + } + if (verbose) + printf("a - %s\n", argv[i_obj]); + + fseek(fi, 0, SEEK_END); + fsize = ftell(fi); + fseek(fi, 0, SEEK_SET); + buf = tcc_malloc(fsize + 1); + fread(buf, fsize, 1, fi); + fclose(fi); + + // elf header + ehdr = (ElfW(Ehdr) *)buf; + if (ehdr->e_ident[4] != ELFCLASSW) + { + fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]); + goto the_end; + } + + shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize); + shstr = (char *)(buf + shdr->sh_offset); + for (i = 0; i < ehdr->e_shnum; i++) + { + shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize); + if (!shdr->sh_offset) + continue; + if (shdr->sh_type == SHT_SYMTAB) + { + symtab = (char *)(buf + shdr->sh_offset); + symtabsize = shdr->sh_size; + } + if (shdr->sh_type == SHT_STRTAB) + { + if (!strcmp(shstr + shdr->sh_name, ".strtab")) + { + strtab = (char *)(buf + shdr->sh_offset); + //strtabsize = shdr->sh_size; + } + } + } + + if (symtab && symtabsize) + { + int nsym = symtabsize / sizeof(ElfW(Sym)); + //printf("symtab: info size shndx name\n"); + for (i = 1; i < nsym; i++) + { + sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym))); + if (sym->st_shndx && + (sym->st_info == 0x10 + || sym->st_info == 0x11 + || sym->st_info == 0x12 + )) { + //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name); + istrlen = strlen(strtab + sym->st_name)+1; + anames = tcc_realloc(anames, strpos+istrlen); + strcpy(anames + strpos, strtab + sym->st_name); + strpos += istrlen; + if (++funccnt >= funcmax) { + funcmax += 250; + afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more + } + afpos[funccnt] = fpos; + } + } + } + + file = argv[i_obj]; + for (name = strchr(file, 0); + name > file && name[-1] != '/' && name[-1] != '\\'; + --name); + istrlen = strlen(name); + if (istrlen >= sizeof(arhdro.ar_name)) + istrlen = sizeof(arhdro.ar_name) - 1; + memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name)); + memcpy(arhdro.ar_name, name, istrlen); + arhdro.ar_name[istrlen] = '/'; + sprintf(stmp, "%-10d", fsize); + memcpy(&arhdro.ar_size, stmp, 10); + fwrite(&arhdro, sizeof(arhdro), 1, fo); + fwrite(buf, fsize, 1, fo); + tcc_free(buf); + i_obj++; + fpos += (fsize + sizeof(arhdro)); + } + hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int); + fpos = 0; + if ((hofs & 1)) // align + hofs++, fpos = 1; + // write header + fwrite("!\n", 8, 1, fh); + sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int))); + memcpy(&arhdr.ar_size, stmp, 10); + fwrite(&arhdr, sizeof(arhdr), 1, fh); + afpos[0] = le2belong(funccnt); + for (i=1; i<=funccnt; i++) + afpos[i] = le2belong(afpos[i] + hofs); + fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh); + fwrite(anames, strpos, 1, fh); + if (fpos) + fwrite("", 1, 1, fh); + // write objects + fseek(fo, 0, SEEK_END); + fsize = ftell(fo); + fseek(fo, 0, SEEK_SET); + buf = tcc_malloc(fsize + 1); + fread(buf, fsize, 1, fo); + fwrite(buf, fsize, 1, fh); + tcc_free(buf); + ret = 0; +the_end: + if (anames) + tcc_free(anames); + if (afpos) + tcc_free(afpos); + if (fh) + fclose(fh); + if (fo) + fclose(fo), remove(tfile); + return ret; +} + +/* -------------------------------------------------------------- */ +/* + * tiny_impdef creates an export definition file (.def) from a dll + * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]" + * + * Copyright (c) 2005,2007 grischka + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef TCC_TARGET_PE + +ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv) +{ + int ret, v, i; + char infile[MAX_PATH]; + char outfile[MAX_PATH]; + + const char *file; + char *p, *q; + FILE *fp, *op; + +#ifdef _WIN32 + char path[MAX_PATH]; +#endif + + infile[0] = outfile[0] = 0; + fp = op = NULL; + ret = 1; + p = NULL; + v = 0; + + for (i = 1; i < argc; ++i) { + const char *a = argv[i]; + if ('-' == a[0]) { + if (0 == strcmp(a, "-v")) { + v = 1; + } else if (0 == strcmp(a, "-o")) { + if (++i == argc) + goto usage; + strcpy(outfile, argv[i]); + } else + goto usage; + } else if (0 == infile[0]) + strcpy(infile, a); + else + goto usage; + } + + if (0 == infile[0]) { +usage: + fprintf(stderr, + "usage: tcc -impdef library.dll [-v] [-o outputfile]\n" + "create export definition file (.def) from dll\n" + ); + goto the_end; + } + + if (0 == outfile[0]) { + strcpy(outfile, tcc_basename(infile)); + q = strrchr(outfile, '.'); + if (NULL == q) + q = strchr(outfile, 0); + strcpy(q, ".def"); + } + + file = infile; +#ifdef _WIN32 + if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL)) + file = path; +#endif + ret = tcc_get_dllexports(file, &p); + if (ret || !p) { + fprintf(stderr, "tcc: impdef: %s '%s'\n", + ret == 32 ? "can't read symbols from 32bit" : + ret == 64 ? "can't read symbols from 64bit" : + ret == -1 ? "can't find file" : + ret == 0 ? "no symbols found in" : + "unknown file type", file); + ret = 1; + goto the_end; + } + + if (v) + printf("-> %s\n", file); + + op = fopen(outfile, "w"); + if (NULL == op) { + fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile); + goto the_end; + } + + fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file)); + for (q = p, i = 0; *q; ++i) { + fprintf(op, "%s\n", q); + q += strlen(q) + 1; + } + + if (v) + printf("<- %s (%d symbol%s)\n", outfile, i, "s" + (i<2)); + + ret = 0; + +the_end: + /* cannot free memory received from tcc_get_dllexports + if it came from a dll */ + /* if (p) + tcc_free(p); */ + if (fp) + fclose(fp); + if (op) + fclose(op); + return ret; +} + +#endif /* TCC_TARGET_PE */ + +/* -------------------------------------------------------------- */ +/* + * 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 + */ + +/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ + +#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64 + +ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option) +{ + tcc_error("-m%d not implemented.", option); +} + +#else +#ifdef _WIN32 +#include + +static char *str_replace(const char *str, const char *p, const char *r) +{ + const char *s, *s0; + char *d, *d0; + int sl, pl, rl; + + sl = strlen(str); + pl = strlen(p); + rl = strlen(r); + for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) { + for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) { + if (d) { + memcpy(d, s0, sl = s - s0), d += sl; + memcpy(d, r, rl), d += rl; + } else + sl += rl - pl; + } + if (d) { + strcpy(d, s0); + return d0; + } + } +} + +static int execvp_win32(const char *prog, char **argv) +{ + int ret; char **p; + /* replace all " by \" */ + for (p = argv; *p; ++p) + if (strchr(*p, '"')) + *p = str_replace(*p, "\"", "\\\""); + ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv); + if (-1 == ret) + return ret; + _cwait(&ret, ret, WAIT_CHILD); + exit(ret); +} +#define execvp execvp_win32 +#endif /* _WIN32 */ + +ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target) +{ + char program[4096]; + char *a0 = argv[0]; + int prefix = tcc_basename(a0) - a0; + + snprintf(program, sizeof program, + "%.*s%s" +#ifdef TCC_TARGET_PE + "-win32" +#endif + "-tcc" +#ifdef _WIN32 + ".exe" +#endif + , prefix, a0, target == 64 ? "x86_64" : "i386"); + + if (strcmp(a0, program)) + execvp(argv[0] = program, argv); + tcc_error("could not run '%s'", program); +} + +#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */ +/* -------------------------------------------------------------- */ +/* enable commandline wildcard expansion (tcc -o x.exe *.c) */ + +#ifdef _WIN32 +int _CRT_glob = 1; +#ifndef _CRT_glob +int _dowildcard = 1; +#endif +#endif + +/* -------------------------------------------------------------- */ +/* generate xxx.d file */ + +ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename) +{ + FILE *depout; + char buf[1024]; + int i; + + if (!filename) { + /* compute filename automatically: dir/file.o -> dir/file.d */ + snprintf(buf, sizeof buf, "%.*s.d", + (int)(tcc_fileextension(target) - target), target); + 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); +} + +/* -------------------------------------------------------------- */ diff --git a/tests/tcctest.c b/tests/tcctest.c index e5b6558..988b212 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3431,7 +3431,7 @@ void builtin_test(void) i = sizeof (__builtin_choose_expr (0, ll, s)); printf("bce: %d\n", i); - printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); + //printf("bera: %p\n", __builtin_extract_return_addr((void*)43)); } #ifndef _WIN32 diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index daf5a12..924e808 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -5,10 +5,6 @@ @echo off setlocal -set VSCOMNTOOLS=%VS150COMNTOOLS% -if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS140COMNTOOLS% -if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS130COMNTOOLS% -if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS120COMNTOOLS% set CC=gcc -Os -s set /p VERSION= < ..\VERSION set INST= @@ -70,10 +66,17 @@ goto :a1 if not (%1)==() goto :usage if not "%CC%"=="@call :cl" goto :p1 +set VSCOMNTOOLS=%VS150COMNTOOLS% +if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS140COMNTOOLS% +if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS130COMNTOOLS% +if "%VSCOMNTOOLS%"=="" set VSCOMNTOOLS=%VS120COMNTOOLS% if %T%_==32_ set CLVARS="%VSCOMNTOOLS%..\..\VC\bin\vcvars32.bat" if %T%_==64_ set CLVARS="%VSCOMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat" if %T%_==_ set T=32& if %Platform%_==X64_ set T=64 +if %CLVARS%_==_ goto :p1 +if exist %CLVARS% call %CLVARS% :p1 + if not %T%_==_ goto :p2 set T=32 if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64 @@ -97,9 +100,6 @@ set PX=i386-win32 @echo on -@if %CLVARS%_==_ goto :config.h -call %CLVARS% - :config.h echo>..\config.h #define TCC_VERSION "%VERSION%" echo>> ..\config.h #ifdef TCC_TARGET_X86_64 @@ -108,7 +108,7 @@ echo>> ..\config.h #else echo>> ..\config.h #define CONFIG_TCC_LIBPATHS "{B}/lib/32;{B}/lib" echo>> ..\config.h #endif -@del /q *tcc.exe tiny_*.exe *tcc.dll +for %%f in (*tcc.exe *tcc.dll) do @del %%f :compiler %CC% -o libtcc.dll -shared ..\libtcc.c %D% -DONE_SOURCE -DLIBTCC_AS_DLL @@ -116,10 +116,6 @@ echo>> ..\config.h #endif %CC% -o tcc.exe ..\tcc.c libtcc.dll %D% %CC% -o %PX%-tcc.exe ..\tcc.c %DX% -DONE_SOURCE -:tools -%CC% -o tiny_impdef.exe tools\tiny_impdef.c %D% -%CC% -o tiny_libmaker.exe tools\tiny_libmaker.c %D% - @if (%TCC_FILES%)==(no) goto :files-done if not exist libtcc mkdir libtcc @@ -129,12 +125,11 @@ if not exist lib\64 mkdir lib\64 copy>nul ..\include\*.h include copy>nul ..\tcclib.h include copy>nul ..\libtcc.h libtcc -tiny_impdef libtcc.dll -o libtcc\libtcc.def copy>nul ..\tests\libtcc_test.c examples copy>nul tcc-win32.txt doc -copy>nul tiny_libmaker.exe tiny_libmaker-m%T%.exe -%CC% -o tiny_libmaker-m%TX%.exe tools\tiny_libmaker.c %DX% +.\tcc -impdef libtcc.dll -o libtcc\libtcc.def +@if errorlevel 1 goto :the_end :libtcc1.a @set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o @@ -149,7 +144,7 @@ copy>nul tiny_libmaker.exe tiny_libmaker-m%T%.exe .\tcc -m32 %D32% -w -c ../lib/bcheck.c .\tcc -m32 %D32% -c ../lib/alloca86.S .\tcc -m32 %D32% -c ../lib/alloca86-bt.S -tiny_libmaker-m32 lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o +.\tcc -m32 -ar lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o @if errorlevel 1 goto :the_end .\tcc -m64 %D64% -c ../lib/libtcc1.c .\tcc -m64 %D64% -c lib/crt1.c @@ -162,7 +157,7 @@ tiny_libmaker-m32 lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o .\tcc -m64 %D64% -w -c ../lib/bcheck.c .\tcc -m64 %D64% -c ../lib/alloca86_64.S .\tcc -m64 %D64% -c ../lib/alloca86_64-bt.S -tiny_libmaker-m64 lib/64/libtcc1.a %O1% alloca86_64.o alloca86_64-bt.o +.\tcc -m64 -ar lib/64/libtcc1.a %O1% alloca86_64.o alloca86_64-bt.o @if errorlevel 1 goto :the_end :tcc-doc.html @@ -172,7 +167,7 @@ cmd /c makeinfo --html --no-split ../tcc-doc.texi -o doc/tcc-doc.html :doc-done :files-done -@del /q *.o *.def *-m??.exe +for %%f in (*.o *.def) do @del %%f :copy-install @if (%INST%)==() goto :the_end diff --git a/win32/tcc-win32.txt b/win32/tcc-win32.txt index dfcfb1b..3609684 100644 --- a/win32/tcc-win32.txt +++ b/win32/tcc-win32.txt @@ -39,7 +39,7 @@ For the 'Hello DLL' example type tcc -shared dll.c - tiny_impdef dll.dll (optional) + tcc -impdef dll.dll (optional) tcc hello_dll.c dll.def @@ -66,10 +66,10 @@ To link with Windows system DLLs, TCC uses import definition files (.def) instead of libraries. - The included 'tiny_impdef' program may be used to make additional - .def files for any DLL. For example: + The now built-in 'tiny_impdef' program may be used to make + additional .def files for any DLL. For example - tiny_impdef.exe opengl32.dll + tcc -impdef [-v] opengl32.dll [-o opengl32.def] Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at the TCC commandline to link a program that uses opengl32.dll. @@ -98,10 +98,10 @@ Tiny Libmaker: -------------- - The included tiny_libmaker tool by Timovj Lahde can be used as + The now built-in tiny_libmaker tool by Timovj Lahde can be used as 'ar' replacement to make a library from several object files: - tiny_libmaker [rcs] library objectfiles ... + tcc -ar [rcsv] library objectfiles ... Compilation from source: @@ -143,15 +143,13 @@ ------------ - On the object file level, currently TCC supports only the ELF format, not COFF as used by MinGW and MSVC. It is not possible to exchange - object files or libraries between TCC and these compilers. However - libraries for TCC from objects by TCC can be made using tiny_libmaker - or MinGW's ar. + object files or libraries between TCC and these compilers. + + However libraries for TCC from objects by TCC can be made using + tcc -ar lib.a files.o ,,, - No leading underscore is generated in the ELF symbols. - - 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 diff --git a/win32/tools/tiny_impdef.c b/win32/tools/tiny_impdef.c deleted file mode 100644 index b6debe6..0000000 --- a/win32/tools/tiny_impdef.c +++ /dev/null @@ -1,249 +0,0 @@ -/* -------------------------------------------------------------- */ -/* - * tiny_impdef creates an export definition file (.def) from a dll - * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]" - * - * Copyright (c) 2005,2007 grischka - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef TINY_IMPDEF_GET_EXPORT_NAMES_ONLY - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include - -static char *get_export_names(int fd); -#define tcc_free free -#define tcc_realloc realloc - -/* extract the basename of a file */ -static char *file_basename(const char *name) -{ - const char *p = strchr(name, 0); - while (p > name - && p[-1] != '/' - && p[-1] != '\\' - ) - --p; - return (char*)p; -} - -int main(int argc, char **argv) -{ - int ret, v, i; - char infile[MAX_PATH]; - char outfile[MAX_PATH]; - - static const char *ext[] = { ".dll", ".exe", NULL }; - const char *file, **pp; - char path[MAX_PATH], *p, *q; - FILE *fp, *op; - - infile[0] = 0; - outfile[0] = 0; - fp = op = NULL; - v = 0; - ret = 1; - p = NULL; - - for (i = 1; i < argc; ++i) { - const char *a = argv[i]; - if ('-' == a[0]) { - if (0 == strcmp(a, "-v")) { - v = 1; - } else if (0 == strcmp(a, "-o")) { - if (++i == argc) - goto usage; - strcpy(outfile, argv[i]); - } else - goto usage; - } else if (0 == infile[0]) - strcpy(infile, a); - else - goto usage; - } - - if (0 == infile[0]) { -usage: - fprintf(stderr, - "tiny_impdef: create export definition file (.def) from a dll\n" - "Usage: tiny_impdef library.dll [-o outputfile]\n" - ); - goto the_end; - } - - if (0 == outfile[0]) - { - strcpy(outfile, file_basename(infile)); - q = strrchr(outfile, '.'); - if (NULL == q) - q = strchr(outfile, 0); - strcpy(q, ".def"); - } - - file = infile; - -#ifdef _WIN32 - pp = ext; - do if (SearchPath(NULL, file, *pp, sizeof path, path, NULL)) { - file = path; - break; - } while (*pp++); -#endif - - fp = fopen(file, "rb"); - if (NULL == fp) { - fprintf(stderr, "tiny_impdef: no such file: %s\n", infile); - goto the_end; - } - if (v) - printf("--> %s\n", file); - - p = get_export_names(fileno(fp)); - if (NULL == p) { - fprintf(stderr, "tiny_impdef: could not get exported function names.\n"); - goto the_end; - } - - op = fopen(outfile, "w"); - if (NULL == op) { - fprintf(stderr, "tiny_impdef: could not create output file: %s\n", outfile); - goto the_end; - } - - fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(file)); - for (q = p, i = 0; *q; ++i) { - fprintf(op, "%s\n", q); - q += strlen(q) + 1; - } - - if (v) { - printf("<-- %s\n", outfile); - printf("%d symbol(s) found\n", i); - } - - ret = 0; - -the_end: - if (p) - free(p); - if (fp) - fclose(fp); - if (op) - fclose(op); - return ret; -} - -int read_mem(int fd, unsigned offset, void *buffer, unsigned len) -{ - lseek(fd, offset, SEEK_SET); - return len == read(fd, buffer, len); -} - -/* -------------------------------------------------------------- */ - -#if defined TCC_TARGET_X86_64 -# define IMAGE_FILE_MACHINE 0x8664 -#elif defined TCC_TARGET_ARM -# define IMAGE_FILE_MACHINE 0x01C0 -#elif 1 /* defined TCC_TARGET_I386 */ -# define IMAGE_FILE_MACHINE 0x014C -#endif - -/* -------------------------------------------------------------- */ -#endif - -static char *get_export_names(int fd) -{ - int l, i, n, n0; - char *p; - - IMAGE_SECTION_HEADER ish; - IMAGE_EXPORT_DIRECTORY ied; - IMAGE_DOS_HEADER dh; - IMAGE_FILE_HEADER ih; - DWORD sig, ref, addr, ptr, namep; -#ifdef TCC_TARGET_X86_64 - IMAGE_OPTIONAL_HEADER64 oh; -#else - IMAGE_OPTIONAL_HEADER32 oh; -#endif - int pef_hdroffset, opt_hdroffset, sec_hdroffset; - - n = n0 = 0; - p = NULL; - - if (!read_mem(fd, 0, &dh, sizeof dh)) - goto the_end; - 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(fd, pef_hdroffset, &ih, sizeof ih)) - goto the_end; - if (IMAGE_FILE_MACHINE != ih.Machine) - goto the_end; - opt_hdroffset = pef_hdroffset + sizeof ih; - sec_hdroffset = opt_hdroffset + sizeof oh; - if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) - goto the_end; - - if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) - goto the_end; - - addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - //printf("addr: %08x\n", addr); - for (i = 0; i < ih.NumberOfSections; ++i) { - 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) - goto found; - } - goto the_end; - -found: - ref = ish.VirtualAddress - ish.PointerToRawData; - 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(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(fd, ptr - ref + l++, p + n, 1)) { - tcc_free(p), p = NULL; - goto the_end; - } - if (p[n++] == 0) - break; - } - } - if (p) - p[n] = 0; -the_end: - return p; -} - -/* -------------------------------------------------------------- */ diff --git a/win32/tools/tiny_libmaker.c b/win32/tools/tiny_libmaker.c deleted file mode 100644 index a694915..0000000 --- a/win32/tools/tiny_libmaker.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * This program is for making libtcc1.a without ar - * tiny_libmaker - tiny elf lib maker - * usage: tiny_libmaker [lib] files... - * Copyright (c) 2007 Timppa - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include -#include -#include -#include "../../elf.h" - -#ifdef TCC_TARGET_X86_64 -# define ELFCLASSW ELFCLASS64 -# define ElfW(type) Elf##64##_##type -# define ELFW(type) ELF##64##_##type -#else -# define ELFCLASSW ELFCLASS32 -# define ElfW(type) Elf##32##_##type -# define ELFW(type) ELF##32##_##type -#endif - -#define ARMAG "!\n" -#define ARFMAG "`\n" - -typedef struct ArHdr { - char ar_name[16]; - char ar_date[12]; - char ar_uid[6]; - char ar_gid[6]; - char ar_mode[8]; - char ar_size[10]; - char ar_fmag[2]; -} ArHdr; - -unsigned long le2belong(unsigned long ul) { - return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) + - ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8); -} - -ArHdr arhdr = { - "/ ", - " ", - "0 ", - "0 ", - "0 ", - " ", - ARFMAG - }; - -ArHdr arhdro = { - " ", - " ", - "0 ", - "0 ", - "0 ", - " ", - ARFMAG - }; - -/* Returns 1 if s contains any of the chars of list, else 0 */ -int contains_any(const char *s, const char *list) { - const char *l; - for (; *s; s++) { - for (l = list; *l; l++) { - if (*s == *l) - return 1; - } - } - return 0; -} - -int usage(int ret) { - fprintf(stderr, "usage: tiny_libmaker [rcsv] lib file...\n"); - fprintf(stderr, "Always creates a new lib. [abdioptxN] are explicitly rejected.\n"); - return ret; -} - -int main(int argc, char **argv) -{ - FILE *fi, *fh = NULL, *fo = NULL; - ElfW(Ehdr) *ehdr; - ElfW(Shdr) *shdr; - ElfW(Sym) *sym; - int i, fsize, i_lib, i_obj; - char *buf, *shstr, *symtab = NULL, *strtab = NULL; - int symtabsize = 0;//, strtabsize = 0; - char *anames = NULL; - int *afpos = NULL; - int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs; - char tfile[260], stmp[20]; - char *file, *name; - int ret = 2; - char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored. - int verbose = 0; - - i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj - for (i = 1; i < argc; i++) { - const char *a = argv[i]; - if (*a == '-' && strstr(a, ".")) - return usage(1); // -x.y is always invalid (same as gnu ar) - if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument - if (contains_any(a, ops_conflict)) - return usage(1); - if (strstr(a, "v")) - verbose = 1; - } else { // lib or obj files: don't abort - keep validating all args. - if (!i_lib) // first file is the lib - i_lib = i; - else if (!i_obj) // second file is the first obj - i_obj = i; - } - } - if (!i_obj) // i_obj implies also i_lib. we require both. - return usage(1); - - if ((fh = fopen(argv[i_lib], "wb")) == NULL) - { - fprintf(stderr, "Can't open file %s \n", argv[i_lib]); - goto the_end; - } - - sprintf(tfile, "%s.tmp", argv[i_lib]); - if ((fo = fopen(tfile, "wb+")) == NULL) - { - fprintf(stderr, "Can't create temporary file %s\n", tfile); - goto the_end; - } - - funcmax = 250; - afpos = realloc(NULL, funcmax * sizeof *afpos); // 250 func - memcpy(&arhdro.ar_mode, "100666", 6); - - // i_obj = first input object file - while (i_obj < argc) - { - if (*argv[i_obj] == '-') { // by now, all options start with '-' - i_obj++; - continue; - } - if (verbose) - printf("a - %s\n", argv[i_obj]); - - if ((fi = fopen(argv[i_obj], "rb")) == NULL) - { - fprintf(stderr, "Can't open file %s \n", argv[i_obj]); - goto the_end; - } - fseek(fi, 0, SEEK_END); - fsize = ftell(fi); - fseek(fi, 0, SEEK_SET); - buf = malloc(fsize + 1); - fread(buf, fsize, 1, fi); - fclose(fi); - - // elf header - ehdr = (ElfW(Ehdr) *)buf; - if (ehdr->e_ident[4] != ELFCLASSW) - { - fprintf(stderr, "Unsupported Elf Class: %s\n", argv[i_obj]); - goto the_end; - } - - shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize); - shstr = (char *)(buf + shdr->sh_offset); - for (i = 0; i < ehdr->e_shnum; i++) - { - shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize); - if (!shdr->sh_offset) - continue; - if (shdr->sh_type == SHT_SYMTAB) - { - symtab = (char *)(buf + shdr->sh_offset); - symtabsize = shdr->sh_size; - } - if (shdr->sh_type == SHT_STRTAB) - { - if (!strcmp(shstr + shdr->sh_name, ".strtab")) - { - strtab = (char *)(buf + shdr->sh_offset); - //strtabsize = shdr->sh_size; - } - } - } - - if (symtab && symtabsize) - { - int nsym = symtabsize / sizeof(ElfW(Sym)); - //printf("symtab: info size shndx name\n"); - for (i = 1; i < nsym; i++) - { - sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym))); - if (sym->st_shndx && - (sym->st_info == 0x10 - || sym->st_info == 0x11 - || sym->st_info == 0x12 - )) { - //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name); - istrlen = strlen(strtab + sym->st_name)+1; - anames = realloc(anames, strpos+istrlen); - strcpy(anames + strpos, strtab + sym->st_name); - strpos += istrlen; - if (++funccnt >= funcmax) { - funcmax += 250; - afpos = realloc(afpos, funcmax * sizeof *afpos); // 250 func more - } - afpos[funccnt] = fpos; - } - } - } - - file = argv[i_obj]; - for (name = strchr(file, 0); - name > file && name[-1] != '/' && name[-1] != '\\'; - --name); - istrlen = strlen(name); - if (istrlen >= sizeof(arhdro.ar_name)) - istrlen = sizeof(arhdro.ar_name) - 1; - memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name)); - memcpy(arhdro.ar_name, name, istrlen); - arhdro.ar_name[istrlen] = '/'; - sprintf(stmp, "%-10d", fsize); - memcpy(&arhdro.ar_size, stmp, 10); - fwrite(&arhdro, sizeof(arhdro), 1, fo); - fwrite(buf, fsize, 1, fo); - free(buf); - i_obj++; - fpos += (fsize + sizeof(arhdro)); - } - hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int); - fpos = 0; - if ((hofs & 1)) // align - hofs++, fpos = 1; - // write header - fwrite("!\n", 8, 1, fh); - sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int))); - memcpy(&arhdr.ar_size, stmp, 10); - fwrite(&arhdr, sizeof(arhdr), 1, fh); - afpos[0] = le2belong(funccnt); - for (i=1; i<=funccnt; i++) - afpos[i] = le2belong(afpos[i] + hofs); - fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh); - fwrite(anames, strpos, 1, fh); - if (fpos) - fwrite("", 1, 1, fh); - // write objects - fseek(fo, 0, SEEK_END); - fsize = ftell(fo); - fseek(fo, 0, SEEK_SET); - buf = malloc(fsize + 1); - fread(buf, fsize, 1, fo); - fwrite(buf, fsize, 1, fh); - free(buf); - ret = 0; -the_end: - if (anames) - free(anames); - if (afpos) - free(afpos); - if (fh) - fclose(fh); - if (fo) - fclose(fo), remove(tfile); - return ret; -}