summary refs log tree commit diff stats
path: root/tinyc/libtcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyc/libtcc.c')
-rw-r--r--tinyc/libtcc.c3215
1 files changed, 1469 insertions, 1746 deletions
diff --git a/tinyc/libtcc.c b/tinyc/libtcc.c
index 0d8702b5f..092c0ba32 100644
--- a/tinyc/libtcc.c
+++ b/tinyc/libtcc.c
@@ -1,6 +1,6 @@
 /*
  *  TCC - Tiny C Compiler
- * 
+ *
  *  Copyright (c) 2001-2004 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -23,310 +23,115 @@
 /********************************************************/
 /* global variables */
 
-/* display benchmark infos */
-int total_lines;
-int total_bytes;
-
-/* parser */
-static struct BufferedFile *file;
-static int ch, tok;
-static CValue tokc;
-static CString tokcstr; /* current parsed string, if any */
-/* additional informations about token */
-static int tok_flags;
-#define TOK_FLAG_BOL   0x0001 /* beginning of line before */
-#define TOK_FLAG_BOF   0x0002 /* beginning of file before */
-#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */
-#define TOK_FLAG_EOF   0x0008 /* end of file */
-
-static int *macro_ptr, *macro_ptr_allocated;
-static int *unget_saved_macro_ptr;
-static int unget_saved_buffer[TOK_MAX_SIZE + 1];
-static int unget_buffer_enabled;
-static int parse_flags;
-#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */
-#define PARSE_FLAG_TOK_NUM    0x0002 /* return numbers instead of TOK_PPNUM */
-#define PARSE_FLAG_LINEFEED   0x0004 /* line feed is returned as a
-                                        token. line feed is also
-                                        returned at eof */
-#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */
-#define PARSE_FLAG_SPACES     0x0010 /* next() returns space tokens (for -E) */
- 
-static Section *text_section, *data_section, *bss_section; /* predefined sections */
-static Section *cur_text_section; /* current section where function code is
-                              generated */
-#ifdef CONFIG_TCC_ASM
-static Section *last_text_section; /* to handle .previous asm directive */
-#endif
-/* bound check related sections */
-static Section *bounds_section; /* contains global data bound description */
-static Section *lbounds_section; /* contains local data bound description */
-/* symbol sections */
-static Section *symtab_section, *strtab_section;
-
-/* debug sections */
-static Section *stab_section, *stabstr_section;
-
-/* loc : local variable index
-   ind : output code index
-   rsym: return symbol
-   anon_sym: anonymous symbol index
-*/
-static int rsym, anon_sym, ind, loc;
-/* expression generation modifiers */
-static int const_wanted; /* true if constant wanted */
-static int nocode_wanted; /* true if no code generation wanted for an expression */
-static int global_expr;  /* true if compound literals must be allocated
-                            globally (used during initializers parsing */
-static CType func_vt; /* current function return type (used by return
-                         instruction) */
-static int func_vc;
-static int last_line_num, last_ind, func_ind; /* debug last line number and pc */
-static int tok_ident;
-static TokenSym **table_ident;
-static TokenSym *hash_ident[TOK_HASH_SIZE];
-static char token_buf[STRING_MAX_SIZE + 1];
-static char *funcname;
-static Sym *global_stack, *local_stack;
-static Sym *define_stack;
-static Sym *global_label_stack, *local_label_stack;
-/* symbol allocator */
-#define SYM_POOL_NB (8192 / sizeof(Sym))
-static Sym *sym_free_first;
-static void **sym_pools;
-static int nb_sym_pools;
-
-static SValue vstack[VSTACK_SIZE], *vtop;
-/* some predefined types */
-static CType char_pointer_type, func_old_type, int_type;
-
 /* use GNU C extensions */
-static int gnu_ext = 1;
+ST_DATA int gnu_ext = 1;
 
-/* use Tiny C extensions */
-static int tcc_ext = 1;
-
-/* max number of callers shown if error */
-#ifdef CONFIG_TCC_BACKTRACE
-int num_callers = 6;
-const char **rt_bound_error_msg;
-#endif
+/* use TinyCC extensions */
+ST_DATA int tcc_ext = 1;
 
 /* XXX: get rid of this ASAP */
-static struct TCCState *tcc_state;
+ST_DATA struct TCCState *tcc_state;
 
-/********************************************************/
-/* function prototypes */
-
-/* tccpp.c */
-static void next(void);
-char *get_tok_str(int v, CValue *cv);
-
-/* tccgen.c */
-static void parse_expr_type(CType *type);
-static void expr_type(CType *type);
-static void unary_type(CType *type);
-static void block(int *bsym, int *csym, int *case_sym, int *def_sym, 
-                  int case_reg, int is_expr);
-static int expr_const(void);
-static void expr_eq(void);
-static void gexpr(void);
-static void gen_inline_functions(void);
-static void decl(int l);
-static void decl_initializer(CType *type, Section *sec, unsigned long c, 
-                             int first, int size_only);
-static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, 
-                                   int has_init, int v, int scope);
-int gv(int rc);
-void gv2(int rc1, int rc2);
-void move_reg(int r, int s);
-void save_regs(int n);
-void save_reg(int r);
-void vpop(void);
-void vswap(void);
-void vdup(void);
-int get_reg(int rc);
-int get_reg_ex(int rc,int rc2);
-
-void gen_op(int op);
-void force_charshort_cast(int t);
-static void gen_cast(CType *type);
-void vstore(void);
-static Sym *sym_find(int v);
-static Sym *sym_push(int v, CType *type, int r, int c);
-
-/* type handling */
-static int type_size(CType *type, int *a);
-static inline CType *pointed_type(CType *type);
-static int pointed_size(CType *type);
-static int lvalue_type(int t);
-static int parse_btype(CType *type, AttributeDef *ad);
-static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
-static int compare_types(CType *type1, CType *type2, int unqualified);
-static int is_compatible_types(CType *type1, CType *type2);
-static int is_compatible_parameter_types(CType *type1, CType *type2);
-
-int ieee_finite(double d);
-void vpushi(int v);
-void vpushll(long long v);
-void vrott(int n);
-void vnrott(int n);
-void lexpand_nr(void);
-static void vpush_global_sym(CType *type, int v);
-void vset(CType *type, int r, int v);
-void type_to_str(char *buf, int buf_size, 
-                 CType *type, const char *varstr);
-static Sym *get_sym_ref(CType *type, Section *sec,
-                        unsigned long offset, unsigned long size);
-static Sym *external_global_sym(int v, CType *type, int r);
-
-/* section generation */
-static void section_realloc(Section *sec, unsigned long new_size);
-static void *section_ptr_add(Section *sec, unsigned long size);
-static void put_extern_sym(Sym *sym, Section *section, 
-                           unsigned long value, unsigned long size);
-static void greloc(Section *s, Sym *sym, unsigned long addr, int type);
-static int put_elf_str(Section *s, const char *sym);
-static int put_elf_sym(Section *s, 
-                       unsigned long value, unsigned long size,
-                       int info, int other, int shndx, const char *name);
-static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
-                       int info, int other, int sh_num, const char *name);
-static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
-                          int type, int symbol);
-static void put_stabs(const char *str, int type, int other, int desc, 
-                      unsigned long value);
-static void put_stabs_r(const char *str, int type, int other, int desc, 
-                        unsigned long value, Section *sec, int sym_index);
-static void put_stabn(int type, int other, int desc, int value);
-static void put_stabd(int type, int other, int desc);
-static int tcc_add_dll(TCCState *s, const char *filename, int flags);
-
-#define AFF_PRINT_ERROR     0x0001 /* print error if file not found */
-#define AFF_REFERENCED_DLL  0x0002 /* load a referenced dll from another dll */
-#define AFF_PREPROCESS      0x0004 /* preprocess file */
-static int tcc_add_file_internal(TCCState *s, const char *filename, int flags);
-
-/* tcccoff.c */
-int tcc_output_coff(TCCState *s1, FILE *f);
-
-/* tccpe.c */
-void *resolve_sym(TCCState *s1, const char *sym, int type);
-int pe_load_def_file(struct TCCState *s1, int fd);
-int pe_test_res_file(void *v, int size);
-int pe_load_res_file(struct TCCState *s1, int fd);
-void pe_add_runtime(struct TCCState *s1);
-void pe_guess_outfile(char *objfilename, int output_type);
-int pe_output_file(struct TCCState *s1, const char *filename);
-
-/* tccasm.c */
-#ifdef CONFIG_TCC_ASM
-static void asm_expr(TCCState *s1, ExprValue *pe);
-static int asm_int_expr(TCCState *s1);
-static int find_constraint(ASMOperand *operands, int nb_operands, 
-                           const char *name, const char **pp);
-
-static int tcc_assemble(TCCState *s1, int do_preprocess);
-#endif
-
-static void asm_instr(void);
-static void asm_global_instr(void);
+static int nb_states;
 
 /********************************************************/
-/* global variables */
 
+#if ONE_SOURCE
+#include "tccpp.c"
+#include "tccgen.c"
+#include "tccelf.c"
+#include "tccrun.c"
 #ifdef TCC_TARGET_I386
 #include "i386-gen.c"
+#include "i386-link.c"
+#include "i386-asm.c"
 #endif
-
 #ifdef TCC_TARGET_ARM
 #include "arm-gen.c"
+#include "arm-link.c"
+#include "arm-asm.c"
+#endif
+#ifdef TCC_TARGET_ARM64
+#include "arm64-gen.c"
+#include "arm64-link.c"
 #endif
-
 #ifdef TCC_TARGET_C67
 #include "c67-gen.c"
+#include "c67-link.c"
+#include "tcccoff.c"
 #endif
-
 #ifdef TCC_TARGET_X86_64
 #include "x86_64-gen.c"
+#include "x86_64-link.c"
+#include "i386-asm.c"
 #endif
+#ifdef CONFIG_TCC_ASM
+#include "tccasm.c"
+#endif
+#ifdef TCC_TARGET_PE
+#include "tccpe.c"
+#endif
+#endif /* ONE_SOURCE */
 
-#ifdef CONFIG_TCC_STATIC
-
-#define RTLD_LAZY       0x001
-#define RTLD_NOW        0x002
-#define RTLD_GLOBAL     0x100
-#define RTLD_DEFAULT    NULL
-
-/* dummy function for profiling */
-void *dlopen(const char *filename, int flag)
+/********************************************************/
+#ifndef CONFIG_TCC_ASM
+ST_FUNC void asm_instr(void)
 {
-    return NULL;
+    tcc_error("inline asm() not supported");
 }
-
-void dlclose(void *p)
+ST_FUNC void asm_global_instr(void)
 {
+    tcc_error("inline asm() not supported");
 }
+#endif
 
-const char *dlerror(void)
+/********************************************************/
+#ifdef _WIN32
+ST_FUNC char *normalize_slashes(char *path)
 {
-    return "error";
+    char *p;
+    for (p = path; *p; ++p)
+        if (*p == '\\')
+            *p = '/';
+    return path;
 }
 
-typedef struct TCCSyms {
-    char *str;
-    void *ptr;
-} TCCSyms;
-
-#define TCCSYM(a) { #a, &a, },
+static HMODULE tcc_module;
 
-/* add the symbol you want here if no dynamic linking is done */
-static TCCSyms tcc_syms[] = {
-#if !defined(CONFIG_TCCBOOT)
-    TCCSYM(printf)
-    TCCSYM(fprintf)
-    TCCSYM(fopen)
-    TCCSYM(fclose)
-#endif
-    { NULL, NULL },
-};
-
-void *resolve_sym(TCCState *s1, const char *symbol, int type)
+/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */
+static void tcc_set_lib_path_w32(TCCState *s)
 {
-    TCCSyms *p;
-    p = tcc_syms;
-    while (p->str != NULL) {
-        if (!strcmp(p->str, symbol))
-            return p->ptr;
-        p++;
-    }
-    return NULL;
+    char path[1024], *p;
+    GetModuleFileNameA(tcc_module, path, sizeof path);
+    p = tcc_basename(normalize_slashes(strlwr(path)));
+    if (p > path)
+        --p;
+    *p = 0;
+    tcc_set_lib_path(s, path);
 }
 
-#elif !defined(_WIN32)
-
-#include <dlfcn.h>
-
-void *resolve_sym(TCCState *s1, const char *sym, int type)
+#ifdef TCC_TARGET_PE
+static void tcc_add_systemdir(TCCState *s)
 {
-    return dlsym(RTLD_DEFAULT, sym);
+    char buf[1000];
+    GetSystemDirectory(buf, sizeof buf);
+    tcc_add_library_path(s, normalize_slashes(buf));
 }
-
 #endif
 
-/********************************************************/
-
-/* we use our own 'finite' function to avoid potential problems with
-   non standard math libs */
-/* XXX: endianness dependent */
-int ieee_finite(double d)
+#ifdef LIBTCC_AS_DLL
+BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
 {
-    int *p = (int *)&d;
-    return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
+    if (DLL_PROCESS_ATTACH == dwReason)
+        tcc_module = hDll;
+    return TRUE;
 }
+#endif
+#endif
 
+/********************************************************/
 /* copy a string and truncate it. */
-char *pstrcpy(char *buf, int buf_size, const char *s)
+ST_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
 {
     char *q, *q_end;
     int c;
@@ -346,101 +151,66 @@ char *pstrcpy(char *buf, int buf_size, const char *s)
 }
 
 /* strcat and truncate. */
-char *pstrcat(char *buf, int buf_size, const char *s)
+ST_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
 {
     int len;
     len = strlen(buf);
-    if (len < buf_size) 
+    if (len < buf_size)
         pstrcpy(buf + len, buf_size - len, s);
     return buf;
 }
 
+ST_FUNC char *pstrncpy(char *out, const char *in, size_t num)
+{
+    memcpy(out, in, num);
+    out[num] = '\0';
+    return out;
+}
+
 /* extract the basename of a file */
