exception handler borrowed from k1w1. Thanks.
Unified · Split
| @@ -78,7 +78,7 @@ ARM_CROSS = arm-tcc-fpa$(EXESUF) arm-tcc-fpa-ld$(EXESUF) \ · 77 unmodified lines | |||
| 78 | arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF) | 78 | arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF) |
| 79 | C67_CROSS = c67-tcc$(EXESUF) | 79 | C67_CROSS = c67-tcc$(EXESUF) |
| 80 | 80 | ||
| 81 | CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c \ | 81 | CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c \ |
| 82 | tcc.h config.h libtcc.h tcctok.h | 82 | tcc.h config.h libtcc.h tcctok.h |
| 83 | I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h | 83 | I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h |
| 84 | WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c | 84 | WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c |
| @@ -180,7 +180,7 @@ VPATH+=lib · 95 unmodified lines | |||
| 180 | 180 | ||
| 181 | ifdef CONFIG_WIN32 | 181 | ifdef CONFIG_WIN32 |
| 182 | # for windows, we must use TCC because we generate ELF objects | 182 | # for windows, we must use TCC because we generate ELF objects |
| 183 | LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o | 183 | LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o bcheck.o |
| 184 | LIBTCC1_CC=./tcc.exe -Bwin32 -Iinclude $(NATIVE_TARGET) | 184 | LIBTCC1_CC=./tcc.exe -Bwin32 -Iinclude $(NATIVE_TARGET) |
| 185 | VPATH+=win32/lib | 185 | VPATH+=win32/lib |
| 186 | endif | 186 | endif |
| @@ -193,9 +193,6 @@ endif · 6 unmodified lines | |||
| 193 | libtcc1.a: $(LIBTCC1_OBJS) | 193 | libtcc1.a: $(LIBTCC1_OBJS) |
| 194 | $(AR) rcs $@ $^ | 194 | $(AR) rcs $@ $^ |
| 195 | 195 | ||
| 196 | bcheck.o: bcheck.c | ||
| 197 | $(CC) -o $@ -c $< -O2 -Wall | ||
| 198 | |||
| 199 | # install | 196 | # install |
| 200 | TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h | 197 | TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h |
| 201 | INSTALL=install | 198 | INSTALL=install |
| @@ -87,8 +87,10 @@ const int reg_classes[NB_REGS] = { · 86 unmodified lines | |||
| 87 | /******************************************************/ | 87 | /******************************************************/ |
| 88 | 88 | ||
| 89 | static unsigned long func_sub_sp_offset; | 89 | static unsigned long func_sub_sp_offset; |
| 90 | static unsigned long func_bound_offset; | ||
| 91 | static int func_ret_sub; | 90 | static int func_ret_sub; |
| 91 | #ifdef CONFIG_TCC_BCHECK | ||
| 92 | static unsigned long func_bound_offset; | ||
| 93 | #endif | ||
| 92 | 94 | ||
| 93 | /* XXX: make it faster ? */ | 95 | /* XXX: make it faster ? */ |
| 94 | void g(int c) | 96 | void g(int c) |
| @@ -511,12 +513,14 @@ void gfunc_prolog(CType *func_type) · 416 unmodified lines | |||
| 511 | func_ret_sub = 4; | 513 | func_ret_sub = 4; |
| 512 | #endif | 514 | #endif |
| 513 | 515 | ||
| 516 | #ifdef CONFIG_TCC_BCHECK | ||
| 514 | /* leave some room for bound checking code */ | 517 | /* leave some room for bound checking code */ |
| 515 | if (tcc_state->do_bounds_check) { | 518 | if (tcc_state->do_bounds_check) { |
| 516 | oad(0xb8, 0); /* lbound section pointer */ | 519 | oad(0xb8, 0); /* lbound section pointer */ |
| 517 | oad(0xb8, 0); /* call to function */ | 520 | oad(0xb8, 0); /* call to function */ |
| 518 | func_bound_offset = lbounds_section->data_offset; | 521 | func_bound_offset = lbounds_section->data_offset; |
| 519 | } | 522 | } |
| 523 | #endif | ||
| 520 | } | 524 | } |
| 521 | 525 | ||
| 522 | /* generate function epilog */ | 526 | /* generate function epilog */ |
| @@ -33,12 +33,11 @@ · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | /* use malloc hooks. Currently the code cannot be reliable if no hooks */ | 34 | /* use malloc hooks. Currently the code cannot be reliable if no hooks */ |
| 35 | #define CONFIG_TCC_MALLOC_HOOKS | 35 | #define CONFIG_TCC_MALLOC_HOOKS |
| 36 | |||
| 37 | #define HAVE_MEMALIGN | 36 | #define HAVE_MEMALIGN |
| 38 | 37 | ||
| 39 | #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \ | 38 | #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \ |
| 40 | || defined(__UCLIBC__) || defined(__OpenBSD__) | 39 | || defined(__UCLIBC__) || defined(__OpenBSD__) || defined(_WIN32) |
| 41 | #warning Bound checking not fully supported in this environment. | 40 | #warning Bound checking does not support malloc (etc.) in this environment. |
| 42 | #undef CONFIG_TCC_MALLOC_HOOKS | 41 | #undef CONFIG_TCC_MALLOC_HOOKS |
| 43 | #undef HAVE_MEMALIGN | 42 | #undef HAVE_MEMALIGN |
| 44 | #endif | 43 | #endif |
| @@ -152,9 +151,6 @@ static void bound_alloc_error(void) · 107 unmodified lines | |||
| 152 | bound_error("not enough memory for bound checking code"); | 151 | bound_error("not enough memory for bound checking code"); |
| 153 | } | 152 | } |
| 154 | 153 | ||
| 155 | /* currently, tcc cannot compile that because we use GNUC extensions */ | ||
| 156 | #if !defined(__TINYC__) | ||
| 157 | |||
| 158 | /* return '(p + offset)' for pointer arithmetic (a pointer can reach | 154 | /* return '(p + offset)' for pointer arithmetic (a pointer can reach |
| 159 | the end of a region in this case */ | 155 | the end of a region in this case */ |
| 160 | void * FASTCALL __bound_ptr_add(void *p, int offset) | 156 | void * FASTCALL __bound_ptr_add(void *p, int offset) |
| @@ -203,6 +199,13 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \ · 42 unmodified lines | |||
| 203 | return p + offset; \ | 199 | return p + offset; \ |
| 204 | } | 200 | } |
| 205 | 201 | ||
| 202 | BOUND_PTR_INDIR(1) | ||
| 203 | BOUND_PTR_INDIR(2) | ||
| 204 | BOUND_PTR_INDIR(4) | ||
| 205 | BOUND_PTR_INDIR(8) | ||
| 206 | BOUND_PTR_INDIR(12) | ||
| 207 | BOUND_PTR_INDIR(16) | ||
| 208 | |||
| 206 | #ifdef __i386__ | 209 | #ifdef __i386__ |
| 207 | /* return the frame pointer of the caller */ | 210 | /* return the frame pointer of the caller */ |
| 208 | #define GET_CALLER_FP(fp)\ | 211 | #define GET_CALLER_FP(fp)\ |
| @@ -246,34 +249,6 @@ void FASTCALL __bound_local_delete(void *p1) · 37 unmodified lines | |||
| 246 | } | 249 | } |
| 247 | } | 250 | } |
| 248 | 251 | ||
| 249 | #else | ||
| 250 | |||
| 251 | void __bound_local_new(void *p) | ||
| 252 | { | ||
| 253 | } | ||
| 254 | void __bound_local_delete(void *p) | ||
| 255 | { | ||
| 256 | } | ||
| 257 | |||
| 258 | void *__bound_ptr_add(void *p, int offset) | ||
| 259 | { | ||
| 260 | return p + offset; | ||
| 261 | } | ||
| 262 | |||
| 263 | #define BOUND_PTR_INDIR(dsize) \ | ||
| 264 | void *__bound_ptr_indir ## dsize (void *p, int offset) \ | ||
| 265 | { \ | ||
| 266 | return p + offset; \ | ||
| 267 | } | ||
| 268 | #endif | ||
| 269 | |||
| 270 | BOUND_PTR_INDIR(1) | ||
| 271 | BOUND_PTR_INDIR(2) | ||
| 272 | BOUND_PTR_INDIR(4) | ||
| 273 | BOUND_PTR_INDIR(8) | ||
| 274 | BOUND_PTR_INDIR(12) | ||
| 275 | BOUND_PTR_INDIR(16) | ||
| 276 | |||
| 277 | static BoundEntry *__bound_new_page(void) | 252 | static BoundEntry *__bound_new_page(void) |
| 278 | { | 253 | { |
| 279 | BoundEntry *page; | 254 | BoundEntry *page; |
| @@ -58,9 +58,13 @@ static Section *cur_text_section; /* current section where function code is · 57 unmodified lines | |||
| 58 | #ifdef CONFIG_TCC_ASM | 58 | #ifdef CONFIG_TCC_ASM |
| 59 | static Section *last_text_section; /* to handle .previous asm directive */ | 59 | static Section *last_text_section; /* to handle .previous asm directive */ |
| 60 | #endif | 60 | #endif |
| 61 | |||
| 62 | #ifdef CONFIG_TCC_BCHECK | ||
| 61 | /* bound check related sections */ | 63 | /* bound check related sections */ |
| 62 | static Section *bounds_section; /* contains global data bound description */ | 64 | static Section *bounds_section; /* contains global data bound description */ |
| 63 | static Section *lbounds_section; /* contains local data bound description */ | 65 | static Section *lbounds_section; /* contains local data bound description */ |
| 66 | #endif | ||
| 67 | |||
| 64 | /* symbol sections */ | 68 | /* symbol sections */ |
| 65 | static Section *symtab_section, *strtab_section; | 69 | static Section *symtab_section, *strtab_section; |
| 66 | 70 | ||
| @@ -109,8 +113,8 @@ static int tcc_ext = 1; · 42 unmodified lines | |||
| 109 | /* max number of callers shown if error */ | 113 | /* max number of callers shown if error */ |
| 110 | #ifdef CONFIG_TCC_BACKTRACE | 114 | #ifdef CONFIG_TCC_BACKTRACE |
| 111 | int num_callers = 6; | 115 | int num_callers = 6; |
| 116 | void *rt_prog_main; | ||
| 112 | const char **rt_bound_error_msg; | 117 | const char **rt_bound_error_msg; |
| 113 | unsigned long rt_prog_main; | ||
| 114 | #endif | 118 | #endif |
| 115 | 119 | ||
| 116 | /* XXX: get rid of this ASAP */ | 120 | /* XXX: get rid of this ASAP */ |
| @@ -731,7 +735,7 @@ static void put_extern_sym2(Sym *sym, Section *section, · 614 unmodified lines | |||
| 731 | /* if bound checking is activated, we change some function | 735 | /* if bound checking is activated, we change some function |
| 732 | names by adding the "__bound" prefix */ | 736 | names by adding the "__bound" prefix */ |
| 733 | switch(sym->v) { | 737 | switch(sym->v) { |
| 734 | #if 0 | 738 | #ifdef TCC_TARGET_PE |
| 735 | /* XXX: we rely only on malloc hooks */ | 739 | /* XXX: we rely only on malloc hooks */ |
| 736 | case TOK_malloc: | 740 | case TOK_malloc: |
| 737 | case TOK_free: | 741 | case TOK_free: |
| @@ -101,7 +101,7 @@ · 100 unmodified lines | |||
| 101 | #define TCC_TARGET_I386 | 101 | #define TCC_TARGET_I386 |
| 102 | #endif | 102 | #endif |
| 103 | 103 | ||
| 104 | #if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ | 104 | #if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
| 105 | !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) | 105 | !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64) |
| 106 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ | 106 | #define CONFIG_TCC_BCHECK /* enable bound checking code */ |
| 107 | #endif | 107 | #endif |
| @@ -120,7 +120,7 @@ · 12 unmodified lines | |||
| 120 | #define TCC_TARGET_COFF | 120 | #define TCC_TARGET_COFF |
| 121 | #endif | 121 | #endif |
| 122 | 122 | ||
| 123 | #if !defined(_WIN32) && !defined(CONFIG_TCCBOOT) | 123 | #if !defined(CONFIG_TCCBOOT) |
| 124 | #define CONFIG_TCC_BACKTRACE | 124 | #define CONFIG_TCC_BACKTRACE |
| 125 | #endif | 125 | #endif |
| 126 | 126 | ||
| @@ -465,8 +465,10 @@ struct TCCState { · 338 unmodified lines | |||
| 465 | int verbose; | 465 | int verbose; |
| 466 | /* compile with debug symbol (and use them if error during execution) */ | 466 | /* compile with debug symbol (and use them if error during execution) */ |
| 467 | int do_debug; | 467 | int do_debug; |
| 468 | #ifdef CONFIG_TCC_BCHECK | ||
| 468 | /* compile with built-in memory and bounds checker */ | 469 | /* compile with built-in memory and bounds checker */ |
| 469 | int do_bounds_check; | 470 | int do_bounds_check; |
| 471 | #endif | ||
| 470 | /* give the path of the tcc libraries */ | 472 | /* give the path of the tcc libraries */ |
| 471 | char *tcc_lib_path; | 473 | char *tcc_lib_path; |
| 472 | 474 | ||
| @@ -809,11 +811,6 @@ char *pstrcat(char *buf, int buf_size, const char *s); · 336 unmodified lines | |||
| 809 | void dynarray_add(void ***ptab, int *nb_ptr, void *data); | 811 | void dynarray_add(void ***ptab, int *nb_ptr, void *data); |
| 810 | void dynarray_reset(void *pp, int *n); | 812 | void dynarray_reset(void *pp, int *n); |
| 811 | 813 | ||
| 812 | #ifdef CONFIG_TCC_BACKTRACE | ||
| 813 | extern int num_callers; | ||
| 814 | extern const char **rt_bound_error_msg; | ||
| 815 | #endif | ||
| 816 | |||
| 817 | /* true if float/double/long double type */ | 814 | /* true if float/double/long double type */ |
| 818 | static inline int is_float(int t) | 815 | static inline int is_float(int t) |
| 819 | { | 816 | { |
| @@ -1186,50 +1186,59 @@ static void add_init_array_defines(TCCState *s1, const char *section_name) · 1185 unmodified lines | |||
| 1186 | s->sh_num, sym_end); | 1186 | s->sh_num, sym_end); |
| 1187 | } | 1187 | } |
| 1188 | 1188 | ||
| 1189 | /* add tcc runtime libraries */ | 1189 | static void tcc_add_bcheck(TCCState *s1) |
| 1190 | static void tcc_add_runtime(TCCState *s1) | ||
| 1191 | { | 1190 | { |
| 1192 | #if defined(CONFIG_TCC_BCHECK) || !defined(CONFIG_USE_LIBGCC) | 1191 | #ifdef CONFIG_TCC_BCHECK |
| 1192 | unsigned long *ptr; | ||
| 1193 | Section *init_section; | ||
| 1194 | unsigned char *pinit; | ||
| 1195 | int sym_index; | ||
| 1196 | |||
| 1197 | if (0 == s1->do_bounds_check) | ||
| 1198 | return; | ||
| 1199 | |||
| 1200 | /* XXX: add an object file to do that */ | ||
| 1201 | ptr = section_ptr_add(bounds_section, sizeof(unsigned long)); | ||
| 1202 | *ptr = 0; | ||
| 1203 | add_elf_sym(symtab_section, 0, 0, | ||
| 1204 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, | ||
| 1205 | bounds_section->sh_num, "__bounds_start"); | ||
| 1206 | /* add bound check code */ | ||
| 1207 | #ifndef TCC_TARGET_PE | ||
| 1208 | { | ||
| 1193 | char buf[1024]; | 1209 | char buf[1024]; |
| 1210 | snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o"); | ||
| 1211 | tcc_add_file(s1, buf); | ||
| 1212 | } | ||
| 1194 | #endif | 1213 | #endif |
| 1195 | |||
| 1196 | #ifdef CONFIG_TCC_BCHECK | ||
| 1197 | if (s1->do_bounds_check) { | ||
| 1198 | unsigned long *ptr; | ||
| 1199 | Section *init_section; | ||
| 1200 | unsigned char *pinit; | ||
| 1201 | int sym_index; | ||
| 1202 | |||
| 1203 | /* XXX: add an object file to do that */ | ||
| 1204 | ptr = section_ptr_add(bounds_section, sizeof(unsigned long)); | ||
| 1205 | *ptr = 0; | ||
| 1206 | add_elf_sym(symtab_section, 0, 0, | ||
| 1207 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, | ||
| 1208 | bounds_section->sh_num, "__bounds_start"); | ||
| 1209 | /* add bound check code */ | ||
| 1210 | snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o"); | ||
| 1211 | tcc_add_file(s1, buf); | ||
| 1212 | #ifdef TCC_TARGET_I386 | 1214 | #ifdef TCC_TARGET_I386 |
| 1213 | if (s1->output_type != TCC_OUTPUT_MEMORY) { | 1215 | if (s1->output_type != TCC_OUTPUT_MEMORY) { |
| 1214 | /* add 'call __bound_init()' in .init section */ | 1216 | /* add 'call __bound_init()' in .init section */ |
| 1215 | init_section = find_section(s1, ".init"); | 1217 | init_section = find_section(s1, ".init"); |
| 1216 | pinit = section_ptr_add(init_section, 5); | 1218 | pinit = section_ptr_add(init_section, 5); |
| 1217 | pinit[0] = 0xe8; | 1219 | pinit[0] = 0xe8; |
| 1218 | put32(pinit + 1, -4); | 1220 | put32(pinit + 1, -4); |
| 1219 | sym_index = find_elf_sym(symtab_section, "__bound_init"); | 1221 | sym_index = find_elf_sym(symtab_section, "__bound_init"); |
| 1220 | put_elf_reloc(symtab_section, init_section, | 1222 | put_elf_reloc(symtab_section, init_section, |
| 1221 | init_section->data_offset - 4, R_386_PC32, sym_index); | 1223 | init_section->data_offset - 4, R_386_PC32, sym_index); |
| 1222 | } | ||
| 1223 | #endif | ||
| 1224 | } | 1224 | } |
| 1225 | #endif | 1225 | #endif |
| 1226 | #endif | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | /* add tcc runtime libraries */ | ||
| 1230 | static void tcc_add_runtime(TCCState *s1) | ||
| 1231 | { | ||
| 1232 | tcc_add_bcheck(s1); | ||
| 1233 | |||
| 1226 | /* add libc */ | 1234 | /* add libc */ |
| 1227 | if (!s1->nostdlib) { | 1235 | if (!s1->nostdlib) { |
| 1228 | tcc_add_library(s1, "c"); | ||
| 1229 | |||
| 1230 | #ifdef CONFIG_USE_LIBGCC | 1236 | #ifdef CONFIG_USE_LIBGCC |
| 1237 | tcc_add_library(s1, "c"); | ||
| 1231 | tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1"); | 1238 | tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1"); |
| 1232 | #else | 1239 | #else |
| 1240 | char buf[1024]; | ||
| 1241 | tcc_add_library(s1, "c"); | ||
| 1233 | snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a"); | 1242 | snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a"); |
| 1234 | tcc_add_file(s1, buf); | 1243 | tcc_add_file(s1, buf); |
| 1235 | #endif | 1244 | #endif |
| @@ -2911,8 +2911,10 @@ static void indir(void) · 2910 unmodified lines | |||
| 2911 | && (vtop->type.t & VT_BTYPE) != VT_FUNC) { | 2911 | && (vtop->type.t & VT_BTYPE) != VT_FUNC) { |
| 2912 | vtop->r |= lvalue_type(vtop->type.t); | 2912 | vtop->r |= lvalue_type(vtop->type.t); |
| 2913 | /* if bound checking, the referenced pointer must be checked */ | 2913 | /* if bound checking, the referenced pointer must be checked */ |
| 2914 | #ifdef CONFIG_TCC_BCHECK | ||
| 2914 | if (tcc_state->do_bounds_check) | 2915 | if (tcc_state->do_bounds_check) |
| 2915 | vtop->r |= VT_MUSTBOUND; | 2916 | vtop->r |= VT_MUSTBOUND; |
| 2917 | #endif | ||
| 2916 | } | 2918 | } |
| 2917 | } | 2919 | } |
| 2918 | 2920 | ||
| @@ -3328,9 +3330,11 @@ static void unary(void) · 409 unmodified lines | |||
| 3328 | /* an array is never an lvalue */ | 3330 | /* an array is never an lvalue */ |
| 3329 | if (!(vtop->type.t & VT_ARRAY)) { | 3331 | if (!(vtop->type.t & VT_ARRAY)) { |
| 3330 | vtop->r |= lvalue_type(vtop->type.t); | 3332 | vtop->r |= lvalue_type(vtop->type.t); |
| 3333 | #ifdef CONFIG_TCC_BCHECK | ||
| 3331 | /* if bound checking, the referenced pointer must be checked */ | 3334 | /* if bound checking, the referenced pointer must be checked */ |
| 3332 | if (tcc_state->do_bounds_check) | 3335 | if (tcc_state->do_bounds_check) |
| 3333 | vtop->r |= VT_MUSTBOUND; | 3336 | vtop->r |= VT_MUSTBOUND; |
| 3337 | #endif | ||
| 3334 | } | 3338 | } |
| 3335 | next(); | 3339 | next(); |
| 3336 | } else if (tok == '[') { | 3340 | } else if (tok == '[') { |
| @@ -4702,10 +4706,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 1365 unmodified lines | |||
| 4702 | } | 4706 | } |
| 4703 | if ((r & VT_VALMASK) == VT_LOCAL) { | 4707 | if ((r & VT_VALMASK) == VT_LOCAL) { |
| 4704 | sec = NULL; | 4708 | sec = NULL; |
| 4709 | #ifdef CONFIG_TCC_BCHECK | ||
| 4705 | if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) | 4710 | if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) |
| 4706 | loc--; | 4711 | loc--; |
| 4712 | #endif | ||
| 4707 | loc = (loc - size) & -align; | 4713 | loc = (loc - size) & -align; |
| 4708 | addr = loc; | 4714 | addr = loc; |
| 4715 | #ifdef CONFIG_TCC_BCHECK | ||
| 4709 | /* handles bounds */ | 4716 | /* handles bounds */ |
| 4710 | /* XXX: currently, since we do only one pass, we cannot track | 4717 | /* XXX: currently, since we do only one pass, we cannot track |
| 4711 | '&' operators, so we add only arrays */ | 4718 | '&' operators, so we add only arrays */ |
| @@ -4718,6 +4725,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 6 unmodified lines | |||
| 4718 | bounds_ptr[0] = addr; | 4725 | bounds_ptr[0] = addr; |
| 4719 | bounds_ptr[1] = size; | 4726 | bounds_ptr[1] = size; |
| 4720 | } | 4727 | } |
| 4728 | #endif | ||
| 4721 | if (v) { | 4729 | if (v) { |
| 4722 | /* local variable */ | 4730 | /* local variable */ |
| 4723 | sym_push(v, type, r, addr); | 4731 | sym_push(v, type, r, addr); |
| @@ -4774,9 +4782,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 50 unmodified lines | |||
| 4774 | /* very important to increment global pointer at this time | 4782 | /* very important to increment global pointer at this time |
| 4775 | because initializers themselves can create new initializers */ | 4783 | because initializers themselves can create new initializers */ |
| 4776 | data_offset += size; | 4784 | data_offset += size; |
| 4785 | #ifdef CONFIG_TCC_BCHECK | ||
| 4777 | /* add padding if bound check */ | 4786 | /* add padding if bound check */ |
| 4778 | if (tcc_state->do_bounds_check) | 4787 | if (tcc_state->do_bounds_check) |
| 4779 | data_offset++; | 4788 | data_offset++; |
| 4789 | #endif | ||
| 4780 | sec->data_offset = data_offset; | 4790 | sec->data_offset = data_offset; |
| 4781 | /* allocate section space to put the data */ | 4791 | /* allocate section space to put the data */ |
| 4782 | if (sec->sh_type != SHT_NOBITS && | 4792 | if (sec->sh_type != SHT_NOBITS && |
| @@ -4813,7 +4823,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 30 unmodified lines | |||
| 4813 | vsetc(type, VT_CONST | VT_SYM, &cval); | 4823 | vsetc(type, VT_CONST | VT_SYM, &cval); |
| 4814 | vtop->sym = sym; | 4824 | vtop->sym = sym; |
| 4815 | } | 4825 | } |
| 4816 | 4826 | #ifdef CONFIG_TCC_BCHECK | |
| 4817 | /* handles bounds now because the symbol must be defined | 4827 | /* handles bounds now because the symbol must be defined |
| 4818 | before for the relocation */ | 4828 | before for the relocation */ |
| 4819 | if (tcc_state->do_bounds_check) { | 4829 | if (tcc_state->do_bounds_check) { |
| @@ -4825,6 +4835,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 5 unmodified lines | |||
| 4825 | bounds_ptr[0] = 0; /* relocated */ | 4835 | bounds_ptr[0] = 0; /* relocated */ |
| 4826 | bounds_ptr[1] = size; | 4836 | bounds_ptr[1] = size; |
| 4827 | } | 4837 | } |
| 4838 | #endif | ||
| 4828 | } | 4839 | } |
| 4829 | if (has_init) { | 4840 | if (has_init) { |
| 4830 | decl_initializer(type, sec, addr, 1, 0); | 4841 | decl_initializer(type, sec, addr, 1, 0); |
| @@ -1700,15 +1700,15 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename) · 1699 unmodified lines | |||
| 1700 | pe.filename = filename; | 1700 | pe.filename = filename; |
| 1701 | pe.s1 = s1; | 1701 | pe.s1 = s1; |
| 1702 | 1702 | ||
| 1703 | tcc_add_bcheck(s1); | ||
| 1703 | pe_add_runtime_ex(s1, &pe); | 1704 | pe_add_runtime_ex(s1, &pe); |
| 1704 | relocate_common_syms(); /* assign bss adresses */ | 1705 | relocate_common_syms(); /* assign bss adresses */ |
| 1705 | tcc_add_linker_symbols(s1); | 1706 | tcc_add_linker_symbols(s1); |
| 1706 | 1707 | ||
| 1707 | ret = pe_check_symbols(&pe); | 1708 | ret = pe_check_symbols(&pe); |
| 1708 | if (ret) | 1709 | if (ret) |
| 1709 | return ret; | 1710 | ; |
| 1710 | 1711 | else if (filename) { | |
| 1711 | if (filename) { | ||
| 1712 | if (PE_DLL == pe.type) { | 1712 | if (PE_DLL == pe.type) { |
| 1713 | pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0); | 1713 | pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0); |
| 1714 | /* XXX: check if is correct for arm-pe target */ | 1714 | /* XXX: check if is correct for arm-pe target */ |
| @@ -20,75 +20,167 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | /* tccrun.c - support for tcc -run */ | 21 | /* tccrun.c - support for tcc -run */ |
| 22 | 22 | ||
| 23 | #ifdef _WIN32 | ||
| 24 | #define ucontext_t CONTEXT | ||
| 25 | #endif | ||
| 23 | 26 | ||
| 24 | /********************************************************/ | 27 | static void set_pages_executable(void *ptr, unsigned long length); |
| 25 | #ifdef CONFIG_TCC_STATIC | 28 | static void set_exception_handler(void); |
| 29 | static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level); | ||
| 30 | static void rt_error(ucontext_t *uc, const char *fmt, ...); | ||
| 31 | static int tcc_relocate_ex(TCCState *s1, void *ptr); | ||
| 26 | 32 | ||
| 27 | #define RTLD_LAZY 0x001 | 33 | /* ------------------------------------------------------------- */ |
| 28 | #define RTLD_NOW 0x002 | 34 | /* Do all relocations (needed before using tcc_get_symbol()) |
| 29 | #define RTLD_GLOBAL 0x100 | 35 | Returns -1 on error. */ |
| 30 | #define RTLD_DEFAULT NULL | ||
| 31 | 36 | ||
| 32 | /* dummy function for profiling */ | 37 | int tcc_relocate(TCCState *s1) |
| 33 | void *dlopen(const char *filename, int flag) | ||
| 34 | { | 38 | { |
| 35 | return NULL; | 39 | int ret; |
| 36 | } | ||
| 37 | 40 | ||
| 38 | void dlclose(void *p) | 41 | ret = tcc_relocate_ex(s1, NULL); |
| 39 | { | 42 | if (-1 != ret) { |
| 43 | s1->runtime_mem = tcc_malloc(ret); | ||
| 44 | ret = tcc_relocate_ex(s1, s1->runtime_mem); | ||
| 45 | } | ||
| 46 | return ret; | ||
| 40 | } | 47 | } |
| 41 | 48 | ||
| 42 | const char *dlerror(void) | 49 | /* launch the compiled program with the given arguments */ |
| 50 | int tcc_run(TCCState *s1, int argc, char **argv) | ||
| 43 | { | 51 | { |
| 44 | return "error"; | 52 | int (*prog_main)(int, char **); |
| 45 | } | ||
| 46 | 53 | ||
| 47 | typedef struct TCCSyms { | 54 | if (tcc_relocate(s1) < 0) |
| 48 | char *str; | 55 | return -1; |
| 49 | void *ptr; | ||
| 50 | } TCCSyms; | ||
| 51 | 56 | ||
| 52 | #define TCCSYM(a) { #a, &a, }, | 57 | prog_main = tcc_get_symbol_err(s1, "main"); |
| 53 | 58 | ||
| 54 | /* add the symbol you want here if no dynamic linking is done */ | 59 | #ifdef CONFIG_TCC_BACKTRACE |
| 55 | static TCCSyms tcc_syms[] = { | 60 | if (s1->do_debug) |
| 56 | #if !defined(CONFIG_TCCBOOT) | 61 | set_exception_handler(); |
| 57 | TCCSYM(printf) | ||
| 58 | TCCSYM(fprintf) | ||
| 59 | TCCSYM(fopen) | ||
| 60 | TCCSYM(fclose) | ||
| 61 | #endif | 62 | #endif |
| 62 | { NULL, NULL }, | ||
| 63 | }; | ||
| 64 | 63 | ||
| 65 | void *resolve_sym(TCCState *s1, const char *symbol) | 64 | #ifdef CONFIG_TCC_BCHECK |
| 66 | { | 65 | if (s1->do_bounds_check) { |
| 67 | TCCSyms *p; | 66 | void (*bound_init)(void); |
| 68 | p = tcc_syms; | 67 | void (*bound_exit)(void); |
| 69 | while (p->str != NULL) { | 68 | int ret; |
| 70 | if (!strcmp(p->str, symbol)) | 69 | /* set error function */ |
| 71 | return p->ptr; | 70 | rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); |
| 72 | p++; | 71 | rt_prog_main = prog_main; |
| 72 | /* XXX: use .init section so that it also work in binary ? */ | ||
| 73 | bound_init = tcc_get_symbol_err(s1, "__bound_init"); | ||
| 74 | bound_exit = tcc_get_symbol_err(s1, "__bound_exit"); | ||
| 75 | bound_init(); | ||
| 76 | ret = (*prog_main)(argc, argv); | ||
| 77 | bound_exit(); | ||
| 78 | return ret; | ||
| 73 | } | 79 | } |
| 74 | return NULL; | 80 | #endif |
| 81 | return (*prog_main)(argc, argv); | ||
| 75 | } | 82 | } |
| 76 | 83 | ||
| 77 | #elif defined(_WIN32) | ||
| 78 | #define dlclose FreeLibrary | ||
| 79 | 84 | ||
| 85 | /* relocate code. Return -1 on error, required size if ptr is NULL, | ||
| 86 | otherwise copy code into buffer passed by the caller */ | ||
| 87 | static int tcc_relocate_ex(TCCState *s1, void *ptr) | ||
| 88 | { | ||
| 89 | Section *s; | ||
| 90 | unsigned long offset, length; | ||
| 91 | uplong mem; | ||
| 92 | int i; | ||
| 93 | |||
| 94 | if (0 == s1->runtime_added) { | ||
| 95 | s1->runtime_added = 1; | ||
| 96 | s1->nb_errors = 0; | ||
| 97 | #ifdef TCC_TARGET_PE | ||
| 98 | pe_output_file(s1, NULL); | ||
| 80 | #else | 99 | #else |
| 81 | #include <dlfcn.h> | 100 | tcc_add_runtime(s1); |
| 101 | relocate_common_syms(); | ||
| 102 | tcc_add_linker_symbols(s1); | ||
| 103 | build_got_entries(s1); | ||
| 104 | #endif | ||
| 105 | if (s1->nb_errors) | ||
| 106 | return -1; | ||
| 107 | } | ||
| 82 | 108 | ||
| 83 | void *resolve_sym(TCCState *s1, const char *sym) | 109 | offset = 0, mem = (uplong)ptr; |
| 84 | { | 110 | for(i = 1; i < s1->nb_sections; i++) { |
| 85 | return dlsym(RTLD_DEFAULT, sym); | 111 | s = s1->sections[i]; |
| 112 | if (0 == (s->sh_flags & SHF_ALLOC)) | ||
| 113 | continue; | ||
| 114 | length = s->data_offset; | ||
| 115 | s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0; | ||
| 116 | offset = (offset + length + 15) & ~15; | ||
| 117 | } | ||
| 118 | offset += 16; | ||
| 119 | |||
| 120 | /* relocate symbols */ | ||
| 121 | relocate_syms(s1, 1); | ||
| 122 | if (s1->nb_errors) | ||
| 123 | return -1; | ||
| 124 | |||
| 125 | #if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE | ||
| 126 | s1->runtime_plt_and_got_offset = 0; | ||
| 127 | s1->runtime_plt_and_got = (char *)(mem + offset); | ||
| 128 | /* double the size of the buffer for got and plt entries | ||
| 129 | XXX: calculate exact size for them? */ | ||
| 130 | offset *= 2; | ||
| 131 | #endif | ||
| 132 | |||
| 133 | if (0 == mem) | ||
| 134 | return offset; | ||
| 135 | |||
| 136 | /* relocate each section */ | ||
| 137 | for(i = 1; i < s1->nb_sections; i++) { | ||
| 138 | s = s1->sections[i]; | ||
| 139 | if (s->reloc) | ||
| 140 | relocate_section(s1, s); | ||
| 141 | } | ||
| 142 | |||
| 143 | for(i = 1; i < s1->nb_sections; i++) { | ||
| 144 | s = s1->sections[i]; | ||
| 145 | if (0 == (s->sh_flags & SHF_ALLOC)) | ||
| 146 | continue; | ||
| 147 | length = s->data_offset; | ||
| 148 | // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length); | ||
| 149 | ptr = (void*)(uplong)s->sh_addr; | ||
| 150 | if (NULL == s->data || s->sh_type == SHT_NOBITS) | ||
| 151 | memset(ptr, 0, length); | ||
| 152 | else | ||
| 153 | memcpy(ptr, s->data, length); | ||
| 154 | /* mark executable sections as executable in memory */ | ||
| 155 | if (s->sh_flags & SHF_EXECINSTR) | ||
| 156 | set_pages_executable(ptr, length); | ||
| 157 | } | ||
| 158 | |||
| 159 | #if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE | ||
| 160 | set_pages_executable(s1->runtime_plt_and_got, | ||
| 161 | s1->runtime_plt_and_got_offset); | ||
| 162 | #endif | ||
| 163 | return 0; | ||
| 86 | } | 164 | } |
| 87 | 165 | ||
| 88 | #endif /* defined CONFIG_TCC_STATIC */ | 166 | /* ------------------------------------------------------------- */ |
| 167 | /* allow to run code in memory */ | ||
| 89 | 168 | ||
| 90 | /********************************************************/ | 169 | static void set_pages_executable(void *ptr, unsigned long length) |
| 170 | { | ||
| 171 | #ifdef _WIN32 | ||
| 172 | unsigned long old_protect; | ||
| 173 | VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); | ||
| 174 | #else | ||
| 175 | unsigned long start, end; | ||
| 176 | start = (unsigned long)ptr & ~(PAGESIZE - 1); | ||
| 177 | end = (unsigned long)ptr + length; | ||
| 178 | end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); | ||
| 179 | mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC); | ||
| 180 | #endif | ||
| 181 | } | ||
| 91 | 182 | ||
| 183 | /* ------------------------------------------------------------- */ | ||
| 92 | #ifdef CONFIG_TCC_BACKTRACE | 184 | #ifdef CONFIG_TCC_BACKTRACE |
| 93 | 185 | ||
| 94 | /* print the position in the source file of PC value 'pc' by reading | 186 | /* 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) · 120 unmodified lines | |||
| 215 | return func_addr; | 307 | return func_addr; |
| 216 | } | 308 | } |
| 217 | 309 | ||
| 310 | /* emit a run time error at position 'pc' */ | ||
| 311 | static void rt_error(ucontext_t *uc, const char *fmt, ...) | ||
| 312 | { | ||
| 313 | va_list ap; | ||
| 314 | unsigned long pc; | ||
| 315 | int i; | ||
| 316 | |||
| 317 | va_start(ap, fmt); | ||
| 318 | fprintf(stderr, "Runtime error: "); | ||
| 319 | vfprintf(stderr, fmt, ap); | ||
| 320 | fprintf(stderr, "\n"); | ||
| 321 | |||
| 322 | for(i=0;i<num_callers;i++) { | ||
| 323 | if (rt_get_caller_pc(&pc, uc, i) < 0) | ||
| 324 | break; | ||
| 325 | if (i == 0) | ||
| 326 | fprintf(stderr, "at "); | ||
| 327 | else | ||
| 328 | fprintf(stderr, "by "); | ||
| 329 | pc = rt_printline(pc); | ||
| 330 | if (pc == (unsigned long)rt_prog_main && pc) | ||
| 331 | break; | ||
| 332 | } | ||
| 333 | exit(255); | ||
| 334 | va_end(ap); | ||
| 335 | } | ||
| 336 | |||
| 337 | /* ------------------------------------------------------------- */ | ||
| 338 | #ifndef _WIN32 | ||
| 339 | |||
| 340 | /* signal handler for fatal errors */ | ||
| 341 | static void sig_error(int signum, siginfo_t *siginf, void *puc) | ||
| 342 | { | ||
| 343 | ucontext_t *uc = puc; | ||
| 344 | |||
| 345 | switch(signum) { | ||
| 346 | case SIGFPE: | ||
| 347 | switch(siginf->si_code) { | ||
| 348 | case FPE_INTDIV: | ||
| 349 | case FPE_FLTDIV: | ||
| 350 | rt_error(uc, "division by zero"); | ||
| 351 | break; | ||
| 352 | default: | ||
| 353 | rt_error(uc, "floating point exception"); | ||
| 354 | break; | ||
| 355 | } | ||
| 356 | break; | ||
| 357 | case SIGBUS: | ||
| 358 | case SIGSEGV: | ||
| 359 | if (rt_bound_error_msg && *rt_bound_error_msg) | ||
| 360 | rt_error(uc, *rt_bound_error_msg); | ||
| 361 | else | ||
| 362 | rt_error(uc, "dereferencing invalid pointer"); | ||
| 363 | break; | ||
| 364 | case SIGILL: | ||
| 365 | rt_error(uc, "illegal instruction"); | ||
| 366 | break; | ||
| 367 | case SIGABRT: | ||
| 368 | rt_error(uc, "abort() called"); | ||
| 369 | break; | ||
| 370 | default: | ||
| 371 | rt_error(uc, "caught signal %d", signum); | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | exit(255); | ||
| 375 | } | ||
| 376 | |||
| 377 | /* Generate a stack backtrace when a CPU exception occurs. */ | ||
| 378 | static void set_exception_handler(void) | ||
| 379 | { | ||
| 380 | struct sigaction sigact; | ||
| 381 | /* install TCC signal handlers to print debug info on fatal | ||
| 382 | runtime errors */ | ||
| 383 | sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; | ||
| 384 | sigact.sa_sigaction = sig_error; | ||
| 385 | sigemptyset(&sigact.sa_mask); | ||
| 386 | sigaction(SIGFPE, &sigact, NULL); | ||
| 387 | sigaction(SIGILL, &sigact, NULL); | ||
| 388 | sigaction(SIGSEGV, &sigact, NULL); | ||
| 389 | sigaction(SIGBUS, &sigact, NULL); | ||
| 390 | sigaction(SIGABRT, &sigact, NULL); | ||
| 391 | } | ||
| 392 | |||
| 393 | /* ------------------------------------------------------------- */ | ||
| 218 | #ifdef __i386__ | 394 | #ifdef __i386__ |
| 395 | |||
| 219 | /* fix for glibc 2.1 */ | 396 | /* fix for glibc 2.1 */ |
| 220 | #ifndef REG_EIP | 397 | #ifndef REG_EIP |
| 221 | #define REG_EIP EIP | 398 | #define REG_EIP EIP |
| @@ -223,8 +400,7 @@ static unsigned long rt_printline(unsigned long wanted_pc) · 1 unmodified line | |||
| 223 | #endif | 400 | #endif |
| 224 | 401 | ||
| 225 | /* return the PC at frame level 'level'. Return non zero if not found */ | 402 | /* return the PC at frame level 'level'. Return non zero if not found */ |
| 226 | static int rt_get_caller_pc(unsigned long *paddr, | 403 | static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level) |
| 227 | ucontext_t *uc, int level) | ||
| 228 | { | 404 | { |
| 229 | unsigned long fp; | 405 | unsigned long fp; |
| 230 | int i; | 406 | int i; |
| @@ -256,7 +432,10 @@ static int rt_get_caller_pc(unsigned long *paddr, · 25 unmodified lines | |||
| 256 | return 0; | 432 | return 0; |
| 257 | } | 433 | } |
| 258 | } | 434 | } |
| 435 | |||
| 436 | /* ------------------------------------------------------------- */ | ||
| 259 | #elif defined(__x86_64__) | 437 | #elif defined(__x86_64__) |
| 438 | |||
| 260 | /* return the PC at frame level 'level'. Return non zero if not found */ | 439 | /* return the PC at frame level 'level'. Return non zero if not found */ |
| 261 | static int rt_get_caller_pc(unsigned long *paddr, | 440 | static int rt_get_caller_pc(unsigned long *paddr, |
| 262 | ucontext_t *uc, int level) | 441 | ucontext_t *uc, int level) |
| @@ -288,236 +467,136 @@ static int rt_get_caller_pc(unsigned long *paddr, · 25 unmodified lines | |||
| 288 | return 0; | 467 | return 0; |
| 289 | } | 468 | } |
| 290 | } | 469 | } |
| 470 | |||
| 471 | /* ------------------------------------------------------------- */ | ||
| 291 | #else | 472 | #else |
| 473 | |||
| 292 | #warning add arch specific rt_get_caller_pc() | 474 | #warning add arch specific rt_get_caller_pc() |
| 293 | static int rt_get_caller_pc(unsigned long *paddr, | 475 | static int rt_get_caller_pc(unsigned long *paddr, |
| 294 | ucontext_t *uc, int level) | 476 | ucontext_t *uc, int level) |
| 295 | { | 477 | { |
| 296 | return -1; | 478 | return -1; |
| 297 | } | 479 | } |
| 298 | #endif | ||
| 299 | 480 | ||
| 300 | /* emit a run time error at position 'pc' */ | 481 | #endif /* !__i386__ */ |
| 301 | void rt_error(ucontext_t *uc, const char *fmt, ...) | ||
| 302 | { | ||
| 303 | va_list ap; | ||
| 304 | unsigned long pc; | ||
| 305 | int i; | ||
| 306 | 482 | ||
| 307 | va_start(ap, fmt); | 483 | /* ------------------------------------------------------------- */ |
| 308 | fprintf(stderr, "Runtime error: "); | 484 | #else /* WIN32 */ |
| 309 | vfprintf(stderr, fmt, ap); | ||
| 310 | fprintf(stderr, "\n"); | ||
| 311 | for(i=0;i<num_callers;i++) { | ||
| 312 | if (rt_get_caller_pc(&pc, uc, i) < 0) | ||
| 313 | break; | ||
| 314 | if (i == 0) | ||
| 315 | fprintf(stderr, "at "); | ||
| 316 | else | ||
| 317 | fprintf(stderr, "by "); | ||
| 318 | pc = rt_printline(pc); | ||
| 319 | if (pc == rt_prog_main && pc) | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | exit(255); | ||
| 323 | va_end(ap); | ||
| 324 | } | ||
| 325 | 485 | ||
| 326 | /* signal handler for fatal errors */ | 486 | static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) |
| 327 | static void sig_error(int signum, siginfo_t *siginf, void *puc) | ||
| 328 | { | 487 | { |
| 329 | ucontext_t *uc = puc; | 488 | CONTEXT *uc = ex_info->ContextRecord; |
| 330 | 489 | /* | |
| 331 | switch(signum) { | 490 | EXCEPTION_RECORD *er = ex_info->ExceptionRecord; |
| 332 | case SIGFPE: | 491 | printf("CPU exception: code=%08lx addr=%p\n", |
| 333 | switch(siginf->si_code) { | 492 | er->ExceptionCode, er->ExceptionAddress); |
| 334 | case FPE_INTDIV: | 493 | */ |
| 335 | case FPE_FLTDIV: | 494 | if (rt_bound_error_msg && *rt_bound_error_msg) |
| 336 | rt_error(uc, "division by zero"); | 495 | rt_error(uc, *rt_bound_error_msg); |
| 337 | break; | 496 | else |
| 338 | default: | 497 | rt_error(uc, "dereferencing invalid pointer"); |
| 339 | rt_error(uc, "floating point exception"); | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | break; | ||
| 343 | case SIGBUS: | ||
| 344 | case SIGSEGV: | ||
| 345 | if (rt_bound_error_msg && *rt_bound_error_msg) | ||
| 346 | rt_error(uc, *rt_bound_error_msg); | ||
| 347 | else | ||
| 348 | rt_error(uc, "dereferencing invalid pointer"); | ||
| 349 | break; | ||
| 350 | case SIGILL: | ||
| 351 | rt_error(uc, "illegal instruction"); | ||
| 352 | break; | ||
| 353 | case SIGABRT: | ||
| 354 | rt_error(uc, "abort() called"); | ||
| 355 | break; | ||
| 356 | default: | ||
| 357 | rt_error(uc, "caught signal %d", signum); | ||
| 358 | break; | ||
| 359 | } | ||
| 360 | exit(255); | 498 | exit(255); |
| 499 | //return EXCEPTION_CONTINUE_SEARCH; | ||
| 361 | } | 500 | } |
| 362 | 501 | ||
| 363 | #endif /* defined CONFIG_TCC_BACKTRACE */ | 502 | /* Generate a stack backtrace when a CPU exception occurs. */ |
| 364 | 503 | static void set_exception_handler(void) | |
| 365 | /********************************************************/ | ||
| 366 | |||
| 367 | void set_pages_executable(void *ptr, unsigned long length) | ||
| 368 | { | 504 | { |
| 369 | #ifdef _WIN32 | 505 | SetUnhandledExceptionFilter(cpu_exception_handler); |
| 370 | unsigned long old_protect; | ||
| 371 | VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect); | ||
| 372 | #else | ||
| 373 | unsigned long start, end; | ||
| 374 | start = (unsigned long)ptr & ~(PAGESIZE - 1); | ||
| 375 | end = (unsigned long)ptr + length; | ||
| 376 | end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1); | ||
| 377 | mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC); | ||
| 378 | #endif | ||
| 379 | } | 506 | } |
| 380 | 507 | ||
| 381 | /* relocate code. Return -1 on error, required size if ptr is NULL, | 508 | /* return the PC at frame level 'level'. Return non zero if not found */ |
| 382 | otherwise copy code into buffer passed by the caller */ | 509 | static int rt_get_caller_pc(unsigned long *paddr, |
| 383 | static int tcc_relocate_ex(TCCState *s1, void *ptr) | 510 | CONTEXT *uc, int level) |
| 384 | { | 511 | { |
| 385 | Section *s; | 512 | unsigned long fp; |
| 386 | unsigned long offset, length; | ||
| 387 | uplong mem; | ||
| 388 | int i; | 513 | int i; |
| 389 | 514 | ||
| 390 | if (0 == s1->runtime_added) { | 515 | if (level == 0) { |
| 391 | s1->runtime_added = 1; | 516 | *paddr = uc->Eip; |
| 392 | s1->nb_errors = 0; | 517 | return 0; |
| 393 | #ifdef TCC_TARGET_PE | 518 | } else { |
| 394 | pe_output_file(s1, NULL); | 519 | fp = uc->Ebp; |
| 395 | #else | 520 | for(i=1;i<level;i++) { |
| 396 | tcc_add_runtime(s1); | 521 | /* XXX: check address validity with program info */ |
| 397 | relocate_common_syms(); | 522 | if (fp <= 0x1000 || fp >= 0xc0000000) |
| 398 | tcc_add_linker_symbols(s1); | 523 | return -1; |
| 399 | build_got_entries(s1); | 524 | fp = ((unsigned long *)fp)[0]; |
| 400 | #endif | 525 | } |
| 401 | if (s1->nb_errors) | 526 | *paddr = ((unsigned long *)fp)[1]; |
| 402 | return -1; | 527 | return 0; |
| 403 | } | ||
| 404 | |||
| 405 | offset = 0, mem = (uplong)ptr; | ||
| 406 | for(i = 1; i < s1->nb_sections; i++) { | ||
| 407 | s = s1->sections[i]; | ||
| 408 | if (0 == (s->sh_flags & SHF_ALLOC)) | ||
| 409 | continue; | ||
| 410 | length = s->data_offset; | ||
| 411 | s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0; | ||
| 412 | offset = (offset + length + 15) & ~15; | ||
| 413 | } | 528 | } |
| 414 | offset += 16; | 529 | } |
| 415 | |||
| 416 | /* relocate symbols */ | ||
| 417 | relocate_syms(s1, 1); | ||
| 418 | if (s1->nb_errors) | ||
| 419 | return -1; | ||
| 420 | |||
| 421 | #ifndef TCC_TARGET_PE | ||
| 422 | #ifdef TCC_TARGET_X86_64 | ||
| 423 | s1->runtime_plt_and_got_offset = 0; | ||
| 424 | s1->runtime_plt_and_got = (char *)(mem + offset); | ||
| 425 | /* double the size of the buffer for got and plt entries | ||
| 426 | XXX: calculate exact size for them? */ | ||
| 427 | offset *= 2; | ||
| 428 | #endif | ||
| 429 | #endif | ||
| 430 | 530 | ||
| 431 | if (0 == mem) | 531 | #endif /* _WIN32 */ |
| 432 | return offset; | 532 | #endif /* CONFIG_TCC_BACKTRACE */ |
| 533 | /* ------------------------------------------------------------- */ | ||
| 433 | 534 | ||
| 434 | /* relocate each section */ | 535 | #ifdef CONFIG_TCC_STATIC |
| 435 | for(i = 1; i < s1->nb_sections; i++) { | ||
| 436 | s = s1->sections[i]; | ||
| 437 | if (s->reloc) | ||
| 438 | relocate_section(s1, s); | ||
| 439 | } | ||
| 440 | 536 | ||
| 441 | for(i = 1; i < s1->nb_sections; i++) { | 537 | #define RTLD_LAZY 0x001 |
| 442 | s = s1->sections[i]; | 538 | #define RTLD_NOW 0x002 |
| 443 | if (0 == (s->sh_flags & SHF_ALLOC)) | 539 | #define RTLD_GLOBAL 0x100 |
| 444 | continue; | 540 | #define RTLD_DEFAULT NULL |
| 445 | length = s->data_offset; | ||
| 446 | // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length); | ||
| 447 | ptr = (void*)(uplong)s->sh_addr; | ||
| 448 | if (NULL == s->data || s->sh_type == SHT_NOBITS) | ||
| 449 | memset(ptr, 0, length); | ||
| 450 | else | ||
| 451 | memcpy(ptr, s->data, length); | ||
| 452 | /* mark executable sections as executable in memory */ | ||
| 453 | if (s->sh_flags & SHF_EXECINSTR) | ||
| 454 | set_pages_executable(ptr, length); | ||
| 455 | } | ||
| 456 | 541 | ||
| 457 | #ifndef TCC_TARGET_PE | 542 | /* dummy function for profiling */ |
| 458 | #ifdef TCC_TARGET_X86_64 | 543 | void *dlopen(const char *filename, int flag) |
| 459 | set_pages_executable(s1->runtime_plt_and_got, | 544 | { |
| 460 | s1->runtime_plt_and_got_offset); | 545 | return NULL; |
| 461 | #endif | ||
| 462 | #endif | ||
| 463 | return 0; | ||
| 464 | } | 546 | } |
| 465 | 547 | ||
| 466 | /* Do all relocations (needed before using tcc_get_symbol()) | 548 | void dlclose(void *p) |
| 467 | Returns -1 on error. */ | ||
| 468 | int tcc_relocate(TCCState *s1) | ||
| 469 | { | 549 | { |
| 470 | int ret = tcc_relocate_ex(s1, NULL); | ||
| 471 | if (-1 == ret) | ||
| 472 | return ret; | ||
| 473 | s1->runtime_mem = tcc_malloc(ret); | ||
| 474 | return tcc_relocate_ex(s1, s1->runtime_mem); | ||
| 475 | } | 550 | } |
| 476 | 551 | ||
| 477 | /* launch the compiled program with the given arguments */ | 552 | const char *dlerror(void) |
| 478 | int tcc_run(TCCState *s1, int argc, char **argv) | ||
| 479 | { | 553 | { |
| 480 | int (*prog_main)(int, char **); | 554 | return "error"; |
| 555 | } | ||
| 481 | 556 | ||
| 482 | if (tcc_relocate(s1) < 0) | 557 | typedef struct TCCSyms { |
| 483 | return -1; | 558 | char *str; |
| 559 | void *ptr; | ||
| 560 | } TCCSyms; | ||
| 484 | 561 | ||
| 485 | prog_main = tcc_get_symbol_err(s1, "main"); | 562 | #define TCCSYM(a) { #a, &a, }, |
| 486 | 563 | ||
| 487 | if (s1->do_debug) { | 564 | /* add the symbol you want here if no dynamic linking is done */ |
| 488 | #ifdef CONFIG_TCC_BACKTRACE | 565 | static TCCSyms tcc_syms[] = { |
| 489 | struct sigaction sigact; | 566 | #if !defined(CONFIG_TCCBOOT) |
| 490 | /* install TCC signal handlers to print debug info on fatal | 567 | TCCSYM(printf) |
| 491 | runtime errors */ | 568 | TCCSYM(fprintf) |
| 492 | sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; | 569 | TCCSYM(fopen) |
| 493 | sigact.sa_sigaction = sig_error; | 570 | TCCSYM(fclose) |
| 494 | sigemptyset(&sigact.sa_mask); | ||
| 495 | sigaction(SIGFPE, &sigact, NULL); | ||
| 496 | sigaction(SIGILL, &sigact, NULL); | ||
| 497 | sigaction(SIGSEGV, &sigact, NULL); | ||
| 498 | sigaction(SIGBUS, &sigact, NULL); | ||
| 499 | sigaction(SIGABRT, &sigact, NULL); | ||
| 500 | #else | ||
| 501 | error("debug mode not available"); | ||
| 502 | #endif | 571 | #endif |
| 572 | { NULL, NULL }, | ||
| 573 | }; | ||
| 574 | |||
| 575 | void *resolve_sym(TCCState *s1, const char *symbol) | ||
| 576 | { | ||
| 577 | TCCSyms *p; | ||
| 578 | p = tcc_syms; | ||
| 579 | while (p->str != NULL) { | ||
| 580 | if (!strcmp(p->str, symbol)) | ||
| 581 | return p->ptr; | ||
| 582 | p++; | ||
| 503 | } | 583 | } |
| 584 | return NULL; | ||
| 585 | } | ||
| 504 | 586 | ||
| 505 | #ifdef CONFIG_TCC_BCHECK | 587 | #elif defined(_WIN32) |
| 506 | if (s1->do_bounds_check) { | 588 | |
| 507 | void (*bound_init)(void); | 589 | #define dlclose FreeLibrary |
| 508 | void (*bound_exit)(void); | 590 | |
| 509 | /* set error function */ | 591 | #else |
| 510 | rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg"); | 592 | |
| 511 | rt_prog_main = (unsigned long)prog_main; | 593 | #include <dlfcn.h> |
| 512 | /* XXX: use .init section so that it also work in binary ? */ | 594 | |
| 513 | bound_init = tcc_get_symbol_err(s1, "__bound_init"); | 595 | void *resolve_sym(TCCState *s1, const char *sym) |
| 514 | bound_exit = tcc_get_symbol_err(s1, "__bound_exit"); | 596 | { |
| 515 | bound_init(); | 597 | return dlsym(RTLD_DEFAULT, sym); |
| 516 | ret = (*prog_main)(argc, argv); | ||
| 517 | bound_exit(); | ||
| 518 | } else | ||
| 519 | #endif | ||
| 520 | return (*prog_main)(argc, argv); | ||
| 521 | } | 598 | } |
| 522 | 599 | ||
| 523 | /********************************************************/ | 600 | #endif /* CONFIG_TCC_STATIC */ |
| 601 | |||
| 602 | /* ------------------------------------------------------------- */ | ||
| @@ -219,9 +219,11 @@ · 218 unmodified lines | |||
| 219 | DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16") | 219 | DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16") |
| 220 | DEF(TOK___bound_local_new, "__bound_local_new") | 220 | DEF(TOK___bound_local_new, "__bound_local_new") |
| 221 | DEF(TOK___bound_local_delete, "__bound_local_delete") | 221 | DEF(TOK___bound_local_delete, "__bound_local_delete") |
| 222 | #if 0 | 222 | #ifdef TCC_TARGET_PE |
| 223 | #ifndef TCC_TARGET_X86_64 | ||
| 223 | DEF(TOK_malloc, "malloc") | 224 | DEF(TOK_malloc, "malloc") |
| 224 | DEF(TOK_free, "free") | 225 | DEF(TOK_free, "free") |
| 226 | #endif | ||
| 225 | DEF(TOK_realloc, "realloc") | 227 | DEF(TOK_realloc, "realloc") |
| 226 | DEF(TOK_memalign, "memalign") | 228 | DEF(TOK_memalign, "memalign") |
| 227 | DEF(TOK_calloc, "calloc") | 229 | DEF(TOK_calloc, "calloc") |
| @@ -31,8 +31,10 @@ copy ..\libtcc.h libtcc\libtcc.h · 30 unmodified lines | |||
| 31 | :tcc | 31 | :tcc |
| 32 | %P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc | 32 | %P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc |
| 33 | 33 | ||
| 34 | :libtcc1.a | 34 | :copy_std_includes |
| 35 | copy ..\include\*.h include | 35 | copy ..\include\*.h include |
| 36 | |||
| 37 | :libtcc1.a | ||
| 36 | .\tcc -c lib/crt1.c | 38 | .\tcc -c lib/crt1.c |
| 37 | .\tcc -c lib/wincrt1.c | 39 | .\tcc -c lib/wincrt1.c |
| 38 | .\tcc -c lib/dllcrt1.c | 40 | .\tcc -c lib/dllcrt1.c |
| @@ -40,5 +42,15 @@ copy ..\include\*.h include · 1 unmodified line | |||
| 40 | .\tcc -c ../lib/libtcc1.c | 42 | .\tcc -c ../lib/libtcc1.c |
| 41 | .\tcc -c lib/chkstk.S | 43 | .\tcc -c lib/chkstk.S |
| 42 | .\tcc -c ../lib/alloca86%S%.S | 44 | .\tcc -c ../lib/alloca86%S%.S |
| 43 | tiny_libmaker lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o | 45 | |
| 46 | @set LIBFILES=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o | ||
| 47 | |||
| 48 | @if not _%P%==_ goto makelib | ||
| 49 | .\tcc -c ../lib/alloca86-bt%S%.S | ||
| 50 | .\tcc -c ../lib/bcheck.c | ||
| 51 | |||
| 52 | @set LIBFILES=%LIBFILES% alloca86-bt%S%.o bcheck.o | ||
| 53 | |||
| 54 | :makelib | ||
| 55 | tiny_libmaker lib/libtcc1.a %LIBFILES% | ||
| 44 | del *.o | 56 | del *.o |