mirror of
https://github.com/mirror/tinycc.git
synced 2025-02-24 07:50:12 +08:00
win32: enable bounds checker & exception handler
exception handler borrowed from k1w1. Thanks.
This commit is contained in:
parent
8bbde91f62
commit
7fa712e00c
7
Makefile
7
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)
|
arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF)
|
||||||
C67_CROSS = c67-tcc$(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
|
tcc.h config.h libtcc.h tcctok.h
|
||||||
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.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
|
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
|
ifdef CONFIG_WIN32
|
||||||
# for windows, we must use TCC because we generate ELF objects
|
# 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)
|
LIBTCC1_CC=./tcc.exe -Bwin32 -Iinclude $(NATIVE_TARGET)
|
||||||
VPATH+=win32/lib
|
VPATH+=win32/lib
|
||||||
endif
|
endif
|
||||||
@ -193,9 +193,6 @@ endif
|
|||||||
libtcc1.a: $(LIBTCC1_OBJS)
|
libtcc1.a: $(LIBTCC1_OBJS)
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
|
|
||||||
bcheck.o: bcheck.c
|
|
||||||
$(CC) -o $@ -c $< -O2 -Wall
|
|
||||||
|
|
||||||
# install
|
# install
|
||||||
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
|
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
|
||||||
INSTALL=install
|
INSTALL=install
|
||||||
|
@ -87,8 +87,10 @@ const int reg_classes[NB_REGS] = {
|
|||||||
/******************************************************/
|
/******************************************************/
|
||||||
|
|
||||||
static unsigned long func_sub_sp_offset;
|
static unsigned long func_sub_sp_offset;
|
||||||
static unsigned long func_bound_offset;
|
|
||||||
static int func_ret_sub;
|
static int func_ret_sub;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
static unsigned long func_bound_offset;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* XXX: make it faster ? */
|
/* XXX: make it faster ? */
|
||||||
void g(int c)
|
void g(int c)
|
||||||
@ -511,12 +513,14 @@ void gfunc_prolog(CType *func_type)
|
|||||||
func_ret_sub = 4;
|
func_ret_sub = 4;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* leave some room for bound checking code */
|
/* leave some room for bound checking code */
|
||||||
if (tcc_state->do_bounds_check) {
|
if (tcc_state->do_bounds_check) {
|
||||||
oad(0xb8, 0); /* lbound section pointer */
|
oad(0xb8, 0); /* lbound section pointer */
|
||||||
oad(0xb8, 0); /* call to function */
|
oad(0xb8, 0); /* call to function */
|
||||||
func_bound_offset = lbounds_section->data_offset;
|
func_bound_offset = lbounds_section->data_offset;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate function epilog */
|
/* generate function epilog */
|
||||||
|
43
lib/bcheck.c
43
lib/bcheck.c
@ -33,12 +33,11 @@
|
|||||||
|
|
||||||
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
|
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
|
||||||
#define CONFIG_TCC_MALLOC_HOOKS
|
#define CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
|
||||||
#define HAVE_MEMALIGN
|
#define HAVE_MEMALIGN
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
|
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
|
||||||
|| defined(__UCLIBC__) || defined(__OpenBSD__)
|
|| defined(__UCLIBC__) || defined(__OpenBSD__) || defined(_WIN32)
|
||||||
#warning Bound checking not fully supported in this environment.
|
#warning Bound checking does not support malloc (etc.) in this environment.
|
||||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||||
#undef HAVE_MEMALIGN
|
#undef HAVE_MEMALIGN
|
||||||
#endif
|
#endif
|
||||||
@ -152,9 +151,6 @@ static void bound_alloc_error(void)
|
|||||||
bound_error("not enough memory for bound checking code");
|
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
|
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||||
the end of a region in this case */
|
the end of a region in this case */
|
||||||
void * FASTCALL __bound_ptr_add(void *p, int offset)
|
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; \
|
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__
|
#ifdef __i386__
|
||||||
/* return the frame pointer of the caller */
|
/* return the frame pointer of the caller */
|
||||||
#define GET_CALLER_FP(fp)\
|
#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)
|
static BoundEntry *__bound_new_page(void)
|
||||||
{
|
{
|
||||||
BoundEntry *page;
|
BoundEntry *page;
|
||||||
|
8
libtcc.c
8
libtcc.c
@ -58,9 +58,13 @@ static Section *cur_text_section; /* current section where function code is
|
|||||||
#ifdef CONFIG_TCC_ASM
|
#ifdef CONFIG_TCC_ASM
|
||||||
static Section *last_text_section; /* to handle .previous asm directive */
|
static Section *last_text_section; /* to handle .previous asm directive */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* bound check related sections */
|
/* bound check related sections */
|
||||||
static Section *bounds_section; /* contains global data bound description */
|
static Section *bounds_section; /* contains global data bound description */
|
||||||
static Section *lbounds_section; /* contains local data bound description */
|
static Section *lbounds_section; /* contains local data bound description */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* symbol sections */
|
/* symbol sections */
|
||||||
static Section *symtab_section, *strtab_section;
|
static Section *symtab_section, *strtab_section;
|
||||||
|
|
||||||
@ -109,8 +113,8 @@ static int tcc_ext = 1;
|
|||||||
/* max number of callers shown if error */
|
/* max number of callers shown if error */
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
int num_callers = 6;
|
int num_callers = 6;
|
||||||
|
void *rt_prog_main;
|
||||||
const char **rt_bound_error_msg;
|
const char **rt_bound_error_msg;
|
||||||
unsigned long rt_prog_main;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* XXX: get rid of this ASAP */
|
/* 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
|
/* if bound checking is activated, we change some function
|
||||||
names by adding the "__bound" prefix */
|
names by adding the "__bound" prefix */
|
||||||
switch(sym->v) {
|
switch(sym->v) {
|
||||||
#if 0
|
#ifdef TCC_TARGET_PE
|
||||||
/* XXX: we rely only on malloc hooks */
|
/* XXX: we rely only on malloc hooks */
|
||||||
case TOK_malloc:
|
case TOK_malloc:
|
||||||
case TOK_free:
|
case TOK_free:
|
||||||
|
11
tcc.h
11
tcc.h
@ -101,7 +101,7 @@
|
|||||||
#define TCC_TARGET_I386
|
#define TCC_TARGET_I386
|
||||||
#endif
|
#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)
|
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
|
||||||
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
||||||
#endif
|
#endif
|
||||||
@ -120,7 +120,7 @@
|
|||||||
#define TCC_TARGET_COFF
|
#define TCC_TARGET_COFF
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
|
#if !defined(CONFIG_TCCBOOT)
|
||||||
#define CONFIG_TCC_BACKTRACE
|
#define CONFIG_TCC_BACKTRACE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -465,8 +465,10 @@ struct TCCState {
|
|||||||
int verbose;
|
int verbose;
|
||||||
/* compile with debug symbol (and use them if error during execution) */
|
/* compile with debug symbol (and use them if error during execution) */
|
||||||
int do_debug;
|
int do_debug;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* compile with built-in memory and bounds checker */
|
/* compile with built-in memory and bounds checker */
|
||||||
int do_bounds_check;
|
int do_bounds_check;
|
||||||
|
#endif
|
||||||
/* give the path of the tcc libraries */
|
/* give the path of the tcc libraries */
|
||||||
char *tcc_lib_path;
|
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_add(void ***ptab, int *nb_ptr, void *data);
|
||||||
void dynarray_reset(void *pp, int *n);
|
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 */
|
/* true if float/double/long double type */
|
||||||
static inline int is_float(int t)
|
static inline int is_float(int t)
|
||||||
{
|
{
|
||||||
|
79
tccelf.c
79
tccelf.c
@ -1186,50 +1186,59 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
|
|||||||
s->sh_num, sym_end);
|
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 */
|
/* add tcc runtime libraries */
|
||||||
static void tcc_add_runtime(TCCState *s1)
|
static void tcc_add_runtime(TCCState *s1)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_TCC_BCHECK) || !defined(CONFIG_USE_LIBGCC)
|
tcc_add_bcheck(s1);
|
||||||
char buf[1024];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
|
||||||
if (s1->do_bounds_check) {
|
|
||||||
unsigned long *ptr;
|
|
||||||
Section *init_section;
|
|
||||||
unsigned char *pinit;
|
|
||||||
int sym_index;
|
|
||||||
|
|
||||||
/* 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 */
|
/* add libc */
|
||||||
if (!s1->nostdlib) {
|
if (!s1->nostdlib) {
|
||||||
tcc_add_library(s1, "c");
|
|
||||||
|
|
||||||
#ifdef CONFIG_USE_LIBGCC
|
#ifdef CONFIG_USE_LIBGCC
|
||||||
|
tcc_add_library(s1, "c");
|
||||||
tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1");
|
tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1");
|
||||||
#else
|
#else
|
||||||
|
char buf[1024];
|
||||||
|
tcc_add_library(s1, "c");
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a");
|
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a");
|
||||||
tcc_add_file(s1, buf);
|
tcc_add_file(s1, buf);
|
||||||
#endif
|
#endif
|
||||||
|
13
tccgen.c
13
tccgen.c
@ -2911,8 +2911,10 @@ static void indir(void)
|
|||||||
&& (vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
&& (vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||||
vtop->r |= lvalue_type(vtop->type.t);
|
vtop->r |= lvalue_type(vtop->type.t);
|
||||||
/* if bound checking, the referenced pointer must be checked */
|
/* if bound checking, the referenced pointer must be checked */
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (tcc_state->do_bounds_check)
|
if (tcc_state->do_bounds_check)
|
||||||
vtop->r |= VT_MUSTBOUND;
|
vtop->r |= VT_MUSTBOUND;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3328,9 +3330,11 @@ static void unary(void)
|
|||||||
/* an array is never an lvalue */
|
/* an array is never an lvalue */
|
||||||
if (!(vtop->type.t & VT_ARRAY)) {
|
if (!(vtop->type.t & VT_ARRAY)) {
|
||||||
vtop->r |= lvalue_type(vtop->type.t);
|
vtop->r |= lvalue_type(vtop->type.t);
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* if bound checking, the referenced pointer must be checked */
|
/* if bound checking, the referenced pointer must be checked */
|
||||||
if (tcc_state->do_bounds_check)
|
if (tcc_state->do_bounds_check)
|
||||||
vtop->r |= VT_MUSTBOUND;
|
vtop->r |= VT_MUSTBOUND;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
} else if (tok == '[') {
|
} else if (tok == '[') {
|
||||||
@ -4702,10 +4706,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
}
|
}
|
||||||
if ((r & VT_VALMASK) == VT_LOCAL) {
|
if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||||
sec = NULL;
|
sec = NULL;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY))
|
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY))
|
||||||
loc--;
|
loc--;
|
||||||
|
#endif
|
||||||
loc = (loc - size) & -align;
|
loc = (loc - size) & -align;
|
||||||
addr = loc;
|
addr = loc;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* handles bounds */
|
/* handles bounds */
|
||||||
/* XXX: currently, since we do only one pass, we cannot track
|
/* XXX: currently, since we do only one pass, we cannot track
|
||||||
'&' operators, so we add only arrays */
|
'&' 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[0] = addr;
|
||||||
bounds_ptr[1] = size;
|
bounds_ptr[1] = size;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (v) {
|
if (v) {
|
||||||
/* local variable */
|
/* local variable */
|
||||||
sym_push(v, type, r, addr);
|
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
|
/* very important to increment global pointer at this time
|
||||||
because initializers themselves can create new initializers */
|
because initializers themselves can create new initializers */
|
||||||
data_offset += size;
|
data_offset += size;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* add padding if bound check */
|
/* add padding if bound check */
|
||||||
if (tcc_state->do_bounds_check)
|
if (tcc_state->do_bounds_check)
|
||||||
data_offset++;
|
data_offset++;
|
||||||
|
#endif
|
||||||
sec->data_offset = data_offset;
|
sec->data_offset = data_offset;
|
||||||
/* allocate section space to put the data */
|
/* allocate section space to put the data */
|
||||||
if (sec->sh_type != SHT_NOBITS &&
|
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);
|
vsetc(type, VT_CONST | VT_SYM, &cval);
|
||||||
vtop->sym = sym;
|
vtop->sym = sym;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* handles bounds now because the symbol must be defined
|
/* handles bounds now because the symbol must be defined
|
||||||
before for the relocation */
|
before for the relocation */
|
||||||
if (tcc_state->do_bounds_check) {
|
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[0] = 0; /* relocated */
|
||||||
bounds_ptr[1] = size;
|
bounds_ptr[1] = size;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (has_init) {
|
if (has_init) {
|
||||||
decl_initializer(type, sec, addr, 1, 0);
|
decl_initializer(type, sec, addr, 1, 0);
|
||||||
|
6
tccpe.c
6
tccpe.c
@ -1700,15 +1700,15 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename)
|
|||||||
pe.filename = filename;
|
pe.filename = filename;
|
||||||
pe.s1 = s1;
|
pe.s1 = s1;
|
||||||
|
|
||||||
|
tcc_add_bcheck(s1);
|
||||||
pe_add_runtime_ex(s1, &pe);
|
pe_add_runtime_ex(s1, &pe);
|
||||||
relocate_common_syms(); /* assign bss adresses */
|
relocate_common_syms(); /* assign bss adresses */
|
||||||
tcc_add_linker_symbols(s1);
|
tcc_add_linker_symbols(s1);
|
||||||
|
|
||||||
ret = pe_check_symbols(&pe);
|
ret = pe_check_symbols(&pe);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
;
|
||||||
|
else if (filename) {
|
||||||
if (filename) {
|
|
||||||
if (PE_DLL == pe.type) {
|
if (PE_DLL == pe.type) {
|
||||||
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
|
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
|
||||||
/* XXX: check if is correct for arm-pe target */
|
/* XXX: check if is correct for arm-pe target */
|
||||||
|
659
tccrun.c
659
tccrun.c
@ -20,75 +20,167 @@
|
|||||||
|
|
||||||
/* tccrun.c - support for tcc -run */
|
/* tccrun.c - support for tcc -run */
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
/********************************************************/
|
#define ucontext_t CONTEXT
|
||||||
#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
|
#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;
|
int ret;
|
||||||
p = tcc_syms;
|
|
||||||
while (p->str != NULL) {
|
ret = tcc_relocate_ex(s1, NULL);
|
||||||
if (!strcmp(p->str, symbol))
|
if (-1 != ret) {
|
||||||
return p->ptr;
|
s1->runtime_mem = tcc_malloc(ret);
|
||||||
p++;
|
ret = tcc_relocate_ex(s1, s1->runtime_mem);
|
||||||
}
|
}
|
||||||
return NULL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
/* launch the compiled program with the given arguments */
|
||||||
#define dlclose FreeLibrary
|
int tcc_run(TCCState *s1, int argc, char **argv)
|
||||||
|
|
||||||
#else
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
void *resolve_sym(TCCState *s1, const char *sym)
|
|
||||||
{
|
{
|
||||||
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
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
|
||||||
/* print the position in the source file of PC value 'pc' by reading
|
/* 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;
|
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<level;i++) {
|
|
||||||
/* XXX: check address validity with program info */
|
|
||||||
if (fp <= 0x1000 || fp >= 0xc0000000)
|
|
||||||
return -1;
|
|
||||||
fp = ((unsigned long *)fp)[0];
|
|
||||||
}
|
|
||||||
*paddr = ((unsigned long *)fp)[1];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#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;i<level;i++) {
|
|
||||||
/* XXX: check address validity with program info */
|
|
||||||
if (fp <= 0x1000)
|
|
||||||
return -1;
|
|
||||||
fp = ((unsigned long *)fp)[0];
|
|
||||||
}
|
|
||||||
*paddr = ((unsigned long *)fp)[1];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#warning add arch specific rt_get_caller_pc()
|
|
||||||
static int rt_get_caller_pc(unsigned long *paddr,
|
|
||||||
ucontext_t *uc, int level)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* emit a run time error at position 'pc' */
|
/* emit a run time error at position 'pc' */
|
||||||
void rt_error(ucontext_t *uc, const char *fmt, ...)
|
static void rt_error(ucontext_t *uc, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
unsigned long pc;
|
unsigned long pc;
|
||||||
@ -308,6 +318,7 @@ void rt_error(ucontext_t *uc, const char *fmt, ...)
|
|||||||
fprintf(stderr, "Runtime error: ");
|
fprintf(stderr, "Runtime error: ");
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
for(i=0;i<num_callers;i++) {
|
for(i=0;i<num_callers;i++) {
|
||||||
if (rt_get_caller_pc(&pc, uc, i) < 0)
|
if (rt_get_caller_pc(&pc, uc, i) < 0)
|
||||||
break;
|
break;
|
||||||
@ -316,13 +327,16 @@ void rt_error(ucontext_t *uc, const char *fmt, ...)
|
|||||||
else
|
else
|
||||||
fprintf(stderr, "by ");
|
fprintf(stderr, "by ");
|
||||||
pc = rt_printline(pc);
|
pc = rt_printline(pc);
|
||||||
if (pc == rt_prog_main && pc)
|
if (pc == (unsigned long)rt_prog_main && pc)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exit(255);
|
exit(255);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
/* signal handler for fatal errors */
|
/* signal handler for fatal errors */
|
||||||
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||||
{
|
{
|
||||||
@ -360,164 +374,229 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
|||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined CONFIG_TCC_BACKTRACE */
|
/* Generate a stack backtrace when a CPU exception occurs. */
|
||||||
|
static void set_exception_handler(void)
|
||||||
/********************************************************/
|
|
||||||
|
|
||||||
void set_pages_executable(void *ptr, unsigned long length)
|
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
struct sigaction sigact;
|
||||||
unsigned long old_protect;
|
/* install TCC signal handlers to print debug info on fatal
|
||||||
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
runtime errors */
|
||||||
#else
|
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||||
unsigned long start, end;
|
sigact.sa_sigaction = sig_error;
|
||||||
start = (unsigned long)ptr & ~(PAGESIZE - 1);
|
sigemptyset(&sigact.sa_mask);
|
||||||
end = (unsigned long)ptr + length;
|
sigaction(SIGFPE, &sigact, NULL);
|
||||||
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
|
sigaction(SIGILL, &sigact, NULL);
|
||||||
mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
|
sigaction(SIGSEGV, &sigact, NULL);
|
||||||
#endif
|
sigaction(SIGBUS, &sigact, NULL);
|
||||||
|
sigaction(SIGABRT, &sigact, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* relocate code. Return -1 on error, required size if ptr is NULL,
|
/* ------------------------------------------------------------- */
|
||||||
otherwise copy code into buffer passed by the caller */
|
#ifdef __i386__
|
||||||
static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
|
||||||
|
/* 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)
|
||||||
{
|
{
|
||||||
Section *s;
|
unsigned long fp;
|
||||||
unsigned long offset, length;
|
|
||||||
uplong mem;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (0 == s1->runtime_added) {
|
if (level == 0) {
|
||||||
s1->runtime_added = 1;
|
#if defined(__FreeBSD__)
|
||||||
s1->nb_errors = 0;
|
*paddr = uc->uc_mcontext.mc_eip;
|
||||||
#ifdef TCC_TARGET_PE
|
#elif defined(__dietlibc__)
|
||||||
pe_output_file(s1, NULL);
|
*paddr = uc->uc_mcontext.eip;
|
||||||
#else
|
#else
|
||||||
tcc_add_runtime(s1);
|
*paddr = uc->uc_mcontext.gregs[REG_EIP];
|
||||||
relocate_common_syms();
|
|
||||||
tcc_add_linker_symbols(s1);
|
|
||||||
build_got_entries(s1);
|
|
||||||
#endif
|
#endif
|
||||||
if (s1->nb_errors)
|
return 0;
|
||||||
return -1;
|
} else {
|
||||||
}
|
#if defined(__FreeBSD__)
|
||||||
|
fp = uc->uc_mcontext.mc_ebp;
|
||||||
offset = 0, mem = (uplong)ptr;
|
#elif defined(__dietlibc__)
|
||||||
for(i = 1; i < s1->nb_sections; i++) {
|
fp = uc->uc_mcontext.ebp;
|
||||||
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);
|
|
||||||
#else
|
#else
|
||||||
error("debug mode not available");
|
fp = uc->uc_mcontext.gregs[REG_EBP];
|
||||||
#endif
|
#endif
|
||||||
|
for(i=1;i<level;i++) {
|
||||||
|
/* XXX: check address validity with program info */
|
||||||
|
if (fp <= 0x1000 || fp >= 0xc0000000)
|
||||||
|
return -1;
|
||||||
|
fp = ((unsigned long *)fp)[0];
|
||||||
|
}
|
||||||
|
*paddr = ((unsigned long *)fp)[1];
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#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;i<level;i++) {
|
||||||
|
/* XXX: check address validity with program info */
|
||||||
|
if (fp <= 0x1000)
|
||||||
|
return -1;
|
||||||
|
fp = ((unsigned long *)fp)[0];
|
||||||
|
}
|
||||||
|
*paddr = ((unsigned long *)fp)[1];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
#else
|
||||||
|
|
||||||
|
#warning add arch specific rt_get_caller_pc()
|
||||||
|
static int rt_get_caller_pc(unsigned long *paddr,
|
||||||
|
ucontext_t *uc, int level)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !__i386__ */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
#else /* WIN32 */
|
||||||
|
|
||||||
|
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||||
|
{
|
||||||
|
CONTEXT *uc = ex_info->ContextRecord;
|
||||||
|
/*
|
||||||
|
EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
|
||||||
|
printf("CPU exception: code=%08lx addr=%p\n",
|
||||||
|
er->ExceptionCode, er->ExceptionAddress);
|
||||||
|
*/
|
||||||
|
if (rt_bound_error_msg && *rt_bound_error_msg)
|
||||||
|
rt_error(uc, *rt_bound_error_msg);
|
||||||
|
else
|
||||||
|
rt_error(uc, "dereferencing invalid pointer");
|
||||||
|
exit(255);
|
||||||
|
//return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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<level;i++) {
|
||||||
|
/* XXX: check address validity with program info */
|
||||||
|
if (fp <= 0x1000 || fp >= 0xc0000000)
|
||||||
|
return -1;
|
||||||
|
fp = ((unsigned long *)fp)[0];
|
||||||
|
}
|
||||||
|
*paddr = ((unsigned long *)fp)[1];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 <dlfcn.h>
|
||||||
|
|
||||||
|
void *resolve_sym(TCCState *s1, const char *sym)
|
||||||
|
{
|
||||||
|
return dlsym(RTLD_DEFAULT, sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_TCC_STATIC */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
4
tcctok.h
4
tcctok.h
@ -219,9 +219,11 @@
|
|||||||
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
|
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
|
||||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
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_malloc, "malloc")
|
||||||
DEF(TOK_free, "free")
|
DEF(TOK_free, "free")
|
||||||
|
#endif
|
||||||
DEF(TOK_realloc, "realloc")
|
DEF(TOK_realloc, "realloc")
|
||||||
DEF(TOK_memalign, "memalign")
|
DEF(TOK_memalign, "memalign")
|
||||||
DEF(TOK_calloc, "calloc")
|
DEF(TOK_calloc, "calloc")
|
||||||
|
@ -31,8 +31,10 @@ copy ..\libtcc.h libtcc\libtcc.h
|
|||||||
:tcc
|
:tcc
|
||||||
%P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc
|
%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
|
copy ..\include\*.h include
|
||||||
|
|
||||||
|
:libtcc1.a
|
||||||
.\tcc -c lib/crt1.c
|
.\tcc -c lib/crt1.c
|
||||||
.\tcc -c lib/wincrt1.c
|
.\tcc -c lib/wincrt1.c
|
||||||
.\tcc -c lib/dllcrt1.c
|
.\tcc -c lib/dllcrt1.c
|
||||||
@ -40,5 +42,15 @@ copy ..\include\*.h include
|
|||||||
.\tcc -c ../lib/libtcc1.c
|
.\tcc -c ../lib/libtcc1.c
|
||||||
.\tcc -c lib/chkstk.S
|
.\tcc -c lib/chkstk.S
|
||||||
.\tcc -c ../lib/alloca86%S%.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
|
del *.o
|
||||||
|
Loading…
Reference in New Issue
Block a user