-char *tcc_basename(const char *name)
+PUB_FUNC char *tcc_basename(const char *name)
 {
     char *p = strchr(name, 0);
-    while (p > name && !IS_PATHSEP(p[-1]))
+    while (p > name && !IS_DIRSEP(p[-1]))
         --p;
     return p;
 }
 
-char *tcc_fileextension (const char *name)
+/* extract extension part of a file
+ *
+ * (if no extension, return pointer to end-of-string)
+ */
+PUB_FUNC char *tcc_fileextension (const char *name)
 {
     char *b = tcc_basename(name);
     char *e = strrchr(b, '.');
     return e ? e : strchr(b, 0);
 }
 
-#ifdef _WIN32
-char *normalize_slashes(char *path)
-{
-    char *p;
-    for (p = path; *p; ++p)
-        if (*p == '\\')
-            *p = '/';
-    return path;
-}
-
-void tcc_set_lib_path_w32(TCCState *s)
-{
-    /* on win32, we suppose the lib and includes are at the location
-       of 'tcc.exe' */
-    char path[1024], *p;
-    GetModuleFileNameA(NULL, path, sizeof path);
-    p = tcc_basename(normalize_slashes(strlwr(path)));
-    if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
-        p -= 5;
-    else if (p > path)
-        p--;
-    *p = 0;
-    tcc_set_lib_path(s, path);
-}
-#endif
+/********************************************************/
+/* memory management */
 
-void set_pages_executable(void *ptr, unsigned long length)
-{
-#ifdef _WIN32
-    unsigned long old_protect;
-    VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
-#else
-    unsigned long start, end;
-    start = (unsigned long)ptr & ~(PAGESIZE - 1);
-    end = (unsigned long)ptr + length;
-    end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
-    mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
-#endif            
-}
+#undef free
+#undef malloc
+#undef realloc
 
-/* memory management */
-#ifdef MEM_DEBUG
-int mem_cur_size;
-int mem_max_size;
-unsigned malloc_usable_size(void*);
-#endif
+#ifndef MEM_DEBUG
 
-void tcc_free(void *ptr)
+PUB_FUNC void tcc_free(void *ptr)
 {
-#ifdef MEM_DEBUG
-    mem_cur_size -= malloc_usable_size(ptr);
-#endif
     free(ptr);
 }
 
-void *tcc_malloc(unsigned long size)
+PUB_FUNC void *tcc_malloc(unsigned long size)
 {
     void *ptr;
     ptr = malloc(size);
     if (!ptr && size)
-        error("memory full");
-#ifdef MEM_DEBUG
-    mem_cur_size += malloc_usable_size(ptr);
-    if (mem_cur_size > mem_max_size)
-        mem_max_size = mem_cur_size;
-#endif
+        tcc_error("memory full (malloc)");
     return ptr;
 }
 
-void *tcc_mallocz(unsigned long size)
+PUB_FUNC void *tcc_mallocz(unsigned long size)
 {
     void *ptr;
     ptr = tcc_malloc(size);
@@ -448,23 +218,16 @@ void *tcc_mallocz(unsigned long size)
     return ptr;
 }
 
-void *tcc_realloc(void *ptr, unsigned long size)
+PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size)
 {
     void *ptr1;
-#ifdef MEM_DEBUG
-    mem_cur_size -= malloc_usable_size(ptr);
-#endif
     ptr1 = realloc(ptr, size);
-#ifdef MEM_DEBUG
-    /* NOTE: count not correct if alloc error, but not critical */
-    mem_cur_size += malloc_usable_size(ptr1);
-    if (mem_cur_size > mem_max_size)
-        mem_max_size = mem_cur_size;
-#endif
+    if (!ptr1 && size)
+        tcc_error("memory full (realloc)");
     return ptr1;
 }
 
-char *tcc_strdup(const char *str)
+PUB_FUNC char *tcc_strdup(const char *str)
 {
     char *ptr;
     ptr = tcc_malloc(strlen(str) + 1);
@@ -472,299 +235,229 @@ char *tcc_strdup(const char *str)
     return ptr;
 }
 
-#define free(p) use_tcc_free(p)
-#define malloc(s) use_tcc_malloc(s)
-#define realloc(p, s) use_tcc_realloc(p, s)
-
-void dynarray_add(void ***ptab, int *nb_ptr, void *data)
+PUB_FUNC void tcc_memcheck(void)
 {
-    int nb, nb_alloc;
-    void **pp;
-    
-    nb = *nb_ptr;
-    pp = *ptab;
-    /* every power of two we double array size */
-    if ((nb & (nb - 1)) == 0) {
-        if (!nb)
-            nb_alloc = 1;
-        else
-            nb_alloc = nb * 2;
-        pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
-        if (!pp)
-            error("memory full");
-        *ptab = pp;
-    }
-    pp[nb++] = data;
-    *nb_ptr = nb;
 }
 
-void dynarray_reset(void *pp, int *n)
-{
-    void **p;
-    for (p = *(void***)pp; *n; ++p, --*n)
-        if (*p)
-            tcc_free(*p);
-    tcc_free(*(void**)pp);
-    *(void**)pp = NULL;
-}
+#else
 
-/* symbol allocator */
-static Sym *__sym_malloc(void)
-{
-    Sym *sym_pool, *sym, *last_sym;
-    int i;
+#define MEM_DEBUG_MAGIC1 0xFEEDDEB1
+#define MEM_DEBUG_MAGIC2 0xFEEDDEB2
+#define MEM_DEBUG_MAGIC3 0xFEEDDEB3
+#define MEM_DEBUG_FILE_LEN 40
+#define MEM_DEBUG_CHECK3(header) \
+    ((mem_debug_header_t*)((char*)header + header->size))->magic3
+#define MEM_USER_PTR(header) \
+    ((char *)header + offsetof(mem_debug_header_t, magic3))
+#define MEM_HEADER_PTR(ptr) \
+    (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3))
+
+struct mem_debug_header {
+    unsigned magic1;
+    unsigned size;
+    struct mem_debug_header *prev;
+    struct mem_debug_header *next;
+    int line_num;
+    char file_name[MEM_DEBUG_FILE_LEN + 1];
+    unsigned magic2;
+    ALIGNED(16) unsigned magic3;
+};
 
-    sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym));
-    dynarray_add(&sym_pools, &nb_sym_pools, sym_pool);
+typedef struct mem_debug_header mem_debug_header_t;
 
-    last_sym = sym_free_first;
-    sym = sym_pool;
-    for(i = 0; i < SYM_POOL_NB; i++) {
-        sym->next = last_sym;
-        last_sym = sym;
-        sym++;
-    }
-    sym_free_first = last_sym;
-    return last_sym;
-}
+static mem_debug_header_t *mem_debug_chain;
+static unsigned mem_cur_size;
+static unsigned mem_max_size;
 
-static inline Sym *sym_malloc(void)
+static mem_debug_header_t *malloc_check(void *ptr, const char *msg)
 {
-    Sym *sym;
-    sym = sym_free_first;
-    if (!sym)
-        sym = __sym_malloc();
-    sym_free_first = sym->next;
-    return sym;
+    mem_debug_header_t * header = MEM_HEADER_PTR(ptr);
+    if (header->magic1 != MEM_DEBUG_MAGIC1 ||
+        header->magic2 != MEM_DEBUG_MAGIC2 ||
+        MEM_DEBUG_CHECK3(header) != MEM_DEBUG_MAGIC3 ||
+        header->size == (unsigned)-1) {
+        fprintf(stderr, "%s check failed\n", msg);
+        if (header->magic1 == MEM_DEBUG_MAGIC1)
+            fprintf(stderr, "%s:%u: block allocated here.\n",
+                header->file_name, header->line_num);
+        exit(1);
+    }
+    return header;
 }
 
-static inline void sym_free(Sym *sym)
+PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
 {
-    sym->next = sym_free_first;
-    sym_free_first = sym;
-}
+    int ofs;
+    mem_debug_header_t *header;
 
-Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
-{
-    Section *sec;
+    header = malloc(sizeof(mem_debug_header_t) + size);
+    if (!header)
+        tcc_error("memory full (malloc)");
 
-    sec = tcc_mallocz(sizeof(Section) + strlen(name));
-    strcpy(sec->name, name);
-    sec->sh_type = sh_type;
-    sec->sh_flags = sh_flags;
-    switch(sh_type) {
-    case SHT_HASH:
-    case SHT_REL:
-    case SHT_RELA:
-    case SHT_DYNSYM:
-    case SHT_SYMTAB:
-    case SHT_DYNAMIC:
-        sec->sh_addralign = 4;
-        break;
-    case SHT_STRTAB:
-        sec->sh_addralign = 1;
-        break;
-    default:
-        sec->sh_addralign = 32; /* default conservative alignment */
-        break;
-    }
+    header->magic1 = MEM_DEBUG_MAGIC1;
+    header->magic2 = MEM_DEBUG_MAGIC2;
+    header->size = size;
+    MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
+    header->line_num = line;
+    ofs = strlen(file) - MEM_DEBUG_FILE_LEN;
+    strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);
+    header->file_name[MEM_DEBUG_FILE_LEN] = 0;
 
-    if (sh_flags & SHF_PRIVATE) {
-        dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
-    } else {
-        sec->sh_num = s1->nb_sections;
-        dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
-    }
+    header->next = mem_debug_chain;
+    header->prev = NULL;
+    if (header->next)
+        header->next->prev = header;
+    mem_debug_chain = header;
 
-    return sec;
-}
+    mem_cur_size += size;
+    if (mem_cur_size > mem_max_size)
+        mem_max_size = mem_cur_size;
 
-static void free_section(Section *s)
-{
-    tcc_free(s->data);
+    return MEM_USER_PTR(header);
 }
 
-/* realloc section and set its content to zero */
-static void section_realloc(Section *sec, unsigned long new_size)
+PUB_FUNC void tcc_free_debug(void *ptr)
 {
-    unsigned long size;
-    unsigned char *data;
-    
-    size = sec->data_allocated;
-    if (size == 0)
-        size = 1;
-    while (size < new_size)
-        size = size * 2;
-    data = tcc_realloc(sec->data, size);
-    if (!data)
-        error("memory full");
-    memset(data + sec->data_allocated, 0, size - sec->data_allocated);
-    sec->data = data;
-    sec->data_allocated = size;
+    mem_debug_header_t *header;
+    if (!ptr)
+        return;
+    header = malloc_check(ptr, "tcc_free");
+    mem_cur_size -= header->size;
+    header->size = (unsigned)-1;
+    if (header->next)
+        header->next->prev = header->prev;
+    if (header->prev)
+        header->prev->next = header->next;
+    if (header == mem_debug_chain)
+        mem_debug_chain = header->next;
+    free(header);
 }
 
-/* reserve at least 'size' bytes in section 'sec' from
-   sec->data_offset. */
-static void *section_ptr_add(Section *sec, unsigned long size)
+PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line)
 {
-    unsigned long offset, offset1;
+    void *ptr;
+    ptr = tcc_malloc_debug(size,file,line);
+    memset(ptr, 0, size);
+    return ptr;
+}
 
-    offset = sec->data_offset;
-    offset1 = offset + size;
-    if (offset1 > sec->data_allocated)
-        section_realloc(sec, offset1);
-    sec->data_offset = offset1;
-    return sec->data + offset;
+PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line)
+{
+    mem_debug_header_t *header;
+    int mem_debug_chain_update = 0;
+    if (!ptr)
+        return tcc_malloc_debug(size, file, line);
+    header = malloc_check(ptr, "tcc_realloc");
+    mem_cur_size -= header->size;
+    mem_debug_chain_update = (header == mem_debug_chain);
+    header = realloc(header, sizeof(mem_debug_header_t) + size);
+    if (!header)
+        tcc_error("memory full (realloc)");
+    header->size = size;
+    MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
+    if (header->next)
+        header->next->prev = header;
+    if (header->prev)
+        header->prev->next = header;
+    if (mem_debug_chain_update)
+        mem_debug_chain = header;
+    mem_cur_size += size;
+    if (mem_cur_size > mem_max_size)
+        mem_max_size = mem_cur_size;
+    return MEM_USER_PTR(header);
 }
 
-/* return a reference to a section, and create it if it does not
-   exists */
-Section *find_section(TCCState *s1, const char *name)
+PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
 {
-    Section *sec;
-    int i;
-    for(i = 1; i < s1->nb_sections; i++) {
-        sec = s1->sections[i];
-        if (!strcmp(name, sec->name)) 
-            return sec;
-    }
-    /* sections are created as PROGBITS */
-    return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
+    char *ptr;
+    ptr = tcc_malloc_debug(strlen(str) + 1, file, line);
+    strcpy(ptr, str);
+    return ptr;
 }
 
