From 7fa712e00c5221d9373e8f8fa073e9e6fa064da1 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 19 Dec 2009 22:22:43 +0100 Subject: [PATCH] win32: enable bounds checker & exception handler exception handler borrowed from k1w1. Thanks. --- Makefile | 7 +- i386-gen.c | 6 +- lib/bcheck.c | 43 +-- libtcc.c | 8 +- tcc.h | 11 +- tccelf.c | 79 +++--- tccgen.c | 13 +- tccpe.c | 6 +- tccrun.c | 659 +++++++++++++++++++++++++------------------- tcctok.h | 4 +- win32/build-tcc.bat | 16 +- 11 files changed, 471 insertions(+), 381 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); } +static void tcc_add_bcheck(TCCState *s1) +{ +#ifdef CONFIG_TCC_BCHECK + unsigned long *ptr; + Section *init_section; + unsigned char *pinit; + int 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) { -#if defined(CONFIG_TCC_BCHECK) || !defined(CONFIG_USE_LIBGCC) - char buf[1024]; -#endif + tcc_add_bcheck(s1); -#ifdef CONFIG_TCC_BCHECK - if (s1->do_bounds_check) { - 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); - } -#endif - } -#endif /* 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 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) -{ - return NULL; -} - -void dlclose(void *p) -{ -} - -const char *dlerror(void) -{ - return "error"; -} - -typedef struct TCCSyms { - char *str; - void *ptr; -} TCCSyms; - -#define TCCSYM(a) { #a, &a, }, - -/* 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 _WIN32 +#define ucontext_t CONTEXT #endif - { NULL, NULL }, -}; -void *resolve_sym(TCCState *s1, const char *symbol) +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); + +/* ------------------------------------------------------------- */ +/* Do all relocations (needed before using tcc_get_symbol()) + Returns -1 on error. */ + +int tcc_relocate(TCCState *s1) { - TCCSyms *p; - p = tcc_syms; - while (p->str != NULL) { - if (!strcmp(p->str, symbol)) - return p->ptr; - p++; + int ret; + + ret = tcc_relocate_ex(s1, NULL); + if (-1 != ret) { + s1->runtime_mem = tcc_malloc(ret); + ret = tcc_relocate_ex(s1, s1->runtime_mem); } - return NULL; + return ret; } -#elif defined(_WIN32) -#define dlclose FreeLibrary - -#else -#include - -void *resolve_sym(TCCState *s1, const char *sym) +/* launch the compiled program with the given arguments */ +int tcc_run(TCCState *s1, int argc, char **argv) { - return dlsym(RTLD_DEFAULT, sym); + int (*prog_main)(int, char **); + + if (tcc_relocate(s1) < 0) + return -1; + + prog_main = tcc_get_symbol_err(s1, "main"); + +#ifdef CONFIG_TCC_BACKTRACE + if (s1->do_debug) + set_exception_handler(); +#endif + +#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; + } +#endif + return (*prog_main)(argc, argv); } -#endif /* defined CONFIG_TCC_STATIC */ -/********************************************************/ +/* 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 + 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; + } + 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; +} + +/* ------------------------------------------------------------- */ +/* 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,90 +307,8 @@ static unsigned long rt_printline(unsigned long wanted_pc) return func_addr; } -#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= 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 */ -#if defined(__FreeBSD__) - *paddr = uc->uc_mcontext.mc_rip; -#else - *paddr = uc->uc_mcontext.gregs[REG_RIP]; -#endif - return 0; - } else { -#if defined(__FreeBSD__) - fp = uc->uc_mcontext.mc_rbp; -#else - fp = uc->uc_mcontext.gregs[REG_RBP]; -#endif - for(i=1;iruntime_added) { - s1->runtime_added = 1; - s1->nb_errors = 0; -#ifdef TCC_TARGET_PE - pe_output_file(s1, NULL); + if (level == 0) { +#if defined(__FreeBSD__) + *paddr = uc->uc_mcontext.mc_eip; +#elif defined(__dietlibc__) + *paddr = uc->uc_mcontext.eip; #else - tcc_add_runtime(s1); - relocate_common_syms(); - tcc_add_linker_symbols(s1); - build_got_entries(s1); + *paddr = uc->uc_mcontext.gregs[REG_EIP]; #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; - } - 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; - - /* 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); - } - -#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; -} - -/* Do all relocations (needed before using tcc_get_symbol()) - Returns -1 on error. */ -int tcc_relocate(TCCState *s1) -{ - 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) -{ - int (*prog_main)(int, char **); - - if (tcc_relocate(s1) < 0) - return -1; - - 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); + return 0; + } else { +#if defined(__FreeBSD__) + fp = uc->uc_mcontext.mc_ebp; +#elif defined(__dietlibc__) + fp = uc->uc_mcontext.ebp; #else - error("debug mode not available"); + fp = uc->uc_mcontext.gregs[REG_EBP]; #endif + for(i=1;i= 0xc0000000) + return -1; + fp = ((unsigned long *)fp)[0]; + } + *paddr = ((unsigned long *)fp)[1]; + return 0; } - -#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(__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 */ +#if defined(__FreeBSD__) + *paddr = uc->uc_mcontext.mc_rip; +#else + *paddr = uc->uc_mcontext.gregs[REG_RIP]; +#endif + return 0; + } else { +#if defined(__FreeBSD__) + fp = uc->uc_mcontext.mc_rbp; +#else + fp = uc->uc_mcontext.gregs[REG_RBP]; +#endif + for(i=1;iContextRecord; +/* + 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; +} + +/* Generate a stack backtrace when a CPU exception occurs. */ +static void set_exception_handler(void) +{ + SetUnhandledExceptionFilter(cpu_exception_handler); +} + +/* 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) +{ + unsigned long fp; + int i; + + if (level == 0) { + *paddr = uc->Eip; + return 0; + } else { + fp = uc->Ebp; + for(i=1;i= 0xc0000000) + return -1; + fp = ((unsigned long *)fp)[0]; + } + *paddr = ((unsigned long *)fp)[1]; + return 0; + } +} + +#endif /* _WIN32 */ +#endif /* CONFIG_TCC_BACKTRACE */ +/* ------------------------------------------------------------- */ + +#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) +{ + return NULL; +} + +void dlclose(void *p) +{ +} + +const char *dlerror(void) +{ + return "error"; +} + +typedef struct TCCSyms { + char *str; + void *ptr; +} TCCSyms; + +#define TCCSYM(a) { #a, &a, }, + +/* 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; +} + +#elif defined(_WIN32) + +#define dlclose FreeLibrary + +#else + +#include + +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