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)
|
||||
C67_CROSS = c67-tcc$(EXESUF)
|
||||
|
||||
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c \
|
||||
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c \
|
||||
tcc.h config.h libtcc.h tcctok.h
|
||||
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h
|
||||
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
|
||||
@ -180,7 +180,7 @@ VPATH+=lib
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
# for windows, we must use TCC because we generate ELF objects
|
||||
LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
|
||||
LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o bcheck.o
|
||||
LIBTCC1_CC=./tcc.exe -Bwin32 -Iinclude $(NATIVE_TARGET)
|
||||
VPATH+=win32/lib
|
||||
endif
|
||||
@ -193,9 +193,6 @@ endif
|
||||
libtcc1.a: $(LIBTCC1_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
bcheck.o: bcheck.c
|
||||
$(CC) -o $@ -c $< -O2 -Wall
|
||||
|
||||
# install
|
||||
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
|
||||
INSTALL=install
|
||||
|
@ -87,8 +87,10 @@ const int reg_classes[NB_REGS] = {
|
||||
/******************************************************/
|
||||
|
||||
static unsigned long func_sub_sp_offset;
|
||||
static unsigned long func_bound_offset;
|
||||
static int func_ret_sub;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static unsigned long func_bound_offset;
|
||||
#endif
|
||||
|
||||
/* XXX: make it faster ? */
|
||||
void g(int c)
|
||||
@ -511,12 +513,14 @@ void gfunc_prolog(CType *func_type)
|
||||
func_ret_sub = 4;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* leave some room for bound checking code */
|
||||
if (tcc_state->do_bounds_check) {
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* generate function epilog */
|
||||
|
43
lib/bcheck.c
43
lib/bcheck.c
@ -33,12 +33,11 @@
|
||||
|
||||
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
|
||||
#define CONFIG_TCC_MALLOC_HOOKS
|
||||
|
||||
#define HAVE_MEMALIGN
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__)
|
||||
#warning Bound checking not fully supported in this environment.
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__) || defined(_WIN32)
|
||||
#warning Bound checking does not support malloc (etc.) in this environment.
|
||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||
#undef HAVE_MEMALIGN
|
||||
#endif
|
||||
@ -152,9 +151,6 @@ static void bound_alloc_error(void)
|
||||
bound_error("not enough memory for bound checking code");
|
||||
}
|
||||
|
||||
/* currently, tcc cannot compile that because we use GNUC extensions */
|
||||
#if !defined(__TINYC__)
|
||||
|
||||
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||
the end of a region in this case */
|
||||
void * FASTCALL __bound_ptr_add(void *p, int offset)
|
||||
@ -203,6 +199,13 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
|
||||
return p + offset; \
|
||||
}
|
||||
|
||||
BOUND_PTR_INDIR(1)
|
||||
BOUND_PTR_INDIR(2)
|
||||
BOUND_PTR_INDIR(4)
|
||||
BOUND_PTR_INDIR(8)
|
||||
BOUND_PTR_INDIR(12)
|
||||
BOUND_PTR_INDIR(16)
|
||||
|
||||
#ifdef __i386__
|
||||
/* return the frame pointer of the caller */
|
||||
#define GET_CALLER_FP(fp)\
|
||||
@ -246,34 +249,6 @@ void FASTCALL __bound_local_delete(void *p1)
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void __bound_local_new(void *p)
|
||||
{
|
||||
}
|
||||
void __bound_local_delete(void *p)
|
||||
{
|
||||
}
|
||||
|
||||
void *__bound_ptr_add(void *p, int offset)
|
||||
{
|
||||
return p + offset;
|
||||
}
|
||||
|
||||
#define BOUND_PTR_INDIR(dsize) \
|
||||
void *__bound_ptr_indir ## dsize (void *p, int offset) \
|
||||
{ \
|
||||
return p + offset; \
|
||||
}
|
||||
#endif
|
||||
|
||||
BOUND_PTR_INDIR(1)
|
||||
BOUND_PTR_INDIR(2)
|
||||
BOUND_PTR_INDIR(4)
|
||||
BOUND_PTR_INDIR(8)
|
||||
BOUND_PTR_INDIR(12)
|
||||
BOUND_PTR_INDIR(16)
|
||||
|
||||
static BoundEntry *__bound_new_page(void)
|
||||
{
|
||||
BoundEntry *page;
|
||||
|
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
|
||||
static Section *last_text_section; /* to handle .previous asm directive */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* bound check related sections */
|
||||
static Section *bounds_section; /* contains global data bound description */
|
||||
static Section *lbounds_section; /* contains local data bound description */
|
||||
#endif
|
||||
|
||||
/* symbol sections */
|
||||
static Section *symtab_section, *strtab_section;
|
||||
|
||||
@ -109,8 +113,8 @@ static int tcc_ext = 1;
|
||||
/* max number of callers shown if error */
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
int num_callers = 6;
|
||||
void *rt_prog_main;
|
||||
const char **rt_bound_error_msg;
|
||||
unsigned long rt_prog_main;
|
||||
#endif
|
||||
|
||||
/* XXX: get rid of this ASAP */
|
||||
@ -731,7 +735,7 @@ static void put_extern_sym2(Sym *sym, Section *section,
|
||||
/* if bound checking is activated, we change some function
|
||||
names by adding the "__bound" prefix */
|
||||
switch(sym->v) {
|
||||
#if 0
|
||||
#ifdef TCC_TARGET_PE
|
||||
/* XXX: we rely only on malloc hooks */
|
||||
case TOK_malloc:
|
||||
case TOK_free:
|
||||
|
11
tcc.h
11
tcc.h
@ -101,7 +101,7 @@
|
||||
#define TCC_TARGET_I386
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
|
||||
#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
|
||||
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
|
||||
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
||||
#endif
|
||||
@ -120,7 +120,7 @@
|
||||
#define TCC_TARGET_COFF
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
|
||||
#if !defined(CONFIG_TCCBOOT)
|
||||
#define CONFIG_TCC_BACKTRACE
|
||||
#endif
|
||||
|
||||
@ -465,8 +465,10 @@ struct TCCState {
|
||||
int verbose;
|
||||
/* compile with debug symbol (and use them if error during execution) */
|
||||
int do_debug;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* compile with built-in memory and bounds checker */
|
||||
int do_bounds_check;
|
||||
#endif
|
||||
/* give the path of the tcc libraries */
|
||||
char *tcc_lib_path;
|
||||
|
||||
@ -809,11 +811,6 @@ char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
void dynarray_add(void ***ptab, int *nb_ptr, void *data);
|
||||
void dynarray_reset(void *pp, int *n);
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
extern int num_callers;
|
||||
extern const char **rt_bound_error_msg;
|
||||
#endif
|
||||
|
||||
/* true if float/double/long double type */
|
||||
static inline int is_float(int t)
|
||||
{
|
||||
|
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);
|
||||
}
|
||||
|
||||
static void tcc_add_bcheck(TCCState *s1)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
unsigned long *ptr;
|
||||
Section *init_section;
|
||||
unsigned char *pinit;
|
||||
int sym_index;
|
||||
|
||||
if (0 == s1->do_bounds_check)
|
||||
return;
|
||||
|
||||
/* XXX: add an object file to do that */
|
||||
ptr = section_ptr_add(bounds_section, sizeof(unsigned long));
|
||||
*ptr = 0;
|
||||
add_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
bounds_section->sh_num, "__bounds_start");
|
||||
/* add bound check code */
|
||||
#ifndef TCC_TARGET_PE
|
||||
{
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o");
|
||||
tcc_add_file(s1, buf);
|
||||
}
|
||||
#endif
|
||||
#ifdef TCC_TARGET_I386
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
init_section = find_section(s1, ".init");
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
put32(pinit + 1, -4);
|
||||
sym_index = find_elf_sym(symtab_section, "__bound_init");
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* add tcc runtime libraries */
|
||||
static void tcc_add_runtime(TCCState *s1)
|
||||
{
|
||||
#if defined(CONFIG_TCC_BCHECK) || !defined(CONFIG_USE_LIBGCC)
|
||||
char buf[1024];
|
||||
#endif
|
||||
tcc_add_bcheck(s1);
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
unsigned long *ptr;
|
||||
Section *init_section;
|
||||
unsigned char *pinit;
|
||||
int sym_index;
|
||||
|
||||
/* XXX: add an object file to do that */
|
||||
ptr = section_ptr_add(bounds_section, sizeof(unsigned long));
|
||||
*ptr = 0;
|
||||
add_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
bounds_section->sh_num, "__bounds_start");
|
||||
/* add bound check code */
|
||||
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o");
|
||||
tcc_add_file(s1, buf);
|
||||
#ifdef TCC_TARGET_I386
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
init_section = find_section(s1, ".init");
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
put32(pinit + 1, -4);
|
||||
sym_index = find_elf_sym(symtab_section, "__bound_init");
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* add libc */
|
||||
if (!s1->nostdlib) {
|
||||
tcc_add_library(s1, "c");
|
||||
|
||||
#ifdef CONFIG_USE_LIBGCC
|
||||
tcc_add_library(s1, "c");
|
||||
tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1");
|
||||
#else
|
||||
char buf[1024];
|
||||
tcc_add_library(s1, "c");
|
||||
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a");
|
||||
tcc_add_file(s1, buf);
|
||||
#endif
|
||||
|
13
tccgen.c
13
tccgen.c
@ -2911,8 +2911,10 @@ static void indir(void)
|
||||
&& (vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||
vtop->r |= lvalue_type(vtop->type.t);
|
||||
/* if bound checking, the referenced pointer must be checked */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
vtop->r |= VT_MUSTBOUND;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -3328,9 +3330,11 @@ static void unary(void)
|
||||
/* an array is never an lvalue */
|
||||
if (!(vtop->type.t & VT_ARRAY)) {
|
||||
vtop->r |= lvalue_type(vtop->type.t);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* if bound checking, the referenced pointer must be checked */
|
||||
if (tcc_state->do_bounds_check)
|
||||
vtop->r |= VT_MUSTBOUND;
|
||||
#endif
|
||||
}
|
||||
next();
|
||||
} else if (tok == '[') {
|
||||
@ -4702,10 +4706,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
}
|
||||
if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||
sec = NULL;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY))
|
||||
loc--;
|
||||
#endif
|
||||
loc = (loc - size) & -align;
|
||||
addr = loc;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* handles bounds */
|
||||
/* XXX: currently, since we do only one pass, we cannot track
|
||||
'&' operators, so we add only arrays */
|
||||
@ -4718,6 +4725,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
bounds_ptr[0] = addr;
|
||||
bounds_ptr[1] = size;
|
||||
}
|
||||
#endif
|
||||
if (v) {
|
||||
/* local variable */
|
||||
sym_push(v, type, r, addr);
|
||||
@ -4774,9 +4782,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
/* very important to increment global pointer at this time
|
||||
because initializers themselves can create new initializers */
|
||||
data_offset += size;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* add padding if bound check */
|
||||
if (tcc_state->do_bounds_check)
|
||||
data_offset++;
|
||||
#endif
|
||||
sec->data_offset = data_offset;
|
||||
/* allocate section space to put the data */
|
||||
if (sec->sh_type != SHT_NOBITS &&
|
||||
@ -4813,7 +4823,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
vsetc(type, VT_CONST | VT_SYM, &cval);
|
||||
vtop->sym = sym;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* handles bounds now because the symbol must be defined
|
||||
before for the relocation */
|
||||
if (tcc_state->do_bounds_check) {
|
||||
@ -4825,6 +4835,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
bounds_ptr[0] = 0; /* relocated */
|
||||
bounds_ptr[1] = size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (has_init) {
|
||||
decl_initializer(type, sec, addr, 1, 0);
|
||||
|
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.s1 = s1;
|
||||
|
||||
tcc_add_bcheck(s1);
|
||||
pe_add_runtime_ex(s1, &pe);
|
||||
relocate_common_syms(); /* assign bss adresses */
|
||||
tcc_add_linker_symbols(s1);
|
||||
|
||||
ret = pe_check_symbols(&pe);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (filename) {
|
||||
;
|
||||
else if (filename) {
|
||||
if (PE_DLL == pe.type) {
|
||||
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
|
||||
/* XXX: check if is correct for arm-pe target */
|
||||
|
659
tccrun.c
659
tccrun.c
@ -20,75 +20,167 @@
|
||||
|
||||
/* tccrun.c - support for tcc -run */
|
||||
|
||||
|
||||
/********************************************************/
|
||||
#ifdef CONFIG_TCC_STATIC
|
||||
|
||||
#define RTLD_LAZY 0x001
|
||||
#define RTLD_NOW 0x002
|
||||
#define RTLD_GLOBAL 0x100
|
||||
#define RTLD_DEFAULT NULL
|
||||
|
||||
/* dummy function for profiling */
|
||||
void *dlopen(const char *filename, int flag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dlclose(void *p)
|
||||
{
|
||||
}
|
||||
|
||||
const char *dlerror(void)
|
||||
{
|
||||
return "error";
|
||||
}
|
||||
|
||||
typedef struct TCCSyms {
|
||||
char *str;
|
||||
void *ptr;
|
||||
} TCCSyms;
|
||||
|
||||
#define TCCSYM(a) { #a, &a, },
|
||||
|
||||
/* add the symbol you want here if no dynamic linking is done */
|
||||
static TCCSyms tcc_syms[] = {
|
||||
#if !defined(CONFIG_TCCBOOT)
|
||||
TCCSYM(printf)
|
||||
TCCSYM(fprintf)
|
||||
TCCSYM(fopen)
|
||||
TCCSYM(fclose)
|
||||
#ifdef _WIN32
|
||||
#define ucontext_t CONTEXT
|
||||
#endif
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
void *resolve_sym(TCCState *s1, const char *symbol)
|
||||
static void set_pages_executable(void *ptr, unsigned long length);
|
||||
static void set_exception_handler(void);
|
||||
static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level);
|
||||
static void rt_error(ucontext_t *uc, const char *fmt, ...);
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr);
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* Do all relocations (needed before using tcc_get_symbol())
|
||||
Returns -1 on error. */
|
||||
|
||||
int tcc_relocate(TCCState *s1)
|
||||
{
|
||||
TCCSyms *p;
|
||||
p = tcc_syms;
|
||||
while (p->str != NULL) {
|
||||
if (!strcmp(p->str, symbol))
|
||||
return p->ptr;
|
||||
p++;
|
||||
int ret;
|
||||
|
||||
ret = tcc_relocate_ex(s1, NULL);
|
||||
if (-1 != ret) {
|
||||
s1->runtime_mem = tcc_malloc(ret);
|
||||
ret = tcc_relocate_ex(s1, s1->runtime_mem);
|
||||
}
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#define dlclose FreeLibrary
|
||||
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
|
||||
void *resolve_sym(TCCState *s1, const char *sym)
|
||||
/* launch the compiled program with the given arguments */
|
||||
int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
return dlsym(RTLD_DEFAULT, sym);
|
||||
int (*prog_main)(int, char **);
|
||||
|
||||
if (tcc_relocate(s1) < 0)
|
||||
return -1;
|
||||
|
||||
prog_main = tcc_get_symbol_err(s1, "main");
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
if (s1->do_debug)
|
||||
set_exception_handler();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
void (*bound_init)(void);
|
||||
void (*bound_exit)(void);
|
||||
int ret;
|
||||
/* set error function */
|
||||
rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
|
||||
rt_prog_main = prog_main;
|
||||
/* XXX: use .init section so that it also work in binary ? */
|
||||
bound_init = tcc_get_symbol_err(s1, "__bound_init");
|
||||
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
|
||||
bound_init();
|
||||
ret = (*prog_main)(argc, argv);
|
||||
bound_exit();
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
return (*prog_main)(argc, argv);
|
||||
}
|
||||
|
||||
#endif /* defined CONFIG_TCC_STATIC */
|
||||
|
||||
/********************************************************/
|
||||
/* relocate code. Return -1 on error, required size if ptr is NULL,
|
||||
otherwise copy code into buffer passed by the caller */
|
||||
static int tcc_relocate_ex(TCCState *s1, void *ptr)
|
||||
{
|
||||
Section *s;
|
||||
unsigned long offset, length;
|
||||
uplong mem;
|
||||
int i;
|
||||
|
||||
if (0 == s1->runtime_added) {
|
||||
s1->runtime_added = 1;
|
||||
s1->nb_errors = 0;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pe_output_file(s1, NULL);
|
||||
#else
|
||||
tcc_add_runtime(s1);
|
||||
relocate_common_syms();
|
||||
tcc_add_linker_symbols(s1);
|
||||
build_got_entries(s1);
|
||||
#endif
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = 0, mem = (uplong)ptr;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
|
||||
offset = (offset + length + 15) & ~15;
|
||||
}
|
||||
offset += 16;
|
||||
|
||||
/* relocate symbols */
|
||||
relocate_syms(s1, 1);
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
|
||||
#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
|
||||
s1->runtime_plt_and_got_offset = 0;
|
||||
s1->runtime_plt_and_got = (char *)(mem + offset);
|
||||
/* double the size of the buffer for got and plt entries
|
||||
XXX: calculate exact size for them? */
|
||||
offset *= 2;
|
||||
#endif
|
||||
|
||||
if (0 == mem)
|
||||
return offset;
|
||||
|
||||
/* relocate each section */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (s->reloc)
|
||||
relocate_section(s1, s);
|
||||
}
|
||||
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
// printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
|
||||
ptr = (void*)(uplong)s->sh_addr;
|
||||
if (NULL == s->data || s->sh_type == SHT_NOBITS)
|
||||
memset(ptr, 0, length);
|
||||
else
|
||||
memcpy(ptr, s->data, length);
|
||||
/* mark executable sections as executable in memory */
|
||||
if (s->sh_flags & SHF_EXECINSTR)
|
||||
set_pages_executable(ptr, length);
|
||||
}
|
||||
|
||||
#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
|
||||
set_pages_executable(s1->runtime_plt_and_got,
|
||||
s1->runtime_plt_and_got_offset);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
/* allow to run code in memory */
|
||||
|
||||
static void set_pages_executable(void *ptr, unsigned long length)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long old_protect;
|
||||
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
#else
|
||||
unsigned long start, end;
|
||||
start = (unsigned long)ptr & ~(PAGESIZE - 1);
|
||||
end = (unsigned long)ptr + length;
|
||||
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
|
||||
mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
|
||||
/* print the position in the source file of PC value 'pc' by reading
|
||||
@ -215,90 +307,8 @@ static unsigned long rt_printline(unsigned long wanted_pc)
|
||||
return func_addr;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
/* fix for glibc 2.1 */
|
||||
#ifndef REG_EIP
|
||||
#define REG_EIP EIP
|
||||
#define REG_EBP EBP
|
||||
#endif
|
||||
|
||||
/* return the PC at frame level 'level'. Return non zero if not found */
|
||||
static int rt_get_caller_pc(unsigned long *paddr,
|
||||
ucontext_t *uc, int level)
|
||||
{
|
||||
unsigned long fp;
|
||||
int i;
|
||||
|
||||
if (level == 0) {
|
||||
#if defined(__FreeBSD__)
|
||||
*paddr = uc->uc_mcontext.mc_eip;
|
||||
#elif defined(__dietlibc__)
|
||||
*paddr = uc->uc_mcontext.eip;
|
||||
#else
|
||||
*paddr = uc->uc_mcontext.gregs[REG_EIP];
|
||||
#endif
|
||||
return 0;
|
||||
} else {
|
||||
#if defined(__FreeBSD__)
|
||||
fp = uc->uc_mcontext.mc_ebp;
|
||||
#elif defined(__dietlibc__)
|
||||
fp = uc->uc_mcontext.ebp;
|
||||
#else
|
||||
fp = uc->uc_mcontext.gregs[REG_EBP];
|
||||
#endif
|
||||
for(i=1;i<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' */
|
||||
void rt_error(ucontext_t *uc, const char *fmt, ...)
|
||||
static void rt_error(ucontext_t *uc, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
unsigned long pc;
|
||||
@ -308,6 +318,7 @@ void rt_error(ucontext_t *uc, const char *fmt, ...)
|
||||
fprintf(stderr, "Runtime error: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for(i=0;i<num_callers;i++) {
|
||||
if (rt_get_caller_pc(&pc, uc, i) < 0)
|
||||
break;
|
||||
@ -316,13 +327,16 @@ void rt_error(ucontext_t *uc, const char *fmt, ...)
|
||||
else
|
||||
fprintf(stderr, "by ");
|
||||
pc = rt_printline(pc);
|
||||
if (pc == rt_prog_main && pc)
|
||||
if (pc == (unsigned long)rt_prog_main && pc)
|
||||
break;
|
||||
}
|
||||
exit(255);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifndef _WIN32
|
||||
|
||||
/* signal handler for fatal errors */
|
||||
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||
{
|
||||
@ -360,164 +374,229 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||
exit(255);
|
||||
}
|
||||
|
||||
#endif /* defined CONFIG_TCC_BACKTRACE */
|
||||
|
||||
/********************************************************/
|
||||
|
||||
void set_pages_executable(void *ptr, unsigned long length)
|
||||
/* Generate a stack backtrace when a CPU exception occurs. */
|
||||
static void set_exception_handler(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long old_protect;
|
||||
VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
#else
|
||||
unsigned long start, end;
|
||||
start = (unsigned long)ptr & ~(PAGESIZE - 1);
|
||||
end = (unsigned long)ptr + length;
|
||||
end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
|
||||
mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
/* ------------------------------------------------------------- */
|
||||
#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)
|
||||
{
|
||||
Section *s;
|
||||
unsigned long offset, length;
|
||||
uplong mem;
|
||||
unsigned long fp;
|
||||
int i;
|
||||
|
||||
if (0 == s1->runtime_added) {
|
||||
s1->runtime_added = 1;
|
||||
s1->nb_errors = 0;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pe_output_file(s1, NULL);
|
||||
if (level == 0) {
|
||||
#if defined(__FreeBSD__)
|
||||
*paddr = uc->uc_mcontext.mc_eip;
|
||||
#elif defined(__dietlibc__)
|
||||
*paddr = uc->uc_mcontext.eip;
|
||||
#else
|
||||
tcc_add_runtime(s1);
|
||||
relocate_common_syms();
|
||||
tcc_add_linker_symbols(s1);
|
||||
build_got_entries(s1);
|
||||
*paddr = uc->uc_mcontext.gregs[REG_EIP];
|
||||
#endif
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = 0, mem = (uplong)ptr;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
|
||||
offset = (offset + length + 15) & ~15;
|
||||
}
|
||||
offset += 16;
|
||||
|
||||
/* relocate symbols */
|
||||
relocate_syms(s1, 1);
|
||||
if (s1->nb_errors)
|
||||
return -1;
|
||||
|
||||
#ifndef TCC_TARGET_PE
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
s1->runtime_plt_and_got_offset = 0;
|
||||
s1->runtime_plt_and_got = (char *)(mem + offset);
|
||||
/* double the size of the buffer for got and plt entries
|
||||
XXX: calculate exact size for them? */
|
||||
offset *= 2;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (0 == mem)
|
||||
return offset;
|
||||
|
||||
/* relocate each section */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (s->reloc)
|
||||
relocate_section(s1, s);
|
||||
}
|
||||
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[i];
|
||||
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
length = s->data_offset;
|
||||
// printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
|
||||
ptr = (void*)(uplong)s->sh_addr;
|
||||
if (NULL == s->data || s->sh_type == SHT_NOBITS)
|
||||
memset(ptr, 0, length);
|
||||
else
|
||||
memcpy(ptr, s->data, length);
|
||||
/* mark executable sections as executable in memory */
|
||||
if (s->sh_flags & SHF_EXECINSTR)
|
||||
set_pages_executable(ptr, length);
|
||||
}
|
||||
|
||||
#ifndef TCC_TARGET_PE
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
set_pages_executable(s1->runtime_plt_and_got,
|
||||
s1->runtime_plt_and_got_offset);
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do all relocations (needed before using tcc_get_symbol())
|
||||
Returns -1 on error. */
|
||||
int tcc_relocate(TCCState *s1)
|
||||
{
|
||||
int ret = tcc_relocate_ex(s1, NULL);
|
||||
if (-1 == ret)
|
||||
return ret;
|
||||
s1->runtime_mem = tcc_malloc(ret);
|
||||
return tcc_relocate_ex(s1, s1->runtime_mem);
|
||||
}
|
||||
|
||||
/* launch the compiled program with the given arguments */
|
||||
int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
int (*prog_main)(int, char **);
|
||||
|
||||
if (tcc_relocate(s1) < 0)
|
||||
return -1;
|
||||
|
||||
prog_main = tcc_get_symbol_err(s1, "main");
|
||||
|
||||
if (s1->do_debug) {
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
struct sigaction sigact;
|
||||
/* install TCC signal handlers to print debug info on fatal
|
||||
runtime errors */
|
||||
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||
sigact.sa_sigaction = sig_error;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGFPE, &sigact, NULL);
|
||||
sigaction(SIGILL, &sigact, NULL);
|
||||
sigaction(SIGSEGV, &sigact, NULL);
|
||||
sigaction(SIGBUS, &sigact, NULL);
|
||||
sigaction(SIGABRT, &sigact, NULL);
|
||||
return 0;
|
||||
} else {
|
||||
#if defined(__FreeBSD__)
|
||||
fp = uc->uc_mcontext.mc_ebp;
|
||||
#elif defined(__dietlibc__)
|
||||
fp = uc->uc_mcontext.ebp;
|
||||
#else
|
||||
error("debug mode not available");
|
||||
fp = uc->uc_mcontext.gregs[REG_EBP];
|
||||
#endif
|
||||
for(i=1;i<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_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
#if 0
|
||||
#ifdef TCC_TARGET_PE
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
#endif
|
||||
DEF(TOK_realloc, "realloc")
|
||||
DEF(TOK_memalign, "memalign")
|
||||
DEF(TOK_calloc, "calloc")
|
||||
|
@ -31,8 +31,10 @@ copy ..\libtcc.h libtcc\libtcc.h
|
||||
:tcc
|
||||
%P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc
|
||||
|
||||
:libtcc1.a
|
||||
:copy_std_includes
|
||||
copy ..\include\*.h include
|
||||
|
||||
:libtcc1.a
|
||||
.\tcc -c lib/crt1.c
|
||||
.\tcc -c lib/wincrt1.c
|
||||
.\tcc -c lib/dllcrt1.c
|
||||
@ -40,5 +42,15 @@ copy ..\include\*.h include
|
||||
.\tcc -c ../lib/libtcc1.c
|
||||
.\tcc -c lib/chkstk.S
|
||||
.\tcc -c ../lib/alloca86%S%.S
|
||||
tiny_libmaker lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o
|
||||
|
||||
@set LIBFILES=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o
|
||||
|
||||
@if not _%P%==_ goto makelib
|
||||
.\tcc -c ../lib/alloca86-bt%S%.S
|
||||
.\tcc -c ../lib/bcheck.c
|
||||
|
||||
@set LIBFILES=%LIBFILES% alloca86-bt%S%.o bcheck.o
|
||||
|
||||
:makelib
|
||||
tiny_libmaker lib/libtcc1.a %LIBFILES%
|
||||
del *.o
|
||||
|
Loading…
Reference in New Issue
Block a user