-/* update sym->c so that it points to an external symbol in section
-   'section' with value 'value' */
-static void put_extern_sym2(Sym *sym, Section *section, 
-                            unsigned long value, unsigned long size,
-                            int can_add_underscore)
+PUB_FUNC void tcc_memcheck(void)
 {
-    int sym_type, sym_bind, sh_num, info, other, attr;
-    ElfW(Sym) *esym;
-    const char *name;
-    char buf1[256];
-
-    if (section == NULL)
-        sh_num = SHN_UNDEF;
-    else if (section == SECTION_ABS) 
-        sh_num = SHN_ABS;
-    else
-        sh_num = section->sh_num;
-
-    other = attr = 0;
-
-    if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
-        sym_type = STT_FUNC;
-#ifdef TCC_TARGET_PE
-        if (sym->type.ref)
-            attr = sym->type.ref->r;
-        if (FUNC_EXPORT(attr))
-            other |= 1;
-        if (FUNC_CALL(attr) == FUNC_STDCALL)
-            other |= 2;
-#endif
-    } else {
-        sym_type = STT_OBJECT;
-    }
-
-    if (sym->type.t & VT_STATIC)
-        sym_bind = STB_LOCAL;
-    else
-        sym_bind = STB_GLOBAL;
-
-    if (!sym->c) {
-        name = get_tok_str(sym->v, NULL);
-#ifdef CONFIG_TCC_BCHECK
-        if (tcc_state->do_bounds_check) {
-            char buf[32];
-
-            /* XXX: avoid doing that for statics ? */
-            /* if bound checking is activated, we change some function
-               names by adding the "__bound" prefix */
-            switch(sym->v) {
-#if 0
-            /* XXX: we rely only on malloc hooks */
-            case TOK_malloc: 
-            case TOK_free: 
-            case TOK_realloc: 
-            case TOK_memalign: 
-            case TOK_calloc: 
-#endif
-            case TOK_memcpy: 
-            case TOK_memmove:
-            case TOK_memset:
-            case TOK_strlen:
-            case TOK_strcpy:
-            case TOK_alloca:
-                strcpy(buf, "__bound_");
-                strcat(buf, name);
-                name = buf;
-                break;
-            }
+    if (mem_cur_size) {
+        mem_debug_header_t *header = mem_debug_chain;
+        fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",
+            mem_cur_size, mem_max_size);
+        while (header) {
+            fprintf(stderr, "%s:%u: error: %u bytes leaked\n",
+                header->file_name, header->line_num, header->size);
+            header = header->next;
         }
+#if MEM_DEBUG-0 == 2
+        exit(2);
 #endif
-
-#ifdef TCC_TARGET_PE
-        if ((other & 2) && can_add_underscore) {
-            sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr));
-            name = buf1;
-        } else
-#endif
-        if (tcc_state->leading_underscore && can_add_underscore) {
-            buf1[0] = '_';
-            pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
-            name = buf1;
-        }
-        info = ELFW(ST_INFO)(sym_bind, sym_type);
-        sym->c = add_elf_sym(symtab_section, value, size, info, other, sh_num, name);
-    } else {
-        esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
-        esym->st_value = value;
-        esym->st_size = size;
-        esym->st_shndx = sh_num;
-        esym->st_other |= other;
     }
 }
+#endif /* MEM_DEBUG */
 
-static void put_extern_sym(Sym *sym, Section *section, 
-                           unsigned long value, unsigned long size)
-{
-    put_extern_sym2(sym, section, value, size, 1);
-}
+#define free(p) use_tcc_free(p)
+#define malloc(s) use_tcc_malloc(s)
+#define realloc(p, s) use_tcc_realloc(p, s)
 
-/* add a new relocation entry to symbol 'sym' in section 's' */
-static void greloc(Section *s, Sym *sym, unsigned long offset, int type)
-{
-    if (!sym->c) 
-        put_extern_sym(sym, NULL, 0, 0);
-    /* now we can add ELF relocation info */
-    put_elf_reloc(symtab_section, s, offset, type, sym->c);
-}
+/********************************************************/
+/* dynarrays */
 
-static inline int isid(int c)
+ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data)
 {
-    return (c >= 'a' && c <= 'z') ||
-        (c >= 'A' && c <= 'Z') ||
-        c == '_';
-}
+    int nb, nb_alloc;
+    void **pp;
 
-static inline int isnum(int c)
-{
-    return c >= '0' && c <= '9';
+    nb = *nb_ptr;
+    pp = *(void ***)ptab;
+    /* every power of two we double array size */
+    if ((nb & (nb - 1)) == 0) {
+        if (!nb)
+            nb_alloc = 1;
+        else
+            nb_alloc = nb * 2;
+        pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
+        *(void***)ptab = pp;
+    }
+    pp[nb++] = data;
+    *nb_ptr = nb;
 }
 
-static inline int isoct(int c)
+ST_FUNC void dynarray_reset(void *pp, int *n)
 {
-    return c >= '0' && c <= '7';
+    void **p;
+    for (p = *(void***)pp; *n; ++p, --*n)
+        if (*p)
+            tcc_free(*p);
+    tcc_free(*(void**)pp);
+    *(void**)pp = NULL;
 }
 
-static inline int toup(int c)
+static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in)
 {
-    if (c >= 'a' && c <= 'z')
-        return c - 'a' + 'A';
-    else
-        return c;
+    const char *p;
+    do {
+        int c;
+        CString str;
+
+        cstr_new(&str);
+        for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) {
+            if (c == '{' && p[1] && p[2] == '}') {
+                c = p[1], p += 2;
+                if (c == 'B')
+                    cstr_cat(&str, s->tcc_lib_path, -1);
+            } else {
+                cstr_ccat(&str, c);
+            }
+        }
+        if (str.size) {
+            cstr_ccat(&str, '\0');
+            dynarray_add(p_ary, p_nb_ary, tcc_strdup(str.data));
+        }
+        cstr_free(&str);
+        in = p+1;
+    } while (*p);
 }
 
+/********************************************************/
+
 static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
 {
     int len;
@@ -780,42 +473,51 @@ static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
     va_end(ap);
 }
 
-void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
+static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
 {
     char buf[2048];
-    BufferedFile **f;
-    
+    BufferedFile **pf, *f;
+
     buf[0] = '\0';
-    if (file) {
-        for(f = s1->include_stack; f < s1->include_stack_ptr; f++)
-            strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", 
-                          (*f)->filename, (*f)->line_num);
-        if (file->line_num > 0) {
-            strcat_printf(buf, sizeof(buf), 
-                          "%s:%d: ", file->filename, file->line_num);
+    /* use upper file if inline ":asm:" or token ":paste:" */
+    for (f = file; f && f->filename[0] == ':'; f = f->prev)
+     ;
+    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",
+                (*pf)->filename, (*pf)->line_num);
+        if (f->line_num > 0) {
+            strcat_printf(buf, sizeof(buf), "%s:%d: ",
+                f->filename, f->line_num - !!(tok_flags & TOK_FLAG_BOL));
         } else {
-            strcat_printf(buf, sizeof(buf),
-                          "%s: ", file->filename);
+            strcat_printf(buf, sizeof(buf), "%s: ",
+                f->filename);
         }
     } else {
-        strcat_printf(buf, sizeof(buf),
-                      "tcc: ");
+        strcat_printf(buf, sizeof(buf), "tcc: ");
     }
     if (is_warning)
         strcat_printf(buf, sizeof(buf), "warning: ");
+    else
+        strcat_printf(buf, sizeof(buf), "error: ");
     strcat_vprintf(buf, sizeof(buf), fmt, ap);
 
     if (!s1->error_func) {
         /* default case: stderr */
+        if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
+            /* print a newline during tcc -E */
+            printf("\n"), fflush(stdout);
+        fflush(stdout); /* flush -v output */
         fprintf(stderr, "%s\n", buf);
-    } 
-    if (!is_warning || s1->warn_error) {
+        fflush(stderr); /* print error/warning now (win32) */
+    } else {
         s1->error_func(s1->error_opaque, buf);
-        s1->nb_errors++;
     }
+    if (!is_warning || s1->warn_error)
+        s1->nb_errors++;
 }
 
-void tcc_set_error_func(TCCState *s, void *error_opaque,
+LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
                         void (*error_func)(void *opaque, const char *msg))
 {
     s->error_opaque = error_opaque;
@@ -823,7 +525,7 @@ void tcc_set_error_func(TCCState *s, void *error_opaque,
 }
 
 /* error without aborting current compilation */
-void error_noabort(const char *fmt, ...)
+PUB_FUNC void tcc_error_noabort(const char *fmt, ...)
 {
     TCCState *s1 = tcc_state;
     va_list ap;
@@ -833,7 +535,7 @@ void error_noabort(const char *fmt, ...)
     va_end(ap);
 }
 
-void error(const char *fmt, ...)
+PUB_FUNC void tcc_error(const char *fmt, ...)
 {
     TCCState *s1 = tcc_state;
     va_list ap;
@@ -850,12 +552,7 @@ void error(const char *fmt, ...)
     }
 }
 
-void expect(const char *msg)
-{
-    error("%s expected", msg);
-}
-
-void warning(const char *fmt, ...)
+PUB_FUNC void tcc_warning(const char *fmt, ...)
 {
     TCCState *s1 = tcc_state;
     va_list ap;
@@ -868,435 +565,135 @@ void warning(const char *fmt, ...)
     va_end(ap);
 }
 
-void skip(int c)
-{
-    if (tok != c)
-        error("'%c' expected", c);
-    next();
-}
-
-static void test_lvalue(void)
-{
-    if (!(vtop->r & VT_LVAL))
-        expect("lvalue");
-}
-
-/* CString handling */
-
-static void cstr_realloc(CString *cstr, int new_size)
-{
-    int size;
-    void *data;
-
-    size = cstr->size_allocated;
-    if (size == 0)
-        size = 8; /* no need to allocate a too small first string */
-    while (size < new_size)
-        size = size * 2;
-    data = tcc_realloc(cstr->data_allocated, size);
-    if (!data)
-        error("memory full");
-    cstr->data_allocated = data;
-    cstr->size_allocated = size;
-    cstr->data = data;
-}
-
-/* add a byte */
-static inline void cstr_ccat(CString *cstr, int ch)
-{
-    int size;
-    size = cstr->size + 1;
-    if (size > cstr->size_allocated)
-        cstr_realloc(cstr, size);
-    ((unsigned char *)cstr->data)[size - 1] = ch;
-    cstr->size = size;
-}
-
-static void cstr_cat(CString *cstr, const char *str)
-{
-    int c;
-    for(;;) {
-        c = *str;
-        if (c == '\0')
-            break;
-        cstr_ccat(cstr, c);
-        str++;
-    }
-}
-
-/* add a wide char */
-static void cstr_wccat(CString *cstr, int ch)
-{
-    int size;
-    size = cstr->size + sizeof(nwchar_t);
-    if (size > cstr->size_allocated)
-        cstr_realloc(cstr, size);
-    *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
-    cstr->size = size;
-}
-
-static void cstr_new(CString *cstr)
-{
-    memset(cstr, 0, sizeof(CString));
-}
-
-/* free string and reset it to NULL */
-static void cstr_free(CString *cstr)
-{
-    tcc_free(cstr->data_allocated);
-    cstr_new(cstr);
-}
-
-#define cstr_reset(cstr) cstr_free(cstr)
-
-/* XXX: unicode ? */
-static void add_char(CString *cstr, int c)
-{
-    if (c == '\'' || c == '\"' || c == '\\') {
-        /* XXX: could be more precise if char or string */
-        cstr_ccat(cstr, '\\');
-    }
-    if (c >= 32 && c <= 126) {
-        cstr_ccat(cstr, c);
-    } else {
-        cstr_ccat(cstr, '\\');
-        if (c == '\n') {
-            cstr_ccat(cstr, 'n');
-        } else {
-            cstr_ccat(cstr, '0' + ((c >> 6) & 7));
-            cstr_ccat(cstr, '0' + ((c >> 3) & 7));
-            cstr_ccat(cstr, '0' + (c & 7));
-        }
-    }
-}
-
-/* push, without hashing */
-static Sym *sym_push2(Sym **ps, int v, int t, long c)
-{
-    Sym *s;
-    s = sym_malloc();
-    s->v = v;
-    s->type.t = t;
-    s->c = c;
-    s->next = NULL;
-    /* add in stack */
-    s->prev = *ps;
-    *ps = s;
-    return s;
-}
-
-/* find a symbol and return its associated structure. 's' is the top
-   of the symbol stack */
-static Sym *sym_find2(Sym *s, int v)
-{
-    while (s) {
-        if (s->v == v)
-            return s;
-        s = s->prev;
-    }
-    return NULL;
-}
-
-/* structure lookup */
-static inline Sym *struct_find(int v)
-{
-    v -= TOK_IDENT;
-    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
-        return NULL;
-    return table_ident[v]->sym_struct;
-}
-
-/* find an identifier */
-static inline Sym *sym_find(int v)
-{
-    v -= TOK_IDENT;
-    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
-        return NULL;
-    return table_ident[v]->sym_identifier;
-}
+/********************************************************/
+/* I/O layer */
 
-/* push a given symbol on the symbol stack */
-static Sym *sym_push(int v, CType *type, int r, int c)
+ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
 {
-    Sym *s, **ps;
-    TokenSym *ts;
-
-    if (local_stack)
-        ps = &local_stack;
-    else
-        ps = &global_stack;
-    s = sym_push2(ps, v, type->t, c);
-    s->type.ref = type->ref;
-    s->r = r;
-    /* don't record fields or anonymous symbols */
-    /* XXX: simplify */
-    if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
-        /* record symbol in token array */
-        ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
-        if (v & SYM_STRUCT)
-            ps = &ts->sym_struct;
-        else
-            ps = &ts->sym_identifier;
-        s->prev_tok = *ps;
-        *ps = s;
-    }
-    return s;
-}
+    BufferedFile *bf;
+    int buflen = initlen ? initlen : IO_BUF_SIZE;
 
-/* push a global identifier */
-static Sym *global_identifier_push(int v, int t, int c)
-{
-    Sym *s, **ps;
-    s = sym_push2(&global_stack, v, t, c);
-    /* don't record anonymous symbol */
-    if (v < SYM_FIRST_ANOM) {
-        ps = &table_ident[v - TOK_IDENT]->sym_identifier;
-        /* modify the top most local identifier, so that
-           sym_identifier will point to 's' when popped */
-        while (*ps != NULL)
-            ps = &(*ps)->prev_tok;
-        s->prev_tok = NULL;
-        *ps = s;
-    }
-    return s;
+    bf = tcc_mallocz(sizeof(BufferedFile) + buflen);
+    bf->buf_ptr = bf->buffer;
+    bf->buf_end = bf->buffer + initlen;
+    bf->buf_end[0] = CH_EOB; /* put eob symbol */
+    pstrcpy(bf->filename, sizeof(bf->filename), filename);
+    bf->true_filename = bf->filename;
+    bf->line_num = 1;
+    bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
+    bf->fd = -1;
+    bf->prev = file;
+    file = bf;
+    tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
 }
 
