From dda95e9b0b30771369efe66b4a47e94cf0ca7dc0 Mon Sep 17 00:00:00 2001
From: grischka <grischka>
Date: Sun, 1 Aug 2021 20:04:46 +0200
Subject: [PATCH] WAIT/POST_SEM(): generalize interface (and more)

Currently used only with 'tcc_compile_sem' to protect
tcc_compile(),  but can be used with other semaphores

Also fix deadlock when tcc_enter_state() is called
recursively for the same state, for example with
tcc_warning() from #pragma comment(option,"...")

Also:
- libtcc.c: error1(): use cstr_[v]printf()
- tcc.h: set TCC_USING_DOUBLE_FOR_LDOUBLE for macho-arm64
  (rather than for macho-X86_64)
- tcc.h: define TCC_TARGET_MACHO on __APPLE__ by default
- tcc.h: cleanup TCCState, move DEFASM token stuff to tcctok.h
- tccgen.c: more static
- Makefile/tcc.c: review githash
- tccpe/tcctools: use read() instead of fgets() in pe_load_def()
  (all files opened by tcc for reading are now read via 'int fd')
- configure/win32: don't preset CONFIG_TCCDIR (to allow to override it)
- tcc.c -bench: do not include output/run-time
---
 Makefile               |  10 +-
 configure              |   4 +-
 i386-tok.h             |  76 +++++++++++++++
 libtcc.c               | 175 +++++++++++++++-------------------
 tcc.c                  |  17 ++--
 tcc.h                  | 212 +++++++++++++++--------------------------
 tccasm.c               |  17 ++++
 tccgen.c               |  34 +++----
 tccmacho.c             |   2 +-
 tccpe.c                |  92 +++++++++---------
 tccpp.c                |  13 ++-
 tcctok.h               |  16 +++-
 tcctools.c             |   6 +-
 tests/libtcc_test_mt.c |   9 +-
 14 files changed, 361 insertions(+), 322 deletions(-)

diff --git a/Makefile b/Makefile
index 5ed0be4b..fca50dd4 100644
--- a/Makefile
+++ b/Makefile
@@ -134,7 +134,7 @@ all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
 
 # cross compiler targets to build
 TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
-TCC_X += riscv64
+TCC_X += riscv64 arm64-osx
 # TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
 
 # cross libtcc1.a targets to build
@@ -222,10 +222,9 @@ $(TCC_FILES) : DEFINES += -DONE_SOURCE=0
 $(X)tccpp.o : $(TCCDEFS_H)
 endif
 
-TCC_GIT_HASH=$(shell git rev-parse > /dev/null 2>&1 && git rev-parse --short HEAD || echo no)
-ifneq ($(TCC_GIT_HASH),no)
-MODIFIED = $(shell git diff | grep -q +++ && echo "modified ")
-$(X)tcc.o : DEFINES +=  -DTCC_GIT_HASH="\"$(MODIFIED)$(TCC_GIT_HASH)\""
+GITHASH := $(shell git rev-parse >/dev/null 2>&1 && git rev-parse --short HEAD || echo no)
+ifneq ($(GITHASH),no)
+DEF_GITHASH := -DTCC_GITHASH="\"$(GITHASH)$(shell git diff --quiet || echo '-mod')\""
 endif
 
 ifeq ($(CONFIG_debug),yes)
@@ -247,6 +246,7 @@ $(X)%.o : %.c $(LIBTCC_INC)
 
 # additional dependencies
 $(X)tcc.o : tcctools.c
+$(X)tcc.o : DEFINES += $(DEF_GITHASH)
 
 # Host Tiny C Compiler
 tcc$(EXESUF): tcc.o $(LIBTCC)
diff --git a/configure b/configure
index 1618570c..2a003981 100755
--- a/configure
+++ b/configure
@@ -238,7 +238,7 @@ if test "$mingw32" = "yes" ; then
       source_path="."
     fi
     test -z "$prefix" && prefix="C:/Program Files/tcc"
-    test -z "$tccdir" && tccdir="${prefix}"
+    test -z "$tccdir" && tccdir="${prefix}" && tccdir_auto="yes"
     test -z "$bindir" && bindir="${tccdir}"
     test -z "$docdir" && docdir="${tccdir}/doc"
     test -z "$libdir" && libdir="${tccdir}/libtcc"
