summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2024-02-11 13:13:13 +0100
committergrischka <grischka>2024-02-14 00:56:36 +0100
commita7cd016d713ce749f707f9e3793f56c13672e791 (patch)
treecbd54f1bb66ad3297a805ec4cb15b769c1b9fb2c
parent7b9f19eaab7e568a7c7a42725da812377a588f50 (diff)
tccrun: 'tcc_relocate()' twice no longer supported
- abort with notice when tcc_relocate() is called with the former two-step method - support backtrace & bcheck not only with tcc_run() but also for directly called functions from tcc_get_symbol(); enable witn 'tcc_set_options("-bt/-b");' - move struct rt_context and debug sections into compiled code for TCC_OUTPUT_MEMORY also - protect access (g_rc) with semaphore Also: - add armv7/aarch4/riscv64 github tests (qemu emulated) - win32/build-tcc.bat: build cross compiler only with -x
-rw-r--r--.github/workflows/build.yml54
-rw-r--r--Makefile3
-rwxr-xr-xconfigure4
-rw-r--r--lib/bt-exe.c59
-rw-r--r--lib/bt-log.c20
-rw-r--r--libtcc.c42
-rw-r--r--tcc.h48
-rw-r--r--tccdbg.c7
-rw-r--r--tccelf.c61
-rw-r--r--tccpe.c3
-rw-r--r--tccrun.c401
-rw-r--r--tests/Makefile2
-rw-r--r--win32/build-tcc.bat7
13 files changed, 416 insertions, 295 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 885b310..5fda5d9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,21 +8,21 @@ jobs:
test-x86_64-linux:
runs-on: ubuntu-20.04
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: make & test tcc
run: ./configure && make && make test -k
test-x86_64-osx:
runs-on: macos-11
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: make & test tcc
run: ./configure --config-codesign=no && make && make test -k
test-x86_64-win32:
runs-on: windows-2019
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: make & test tcc
shell: cmd
run: |
@@ -30,3 +30,51 @@ jobs:
set MSYSTEM=MINGW64
set CHERE_INVOKING=yes
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
+
+ test-armv7-linux:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v4
+ - uses: uraimo/run-on-arch-action@v2
+ with:
+ arch: armv7
+ distro: ubuntu20.04
+ githubToken: ${{ github.token }}
+ install: |
+ apt-get update -q -y
+ apt-get install -q -y gcc make
+ run: |
+ echo "::endgroup::" && echo "::endgroup::" # missing in 'run-on-arch-action'
+ ./configure && make && make test -k
+
+ test-aarch64-linux:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v4
+ - uses: uraimo/run-on-arch-action@v2
+ with:
+ arch: aarch64
+ distro: ubuntu20.04
+ githubToken: ${{ github.token }}
+ install: |
+ apt-get update -q -y
+ apt-get install -q -y gcc make
+ run: |
+ echo "::endgroup::" && echo "::endgroup::" # missing in 'run-on-arch-action'
+ ./configure && make && make test -k
+
+ test-riscv64-linux:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v4
+ - uses: uraimo/run-on-arch-action@v2
+ with:
+ arch: riscv64
+ distro: ubuntu20.04
+ githubToken: ${{ github.token }}
+ install: |
+ apt-get update -q -y
+ apt-get install -q -y gcc make
+ run: |
+ echo "::endgroup::" && echo "::endgroup::" # missing in 'run-on-arch-action'
+ ./configure && make && make test -k
diff --git a/Makefile b/Makefile
index e6404d5..652bf2d 100644
--- a/Makefile
+++ b/Makefile
@@ -152,8 +152,7 @@ TCC_X += riscv64 arm64-osx
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
# cross libtcc1.a targets to build
-LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
-LIBTCC1_X += riscv64 arm64-osx
+LIBTCC1_X = $(filter-out c67,$(TCC_X))
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
diff --git a/configure b/configure
index 1222396..06bb2d5 100755
--- a/configure
+++ b/configure
@@ -478,6 +478,10 @@ if test "$cpu" = "arm"; then
fi
fi
+if test -n "$dwarf"; then
+ confvars="$confvars dwarf=$dwarf"
+fi
+
# a final configuration tuning
if test "$cc_name" != "tcc"; then
OPT1="-Wdeclaration-after-statement -fno-strict-aliasing"
diff --git a/lib/bt-exe.c b/lib/bt-exe.c
index 3a2d02e..258ab0f 100644
--- a/lib/bt-exe.c
+++ b/lib/bt-exe.c
@@ -5,61 +5,56 @@
#define CONFIG_TCC_BACKTRACE_ONLY
#define ONE_SOURCE 1
#define pstrcpy tcc_pstrcpy
+#define TCC_SEM_IMPL 1
#include "../tccrun.c"
-int (*__rt_error)(void*, void*, const char *, va_list);
-__attribute__((weak)) void __bound_checking_lock(void);
-__attribute__((weak)) void __bound_checking_unlock(void);
-
#ifndef _WIN32
# define __declspec(n)
#endif
__declspec(dllexport)
-void __bt_init(rt_context *p, int num_callers)
+void __bt_init(rt_context *p, int is_exe)
{
__attribute__((weak)) int main();
__attribute__((weak)) void __bound_init(void*, int);
- struct rt_context *rc = &g_rtctxt;
- //fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
+
+ WAIT_SEM(&rt_sem);
+ //fprintf(stderr, "__bt_init %d %p %p %p\n", is_exe, p, p->stab_sym, p->bounds_start), fflush(stderr);
+
/* call __bound_init here due to redirection of sigaction */
/* needed to add global symbols */
- if (p->bounds_start) {
+ if (p->bounds_start)
__bound_init(p->bounds_start, -1);
- __bound_checking_lock();
- }
- if (num_callers) {
- memcpy(rc, p, offsetof(rt_context, next));
- rc->num_callers = num_callers - 1;
- rc->top_func = main;
- __rt_error = _rt_error;
+
+ /* add to chain */
+ p->next = g_rc, g_rc = p;
+ if (is_exe) {
+ /* we are the executable (not a dll) */
+ p->top_func = main;
set_exception_handler();
- } else {
- p->next = rc->next, rc->next = p;
}
- if (p->bounds_start)
- __bound_checking_unlock();
+ POST_SEM(&rt_sem);
}
__declspec(dllexport)
void __bt_exit(rt_context *p)
{
+ struct rt_context *rc, **pp;
__attribute__((weak)) void __bound_exit_dll(void*);
- struct rt_context *rc = &g_rtctxt;
- if (p->bounds_start) {
- __bound_exit_dll(p->bounds_start);
- __bound_checking_lock();
- }
- while (rc) {
- if (rc->next == p) {
- rc->next = rc->next->next;
- break;
- }
- rc = rc->next;
- }
+ WAIT_SEM(&rt_sem);
+ //fprintf(stderr, "__bt_exit %d %p\n", !!p->top_func, p);
+
if (p->bounds_start)
- __bound_checking_unlock();
+ __bound_exit_dll(p->bounds_start);
+
+ /* remove from chain */
+ for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
+ if (rc == p) {
+ *pp = rc->next;
+ break;
+ }
+ POST_SEM(&rt_sem);
}
/* copy a string and truncate it. */
diff --git a/lib/bt-log.c b/lib/bt-log.c
index aaa47ee..05f7c40 100644
--- a/lib/bt-log.c
+++ b/lib/bt-log.c
@@ -4,8 +4,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
-
-int (*__rt_error)(void*, void*, const char *, va_list);
+#undef __attribute__
#ifdef _WIN32
# define DLL_EXPORT __declspec(dllexport)
@@ -19,16 +18,25 @@ int (*__rt_error)(void*, void*, const char *, va_list);
#pragma GCC diagnostic ignored "-Wframe-address"
#endif
+typedef struct rt_frame
+{
+ void *ip, *fp, *sp;
+} rt_frame;
+
+__attribute__((weak))
+int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
+
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
{
va_list ap;
int ret;
- if (__rt_error) {
- void *fp = __builtin_frame_address(1);
- void *ip = __builtin_return_address(0);
+ if (_rt_error) {
+ rt_frame f;
+ f.fp = __builtin_frame_address(1);
+ f.ip = __builtin_return_address(0);
va_start(ap, fmt);
- ret = __rt_error(fp, ip, fmt, ap);
+ ret = _rt_error(&f, "", fmt, ap);
va_end(ap);
} else {
const char *p, *nl = "\n";
diff --git a/libtcc.c b/libtcc.c
index 2ca1ddb..a318ea7 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -60,6 +60,7 @@
#endif
#endif /* ONE_SOURCE */
+#define TCC_SEM_IMPL 1
#include "tcc.h"
/********************************************************/
@@ -110,7 +111,7 @@ static inline char *config_tccdir_w32(char *path)
#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH))
#endif
-#ifdef TCC_TARGET_PE
+#ifdef TCC_IS_NATIVE
static void tcc_add_systemdir(TCCState *s)
{
char buf[1000];
@@ -121,44 +122,6 @@ static void tcc_add_systemdir(TCCState *s)
#endif
/********************************************************/
-#if CONFIG_TCC_SEMLOCK
-#if defined _WIN32
-ST_FUNC void wait_sem(TCCSem *p)
-{
- if (!p->init)
- InitializeCriticalSection(&p->cr), p->init = 1;
- EnterCriticalSection(&p->cr);
-}
-ST_FUNC void post_sem(TCCSem *p)
-{
- LeaveCriticalSection(&p->cr);
-}
-#elif defined __APPLE__
-/* Half-compatible MacOS doesn't have non-shared (process local)
- semaphores. Use the dispatch framework for lightweight locks. */
-ST_FUNC void wait_sem(TCCSem *p)
-{
- if (!p->init)
- p->sem = dispatch_semaphore_create(1), p->init = 1;
- dispatch_semaphore_wait(p->sem, DISPATCH_TIME_FOREVER);
-}
-ST_FUNC void post_sem(TCCSem *p)
-{
- dispatch_semaphore_signal(p->sem);
-}
-#else
-ST_FUNC void wait_sem(TCCSem *p)
-{
- if (!p->init)
- sem_init(&p->sem, 0, 1), p->init = 1;
- while (sem_wait(&p->sem) < 0 && errno == EINTR);
-}
-ST_FUNC void post_sem(TCCSem *p)
-{
- sem_post(&p->sem);
-}
-#endif
-#endif
PUB_FUNC void tcc_enter_state(TCCState *s1)
{
@@ -1959,6 +1922,7 @@ dorun:
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
s->rt_num_callers = atoi(optarg); /* zero = default (6) */
+ goto enable_backtrace;
enable_backtrace:
s->do_backtrace = 1;
s->do_debug = s->do_debug ? s->do_debug : 1;
diff --git a/tcc.h b/tcc.h
index 28a9d3e..837dc6e 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1853,11 +1853,6 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
#define dwarf_str_section s1->dwarf_str_section
#define dwarf_line_str_section s1->dwarf_line_str_section
-/* default dwarf version for "-g". use 0 to emit stab debug infos */
-#ifndef DWARF_VERSION
-# define DWARF_VERSION 0
-#endif
-
/* default dwarf version for "-gdwarf" */
#ifdef TCC_TARGET_MACHO
# define DEFAULT_DWARF_VERSION 2
@@ -1865,6 +1860,11 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
# define DEFAULT_DWARF_VERSION 5
#endif
+/* default dwarf version for "-g". use 0 to emit stab debug infos */
+#ifndef DWARF_VERSION
+# define DWARF_VERSION 0 //DEFAULT_DWARF_VERSION
+#endif
+
#if defined TCC_TARGET_PE
# define R_DATA_32DW 'Z' /* fake code to avoid DLL relocs */
#elif defined TCC_TARGET_X86_64
@@ -1946,3 +1946,41 @@ PUB_FUNC void tcc_exit_state(TCCState *s1);
# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
# define _tcc_error use_tcc_error_noabort
#endif
+
+#if CONFIG_TCC_SEMLOCK && TCC_SEM_IMPL
+#undef TCC_SEM_IMPL
+#if defined _WIN32
+ST_FUNC void wait_sem(TCCSem *p)
+{
+ if (!p->init)
+ InitializeCriticalSection(&p->cr), p->init = 1;
+ EnterCriticalSection(&p->cr);
+}
+ST_FUNC void post_sem(TCCSem *p)
+{
+ LeaveCriticalSection(&p->cr);
+}
+#elif defined __APPLE__
+ST_FUNC void wait_sem(TCCSem *p)
+{
+ if (!p->init)
+ p->sem = dispatch_semaphore_create(1), p->init = 1;
+ dispatch_semaphore_wait(p->sem, DISPATCH_TIME_FOREVER);
+}
+ST_FUNC void post_sem(TCCSem *p)
+{
+ dispatch_semaphore_signal(p->sem);
+}
+#else
+ST_FUNC void wait_sem(TCCSem *p)
+{
+ if (!p->init)
+ sem_init(&p->sem, 0, 1), p->init = 1;
+ while (sem_wait(&p->sem) < 0 && errno == EINTR);
+}
+ST_INLN void post_sem(TCCSem *p)
+{
+ sem_post(&p->sem);
+}
+#endif
+#endif
diff --git a/tccdbg.c b/tccdbg.c
index 47393a4..a2c6b56 100644
--- a/tccdbg.c
+++ b/tccdbg.c
@@ -416,12 +416,15 @@ ST_FUNC void tcc_debug_new(TCCState *s1)
int shf = 0;
if (!s1->dState)
s1->dState = tcc_mallocz(sizeof *s1->dState);
+
#ifdef CONFIG_TCC_BACKTRACE
/* include stab info with standalone backtrace support */
- if (s1->do_backtrace
- && (s1->output_type & (TCC_OUTPUT_EXE | TCC_OUTPUT_DLL)))
+ if (s1->do_debug && s1->output_type == TCC_OUTPUT_MEMORY)
+ s1->do_backtrace = 1;
+ if (s1->do_backtrace)
shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX
#endif
+
if (s1->dwarf) {
s1->dwlo = s1->nb_sections;
dwarf_info_section =
diff --git a/tccelf.c b/tccelf.c
index 1b06726..2ccf981 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -139,21 +139,6 @@ ST_FUNC void tccelf_delete(TCCState *s1)
tcc_free(s1->sym_attrs);
symtab_section = NULL; /* for tccrun.c:rt_printline() */
-
- /* free any loaded DLLs */
-#ifdef TCC_IS_NATIVE
- for ( i = 0; i < s1->nb_loaded_dlls; i++) {
- DLLReference *ref = s1->loaded_dlls[i];
- if ( ref->handle )
-# ifdef _WIN32
- FreeLibrary((HMODULE)ref->handle);
-# else
- dlclose(ref->handle);
-# endif
- }
-#endif
- /* free loaded dlls array */
- dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
}
/* save section data state */
@@ -1582,14 +1567,15 @@ static void put_ptr(TCCState *s1, Section *s, int offs)
ST_FUNC void tcc_add_btstub(TCCState *s1)
{
Section *s;
- int n, o;
+ int n, o, *p;
CString cstr;
+ const char *__rt_info = &"___rt_info"[!s1->leading_underscore];
s = data_section;
/* Align to PTR_SIZE */
section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1));
o = s->data_offset;
- /* create (part of) a struct rt_context (see tccrun.c) */
+ /* create a struct rt_context (see tccrun.c) */
if (s1->dwarf) {
put_ptr(s1, dwarf_line_section, 0);
put_ptr(s1, dwarf_line_section, -1);
@@ -1604,18 +1590,23 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
put_ptr(s1, stab_section, -1);
put_ptr(s1, stab_section->link, 0);
}
- *(addr_t *)section_ptr_add(s, PTR_SIZE) = s1->dwarf;
+
/* skip esym_start/esym_end/elf_str (not loaded) */
section_ptr_add(s, 3 * PTR_SIZE);
- /* prog_base : local nameless symbol with offset 0 at SHN_ABS */
- put_ptr(s1, NULL, 0);
+
+ if (s1->output_type == TCC_OUTPUT_MEMORY && 0 == s1->dwarf) {
+ put_ptr(s1, text_section, 0);
+ } else {
+ /* prog_base : local nameless symbol with offset 0 at SHN_ABS */
+ put_ptr(s1, NULL, 0);
#if defined TCC_TARGET_MACHO
- /* adjust for __PAGEZERO */
- if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE)
- write64le(data_section->data + data_section->data_offset - PTR_SIZE,
- (uint64_t)1 << 32);
+ /* adjust for __PAGEZERO */
+ if (s1->dwarf == 0 && s1->output_type == TCC_OUTPUT_EXE)
+ write64le(data_section->data + data_section->data_offset - PTR_SIZE,
+ (uint64_t)1 << 32);
#endif
- n = 2 * PTR_SIZE;
+ }
+ n = 4 * PTR_SIZE;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
put_ptr(s1, bounds_section, 0);
@@ -1623,6 +1614,18 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
}
#endif
section_ptr_add(s, n);
+ p = section_ptr_add(s, 2 * sizeof (int));
+ p[0] = s1->rt_num_callers;
+ p[1] = s1->dwarf;
+
+ if (s->data_offset - o != 11 * PTR_SIZE + 2 * sizeof (int))
+ exit(99);
+
+ if (s1->output_type == TCC_OUTPUT_MEMORY) {
+ set_global_sym(s1, __rt_info, s, o);
+ return;
+ }
+
cstr_new(&cstr);
cstr_printf(&cstr,
"extern void __bt_init(),__bt_exit(),__bt_init_dll();"
@@ -1637,14 +1640,14 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
#endif
#endif
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
- s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
+ s1->output_type != TCC_OUTPUT_DLL);
/* In case dlcose is called by application */
cstr_printf(&cstr,
"__attribute__((destructor)) static void __bt_exit_rt(){"
"__bt_exit(__rt_info);}");
tcc_compile_string_no_debug(s1, cstr.data);
cstr_free(&cstr);
- set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o);
+ set_local_sym(s1, __rt_info, s, o);
}
#endif /* def CONFIG_TCC_BACKTRACE */
@@ -1777,8 +1780,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
tcc_add_support(s1, "bt-exe.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
- if (s1->output_type != TCC_OUTPUT_MEMORY)
- tcc_add_btstub(s1);
+ tcc_add_btstub(s1);
+ lpthread = 1;
}
#endif
if (lpthread)
diff --git a/tccpe.c b/tccpe.c
index 7695c3c..936f146 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1963,8 +1963,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
tcc_add_support(s1, "bt-dll.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
- if (s1->output_type != TCC_OUTPUT_MEMORY)
- tcc_add_btstub(s1);
+ tcc_add_btstub(s1);
}
#endif
diff --git a/tccrun.c b/tccrun.c
index 75ca1a4..ff8849e 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -23,52 +23,69 @@
/* only native compiler supports -run */
#ifdef TCC_IS_NATIVE
+#ifdef CONFIG_TCC_BACKTRACE
typedef struct rt_context
{
-#ifdef CONFIG_TCC_BACKTRACE
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */
union {
struct {
- Stab_Sym *stab_sym, *stab_sym_end;
- char *stab_str;
+ Stab_Sym *stab_sym;
+ Stab_Sym *stab_sym_end;
+ char *stab_str;
};
struct {
- unsigned char *dwarf_line, *dwarf_line_end, *dwarf_line_str;
+ unsigned char *dwarf_line;
+ unsigned char *dwarf_line_end;
+ unsigned char *dwarf_line_str;
};
};
- addr_t dwarf;
- ElfW(Sym) *esym_start, *esym_end;
+ ElfW(Sym) *esym_start;
+ ElfW(Sym) *esym_end;
char *elf_str;
+
addr_t prog_base;
void *bounds_start;
+ void *top_func;
+ TCCState *s1;
struct rt_context *next;
- /* <-- */
+
int num_callers;
+ int dwarf;
+ /* <-- */
+} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
+
+typedef struct rt_frame
+{
addr_t ip, fp, sp;
- void *top_func;
-#endif
- jmp_buf jb;
- int do_jmp;
-# define NR_AT_EXIT 32
- int nr_exit;
- void *exitfunc[NR_AT_EXIT];
- void *exitarg[NR_AT_EXIT];
-} rt_context;
-
-static rt_context g_rtctxt;
+} rt_frame;
+
+/* linked list of rt_contexts */
+static rt_context *g_rc;
+/* semaphore to protect it */
+TCC_SEM(static rt_sem);
+static int signal_set;
+static void set_exception_handler(void);
+
+int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
+void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
+void rt_post_sem(void) { POST_SEM(&rt_sem); }
+#endif /* def CONFIG_TCC_BACKTRACE */
+
+/* handle exit/atexit for tcc_run() -- thread-unsafe */
+static jmp_buf rt_jb;
+static int rt_do_jmp;
+static int rt_nr_exit;
+static void *rt_exitfunc[32];
+static void *rt_exitarg[32];
+
static void rt_exit(int code)
{
- rt_context *rc = &g_rtctxt;
- if (rc->do_jmp)
- longjmp(rc->jb, code ? code : 256);
+ if (rt_do_jmp)
+ longjmp(rt_jb, code ? code : 256);
exit(code);
}
-#ifdef CONFIG_TCC_BACKTRACE
-static void set_exception_handler(void);
-static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
-#endif /* CONFIG_TCC_BACKTRACE */
-
+/* ------------------------------------------------------------- */
/* defined when included from lib/bt-exe.c */
#ifndef CONFIG_TCC_BACKTRACE_ONLY
@@ -84,22 +101,60 @@ static void *win64_add_function_table(TCCState *s1);
static void win64_del_function_table(void *);
#endif
-/* ------------------------------------------------------------- */
-/* Do all relocations (needed before using tcc_get_symbol())
- Returns -1 on error. */
+static void bt_link(TCCState *s1)
+{
+#ifdef CONFIG_TCC_BACKTRACE
+ rt_context *rc;
+ void *p;
+
+ if (!s1->do_backtrace)
+ return;
+ rc = tcc_get_symbol(s1, "__rt_info");
+ if (!rc)
+ return;
+ rt_wait_sem();
+ rc->next = g_rc, g_rc = rc, rc->s1 = s1;
+ rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
+ rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
+ rc->elf_str = (char *)symtab_section->link->data;
+ rc->top_func = tcc_get_symbol(s1, "main");
+ if (PTR_SIZE == 8 && !s1->dwarf)
+ rc->prog_base &= 0xffffffff00000000ULL;
+#ifdef CONFIG_TCC_BCHECK
+ if (s1->do_bounds_check) {
+ if ((p = tcc_get_symbol(s1, "__bound_init")))
+ ((void(*)(void*,int))p)(rc->bounds_start, 1);
+ }
+#endif
+ rt_post_sem();
+ if (0 == signal_set)
+ set_exception_handler(), signal_set = 1;
+#endif
+}
-LIBTCCAPI int tcc_relocate(TCCState *s1)
+static void bt_unlink(TCCState *s1)
{
- void *ptr;
- int size;
- unsigned ptr_diff = 0;
+#ifdef CONFIG_TCC_BACKTRACE
+ rt_context *rc, **pp;
+ rt_wait_sem();
+ for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
+ if (rc->s1 == s1) {
+ *pp = rc->next;
+ break;
+ }
+ rt_post_sem();
+#endif
+}
- size = tcc_relocate_ex(s1, NULL, 0);
- if (size < 0)
- return -1;
+#if !_WIN32 && !__APPLE__
+//#define HAVE_SELINUX 1
+#endif
-#ifdef HAVE_SELINUX
+static int rt_mem(TCCState *s1, int size)
{
+ void *ptr;
+ int ptr_diff = 0;
+#ifdef HAVE_SELINUX
/* Using mmap instead of malloc */
void *prw;
char tmpfname[] = "/tmp/.tccrunXXXXXX";
@@ -115,21 +170,68 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
return tcc_error_noabort("tccrun: could not map memory");
ptr_diff = (char*)prw - (char*)ptr; /* = size; */
//printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
-}
#else
ptr = tcc_malloc(size);
#endif
s1->run_ptr = ptr;
s1->run_size = size;
- tcc_relocate_ex(s1, ptr, ptr_diff);
- return 0;
+ return ptr_diff;
+}
+
+/* ------------------------------------------------------------- */
+/* Do all relocations (needed before using tcc_get_symbol())
+ Returns -1 on error. */
+
+LIBTCCAPI int tcc_relocate(TCCState *s1)
+{
+ int size, ret, ptr_diff;
+
+ if (s1->run_ptr)
+ exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
+
+#ifdef CONFIG_TCC_BACKTRACE
+ /* for bt-log.c (but not when 'tcc -bt -run tcc.c') */
+ if (s1->do_backtrace && !tcc_get_symbol(s1, "_rt_error"))
+ tcc_add_symbol(s1, "_rt_error", _rt_error);
+#endif
+
+ size = tcc_relocate_ex(s1, NULL, 0);
+ if (size < 0)
+ return -1;
+ ptr_diff = rt_mem(s1, size);
+ if (ptr_diff < 0)
+ return -1;
+ ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff);
+ if (ret == 0)
+ bt_link(s1);
+ return ret;
}
ST_FUNC void tcc_run_free(TCCState *s1)
{
- void *ptr = s1->run_ptr;
- unsigned size = s1->run_size;
+ unsigned size;
+ void *ptr;
+ int i;
+ /* free any loaded DLLs */
+ for ( i = 0; i < s1->nb_loaded_dlls; i++) {
+ DLLReference *ref = s1->loaded_dlls[i];
+ if ( ref->handle )
+#ifdef _WIN32
+ FreeLibrary((HMODULE)ref->handle);
+#else
+ dlclose(ref->handle);
+#endif
+ }
+ /* free loaded dlls array */
+ dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
+
+ /* unmap or unprotect and free memory */
+ ptr = s1->run_ptr;
+ if (NULL == ptr)
+ return;
+ bt_unlink(s1);
+ size = s1->run_size;
#ifdef HAVE_SELINUX
munmap(ptr, size * 2);
#else
@@ -153,18 +255,16 @@ static void run_cdtors(TCCState *s1, const char *start, const char *end,
static void run_on_exit(int ret)
{
- rt_context *rc = &g_rtctxt;
- int n = rc->nr_exit;
+ int n = rt_nr_exit;
while (n)
- --n, ((void(*)(int,void*))rc->exitfunc[n])(ret, rc->exitarg[n]);
+ --n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
}
static int rt_on_exit(void *function, void *arg)
{
- rt_context *rc = &g_rtctxt;
- if (rc->nr_exit < NR_AT_EXIT) {
- rc->exitfunc[rc->nr_exit] = function;
- rc->exitarg[rc->nr_exit++] = arg;
+ if (rt_nr_exit < countof(rt_exitfunc)) {
+ rt_exitfunc[rt_nr_exit] = function;
+ rt_exitarg[rt_nr_exit++] = arg;
return 0;
}
return 1;
@@ -179,7 +279,6 @@ static int rt_atexit(void *function)
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
int (*prog_main)(int, char **, char **), ret;
- rt_context *rc = &g_rtctxt;
#if defined(__APPLE__) || defined(__FreeBSD__)
char **envp = NULL;
@@ -204,58 +303,15 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
if ((addr_t)-1 == (addr_t)prog_main)
return -1;
- memset(rc, 0, sizeof *rc);
- rc->do_jmp = 1;
-
-#ifdef CONFIG_TCC_BACKTRACE
- if (s1->do_debug) {
- void *p;
- if (s1->dwarf) {
- rc->dwarf_line = dwarf_line_section->data;
- rc->dwarf_line_end = dwarf_line_section->data + dwarf_line_section->data_offset;
- if (dwarf_line_str_section)
- rc->dwarf_line_str = dwarf_line_str_section->data;
- }
- else
- {
- rc->stab_sym = (Stab_Sym *)stab_section->data;
- rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
- rc->stab_str = (char *)stab_section->link->data;
- }
- rc->dwarf = s1->dwarf;
- rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
- rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
- rc->elf_str = (char *)symtab_section->link->data;
-#if PTR_SIZE == 8
- rc->prog_base = text_section->sh_addr & 0xffffffff00000000ULL;
-#if defined TCC_TARGET_MACHO
- if (s1->dwarf)
- rc->prog_base = (addr_t) -1;
-#else
-#endif
-#endif
- rc->top_func = tcc_get_symbol(s1, "main");
- rc->num_callers = s1->rt_num_callers;
- if ((p = tcc_get_symbol(s1, "__rt_error")))
- *(void**)p = _rt_error;
-#ifdef CONFIG_TCC_BCHECK
- if (s1->do_bounds_check) {
- rc->bounds_start = (void*)bounds_section->sh_addr;
- if ((p = tcc_get_symbol(s1, "__bound_init")))
- ((void(*)(void*,int))p)(rc->bounds_start, 1);
- }
-#endif
- set_exception_handler();
- }
-#endif
-
errno = 0; /* clean errno value */
fflush(stdout);
fflush(stderr);
+ rt_do_jmp = 1;
+ rt_nr_exit = 0;
/* These aren't C symbols, so don't need leading underscore handling. */
run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
- ret = setjmp(rc->jb);
+ ret = setjmp(rt_jb);
if (0 == ret)
ret = prog_main(argc, argv, envp);
else if (256 == ret)
@@ -276,7 +332,7 @@ static void cleanup_symbols(TCCState *s1)
/* reset symtab */
s->data_offset = s->link->data_offset = s->hash->data_offset = 0;
init_symtab(s);
- /* re-add symbols except STB_LOCAL */
+ /* add global symbols again */
for (sym_index = 1; sym_index < end_sym; ++sym_index) {
ElfW(Sym) *sym = &((ElfW(Sym) *)s->data)[sym_index];
const char *name = (char *)s->link->data + sym->st_name;
@@ -295,14 +351,10 @@ static void cleanup_sections(TCCState *s1)
do {
for (i = --f; i < p->nb_secs; i++) {
Section *s = p->secs[i];
- if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash
- || 0 == memcmp(s->name, ".stab", 5)
- || 0 == memcmp(s->name, ".debug_", 7)) {
+ if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
} else {
- free_section(s);
- if (0 == (s->sh_flags & SHF_ALLOC))
- tcc_free(s), p->secs[i] = NULL;
+ free_section(s), tcc_free(s), p->secs[i] = NULL;
}
}
} while (++p, f);
@@ -335,8 +387,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
resolve_common_syms(s1);
build_got_entries(s1, 0);
#endif
- if (s1->nb_errors)
- return -1;
}
offset = copy = 0;
@@ -349,6 +399,8 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
#endif
redo:
+ if (s1->nb_errors)
+ return -1;
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
n = 0; addr = 0;
for(i = 1; i < s1->nb_sections; i++) {
@@ -376,7 +428,6 @@ redo:
if (s == s1->uw_pdata)
s1->run_function_table = win64_add_function_table(s1);
#endif
- free_section(s);
continue;
}
@@ -423,11 +474,18 @@ redo:
#endif
if (protect_pages((void*)addr, n, f) < 0)
return tcc_error_noabort(
- "mprotect failed "
- "(did you mean to configure --with-selinux?)");
+ "mprotect failed (did you mean to configure --with-selinux?)");
}
}
+ if (0 == mem) {
+ offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
+#ifndef HAVE_SELINUX
+ offset += PAGESIZE; /* extra space to align malloc memory start */
+#endif
+ return offset;
+ }
+
if (copy) {
/* remove local symbols and free sections except symtab */
cleanup_symbols(s1);
@@ -437,17 +495,7 @@ redo:
/* relocate symbols */
relocate_syms(s1, s1->symtab, !(s1->nostdlib));
- if (s1->nb_errors)
- return -1;
-
- if (0 == mem) {
- offset = (offset + (PAGESIZE-1)) & ~(PAGESIZE-1);
-#ifndef HAVE_SELINUX
- offset += PAGESIZE; /* extra space to align malloc memory start */
-#endif
- return offset;
- }
-
+ /* relocate sections */
#ifdef TCC_TARGET_PE
s1->pe_imagebase = mem;
#else
@@ -578,6 +626,8 @@ next:
last_pc = (addr_t)-1;
last_line_num = 1;
last_incl_index = 0;
+ if (NULL == rc)
+ goto found;
for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
str = rc->stab_str + sym->n_strx;
@@ -658,14 +708,16 @@ next:
func_name[0] = '\0';
func_addr = 0;
last_incl_index = 0;
+
/* we try symtab symbols (no line number info) */
p = rt_elfsym(rc, wanted_pc, &func_addr);
if (p) {
pstrcpy(func_name, sizeof func_name, p);
goto found;
}
- if ((rc = rc->next))
- goto next;
+ rc = rc->next;
+ goto next;
+
found:
i = last_incl_index;
if (i > 0) {
@@ -799,6 +851,11 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
char *function;
next:
+ filename = NULL;
+ func_addr = 0;
+ if (NULL == rc)
+ goto found;
+
ln = rc->dwarf_line;
while (ln < rc->dwarf_line_end) {
dir_size = 0;
@@ -953,8 +1010,7 @@ check_pc:
pc = dwarf_read_8(cp, end);
#endif
#if defined TCC_TARGET_MACHO
- if (rc->prog_base != (addr_t) -1)
- pc += rc->prog_base;
+ pc += rc->prog_base;
#endif
opindex = 0;
break;
@@ -1036,8 +1092,9 @@ next_line:
function = rt_elfsym(rc, wanted_pc, &func_addr);
if (function)
goto found;
- if ((rc = rc->next))
- goto next;
+ rc = rc->next;
+ goto next;
+
found:
if (filename) {
if (skip[0] && strstr(filename, skip))
@@ -1051,25 +1108,17 @@ found:
}
/* ------------------------------------------------------------- */
-static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
+static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
-static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
+int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap)
{
- rt_context *rc = &g_rtctxt;
+ rt_context *rc;
addr_t pc = 0;
char skip[100];
int i, level, ret, n, one;
- const char *a, *b, *msg;
-
- if (fp) {
- /* we're called from tcc_backtrace. */
- rc->fp = (addr_t)fp;
- rc->ip = (addr_t)ip;
- msg = "";
- } else {
- /* we're called from signal/exception handler */
- msg = "RUNTIME ERROR: ";
- }
+ const char *a, *b;
+ addr_t (*printline)(rt_context*, addr_t, const char*, const char*);
+ addr_t top_func = 0;
skip[0] = 0;
/* If fmt is like "^file.c^..." then skip calls from 'file.c' */
@@ -1082,15 +1131,22 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
if (fmt[0] == '\001')
++fmt, one = 1;
- n = rc->num_callers ? rc->num_callers : 6;
+ rt_wait_sem();
+ rc = g_rc;
+ printline = rt_printline, n = 6;
+ if (rc) {
+ if (rc->dwarf)
+ printline = rt_printline_dwarf;
+ if (rc->num_callers)
+ n = rc->num_callers;
+ top_func = (addr_t)rc->top_func;
+ }
+
for (i = level = 0; level < n; i++) {
- ret = rt_get_caller_pc(&pc, rc, i);
+ ret = rt_get_caller_pc(&pc, f, i);
a = "%s";
if (ret != -1) {
- if (rc->dwarf)
- pc = rt_printline_dwarf(rc, pc, level ? "by" : "at", skip);
- else
- pc = rt_printline(rc, pc, level ? "by" : "at", skip);
+ pc = printline(rc, pc, level ? "by" : "at", skip);
if (pc == (addr_t)-1)
continue;
a = ": %s";
@@ -1103,22 +1159,22 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
if (one)
break;
rt_printf("\n");
- if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
+ if (ret == -1 || (pc == top_func && pc))
break;
++level;
}
- rc->ip = rc->fp = 0;
+ rt_post_sem();
return 0;
}
/* emit a run time error at position 'pc' */
-static int rt_error(const char *fmt, ...)
+static int rt_error(rt_frame *f, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
- ret = _rt_error(0, 0, fmt, ap);
+ ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap);
va_end(ap);
return ret;
}
@@ -1135,7 +1191,7 @@ static int rt_error(const char *fmt, ...)
#endif
/* translate from ucontext_t* to internal rt_context * */
-static void rt_getcontext(ucontext_t *uc, rt_context *rc)
+static void rt_getcontext(ucontext_t *uc, rt_frame *rc)
{
#if defined _WIN64
rc->ip = uc->Rip;
@@ -1228,33 +1284,33 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
/* signal handler for fatal errors */
static void sig_error(int signum, siginfo_t *siginf, void *puc)
{
- rt_context *rc = &g_rtctxt;
- rt_getcontext(puc, rc);
+ rt_frame f;
+ rt_getcontext(puc, &f);
switch(signum) {
case SIGFPE:
switch(siginf->si_code) {
case FPE_INTDIV:
case FPE_FLTDIV:
- rt_error("division by zero");
+ rt_error(&f, "division by zero");
break;
default:
- rt_error("floating point exception");
+ rt_error(&f, "floating point exception");
break;
}
break;
case SIGBUS:
case SIGSEGV:
- rt_error("invalid memory access");
+ rt_error(&f, "invalid memory access");
break;
case SIGILL:
- rt_error("illegal instruction");
+ rt_error(&f, "illegal instruction");
break;
case SIGABRT:
- rt_error("abort() called");
+ rt_error(&f, "abort() called");
break;
default:
- rt_error("caught signal %d", signum);
+ rt_error(&f, "caught signal %d", signum);
break;
}
rt_exit(255);
@@ -1301,30 +1357,31 @@ static void set_exception_handler(void)
/* signal handler for fatal errors */
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
- rt_context *rc = &g_rtctxt;
+ rt_frame f;
unsigned code;
- rt_getcontext(ex_info->ContextRecord, rc);
+
+ rt_getcontext(ex_info->ContextRecord, &f);
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
- rt_error("invalid memory access");
+ rt_error(&f, "invalid memory access");
break;
case EXCEPTION_STACK_OVERFLOW:
- rt_error("stack overflow");
+ rt_error(&f, "stack overflow");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
- rt_error("division by zero");
+ rt_error(&f, "division by zero");
break;
case EXCEPTION_BREAKPOINT:
case EXCEPTION_SINGLE_STEP:
- rc->ip = *(addr_t*)rc->sp;
- rt_error("breakpoint/single-step exception:");
+ f.ip = *(addr_t*)f.sp;
+ rt_error(&f, "breakpoint/single-step exception:");
return EXCEPTION_CONTINUE_SEARCH;
default:
- rt_error("caught exception %08x", code);
+ rt_error(&f, "caught exception %08x", code);
break;
}
- if (rc->do_jmp)
+ if (rt_do_jmp)
rt_exit(255);
return EXCEPTION_EXECUTE_HANDLER;
}
@@ -1340,7 +1397,7 @@ static void set_exception_handler(void)
/* ------------------------------------------------------------- */
/* return the PC at frame level 'level'. Return negative if not found */
#if defined(__i386__) || defined(__x86_64__)
-static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{
addr_t ip, fp;
if (level == 0) {
@@ -1364,7 +1421,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
}
#elif defined(__arm__)
-static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{
/* XXX: only supports linux/bsd */
#if !defined(__linux__) && \
@@ -1384,7 +1441,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
}
#elif defined(__aarch64__)
-static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{
if (level == 0) {
*paddr = rc->ip;
@@ -1398,7 +1455,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
}
#elif defined(__riscv)
-static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{
if (level == 0) {
*paddr = rc->ip;
@@ -1415,7 +1472,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
#else
#warning add arch specific rt_get_caller_pc()
-static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
+static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
{
return -1;
}
diff --git a/tests/Makefile b/tests/Makefile
index a46c852..f5b91ad 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -76,6 +76,8 @@ DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
endif
all test :
+ @echo ------------ version ------------
+ @$(TCC_LOCAL) -v
@$(MAKE) --no-print-directory -s clean
@$(MAKE) --no-print-directory -s -r $(TESTS)
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index 147823e..6b49aed 100644
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -10,7 +10,7 @@ set /p VERSION= < ..\VERSION
set TCCDIR=
set BINDIR=
set DOC=no
-set EXES_ONLY=no
+set XCC=no
goto :a0
:a2
shift
@@ -27,7 +27,7 @@ if (%1)==(-v) set VERSION=%~2&& goto :a2
if (%1)==(-i) set TCCDIR=%2&& goto :a2
if (%1)==(-b) set BINDIR=%2&& goto :a2
if (%1)==(-d) set DOC=yes&& goto :a3
-if (%1)==(-x) set EXES_ONLY=yes&& goto :a3
+if (%1)==(-x) set XCC=yes&& goto :a3
if (%1)==() goto :p1
:usage
echo usage: build-tcc.bat [ options ... ]
@@ -39,7 +39,7 @@ echo -v "version" set tcc version
echo -i tccdir install tcc into tccdir
echo -b bindir but install tcc.exe and libtcc.dll into bindir
echo -d create tcc-doc.html too (needs makeinfo)
-echo -x just create the executables
+echo -x build the cross compiler too
echo -clean delete all previously produced files and directories
exit /B 1
@@ -144,6 +144,7 @@ for %%f in (*tcc.exe *tcc.dll) do @del %%f
%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL
@if errorlevel 1 goto :the_end
%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
+if not _%XCC%_==_yes_ goto :compiler_done
%CC% -o %PX%-tcc.exe ..\tcc.c %DX%
:compiler_done
@if (%EXES_ONLY%)==(yes) goto :files_done