-/* pop symbols until top reaches 'b' */
-static void sym_pop(Sym **ptop, Sym *b)
+ST_FUNC void tcc_close(void)
 {
-    Sym *s, *ss, **ps;
-    TokenSym *ts;
-    int v;
-
-    s = *ptop;
-    while(s != b) {
-        ss = s->prev;
-        v = s->v;
-        /* remove symbol in token array */
-        /* XXX: simplify */
-        if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
-            ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
-            if (v & SYM_STRUCT)
-                ps = &ts->sym_struct;
-            else
-                ps = &ts->sym_identifier;
-            *ps = s->prev_tok;
-        }
-        sym_free(s);
-        s = ss;
+    BufferedFile *bf = file;
+    if (bf->fd > 0) {
+        close(bf->fd);
+        total_lines += bf->line_num;
     }
-    *ptop = b;
+    if (bf->true_filename != bf->filename)
+        tcc_free(bf->true_filename);
+    file = bf->prev;
+    tcc_free(bf);
 }
 
-/* I/O layer */
-
-BufferedFile *tcc_open(TCCState *s1, const char *filename)
+ST_FUNC int tcc_open(TCCState *s1, const char *filename)
 {
     int fd;
-    BufferedFile *bf;
-
     if (strcmp(filename, "-") == 0)
-        fd = 0, filename = "stdin";
+        fd = 0, filename = "<stdin>";
     else
         fd = open(filename, O_RDONLY | O_BINARY);
     if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
         printf("%s %*s%s\n", fd < 0 ? "nf":"->",
-               (s1->include_stack_ptr - s1->include_stack), "", filename);
+               (int)(s1->include_stack_ptr - s1->include_stack), "", filename);
     if (fd < 0)
-        return NULL;
-    bf = tcc_malloc(sizeof(BufferedFile));
-    bf->fd = fd;
-    bf->buf_ptr = bf->buffer;
-    bf->buf_end = bf->buffer;
-    bf->buffer[0] = CH_EOB; /* put eob symbol */
-    pstrcpy(bf->filename, sizeof(bf->filename), filename);
+        return -1;
+    tcc_open_bf(s1, filename, 0);
 #ifdef _WIN32
-    normalize_slashes(bf->filename);
+    normalize_slashes(file->filename);
 #endif
-    bf->line_num = 1;
-    bf->ifndef_macro = 0;
-    bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
-    //    printf("opening '%s'\n", filename);
-    return bf;
+    file->fd = fd;
+    return fd;
 }
 