@@ -483,7 +483,7 @@ print_mak() {
 echo "/* Automatically generated by configure - do not modify */" > $TMPH
 
 print_inc CONFIG_SYSROOT "$sysroot"
-print_inc CONFIG_TCCDIR "$tccdir"
+test "$tccdir_auto" = "yes" || print_inc CONFIG_TCCDIR "$tccdir"
 print_mak CONFIG_USR_INCLUDE "$tcc_usrinclude"
 print_mak CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths"
 print_mak CONFIG_TCC_LIBPATHS "$tcc_libpaths"
diff --git a/i386-tok.h b/i386-tok.h
index 8c25af09..e3ef2c75 100644
--- a/i386-tok.h
+++ b/i386-tok.h
@@ -1,6 +1,82 @@
 /* ------------------------------------------------------------------ */
 /* WARNING: relative order of tokens is important. */
 
+#define DEF_BWL(x) \
+ DEF(TOK_ASM_ ## x ## b, #x "b") \
+ DEF(TOK_ASM_ ## x ## w, #x "w") \
+ DEF(TOK_ASM_ ## x ## l, #x "l") \
+ DEF(TOK_ASM_ ## x, #x)
+#define DEF_WL(x) \
+ DEF(TOK_ASM_ ## x ## w, #x "w") \
+ DEF(TOK_ASM_ ## x ## l, #x "l") \
+ DEF(TOK_ASM_ ## x, #x)
+#ifdef TCC_TARGET_X86_64
+# define DEF_BWLQ(x) \
+ DEF(TOK_ASM_ ## x ## b, #x "b") \
+ DEF(TOK_ASM_ ## x ## w, #x "w") \
+ DEF(TOK_ASM_ ## x ## l, #x "l") \
+ DEF(TOK_ASM_ ## x ## q, #x "q") \
+ DEF(TOK_ASM_ ## x, #x)
+# define DEF_WLQ(x) \
+ DEF(TOK_ASM_ ## x ## w, #x "w") \
+ DEF(TOK_ASM_ ## x ## l, #x "l") \
+ DEF(TOK_ASM_ ## x ## q, #x "q") \
+ DEF(TOK_ASM_ ## x, #x)
+# define DEF_BWLX DEF_BWLQ
+# define DEF_WLX DEF_WLQ
+/* number of sizes + 1 */
+# define NBWLX 5
+#else
+# define DEF_BWLX DEF_BWL
+# define DEF_WLX DEF_WL
+/* number of sizes + 1 */
+# define NBWLX 4
+#endif
+
+#define DEF_FP1(x) \
+ DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \
+ DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \
+ DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \
+ DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s")
+
+#define DEF_FP(x) \
+ DEF(TOK_ASM_ ## f ## x, "f" #x ) \
+ DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \
+ DEF_FP1(x)
+
+#define DEF_ASMTEST(x,suffix) \
+ DEF_ASM(x ## o ## suffix) \
+ DEF_ASM(x ## no ## suffix) \
+ DEF_ASM(x ## b ## suffix) \
+ DEF_ASM(x ## c ## suffix) \
+ DEF_ASM(x ## nae ## suffix) \
+ DEF_ASM(x ## nb ## suffix) \
+ DEF_ASM(x ## nc ## suffix) \
+ DEF_ASM(x ## ae ## suffix) \
+ DEF_ASM(x ## e ## suffix) \
+ DEF_ASM(x ## z ## suffix) \
+ DEF_ASM(x ## ne ## suffix) \
+ DEF_ASM(x ## nz ## suffix) \
+ DEF_ASM(x ## be ## suffix) \
+ DEF_ASM(x ## na ## suffix) \
+ DEF_ASM(x ## nbe ## suffix) \
+ DEF_ASM(x ## a ## suffix) \
+ DEF_ASM(x ## s ## suffix) \
+ DEF_ASM(x ## ns ## suffix) \
+ DEF_ASM(x ## p ## suffix) \
+ DEF_ASM(x ## pe ## suffix) \
+ DEF_ASM(x ## np ## suffix) \
+ DEF_ASM(x ## po ## suffix) \
+ DEF_ASM(x ## l ## suffix) \
+ DEF_ASM(x ## nge ## suffix) \
+ DEF_ASM(x ## nl ## suffix) \
+ DEF_ASM(x ## ge ## suffix) \
+ DEF_ASM(x ## le ## suffix) \
+ DEF_ASM(x ## ng ## suffix) \
+ DEF_ASM(x ## nle ## suffix) \
+ DEF_ASM(x ## g ## suffix)
+
+/* ------------------------------------------------------------------ */
 /* register */
  DEF_ASM(al)
  DEF_ASM(cl)
diff --git a/libtcc.c b/libtcc.c
index e1976816..949a7ced 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -21,6 +21,7 @@
 #if !defined ONE_SOURCE || ONE_SOURCE
 #include "tccpp.c"
 #include "tccgen.c"
+#include "tccasm.c"
 #include "tccelf.c"
 #include "tccrun.c"
 #ifdef TCC_TARGET_I386
@@ -50,9 +51,6 @@
 #else
 #error unknown target
 #endif
-#ifdef CONFIG_TCC_ASM
-#include "tccasm.c"
-#endif
 #ifdef TCC_TARGET_PE
 #include "tccpe.c"
 #endif
@@ -68,6 +66,7 @@
 
 /* XXX: get rid of this ASAP (or maybe not) */
 ST_DATA struct TCCState *tcc_state;
+TCC_SEM(static tcc_compile_sem);
 
 #ifdef MEM_DEBUG
 static int nb_states;
@@ -84,19 +83,23 @@ ST_FUNC char *normalize_slashes(char *path)
     return path;
 }
 
+/* NULL if this is tcc.exe, HINSTANCE if this is libtcc.dll */
 static HMODULE tcc_module;
 
+#ifndef CONFIG_TCCDIR
 /* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */
-static void tcc_set_lib_path_w32(TCCState *s)
+static inline char *config_tccdir_w32(char *path)
 {
-    char path[1024], *p;
-    GetModuleFileNameA(tcc_module, path, sizeof path);
+    char *p;
+    GetModuleFileName(tcc_module, path, MAX_PATH);
     p = tcc_basename(normalize_slashes(strlwr(path)));
     if (p > path)
         --p;
     *p = 0;
-    tcc_set_lib_path(s, path);
+    return path;
 }
+#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH))
+#endif
 
 #ifdef TCC_TARGET_PE
 static void tcc_add_systemdir(TCCState *s)
@@ -118,47 +121,60 @@ BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
 #endif
 
 /********************************************************/
-#if CONFIG_TCC_SEMLOCK == 0
-#define WAIT_SEM()
-#define POST_SEM()
-#elif defined _WIN32
-static int tcc_sem_init;
-static CRITICAL_SECTION tcc_cr;
-static void wait_sem(void)
+#if CONFIG_TCC_SEMLOCK
+#if defined _WIN32
+ST_FUNC void wait_sem(TCCSem *p)
 {
-    if (!tcc_sem_init)
-        InitializeCriticalSection(&tcc_cr), tcc_sem_init = 1;
-    EnterCriticalSection(&tcc_cr);
+    if (!p->init)
+        InitializeCriticalSection(&p->cr), p->init = 1;
+    EnterCriticalSection(&p->cr);
+}
+ST_FUNC void post_sem(TCCSem *p)
+{
+    LeaveCriticalSection(&p->cr);
 }
-#define WAIT_SEM() wait_sem()
-#define POST_SEM() LeaveCriticalSection(&tcc_cr);
 #elif defined __APPLE__
 /* Half-compatible MacOS doesn't have non-shared (process local)
    semaphores.  Use the dispatch framework for lightweight locks.  */
-#include <dispatch/dispatch.h>
-static int tcc_sem_init;
-static dispatch_semaphore_t tcc_sem;
-static void wait_sem(void)
+ST_FUNC void wait_sem(TCCSem *p)
 {
-    if (!tcc_sem_init)
-      tcc_sem = dispatch_semaphore_create(1), tcc_sem_init = 1;
-    dispatch_semaphore_wait(tcc_sem, DISPATCH_TIME_FOREVER);
+    if (!p->init)
+        p->sem = dispatch_semaphore_create(1), p->init = 1;
+    dispatch_semaphore_wait(p->sem, DISPATCH_TIME_FOREVER);
+}
+ST_FUNC void post_sem(TCCSem *p)
+{
+    dispatch_semaphore_signal(p->sem);
 }
-#define WAIT_SEM() wait_sem()
-#define POST_SEM() dispatch_semaphore_signal(tcc_sem)
 #else
-#include <semaphore.h>
-static int tcc_sem_init;
-static sem_t tcc_sem;
-static void wait_sem(void)
+ST_FUNC void wait_sem(TCCSem *p)
 {
-    if (!tcc_sem_init)
-        sem_init(&tcc_sem, 0, 1), tcc_sem_init = 1;
-    while (sem_wait (&tcc_sem) < 0 && errno == EINTR);
+    if (!p->init)
+        sem_init(&p->sem, 0, 1), p->init = 1;
+    while (sem_wait(&p->sem) < 0 && errno == EINTR);
+}
+ST_FUNC void post_sem(TCCSem *p)
+{
+    sem_post(&p->sem);
 }
-#define WAIT_SEM() wait_sem()
-#define POST_SEM() sem_post(&tcc_sem)
 #endif
+#endif
+
+PUB_FUNC void tcc_enter_state(TCCState *s1)
+{
+    if (s1->error_set_jmp_enabled)
+        return;
+    WAIT_SEM(&tcc_compile_sem);
+    tcc_state = s1;
+}
+
+PUB_FUNC void tcc_exit_state(TCCState *s1)
+{
+    if (s1->error_set_jmp_enabled)
+        return;
+    tcc_state = NULL;
+    POST_SEM(&tcc_compile_sem);
+}
 
 /********************************************************/
 /* copy a string and truncate it. */
@@ -494,52 +510,29 @@ static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *
 }
 
 /********************************************************/
+/* warning / error */
 
-static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
-{
-    int len;
-    len = strlen(buf);
-    vsnprintf(buf + len, buf_size - len, fmt, ap);
-}
+/* warn_... option bits */
+#define WARN_ON  1 /* warning is on (-Woption) */
+#define WARN_ERR 2 /* warning is an error (-Werror=option) */
+#define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */
 
-static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    strcat_vprintf(buf, buf_size, fmt, ap);
-    va_end(ap);
-}
-
-PUB_FUNC void tcc_enter_state(TCCState *s1)
-{
-    WAIT_SEM();
-    tcc_state = s1;
-}
-
-PUB_FUNC void tcc_exit_state(void)
-{
-    tcc_state = NULL;
-    POST_SEM();
-}
-
-#define ERROR_WARN 0
-#define ERROR_NOABORT 1
-#define ERROR_ERROR 2
+/* error1() modes */
+enum { ERROR_WARN, ERROR_NOABORT, ERROR_ERROR };
 
 static void error1(int mode, const char *fmt, va_list ap)
 {
-    char buf[2048];
     BufferedFile **pf, *f;
     TCCState *s1 = tcc_state;
+    CString cs;
+
+    cstr_new(&cs);
 
-    buf[0] = '\0';
     if (s1 == NULL)
         /* can happen only if called from tcc_malloc(): 'out of memory' */
         goto no_file;
 
-    if (!s1->error_set_jmp_enabled)
-        /* tcc_state just was set by tcc_enter_state() */
-        tcc_exit_state();
+    tcc_exit_state(s1);
 
     if (mode == ERROR_WARN) {
         if (s1->warn_error)
@@ -567,33 +560,30 @@ static void error1(int mode, const char *fmt, va_list ap)
     }
     if (f) {
         for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
-            strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
+            cstr_printf(&cs, "In file included from %s:%d:\n",
                 (*pf)->filename, (*pf)->line_num);
-        strcat_printf(buf, sizeof(buf), "%s:%d: ",
+        cstr_printf(&cs, "%s:%d: ",
             f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
     } else if (s1->current_filename) {
-        strcat_printf(buf, sizeof(buf), "%s: ", s1->current_filename);
+        cstr_printf(&cs, "%s: ", s1->current_filename);
     }
 
 no_file:
-    if (0 == buf[0])
-        strcat_printf(buf, sizeof(buf), "tcc: ");
-    if (mode == ERROR_WARN)
-        strcat_printf(buf, sizeof(buf), "warning: ");
-    else
-        strcat_printf(buf, sizeof(buf), "error: ");
-    strcat_vprintf(buf, sizeof(buf), fmt, ap);
+    if (0 == cs.size)
+        cstr_printf(&cs, "tcc: ");
+    cstr_printf(&cs, mode == ERROR_WARN ? "warning: " : "error: ");
+    cstr_vprintf(&cs, fmt, ap);
     if (!s1 || !s1->error_func) {
         /* default case: stderr */
         if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
-            /* print a newline during tcc -E */
-            printf("\n"), fflush(stdout);
+            printf("\n"); /* print a newline during tcc -E */
         fflush(stdout); /* flush -v output */
-        fprintf(stderr, "%s\n", buf);
+        fprintf(stderr, "%s\n", (char*)cs.data);
         fflush(stderr); /* print error/warning now (win32) */
     } else {
-        s1->error_func(s1->error_opaque, buf);
+        s1->error_func(s1->error_opaque, (char*)cs.data);
     }
+    cstr_free(&cs);
     if (s1) {
         if (mode != ERROR_WARN)
             s1->nb_errors++;
@@ -718,9 +708,9 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
        variables, which may or may not have advantages */
 
     tcc_enter_state(s1);
+    s1->error_set_jmp_enabled = 1;
 
     if (setjmp(s1->error_jmp_buf) == 0) {
-        s1->error_set_jmp_enabled = 1;
         s1->nb_errors = 0;
 
         if (fd == -1) {
@@ -738,19 +728,16 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
         if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
             tcc_preprocess(s1);
         } else if (filetype & (AFF_TYPE_ASM | AFF_TYPE_ASMPP)) {
-#ifdef CONFIG_TCC_ASM
             tcc_assemble(s1, !!(filetype & AFF_TYPE_ASMPP));
-#else
-            tcc_error_noabort("asm not supported");
-#endif
         } else {
             tccgen_compile(s1);
         }
     }
-    s1->error_set_jmp_enabled = 0;
     tccgen_finish(s1);
     preprocess_end(s1);
-    tcc_exit_state();
+
+    s1->error_set_jmp_enabled = 0;
+    tcc_exit_state(s1);
 
     tccelf_end_file(s1);
     return s1->nb_errors != 0 ? -1 : 0;
@@ -821,11 +808,7 @@ LIBTCCAPI TCCState *tcc_new(void)
 
     tccelf_new(s);
 
-#ifdef _WIN32
-    tcc_set_lib_path_w32(s);
-#else
     tcc_set_lib_path(s, CONFIG_TCCDIR);
-#endif
     return s;
 }
 
diff --git a/tcc.c b/tcc.c
index 893cdac8..481eb27c 100644
--- a/tcc.c
+++ b/tcc.c
@@ -154,10 +154,8 @@ static const char help2[] =
 
 static const char version[] =
     "tcc version "TCC_VERSION
-#ifdef TCC_GIT_HASH
-        " - " TCC_GIT_HASH
-#else
-        " - unknown hash"
+#ifdef TCC_GITHASH
+    " "TCC_GITHASH
 #endif
     " ("
 #ifdef TCC_TARGET_I386
@@ -276,7 +274,7 @@ int main(int argc0, char **argv0)
 {
     TCCState *s, *s1;
     int ret, opt, n = 0, t = 0, done;
-    unsigned start_time = 0;
+    unsigned start_time = 0, end_time = 0;
     const char *first_file;
     int argc; char **argv;
     FILE *ppfp = stdout;
@@ -372,6 +370,9 @@ redo:
         done = ret || ++n >= s->nb_files;
     } while (!done && (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
 
+    if (s->do_bench)
+        end_time = getclock_ms();
+
     if (s->run_test) {
         t = 0;
     } else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
@@ -391,13 +392,15 @@ redo:
         }
     }
 
-    if (s->do_bench && done && !(t | ret))
-        tcc_print_stats(s, getclock_ms() - start_time);
+    if (done && 0 == t && 0 == ret && s->do_bench)
+        tcc_print_stats(s, end_time - start_time);
+
     tcc_delete(s);
     if (!done)
         goto redo; /* compile more files with -c */
     if (t)
         goto redo; /* run more tests with -dt -run */
+
     if (ppfp && ppfp != stdout)
         fclose(ppfp);
     return ret;
diff --git a/tcc.h b/tcc.h
index 96615696..ef69ef59 100644
--- a/tcc.h
+++ b/tcc.h
@@ -55,6 +55,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
 # include <windows.h>
 # include <io.h> /* open, close etc. */
 # include <direct.h> /* getcwd */
+# include <malloc.h> /* alloca */
 # ifdef __GNUC__
 #  include <stdint.h>
 # endif
@@ -91,6 +92,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
 #   define __x86_64__ 1
 #  endif
 # endif
+# ifndef va_copy
+#  define va_copy(a,b) a = b
+# endif
 # undef CONFIG_TCC_STATIC
 #endif
 
@@ -124,7 +128,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
 # define PRINTF_LIKE(x,y) __attribute__ ((format (printf, (x), (y))))
 #endif
 
-
 #ifdef _WIN32
 # define IS_DIRSEP(c) (c == '/' || c == '\\')
 # define IS_ABSPATH(p) (IS_DIRSEP(p[0]) || (p[0] && p[1] == ':' && IS_DIRSEP(p[2])))
@@ -179,6 +182,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
 # ifdef _WIN32
 #  define TCC_TARGET_PE 1
 # endif
+# ifdef __APPLE__
+#  define TCC_TARGET_MACHO 1
+# endif
 #endif
 
 /* only native compiler supports -run */
@@ -226,7 +232,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
 /* No ten-byte long doubles on window and macos except in
    cross-compilers made by a mingw-GCC */
 #if defined TCC_TARGET_PE \
-    || (defined TCC_TARGET_MACHO && defined TCC_TARGET_X86_64) \
+    || (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64) \
     || (defined _WIN32 && !defined __GNUC__)
 # define TCC_USING_DOUBLE_FOR_LDOUBLE 1
 #endif
@@ -236,7 +242,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
 #ifndef CONFIG_SYSROOT
 # define CONFIG_SYSROOT ""
 #endif
-#ifndef CONFIG_TCCDIR
+#if !defined CONFIG_TCCDIR && !defined _WIN32
 # define CONFIG_TCCDIR "/usr/local/lib/tcc"
 #endif
 #ifndef CONFIG_LDDIR
@@ -751,15 +757,6 @@ struct TCCState {
     unsigned char enable_new_dtags; /* -Wl,--enable-new-dtags */
     unsigned int  cversion; /* supported C ISO version, 199901 (the default), 201112, ... */
 
-    char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
-    char *soname; /* as specified on the command line (-soname) */
-    char *rpath; /* as specified on the command line (-Wl,-rpath=) */
-
-    /* output type, see TCC_OUTPUT_XXX */
-    int output_type;
-    /* output format, see TCC_OUTPUT_FORMAT_xxx */
-    int output_format;
-
     /* C language options */
     unsigned char char_is_unsigned;
     unsigned char leading_underscore;
@@ -776,10 +773,14 @@ struct TCCState {
     unsigned char warn_implicit_function_declaration;
     unsigned char warn_discarded_qualifiers;
     #define WARN_ON  1 /* warning is on (-Woption) */
-    #define WARN_ERR 2 /* warning is an error (-Werror=option) */
-    #define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */
     unsigned char warn_num; /* temp var for tcc_warning_c() */
 
+    unsigned char option_r; /* option -r */
+    unsigned char do_bench; /* option -bench */
+    unsigned char just_deps; /* option -M  */
+    unsigned char gen_deps; /* option -MD  */
+    unsigned char include_sys_deps; /* option -MD  */
+
     /* compile with debug symbol (and use them if error during execution) */
     unsigned char do_debug;
     unsigned char do_backtrace;
@@ -789,30 +790,41 @@ struct TCCState {
 #endif
     unsigned char test_coverage;  /* generate test coverage code */
 
-#ifdef TCC_TARGET_ARM
-    enum float_abi float_abi; /* float ABI of the generated code*/
-#endif
-    int run_test; /* nth test to run with -dt -run */
-
-    addr_t text_addr; /* address of text section */
-    unsigned char has_text_addr;
-
-    unsigned section_align; /* section alignment */
-
     /* use GNU C extensions */
     unsigned char gnu_ext;
     /* use TinyCC extensions */
     unsigned char tcc_ext;
 
-    char *init_symbol; /* symbols to call at load-time (not used currently) */
-    char *fini_symbol; /* symbols to call at unload-time (not used currently) */
+    unsigned char dflag; /* -dX value */
+    unsigned char Pflag; /* -P switch (LINE_MACRO_OUTPUT_FORMAT) */
 
-#ifdef TCC_TARGET_I386
-    int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
-#endif
 #ifdef TCC_TARGET_X86_64
     unsigned char nosse; /* For -mno-sse support. */
 #endif
+#ifdef TCC_TARGET_ARM
+    unsigned char float_abi; /* float ABI of the generated code*/
+#endif
+
+    unsigned char has_text_addr;
+    addr_t text_addr; /* address of text section */
+    unsigned section_align; /* section alignment */
+#ifdef TCC_TARGET_I386
+    int seg_size; /* 32. Can be 16 with i386 assembler (.code16) */
+#endif
+
+    char *tcc_lib_path; /* CONFIG_TCCDIR or -B option */
+    char *soname; /* as specified on the command line (-soname) */
+    char *rpath; /* as specified on the command line (-Wl,-rpath=) */
+
+    char *init_symbol; /* symbols to call at load-time (not used currently) */
+    char *fini_symbol; /* symbols to call at unload-time (not used currently) */
+
+    /* output type, see TCC_OUTPUT_XXX */
+    int output_type;
+    /* output format, see TCC_OUTPUT_FORMAT_xxx */
+    int output_format;
+    /* nth test to run with -dt -run */
+    int run_test;
 
     /* array of all loaded dlls (including those referenced by loaded dlls) */
     DLLReference **loaded_dlls;
@@ -847,13 +859,6 @@ struct TCCState {
 
     /* output file for preprocessing (-E) */
     FILE *ppfp;
-    enum {
-	LINE_MACRO_OUTPUT_FORMAT_GCC,
-	LINE_MACRO_OUTPUT_FORMAT_NONE,
-	LINE_MACRO_OUTPUT_FORMAT_STD,
-    LINE_MACRO_OUTPUT_FORMAT_P10 = 11
-    } Pflag; /* -P switch */
-    char dflag; /* -dX value */
 
     /* for -MD/-MF: collected dependencies for this compilation */
     char **target_deps;
@@ -922,11 +927,11 @@ struct TCCState {
     int nb_sym_attrs;
     /* ptr to next reloc entry reused */
     ElfW_Rel *qrel;
-#   define qrel s1->qrel
+    #define qrel s1->qrel
 
 #ifdef TCC_TARGET_RISCV64
     struct pcrel_hi { addr_t addr, val; } last_hi;
-#   define last_hi s1->last_hi
+    #define last_hi s1->last_hi
 #endif
 
 #ifdef TCC_TARGET_PE
@@ -963,8 +968,6 @@ struct TCCState {
     int rt_num_callers;
 #endif
 
-    int fd, cc; /* used by tcc_load_ldscript */
-
     /* benchmark info */
     int total_idents;
     int total_lines;
@@ -974,7 +977,10 @@ struct TCCState {
     /* option -dnum (for general development purposes) */
     int g_debug;
 
-    /* for warnings/errors for object files*/
+    /* used by tcc_load_ldscript */
+    int fd, cc;
+
+    /* for warnings/errors for object files */
     const char *current_filename;
 
     /* used by main and tcc_parse_args only */
@@ -982,11 +988,6 @@ struct TCCState {
     int nb_files; /* number thereof */
     int nb_libraries; /* number of libs thereof */
     char *outfile; /* output filename */
-    unsigned char option_r; /* option -r */
-    unsigned char do_bench; /* option -bench */
-    int just_deps; /* option -M  */
-    int gen_deps; /* option -MD  */
-    int include_sys_deps; /* option -MD  */
     char *deps_outfile; /* option -MF */
     int argc;
     char **argv;
@@ -1161,91 +1162,6 @@ struct filespec {
 /* all identifiers and strings have token above that */
 #define TOK_IDENT 256
 
-#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
-#define TOK_ASM_int TOK_INT
-#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x)
-#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte
-#define TOK_ASMDIR_LAST TOK_ASMDIR_section
-
-#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
-/* only used for i386 asm opcodes definitions */
-#define DEF_BWL(x) \
- DEF(TOK_ASM_ ## x ## b, #x "b") \
- DEF(TOK_ASM_ ## x ## w, #x "w") \
- DEF(TOK_ASM_ ## x ## l, #x "l") \
- DEF(TOK_ASM_ ## x, #x)
-#define DEF_WL(x) \
- DEF(TOK_ASM_ ## x ## w, #x "w") \
- DEF(TOK_ASM_ ## x ## l, #x "l") \
- DEF(TOK_ASM_ ## x, #x)
-#ifdef TCC_TARGET_X86_64
-# define DEF_BWLQ(x) \
- DEF(TOK_ASM_ ## x ## b, #x "b") \
- DEF(TOK_ASM_ ## x ## w, #x "w") \
- DEF(TOK_ASM_ ## x ## l, #x "l") \
- DEF(TOK_ASM_ ## x ## q, #x "q") \
- DEF(TOK_ASM_ ## x, #x)
-# define DEF_WLQ(x) \
- DEF(TOK_ASM_ ## x ## w, #x "w") \
- DEF(TOK_ASM_ ## x ## l, #x "l") \
- DEF(TOK_ASM_ ## x ## q, #x "q") \
- DEF(TOK_ASM_ ## x, #x)
-# define DEF_BWLX DEF_BWLQ
-# define DEF_WLX DEF_WLQ
-/* number of sizes + 1 */
-# define NBWLX 5
-#else
-# define DEF_BWLX DEF_BWL
-# define DEF_WLX DEF_WL
-/* number of sizes + 1 */
-# define NBWLX 4
-#endif
-
-#define DEF_FP1(x) \
- DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \
- DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \
- DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \
- DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s")
-
-#define DEF_FP(x) \
- DEF(TOK_ASM_ ## f ## x, "f" #x ) \
- DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \
- DEF_FP1(x)
-
-#define DEF_ASMTEST(x,suffix) \
- DEF_ASM(x ## o ## suffix) \
- DEF_ASM(x ## no ## suffix) \
- DEF_ASM(x ## b ## suffix) \
- DEF_ASM(x ## c ## suffix) \
- DEF_ASM(x ## nae ## suffix) \
- DEF_ASM(x ## nb ## suffix) \
- DEF_ASM(x ## nc ## suffix) \
- DEF_ASM(x ## ae ## suffix) \
- DEF_ASM(x ## e ## suffix) \
- DEF_ASM(x ## z ## suffix) \
- DEF_ASM(x ## ne ## suffix) \
- DEF_ASM(x ## nz ## suffix) \
- DEF_ASM(x ## be ## suffix) \
- DEF_ASM(x ## na ## suffix) \
- DEF_ASM(x ## nbe ## suffix) \
- DEF_ASM(x ## a ## suffix) \
- DEF_ASM(x ## s ## suffix) \
- DEF_ASM(x ## ns ## suffix) \
- DEF_ASM(x ## p ## suffix) \
- DEF_ASM(x ## pe ## suffix) \
- DEF_ASM(x ## np ## suffix) \
- DEF_ASM(x ## po ## suffix) \
- DEF_ASM(x ## l ## suffix) \
- DEF_ASM(x ## nge ## suffix) \
- DEF_ASM(x ## nl ## suffix) \
- DEF_ASM(x ## ge ## suffix) \
- DEF_ASM(x ## le ## suffix) \
- DEF_ASM(x ## ng ## suffix) \
- DEF_ASM(x ## nle ## suffix) \
- DEF_ASM(x ## g ## suffix)
-
-#endif /* defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 */
-
 enum tcc_token {
     TOK_LAST = TOK_IDENT - 1
 #define DEF(id, str) ,id
@@ -1306,6 +1222,7 @@ ST_FUNC void cstr_wccat(CString *cstr, int ch);
 ST_FUNC void cstr_new(CString *cstr);
 ST_FUNC void cstr_free(CString *cstr);
 ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...) PRINTF_LIKE(2,3);
+ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap);
 ST_FUNC void cstr_reset(CString *cstr);
 
 ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen);
@@ -1397,6 +1314,13 @@ ST_DATA TokenSym **table_ident;
 #define IS_ID  2
 #define IS_NUM 4
 
+enum line_macro_output_format {
+    LINE_MACRO_OUTPUT_FORMAT_GCC,
+    LINE_MACRO_OUTPUT_FORMAT_NONE,
+    LINE_MACRO_OUTPUT_FORMAT_STD,
+    LINE_MACRO_OUTPUT_FORMAT_P10 = 11
+};
+
 ST_FUNC TokenSym *tok_alloc(const char *str, int len);
 ST_FUNC int tok_alloc_const(const char *str);
 ST_FUNC const char *get_tok_str(int v, CValue *cv);
@@ -1770,12 +1694,12 @@ ST_FUNC int tcc_load_coff(TCCState * s1, int fd);
 /* ------------ tccasm.c ------------ */
 ST_FUNC void asm_instr(void);
 ST_FUNC void asm_global_instr(void);
+ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess);
 #ifdef CONFIG_TCC_ASM
 ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp);
 ST_FUNC Sym* get_asm_sym(int name, Sym *csym);
 ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
 ST_FUNC int asm_int_expr(TCCState *s1);
-ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess);
 /* ------------ i386-asm.c ------------ */
 ST_FUNC void gen_expr32(ExprValue *pe);
 #ifdef TCC_TARGET_X86_64
@@ -1844,6 +1768,28 @@ 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
 
+/********************************************************/
+#if CONFIG_TCC_SEMLOCK
+#if defined _WIN32
+typedef struct { int init; CRITICAL_SECTION cr; } TCCSem;
+#elif defined __APPLE__
+#include <dispatch/dispatch.h>
+typedef struct { int init; dispatch_semaphore_t sem; } TCCSem;
+#else
+#include <semaphore.h>
+typedef struct { int init; sem_t sem; } TCCSem;
+#endif
+ST_FUNC void wait_sem(TCCSem *p);
+ST_FUNC void post_sem(TCCSem *p);
+#define TCC_SEM(s) TCCSem s
+#define WAIT_SEM wait_sem
+#define POST_SEM post_sem
+#else
+#define TCC_SEM(s)
+#define WAIT_SEM(p)
+#define POST_SEM(p)
+#endif
+
 /********************************************************/
 #undef ST_DATA
 #if ONE_SOURCE
@@ -1875,7 +1821,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
 #define total_bytes         TCC_STATE_VAR(total_bytes)
 
 PUB_FUNC void tcc_enter_state(TCCState *s1);
-PUB_FUNC void tcc_exit_state(void);
+PUB_FUNC void tcc_exit_state(TCCState *s1);
 
 /* conditional warning depending on switch */
 #define tcc_warning_c(sw) TCC_SET_STATE((\
diff --git a/tccasm.c b/tccasm.c
index aabb66fe..2dd8921b 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -1298,4 +1298,21 @@ ST_FUNC void asm_global_instr(void)
     cstr_free(&astr);
     nocode_wanted = saved_nocode_wanted;
 }
+
+/********************************************************/
+#else
+ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
+{
+    tcc_error("asm not supported");
+}
+
+ST_FUNC void asm_instr(void)
+{
+    tcc_error("inline asm() not supported");
+}
+
+ST_FUNC void asm_global_instr(void)
+{
+    tcc_error("inline asm() not supported");
+}
 #endif /* CONFIG_TCC_ASM */
diff --git a/tccgen.c b/tccgen.c
index a2efee6a..e0b5fd6f 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -97,7 +97,7 @@ static CString initstr;
 #define VT_PTRDIFF_T (VT_LONG | VT_LLONG)
 #endif
 
-ST_DATA struct switch_t {
+static struct switch_t {
     struct case_t {
         int64_t v1, v2;
 	int sym;
@@ -111,12 +111,12 @@ ST_DATA struct switch_t {
 
 #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
 /*list of temporary local variables on the stack in current function. */
-ST_DATA struct temp_local_variable {
+static struct temp_local_variable {
 	int location; //offset on stack. Svalue.c.i
 	short size;
 	short align;
 } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
-short nb_temp_local_vars;
+static int nb_temp_local_vars;
 
 static struct scope {
     struct scope *prev;
@@ -132,6 +132,11 @@ typedef struct {
     Sym *flex_array_ref;
 } init_params;
 
+#if 1
+#define precedence_parser
+static void init_prec(void);
+#endif
+
 /********************************************************/
 /* stab debug support */
 
@@ -215,23 +220,6 @@ static struct {
 } tcov_data;
 
 /********************************************************/
-#if 1
-#define precedence_parser
-static void init_prec(void);
-#endif
-/********************************************************/
-#ifndef CONFIG_TCC_ASM
-ST_FUNC void asm_instr(void)
-{
-    tcc_error("inline asm() not supported");
-}
-ST_FUNC void asm_global_instr(void)
-{
-    tcc_error("inline asm() not supported");
-}
-#endif
-
-/* ------------------------------------------------------------------------- */
 static void gen_cast(CType *type);
 static void gen_cast_s(int t);
 static inline CType *pointed_type(CType *type);
@@ -7247,7 +7235,7 @@ static void vla_leave(struct scope *o)
 /* ------------------------------------------------------------------------- */
 /* local scopes */
 
-void new_scope(struct scope *o)
+static void new_scope(struct scope *o)
 {
     /* copy and link previous scope */
     *o = *cur_scope;
@@ -7264,7 +7252,7 @@ void new_scope(struct scope *o)
         tcc_debug_stabn(tcc_state, N_LBRAC, ind - func_ind);
 }
 
-void prev_scope(struct scope *o, int is_expr)
+static void prev_scope(struct scope *o, int is_expr)
 {
     vla_leave(o->prev);
 
@@ -7292,7 +7280,7 @@ void prev_scope(struct scope *o, int is_expr)
 }
 
 /* leave a scope via break/continue(/goto) */
-void leave_scope(struct scope *o)
+static void leave_scope(struct scope *o)
 {
     if (!o)
         return;
diff --git a/tccmacho.c b/tccmacho.c
index 083fb1a3..57c62c32 100644
--- a/tccmacho.c
+++ b/tccmacho.c
@@ -517,7 +517,7 @@ static void create_symtab(TCCState *s1, struct macho *mo)
     }
     tcc_enter_state(s1);  /* qsort needs global state */
     qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp);
-    tcc_exit_state();
+    tcc_exit_state(s1);
     mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
     mo->e2msym[0] = -1;
     for (sym_index = 1; sym_index < sym_end; ++sym_index) {
diff --git a/tccpe.c b/tccpe.c
index df57f71c..07501a96 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1543,8 +1543,6 @@ static int pe_add_dllref(TCCState *s1, const char *dllname)
     return s1->nb_loaded_dlls;
 }
 
-/* ------------------------------------------------------------- */
-
 static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
 {
     lseek(fd, offset, SEEK_SET);
@@ -1553,11 +1551,10 @@ static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
 
 /* ------------------------------------------------------------- */
 
-PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
+static int get_dllexports(int fd, char **pp)
 {
     int l, i, n, n0, ret;
     char *p;
-    int fd;
 
     IMAGE_SECTION_HEADER ish;
     IMAGE_EXPORT_DIRECTORY ied;
@@ -1569,11 +1566,6 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
 
     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;
@@ -1640,8 +1632,6 @@ found:
 the_end_0:
     ret = 0;
 the_end:
-    close(fd);
-the_end_1:
     *pp = p;
     return ret;
 }
@@ -1694,47 +1684,53 @@ quit:
 
 static char *trimfront(char *p)
 {
-    while (*p && (unsigned char)*p <= ' ')
+    while ((unsigned char)*p <= ' ' && *p && *p != '\n')
 	++p;
     return p;
 }
 
+/*
 static char *trimback(char *a, char *e)
 {
     while (e > a && (unsigned char)e[-1] <= ' ')
 	--e;
     *e = 0;;
     return a;
+}*/
+
+static char *get_token(char **s, char *f)
+{
+    char *p = *s, *e;
+    p = e = trimfront(p);
+    while ((unsigned char)*e > ' ')
+        ++e;
+    *s = trimfront(e);
+    *f = **s; *e = 0;
+    return p;
 }
 
-/* ------------------------------------------------------------- */
 static int pe_load_def(TCCState *s1, int fd)
 {
     int state = 0, ret = -1, dllindex = 0, ord;
-    char line[400], dllname[80], *p, *x;
-    FILE *fp;
-
-    fp = fdopen(dup(fd), "rb");
-    while (fgets(line, sizeof line, fp))
-    {
-        p = trimfront(trimback(line, strchr(line, 0)));
-        if (0 == *p || ';' == *p)
-            continue;
+    char dllname[80], *buf, *line, *p, *x, next;
 
+    buf = tcc_load_text(fd);
+    for (line = buf;; ++line)  {
+        p = get_token(&line, &next);
+        if (!(*p && *p != ';'))
+            goto skip;
         switch (state) {
         case 0:
-            if (0 != strnicmp(p, "LIBRARY", 7))
+            if (0 != stricmp(p, "LIBRARY") || next == '\n')
                 goto quit;
-            pstrcpy(dllname, sizeof dllname, trimfront(p+7));
+            pstrcpy(dllname, sizeof dllname, get_token(&line, &next));
             ++state;
-            continue;
-
+            break;
         case 1:
             if (0 != stricmp(p, "EXPORTS"))
                 goto quit;
             ++state;
-            continue;
-
+            break;
         case 2:
             dllindex = pe_add_dllref(s1, dllname);
             ++state;
@@ -1742,33 +1738,34 @@ static int pe_load_def(TCCState *s1, int fd)
         default:
             /* get ordinal and will store in sym->st_value */
             ord = 0;
-            x = strchr(p, ' ');
-            if (x) {
-                *x = 0, x = strrchr(x + 1, '@');
-                if (x) {
-                    char *d;
-                    ord = (int)strtol(x + 1, &d, 10);
-                    if (*d)
-                        ord = 0;
-                }
+            if (next == '@') {
+                x = get_token(&line, &next);
+                ord = (int)strtol(x + 1, &x, 10);
             }
+            //printf("token %s ; %s : %d\n", dllname, p, ord);
             pe_putimport(s1, dllindex, p, ord);
-            continue;
+            break;
         }
+skip:
+        while ((unsigned char)next > ' ')
+            get_token(&line, &next);
+        if (next != '\n')
+            break;
     }
     ret = 0;
 quit:
-    fclose(fp);
+    tcc_free(buf);
     return ret;
 }
 
 /* ------------------------------------------------------------- */
-static int pe_load_dll(TCCState *s1, const char *filename)
+
+static int pe_load_dll(TCCState *s1, int fd, const char *filename)
 {
     char *p, *q;
     int index, ret;
 
-    ret = tcc_get_dllexports(filename, &p);
+    ret = get_dllexports(fd, &p);
     if (ret) {
         return -1;
     } else if (p) {
@@ -1780,7 +1777,6 @@ static int pe_load_dll(TCCState *s1, const char *filename)
     return 0;
 }
 
-/* ------------------------------------------------------------- */
 ST_FUNC int pe_load_file(struct TCCState *s1, int fd, const char *filename)
 {
     int ret = -1;
@@ -1790,7 +1786,17 @@ ST_FUNC int pe_load_file(struct TCCState *s1, int fd, const char *filename)
     else if (pe_load_res(s1, fd) == 0)
         ret = 0;
     else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2))
-        ret = pe_load_dll(s1, filename);
+        ret = pe_load_dll(s1, fd, filename);
+    return ret;
+}
+
+PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
+{
+    int ret, fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    ret = get_dllexports(fd, pp);
+    close(fd);
     return ret;
 }
 
diff --git a/tccpp.c b/tccpp.c
index 4a423879..897ef151 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -404,7 +404,7 @@ ST_FUNC void cstr_reset(CString *cstr)
     cstr->size = 0;
 }
 
-ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
+ST_FUNC int cstr_vprintf(CString *cstr, const char *fmt, va_list ap)
 {
     va_list v;
     int len, size = 80;
@@ -413,7 +413,7 @@ ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
         if (size > cstr->size_allocated)
             cstr_realloc(cstr, size);
         size = cstr->size_allocated - cstr->size;
-        va_start(v, fmt);
+        va_copy(v, ap);
         len = vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
         va_end(v);
         if (len > 0 && len < size)
@@ -424,6 +424,15 @@ ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
     return len;
 }
 
+ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
+{
+    va_list ap; int len;
+    va_start(ap, fmt);
+    len = cstr_vprintf(cstr, fmt, ap);
+    va_end(ap);
+    return len;
+}
+
 /* XXX: unicode ? */
 static void add_char(CString *cstr, int c)
 {
diff --git a/tcctok.h b/tcctok.h
index e5bc5fbe..d4c1ef5c 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -1,3 +1,4 @@
+/*********************************************************************/
 /* keywords */
      DEF(TOK_INT, "int")
      DEF(TOK_VOID, "void")
@@ -343,8 +344,17 @@
      DEF(TOK_longjmp, "longjmp")
 #endif
 
+
+/*********************************************************************/
 /* Tiny Assembler */
- DEF_ASMDIR(byte)              /* must be first directive */
+#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
+#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x)
+#define TOK_ASM_int TOK_INT
+
+#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte
+#define TOK_ASMDIR_LAST TOK_ASMDIR_section
+
+ DEF_ASMDIR(byte)       /* must be first directive */
  DEF_ASMDIR(word)
  DEF_ASMDIR(align)
  DEF_ASMDIR(balign)
@@ -383,14 +393,16 @@
  DEF_ASMDIR(short)
  DEF_ASMDIR(long)
  DEF_ASMDIR(int)
- DEF_ASMDIR(section)            /* must be last directive */
+ DEF_ASMDIR(section)    /* must be last directive */
 
 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
 #include "i386-tok.h"
 #endif
+
 #if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
 #include "arm-tok.h"
 #endif
+
 #if defined TCC_TARGET_RISCV64
 #include "riscv64-tok.h"
 #endif
diff --git a/tcctools.c b/tcctools.c
index 7d074c7b..cf174965 100644
--- a/tcctools.c
+++ b/tcctools.c
@@ -385,10 +385,8 @@ usage:
     ret = 0;
 
 the_end:
-    /* cannot free memory received from tcc_get_dllexports
-       if it came from a dll */
-    /* if (p)
-        tcc_free(p); */
+    if (p)
+        tcc_free(p);
     if (fp)
         fclose(fp);
     if (op)
diff --git a/tests/libtcc_test_mt.c b/tests/libtcc_test_mt.c
index 47d493d8..6892bfef 100644
--- a/tests/libtcc_test_mt.c
+++ b/tests/libtcc_test_mt.c
@@ -220,9 +220,10 @@ TF_TYPE(thread_test_complex, vn)
 void time_tcc(int n, const char *src)
 {
     TCCState *s;
-    int ret;
-    while (--n >= 0) {
+    int ret, i = 0;
+    while (i++ < n) {
         s = new_state(1);
+        printf(" %d", i), fflush(stdout);
         ret = tcc_add_file(s, src);
         tcc_delete(s);
         if (ret < 0)
@@ -277,10 +278,10 @@ int main(int argc, char **argv)
     printf("\n (%u ms)\n", getclock_ms() - t);
 #endif
 #if 1
-    printf("compiling tcc.c 10 times\n"), fflush(stdout);
+    printf("compiling tcc.c 10 times\n "), fflush(stdout);
     t = getclock_ms();
     time_tcc(10, argv[1]);
-    printf(" (%u ms)\n", getclock_ms() - t), fflush(stdout);
+    printf("\n (%u ms)\n", getclock_ms() - t), fflush(stdout);
 #endif
     return 0;
 }