Browse Source

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)
grischka 2 years ago
parent
commit
2d3b9559bf
17 changed files with 996 additions and 915 deletions
  1. 1 0
      Changelog
  2. 10 10
      Makefile
  3. 1 0
      TODO
  4. 16 6
      conftest.c
  5. 10 20
      lib/Makefile
  6. 128 82
      libtcc.c
  7. 1 1
      libtcc.h
  8. 121 218
      tcc.c
  9. 27 7
      tcc.h
  10. 1 0
      tccasm.c
  11. 109 13
      tccpe.c
  12. 547 0
      tcctools.c
  13. 1 1
      tests/tcctest.c
  14. 13 18
      win32/build-tcc.bat
  15. 10 12
      win32/tcc-win32.txt
  16. 0 249
      win32/tools/tiny_impdef.c
  17. 0 278
      win32/tools/tiny_libmaker.c

+ 1 - 0
Changelog

@@ -7,6 +7,7 @@ User interface:
 - -mms-bitfields option (David Mertens)
 - -include <file> 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)
 

+ 10 - 10
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
 

+ 1 - 0
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

+ 16 - 6
conftest.c

@@ -1,9 +1,9 @@
 #include <stdio.h>
 
 /* 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;

+ 10 - 20
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)

+ 128 - 82
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);
 }
 
+static int args_parser_make_argv(const char *r, int *argc, char ***argv)
+{
+    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)
+static void args_parser_listfile(TCCState *s,
+    const char *filename, int optind, int *pargc, char ***pargv)
 {
-    int fd;
+    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)

+ 1 - 1
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 */

+ 121 - 218
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 <process.h>
-
-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
-static void exec_other_tcc(TCCState *s, char **argv, int option)
+static void version(void)
 {
-    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; i<s->nb_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);
+
+    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;
 
-    optind = tcc_parse_args(s, argc - 1, argv + 1);
-
-    tcc_set_environment(s);
-
-    if (optind == 0) {
-        help();
-        return 1;
-    }
-
-    if (s->cross_target)
-        exec_other_tcc(s, argv, s->cross_target);
+        tcc_set_environment(s);
 
-    if (s->verbose)
-        display_info(s, 0);
+        if (opt == OPT_PRINT_DIRS) {
+            /* initialize search dirs */
+            tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+            print_search_dirs(s);
+            return 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;
+        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);
             }
-            if (s->verbose)
-                return 1;
+        } 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");
         }
-        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->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;
 }

+ 27 - 7
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

+ 1 - 0
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 */

+ 109 - 13
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;
 }
 

+ 547 - 0
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  "!<arch>\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("!<arch>\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 <process.h>
+
+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; i<s->nb_target_deps; ++i)
+        fprintf(depout, " %s \\\n", s->target_deps[i]);
+    fprintf(depout, "\n");
+    fclose(depout);
+}
+
+/* -------------------------------------------------------------- */

+ 1 - 1
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

+ 13 - 18
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

+ 10 - 12
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,14 +143,12 @@
     ------------
     - 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.
 
-    - No leading underscore is generated in the ELF symbols.
-
-    - Bounds checking (option -b) is not supported on 64-bit OS.
+      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.
 
     Documentation and License:
     --------------------------

+ 0 - 249
win32/tools/tiny_impdef.c

@@ -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 <windows.h>
-#include <stdio.h>
-#include <io.h>
-#include <malloc.h>
-
-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;
-}
-
-/* -------------------------------------------------------------- */

+ 0 - 278
win32/tools/tiny_libmaker.c

@@ -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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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  "!<arch>\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("!<arch>\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;
-}