History

win32: enable bounds checker & exception handler

exception handler borrowed from k1w1. Thanks.

grischka committed 16 years ago

Commit 7fa712e1 parent 8bbde9111 files · +421 −331Browse files

Unified · Split

11 files
  1. Makefile +2 −5
  2. i386-gen.c +5 −1
  3. lib/bcheck.c +9 −34
  4. libtcc.c +6 −2
  5. tcc.h +4 −7
  6. tccelf.c +42 −33
  7. tccgen.c +12 −1
  8. tccpe.c +3 −3
  9. tccrun.c +321 −242
  10. tcctok.h +3 −1
  11. win32/build-tcc.bat +14 −2
Makefile+2−5
@@ -78,7 +78,7 @@ ARM_CROSS = arm-tcc-fpa$(EXESUF) arm-tcc-fpa-ld$(EXESUF) \ · 77 unmodified lines
7878 arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF)
7979 C67_CROSS = c67-tcc$(EXESUF)
8080
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 \
8282 tcc.h config.h libtcc.h tcctok.h
8383 I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h
8484 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
180180
181181 ifdef CONFIG_WIN32
182182 # 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
184184 LIBTCC1_CC=./tcc.exe -Bwin32 -Iinclude $(NATIVE_TARGET)
185185 VPATH+=win32/lib
186186 endif
@@ -193,9 +193,6 @@ endif · 6 unmodified lines
193193 libtcc1.a: $(LIBTCC1_OBJS)
194194 $(AR) rcs $@ $^
195195
196−bcheck.o: bcheck.c
197− $(CC) -o $@ -c $< -O2 -Wall
198−
199196 # install
200197 TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
201198 INSTALL=install
i386-gen.c+5−1
@@ -87,8 +87,10 @@ const int reg_classes[NB_REGS] = { · 86 unmodified lines
8787 /******************************************************/
8888
8989 static unsigned long func_sub_sp_offset;
90−static unsigned long func_bound_offset;
9190 static int func_ret_sub;
91+#ifdef CONFIG_TCC_BCHECK
92+static unsigned long func_bound_offset;
93+#endif
9294
9395 /* XXX: make it faster ? */
9496 void g(int c)
@@ -511,12 +513,14 @@ void gfunc_prolog(CType *func_type) · 416 unmodified lines
511513 func_ret_sub = 4;
512514 #endif
513515
516+#ifdef CONFIG_TCC_BCHECK
514517 /* leave some room for bound checking code */
515518 if (tcc_state->do_bounds_check) {
516519 oad(0xb8, 0); /* lbound section pointer */
517520 oad(0xb8, 0); /* call to function */
518521 func_bound_offset = lbounds_section->data_offset;
519522 }
523+#endif
520524 }
521525
522526 /* generate function epilog */
lib/bcheck.c+9−34
@@ -33,12 +33,11 @@ · 32 unmodified lines
3333
3434 /* use malloc hooks. Currently the code cannot be reliable if no hooks */
3535 #define CONFIG_TCC_MALLOC_HOOKS
36−
3736 #define HAVE_MEMALIGN
3837
3938 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
40− || defined(__UCLIBC__) || defined(__OpenBSD__)
41−#warning Bound checking not fully supported in this environment.
39+ || defined(__UCLIBC__) || defined(__OpenBSD__) || defined(_WIN32)
40+#warning Bound checking does not support malloc (etc.) in this environment.
4241 #undef CONFIG_TCC_MALLOC_HOOKS
4342 #undef HAVE_MEMALIGN
4443 #endif
@@ -152,9 +151,6 @@ static void bound_alloc_error(void) · 107 unmodified lines
152151 bound_error("not enough memory for bound checking code");
153152 }
154153
155−/* currently, tcc cannot compile that because we use GNUC extensions */
156−#if !defined(__TINYC__)
157−
158154 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
159155 the end of a region in this case */
160156 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
203199 return p + offset; \
204200 }
205201
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+
206209 #ifdef __i386__
207210 /* return the frame pointer of the caller */
208211 #define GET_CALLER_FP(fp)\
@@ -246,34 +249,6 @@ void FASTCALL __bound_local_delete(void *p1) · 37 unmodified lines
246249 }
247250 }
248251
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−
277252 static BoundEntry *__bound_new_page(void)
278253 {
279254 BoundEntry *page;
libtcc.c+6−2
@@ -58,9 +58,13 @@ static Section *cur_text_section; /* current section where function code is · 57 unmodified lines
5858 #ifdef CONFIG_TCC_ASM
5959 static Section *last_text_section; /* to handle .previous asm directive */
6060 #endif
61+
62+#ifdef CONFIG_TCC_BCHECK
6163 /* bound check related sections */
6264 static Section *bounds_section; /* contains global data bound description */
6365 static Section *lbounds_section; /* contains local data bound description */
66+#endif
67+
6468 /* symbol sections */
6569 static Section *symtab_section, *strtab_section;
6670
@@ -109,8 +113,8 @@ static int tcc_ext = 1; · 42 unmodified lines
109113 /* max number of callers shown if error */
110114 #ifdef CONFIG_TCC_BACKTRACE
111115 int num_callers = 6;
116+void *rt_prog_main;
112117 const char **rt_bound_error_msg;
113−unsigned long rt_prog_main;
114118 #endif
115119
116120 /* XXX: get rid of this ASAP */
@@ -731,7 +735,7 @@ static void put_extern_sym2(Sym *sym, Section *section, · 614 unmodified lines
731735 /* if bound checking is activated, we change some function
732736 names by adding the "__bound" prefix */
733737 switch(sym->v) {
734−#if 0
738+#ifdef TCC_TARGET_PE
735739 /* XXX: we rely only on malloc hooks */
736740 case TOK_malloc:
737741 case TOK_free:
tcc.h+4−7
@@ -101,7 +101,7 @@ · 100 unmodified lines
101101 #define TCC_TARGET_I386
102102 #endif
103103
104−#if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
104+#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
105105 !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
106106 #define CONFIG_TCC_BCHECK /* enable bound checking code */
107107 #endif
@@ -120,7 +120,7 @@ · 12 unmodified lines
120120 #define TCC_TARGET_COFF
121121 #endif
122122
123−#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
123+#if !defined(CONFIG_TCCBOOT)
124124 #define CONFIG_TCC_BACKTRACE
125125 #endif
126126
@@ -465,8 +465,10 @@ struct TCCState { · 338 unmodified lines
465465 int verbose;
466466 /* compile with debug symbol (and use them if error during execution) */
467467 int do_debug;
468+#ifdef CONFIG_TCC_BCHECK
468469 /* compile with built-in memory and bounds checker */
469470 int do_bounds_check;
471+#endif
470472 /* give the path of the tcc libraries */
471473 char *tcc_lib_path;
472474
@@ -809,11 +811,6 @@ char *pstrcat(char *buf, int buf_size, const char *s); · 336 unmodified lines
809811 void dynarray_add(void ***ptab, int *nb_ptr, void *data);
810812 void dynarray_reset(void *pp, int *n);
811813
812−#ifdef CONFIG_TCC_BACKTRACE
813−extern int num_callers;
814−extern const char **rt_bound_error_msg;
815−#endif
816−
817814 /* true if float/double/long double type */
818815 static inline int is_float(int t)
819816 {
tccelf.c+42−33
@@ -1186,50 +1186,59 @@ static void add_init_array_defines(TCCState *s1, const char *section_name) · 1185 unmodified lines
11861186 s->sh_num, sym_end);
11871187 }
11881188
1189−/* add tcc runtime libraries */
1190−static void tcc_add_runtime(TCCState *s1)
1189+static void tcc_add_bcheck(TCCState *s1)
11911190 {
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+ {
11931209 char buf[1024];
1210+ snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o");
1211+ tcc_add_file(s1, buf);
1212+ }
11941213 #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);
12121214 #ifdef TCC_TARGET_I386
1213− if (s1->output_type != TCC_OUTPUT_MEMORY) {
1214− /* add 'call __bound_init()' in .init section */
1215− init_section = find_section(s1, ".init");
1216− pinit = section_ptr_add(init_section, 5);
1217− pinit[0] = 0xe8;
1218− put32(pinit + 1, -4);
1219− sym_index = find_elf_sym(symtab_section, "__bound_init");
1220− put_elf_reloc(symtab_section, init_section,
1221− init_section->data_offset - 4, R_386_PC32, sym_index);
1222− }
1223−#endif
1215+ if (s1->output_type != TCC_OUTPUT_MEMORY) {
1216+ /* add 'call __bound_init()' in .init section */
1217+ init_section = find_section(s1, ".init");
1218+ pinit = section_ptr_add(init_section, 5);
1219+ pinit[0] = 0xe8;
1220+ put32(pinit + 1, -4);
1221+ sym_index = find_elf_sym(symtab_section, "__bound_init");
1222+ put_elf_reloc(symtab_section, init_section,
1223+ init_section->data_offset - 4, R_386_PC32, sym_index);
12241224 }
12251225 #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+
12261234 /* add libc */
12271235 if (!s1->nostdlib) {
1228− tcc_add_library(s1, "c");
1229−
12301236 #ifdef CONFIG_USE_LIBGCC
1237+ tcc_add_library(s1, "c");
12311238 tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1");
12321239 #else
1240+ char buf[1024];
1241+ tcc_add_library(s1, "c");
12331242 snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a");
12341243 tcc_add_file(s1, buf);
12351244 #endif
tccgen.c+12−1
@@ -2911,8 +2911,10 @@ static void indir(void) · 2910 unmodified lines
29112911 && (vtop->type.t & VT_BTYPE) != VT_FUNC) {
29122912 vtop->r |= lvalue_type(vtop->type.t);
29132913 /* if bound checking, the referenced pointer must be checked */
2914+#ifdef CONFIG_TCC_BCHECK
29142915 if (tcc_state->do_bounds_check)
29152916 vtop->r |= VT_MUSTBOUND;
2917+#endif
29162918 }
29172919 }
29182920
@@ -3328,9 +3330,11 @@ static void unary(void) · 409 unmodified lines
33283330 /* an array is never an lvalue */
33293331 if (!(vtop->type.t & VT_ARRAY)) {
33303332 vtop->r |= lvalue_type(vtop->type.t);
3333+#ifdef CONFIG_TCC_BCHECK
33313334 /* if bound checking, the referenced pointer must be checked */
33323335 if (tcc_state->do_bounds_check)
33333336 vtop->r |= VT_MUSTBOUND;
3337+#endif
33343338 }
33353339 next();
33363340 } else if (tok == '[') {
@@ -4702,10 +4706,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 1365 unmodified lines
47024706 }
47034707 if ((r & VT_VALMASK) == VT_LOCAL) {
47044708 sec = NULL;
4709+#ifdef CONFIG_TCC_BCHECK
47054710 if (tcc_state->do_bounds_check && (type->t & VT_ARRAY))
47064711 loc--;
4712+#endif
47074713 loc = (loc - size) & -align;
47084714 addr = loc;
4715+#ifdef CONFIG_TCC_BCHECK
47094716 /* handles bounds */
47104717 /* XXX: currently, since we do only one pass, we cannot track
47114718 '&' operators, so we add only arrays */
@@ -4718,6 +4725,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 6 unmodified lines
47184725 bounds_ptr[0] = addr;
47194726 bounds_ptr[1] = size;
47204727 }
4728+#endif
47214729 if (v) {
47224730 /* local variable */
47234731 sym_push(v, type, r, addr);
@@ -4774,9 +4782,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 50 unmodified lines
47744782 /* very important to increment global pointer at this time
47754783 because initializers themselves can create new initializers */
47764784 data_offset += size;
4785+#ifdef CONFIG_TCC_BCHECK
47774786 /* add padding if bound check */
47784787 if (tcc_state->do_bounds_check)
47794788 data_offset++;
4789+#endif
47804790 sec->data_offset = data_offset;
47814791 /* allocate section space to put the data */
47824792 if (sec->sh_type != SHT_NOBITS &&
@@ -4813,7 +4823,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 30 unmodified lines
48134823 vsetc(type, VT_CONST | VT_SYM, &cval);
48144824 vtop->sym = sym;
48154825 }
4816−
4826+#ifdef CONFIG_TCC_BCHECK
48174827 /* handles bounds now because the symbol must be defined
48184828 before for the relocation */
48194829 if (tcc_state->do_bounds_check) {
@@ -4825,6 +4835,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 5 unmodified lines
48254835 bounds_ptr[0] = 0; /* relocated */
48264836 bounds_ptr[1] = size;
48274837 }
4838+#endif
48284839 }
48294840 if (has_init) {
48304841 decl_initializer(type, sec, addr, 1, 0);
tccpe.c+3−3
@@ -1700,15 +1700,15 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename) · 1699 unmodified lines
17001700 pe.filename = filename;
17011701 pe.s1 = s1;
17021702
1703+ tcc_add_bcheck(s1);
17031704 pe_add_runtime_ex(s1, &pe);
17041705 relocate_common_syms(); /* assign bss adresses */
17051706 tcc_add_linker_symbols(s1);
17061707
17071708 ret = pe_check_symbols(&pe);
17081709 if (ret)
1709− return ret;
1710−
1711− if (filename) {
1710+ ;
1711+ else if (filename) {
17121712 if (PE_DLL == pe.type) {
17131713 pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
17141714 /* XXX: check if is correct for arm-pe target */
tccrun.c+321−242
@@ -20,75 +20,167 @@ · 19 unmodified lines
2020
2121 /* tccrun.c - support for tcc -run */
2222
23+#ifdef _WIN32
24+#define ucontext_t CONTEXT
25+#endif
2326
24−/********************************************************/
25−#ifdef CONFIG_TCC_STATIC
27+static void set_pages_executable(void *ptr, unsigned long length);
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);
2632
27−#define RTLD_LAZY 0x001
28−#define RTLD_NOW 0x002
29−#define RTLD_GLOBAL 0x100
30−#define RTLD_DEFAULT NULL
33+/* ------------------------------------------------------------- */
34+/* Do all relocations (needed before using tcc_get_symbol())
35+ Returns -1 on error. */
3136
32−/* dummy function for profiling */
33−void *dlopen(const char *filename, int flag)
37+int tcc_relocate(TCCState *s1)
3438 {
35− return NULL;
36−}
39+ int ret;
3740
38−void dlclose(void *p)
39−{
41+ ret = tcc_relocate_ex(s1, NULL);
42+ if (-1 != ret) {
43+ s1->runtime_mem = tcc_malloc(ret);
44+ ret = tcc_relocate_ex(s1, s1->runtime_mem);
45+ }
46+ return ret;
4047 }
4148
42−const char *dlerror(void)
49+/* launch the compiled program with the given arguments */
50+int tcc_run(TCCState *s1, int argc, char **argv)
4351 {
44− return "error";
45−}
52+ int (*prog_main)(int, char **);
4653
47−typedef struct TCCSyms {
48− char *str;
49− void *ptr;
50−} TCCSyms;
54+ if (tcc_relocate(s1) < 0)
55+ return -1;
5156
52−#define TCCSYM(a) { #a, &a, },
57+ prog_main = tcc_get_symbol_err(s1, "main");
5358
54−/* add the symbol you want here if no dynamic linking is done */
55−static TCCSyms tcc_syms[] = {
56−#if !defined(CONFIG_TCCBOOT)
57− TCCSYM(printf)
58− TCCSYM(fprintf)
59− TCCSYM(fopen)
60− TCCSYM(fclose)
59+#ifdef CONFIG_TCC_BACKTRACE
60+ if (s1->do_debug)
61+ set_exception_handler();
6162 #endif
62− { NULL, NULL },
63−};
6463
65−void *resolve_sym(TCCState *s1, const char *symbol)
66−{
67− TCCSyms *p;
68− p = tcc_syms;
69− while (p->str != NULL) {
70− if (!strcmp(p->str, symbol))
71− return p->ptr;
72− p++;
64+#ifdef CONFIG_TCC_BCHECK
65+ if (s1->do_bounds_check) {
66+ void (*bound_init)(void);
67+ void (*bound_exit)(void);
68+ int ret;
69+ /* set error function */
70+ rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
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;
7379 }
74− return NULL;
80+#endif
81+ return (*prog_main)(argc, argv);
7582 }
7683
77−#elif defined(_WIN32)
78−#define dlclose FreeLibrary
7984
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);
8099 #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+ }
82108
83−void *resolve_sym(TCCState *s1, const char *sym)
84−{
85− return dlsym(RTLD_DEFAULT, sym);
109+ offset = 0, mem = (uplong)ptr;
110+ for(i = 1; i < s1->nb_sections; i++) {
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;
86164 }
87165
88−#endif /* defined CONFIG_TCC_STATIC */
166+/* ------------------------------------------------------------- */
167+/* allow to run code in memory */
89168
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+}
91182
183+/* ------------------------------------------------------------- */
92184 #ifdef CONFIG_TCC_BACKTRACE
93185
94186 /* 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
215307 return func_addr;
216308 }
217309
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+/* ------------------------------------------------------------- */
218394 #ifdef __i386__
395+
219396 /* fix for glibc 2.1 */
220397 #ifndef REG_EIP
221398 #define REG_EIP EIP
@@ -223,8 +400,7 @@ static unsigned long rt_printline(unsigned long wanted_pc) · 1 unmodified line
223400 #endif
224401
225402 /* return the PC at frame level 'level'. Return non zero if not found */
226−static int rt_get_caller_pc(unsigned long *paddr,
227− ucontext_t *uc, int level)
403+static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level)
228404 {
229405 unsigned long fp;
230406 int i;
@@ -256,7 +432,10 @@ static int rt_get_caller_pc(unsigned long *paddr, · 25 unmodified lines
256432 return 0;
257433 }
258434 }
435+
436+/* ------------------------------------------------------------- */
259437 #elif defined(__x86_64__)
438+
260439 /* return the PC at frame level 'level'. Return non zero if not found */
261440 static int rt_get_caller_pc(unsigned long *paddr,
262441 ucontext_t *uc, int level)
@@ -288,236 +467,136 @@ static int rt_get_caller_pc(unsigned long *paddr, · 25 unmodified lines
288467 return 0;
289468 }
290469 }
470+
471+/* ------------------------------------------------------------- */
291472 #else
473+
292474 #warning add arch specific rt_get_caller_pc()
293475 static int rt_get_caller_pc(unsigned long *paddr,
294476 ucontext_t *uc, int level)
295477 {
296478 return -1;
297479 }
298−#endif
299480
300−/* emit a run time error at position 'pc' */
301−void rt_error(ucontext_t *uc, const char *fmt, ...)
302−{
303− va_list ap;
304− unsigned long pc;
305− int i;
481+#endif /* !__i386__ */
306482
307− va_start(ap, fmt);
308− fprintf(stderr, "Runtime error: ");
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−}
483+/* ------------------------------------------------------------- */
484+#else /* WIN32 */
325485
326−/* signal handler for fatal errors */
327−static void sig_error(int signum, siginfo_t *siginf, void *puc)
486+static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
328487 {
329− ucontext_t *uc = puc;
330−
331− switch(signum) {
332− case SIGFPE:
333− switch(siginf->si_code) {
334− case FPE_INTDIV:
335− case FPE_FLTDIV:
336− rt_error(uc, "division by zero");
337− break;
338− default:
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− }
488+ CONTEXT *uc = ex_info->ContextRecord;
489+/*
490+ EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
491+ printf("CPU exception: code=%08lx addr=%p\n",
492+ er->ExceptionCode, er->ExceptionAddress);
493+*/
494+ if (rt_bound_error_msg && *rt_bound_error_msg)
495+ rt_error(uc, *rt_bound_error_msg);
496+ else
497+ rt_error(uc, "dereferencing invalid pointer");
360498 exit(255);
499+ //return EXCEPTION_CONTINUE_SEARCH;
361500 }
362501
363−#endif /* defined CONFIG_TCC_BACKTRACE */
364−
365−/********************************************************/
366−
367−void set_pages_executable(void *ptr, unsigned long length)
502+/* Generate a stack backtrace when a CPU exception occurs. */
503+static void set_exception_handler(void)
368504 {
369−#ifdef _WIN32
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
505+ SetUnhandledExceptionFilter(cpu_exception_handler);
379506 }
380507
381−/* relocate code. Return -1 on error, required size if ptr is NULL,
382− otherwise copy code into buffer passed by the caller */
383−static int tcc_relocate_ex(TCCState *s1, void *ptr)
508+/* return the PC at frame level 'level'. Return non zero if not found */
509+static int rt_get_caller_pc(unsigned long *paddr,
510+ CONTEXT *uc, int level)
384511 {
385− Section *s;
386− unsigned long offset, length;
387− uplong mem;
512+ unsigned long fp;
388513 int i;
389514
390− if (0 == s1->runtime_added) {
391− s1->runtime_added = 1;
392− s1->nb_errors = 0;
393−#ifdef TCC_TARGET_PE
394− pe_output_file(s1, NULL);
395−#else
396− tcc_add_runtime(s1);
397− relocate_common_syms();
398− tcc_add_linker_symbols(s1);
399− build_got_entries(s1);
400−#endif
401− if (s1->nb_errors)
402− return -1;
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;
515+ if (level == 0) {
516+ *paddr = uc->Eip;
517+ return 0;
518+ } else {
519+ fp = uc->Ebp;
520+ for(i=1;i<level;i++) {
521+ /* XXX: check address validity with program info */
522+ if (fp <= 0x1000 || fp >= 0xc0000000)
523+ return -1;
524+ fp = ((unsigned long *)fp)[0];
525+ }
526+ *paddr = ((unsigned long *)fp)[1];
527+ return 0;
413528 }
414− offset += 16;
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
529+}
430530
431− if (0 == mem)
432− return offset;
531+#endif /* _WIN32 */
532+#endif /* CONFIG_TCC_BACKTRACE */
533+/* ------------------------------------------------------------- */
433534
434− /* relocate each section */
435− for(i = 1; i < s1->nb_sections; i++) {
436− s = s1->sections[i];
437− if (s->reloc)
438− relocate_section(s1, s);
439− }
535+#ifdef CONFIG_TCC_STATIC
440536
441− for(i = 1; i < s1->nb_sections; i++) {
442− s = s1->sections[i];
443− if (0 == (s->sh_flags & SHF_ALLOC))
444− continue;
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− }
537+#define RTLD_LAZY 0x001
538+#define RTLD_NOW 0x002
539+#define RTLD_GLOBAL 0x100
540+#define RTLD_DEFAULT NULL
456541
457−#ifndef TCC_TARGET_PE
458−#ifdef TCC_TARGET_X86_64
459− set_pages_executable(s1->runtime_plt_and_got,
460− s1->runtime_plt_and_got_offset);
461−#endif
462−#endif
463− return 0;
542+/* dummy function for profiling */
543+void *dlopen(const char *filename, int flag)
544+{
545+ return NULL;
464546 }
465547
466−/* Do all relocations (needed before using tcc_get_symbol())
467− Returns -1 on error. */
468−int tcc_relocate(TCCState *s1)
548+void dlclose(void *p)
469549 {
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);
475550 }
476551
477−/* launch the compiled program with the given arguments */
478−int tcc_run(TCCState *s1, int argc, char **argv)
552+const char *dlerror(void)
479553 {
480− int (*prog_main)(int, char **);
554+ return "error";
555+}
481556
482− if (tcc_relocate(s1) < 0)
483− return -1;
557+typedef struct TCCSyms {
558+ char *str;
559+ void *ptr;
560+} TCCSyms;
484561
485− prog_main = tcc_get_symbol_err(s1, "main");
562+#define TCCSYM(a) { #a, &a, },
486563
487− if (s1->do_debug) {
488−#ifdef CONFIG_TCC_BACKTRACE
489− struct sigaction sigact;
490− /* install TCC signal handlers to print debug info on fatal
491− runtime errors */
492− sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
493− sigact.sa_sigaction = sig_error;
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");
564+/* add the symbol you want here if no dynamic linking is done */
565+static TCCSyms tcc_syms[] = {
566+#if !defined(CONFIG_TCCBOOT)
567+ TCCSYM(printf)
568+ TCCSYM(fprintf)
569+ TCCSYM(fopen)
570+ TCCSYM(fclose)
502571 #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++;
503583 }
584+ return NULL;
585+}
504586
505−#ifdef CONFIG_TCC_BCHECK
506− if (s1->do_bounds_check) {
507− void (*bound_init)(void);
508− void (*bound_exit)(void);
509− /* set error function */
510− rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
511− rt_prog_main = (unsigned long)prog_main;
512− /* XXX: use .init section so that it also work in binary ? */
513− bound_init = tcc_get_symbol_err(s1, "__bound_init");
514− bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
515− bound_init();
516− ret = (*prog_main)(argc, argv);
517− bound_exit();
518− } else
519−#endif
520− return (*prog_main)(argc, argv);
587+#elif defined(_WIN32)
588+
589+#define dlclose FreeLibrary
590+
591+#else
592+
593+#include <dlfcn.h>
594+
595+void *resolve_sym(TCCState *s1, const char *sym)
596+{
597+ return dlsym(RTLD_DEFAULT, sym);
521598 }
522599
523−/********************************************************/
600+#endif /* CONFIG_TCC_STATIC */
601+
602+/* ------------------------------------------------------------- */
tcctok.h+3−1
@@ -219,9 +219,11 @@ · 218 unmodified lines
219219 DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
220220 DEF(TOK___bound_local_new, "__bound_local_new")
221221 DEF(TOK___bound_local_delete, "__bound_local_delete")
222−#if 0
222+#ifdef TCC_TARGET_PE
223+#ifndef TCC_TARGET_X86_64
223224 DEF(TOK_malloc, "malloc")
224225 DEF(TOK_free, "free")
226+#endif
225227 DEF(TOK_realloc, "realloc")
226228 DEF(TOK_memalign, "memalign")
227229 DEF(TOK_calloc, "calloc")
win32/build-tcc.bat+14−2
@@ -31,8 +31,10 @@ copy ..\libtcc.h libtcc\libtcc.h · 30 unmodified lines
3131 :tcc
3232 %P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc
3333
34−:libtcc1.a
34+:copy_std_includes
3535 copy ..\include\*.h include
36+
37+:libtcc1.a
3638 .\tcc -c lib/crt1.c
3739 .\tcc -c lib/wincrt1.c
3840 .\tcc -c lib/dllcrt1.c
@@ -40,5 +42,15 @@ copy ..\include\*.h include · 1 unmodified line
4042 .\tcc -c ../lib/libtcc1.c
4143 .\tcc -c lib/chkstk.S
4244 .\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%
4456 del *.o

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t