-void tcc_close(BufferedFile *bf)
-{
-    total_lines += bf->line_num;
-    close(bf->fd);
-    tcc_free(bf);
-}
-
-#include "tccpp.c"
-#include "tccgen.c"
-
-
-/* compile the C file opened in 'file'. Return non zero if errors. */
+/* compile the file opened in 'file'. Return non zero if errors. */
 static int tcc_compile(TCCState *s1)
 {
     Sym *define_start;
-    char buf[512];
-    volatile int section_sym;
-
-#ifdef INC_DEBUG
-    printf("%s: **** new file\n", file->filename);
-#endif
-    preprocess_init(s1);
-
-    cur_text_section = NULL;
-    funcname = "";
-    anon_sym = SYM_FIRST_ANOM; 
-
-    /* file info: full path + filename */
-    section_sym = 0; /* avoid warning */
-    if (s1->do_debug) {
-        section_sym = put_elf_sym(symtab_section, 0, 0, 
-                                  ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, 
-                                  text_section->sh_num, NULL);
-        getcwd(buf, sizeof(buf));
-#ifdef _WIN32
-        normalize_slashes(buf);
-#endif
-        pstrcat(buf, sizeof(buf), "/");
-        put_stabs_r(buf, N_SO, 0, 0, 
-                    text_section->data_offset, text_section, section_sym);
-        put_stabs_r(file->filename, N_SO, 0, 0, 
-                    text_section->data_offset, text_section, section_sym);
-    }
-    /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
-       symbols can be safely used */
-    put_elf_sym(symtab_section, 0, 0, 
-                ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, 
-                SHN_ABS, file->filename);
-
-    /* define some often used types */
-    int_type.t = VT_INT;
-
-    char_pointer_type.t = VT_BYTE;
-    mk_pointer(&char_pointer_type);
-
-    func_old_type.t = VT_FUNC;
-    func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
-
-#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
-    float_type.t = VT_FLOAT;
-    double_type.t = VT_DOUBLE;
-
-    func_float_type.t = VT_FUNC;
-    func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
-    func_double_type.t = VT_FUNC;
-    func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
-#endif
-
-#if 0
-    /* define 'void *alloca(unsigned int)' builtin function */
-    {
-        Sym *s1;
-
-        p = anon_sym++;
-        sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
-        s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
-        s1->next = NULL;
-        sym->next = s1;
-        sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
-    }
-#endif
+    int filetype, is_asm;
 
     define_start = define_stack;
-    nocode_wanted = 1;
+    filetype = s1->filetype;
+    is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP;
 
     if (setjmp(s1->error_jmp_buf) == 0) {
         s1->nb_errors = 0;
         s1->error_set_jmp_enabled = 1;
 
-        ch = file->buf_ptr[0];
-        tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
-        parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
-        next();
-        decl(VT_CONST);
-        if (tok != TOK_EOF)
-            expect("declaration");
-
-        /* end of translation unit info */
-        if (s1->do_debug) {
-            put_stabs_r(NULL, N_SO, 0, 0, 
-                        text_section->data_offset, text_section, section_sym);
+        preprocess_start(s1, is_asm);
+        if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
+            tcc_preprocess(s1);
+        } else if (is_asm) {
+#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;
 
-    /* reset define stack, but leave -Dsymbols (may be incorrect if
-       they are undefined) */
-    free_defines(define_start); 
-
-    gen_inline_functions();
-
-    sym_pop(&global_stack, NULL);
-    sym_pop(&local_stack, NULL);
-
+    preprocess_end(s1);
+    free_inline_functions(s1);
+    /* reset define stack, but keep -D and built-ins */
+    free_defines(define_start);
+    sym_pop(&global_stack, NULL, 0);
+    sym_pop(&local_stack, NULL, 0);
     return s1->nb_errors != 0 ? -1 : 0;
 }
 
-int tcc_compile_string(TCCState *s, const char *str)
+LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
 {
-    BufferedFile bf1, *bf = &bf1;
-    int ret, len;
-    char *buf;
+    int len, ret;
 
-    /* init file structure */
-    bf->fd = -1;
-    /* XXX: avoid copying */
     len = strlen(str);
-    buf = tcc_malloc(len + 1);
-    if (!buf)
-        return -1;
-    memcpy(buf, str, len);
-    buf[len] = CH_EOB;
-    bf->buf_ptr = buf;
-    bf->buf_end = buf + len;
-    pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
-    bf->line_num = 1;
-    file = bf;
+    tcc_open_bf(s, "<string>", len);
+    memcpy(file->buffer, str, len);
     ret = tcc_compile(s);
-    file = NULL;
-    tcc_free(buf);
-
-    /* currently, no need to close */
+    tcc_close();
     return ret;
 }
 
 /* define a preprocessor symbol. A value can also be provided with the '=' operator */
-void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
+LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
 {
-    BufferedFile bf1, *bf = &bf1;
-
-    pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
-    pstrcat(bf->buffer, IO_BUF_SIZE, " ");
+    int len1, len2;
     /* default value */
-    if (!value) 
+    if (!value)
         value = "1";
-    pstrcat(bf->buffer, IO_BUF_SIZE, value);
-    
+    len1 = strlen(sym);
+    len2 = strlen(value);
+
     /* init file structure */
-    bf->fd = -1;
-    bf->buf_ptr = bf->buffer;
-    bf->buf_end = bf->buffer + strlen(bf->buffer);
-    *bf->buf_end = CH_EOB;
-    bf->filename[0] = '\0';
-    bf->line_num = 1;
-    file = bf;
-    
-    s1->include_stack_ptr = s1->include_stack;
+    tcc_open_bf(s1, "<define>", len1 + len2 + 1);
+    memcpy(file->buffer, sym, len1);
+    file->buffer[len1] = ' ';
+    memcpy(file->buffer + len1 + 1, value, len2);
 
     /* parse with define parser */
-    ch = file->buf_ptr[0];
     next_nomacro();
     parse_define();
-    file = NULL;
+    tcc_close();
 }
 
 /* undefine a preprocessor symbol */
-void tcc_undefine_symbol(TCCState *s1, const char *sym)
+LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
 {
     TokenSym *ts;
     Sym *s;
@@ -1307,458 +704,22 @@ void tcc_undefine_symbol(TCCState *s1, const char *sym)
         define_undef(s);
 }
 
-#ifdef CONFIG_TCC_ASM
-
-#ifdef TCC_TARGET_I386
-#include "i386-asm.c"
-#endif
-#include "tccasm.c"
-
-#else
-static void asm_instr(void)
-{
-    error("inline asm() not supported");
-}
-static void asm_global_instr(void)
-{
-    error("inline asm() not supported");
-}
-#endif
-
-#include "tccelf.c"
-
-#ifdef TCC_TARGET_COFF
-#include "tcccoff.c"
-#endif
-
-#ifdef TCC_TARGET_PE
-#include "tccpe.c"
-#endif
-
-#ifdef CONFIG_TCC_BACKTRACE
-/* print the position in the source file of PC value 'pc' by reading
-   the stabs debug information */
-static void rt_printline(unsigned long wanted_pc)
-{
-    Stab_Sym *sym, *sym_end;
-    char func_name[128], last_func_name[128];
-    unsigned long func_addr, last_pc, pc;
-    const char *incl_files[INCLUDE_STACK_SIZE];
-    int incl_index, len, last_line_num, i;
-    const char *str, *p;
-
-    fprintf(stderr, "0x%08lx:", wanted_pc);
-
-    func_name[0] = '\0';
-    func_addr = 0;
-    incl_index = 0;
-    last_func_name[0] = '\0';
-    last_pc = 0xffffffff;
-    last_line_num = 1;
-    sym = (Stab_Sym *)stab_section->data + 1;
-    sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
-    while (sym < sym_end) {
-        switch(sym->n_type) {
-            /* function start or end */
-        case N_FUN:
-            if (sym->n_strx == 0) {
-                /* we test if between last line and end of function */
-                pc = sym->n_value + func_addr;
-                if (wanted_pc >= last_pc && wanted_pc < pc)
-                    goto found;
-                func_name[0] = '\0';
-                func_addr = 0;
-            } else {
-                str = stabstr_section->data + sym->n_strx;
-                p = strchr(str, ':');
-                if (!p) {
-                    pstrcpy(func_name, sizeof(func_name), str);
-                } else {
-                    len = p - str;
-                    if (len > sizeof(func_name) - 1)
-                        len = sizeof(func_name) - 1;
-                    memcpy(func_name, str, len);
-                    func_name[len] = '\0';
-                }
-                func_addr = sym->n_value;
-            }
-            break;
-            /* line number info */
-        case N_SLINE:
-            pc = sym->n_value + func_addr;
-            if (wanted_pc >= last_pc && wanted_pc < pc)
-                goto found;
-            last_pc = pc;
-            last_line_num = sym->n_desc;
-            /* XXX: slow! */
-            strcpy(last_func_name, func_name);
-            break;
-            /* include files */
-        case N_BINCL:
-            str = stabstr_section->data + sym->n_strx;
-        add_incl:
-            if (incl_index < INCLUDE_STACK_SIZE) {
-                incl_files[incl_index++] = str;
-            }
-            break;
-        case N_EINCL:
-            if (incl_index > 1)
-                incl_index--;
-            break;
-        case N_SO:
-            if (sym->n_strx == 0) {
-                incl_index = 0; /* end of translation unit */
-            } else {
-                str = stabstr_section->data + sym->n_strx;
-                /* do not add path */
-                len = strlen(str);
-                if (len > 0 && str[len - 1] != '/')
-                    goto add_incl;
-            }
-            break;
-        }
-        sym++;
-    }
-
-    /* second pass: we try symtab symbols (no line number info) */
-    incl_index = 0;
-    {
-        ElfW(Sym) *sym, *sym_end;
-        int type;
-
-        sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
-        for(sym = (ElfW(Sym) *)symtab_section->data + 1; 
-            sym < sym_end;
-            sym++) {
-            type = ELFW(ST_TYPE)(sym->st_info);
-            if (type == STT_FUNC) {
-                if (wanted_pc >= sym->st_value &&
-                    wanted_pc < sym->st_value + sym->st_size) {
-                    pstrcpy(last_func_name, sizeof(last_func_name),
-                            strtab_section->data + sym->st_name);
-                    goto found;
-                }
-            }
-        }
-    }
-    /* did not find any info: */
-    fprintf(stderr, " ???\n");
-    return;
- found:
-    if (last_func_name[0] != '\0') {
-        fprintf(stderr, " %s()", last_func_name);
-    }
-    if (incl_index > 0) {
-        fprintf(stderr, " (%s:%d", 
-                incl_files[incl_index - 1], last_line_num);
-        for(i = incl_index - 2; i >= 0; i--)
-            fprintf(stderr, ", included from %s", incl_files[i]);
-        fprintf(stderr, ")");
-    }
-    fprintf(stderr, "\n");
-}
-
-#ifdef __i386__
-/* fix for glibc 2.1 */
-#ifndef REG_EIP
-#define REG_EIP EIP
-#define REG_EBP EBP
-#endif
-
-/* return the PC at frame level 'level'. Return non zero if not found */
-static int rt_get_caller_pc(unsigned long *paddr, 
-                            ucontext_t *uc, int level)
-{
-    unsigned long fp;
-    int i;
-
-    if (level == 0) {
-#if defined(__FreeBSD__)
-        *paddr = uc->uc_mcontext.mc_eip;
-#elif defined(__dietlibc__)
-        *paddr = uc->uc_mcontext.eip;
-#else
-        *paddr = uc->uc_mcontext.gregs[REG_EIP];
-#endif
-        return 0;
-    } else {
-#if defined(__FreeBSD__) 
-        fp = uc->uc_mcontext.mc_ebp;
-#elif defined(__dietlibc__)
-        fp = uc->uc_mcontext.ebp;
-#else
-        fp = uc->uc_mcontext.gregs[REG_EBP];
-#endif
-        for(i=1;i<level;i++) {
-            /* XXX: check address validity with program info */
-            if (fp <= 0x1000 || fp >= 0xc0000000)
-                return -1;
-            fp = ((unsigned long *)fp)[0];
-        }
-        *paddr = ((unsigned long *)fp)[1];
-        return 0;
-    }
-}
-#elif defined(__x86_64__)
-/* return the PC at frame level 'level'. Return non zero if not found */
-static int rt_get_caller_pc(unsigned long *paddr,
-                            ucontext_t *uc, int level)
-{
-    unsigned long fp;
-    int i;
-
-    if (level == 0) {
-        /* XXX: only support linux */
-        *paddr = uc->uc_mcontext.gregs[REG_RIP];
-        return 0;
-    } else {
-        fp = uc->uc_mcontext.gregs[REG_RBP];
-        for(i=1;i<level;i++) {
-            /* XXX: check address validity with program info */
-            if (fp <= 0x1000)
-                return -1;
-            fp = ((unsigned long *)fp)[0];
-        }
-        *paddr = ((unsigned long *)fp)[1];
-        return 0;
-    }
-}
-#else
-#warning add arch specific rt_get_caller_pc()
-static int rt_get_caller_pc(unsigned long *paddr,
-                            ucontext_t *uc, int level)
-{
-    return -1;
-}
-#endif
-
-/* emit a run time error at position 'pc' */
-void rt_error(ucontext_t *uc, const char *fmt, ...)
-{
-    va_list ap;
-    unsigned long pc;
-    int i;
-
-    va_start(ap, fmt);
-    fprintf(stderr, "Runtime error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    for(i=0;i<num_callers;i++) {
-        if (rt_get_caller_pc(&pc, uc, i) < 0)
-            break;
-        if (i == 0)
-            fprintf(stderr, "at ");
-        else
-            fprintf(stderr, "by ");
-        rt_printline(pc);
-    }
-    exit(255);
-    va_end(ap);
-}
-
-/* signal handler for fatal errors */
-static void sig_error(int signum, siginfo_t *siginf, void *puc)
-{
-    ucontext_t *uc = puc;
-
-    switch(signum) {
-    case SIGFPE:
-        switch(siginf->si_code) {
-        case FPE_INTDIV:
-        case FPE_FLTDIV:
-            rt_error(uc, "division by zero");
-            break;
-        default:
-            rt_error(uc, "floating point exception");
-            break;
-        }
-        break;
-    case SIGBUS:
-    case SIGSEGV:
-        if (rt_bound_error_msg && *rt_bound_error_msg)
-            rt_error(uc, *rt_bound_error_msg);
-        else
-            rt_error(uc, "dereferencing invalid pointer");
-        break;
-    case SIGILL:
-        rt_error(uc, "illegal instruction");
-        break;
-    case SIGABRT:
-        rt_error(uc, "abort() called");
-        break;
-    default:
-        rt_error(uc, "caught signal %d", signum);
-        break;
-    }
-    exit(255);
-}
-
-#endif
-
-/* copy code into memory passed in by the caller and do all relocations
-   (needed before using tcc_get_symbol()).
-   returns -1 on error and required size if ptr is NULL */
-int tcc_relocate(TCCState *s1, void *ptr)
-{
-    Section *s;
-    unsigned long offset, length, mem;
-    int i;
-
-    if (0 == s1->runtime_added) {
-        s1->runtime_added = 1;
-        s1->nb_errors = 0;
-#ifdef TCC_TARGET_PE
-        pe_add_runtime(s1);
-        relocate_common_syms();
-        tcc_add_linker_symbols(s1);
-#else
-        tcc_add_runtime(s1);
-        relocate_common_syms();
-        tcc_add_linker_symbols(s1);
-        build_got_entries(s1);
-#endif
-    }
-
-    offset = 0, mem = (unsigned long)ptr;
-    for(i = 1; i < s1->nb_sections; i++) {
-        s = s1->sections[i];
-        if (0 == (s->sh_flags & SHF_ALLOC))
-            continue;
-        length = s->data_offset;
-        s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
-        offset = (offset + length + 15) & ~15;
-    }
-
-    /* relocate symbols */
-    relocate_syms(s1, 1);
-    if (s1->nb_errors)
-        return -1;
-
-#ifdef TCC_TARGET_X86_64
-    s1->runtime_plt_and_got_offset = 0;
-    s1->runtime_plt_and_got = (char *)(mem + offset);
-    /* double the size of the buffer for got and plt entries
-       XXX: calculate exact size for them? */
-    offset *= 2;
-#endif
-
-    if (0 == mem)
-        return offset + 15;
-
-    /* relocate each section */
-    for(i = 1; i < s1->nb_sections; i++) {
-        s = s1->sections[i];
-        if (s->reloc)
-            relocate_section(s1, s);
-    }
-
-    for(i = 1; i < s1->nb_sections; i++) {
-        s = s1->sections[i];
-        if (0 == (s->sh_flags & SHF_ALLOC))
-            continue;
-        length = s->data_offset;
-        // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
-        ptr = (void*)s->sh_addr;
-        if (NULL == s->data || s->sh_type == SHT_NOBITS)
-            memset(ptr, 0, length);
-        else
-            memcpy(ptr, s->data, length);
-        /* mark executable sections as executable in memory */
-        if (s->sh_flags & SHF_EXECINSTR)
-            set_pages_executable(ptr, length);
-    }
-#ifdef TCC_TARGET_X86_64
-    set_pages_executable(s1->runtime_plt_and_got,
-                         s1->runtime_plt_and_got_offset);
-#endif
-    return 0;
-}
-
-/* launch the compiled program with the given arguments */
-int tcc_run(TCCState *s1, int argc, char **argv)
-{
-    int (*prog_main)(int, char **);
-    void *ptr;
-    int ret;
-
-    ret = tcc_relocate(s1, NULL);
-    if (ret < 0)
-        return -1;
-    ptr = tcc_malloc(ret);
-    tcc_relocate(s1, ptr);
-
-    prog_main = tcc_get_symbol_err(s1, "main");
-    
-    if (s1->do_debug) {
-#ifdef CONFIG_TCC_BACKTRACE
-        struct sigaction sigact;
-        /* install TCC signal handlers to print debug info on fatal
-           runtime errors */
-        sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
-        sigact.sa_sigaction = sig_error;
-        sigemptyset(&sigact.sa_mask);
-        sigaction(SIGFPE, &sigact, NULL);
-        sigaction(SIGILL, &sigact, NULL);
-        sigaction(SIGSEGV, &sigact, NULL);
-        sigaction(SIGBUS, &sigact, NULL);
-        sigaction(SIGABRT, &sigact, NULL);
-#else        
-        error("debug mode not available");
-#endif
-    }
-
-#ifdef CONFIG_TCC_BCHECK
-    if (s1->do_bounds_check) {
-        void (*bound_init)(void);
-
-        /* set error function */
-        rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
-
-        /* XXX: use .init section so that it also work in binary ? */
-        bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init");
-        bound_init();
-    }
-#endif
-    ret = (*prog_main)(argc, argv);
-    tcc_free(ptr);
-    return ret;
-}
-
-void tcc_memstats(void)
-{
-#ifdef MEM_DEBUG
-    printf("memory in use: %d\n", mem_cur_size);
-#endif
-}
-
+/* cleanup all static data used during compilation */
 static void tcc_cleanup(void)
 {
-    int i, n;
-
     if (NULL == tcc_state)
         return;
+    while (file)
+        tcc_close();
+    tccpp_delete(tcc_state);
     tcc_state = NULL;
-
-    /* free -D defines */
-    free_defines(NULL);
-
-    /* free tokens */
-    n = tok_ident - TOK_IDENT;
-    for(i = 0; i < n; i++)
-        tcc_free(table_ident[i]);
-    tcc_free(table_ident);
-
     /* free sym_pools */
     dynarray_reset(&sym_pools, &nb_sym_pools);
-    /* string buffer */
-    cstr_free(&tokcstr);
     /* reset symbol stack */
     sym_free_first = NULL;
-    /* cleanup from error/setjmp */
-    macro_ptr = NULL;
 }
 
-TCCState *tcc_new(void)
+LIBTCCAPI TCCState *tcc_new(void)
 {
     TCCState *s;
 
@@ -1768,10 +729,30 @@ TCCState *tcc_new(void)
     if (!s)
         return NULL;
     tcc_state = s;
-    s->output_type = TCC_OUTPUT_MEMORY;
-    s->tcc_lib_path = CONFIG_TCCDIR;
+    ++nb_states;
+
+    s->alacarte_link = 1;
+    s->nocommon = 1;
+    s->warn_implicit_function_declaration = 1;
+    s->ms_extensions = 1;
 
-    preprocess_new();
+#ifdef CHAR_IS_UNSIGNED
+    s->char_is_unsigned = 1;
+#endif
+#ifdef TCC_TARGET_I386
+    s->seg_size = 32;
+#endif
+    /* enable this if you want symbols with leading underscore on windows: */
+#if 0 /* def TCC_TARGET_PE */
+    s->leading_underscore = 1;
+#endif
+#ifdef _WIN32
+    tcc_set_lib_path_w32(s);
+#else
+    tcc_set_lib_path(s, CONFIG_TCCDIR);
+#endif
+    tccelf_new(s);
+    tccpp_new(s);
 
     /* we add dummy defines for some special macros to speed up tests
        and to have working defined() */
@@ -1779,17 +760,28 @@ TCCState *tcc_new(void)
     define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
     define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
     define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
+    define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
+    {
+        /* define __TINYC__ 92X  */
+        char buffer[32]; int a,b,c;
+        sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c);
+        sprintf(buffer, "%d", a*10000 + b*100 + c);
+        tcc_define_symbol(s, "__TINYC__", buffer);
+    }
 
     /* standard defines */
     tcc_define_symbol(s, "__STDC__", NULL);
     tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
+    tcc_define_symbol(s, "__STDC_HOSTED__", NULL);
+
+    /* target defines */
 #if defined(TCC_TARGET_I386)
     tcc_define_symbol(s, "__i386__", NULL);
-#endif
-#if defined(TCC_TARGET_X86_64)
+    tcc_define_symbol(s, "__i386", NULL);
+    tcc_define_symbol(s, "i386", NULL);
+#elif defined(TCC_TARGET_X86_64)
     tcc_define_symbol(s, "__x86_64__", NULL);
-#endif
-#if defined(TCC_TARGET_ARM)
+#elif defined(TCC_TARGET_ARM)
     tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
     tcc_define_symbol(s, "__arm_elf__", NULL);
     tcc_define_symbol(s, "__arm_elf", NULL);
@@ -1798,372 +790,403 @@ TCCState *tcc_new(void)
     tcc_define_symbol(s, "__arm", NULL);
     tcc_define_symbol(s, "arm", NULL);
     tcc_define_symbol(s, "__APCS_32__", NULL);
+    tcc_define_symbol(s, "__ARMEL__", NULL);
+#if defined(TCC_ARM_EABI)
+    tcc_define_symbol(s, "__ARM_EABI__", NULL);
+#endif
+#if defined(TCC_ARM_HARDFLOAT)
+    s->float_abi = ARM_HARD_FLOAT;
+    tcc_define_symbol(s, "__ARM_PCS_VFP", NULL);
+#else
+    s->float_abi = ARM_SOFTFP_FLOAT;
 #endif
+#elif defined(TCC_TARGET_ARM64)
+    tcc_define_symbol(s, "__aarch64__", NULL);
+#elif defined TCC_TARGET_C67
+    tcc_define_symbol(s, "__C67__", NULL);
+#endif
+
 #ifdef TCC_TARGET_PE
     tcc_define_symbol(s, "_WIN32", NULL);
+# ifdef TCC_TARGET_X86_64
+    tcc_define_symbol(s, "_WIN64", NULL);
+# endif
 #else
     tcc_define_symbol(s, "__unix__", NULL);
     tcc_define_symbol(s, "__unix", NULL);
-#if defined(__linux)
+    tcc_define_symbol(s, "unix", NULL);
+# if defined(__linux__)
     tcc_define_symbol(s, "__linux__", NULL);
     tcc_define_symbol(s, "__linux", NULL);
+# endif
+# if defined(__FreeBSD__)
+    tcc_define_symbol(s, "__FreeBSD__", "__FreeBSD__");
+    /* No 'Thread Storage Local' on FreeBSD with tcc */
+    tcc_define_symbol(s, "__NO_TLS", NULL);
+# endif
+# if defined(__FreeBSD_kernel__)
+    tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
+# endif
+# if defined(__NetBSD__)
+    tcc_define_symbol(s, "__NetBSD__", "__NetBSD__");
+# endif
+# if defined(__OpenBSD__)
+    tcc_define_symbol(s, "__OpenBSD__", "__OpenBSD__");
+# endif
 #endif
-#endif
-    /* tiny C specific defines */
-    tcc_define_symbol(s, "__TINYC__", NULL);
 
-    /* tiny C & gcc defines */
+    /* TinyCC & gcc defines */
+#if PTR_SIZE == 4
+    /* 32bit systems. */
     tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
     tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
+    tcc_define_symbol(s, "__ILP32__", NULL);
+#elif LONG_SIZE == 4
+    /* 64bit Windows. */
+    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
+    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
+    tcc_define_symbol(s, "__LLP64__", NULL);
+#else
+    /* Other 64bit systems. */
+    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
+    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
+    tcc_define_symbol(s, "__LP64__", NULL);
+#endif
+
 #ifdef TCC_TARGET_PE
     tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
+    tcc_define_symbol(s, "__WINT_TYPE__", "unsigned short");
 #else
     tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
-#endif
-    
-#ifndef TCC_TARGET_PE
-    /* default library paths */
-    tcc_add_library_path(s, CONFIG_SYSROOT "/usr/local/lib");
-    tcc_add_library_path(s, CONFIG_SYSROOT "/usr/lib");
-    tcc_add_library_path(s, CONFIG_SYSROOT "/lib");
-#endif
-
-    /* no section zero */
-    dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
-
-    /* create standard sections */
-    text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
-    data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
-    bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
-
-    /* symbols are always generated for linking stage */
-    symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
-                                ".strtab",
-                                ".hashtab", SHF_PRIVATE); 
-    strtab_section = symtab_section->link;
-    
-    /* private symbol table for dynamic symbols */
-    s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
-                                      ".dynstrtab", 
-                                      ".dynhashtab", SHF_PRIVATE);
-    s->alacarte_link = 1;
-
-#ifdef CHAR_IS_UNSIGNED
-    s->char_is_unsigned = 1;
-#endif
-#if defined(TCC_TARGET_PE) && 0
-    /* XXX: currently the PE linker is not ready to support that */
-    s->leading_underscore = 1;
-#endif
+    /* wint_t is unsigned int by default, but (signed) int on BSDs
+       and unsigned short on windows.  Other OSes might have still
+       other conventions, sigh.  */
+# if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) \
+  || defined(__NetBSD__) || defined(__OpenBSD__)
+    tcc_define_symbol(s, "__WINT_TYPE__", "int");
+#  ifdef __FreeBSD__
+    /* define __GNUC__ to have some useful stuff from sys/cdefs.h
+       that are unconditionally used in FreeBSDs other system headers :/ */
+    tcc_define_symbol(s, "__GNUC__", "2");
+    tcc_define_symbol(s, "__GNUC_MINOR__", "7");
+    tcc_define_symbol(s, "__builtin_alloca", "alloca");
+#  endif
+# else
+    tcc_define_symbol(s, "__WINT_TYPE__", "unsigned int");
+    /* glibc defines */
+    tcc_define_symbol(s, "__REDIRECT(name, proto, alias)",
+        "name proto __asm__ (#alias)");
+    tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)",
+        "name proto __asm__ (#alias) __THROW");
+# endif
+# if defined(TCC_MUSL)
+    tcc_define_symbol(s, "__DEFINED_va_list", "");
+    tcc_define_symbol(s, "__DEFINED___isoc_va_list", "");
+    tcc_define_symbol(s, "__isoc_va_list", "void *");
+# endif /* TCC_MUSL */
+    /* 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;
 }
 
-void tcc_delete(TCCState *s1)
+LIBTCCAPI void tcc_delete(TCCState *s1)
 {
-    int i;
-
     tcc_cleanup();
 
-    /* free all sections */
-    for(i = 1; i < s1->nb_sections; i++)
-        free_section(s1->sections[i]);
-    dynarray_reset(&s1->sections, &s1->nb_sections);
-
-    for(i = 0; i < s1->nb_priv_sections; i++)
-        free_section(s1->priv_sections[i]);
-    dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
-        
-    /* free any loaded DLLs */
-    for ( i = 0; i < s1->nb_loaded_dlls; i++) {
-        DLLReference *ref = s1->loaded_dlls[i];
-        if ( ref->handle )
-            dlclose(ref->handle);
-    }
-    
-    /* free loaded dlls array */
-    dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
+    /* free sections */
+    tccelf_delete(s1);
 
     /* free library paths */
     dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
