aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2009-12-19 22:22:43 +0100
committergrischka <grischka>2009-12-19 22:22:43 +0100
commit7fa712e00c5221d9373e8f8fa073e9e6fa064da1 (patch)
tree21c5acbfcb4ddaa6d61d30fe79cfaece3ff7b5d9
parent8bbde91f62291cb0383c2406ae6123be903c944b (diff)
downloadtinycc-7fa712e00c5221d9373e8f8fa073e9e6fa064da1.tar.gz
tinycc-7fa712e00c5221d9373e8f8fa073e9e6fa064da1.tar.bz2
win32: enable bounds checker & exception handler
exception handler borrowed from k1w1. Thanks.
-rw-r--r--Makefile7
-rw-r--r--i386-gen.c6
-rw-r--r--lib/bcheck.c43
-rw-r--r--libtcc.c8
-rw-r--r--tcc.h11
-rw-r--r--tccelf.c75
-rw-r--r--tccgen.c13
-rw-r--r--tccpe.c6
-rw-r--r--tccrun.c563
-rw-r--r--tcctok.h4
-rw-r--r--win32/build-tcc.bat16
11 files changed, 421 insertions, 331 deletions
diff --git a/Makefile b/Makefile
index e6dba91..08ef48a 100644
--- a/Makefile
+++ b/Makefile
@@ -78,7 +78,7 @@ ARM_CROSS = arm-tcc-fpa$(EXESUF) arm-tcc-fpa-ld$(EXESUF) \
arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF)
C67_CROSS = c67-tcc$(EXESUF)
-CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c \
+CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c \
tcc.h config.h libtcc.h tcctok.h
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
@@ -180,7 +180,7 @@ VPATH+=lib
ifdef CONFIG_WIN32
# for windows, we must use TCC because we generate ELF objects
-LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
+LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o bcheck.o
LIBTCC1_CC=./tcc.exe -Bwin32 -Iinclude $(NATIVE_TARGET)
VPATH+=win32/lib
endif
@@ -193,9 +193,6 @@ endif
libtcc1.a: $(LIBTCC1_OBJS)
$(AR) rcs $@ $^
-bcheck.o: bcheck.c
- $(CC) -o $@ -c $< -O2 -Wall
-
# install
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
INSTALL=install
diff --git a/i386-gen.c b/i386-gen.c
index bd53303..161be93 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -87,8 +87,10 @@ const int reg_classes[NB_REGS] = {
/******************************************************/
static unsigned long func_sub_sp_offset;
-static unsigned long func_bound_offset;
static int func_ret_sub;
+#ifdef CONFIG_TCC_BCHECK
+static unsigned long func_bound_offset;
+#endif
/* XXX: make it faster ? */
void g(int c)
@@ -511,12 +513,14 @@ void gfunc_prolog(CType *func_type)
func_ret_sub = 4;
#endif
+#ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */
if (tcc_state->do_bounds_check) {
oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */
func_bound_offset = lbounds_section->data_offset;
}
+#endif
}
/* generate function epilog */
diff --git a/lib/bcheck.c b/lib/bcheck.c
index 90590f5..09f2a3a 100644
--- a/lib/bcheck.c
+++ b/lib/bcheck.c
@@ -33,12 +33,11 @@
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
#define CONFIG_TCC_MALLOC_HOOKS
-
#define HAVE_MEMALIGN
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
- || defined(__UCLIBC__) || defined(__OpenBSD__)
-#warning Bound checking not fully supported in this environment.
+ || defined(__UCLIBC__) || defined(__OpenBSD__) || defined(_WIN32)
+#warning Bound checking does not support malloc (etc.) in this environment.
#undef CONFIG_TCC_MALLOC_HOOKS
#undef HAVE_MEMALIGN
#endif
@@ -152,9 +151,6 @@ static void bound_alloc_error(void)
bound_error("not enough memory for bound checking code");
}
-/* currently, tcc cannot compile that because we use GNUC extensions */
-#if !defined(__TINYC__)
-
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */
void * FASTCALL __bound_ptr_add(void *p, int offset)
@@ -203,6 +199,13 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
return p + offset; \
}
+BOUND_PTR_INDIR(1)
+BOUND_PTR_INDIR(2)
+BOUND_PTR_INDIR(4)
+BOUND_PTR_INDIR(8)
+BOUND_PTR_INDIR(12)
+BOUND_PTR_INDIR(16)
+
#ifdef __i386__
/* return the frame pointer of the caller */
#define GET_CALLER_FP(fp)\
@@ -246,34 +249,6 @@ void FASTCALL __bound_local_delete(void *p1)
}
}
-#else
-
-void __bound_local_new(void *p)
-{
-}
-void __bound_local_delete(void *p)
-{
-}
-
-void *__bound_ptr_add(void *p, int offset)
-{
- return p + offset;
-}
-
-#define BOUND_PTR_INDIR(dsize) \
-void *__bound_ptr_indir ## dsize (void *p, int offset) \
-{ \
- return p + offset; \
-}
-#endif
-
-BOUND_PTR_INDIR(1)
-BOUND_PTR_INDIR(2)
-BOUND_PTR_INDIR(4)
-BOUND_PTR_INDIR(8)
-BOUND_PTR_INDIR(12)
-BOUND_PTR_INDIR(16)
-
static BoundEntry *__bound_new_page(void)
{
BoundEntry *page;
diff --git a/libtcc.c b/libtcc.c
index 9309b77..7ef1f0b 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -58,9 +58,13 @@ static Section *cur_text_section; /* current section where function code is
#ifdef CONFIG_TCC_ASM
static Section *last_text_section; /* to handle .previous asm directive */
#endif
+
+#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
static Section *bounds_section; /* contains global data bound description */
static Section *lbounds_section; /* contains local data bound description */
+#endif
+
/* symbol sections */
static Section *symtab_section, *strtab_section;
@@ -109,8 +113,8 @@ static int tcc_ext = 1;
/* max number of callers shown if error */
#ifdef CONFIG_TCC_BACKTRACE
int num_callers = 6;
+void *rt_prog_main;
const char **rt_bound_error_msg;
-unsigned long rt_prog_main;
#endif
/* XXX: get rid of this ASAP */
@@ -731,7 +735,7 @@ static void put_extern_sym2(Sym *sym, Section *section,
/* if bound checking is activated, we change some function
names by adding the "__bound" prefix */
switch(sym->v) {
-#if 0
+#ifdef TCC_TARGET_PE
/* XXX: we rely only on malloc hooks */
case TOK_malloc:
case TOK_free:
diff --git a/tcc.h b/tcc.h
index cc63e92..16aba53 100644
--- a/tcc.h
+++ b/tcc.h
@@ -101,7 +101,7 @@
#define TCC_TARGET_I386
#endif
-#if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
+#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
#define CONFIG_TCC_BCHECK /* enable bound checking code */
#endif
@@ -120,7 +120,7 @@
#define TCC_TARGET_COFF
#endif
-#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
+#if !defined(CONFIG_TCCBOOT)
#define CONFIG_TCC_BACKTRACE
#endif
@@ -465,8 +465,10 @@ struct TCCState {
int verbose;
/* compile with debug symbol (and use them if error during execution) */
int do_debug;
+#ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */
int do_bounds_check;
+#endif
/* give the path of the tcc libraries */
char *tcc_lib_path;
@@ -809,11 +811,6 @@ char *pstrcat(char *buf, int buf_size, const char *s);
void dynarray_add(void ***ptab, int *nb_ptr, void *data);
void dynarray_reset(void *pp, int *n);
-#ifdef CONFIG_TCC_BACKTRACE
-extern int num_callers;
-extern const char **rt_bound_error_msg;
-#endif
-
/* true if float/double/long double type */
static inline int is_float(int t)
{
diff --git a/tccelf.c b/tccelf.c
index 7b891cf..1b4a804 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -1186,50 +1186,59 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
s->sh_num, sym_end);
}
-/* add tcc runtime libraries */
-static void tcc_add_runtime(TCCState *s1)
+static void tcc_add_bcheck(TCCState *s1)
{
-#if defined(CONFIG_TCC_BCHECK) || !defined(CONFIG_USE_LIBGCC)
- char buf[1024];
-#endif
-
#ifdef CONFIG_TCC_BCHECK
- if (s1->do_bounds_check) {
- unsigned long *ptr;
- Section *init_section;
- unsigned char *pinit;
- int sym_index;
+ unsigned long *ptr;
+ Section *init_section;
+ unsigned char *pinit;
+ int sym_index;
- /* XXX: add an object file to do that */
- ptr = section_ptr_add(bounds_section, sizeof(unsigned long));
- *ptr = 0;
- add_elf_sym(symtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- bounds_section->sh_num, "__bounds_start");
- /* add bound check code */
- snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o");
- tcc_add_file(s1, buf);
-#ifdef TCC_TARGET_I386
- if (s1->output_type != TCC_OUTPUT_MEMORY) {
- /* add 'call __bound_init()' in .init section */
- init_section = find_section(s1, ".init");
- pinit = section_ptr_add(init_section, 5);
- pinit[0] = 0xe8;
- put32(pinit + 1, -4);
- sym_index = find_elf_sym(symtab_section, "__bound_init");
- put_elf_reloc(symtab_section, init_section,
- init_section->data_offset - 4, R_386_PC32, sym_index);
- }
+ if (0 == s1->do_bounds_check)
+ return;
+
+ /* XXX: add an object file to do that */
+ ptr = section_ptr_add(bounds_section, sizeof(unsigned long));
+ *ptr = 0;
+ add_elf_sym(symtab_section, 0, 0,
+ ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+ bounds_section->sh_num, "__bounds_start");
+ /* add bound check code */
+#ifndef TCC_TARGET_PE
+ {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o");
+ tcc_add_file(s1, buf);
+ }
#endif
+#ifdef TCC_TARGET_I386
+ if (s1->output_type != TCC_OUTPUT_MEMORY) {
+ /* add 'call __bound_init()' in .init section */
+ init_section = find_section(s1, ".init");
+ pinit = section_ptr_add(init_section, 5);
+ pinit[0] = 0xe8;
+ put32(pinit + 1, -4);
+ sym_index = find_elf_sym(symtab_section, "__bound_init");
+ put_elf_reloc(symtab_section, init_section,
+ init_section->data_offset - 4, R_386_PC32, sym_index);
}
#endif
+#endif
+}
+
+/* add tcc runtime libraries */
+static void tcc_add_runtime(TCCState *s1)
+{
+ tcc_add_bcheck(s1);
+
/* add libc */
if (!s1->nostdlib) {
- tcc_add_library(s1, "c");
-
#ifdef CONFIG_USE_LIBGCC
+ tcc_add_library(s1, "c");
tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1");
#else
+ char buf[1024];
+ tcc_add_library(s1, "c");
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a");
tcc_add_file(s1, buf);
#endif
diff --git a/tccgen.c b/tccgen.c
index 6bc8998..9866c55 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -2911,8 +2911,10 @@ static void indir(void)
&& (vtop->type.t & VT_BTYPE) != VT_FUNC) {
vtop->r |= lvalue_type(vtop->type.t);
/* if bound checking, the referenced pointer must be checked */
+#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
vtop->r |= VT_MUSTBOUND;
+#endif
}
}
@@ -3328,9 +3330,11 @@ static void unary(void)
/* an array is never an lvalue */
if (!(vtop->type.t & VT_ARRAY)) {
vtop->r |= lvalue_type(vtop->type.t);
+#ifdef CONFIG_TCC_BCHECK
/* if bound checking, the referenced pointer must be checked */
if (tcc_state->do_bounds_check)
vtop->r |= VT_MUSTBOUND;
+#endif
}
next();
} else if (tok == '[') {
@@ -4702,10 +4706,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
}
if ((r & VT_VALMASK) == VT_LOCAL) {
sec = NULL;
+#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY))
loc--;
+#endif
loc = (loc - size) & -align;
addr = loc;
+#ifdef CONFIG_TCC_BCHECK
/* handles bounds */
/* XXX: currently, since we do only one pass, we cannot track
'&' operators, so we add only arrays */
@@ -4718,6 +4725,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
bounds_ptr[0] = addr;
bounds_ptr[1] = size;
}
+#endif
if (v) {
/* local variable */
sym_push(v, type, r, addr);
@@ -4774,9 +4782,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* very important to increment global pointer at this time
because initializers themselves can create new initializers */
data_offset += size;
+#ifdef CONFIG_TCC_BCHECK
/* add padding if bound check */
if (tcc_state->do_bounds_check)
data_offset++;
+#endif
sec->data_offset = data_offset;
/* allocate section space to put the data */
if (sec->sh_type != SHT_NOBITS &&
@@ -4813,7 +4823,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
vsetc(type, VT_CONST | VT_SYM, &cval);
vtop->sym = sym;
}
-
+#ifdef CONFIG_TCC_BCHECK
/* handles bounds now because the symbol must be defined
before for the relocation */
if (tcc_state->do_bounds_check) {
@@ -4825,6 +4835,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
bounds_ptr[0] = 0; /* relocated */
bounds_ptr[1] = size;
}
+#endif
}
if (has_init) {
decl_initializer(type, sec, addr, 1, 0);
diff --git a/tccpe.c b/tccpe.c
index 69161f9..d603a5e 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1700,15 +1700,15 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename)
pe.filename = filename;
pe.s1 = s1;
+ tcc_add_bcheck(s1);
pe_add_runtime_ex(s1, &pe);
relocate_common_syms(); /* assign bss adresses */
tcc_add_linker_symbols(s1);
ret = pe_check_symbols(&pe);
if (ret)
- return ret;
-
- if (filename) {
+ ;
+ else if (filename) {
if (PE_DLL == pe.type) {
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
/* XXX: check if is correct for arm-pe target */
diff --git a/tccrun.c b/tccrun.c
index d62e92a..e984c0f 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -20,75 +20,167 @@
/* tccrun.c - support for tcc -run */
+#ifdef _WIN32
+#define ucontext_t CONTEXT
+#endif
-/********************************************************/
-#ifdef CONFIG_TCC_STATIC
+static void set_pages_executable(void *ptr, unsigned long length);
+static void set_exception_handler(void);
+static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level);
+static void rt_error(ucontext_t *uc, const char *fmt, ...);
+static int tcc_relocate_ex(TCCState *s1, void *ptr);
-#define RTLD_LAZY 0x001
-#define RTLD_NOW 0x002
-#define RTLD_GLOBAL 0x100
-#define RTLD_DEFAULT NULL
+/* ------------------------------------------------------------- */
+/* Do all relocations (needed before using tcc_get_symbol())
+ Returns -1 on error. */
-/* dummy function for profiling */
-void *dlopen(const char *filename, int flag)
+int tcc_relocate(TCCState *s1)
{
- return NULL;
-}
+ int ret;
-void dlclose(void *p)
-{
+ ret = tcc_relocate_ex(s1, NULL);
+ if (-1 != ret) {
+ s1->runtime_mem = tcc_malloc(ret);
+ ret = tcc_relocate_ex(s1, s1->runtime_mem);
+ }
+ return ret;
}
-const char *dlerror(void)
+/* launch the compiled program with the given arguments */
+int tcc_run(TCCState *s1, int argc, char **argv)
{
- return "error";
-}
+ int (*prog_main)(int, char **);
-typedef struct TCCSyms {
- char *str;
- void *ptr;
-} TCCSyms;
+ if (tcc_relocate(s1) < 0)
+ return -1;
-#define TCCSYM(a) { #a, &a, },
+ prog_main = tcc_get_symbol_err(s1, "main");
-/* 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)
+#ifdef CONFIG_TCC_BACKTRACE
+ if (s1->do_debug)
+ set_exception_handler();
#endif
- { NULL, NULL },
-};
-void *resolve_sym(TCCState *s1, const char *symbol)
-{
- TCCSyms *p;
- p = tcc_syms;
- while (p->str != NULL) {
- if (!strcmp(p->str, symbol))
- return p->ptr;
- p++;
+#ifdef CONFIG_TCC_BCHECK
+ if (s1->do_bounds_check) {
+ void (*bound_init)(void);
+ void (*bound_exit)(void);
+ int ret;
+ /* set error function */
+ rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
+ rt_prog_main = prog_main;
+ /* XXX: use .init section so that it also work in binary ? */
+ bound_init = tcc_get_symbol_err(s1, "__bound_init");
+ bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
+ bound_init();
+ ret = (*prog_main)(argc, argv);
+ bound_exit();
+ return ret;
}
- return NULL;
+#endif
+ return (*prog_main)(argc, argv);
}
-#elif defined(_WIN32)
-#define dlclose FreeLibrary
+/* relocate code. Return -1 on error, required size if ptr is NULL,
+ otherwise copy code into buffer passed by the caller */
+static int tcc_relocate_ex(TCCState *s1, void *ptr)
+{
+ Section *s;
+ unsigned long offset, length;
+ uplong mem;
+ int i;
+
+ if (0 == s1->runtime_added) {
+ s1->runtime_added = 1;
+ s1->nb_errors = 0;
+#ifdef TCC_TARGET_PE
+ pe_output_file(s1, NULL);
#else
-#include <dlfcn.h>
+ tcc_add_runtime(s1);
+ relocate_common_syms();
+ tcc_add_linker_symbols(s1);
+ build_got_entries(s1);
+#endif
+ if (s1->nb_errors)
+ return -1;
+ }
-void *resolve_sym(TCCState *s1, const char *sym)
-{
- return dlsym(RTLD_DEFAULT, sym);
+ offset = 0, mem = (uplong)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;
+ }
+ offset += 16;
+
+ /* relocate symbols */
+ relocate_syms(s1, 1);
+ if (s1->nb_errors)
+ return -1;
+
+#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
+ 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;
+
+ /* 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*)(uplong)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);
+ }
+
+#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
+ set_pages_executable(s1->runtime_plt_and_got,
+ s1->runtime_plt_and_got_offset);
+#endif
+ return 0;
}
-#endif /* defined CONFIG_TCC_STATIC */
+/* ------------------------------------------------------------- */
+/* allow to run code in memory */
-/********************************************************/
+static 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
+}
+/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
/* print the position in the source file of PC value 'pc' by reading
@@ -215,7 +307,92 @@ static unsigned long rt_printline(unsigned long wanted_pc)
return func_addr;
}
+/* emit a run time error at position 'pc' */
+static 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 ");
+ pc = rt_printline(pc);
+ if (pc == (unsigned long)rt_prog_main && pc)
+ break;
+ }
+ exit(255);
+ va_end(ap);
+}
+
+/* ------------------------------------------------------------- */
+#ifndef _WIN32
+
+/* 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);
+}
+
+/* Generate a stack backtrace when a CPU exception occurs. */
+static void set_exception_handler(void)
+{
+ 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);
+}
+
+/* ------------------------------------------------------------- */
#ifdef __i386__
+
/* fix for glibc 2.1 */
#ifndef REG_EIP
#define REG_EIP EIP
@@ -223,8 +400,7 @@ static unsigned long rt_printline(unsigned long wanted_pc)
#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)
+static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level)
{
unsigned long fp;
int i;
@@ -256,7 +432,10 @@ static int rt_get_caller_pc(unsigned long *paddr,
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)
@@ -288,236 +467,136 @@ static int rt_get_caller_pc(unsigned long *paddr,
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;
+#endif /* !__i386__ */
- 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 ");
- pc = rt_printline(pc);
- if (pc == rt_prog_main && pc)
- break;
- }
- exit(255);
- va_end(ap);
-}
+/* ------------------------------------------------------------- */
+#else /* WIN32 */
-/* signal handler for fatal errors */
-static void sig_error(int signum, siginfo_t *siginf, void *puc)
+static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
- 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;
- }
+ CONTEXT *uc = ex_info->ContextRecord;
+/*
+ EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
+ printf("CPU exception: code=%08lx addr=%p\n",
+ er->ExceptionCode, er->ExceptionAddress);
+*/
+ if (rt_bound_error_msg && *rt_bound_error_msg)
+ rt_error(uc, *rt_bound_error_msg);
+ else
+ rt_error(uc, "dereferencing invalid pointer");
exit(255);
+ //return EXCEPTION_CONTINUE_SEARCH;
}
-#endif /* defined CONFIG_TCC_BACKTRACE */
-
-/********************************************************/
-
-void set_pages_executable(void *ptr, unsigned long length)
+/* Generate a stack backtrace when a CPU exception occurs. */
+static void set_exception_handler(void)
{
-#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
+ SetUnhandledExceptionFilter(cpu_exception_handler);
}
-/* relocate code. Return -1 on error, required size if ptr is NULL,
- otherwise copy code into buffer passed by the caller */
-static int tcc_relocate_ex(TCCState *s1, void *ptr)
+/* return the PC at frame level 'level'. Return non zero if not found */
+static int rt_get_caller_pc(unsigned long *paddr,
+ CONTEXT *uc, int level)
{
- Section *s;
- unsigned long offset, length;
- uplong mem;
+ unsigned long fp;
int i;
- if (0 == s1->runtime_added) {
- s1->runtime_added = 1;
- s1->nb_errors = 0;
-#ifdef TCC_TARGET_PE
- pe_output_file(s1, NULL);
-#else
- tcc_add_runtime(s1);
- relocate_common_syms();
- tcc_add_linker_symbols(s1);
- build_got_entries(s1);
-#endif
- if (s1->nb_errors)
- return -1;
- }
-
- offset = 0, mem = (uplong)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;
+ if (level == 0) {
+ *paddr = uc->Eip;
+ return 0;
+ } else {
+ fp = uc->Ebp;
+ 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;
}
- offset += 16;
-
- /* relocate symbols */
- relocate_syms(s1, 1);
- if (s1->nb_errors)
- return -1;
-
-#ifndef TCC_TARGET_PE
-#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
-#endif
+}
- if (0 == mem)
- return offset;
+#endif /* _WIN32 */
+#endif /* CONFIG_TCC_BACKTRACE */
+/* ------------------------------------------------------------- */
- /* relocate each section */
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (s->reloc)
- relocate_section(s1, s);
- }
+#ifdef CONFIG_TCC_STATIC
- 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*)(uplong)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);
- }
+#define RTLD_LAZY 0x001
+#define RTLD_NOW 0x002
+#define RTLD_GLOBAL 0x100
+#define RTLD_DEFAULT NULL
-#ifndef TCC_TARGET_PE
-#ifdef TCC_TARGET_X86_64
- set_pages_executable(s1->runtime_plt_and_got,
- s1->runtime_plt_and_got_offset);
-#endif
-#endif
- return 0;
+/* dummy function for profiling */
+void *dlopen(const char *filename, int flag)
+{
+ return NULL;
}
-/* Do all relocations (needed before using tcc_get_symbol())
- Returns -1 on error. */
-int tcc_relocate(TCCState *s1)
+void dlclose(void *p)
{
- int ret = tcc_relocate_ex(s1, NULL);
- if (-1 == ret)
- return ret;
- s1->runtime_mem = tcc_malloc(ret);
- return tcc_relocate_ex(s1, s1->runtime_mem);
}
-/* launch the compiled program with the given arguments */
-int tcc_run(TCCState *s1, int argc, char **argv)
+const char *dlerror(void)
{
- int (*prog_main)(int, char **);
+ return "error";
+}
- if (tcc_relocate(s1) < 0)
- return -1;
+typedef struct TCCSyms {
+ char *str;
+ void *ptr;
+} TCCSyms;
- prog_main = tcc_get_symbol_err(s1, "main");
+#define TCCSYM(a) { #a, &a, },
- 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");
+/* 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)
+{
+ TCCSyms *p;
+ p = tcc_syms;
+ while (p->str != NULL) {
+ if (!strcmp(p->str, symbol))
+ return p->ptr;
+ p++;
}
+ return NULL;
+}
-#ifdef CONFIG_TCC_BCHECK
- if (s1->do_bounds_check) {
- void (*bound_init)(void);
- void (*bound_exit)(void);
- /* set error function */
- rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
- rt_prog_main = (unsigned long)prog_main;
- /* XXX: use .init section so that it also work in binary ? */
- bound_init = tcc_get_symbol_err(s1, "__bound_init");
- bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
- bound_init();
- ret = (*prog_main)(argc, argv);
- bound_exit();
- } else
-#endif
- return (*prog_main)(argc, argv);
+#elif defined(_WIN32)
+
+#define dlclose FreeLibrary
+
+#else
+
+#include <dlfcn.h>
+
+void *resolve_sym(TCCState *s1, const char *sym)
+{
+ return dlsym(RTLD_DEFAULT, sym);
}
-/********************************************************/
+#endif /* CONFIG_TCC_STATIC */
+
+/* ------------------------------------------------------------- */
diff --git a/tcctok.h b/tcctok.h
index c214ace..889ba0b 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -219,9 +219,11 @@
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
-#if 0
+#ifdef TCC_TARGET_PE
+#ifndef TCC_TARGET_X86_64
DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free")
+#endif
DEF(TOK_realloc, "realloc")
DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc")
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index b706db4..cb2721a 100644
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -31,8 +31,10 @@ copy ..\libtcc.h libtcc\libtcc.h
:tcc
%P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc
-:libtcc1.a
+:copy_std_includes
copy ..\include\*.h include
+
+:libtcc1.a
.\tcc -c lib/crt1.c
.\tcc -c lib/wincrt1.c
.\tcc -c lib/dllcrt1.c
@@ -40,5 +42,15 @@ copy ..\include\*.h include
.\tcc -c ../lib/libtcc1.c
.\tcc -c lib/chkstk.S
.\tcc -c ../lib/alloca86%S%.S
-tiny_libmaker lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o
+
+@set LIBFILES=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o
+
+@if not _%P%==_ goto makelib
+.\tcc -c ../lib/alloca86-bt%S%.S
+.\tcc -c ../lib/bcheck.c
+
+@set LIBFILES=%LIBFILES% alloca86-bt%S%.o bcheck.o
+
+:makelib
+tiny_libmaker lib/libtcc1.a %LIBFILES%
del *.o