+    dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths);
 
     /* free include paths */
     dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
     dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
     dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
+    dynarray_reset(&s1->cmd_include_files, &s1->nb_cmd_include_files);
+
+    tcc_free(s1->tcc_lib_path);
+    tcc_free(s1->soname);
+    tcc_free(s1->rpath);
+    tcc_free(s1->init_symbol);
+    tcc_free(s1->fini_symbol);
+    tcc_free(s1->outfile);
+    tcc_free(s1->deps_outfile);
+    dynarray_reset(&s1->files, &s1->nb_files);
+    dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
+    dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
+    dynarray_reset(&s1->argv, &s1->argc);
+
+#ifdef TCC_IS_NATIVE
+    /* free runtime memory */
+    tcc_run_free(s1);
+#endif
 
     tcc_free(s1);
+    if (0 == --nb_states)
+        tcc_memcheck();
 }
 
-int tcc_add_include_path(TCCState *s1, const char *pathname)
+LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
 {
-    char *pathname1;
-    
-    pathname1 = tcc_strdup(pathname);
-    dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1);
+    s->output_type = output_type;
+
+    /* always elf for objects */
+    if (output_type == TCC_OUTPUT_OBJ)
+        s->output_format = TCC_OUTPUT_FORMAT_ELF;
+
+    if (s->char_is_unsigned)
+        tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
+
+    if (!s->nostdinc) {
+        /* default include paths */
+        /* -isystem paths have already been handled */
+        tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS);
+    }
+
+#ifdef CONFIG_TCC_BCHECK
+    if (s->do_bounds_check) {
+        /* if bound checking, then add corresponding sections */
+        tccelf_bounds_new(s);
+        /* define symbol */
+        tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
+    }
+#endif
+    if (s->do_debug) {
+        /* add debug sections */
+        tccelf_stab_new(s);
+    }
+
+    tcc_add_library_path(s, CONFIG_TCC_LIBPATHS);
+
+#ifdef TCC_TARGET_PE
+# ifdef _WIN32
+    if (!s->nostdlib && output_type != TCC_OUTPUT_OBJ)
+        tcc_add_systemdir(s);
+# endif
+#else
+    /* paths for crt objects */
+    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) {
+        if (output_type != TCC_OUTPUT_DLL)
+            tcc_add_crt(s, "crt1.o");
+        tcc_add_crt(s, "crti.o");
+    }
+#endif
     return 0;
 }
 
-int tcc_add_sysinclude_path(TCCState *s1, const char *pathname)
+LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
 {
-    char *pathname1;
-    
-    pathname1 = tcc_strdup(pathname);
-    dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1);
+    tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname);
     return 0;
 }
 
-static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
+LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
 {
-    const char *ext;
-    ElfW(Ehdr) ehdr;
-    int fd, ret;
-    BufferedFile *saved_file;
+    tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
+    return 0;
+}
 
-    /* find source file type with extension */
-    ext = tcc_fileextension(filename);
-    if (ext[0])
-        ext++;
+ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
+{
+    int ret;
 
     /* open the file */
-    saved_file = file;
-    file = tcc_open(s1, filename);
-    if (!file) {
-        if (flags & AFF_PRINT_ERROR) {
-            error_noabort("file '%s' not found", filename);
-        }
-        ret = -1;
-        goto fail1;
+    ret = tcc_open(s1, filename);
+    if (ret < 0) {
+        if (flags & AFF_PRINT_ERROR)
+            tcc_error_noabort("file '%s' not found", filename);
+        return ret;
     }
 
-    if (flags & AFF_PREPROCESS) {
-        ret = tcc_preprocess(s1);
-    } else if (!ext[0] || !PATHCMP(ext, "c")) {
-        /* C file assumed */
-        ret = tcc_compile(s1);
-    } else 
-#ifdef CONFIG_TCC_ASM
-    if (!strcmp(ext, "S")) {
-        /* preprocessed assembler */
-        ret = tcc_assemble(s1, 1);
-    } else if (!strcmp(ext, "s")) {
-        /* non preprocessed assembler */
-        ret = tcc_assemble(s1, 0);
-    } else 
-#endif
-#ifdef TCC_TARGET_PE
-    if (!PATHCMP(ext, "def")) {
-        ret = pe_load_def_file(s1, file->fd);
-    } else
-#endif
-    {
+    /* update target deps */
+    dynarray_add(&s1->target_deps, &s1->nb_target_deps,
+            tcc_strdup(filename));
+
+    if (flags & AFF_TYPE_BIN) {
+        ElfW(Ehdr) ehdr;
+        int fd, obj_type;
+
         fd = file->fd;
-        /* assume executable format: auto guess file type */
-        ret = read(fd, &ehdr, sizeof(ehdr));
+        obj_type = tcc_object_type(fd, &ehdr);
         lseek(fd, 0, SEEK_SET);
-        if (ret <= 0) {
-            error_noabort("could not read header");
-            goto fail;
-        } else if (ret != sizeof(ehdr)) {
-            goto try_load_script;
-        }
 
-        if (ehdr.e_ident[0] == ELFMAG0 &&
-            ehdr.e_ident[1] == ELFMAG1 &&
-            ehdr.e_ident[2] == ELFMAG2 &&
-            ehdr.e_ident[3] == ELFMAG3) {
-            file->line_num = 0; /* do not display line number if error */
-            if (ehdr.e_type == ET_REL) {
-                ret = tcc_load_object_file(s1, fd, 0);
-            } else if (ehdr.e_type == ET_DYN) {
-                if (s1->output_type == TCC_OUTPUT_MEMORY) {
-#ifdef TCC_TARGET_PE
+        /* do not display line number if error */
+        file->line_num = 0;
+
+#ifdef TCC_TARGET_MACHO
+        if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib"))
+            obj_type = AFF_BINTYPE_DYN;
+#endif
+
+        switch (obj_type) {
+        case AFF_BINTYPE_REL:
+            ret = tcc_load_object_file(s1, fd, 0);
+            break;
+#ifndef TCC_TARGET_PE
+        case AFF_BINTYPE_DYN:
+            if (s1->output_type == TCC_OUTPUT_MEMORY) {
+                ret = 0;
+#ifdef TCC_IS_NATIVE
+                if (NULL == dlopen(filename, RTLD_GLOBAL | RTLD_LAZY))
                     ret = -1;
-#else
-                    void *h;
-                    h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
-                    if (h)
-                        ret = 0;
-                    else
-                        ret = -1;
 #endif
-                } else {
-                    ret = tcc_load_dll(s1, fd, filename, 
-                                       (flags & AFF_REFERENCED_DLL) != 0);
-                }
             } else {
-                error_noabort("unrecognized ELF file");
-                goto fail;
+                ret = tcc_load_dll(s1, fd, filename,
+                                   (flags & AFF_REFERENCED_DLL) != 0);
             }
-        } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
-            file->line_num = 0; /* do not display line number if error */
+            break;
+#endif
+        case AFF_BINTYPE_AR:
             ret = tcc_load_archive(s1, fd);
-        } else 
+            break;
 #ifdef TCC_TARGET_COFF
-        if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
+        case AFF_BINTYPE_C67:
             ret = tcc_load_coff(s1, fd);
-        } else
+            break;
 #endif
+        default:
 #ifdef TCC_TARGET_PE
-        if (pe_test_res_file(&ehdr, ret)) {
-            ret = pe_load_res_file(s1, fd);
-        } else
-#endif
-        {
+            ret = pe_load_file(s1, filename, fd);
+#else
             /* as GNU ld, consider it is an ld script if not recognized */
-        try_load_script:
             ret = tcc_load_ldscript(s1);
-            if (ret < 0) {
-                error_noabort("unrecognized file type");
-                goto fail;
-            }
+#endif
+            if (ret < 0)
+                tcc_error_noabort("unrecognized file type");
+            break;
         }
+    } else {
+        ret = tcc_compile(s1);
     }
- the_end:
-    tcc_close(file);
- fail1:
-    file = saved_file;
+    tcc_close();
     return ret;
- fail:
-    ret = -1;
-    goto the_end;
 }
 
-int tcc_add_file(TCCState *s, const char *filename)
-{
-    if (s->output_type == TCC_OUTPUT_PREPROCESS)
-        return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS);
-    else
-        return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR);
+LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
+{
+    int filetype = s->filetype;
+    int flags = AFF_PRINT_ERROR;
+    if (filetype == 0) {
+        /* use a file extension to detect a filetype */
+        const char *ext = tcc_fileextension(filename);
+        if (ext[0]) {
+            ext++;
+            if (!strcmp(ext, "S"))
+                filetype = AFF_TYPE_ASMPP;
+            else if (!strcmp(ext, "s"))
+                filetype = AFF_TYPE_ASM;
+            else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
+                filetype = AFF_TYPE_C;
+            else
+                flags |= AFF_TYPE_BIN;
+        } else {
+            filetype = AFF_TYPE_C;
+        }
+        s->filetype = filetype;
+    }
+    return tcc_add_file_internal(s, filename, flags);
 }
 
-int tcc_add_library_path(TCCState *s, const char *pathname)
+LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
 {
-    char *pathname1;
-    
-    pathname1 = tcc_strdup(pathname);
-    dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1);
+    tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname);
     return 0;
 }
 
-/* find and load a dll. Return non zero if not found */
-/* XXX: add '-rpath' option support ? */
-static int tcc_add_dll(TCCState *s, const char *filename, int flags)
+static int tcc_add_library_internal(TCCState *s, const char *fmt,
+    const char *filename, int flags, char **paths, int nb_paths)
 {
     char buf[1024];
     int i;
 
-    for(i = 0; i < s->nb_library_paths; i++) {
-        snprintf(buf, sizeof(buf), "%s/%s", 
-                 s->library_paths[i], filename);
-        if (tcc_add_file_internal(s, buf, flags) == 0)
+    for(i = 0; i < nb_paths; i++) {
+        snprintf(buf, sizeof(buf), fmt, paths[i], filename);
+        if (tcc_add_file_internal(s, buf, flags | AFF_TYPE_BIN) == 0)
             return 0;
     }
     return -1;
 }
 
-/* the library name is the same as the argument of the '-l' option */
-int tcc_add_library(TCCState *s, const char *libraryname)
+/* find and load a dll. Return non zero if not found */
+/* XXX: add '-rpath' option support ? */
+ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
 {
-    char buf[1024];
-    int i;
-    
-    /* first we look for the dynamic library if not static linking */
-    if (!s->static_link) {
-#ifdef TCC_TARGET_PE
-        snprintf(buf, sizeof(buf), "%s.def", libraryname);
+    return tcc_add_library_internal(s, "%s/%s", filename, flags,
+        s->library_paths, s->nb_library_paths);
+}
+
+ST_FUNC int tcc_add_crt(TCCState *s, const char *filename)
+{
+    if (-1 == tcc_add_library_internal(s, "%s/%s",
+        filename, 0, s->crt_paths, s->nb_crt_paths))
+        tcc_error_noabort("file '%s' not found", filename);
+    return 0;
+}
+
+/* the library name is the same as the argument of the '-l' option */
+LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
+{
+#if defined TCC_TARGET_PE
+    const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL };
+    const char **pp = s->static_link ? libs + 4 : libs;
+#elif defined TCC_TARGET_MACHO
+    const char *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL };
+    const char **pp = s->static_link ? libs + 1 : libs;
 #else
-        snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
+    const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
+    const char **pp = s->static_link ? libs + 1 : libs;
 #endif
-        if (tcc_add_dll(s, buf, 0) == 0)
-            return 0;
-    }
-
-    /* then we look for the static library */
-    for(i = 0; i < s->nb_library_paths; i++) {
-        snprintf(buf, sizeof(buf), "%s/lib%s.a", 
-                 s->library_paths[i], libraryname);
-        if (tcc_add_file_internal(s, buf, 0) == 0)
+    while (*pp) {
+        if (0 == tcc_add_library_internal(s, *pp,
+            libraryname, 0, s->library_paths, s->nb_library_paths))
             return 0;
+        ++pp;
     }
     return -1;
 }
 
-int tcc_add_symbol(TCCState *s, const char *name, void *val)
+PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname)
 {
-    add_elf_sym(symtab_section, (unsigned long)val, 0, 
-                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
-                SHN_ABS, name);
-    return 0;
+    int ret = tcc_add_library(s, libname);
+    if (ret < 0)
+        tcc_error_noabort("library '%s' not found", libname);
+    return ret;
 }
 
-int tcc_set_output_type(TCCState *s, int output_type)
+/* handle #pragma comment(lib,) */
+ST_FUNC void tcc_add_pragma_libs(TCCState *s1)
 {
-    char buf[1024];
-
-    s->output_type = output_type;
-
-    if (!s->nostdinc) {
-        /* default include paths */
-        /* XXX: reverse order needed if -isystem support */
-#ifndef TCC_TARGET_PE
-        tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/local/include");
-        tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/include");
-#endif
-        snprintf(buf, sizeof(buf), "%s/include", s->tcc_lib_path);
-        tcc_add_sysinclude_path(s, buf);
-#ifdef TCC_TARGET_PE
-        snprintf(buf, sizeof(buf), "%s/include/winapi", s->tcc_lib_path);
-        tcc_add_sysinclude_path(s, buf);
-#endif
-    }
-
-    /* if bound checking, then add corresponding sections */
-#ifdef CONFIG_TCC_BCHECK
-    if (s->do_bounds_check) {
-        /* define symbol */
-        tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
-        /* create bounds sections */
-        bounds_section = new_section(s, ".bounds", 
-                                     SHT_PROGBITS, SHF_ALLOC);
-        lbounds_section = new_section(s, ".lbounds", 
-                                      SHT_PROGBITS, SHF_ALLOC);
-    }
-#endif
-
-    if (s->char_is_unsigned) {
-        tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
-    }
-
-    /* add debug sections */
-    if (s->do_debug) {
-        /* stab symbols */
-        stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
-        stab_section->sh_entsize = sizeof(Stab_Sym);
-        stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
-        put_elf_str(stabstr_section, "");
-        stab_section->link = stabstr_section;
-        /* put first entry */
-        put_stabs("", 0, 0, 0, 0);
-    }
-
-    /* add libc crt1/crti objects */
-#ifndef TCC_TARGET_PE
-    if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
-        !s->nostdlib) {
-        if (output_type != TCC_OUTPUT_DLL)
-            tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
-        tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
-    }
-#endif
+    int i;
+    for (i = 0; i < s1->nb_pragma_libs; i++)
+        tcc_add_library_err(s1, s1->pragma_libs[i]);
+}
 
+LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
+{
 #ifdef TCC_TARGET_PE
-    snprintf(buf, sizeof(buf), "%s/lib", s->tcc_lib_path);
-    tcc_add_library_path(s, buf);
+    /* On x86_64 'val' might not be reachable with a 32bit offset.
+       So it is handled here as if it were in a DLL. */
+    pe_putimport(s, 0, name, (uintptr_t)val);
+#else
+    set_elf_sym(symtab_section, (uintptr_t)val, 0,
+        ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+        SHN_ABS, name);
 #endif
-
     return 0;
 }
 
+LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
+{
+    tcc_free(s->tcc_lib_path);
+    s->tcc_lib_path = tcc_strdup(path);
+}
+
 #define WD_ALL    0x0001 /* warning is activated when using -Wall */
 #define FD_INVERT 0x0002 /* invert value before storing */
 
@@ -2173,87 +1196,787 @@ typedef struct FlagDef {
     const char *name;
 } FlagDef;
 
-static const FlagDef warning_defs[] = {
-    { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
-    { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
-    { offsetof(TCCState, warn_error), 0, "error" },
-    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
-      "implicit-function-declaration" },
-};
+static int no_flag(const char **pp)
+{
+    const char *p = *pp;
+    if (*p != 'n' || *++p != 'o' || *++p != '-')
+        return 0;
+    *pp = p + 1;
+    return 1;
+}
 
-static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
-                    const char *name, int value)
+ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name)
 {
-    int i;
+    int value, ret;
     const FlagDef *p;
     const char *r;
 
+    value = 1;
     r = name;
-    if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
-        r += 3;
-        value = !value;
-    }
-    for(i = 0, p = flags; i < nb_flags; i++, p++) {
-        if (!strcmp(r, p->name))
-            goto found;
+    if (no_flag(&r))
+        value = 0;
+
+    for (ret = -1, p = flags; p->name; ++p) {
+        if (ret) {
+            if (strcmp(r, p->name))
+                continue;
+        } else {
+            if (0 == (p->flags & WD_ALL))
+                continue;
+        }
+        if (p->offset) {
+            *(int*)((char *)s + p->offset) =
+                p->flags & FD_INVERT ? !value : value;
+            if (ret)
+                return 0;
+        } else {
+            ret = 0;
+        }
     }
-    return -1;
- found:
-    if (p->flags & FD_INVERT)
-        value = !value;
-    *(int *)((uint8_t *)s + p->offset) = value;
-    return 0;
+    return ret;
 }
 
+static int strstart(const char *val, const char **str)
+{
+    const char *p, *q;
+    p = *str;
+    q = val;
+    while (*q) {
+        if (*p != *q)
+            return 0;
+        p++;
+        q++;
+    }
+    *str = p;
+    return 1;
+}
 
-/* set/reset a warning */
-int tcc_set_warning(TCCState *s, const char *warning_name, int value)
+/* Like strstart, but automatically takes into account that ld options can
+ *
+ * - start with double or single dash (e.g. '--soname' or '-soname')
+ * - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so'
+ *   or '-Wl,-soname=x.so')
+ *
+ * you provide `val` always in 'option[=]' form (no leading -)
+ */
+static int link_option(const char *str, const char *val, const char **ptr)
 {
-    int i;
-    const FlagDef *p;
+    const char *p, *q;
+    int ret;
 
-    if (!strcmp(warning_name, "all")) {
-        for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
-            if (p->flags & WD_ALL)
-                *(int *)((uint8_t *)s + p->offset) = 1;
-        }
+    /* there should be 1 or 2 dashes */
+    if (*str++ != '-')
         return 0;
-    } else {
-        return set_flag(s, warning_defs, countof(warning_defs),
-                        warning_name, value);
+    if (*str == '-')
+        str++;
+
+    /* then str & val should match (potentially up to '=') */
+    p = str;
+    q = val;
+
+    ret = 1;
+    if (q[0] == '?') {
+        ++q;
+        if (no_flag(&p))
+            ret = -1;
+    }
+
+    while (*q != '\0' && *q != '=') {
+        if (*p != *q)
+            return 0;
+        p++;
+        q++;
+    }
+
+    /* '=' near eos means ',' or '=' is ok */
+    if (*q == '=') {
+        if (*p == 0)
+            *ptr = p;
+        if (*p != ',' && *p != '=')
+            return 0;
+        p++;
+    } else if (*p) {
+        return 0;
+    }
+    *ptr = p;
+    return ret;
+}
+
+static const char *skip_linker_arg(const char **str)
+{
+    const char *s1 = *str;
+    const char *s2 = strchr(s1, ',');
+    *str = s2 ? s2++ : (s2 = s1 + strlen(s1));
+    return s2;
+}
+
+static void copy_linker_arg(char **pp, const char *s, int sep)
+{
+    const char *q = s;
+    char *p = *pp;
+    int l = 0;
+    if (p && sep)
+        p[l = strlen(p)] = sep, ++l;
+    skip_linker_arg(&q);
+    pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s);
+}
+
+/* set linker options */
+static int tcc_set_linker(TCCState *s, const char *option)
+{
+    while (*option) {
+
+        const char *p = NULL;
+        char *end = NULL;
+        int ignoring = 0;
+        int ret;
+
+        if (link_option(option, "Bsymbolic", &p)) {
+            s->symbolic = 1;
+        } else if (link_option(option, "nostdlib", &p)) {
+            s->nostdlib = 1;
+        } else if (link_option(option, "fini=", &p)) {
+            copy_linker_arg(&s->fini_symbol, p, 0);
+            ignoring = 1;
+        } else if (link_option(option, "image-base=", &p)
+                || link_option(option, "Ttext=", &p)) {
+            s->text_addr = strtoull(p, &end, 16);
+            s->has_text_addr = 1;
+        } else if (link_option(option, "init=", &p)) {
+            copy_linker_arg(&s->init_symbol, p, 0);
+            ignoring = 1;
+        } else if (link_option(option, "oformat=", &p)) {
+#if defined(TCC_TARGET_PE)
+            if (strstart("pe-", &p)) {
+#elif PTR_SIZE == 8
+            if (strstart("elf64-", &p)) {
+#else
+            if (strstart("elf32-", &p)) {
+#endif
+                s->output_format = TCC_OUTPUT_FORMAT_ELF;
+            } else if (!strcmp(p, "binary")) {
+                s->output_format = TCC_OUTPUT_FORMAT_BINARY;
+#ifdef TCC_TARGET_COFF
+            } else if (!strcmp(p, "coff")) {
+                s->output_format = TCC_OUTPUT_FORMAT_COFF;
+#endif
+            } else
+                goto err;
+
+        } else if (link_option(option, "as-needed", &p)) {
+            ignoring = 1;
+        } else if (link_option(option, "O", &p)) {
+            ignoring = 1;
+        } else if (link_option(option, "export-all-symbols", &p)) {
+            s->rdynamic = 1;
+        } else if (link_option(option, "rpath=", &p)) {
+            copy_linker_arg(&s->rpath, p, ':');
+        } else if (link_option(option, "enable-new-dtags", &p)) {
+            s->enable_new_dtags = 1;
+        } else if (link_option(option, "section-alignment=", &p)) {
+            s->section_align = strtoul(p, &end, 16);
+        } else if (link_option(option, "soname=", &p)) {
+            copy_linker_arg(&s->soname, p, 0);
+#ifdef TCC_TARGET_PE
+        } else if (link_option(option, "large-address-aware", &p)) {
+            s->pe_characteristics |= 0x20;
+        } else if (link_option(option, "file-alignment=", &p)) {
+            s->pe_file_align = strtoul(p, &end, 16);
+        } else if (link_option(option, "stack=", &p)) {
+            s->pe_stack_size = strtoul(p, &end, 10);
+        } else if (link_option(option, "subsystem=", &p)) {
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+            if (!strcmp(p, "native")) {
+                s->pe_subsystem = 1;
+            } else if (!strcmp(p, "console")) {
+                s->pe_subsystem = 3;
+            } else if (!strcmp(p, "gui") || !strcmp(p, "windows")) {
+                s->pe_subsystem = 2;
+            } else if (!strcmp(p, "posix")) {
+                s->pe_subsystem = 7;
+            } else if (!strcmp(p, "efiapp")) {
+                s->pe_subsystem = 10;
+            } else if (!strcmp(p, "efiboot")) {
+                s->pe_subsystem = 11;
+            } else if (!strcmp(p, "efiruntime")) {
+                s->pe_subsystem = 12;
+            } else if (!strcmp(p, "efirom")) {
+                s->pe_subsystem = 13;
+#elif defined(TCC_TARGET_ARM)
+            if (!strcmp(p, "wince")) {
+                s->pe_subsystem = 9;
+#endif
+            } else
+                goto err;
+#endif
+        } else if (ret = link_option(option, "?whole-archive", &p), ret) {
+            s->alacarte_link = ret < 0;
+        } else if (p) {
+            return 0;
+        } else {
+    err:
+            tcc_error("unsupported linker option '%s'", option);
+        }
+
+        if (ignoring && s->warn_unsupported)
+            tcc_warning("unsupported linker option '%s'", option);
+
+        option = skip_linker_arg(&p);
     }
+    return 1;
 }
 
-static const FlagDef flag_defs[] = {
+typedef struct TCCOption {
+    const char *name;
+    uint16_t index;
+    uint16_t flags;
+} TCCOption;
+
+enum {
+    TCC_OPTION_HELP,
+    TCC_OPTION_HELP2,
+    TCC_OPTION_v,
+    TCC_OPTION_I,
+    TCC_OPTION_D,
+    TCC_OPTION_U,
+    TCC_OPTION_P,
+    TCC_OPTION_L,
+    TCC_OPTION_B,
+    TCC_OPTION_l,
+    TCC_OPTION_bench,
+    TCC_OPTION_bt,
+    TCC_OPTION_b,
+    TCC_OPTION_g,
+    TCC_OPTION_c,
+    TCC_OPTION_dumpversion,
+    TCC_OPTION_d,
+    TCC_OPTION_static,
+    TCC_OPTION_std,
+    TCC_OPTION_shared,
+    TCC_OPTION_soname,
+    TCC_OPTION_o,
+    TCC_OPTION_r,
+    TCC_OPTION_s,
+    TCC_OPTION_traditional,
+    TCC_OPTION_Wl,
+    TCC_OPTION_Wp,
+    TCC_OPTION_W,
+    TCC_OPTION_O,
+    TCC_OPTION_mfloat_abi,
+    TCC_OPTION_m,
+    TCC_OPTION_f,
+    TCC_OPTION_isystem,
+    TCC_OPTION_iwithprefix,
+    TCC_OPTION_include,
+    TCC_OPTION_nostdinc,
+    TCC_OPTION_nostdlib,
+    TCC_OPTION_print_search_dirs,
+    TCC_OPTION_rdynamic,
+    TCC_OPTION_param,
+    TCC_OPTION_pedantic,
+    TCC_OPTION_pthread,
+    TCC_OPTION_run,
+    TCC_OPTION_w,
+    TCC_OPTION_pipe,
+    TCC_OPTION_E,
+    TCC_OPTION_MD,
+    TCC_OPTION_MF,
+    TCC_OPTION_x,
+    TCC_OPTION_ar,
+    TCC_OPTION_impdef
+};
+
+#define TCC_OPTION_HAS_ARG 0x0001
+#define TCC_OPTION_NOSEP   0x0002 /* cannot have space before option and arg */
+
+static const TCCOption tcc_options[] = {
+    { "h", TCC_OPTION_HELP, 0 },
+    { "-help", TCC_OPTION_HELP, 0 },
+    { "?", TCC_OPTION_HELP, 0 },
+    { "hh", TCC_OPTION_HELP2, 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 },
+    { "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
+    { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
+    { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "bench", TCC_OPTION_bench, 0 },
+#ifdef CONFIG_TCC_BACKTRACE
+    { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
+#endif
+#ifdef CONFIG_TCC_BCHECK
+    { "b", TCC_OPTION_b, 0 },
+#endif
+    { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "c", TCC_OPTION_c, 0 },
+    { "dumpversion", TCC_OPTION_dumpversion, 0},
+    { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "static", TCC_OPTION_static, 0 },
+    { "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "shared", TCC_OPTION_shared, 0 },
+    { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
+    { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
+    { "-param", TCC_OPTION_param, TCC_OPTION_HAS_ARG },
+    { "pedantic", TCC_OPTION_pedantic, 0},
+    { "pthread", TCC_OPTION_pthread, 0},
+    { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "rdynamic", TCC_OPTION_rdynamic, 0 },
+    { "r", TCC_OPTION_r, 0 },
+    { "s", TCC_OPTION_s, 0 },
+    { "traditional", TCC_OPTION_traditional, 0 },
+    { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+#ifdef TCC_TARGET_ARM
+    { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG },
+#endif
+    { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
+    { "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG },
+    { "nostdinc", TCC_OPTION_nostdinc, 0 },
+    { "nostdlib", TCC_OPTION_nostdlib, 0 },
+    { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
+    { "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 },
+};
+
+static const FlagDef options_W[] = {
+    { 0, 0, "all" },
+    { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
+    { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
+    { offsetof(TCCState, warn_error), 0, "error" },
+    { offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" },
+    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
+      "implicit-function-declaration" },
+    { 0, 0, NULL }
+};
+
+static const FlagDef options_f[] = {
     { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
     { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
     { offsetof(TCCState, nocommon), FD_INVERT, "common" },
     { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
+    { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
+    { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
+    { 0, 0, NULL }
+};
+
+static const FlagDef options_m[] = {
+    { offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" },
+#ifdef TCC_TARGET_X86_64
+    { offsetof(TCCState, nosse), FD_INVERT, "sse" },
+#endif
+    { 0, 0, NULL }
 };
 
-/* set/reset a flag */
-int tcc_set_flag(TCCState *s, const char *flag_name, int value)
+static void parse_option_D(TCCState *s1, const char *optarg)
 {
-    return set_flag(s, flag_defs, countof(flag_defs),
-                    flag_name, value);
+    char *sym = tcc_strdup(optarg);
+    char *value = strchr(sym, '=');
+    if (value)
+        *value++ = '\0';
+    tcc_define_symbol(s1, sym, value);
+    tcc_free(sym);
 }
 
-/* set CONFIG_TCCDIR at runtime */
-void tcc_set_lib_path(TCCState *s, const char *path)
+static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
 {
-    s->tcc_lib_path = tcc_strdup(path);
+    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, int optind, int *pargc, char ***pargv)
+{
+    int fd, i;
+    size_t len;
+    char *p;
+    int argc = 0;
+    char **argv = NULL;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        tcc_error("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);
+
+    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;
 }
 
-void tcc_print_stats(TCCState *s, int64_t total_time)
+PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
 {
-    double tt;
-    tt = (double)total_time / 1000000.0;
-    if (tt < 0.001)
-        tt = 0.001;
+    const TCCOption *popt;
+    const char *optarg, *r;
+    const char *run = NULL;
+    int last_o = -1;
+    int x;
+    CString linker_arg; /* collect -Wl options */
+    int tool = 0, arg_start = 0, noaction = optind;
+    char **argv = *pargv;
+    int argc = *pargc;
+
+    cstr_new(&linker_arg);
+
+    while (optind < argc) {
+        r = argv[optind];
+        if (r[0] == '@' && r[1] != '\0') {
+            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);
+                arg_start = optind - 1;
+                break;
+            }
+            continue;
+        }
+
+        /* find option in table */
+        for(popt = tcc_options; ; ++popt) {
+            const char *p1 = popt->name;
+            const char *r1 = r + 1;
+            if (p1 == NULL)
+                tcc_error("invalid option -- '%s'", r);
+            if (!strstart(p1, &r1))
+                continue;
+            optarg = r1;
+            if (popt->flags & TCC_OPTION_HAS_ARG) {
+                if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) {
+                    if (optind >= argc)
+                arg_err:
+                        tcc_error("argument to '%s' is missing", r);
+                    optarg = argv[optind++];
+                }
+            } else if (*r1 != '\0')
+                continue;
+            break;
+        }
+
+        switch(popt->index) {
+        case TCC_OPTION_HELP:
+            return OPT_HELP;
+        case TCC_OPTION_HELP2:
+            return OPT_HELP2;
+        case TCC_OPTION_I:
+            tcc_add_include_path(s, optarg);
+            break;
+        case TCC_OPTION_D:
+            parse_option_D(s, optarg);
+            break;
+        case TCC_OPTION_U:
+            tcc_undefine_symbol(s, optarg);
+            break;
+        case TCC_OPTION_L:
+            tcc_add_library_path(s, optarg);
+            break;
+        case TCC_OPTION_B:
+            /* set tcc utilities path (mainly for tcc development) */
+            tcc_set_lib_path(s, optarg);
+            break;
+        case TCC_OPTION_l:
+            args_parser_add_file(s, optarg, AFF_TYPE_LIB);
+            s->nb_libraries++;
+            break;
+        case TCC_OPTION_pthread:
+            parse_option_D(s, "_REENTRANT");
+            s->option_pthread = 1;
+            break;
+        case TCC_OPTION_bench:
+            s->do_bench = 1;
+            break;
+#ifdef CONFIG_TCC_BACKTRACE
+        case TCC_OPTION_bt:
+            tcc_set_num_callers(atoi(optarg));
+            break;
+#endif
+#ifdef CONFIG_TCC_BCHECK
+        case TCC_OPTION_b:
+            s->do_bounds_check = 1;
+            s->do_debug = 1;
+            break;
+#endif
+        case TCC_OPTION_g:
+            s->do_debug = 1;
+            break;
+        case TCC_OPTION_c:
+            x = TCC_OUTPUT_OBJ;
+        set_output_type:
+            if (s->output_type)
+                tcc_warning("-%s: overriding compiler action already specified", popt->name);
+            s->output_type = x;
+            break;
+        case TCC_OPTION_d:
+            if (*optarg == 'D')
+                s->dflag = 3;
+            else if (*optarg == 'M')
+                s->dflag = 7;
+            else if (*optarg == 't')
+                s->dflag = 16;
+            else if (isnum(*optarg))
+                g_debug = atoi(optarg);
+            else
+                goto unsupported_option;
+            break;
+        case TCC_OPTION_static:
+            s->static_link = 1;
+            break;
+        case TCC_OPTION_std:
+    	    /* silently ignore, a current purpose:
+    	       allow to use a tcc as a reference compiler for "make test" */
+            break;
+        case TCC_OPTION_shared:
+            x = TCC_OUTPUT_DLL;
+            goto set_output_type;
+        case TCC_OPTION_soname:
+            s->soname = tcc_strdup(optarg);
+            break;
+        case TCC_OPTION_o:
+            if (s->outfile) {
+                tcc_warning("multiple -o option");
+                tcc_free(s->outfile);
+            }
+            s->outfile = tcc_strdup(optarg);
+            break;
+        case TCC_OPTION_r:
+            /* generate a .o merging several output files */
+            s->option_r = 1;
+            x = TCC_OUTPUT_OBJ;
+            goto set_output_type;
+        case TCC_OPTION_isystem:
+            tcc_add_sysinclude_path(s, optarg);
+            break;
+	case TCC_OPTION_include:
+	    dynarray_add(&s->cmd_include_files,
+			 &s->nb_cmd_include_files, tcc_strdup(optarg));
+	    break;
+        case TCC_OPTION_nostdinc:
+            s->nostdinc = 1;
+            break;
+        case TCC_OPTION_nostdlib:
+            s->nostdlib = 1;
+            break;
+        case TCC_OPTION_run:
+#ifndef TCC_IS_NATIVE
+            tcc_error("-run is not available in a cross compiler");
+#endif
+            run = optarg;
+            x = TCC_OUTPUT_MEMORY;
+            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)
+                goto unsupported_option;
+            break;
+#ifdef TCC_TARGET_ARM
+        case TCC_OPTION_mfloat_abi:
+            /* tcc doesn't support soft float yet */
+            if (!strcmp(optarg, "softfp")) {
+                s->float_abi = ARM_SOFTFP_FLOAT;
+                tcc_undefine_symbol(s, "__ARM_PCS_VFP");
+            } else if (!strcmp(optarg, "hard"))
+                s->float_abi = ARM_HARD_FLOAT;
+            else
+                tcc_error("unsupported float abi '%s'", optarg);
+            break;
+#endif
+        case TCC_OPTION_m:
+            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)
+                goto unsupported_option;
+            break;
+        case TCC_OPTION_w:
+            s->warn_none = 1;
+            break;
+        case TCC_OPTION_rdynamic:
+            s->rdynamic = 1;
+            break;
+        case TCC_OPTION_Wl:
+            if (linker_arg.size)
+                --linker_arg.size, cstr_ccat(&linker_arg, ',');
+            cstr_cat(&linker_arg, optarg, 0);
+            if (tcc_set_linker(s, linker_arg.data))
+                cstr_free(&linker_arg);
+            break;
+	case TCC_OPTION_Wp:
+	    r = optarg;
+	    goto reparse;
+        case TCC_OPTION_E:
+            x = TCC_OUTPUT_PREPROCESS;
+            goto set_output_type;
+        case TCC_OPTION_P:
+            s->Pflag = atoi(optarg) + 1;
+            break;
+        case TCC_OPTION_MD:
+            s->gen_deps = 1;
+            break;
+        case TCC_OPTION_MF:
+            s->deps_outfile = tcc_strdup(optarg);
+            break;
+        case TCC_OPTION_dumpversion:
+            printf ("%s\n", TCC_VERSION);
+            exit(0);
+            break;
+        case TCC_OPTION_x:
+            if (*optarg == 'c')
+                s->filetype = AFF_TYPE_C;
+            else if (*optarg == 'a')
+                s->filetype = AFF_TYPE_ASMPP;
+            else if (*optarg == 'n')
+                s->filetype = AFF_TYPE_NONE;
+            else
+                tcc_warning("unsupported language '%s'", optarg);
+            break;
+        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:
+        case TCC_OPTION_s:
+            /* ignored */
+            break;
+        default:
+unsupported_option:
+            if (s->warn_unsupported)
+                tcc_warning("unsupported option '%s'", r);
+            break;
+        }
+    }
+    if (last_o > 0)
+        tcc_define_symbol(s, "__OPTIMIZE__", NULL);
+    if (linker_arg.size) {
+        r = linker_arg.data;
+        goto arg_err;
+    }
+    *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 void tcc_set_options(TCCState *s, const char *r)
+{
+    char **argv = NULL;
+    int argc = 0;
+    args_parser_make_argv(r, &argc, &argv);
+    tcc_parse_args(s, &argc, &argv, 0);
+    dynarray_reset(&argv, &argc);
+}
+
+PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time)
+{
+    if (total_time < 1)
+        total_time = 1;
     if (total_bytes < 1)
         total_bytes = 1;
-    printf("%d idents, %d lines, %d bytes, %0.3f s, %d 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,
-           tt, (int)(total_lines / tt),
-           total_bytes / tt / 1000000.0);
+           (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
 }