tccrun.c: standalone backtraces with -bt[N] or -b

This makes it possible to get backtraces with executables
(including DLLs/SOs) like we had it already with -g -run.

Option -b includes -bt, and -bt includes -g.

- new file lib/bt-exe.c: used to link rt_printline and the
  exception handler from tccrun.c into executables/DLLs.

- new file lib/bt-log.c: provides a function that may be
  called from user code to print out a backtrace with a
  message (currently for i386/x86_64 only):

     int (*tcc_backtrace)(const char *fmt, ...);

  As an extra hack, if 'fmt' is prefixed like "^file.c^..."
  then the backtrace will skip calls from within 'file.c'.

- new file lib/bt-dll.c:  used on win32 to link the backtrace
  and bcheck functions with the main module at runtime

- bcheck.c: now uses the tcc_backtrace function from above

- tccgen.c: minor cleanups

- tccelf.c: stab sections get SHF_ALLOC for easy access.
  Also in relocate_section(): 64bit relocations for stabs
  in DLLs cannot work.  To find DLL addresses, the DLL base
  is added manually in tccrun.c via rc.prog_base instead.

- tccpe.c: there are some changes to allow merging sections,
  used to merge .finit_array into .data in the first place.

- tccpp.c: tcc -run now #defines __TCC_RUN__
  also: refactor a line in tal_realloc that was incompatible
  with bcheck

- tcctest.c: fixed a problem with r12 which tcc cannot preserve
  as well as gcc does.

- tests2/112_backtrace.c: test the feature and the bcheck test18
  that previously was in boundtest.c
This commit is contained in:
gr 2020-01-17 22:58:39 +01:00
parent 4092b05068
commit ef42295fe8
27 changed files with 1216 additions and 855 deletions

View File

@ -281,11 +281,12 @@ IBw = $(call IB,$(wildcard $1),$2)
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
IFw = $(call IF,$(wildcard $1),$2)
IR = mkdir -p $2 && cp -r $1/. $2
B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
# install progs & libs
install-unx:
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
$(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)")
$(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
@ -310,7 +311,7 @@ uninstall-unx:
install-win:
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
$(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib")
$(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")

View File

@ -171,7 +171,7 @@ ST_FUNC void arm_init(struct TCCState *s)
float_abi = s->float_abi;
#ifndef TCC_ARM_HARDFLOAT
tcc_warning("soft float ABI currently not supported: default to softfp");
# warning "soft float ABI currently not supported: default to softfp"
#endif
}
#else

View File

@ -13,7 +13,7 @@ XCC = $(XTCC)
XAR = $(XTCC) -ar
XFLAGS-unx = -B$(TOPSRC)
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
XFLAGS = $(XFLAGS$(XCFG))
XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
XCFG = $(or $(findstring -win,$T),-unx)
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
@ -27,6 +27,8 @@ endif
# only for native compiler
$(X)BCHECK_O = bcheck.o
$(X)BT_O = bt-exe.o bt-log.o
$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
BCHECK_O =
@ -38,18 +40,18 @@ ifdef CONFIG_OSX
XFLAGS += -D_ANSI_SOURCE
endif
I386_O = libtcc1.o alloca86.o alloca86-bt.o
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
ARM64_O = lib-arm64.o
RISCV64_O = lib-arm64.o
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
ARM64_O = lib-arm64.o $(BT_O)
RISCV64_O = lib-arm64.o $(BT_O)
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
OBJ-x86_64-osx = $(X86_64_O) va_list.o
OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
OBJ-arm64 = $(ARM64_O) $(DSO_O)
OBJ-arm = $(ARM_O) $(DSO_O)
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
@ -60,7 +62,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
OBJ-arm-wince = $(ARM_O) $(WIN_O)
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
OBJ-extra = $(filter bcheck.o,$(OBJ-$T))
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
@ -80,8 +82,10 @@ $(TOP)/%.o : %.c
$(XCC) -c $< -o $@ $(XFLAGS)
$(TOP)/bcheck.o : XFLAGS += -g
$(TOP)/bt-exe.o : $(TOP)/tccrun.c
$(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c
clean :
rm -f *.a *.o $(ALL)

View File

@ -49,6 +49,12 @@
#endif
#define FASTCALL __attribute__((regparm(3)))
#ifdef _WIN32
# define DLL_EXPORT __declspec(dllexport)
#else
# define DLL_EXPORT
#endif
#if defined(__FreeBSD__) \
|| defined(__FreeBSD_kernel__) \
|| defined(__DragonFly__) \
@ -162,16 +168,16 @@ void splay_printtree(Tree * t, int d);
/* external interface */
void __bound_checking (int no_check);
void __bound_never_fatal (int no_check);
void * __bound_ptr_add(void *p, size_t offset);
void * __bound_ptr_indir1(void *p, size_t offset);
void * __bound_ptr_indir2(void *p, size_t offset);
void * __bound_ptr_indir4(void *p, size_t offset);
void * __bound_ptr_indir8(void *p, size_t offset);
void * __bound_ptr_indir12(void *p, size_t offset);
void * __bound_ptr_indir16(void *p, size_t offset);
void FASTCALL __bound_local_new(void *p1);
void FASTCALL __bound_local_delete(void *p1);
void __bound_init(void);
DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset);
DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset);
DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset);
DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset);
DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset);
DLL_EXPORT void FASTCALL __bound_local_new(void *p1);
DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
void __bound_init(size_t *);
void __bound_main_arg(char **p);
void __bound_exit(void);
#if !defined(_WIN32)
@ -179,35 +185,32 @@ void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
off_t offset);
int __bound_munmap (void *start, size_t size);
#endif
void __bound_new_region(void *p, size_t size);
void *__bound_memcpy(void *dst, const void *src, size_t size);
int __bound_memcmp(const void *s1, const void *s2, size_t size);
void *__bound_memmove(void *dst, const void *src, size_t size);
void *__bound_memset(void *dst, int c, size_t size);
int __bound_strlen(const char *s);
char *__bound_strcpy(char *dst, const char *src);
char *__bound_strncpy(char *dst, const char *src, size_t n);
int __bound_strcmp(const char *s1, const char *s2);
int __bound_strncmp(const char *s1, const char *s2, size_t n);
char *__bound_strcat(char *dest, const char *src);
char *__bound_strchr(const char *string, int ch);
char *__bound_strdup(const char *s);
DLL_EXPORT void __bound_new_region(void *p, size_t size);
DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size);
DLL_EXPORT int __bound_strlen(const char *s);
DLL_EXPORT char *__bound_strcpy(char *dst, const char *src);
DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n);
DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2);
DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n);
DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
DLL_EXPORT char *__bound_strchr(const char *string, int ch);
DLL_EXPORT char *__bound_strdup(const char *s);
#if !MALLOC_REDIR
void *__bound_malloc(size_t size, const void *caller);
void *__bound_memalign(size_t size, size_t align, const void *caller);
void __bound_free(void *ptr, const void *caller);
void *__bound_realloc(void *ptr, size_t size, const void *caller);
void *__bound_calloc(size_t nmemb, size_t size);
DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller);
DLL_EXPORT void __bound_free(void *ptr, const void *caller);
DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller);
DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size);
#endif
#define FREE_REUSE_SIZE (100)
static unsigned int free_reuse_index;
static void *free_reuse_list[FREE_REUSE_SIZE];
/* error message, just for TCC */
const char *__bound_error_msg;
static Tree *tree = NULL;
#define TREE_REUSE (1)
#if TREE_REUSE
@ -296,14 +299,18 @@ void __bound_never_fatal (int neverfatal)
fetch_and_add (&never_fatal, neverfatal);
}
int tcc_backtrace(const char *fmt, ...);
/* print a bound error message */
static void bound_error(const char *error)
{
__bound_error_msg = error;
fprintf(stderr,"%s%s %s: %s\n", exec, __FILE__, __FUNCTION__, error);
if (never_fatal == 0)
*(void **)0 = 0; /* force a runtime error */
}
#define bound_warning(...) \
tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__)
#define bound_error(...) \
do { \
bound_warning(__VA_ARGS__); \
if (never_fatal == 0) \
exit(255); \
} while (0)
static void bound_alloc_error(const char *s)
{
@ -317,20 +324,6 @@ static void bound_not_found_warning(const char *file, const char *function,
dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
}
static void bound_ptr_add_warning(const char *file, const char *function,
void *ptr)
{
fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
exec, file, function, ptr);
}
static void bound_ptr_indir_error(const char *file, const char *function,
void *ptr)
{
fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
exec, file, function, ptr);
}
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */
void * __bound_ptr_add(void *p, size_t offset)
@ -360,8 +353,7 @@ void * __bound_ptr_add(void *p, size_t offset)
if (addr <= tree->size) {
if (tree->is_invalid || addr + offset > tree->size) {
POST_SEM ();
if (print_warn_ptr_add)
bound_ptr_add_warning (__FILE__, __FUNCTION__, p + offset);
bound_warning("%p is outside of the region", p + offset);
if (never_fatal <= 0)
return INVALID_POINTER; /* return an invalid pointer */
return p + offset;
@ -407,8 +399,7 @@ void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
if (addr <= tree->size) { \
if (tree->is_invalid || addr + offset + dsize > tree->size) { \
POST_SEM (); \
bound_ptr_indir_error (__FILE__, __FUNCTION__, \
p + offset); \
bound_warning("%p is outside of the region", p + offset); \
if (never_fatal <= 0) \
return INVALID_POINTER; /* return an invalid pointer */ \
return p + offset; \
@ -460,8 +451,7 @@ void FASTCALL __bound_local_new(void *p1)
WAIT_SEM ();
while ((addr = p[0])) {
INCR_COUNT(bound_local_new_count);
if (addr != 1)
tree = splay_insert(addr + fp, p[1], tree);
tree = splay_insert(addr + fp, p[1], tree);
p += 2;
}
POST_SEM ();
@ -498,7 +488,10 @@ void FASTCALL __bound_local_delete(void *p1)
WAIT_SEM ();
while ((addr = p[0])) {
INCR_COUNT(bound_local_delete_count);
if (addr == 1) {
tree = splay_delete(addr + fp, tree);
p += 2;
}
{
alloca_list_type *last = NULL;
alloca_list_type *cur = alloca_list;
@ -518,11 +511,8 @@ void FASTCALL __bound_local_delete(void *p1)
cur = cur->next;
}
}
}
else
tree = splay_delete(addr + fp, tree);
p += 2;
}
POST_SEM ();
while (free_list) {
alloca_list_type *next = free_list->next;
@ -607,14 +597,14 @@ void __bound_new_region(void *p, size_t size)
#pragma GCC diagnostic pop
#endif
void __attribute__((constructor)) __bound_init(void)
void __bound_init(size_t *p)
{
extern size_t __bounds_start[];
size_t *p;
if (inited)
return;
dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
if (inited) {
WAIT_SEM();
goto add_bounds;
}
inited = 1;
print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
@ -623,8 +613,6 @@ void __attribute__((constructor)) __bound_init(void)
print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
INIT_SEM ();
#if MALLOC_REDIR
@ -724,27 +712,26 @@ void __attribute__((constructor)) __bound_init(void)
tree = splay_insert((size_t) (&errno), sizeof (int), tree);
#endif
add_bounds:
if (!p)
goto no_bounds;
/* add all static bound check values */
p = __bounds_start;
while (p[0] != 0) {
tree = splay_insert(p[0], p[1], tree);
p += 2;
}
POST_SEM ();
#if BOUND_DEBUG
if (print_calls) {
p = __bounds_start;
while (p[0] != 0) {
if (print_calls) {
dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
__FILE__, __FUNCTION__,
(void *) p[0], (unsigned long) p[1]);
p += 2;
}
}
#endif
p += 2;
}
no_bounds:
POST_SEM ();
no_checking = 0;
dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
}
@ -931,7 +918,7 @@ void *__bound_malloc(size_t size, const void *caller)
#if MALLOC_REDIR
/* This will catch the first dlsym call from __bound_init */
if (malloc_redir == NULL) {
__bound_init ();
__bound_init (0);
if (malloc_redir == NULL) {
ptr = &initial_pool[pool_index];
pool_index = (pool_index + size + 15) & ~15;
@ -1113,7 +1100,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
#if MALLOC_REDIR
/* This will catch the first dlsym call from __bound_init */
if (malloc_redir == NULL) {
__bound_init ();
__bound_init (0);
if (malloc_redir == NULL) {
ptr = &initial_pool[pool_index];
pool_index = (pool_index + size + 15) & ~15;
@ -1190,10 +1177,8 @@ static void __bound_check(const void *p, size_t size, const char *function)
{
if (no_checking == 0 && size != 0 &&
__bound_ptr_add((void *)p, size) == INVALID_POINTER) {
static char line[100];
sprintf(line, "invalid pointer %p, size 0x%lx in %s",
bound_error("invalid pointer %p, size 0x%lx in %s",
p, (unsigned long)size, function);
bound_error(line);
}
}
@ -1207,10 +1192,8 @@ static int check_overlap (const void *p1, size_t n1,
if (no_checking == 0 && n1 != 0 && n2 !=0 &&
((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
(p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
static char line[100];
sprintf(line, "overlapping regions %p(0x%lx), %p(0x%lx) in %s",
bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
p1, (unsigned long)n1, p2, (unsigned long)n2, function);
bound_error(line);
return never_fatal < 0;
}
return 0;

67
lib/bt-dll.c Normal file
View File

@ -0,0 +1,67 @@
/* ------------------------------------------------------------- */
/* stubs for calling bcheck functions from a dll. */
#include <windows.h>
#include <stdio.h>
#define REDIR_ALL \
REDIR(__bt_init) \
REDIR(tcc_backtrace) \
\
REDIR(__bound_ptr_add) \
REDIR(__bound_ptr_indir1) \
REDIR(__bound_ptr_indir2) \
REDIR(__bound_ptr_indir4) \
REDIR(__bound_ptr_indir8) \
REDIR(__bound_ptr_indir12) \
REDIR(__bound_ptr_indir16) \
REDIR(__bound_local_new) \
REDIR(__bound_local_delete) \
REDIR(__bound_new_region) \
\
REDIR(__bound_free) \
REDIR(__bound_malloc) \
REDIR(__bound_realloc) \
REDIR(__bound_memcpy) \
REDIR(__bound_memcmp) \
REDIR(__bound_memmove) \
REDIR(__bound_memset) \
REDIR(__bound_strlen) \
REDIR(__bound_strcpy) \
REDIR(__bound_strncpy) \
REDIR(__bound_strcmp) \
REDIR(__bound_strncmp) \
REDIR(__bound_strcat) \
REDIR(__bound_strchr) \
REDIR(__bound_strdup)
#define REDIR(s) void *s;
static struct { REDIR_ALL } all_ptrs;
#undef REDIR
#define REDIR(s) #s"\0"
static const char all_names[] = REDIR_ALL;
#undef REDIR
#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) );
static void all_jmps() { REDIR_ALL }
#undef REDIR
void __bt_init_dll(int bcheck)
{
const char *s = all_names;
void **p = (void**)&all_ptrs;
do {
*p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
if (NULL == *p) {
char buf[100];
sprintf(buf,
"Error: function '%s()' not found in executable. "
"(Need -bt or -b for linking the exe.)", s);
if (GetStdHandle(STD_ERROR_HANDLE))
fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
else
MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
ExitProcess(1);
}
s = strchr(s,'\0') + 1, ++p;
} while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
}

43
lib/bt-exe.c Normal file
View File

@ -0,0 +1,43 @@
/* ------------------------------------------------------------- */
/* for linking rt_printline and the signal/exception handler
from tccrun.c into executables. */
#define CONFIG_TCC_BACKTRACE_ONLY
#include "../tccrun.c"
int (*__rt_error)(void*, void*, const char *, va_list);
#ifndef _WIN32
# define __declspec(n)
#endif
__declspec(dllexport)
void __bt_init(rt_context *p, int num_callers)
{
__attribute__((weak)) int main();
__attribute__((weak)) void __bound_init(void*);
struct rt_context *rc = &g_rtctxt;
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
if (num_callers) {
memcpy(rc, p, offsetof(rt_context, next));
rc->num_callers = num_callers - 1;
rc->top_func = main;
__rt_error = _rt_error;
set_exception_handler();
} else {
p->next = rc->next, rc->next = p;
}
if (__bound_init && p->bounds_start)
__bound_init(p->bounds_start);
}
/* copy a string and truncate it. */
static char *pstrcpy(char *buf, size_t buf_size, const char *s)
{
int l = strlen(s);
if (l >= buf_size)
l = buf_size - 1;
memcpy(buf, s, l);
buf[l] = 0;
return buf;
}

36
lib/bt-log.c Normal file
View File

@ -0,0 +1,36 @@
/* ------------------------------------------------------------- */
/* function to get a stack backtrace on demand with a message */
#include <stdio.h>
#include <string.h>
int (*__rt_error)(void*, void*, const char *, va_list);
#ifdef _WIN32
# define DLL_EXPORT __declspec(dllexport)
#else
# define DLL_EXPORT
#endif
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
{
va_list ap;
int ret;
if (__rt_error) {
void *fp = __builtin_frame_address(1);
void *ip = __builtin_return_address(0);
va_start(ap, fmt);
ret = __rt_error(fp, ip, fmt, ap);
va_end(ap);
} else {
const char *p;
if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
fmt = p + 1;
va_start(ap, fmt);
ret = vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n"), fflush(stderr);
}
return ret;
}

View File

@ -776,9 +776,6 @@ LIBTCCAPI TCCState *tcc_new(void)
/* enable this if you want symbols with leading underscore on windows: */
#if 0 /* def TCC_TARGET_PE */
s->leading_underscore = 1;
#endif
#ifdef CONFIG_TCC_BACKTRACE
s->rt_num_callers = 6;
#endif
s->ppfp = stdout;
/* might be used in error() before preprocess_start() */
@ -1556,7 +1553,7 @@ static const TCCOption tcc_options[] = {
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
{ "bench", TCC_OPTION_bench, 0 },
#ifdef CONFIG_TCC_BACKTRACE
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
#endif
#ifdef CONFIG_TCC_BCHECK
{ "b", TCC_OPTION_b, 0 },
@ -1809,11 +1806,14 @@ reparse:
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
s->rt_num_callers = atoi(optarg);
s->do_backtrace = 1;
s->do_debug = 1;
break;
#endif
#ifdef CONFIG_TCC_BCHECK
case TCC_OPTION_b:
s->do_bounds_check = 1;
s->do_backtrace = 1;
s->do_debug = 1;
break;
#endif

View File

@ -372,9 +372,12 @@ Try to continue in case of a bound checking error.
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
@item -bt N
Display N callers in stack traces. This is useful with @option{-g} or
@option{-b}.
@item -bt[N]
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
With executables, additional support for stack traces is included.
A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided
to trigger a stack trace with a message on demand.
@end table

2
tcc.c
View File

@ -61,7 +61,7 @@ static const char help[] =
" -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
#ifdef CONFIG_TCC_BACKTRACE
" -bt N show N callers in stack traces\n"
" -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
#endif
"Misc. options:\n"
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"

26
tcc.h
View File

@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifndef TCC_LIBTCC1
# define TCC_LIBTCC1 "libtcc1.a"
#endif
#ifndef TCC_LIBBCHECK
# define TCC_LIBBCHECK "bcheck.o"
#endif
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
@ -475,7 +472,7 @@ struct SymAttr {
nodecorate : 1,
dllimport : 1,
addrtaken : 1,
unused : 3;
xxxx : 3; /* not used */
};
/* function attributes or temporary attributes for parsing */
@ -484,7 +481,8 @@ struct FuncAttr {
func_call : 3, /* calling convention (0..5), see below */
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
func_noreturn : 1, /* attribute((noreturn)) */
xxxx : 2,
func_ctor : 1, /* attribute((constructor)) */
func_dtor : 1, /* attribute((destructor)) */
func_args : 8; /* PE __stdcall args */
};
@ -619,8 +617,6 @@ typedef struct TokenString {
typedef struct AttributeDef {
struct SymAttr a;
struct FuncAttr f;
unsigned short constructor:1;
unsigned short destructor:1;
struct Section *section;
Sym *cleanup_func;
int alias_target; /* token */
@ -718,6 +714,7 @@ struct TCCState {
/* compile with debug symbol (and use them if error during execution) */
unsigned char do_debug;
unsigned char do_backtrace;
#ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */
unsigned char do_bounds_check;
@ -884,11 +881,7 @@ struct TCCState {
const char *runtime_main;
void **runtime_mem;
int nb_runtime_mem;
#ifdef CONFIG_TCC_BACKTRACE
int rt_num_callers;
const char **rt_bound_error_msg;
void *rt_prog_main;
#endif
#endif
int fd, cc; /* used by tcc_load_ldscript */
@ -1259,6 +1252,9 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tcc_add_bcheck(TCCState *s1);
#endif
#ifdef CONFIG_TCC_BACKTRACE
ST_FUNC void tcc_add_btstub(TCCState *s1);
#endif
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
@ -1485,9 +1481,6 @@ ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
#endif
ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend);
ST_FUNC void add_init_array (TCCState *s1, Sym *sym);
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym);
ST_FUNC int put_elf_str(Section *s, const char *sym);
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
@ -1506,7 +1499,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s);
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
ST_FUNC void tcc_add_runtime(TCCState *s1);
ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
#ifndef ELF_OBJ_ONLY
ST_FUNC void build_got_entries(TCCState *s1);
@ -1521,9 +1514,12 @@ ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
#endif
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs);
#ifndef TCC_TARGET_PE
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
ST_FUNC void tcc_add_runtime(TCCState *s1);
#endif
/* ------------ xxx-link.c ------------ */

261
tccelf.c
View File

@ -85,33 +85,21 @@ ST_FUNC void tccelf_bounds_new(TCCState *s)
lbounds_section = new_section(s, ".lbounds",
SHT_PROGBITS, SHF_ALLOC);
}
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
addr_t *ptr;
if (0 == s1->do_bounds_check)
return;
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
*ptr = 0;
set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
bounds_section->sh_num, "__bounds_start");
/* pull bcheck.o from libtcc1.a */
set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, "__bound_init");
}
#endif
ST_FUNC void tccelf_stab_new(TCCState *s)
{
TCCState *s1 = s;
stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
int shf = 0;
#ifdef CONFIG_TCC_BACKTRACE
/* include stab info with standalone backtrace support */
if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY)
shf = SHF_ALLOC;
#endif
stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
stab_section->sh_entsize = sizeof(Stab_Sym);
stab_section->sh_addralign = 4;
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, 0);
put_elf_str(stab_section->link, "");
stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
/* put first entry */
put_stabs(s, "", 0, 0, 0, 0);
}
@ -803,6 +791,17 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d
{
Stab_Sym *sym;
unsigned offset;
if (type == N_SLINE
&& (offset = stab_section->data_offset)
&& (sym = (Stab_Sym*)(stab_section->data + offset) - 1)
&& sym->n_type == type
&& sym->n_value == value) {
/* just update line_number in previous entry */
sym->n_desc = desc;
return;
}
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
if (str) {
sym->n_strx = put_elf_str(stab_section->link, str);
@ -818,10 +817,11 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc,
unsigned long value, Section *sec, int sym_index)
{
put_stabs(s1, str, type, other, desc, value);
put_elf_reloc(symtab_section, stab_section,
stab_section->data_offset - sizeof(unsigned int),
R_DATA_32, sym_index);
stab_section->data_offset + 8,
sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32,
sym_index);
put_stabs(s1, str, type, other, desc, value);
}
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
@ -990,8 +990,16 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
relocate(s1, rel, type, ptr, addr, tgt);
}
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC)
if (sr->sh_flags & SHF_ALLOC) {
sr->link = s1->dynsym;
if (s1->output_type == TCC_OUTPUT_DLL) {
size_t r = (uint8_t*)qrel - sr->data;
if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE
&& 0 == strcmp(s->name, ".stab"))
r = 0; /* cannot apply 64bit relocation to 32bit value */
sr->data_offset = sr->sh_size = r;
}
}
}
#ifndef ELF_OBJ_ONLY
@ -1268,16 +1276,20 @@ static void put_dt(Section *dynamic, int dt, addr_t val)
}
#endif
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs)
{
int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF;
if (sec && offs == -1)
offs = sec->data_offset;
return set_elf_sym(symtab_section, offs, 0,
ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
}
static void add_init_array_defines(TCCState *s1, const char *section_name)
{
Section *s;
long end_offset;
char sym_start[1024];
char sym_end[1024];
snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
char buf[1024];
s = find_section(s1, section_name);
if (!s) {
end_offset = 0;
@ -1285,15 +1297,10 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
} else {
end_offset = s->data_offset;
}
set_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
s->sh_num, sym_start);
set_elf_sym(symtab_section,
end_offset, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
s->sh_num, sym_end);
snprintf(buf, sizeof(buf), "__%s_start", section_name + 1);
set_global_sym(s1, buf, s, 0);
snprintf(buf, sizeof(buf), "__%s_end", section_name + 1);
set_global_sym(s1, buf, s, end_offset);
}
#ifndef TCC_TARGET_PE
@ -1305,33 +1312,92 @@ static int tcc_add_support(TCCState *s1, const char *filename)
}
#endif
static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type)
ST_FUNC void add_array (TCCState *s1, const char *sec, int c)
{
Section *s;
unsigned char *ptr;
s = find_section(s1, section);
if (s) {
s->sh_flags |= SHF_WRITE;
s = find_section(s1, sec);
s->sh_flags |= SHF_WRITE;
#ifndef TCC_TARGET_PE
s->sh_type = sh_type;
s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY;
#endif
ptr = section_ptr_add(s, PTR_SIZE);
memset (ptr, 0, PTR_SIZE);
put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
section_ptr_add(s, PTR_SIZE);
}
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
if (0 == s1->do_bounds_check)
return;
section_ptr_add(bounds_section, sizeof(addr_t));
}
#endif
#ifdef CONFIG_TCC_BACKTRACE
static void put_ptr(TCCState *s1, Section *s, int offs)
{
int c;
c = set_global_sym(s1, NULL, s, offs);
s = data_section;
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
section_ptr_add(s, PTR_SIZE);
}
/* set symbol to STB_LOCAL and resolve. The point is to not export it as
a dynamic symbol to allow so's to have one each with a different value. */
static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset)
{
int c = find_elf_sym(s1->symtab, name);
if (c) {
ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c;
esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE);
esym->st_value = offset;
esym->st_shndx = s->sh_num;
}
}
ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
ST_FUNC void tcc_add_btstub(TCCState *s1)
{
add_array (".init_array", s1, sym, SHT_INIT_ARRAY);
}
Section *s;
int n, o, b;
CString cstr;
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
{
add_array (".fini_array", s1, sym, SHT_FINI_ARRAY);
}
s = data_section;
o = s->data_offset;
/* create (part of) a struct rt_context (see tccrun.c) */
put_ptr(s1, stab_section, 0);
put_ptr(s1, stab_section, -1);
put_ptr(s1, stab_section->link, 0);
section_ptr_add(s, 3 * PTR_SIZE);
/* prog_base */
put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0);
section_ptr_add(s, PTR_SIZE);
n = 2 * PTR_SIZE, b = 0;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
put_ptr(s1, bounds_section, 0);
n -= PTR_SIZE, b = 1;
}
#endif
section_ptr_add(s, n);
cstr_new(&cstr);
cstr_printf(&cstr,
" extern void __bt_init(),*__rt_info[],__bt_init_dll();"
"__attribute__((constructor)) static void __bt_init_rt(){");
#ifdef TCC_TARGET_PE
if (s1->output_type == TCC_OUTPUT_DLL)
cstr_printf(&cstr, "__bt_init_dll(%d);", b);
#endif
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
tcc_compile_string(s1, cstr.data);
cstr_free(&cstr);
set_local_sym(s1, "__rt_info", s, o);
}
#endif
#ifndef TCC_TARGET_PE
/* add tcc runtime libraries */
ST_FUNC void tcc_add_runtime(TCCState *s1)
{
@ -1340,7 +1406,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
tcc_add_bcheck(s1);
#endif
tcc_add_pragma_libs(s1);
#ifndef TCC_TARGET_PE
/* add libc */
if (!s1->nostdlib) {
tcc_add_library_err(s1, "c");
@ -1356,7 +1421,17 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
tcc_add_library_err(s1, "pthread");
tcc_add_library_err(s1, "dl");
tcc_add_support(s1, TCC_LIBBCHECK);
tcc_add_support(s1, "bcheck.o");
}
#endif
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_backtrace) {
if (s1->output_type == TCC_OUTPUT_EXE)
tcc_add_support(s1, "bt-exe.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_btstub(s1);
}
#endif
tcc_add_support(s1, TCC_LIBTCC1);
@ -1364,8 +1439,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_crt(s1, "crtn.o");
}
#endif
}
#endif
/* add various standard linker symbols (must be done after the
sections are filled (for example after allocating common
@ -1376,59 +1451,39 @@ static void tcc_add_linker_symbols(TCCState *s1)
int i;
Section *s;
set_elf_sym(symtab_section,
text_section->data_offset, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
text_section->sh_num, "_etext");
set_elf_sym(symtab_section,
data_section->data_offset, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
data_section->sh_num, "_edata");
set_elf_sym(symtab_section,
bss_section->data_offset, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
bss_section->sh_num, "_end");
set_global_sym(s1, "_etext", text_section, -1);
set_global_sym(s1, "_edata", data_section, -1);
set_global_sym(s1, "_end", bss_section, -1);
#ifdef TCC_TARGET_RISCV64
/* XXX should be .sdata+0x800, not .data+0x800 */
set_elf_sym(symtab_section,
0x800, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
data_section->sh_num, "__global_pointer$");
set_global_sym(s1, "__global_pointer$", data_section, 0x800);
#endif
/* horrible new standard ldscript defines */
add_init_array_defines(s1, ".preinit_array");
add_init_array_defines(s1, ".init_array");
add_init_array_defines(s1, ".fini_array");
/* add start and stop symbols for sections whose name can be
expressed in C */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_type == SHT_PROGBITS &&
(s->sh_flags & SHF_ALLOC)) {
if ((s->sh_flags & SHF_ALLOC)
&& (s->sh_type == SHT_PROGBITS
|| s->sh_type == SHT_STRTAB)) {
const char *p;
int ch;
/* check if section name can be expressed in C */
p = s->name;
for(;;) {
ch = *p;
if (!ch)
int c = *p;
if (!c)
break;
if (!isid(ch) && !isnum(ch))
if (!isid(c) && !isnum(c))
goto next_sec;
p++;
}
snprintf(buf, sizeof(buf), "__start_%s", s->name);
set_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
s->sh_num, buf);
set_global_sym(s1, buf, s, 0);
snprintf(buf, sizeof(buf), "__stop_%s", s->name);
set_elf_sym(symtab_section,
s->data_offset, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
s->sh_num, buf);
set_global_sym(s1, buf, s, -1);
}
next_sec: ;
}
@ -1699,8 +1754,8 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
!(s->sh_flags & SHF_ALLOC) &&
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
prepare_dynamic_rel(s1, s)) {
if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
textrel = 1;
if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE))
textrel = 1;
} else
#endif
if ((s1->do_debug && s->sh_type != SHT_RELX) ||
@ -1814,9 +1869,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
if (s == interp) {
if (k != 0)
continue;
} else if (s->sh_type == SHT_DYNSYM ||
s->sh_type == SHT_STRTAB ||
s->sh_type == SHT_HASH) {
} else if ((s->sh_type == SHT_DYNSYM ||
s->sh_type == SHT_STRTAB ||
s->sh_type == SHT_HASH)
&& !strstr(s->name, ".stab")) {
if (k != 1)
continue;
} else if (s->sh_type == SHT_RELX) {
@ -2060,7 +2116,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
Section *s;
ElfW(Ehdr) ehdr;
ElfW(Shdr) shdr, *sh;
ElfW(Sym) *sym;
file_type = s1->output_type;
shnum = s1->nb_sections;
@ -2131,10 +2186,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
sort_syms(s1, symtab_section);
if (s1->dynsym)
for_each_elem(s1->dynsym, 0, sym, ElfW(Sym))
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
s1->dynsym->sh_info++;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[sec_order[i]];
if (s->sh_type != SHT_NOBITS) {
@ -2842,12 +2893,6 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
Section *s = symtab_section;
sym_index = find_elf_sym(s, p);
#ifdef TCC_TARGET_PE /* windows DLL's don't have UNDEF syms */
if (sym_index == 0) {
s = s1->dynsymtab_section;
sym_index = find_elf_sym(s, p);
}
#endif
if (!sym_index)
continue;
sym = &((ElfW(Sym) *)s->data)[sym_index];

View File

@ -103,7 +103,7 @@ ST_DATA struct switch_t {
struct scope *scope;
} *cur_switch; /* current switch */
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
/*list of temporary local variables on the stack in current function. */
ST_DATA struct temp_local_variable {
int location; //offset on stack. Svalue.c.i
@ -375,11 +375,10 @@ static BufferedFile* put_new_file(TCCState *s1)
ST_FUNC void tcc_debug_line(TCCState *s1)
{
BufferedFile *f;
if (!s1->do_debug || !(f = put_new_file(s1)))
return;
if (last_line_num == f->line_num)
return;
if (text_section != cur_text_section)
if (!s1->do_debug
|| cur_text_section != text_section
|| !(f = put_new_file(s1))
|| last_line_num == f->line_num)
return;
if (func_ind != -1) {
put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind);
@ -409,9 +408,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
{
if (!s1->do_debug)
return;
#if 0 // this seems to confuse gnu tools
put_stabn(s1, N_FUN, 0, 0, size);
#endif
}
/* put alternative filename */
@ -2592,7 +2589,6 @@ redo:
vswap();
gen_op('-');
}
vtop[-1].r &= ~VT_MUSTBOUND;
gen_bounded_ptr_add();
} else
#endif
@ -3428,6 +3424,10 @@ ST_FUNC void vstore(void)
/* destination */
vswap();
#ifdef CONFIG_TCC_BCHECK
if (vtop->r & VT_MUSTBOUND)
gbound(); /* check would be wrong after gaddrof() */
#endif
vtop->type.t = VT_PTR;
gaddrof();
@ -3444,8 +3444,11 @@ ST_FUNC void vstore(void)
vswap();
/* source */
vtop->r &= ~VT_MUSTBOUND;
vpushv(vtop - 2);
#ifdef CONFIG_TCC_BCHECK
if (vtop->r & VT_MUSTBOUND)
gbound();
#endif
vtop->type.t = VT_PTR;
gaddrof();
/* type size */
@ -3662,11 +3665,11 @@ redo:
}
case TOK_CONSTRUCTOR1:
case TOK_CONSTRUCTOR2:
ad->constructor = 1;
ad->f.func_ctor = 1;
break;
case TOK_DESTRUCTOR1:
case TOK_DESTRUCTOR2:
ad->destructor = 1;
ad->f.func_dtor = 1;
break;
case TOK_SECTION1:
case TOK_SECTION2:
@ -4958,6 +4961,10 @@ ST_FUNC void unary(void)
Sym *s;
AttributeDef ad;
/* generate line number info */
if (tcc_state->do_debug)
tcc_debug_line(tcc_state);
sizeof_caller = in_sizeof;
in_sizeof = 0;
type.ref = NULL;
@ -5522,7 +5529,7 @@ special_math_val:
vtop->r |= VT_LVAL;
#ifdef CONFIG_TCC_BCHECK
/* if bound checking, the referenced pointer must be checked */
if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL)
if (tcc_state->do_bounds_check)
vtop->r |= VT_MUSTBOUND;
#endif
}
@ -5538,15 +5545,6 @@ special_math_val:
Sym *sa;
int nb_args, ret_nregs, ret_align, regsize, variadic;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && (vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
addr_t *bounds_ptr;
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
bounds_ptr[0] = 1; /* marks alloca/vla used */
bounds_ptr[1] = 0;
}
#endif
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
/* pointer test (no array accepted) */
@ -6514,10 +6512,10 @@ again:
}
prev_scope(&o, is_expr);
if (0 == local_scope && !nocode_wanted)
if (local_scope)
next();
else if (!nocode_wanted)
check_func_return();
next();
} else if (t == TOK_RETURN) {
b = (func_vt.t & VT_BTYPE) != VT_VOID;
@ -7582,16 +7580,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
gen_vla_sp_save(addr);
cur_scope->vla.loc = addr;
cur_scope->vla.num++;
#ifdef CONFIG_TCC_BCHECK
if (bcheck) {
addr_t *bounds_ptr;
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
bounds_ptr[0] = 1; /* marks alloca/vla used */
bounds_ptr[1] = 0;
}
#endif
} else if (has_init) {
size_t oldreloc_offset = 0;
if (sec && sec->reloc)
@ -7617,7 +7605,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* parse a function defined by symbol 'sym' and generate its code in
'cur_text_section' */
static void gen_function(Sym *sym, AttributeDef *ad)
static void gen_function(Sym *sym)
{
/* Initialize VLA state */
struct scope f = { 0 };
@ -7632,17 +7620,12 @@ static void gen_function(Sym *sym, AttributeDef *ad)
}
/* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0);
if (ad && ad->constructor) {
add_init_array (tcc_state, sym);
}
if (ad && ad->destructor) {
add_fini_array (tcc_state, sym);
}
if (sym->type.ref->f.func_ctor)
add_array (tcc_state, ".init_array", sym->c);
if (sym->type.ref->f.func_dtor)
add_array (tcc_state, ".fini_array", sym->c);
funcname = get_tok_str(sym->v, NULL);
func_ind = ind;
/* put debug symbol */
tcc_debug_funcstart(tcc_state, sym);
/* push a dummy symbol to enable local sym storage */
@ -7675,6 +7658,8 @@ static void gen_function(Sym *sym, AttributeDef *ad)
ind = 0; /* for safety */
nocode_wanted = 0x80000000;
check_vstack();
/* do this after funcend debug info */
next();
}
static void gen_inline_functions(TCCState *s)
@ -7698,7 +7683,7 @@ static void gen_inline_functions(TCCState *s)
begin_macro(fn->func_str, 1);
next();
cur_text_section = text_section;
gen_function(sym, NULL);
gen_function(sym);
end_macro();
inline_generated = 1;
@ -7866,11 +7851,8 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
the compilation unit only if they are used */
if (sym->type.t & VT_INLINE) {
struct InlineFunc *fn;
const char *filename;
filename = file ? file->filename : "";
fn = tcc_malloc(sizeof *fn + strlen(filename));
strcpy(fn->filename, filename);
fn = tcc_malloc(sizeof *fn + strlen(file->filename));
strcpy(fn->filename, file->filename);
fn->sym = sym;
skip_or_save_block(&fn->func_str);
dynarray_add(&tcc_state->inline_fns,
@ -7880,7 +7862,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
cur_text_section = ad.section;
if (!cur_text_section)
cur_text_section = text_section;
gen_function(sym, &ad);
gen_function(sym);
}
break;
} else {

324
tccpe.c
View File

@ -239,8 +239,6 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
#define IMAGE_SCN_TYPE_NOLOAD 0x00000002
#define IMAGE_SCN_LNK_REMOVE 0x00000800
#pragma pack(pop)
@ -299,6 +297,7 @@ enum {
sec_other ,
sec_rsrc ,
sec_stab ,
sec_stabstr ,
sec_reloc ,
sec_last
};
@ -318,12 +317,12 @@ static const DWORD pe_sec_flags[] = {
#endif
struct section_info {
int cls, ord;
int cls;
char name[32];
DWORD sh_addr;
DWORD sh_size;
DWORD pe_flags;
unsigned char *data;
Section *sec;
DWORD data_size;
IMAGE_SECTION_HEADER ish;
};
@ -359,7 +358,7 @@ struct pe_info {
int subsystem;
DWORD section_align;
DWORD file_align;
struct section_info *sec_info;
struct section_info **sec_info;
int sec_count;
struct pe_import_info **imp_info;
int imp_count;
@ -432,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key)
return -1;
}
#if 0
ST_FN DWORD umin(DWORD a, DWORD b)
static DWORD umin(DWORD a, DWORD b)
{
return a < b ? a : b;
}
#endif
static DWORD umax(DWORD a, DWORD b)
{
@ -467,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz
hdr->opthdr.DataDirectory[dir].Size = size;
}
static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
struct pe_file {
FILE *op;
DWORD sum;
unsigned pos;
};
static int pe_fwrite(void *data, int len, struct pe_file *pf)
{
if (psum) {
DWORD sum = *psum;
WORD *p = data;
int i;
for (i = len; i > 0; i -= 2) {
sum += (i >= 2) ? *p++ : *(BYTE*)p;
sum = (sum + (sum >> 16)) & 0xFFFF;
}
*psum = sum;
WORD *p = data;
DWORD sum;
int ret, i;
pf->pos += (ret = fwrite(data, 1, len, pf->op));
sum = pf->sum;
for (i = len; i > 0; i -= 2) {
sum += (i >= 2) ? *p++ : *(BYTE*)p;
sum = (sum + (sum >> 16)) & 0xFFFF;
}
return len == fwrite(data, 1, len, fp) ? 0 : -1;
pf->sum = sum;
return len == ret ? 0 : -1;
}
static void pe_fpad(FILE *fp, DWORD new_pos)
static void pe_fpad(struct pe_file *pf, DWORD new_pos)
{
DWORD pos = ftell(fp);
while (++pos <= new_pos)
fputc(0, fp);
char buf[256];
int n, diff = new_pos - pf->pos;
memset(buf, 0, sizeof buf);
while (diff > 0) {
diff -= n = umin(diff, sizeof buf);
fwrite(buf, n, 1, pf->op);
}
pf->pos = new_pos;
}
/*----------------------------------------------------------------------------*/
@ -598,14 +606,14 @@ static int pe_write(struct pe_info *pe)
struct pe_header pe_header = pe_template;
int i;
FILE *op;
DWORD file_offset, sum;
struct pe_file pf = {0};
DWORD file_offset;
struct section_info *si;
IMAGE_SECTION_HEADER *psh;
TCCState *s1 = pe->s1;
op = fopen(pe->filename, "wb");
if (NULL == op) {
pf.op = fopen(pe->filename, "wb");
if (NULL == pf.op) {
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
return -1;
}
@ -624,7 +632,7 @@ static int pe_write(struct pe_info *pe)
DWORD addr, size;
const char *sh_name;
si = pe->sec_info + i;
si = pe->sec_info[i];
sh_name = si->name;
addr = si->sh_addr - pe->imagebase;
size = si->sh_size;
@ -663,20 +671,18 @@ static int pe_write(struct pe_info *pe)
break;
}
if (pe->thunk == pe->s1->sections[si->ord]) {
if (pe->imp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs + addr, pe->imp_size);
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs + addr, pe->iat_size);
}
if (pe->exp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs + addr, pe->exp_size);
}
if (pe->imp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs, pe->imp_size);
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs, pe->iat_size);
}
if (pe->exp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs, pe->exp_size);
}
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
psh->Characteristics = si->pe_flags;
psh->VirtualAddress = addr;
@ -707,25 +713,29 @@ static int pe_write(struct pe_info *pe)
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
sum = 0;
pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
pe_fwrite(&pe_header, sizeof pe_header, &pf);
for (i = 0; i < pe->sec_count; ++i)
pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
pe_fpad(op, pe->sizeofheaders);
pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
file_offset = pe->sizeofheaders;
for (i = 0; i < pe->sec_count; ++i) {
si = pe->sec_info + i;
psh = &si->ish;
if (si->data_size) {
pe_fwrite(si->data, si->data_size, op, &sum);
file_offset = psh->PointerToRawData + psh->SizeOfRawData;
pe_fpad(op, file_offset);
Section *s;
si = pe->sec_info[i];
for (s = si->sec; s; s = s->prev) {
pe_fpad(&pf, file_offset);
pe_fwrite(s->data, s->data_offset, &pf);
if (s->prev)
file_offset += s->prev->sh_addr - s->sh_addr;
}
file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
pe_fpad(&pf, file_offset);
}
pe_header.opthdr.CheckSum = sum + file_offset;
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
fclose (op);
pf.sum += file_offset;
fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
fclose (pf.op);
#ifndef _WIN32
chmod(pe->filename, 0777);
#endif
@ -796,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe)
return;
pe_align_section(pe->thunk, 16);
pe->imp_offs = dll_ptr = pe->thunk->data_offset;
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
pe->iat_offs = dll_ptr + pe->imp_size;
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
dll_ptr = pe->thunk->data_offset;
thk_ptr = dll_ptr + pe->imp_size;
ent_ptr = thk_ptr + pe->iat_size;
pe->imp_offs = dll_ptr + rva_base;
pe->iat_offs = thk_ptr + rva_base;
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
thk_ptr = pe->iat_offs;
ent_ptr = pe->iat_offs + pe->iat_size;
for (i = 0; i < pe->imp_count; ++i) {
IMAGE_IMPORT_DESCRIPTOR *hdr;
int k, n, dllindex;
@ -895,7 +904,7 @@ static void pe_build_exports(struct pe_info *pe)
{
ElfW(Sym) *sym;
int sym_index, sym_end;
DWORD rva_base, func_o, name_o, ord_o, str_o;
DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
IMAGE_EXPORT_DIRECTORY *hdr;
int sym_count, ord;
struct pe_sort_sym **sorted, *p;
@ -937,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe)
pe_align_section(pe->thunk, 16);
dllname = tcc_basename(pe->filename);
pe->exp_offs = pe->thunk->data_offset;
func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
base_o = pe->thunk->data_offset;
func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
name_o = func_o + sym_count * sizeof (DWORD);
ord_o = name_o + sym_count * sizeof (DWORD);
str_o = ord_o + sym_count * sizeof(WORD);
hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
hdr = section_ptr_add(pe->thunk, str_o - base_o);
hdr->Characteristics = 0;
hdr->Base = 1;
hdr->NumberOfFunctions = sym_count;
@ -985,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe)
if (op)
fprintf(op, "%s\n", name);
}
pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
pe->exp_offs = base_o + rva_base;
pe->exp_size = pe->thunk->data_offset - base_o;
dynarray_reset(&sorted, &sym_count);
if (op)
fclose(op);
@ -994,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe)
/* ------------------------------------------------------------- */
static void pe_build_reloc (struct pe_info *pe)
{
DWORD offset, block_ptr, addr;
DWORD offset, block_ptr, sh_addr, addr;
int count, i;
ElfW_Rel *rel, *rel_end;
Section *s = NULL, *sr;
struct pe_reloc_header *hdr;
offset = addr = block_ptr = count = i = 0;
sh_addr = offset = block_ptr = count = i = 0;
rel = rel_end = NULL;
for(;;) {
if (rel < rel_end) {
int type = ELFW(R_TYPE)(rel->r_info);
addr = rel->r_offset + s->sh_addr;
addr = rel->r_offset + sh_addr;
++ rel;
if (type != REL_TYPE_DIRECT)
continue;
@ -1022,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe)
}
-- rel;
} else if (i < pe->sec_count) {
sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
} else if (s) {
sr = s->reloc;
if (sr) {
rel = (ElfW_Rel *)sr->data;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
sh_addr = s->sh_addr;
}
s = s->prev;
continue;
}
if (count) {
/* store the last block and ready for a new one */
struct pe_reloc_header *hdr;
if (count & 1) /* align for DWORDS */
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
hdr -> offset = offset - pe->imagebase;
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
count = 0;
}
} else if (i < pe->sec_count) {
s = pe->sec_info[i]->sec, ++i;
continue;
if (rel >= rel_end)
} else if (!count)
break;
/* fill the last block and ready for a new one */
if (count & 1) /* align for DWORDS */
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
hdr -> offset = offset - pe->imagebase;
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
count = 0;
}
}
@ -1072,13 +1086,14 @@ static int pe_section_class(Section *s)
if (flags & SHF_WRITE)
return sec_bss;
}
return sec_other;
} else {
if (0 == strcmp(name, ".reloc"))
return sec_reloc;
if (0 == memcmp(name, ".stab", 5))
return sec_stab;
}
if (0 == memcmp(name, ".stab", 5))
return name[5] ? sec_stabstr : sec_stab;
if (flags & SHF_ALLOC)
return sec_other;
return -1;
}
@ -1092,47 +1107,62 @@ static int pe_assign_addresses (struct pe_info *pe)
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
for (o = k = 0 ; k < sec_last; ++k) {
for (i = 1; i < pe->s1->nb_sections; ++i) {
s = pe->s1->sections[i];
if (k == pe_section_class(s)) {
// printf("%s %d\n", s->name, k);
s->sh_addr = pe->imagebase;
if (k == pe_section_class(s))
section_order[o++] = i;
}
}
}
pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
si = NULL;
addr = pe->imagebase + 1;
for (i = 0; i < o; ++i)
{
for (i = 0; i < o; ++i) {
k = section_order[i];
s = pe->s1->sections[k];
c = pe_section_class(s);
si = &pe->sec_info[pe->sec_count];
if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
continue;
#ifdef PE_MERGE_DATA
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
/* append .bss to .data */
s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
addr += s->data_offset;
si[-1].sh_size = addr - si[-1].sh_addr;
continue;
}
if (c == sec_bss)
c = sec_data;
#endif
if (c == sec_stab && 0 == pe->s1->do_debug)
if (si && c == si->cls) {
/* merge with previous section */
s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
} else {
si = NULL;
s->sh_addr = addr = pe_virtual_align(pe, addr);
}
if (c == sec_data && NULL == pe->thunk)
pe->thunk = s;
if (s == pe->thunk) {
pe_build_imports(pe);
pe_build_exports(pe);
}
if (s == pe->reloc)
pe_build_reloc (pe);
if (0 == s->data_offset)
continue;
if (si)
goto add_section;
si = tcc_mallocz(sizeof *si);
dynarray_add(&pe->sec_info, &pe->sec_count, si);
strcpy(si->name, s->name);
si->cls = c;
si->ord = k;
si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
si->sh_addr = addr;
si->pe_flags = IMAGE_SCN_MEM_READ;
if (s->sh_flags & SHF_EXECINSTR)
@ -1143,48 +1173,35 @@ static int pe_assign_addresses (struct pe_info *pe)
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
if (s->sh_flags & SHF_WRITE)
si->pe_flags |= IMAGE_SCN_MEM_WRITE;
if (0 == (s->sh_flags & SHF_ALLOC)) {
if (0 == (s->sh_flags & SHF_ALLOC))
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
if (c == sec_stab)
si->pe_flags |= 0x802; //IMAGE_SCN_TYPE_NOLOAD|IMAGE_SCN_LNK_REMOVE
add_section:
addr += s->data_offset;
si->sh_size = addr - si->sh_addr;
if (s->sh_type != SHT_NOBITS) {
Section **ps = &si->sec;
while (*ps)
ps = &(*ps)->prev;
*ps = s, s->prev = NULL;
si->data_size = si->sh_size;
}
if (c == sec_data && NULL == pe->thunk)
pe->thunk = s;
if (s == pe->thunk) {
pe_build_imports(pe);
pe_build_exports(pe);
}
if (c == sec_reloc)
pe_build_reloc (pe);
if (s->data_offset)
{
if (s->sh_type != SHT_NOBITS) {
si->data = s->data;
si->data_size = s->data_offset;
}
addr += s->data_offset;
si->sh_size = s->data_offset;
++pe->sec_count;
}
//printf("%08x %05x %s %08x\n", si->sh_addr, si->sh_size, si->name, si->pe_flags);
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
}
tcc_free(section_order);
#if 0
for (i = 1; i < pe->s1->nb_sections; ++i) {
Section *s = pe->s1->sections[i];
int type = s->sh_type;
int flags = s->sh_flags;
printf("section %-16s %-10s %5x %s,%s,%s\n",
printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
s->name,
type == SHT_PROGBITS ? "progbits" :
type == SHT_NOBITS ? "nobits" :
type == SHT_SYMTAB ? "symtab" :
type == SHT_STRTAB ? "strtab" :
type == SHT_RELX ? "rel" : "???",
s->sh_addr,
s->data_offset,
flags & SHF_ALLOC ? "alloc" : "",
flags & SHF_WRITE ? "write" : "",
@ -1193,8 +1210,6 @@ static int pe_assign_addresses (struct pe_info *pe)
}
pe->s1->verbose = 2;
#endif
tcc_free(section_order);
return 0;
}
@ -1860,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
else
if (TCC_OUTPUT_DLL == s1->output_type) {
pe_type = PE_DLL;
/* need this for 'tccelf.c:relocate_section()' */
s1->output_type = TCC_OUTPUT_EXE;
}
else {
pe_type = PE_EXE;
@ -1881,24 +1894,34 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
if (!s1->leading_underscore || strchr(start_symbol, '@'))
++start_symbol;
/* grab the startup code from libtcc1 */
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_backtrace) {
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bcheck.o");
#endif
if (s1->output_type == TCC_OUTPUT_EXE)
tcc_add_support(s1, "bt-exe.o");
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-dll.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
if (s1->output_type != TCC_OUTPUT_MEMORY)
tcc_add_btstub(s1);
}
#endif
/* grab the startup code from libtcc1.a */
#ifdef TCC_IS_NATIVE
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
#endif
set_elf_sym(symtab_section,
0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, start_symbol);
set_global_sym(s1, start_symbol, NULL, 0);
if (0 == s1->nostdlib) {
static const char *libs[] = {
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
#ifdef TCC_IS_NATIVE
if (s1->do_bounds_check)
tcc_add_support(s1, TCC_LIBBCHECK);
#endif
tcc_add_support(s1, TCC_LIBTCC1);
for (pp = libs; 0 != (p = *pp); ++pp) {
if (*p)
@ -1907,6 +1930,10 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
break;
}
}
/* need this for 'tccelf.c:relocate_section()' */
if (TCC_OUTPUT_DLL == s1->output_type)
s1->output_type = TCC_OUTPUT_EXE;
if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN;
pe->type = pe_type;
@ -1970,7 +1997,10 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe.filename = filename;
pe.s1 = s1;
tcc_add_runtime(s1);
#ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1);
#endif
tcc_add_pragma_libs(s1);
pe_add_runtime(s1, &pe);
resolve_common_syms(s1);
pe_set_options(s1, &pe);
@ -1995,7 +2025,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
ret = -1;
else
ret = pe_write(&pe);
tcc_free(pe.sec_info);
dynarray_reset(&pe.sec_info, &pe.sec_count);
} else {
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;

17
tccpp.c
View File

@ -109,9 +109,7 @@ ST_FUNC void expect(const char *msg)
/* ------------------------------------------------------------------------- */
/* Custom allocator for tiny objects */
#ifndef __BOUNDS_CHECKING_ON
#define USE_TAL
#endif
#ifndef USE_TAL
#define tal_free(al, p) tcc_free(p)
@ -250,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
tail_call:
is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
if ((!p || is_own) && size <= al->limit) {
if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {
header = (tal_header_t *)al->p;
header->size = adj_size;
#ifdef TAL_DEBUG
@ -1958,7 +1956,11 @@ include_done:
if (tok == TOK_STR) {
if (file->true_filename == file->filename)
file->true_filename = tcc_strdup(file->filename);
tcc_debug_putfile(s1, (char *)tokc.str.data);
/* prepend directory from real file */
pstrcpy(buf, sizeof buf, file->true_filename);
*tcc_basename(buf) = 0;
pstrcat(buf, sizeof buf, (char *)tokc.str.data);
tcc_debug_putfile(s1, buf);
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
break;
else
@ -3529,9 +3531,6 @@ no_subst:
/* return next token with macro substitution */
ST_FUNC void next(void)
{
/* generate line number info */
if (tcc_state->do_debug)
tcc_debug_line(tcc_state);
redo:
if (parse_flags & PARSE_FLAG_SPACES)
next_nomacro_spc();
@ -3607,6 +3606,8 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
if (is_asm)
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
if (s1->output_type == TCC_OUTPUT_MEMORY)
cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
if (s1->cmdline_incl.size)
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
//printf("%s\n", (char*)cstr.data);
@ -3657,7 +3658,7 @@ ST_FUNC void tccpp_new(TCCState *s)
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
tok_str_new(&tokstr_buf);
tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
tok_ident = TOK_IDENT;
p = tcc_keywords;
while (*p) {

341
tccrun.c
View File

@ -23,29 +23,38 @@
/* only native compiler supports -run */
#ifdef TCC_IS_NATIVE
#ifdef CONFIG_TCC_BACKTRACE
typedef struct rt_context
{
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */
Stab_Sym *stab_sym, *stab_sym_end;
char *stab_str;
ElfW(Sym) *esym_start, *esym_end;
char *elf_str;
addr_t prog_base;
void *bounds_start;
struct rt_context *next;
/* <-- */
int num_callers;
addr_t ip, fp, sp;
void *top_func;
jmp_buf jmp_buf;
char do_jmp;
} rt_context;
static rt_context g_rtctxt;
static void set_exception_handler(void);
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
static void rt_exit(int code);
#endif /* CONFIG_TCC_BACKTRACE */
/* defined when included from lib/bt.c */
#ifndef CONFIG_TCC_BACKTRACE_ONLY
#ifndef _WIN32
# include <sys/mman.h>
#endif
#ifdef CONFIG_TCC_BACKTRACE
static void set_exception_handler(void);
#ifdef _WIN32
static DWORD s1_for_run_idx;
void set_s1_for_run(TCCState *s)
{
if (!s1_for_run_idx)
s1_for_run_idx = TlsAlloc();
TlsSetValue(s1_for_run_idx, s);
}
#define get_s1_for_run() ((TCCState*)TlsGetValue(s1_for_run_idx))
#else
/* XXX: add tls support for linux */
static TCCState *s1_for_run;
#define set_s1_for_run(s) (s1_for_run = s)
#define get_s1_for_run() s1_for_run
#endif
#endif
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
@ -113,72 +122,73 @@ ST_FUNC void tcc_run_free(TCCState *s1)
#endif
}
tcc_free(s1->runtime_mem);
if (get_s1_for_run() == s1)
set_s1_for_run(NULL);
}
static void run_cdtors(TCCState *s1, const char *start, const char *end)
{
void **a = tcc_get_symbol(s1, start);
void **b = tcc_get_symbol(s1, end);
while (a != b)
((void(*)(void))*a++)();
}
/* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
/* PE target overwrites runtime_main */
#ifndef TCC_TARGET_PE
typedef void (*init_array_func)(int, char **, char **);
typedef void (*fini_array_func)(void);
init_array_func *__init_array_start;
init_array_func *__init_array_end;
fini_array_func *__fini_array_start;
fini_array_func *__fini_array_end;
int (*prog_main)(int, char **), ret;
#ifdef CONFIG_TCC_BACKTRACE
rt_context *rc = &g_rtctxt;
#endif
int i;
int ret;
int (*prog_main)(int, char **);
s1->runtime_main = s1->nostdlib ? "_start" : "main";
if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
return 0;
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_debug)
tcc_add_symbol(s1, "exit", rt_exit);
#endif
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1;
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
#ifdef CONFIG_TCC_BACKTRACE
memset(rc, 0, sizeof *rc);
if (s1->do_debug) {
void *p;
rc->stab_sym = (Stab_Sym *)stab_section->data;
rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
rc->stab_str = (char *)stab_section->link->data;
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
rc->elf_str = (char *)symtab_section->link->data;
rc->top_func = tcc_get_symbol(s1, "main");
rc->num_callers = s1->rt_num_callers;
rc->do_jmp = 1;
if ((p = tcc_get_symbol(s1, "__rt_error")))
*(void**)p = _rt_error;
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check) {
if ((p = tcc_get_symbol(s1, "__bound_init")))
((void(*)(void*))p)(bounds_section->data);
}
#endif
set_exception_handler();
s1->rt_prog_main = prog_main;
/* set global state pointer for exception handlers*/
set_s1_for_run(s1);
}
#endif
errno = 0; /* clean errno value */
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check)
/* set error function */
s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
fflush(stdout);
fflush(stderr);
run_cdtors(s1, "__init_array_start", "__init_array_end");
#ifdef CONFIG_TCC_BACKTRACE
if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf)))
#endif
#ifndef TCC_TARGET_PE
__init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
__init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
__fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
__fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
if (__init_array_start && __init_array_end) {
i = 0;
while (&__init_array_start[i] != __init_array_end)
(*__init_array_start[i++])(argc, argv, environ);
{
ret = prog_main(argc, argv);
}
#endif
ret = (*prog_main)(argc, argv);
#ifndef TCC_TARGET_PE
if (__fini_array_start && __fini_array_end) {
i = 0;
while (&__fini_array_end[i] != __fini_array_start)
(*__fini_array_end[--i])();
}
#endif
run_cdtors(s1, "__fini_array_start", "__fini_array_end");
if ((s1->dflag & 16) && ret)
fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
return ret;
}
@ -336,11 +346,10 @@ static void win64_del_function_table(void *p)
}
}
#endif
#endif //ndef CONFIG_TCC_BACKTRACE_ONLY
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
#define INCLUDE_STACK_SIZE 32
static int rt_vprintf(const char *fmt, va_list ap)
{
int ret = vfprintf(stderr, fmt, ap);
@ -358,21 +367,22 @@ static int rt_printf(const char *fmt, ...)
return r;
}
#define INCLUDE_STACK_SIZE 32
/* print the position in the source file of PC value 'pc' by reading
the stabs debug information */
static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
const char *msg, const char *skip)
{
char func_name[128];
addr_t func_addr, last_pc, pc;
const char *incl_files[INCLUDE_STACK_SIZE];
int incl_index, last_incl_index, len, last_line_num, i;
const char *str, *p;
ElfW(Sym) *esym;
Stab_Sym *sym;
ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym;
Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym;
char *stab_str = NULL;
char *elf_str = NULL;
next:
func_name[0] = '\0';
func_addr = 0;
incl_index = 0;
@ -380,19 +390,8 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
last_line_num = 1;
last_incl_index = 0;
if (stab_section) {
stab_sym = (Stab_Sym *)stab_section->data;
stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
stab_str = (char *) stab_section->link->data;
}
if (symtab_section) {
esym_start = (ElfW(Sym) *)(symtab_section->data);
esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
elf_str = (char *) symtab_section->link->data;
}
for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
str = stab_str + sym->n_strx;
for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
str = rc->stab_str + sym->n_strx;
pc = sym->n_value;
switch(sym->n_type) {
@ -406,16 +405,18 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
if (sym->n_strx == 0) /* end of function */
goto rel_pc;
abs_pc:
if (sizeof pc == 8)
if (sizeof sym->n_value < PTR_SIZE) {
/* Stab_Sym.n_value is only 32bits */
pc |= wanted_pc & 0xffffffff00000000ULL;
//fprintf(stderr, "pc = %p %p %p\n", pc, rc->prog_base, wanted_pc), fflush(stderr);
pc += rc->prog_base;
}
break;
rel_pc:
pc += func_addr;
break;
}
if (pc > wanted_pc && wanted_pc > last_pc)
if (pc >= wanted_pc && wanted_pc >= last_pc)
goto found;
switch(sym->n_type) {
@ -434,8 +435,6 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
last_pc = pc;
last_line_num = sym->n_desc;
last_incl_index = incl_index;
if (pc == wanted_pc)
goto found;
break;
/* include files */
case N_BINCL:
@ -468,31 +467,38 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
}
}
func_name[0] = '\0';
func_addr = 0;
last_incl_index = 0;
/* we try symtab symbols (no line number info) */
for (esym = esym_start + 1; esym < esym_end; ++esym) {
for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) {
int type = ELFW(ST_TYPE)(esym->st_info);
if (type == STT_FUNC || type == STT_GNU_IFUNC) {
if (wanted_pc >= esym->st_value &&
wanted_pc < esym->st_value + esym->st_size) {
pstrcpy(func_name, sizeof(func_name),
elf_str + esym->st_name);
rc->elf_str + esym->st_name);
func_addr = esym->st_value;
last_incl_index = 0;
goto found;
}
}
}
/* did not find any info: */
rt_printf("%s %p ???", msg, (void*)wanted_pc);
return 0;
found:
if ((rc = rc->next))
goto next;
found:
i = last_incl_index;
if (i > 0)
rt_printf("%s:%d: ", incl_files[--i], last_line_num);
rt_printf("%s %p", msg, (void*)wanted_pc);
if (func_name[0] != '\0')
rt_printf(" %s()", func_name);
if (i > 0) {
str = incl_files[--i];
if (skip[0] && strstr(str, skip))
return (addr_t)-1;
rt_printf("%s:%d: ", str, last_line_num);
} else
rt_printf("%08llx : ", (long long)wanted_pc);
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
#if 0
if (--i >= 0) {
rt_printf(" (included from ");
for (;;) {
@ -503,48 +509,79 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
}
rt_printf(")");
}
#endif
return func_addr;
}
typedef struct rt_context {
addr_t ip, fp, sp, pc;
} rt_context;
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
{
rt_context *rc = &g_rtctxt;
addr_t pc = 0;
char skip[100];
int i, level, ret, n;
const char *a, *b, *msg;
if (fp) {
/* we're called from tcc_backtrace. */
rc->fp = (addr_t)fp;
rc->ip = (addr_t)ip;
msg = "";
} else {
/* we're called from signal/exception handler */
msg = "RUNTIME ERROR: ";
}
skip[0] = 0;
/* If fmt is like "^file.c^..." then skip calls from 'file.c' */
if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
memcpy(skip, a, b - a), skip[b - a] = 0;
fmt = b + 1;
}
n = rc->num_callers ? rc->num_callers : 6;
for (i = level = 0; level < n; i++) {
ret = rt_get_caller_pc(&pc, rc, i);
a = "%s";
if (ret != -1) {
pc = rt_printline(rc, pc, level ? "by" : "at", skip);
if (pc == (addr_t)-1)
continue;
a = ": %s";
}
if (level == 0) {
rt_printf(a, msg);
rt_vprintf(fmt, ap);
} else if (ret == -1)
break;
rt_printf("\n");
if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
break;
++level;
}
rc->ip = rc->fp = 0;
return 0;
}
/* emit a run time error at position 'pc' */
static void rt_error(rt_context *rc, const char *fmt, ...)
static int rt_error(const char *fmt, ...)
{
va_list ap;
addr_t pc;
int i;
TCCState *s1;
s1 = get_s1_for_run();
if (*fmt == ' ') {
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
fmt = *s1->rt_bound_error_msg;
else
++fmt;
}
rt_printf("Runtime error: ");
int ret;
va_start(ap, fmt);
rt_vprintf(fmt, ap);
ret = _rt_error(0, 0, fmt, ap);
va_end(ap);
rt_printf("\n");
return ret;
}
if (!s1)
return;
for(i=0; i<s1->rt_num_callers; i++) {
if (rt_get_caller_pc(&pc, rc, i) < 0)
break;
pc = rt_printline(s1, pc, i ? "by" : "at");
rt_printf("\n");
if (pc == (addr_t)s1->rt_prog_main && pc)
break;
}
static void rt_exit(int code)
{
rt_context *rc = &g_rtctxt;
if (rc->do_jmp)
longjmp(rc->jmp_buf, code ? code : 256);
exit(code);
}
/* ------------------------------------------------------------- */
@ -621,36 +658,36 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
/* signal handler for fatal errors */
static void sig_error(int signum, siginfo_t *siginf, void *puc)
{
rt_context rc;
rt_context *rc = &g_rtctxt;
rt_getcontext(puc, rc);
rt_getcontext(puc, &rc);
switch(signum) {
case SIGFPE:
switch(siginf->si_code) {
case FPE_INTDIV:
case FPE_FLTDIV:
rt_error(&rc, "division by zero");
rt_error("division by zero");
break;
default:
rt_error(&rc, "floating point exception");
rt_error("floating point exception");
break;
}
break;
case SIGBUS:
case SIGSEGV:
rt_error(&rc, " dereferencing invalid pointer");
rt_error("invalid memory access");
break;
case SIGILL:
rt_error(&rc, "illegal instruction");
rt_error("illegal instruction");
break;
case SIGABRT:
rt_error(&rc, "abort() called");
rt_error("abort() called");
break;
default:
rt_error(&rc, "caught signal %d", signum);
rt_error("caught signal %d", signum);
break;
}
exit(255);
rt_exit(255);
}
#ifndef SA_SIGINFO
@ -664,7 +701,7 @@ static void set_exception_handler(void)
/* install TCC signal handlers to print debug info on fatal
runtime errors */
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
#ifdef SIGSTKSZ
#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
sigact.sa_flags |= SA_ONSTACK;
#endif
sigact.sa_sigaction = sig_error;
@ -674,7 +711,7 @@ static void set_exception_handler(void)
sigaction(SIGSEGV, &sigact, NULL);
sigaction(SIGBUS, &sigact, NULL);
sigaction(SIGABRT, &sigact, NULL);
#ifdef SIGSTKSZ
#if 0//def SIGSTKSZ
/* This allows stack overflow to be reported instead of a SEGV */
{
stack_t ss;
@ -689,32 +726,35 @@ static void set_exception_handler(void)
}
#else /* WIN32 */
/* signal handler for fatal errors */
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
rt_context rc;
rt_context *rc = &g_rtctxt;
unsigned code;
rt_getcontext(ex_info->ContextRecord, rc);
rt_getcontext(ex_info->ContextRecord, &rc);
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
rt_error(&rc, " access violation");
rt_error("invalid memory access");
break;
case EXCEPTION_STACK_OVERFLOW:
rt_error(&rc, "stack overflow");
rt_error("stack overflow");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
rt_error(&rc, "division by zero");
rt_error("division by zero");
break;
case EXCEPTION_BREAKPOINT:
case EXCEPTION_SINGLE_STEP:
rc.ip = *(addr_t*)rc.sp;
rt_error(&rc, "^breakpoint/single-step exception:");
rc->ip = *(addr_t*)rc->sp;
rt_error("breakpoint/single-step exception:");
return EXCEPTION_CONTINUE_SEARCH;
default:
rt_error(&rc, "caught exception %08x", code);
rt_error("caught exception %08x", code);
break;
}
if (rc->do_jmp)
rt_exit(255);
return EXCEPTION_EXECUTE_HANDLER;
}
@ -807,7 +847,6 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
#endif
#endif /* CONFIG_TCC_BACKTRACE */
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_STATIC

View File

@ -73,6 +73,7 @@ endif
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
Q = # >/dev/null 2>&1
all test :
$(MAKE) clean-s
@ -88,7 +89,7 @@ hello-run: ../examples/ex1.c
libtes%: libtcc_tes%$(EXESUF)
@echo ------------ $@ ------------
./libtcc_tes$*$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES)
./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES)
libtcc_tes%$(EXESUF): libtcc_tes%.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
@ -105,22 +106,24 @@ test.ref: tcctest.c
# auto test
test1 test1b: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) -run $< > test.out1
@diff -u test.ref test.out1 && echo "Auto Test OK"
$(TCC) -w -run $< > test.out1 $Q
@diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
# iterated test2 (compile tcc then compile tcctest.c !)
test2 test2b: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
@diff -u test.ref test.out2 && echo "Auto Test2 OK"
$(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2 $Q
@diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3 test3b: tcctest.c test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3 $Q
@diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
test%b : TCCFLAGS += -b
AUTO_TEST = Auto Test
test%b : TCCFLAGS += -b -bt1
test%b : AUTO_TEST = Auto Bound-Test
# binary output test
test4: tcctest.c test.ref
@ -129,21 +132,21 @@ test4: tcctest.c test.ref
$(TCC) -c -o tcctest3.o $<
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
@if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
# dynamic output
$(TCC) -o tcctest1 $<
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
@if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 $<
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
@if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
test4_static: tcctest.c test.ref
# static output.
$(TCC) -static -o tcctest2 $<
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
@if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
dlltest:
@ -164,32 +167,29 @@ memtest:
@echo ------------ $@ ------------
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14 16 18
BOUNDS_OK = 1 4 8 10 14 16
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
btest: boundtest.c
@echo ------------ $@ ------------
@for i in $(BOUNDS_OK); do \
echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -run $< $$i ; then \
echo succeeded as expected; \
echo "- Test $$i succeeded as expected" ; \
else\
echo Failed positive test $$i ; exit 1 ; \
echo "- Failed positive test $$i" ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -run $< $$i ; then \
echo Failed negative test $$i ; exit 1 ;\
if $(TCC) -b -bt1 -run $< $$i ; then \
echo "- Failed negative test $$i" ; exit 1 ;\
else\
echo failed as expected; \
echo "- Test $$i failed as expected" ; \
fi ;\
done ;\
echo; echo Bound test OK
echo Bound test OK
# speed test
speedtest: ex2 ex3

View File

@ -50,15 +50,12 @@ int test4(void)
int i, sum = 0;
int *tab4;
fprintf(stderr, "%s start\n", __FUNCTION__);
tab4 = malloc(20 * sizeof(int));
for(i=0;i<20;i++) {
sum += tab4[i];
}
free(tab4);
fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
@ -68,15 +65,12 @@ int test5(void)
int i, sum = 0;
int *tab4;
fprintf(stderr, "%s start\n", __FUNCTION__);
tab4 = malloc(20 * sizeof(int));
for(i=0;i<21;i++) {
sum += tab4[i];
}
free(tab4);
fprintf(stderr, "%s end\n", __FUNCTION__);
return sum;
}
@ -198,16 +192,12 @@ int test16()
char *demo = "This is only a test.";
char *p;
fprintf(stderr, "%s start\n", __FUNCTION__);
p = alloca(16);
strcpy(p,"12345678901234");
printf("alloca: p is %s\n", p);
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
return 0;
}
@ -217,211 +207,11 @@ int test17()
char *demo = "This is only a test.";
char *p;
fprintf(stderr, "%s start\n", __FUNCTION__);
p = alloca(16);
strcpy(p,"12345678901234");
printf("alloca: p is %s\n", p);
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
fprintf(stderr, "%s end\n", __FUNCTION__);
return 0;
}
#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort();
extern void __bound_never_fatal (int neverfatal);
extern const char *__bound_error_msg;
static void init18(char *a, char *b)
{
memset (a, 'a', 10);
a[3] = 0;
a[9] = 0;
memset (b, 'b', 10);
__bound_error_msg = "";
}
/* ok (catch all errors) */
int test18()
{
char pad1[10];
char a[10];
char pad2[10];
char b[10];
char pad3[10];
memset (pad1, 0, sizeof(pad1));
memset (pad2, 0, sizeof(pad2));
memset (pad3, 0, sizeof(pad3));
/* -2 in case TCC_BOUNDS_NEVER_FATAL is set */
__bound_never_fatal (-2);
/* memcpy */
init18(a,b);
memcpy(&a[1],&b[0],10);
CHECK("memcpy dest");
init18(a,b);
memcpy(&a[0],&b[1],10);
CHECK("memcpy src");
init18(a,b);
memcpy(&a[0],&a[3],4);
CHECK("overlapping regions");
init18(a,b);
memcpy(&a[3],&a[0],4);
CHECK("overlapping regions");
/* memcmp */
init18(a,b);
memcmp(&b[1],&b[0],10);
CHECK("memcmp s1");
init18(a,b);
memcmp(&b[0],&b[1],10);
CHECK("memcmp s2");
/* memmove */
init18(a,b);
memmove(&b[1],&b[0],10);
CHECK("memmove dest");
init18(a,b);
memmove(&b[0],&b[1],10);
CHECK("memmove src");
/* memset */
init18(a,b);
memset(&b[1],'b',10);
CHECK("memset");
/* strlen */
init18(a,b);
strlen(&b[0]);
CHECK("strlen");
/* strcpy */
init18(a,b);
strcpy(&a[7], &a[0]);
CHECK("strcpy dest");
init18(a,b);
strcpy(&a[0], &b[7]);
CHECK("strcpy src");
init18(a,b);
strcpy(&a[0], &a[1]);
CHECK("overlapping regions");
init18(a,b);
strcpy(&a[2], &a[0]);
CHECK("overlapping regions");
/* strncpy */
init18(a,b);
strncpy(&a[7], &a[0], 10);
CHECK("strncpy dest");
init18(a,b);
strncpy(&a[0], &b[7], 10);
CHECK("strncpy src");
init18(a,b);
strncpy(&a[0], &a[1], 10);
CHECK("overlapping regions");
strncpy(&a[2], &a[0], 10);
CHECK("overlapping regions");
/* strcmp */
init18(a,b);
strcmp(&b[2], &b[0]);
CHECK("strcmp s1");
init18(a,b);
strcmp(&b[0], &b[2]);
CHECK("strcmp s2");
/* strncmp */
init18(a,b);
strncmp(&b[5], &b[0], 10);
CHECK("strncmp s1");
init18(a,b);
strncmp(&b[0], &b[5], 10);
CHECK("strncmp s2");
/* strcat */
init18(a,b);
strcat(&a[7], &a[0]);
CHECK("strcat dest");
init18(a,b);
strcat(&a[0], &b[5]);
CHECK("strcat src");
init18(a,b);
strcat(&a[0], &a[4]);
CHECK("overlapping regions");
init18(a,b);
strcat(&a[3], &a[0]);
CHECK("overlapping regions");
/* strchr */
init18(a,b);
strchr(&b[0], 'a');
CHECK("strchr");
/* strdup */
init18(a,b);
free(strdup(&b[0]));
CHECK("strdup");
__bound_never_fatal (2);
/* memcpy */
init18(a,b);
memcpy(&a[0],&b[0],10);
init18(a,b);
memcpy(&a[0],&a[3],3);
init18(a,b);
memcpy(&a[3],&a[0],3);
/* memcmp */
init18(a,b);
memcmp(&b[0],&b[0],10);
/* memmove */
init18(a,b);
memmove(&b[0],&b[5],5);
init18(a,b);
memmove(&b[5],&b[0],5);
/* memset */
init18(a,b);
memset(&b[0],'b',10);
/* strlen */
init18(a,b);
strlen (&a[0]);
/* strcpy */
init18(a,b);
strcpy (&a[0], &a[7]);
/* strncpy */
init18(a,b);
strncpy (&a[0], &a[7], 4);
/* strcmp */
init18(a,b);
strcmp (&a[0], &a[4]);
/* strncmp */
init18(a,b);
strncmp (&a[0], &a[4], 10);
/* strcat */
init18(a,b);
strcat (&a[0], &a[7]);
/* strchr */
init18(a,b);
strchr (&a[0], 0);
/* strdup */
init18(a,b);
free (strdup (&a[0]));
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
return 0;
}
@ -443,8 +233,7 @@ int (*table_test[])(void) = {
test14,
test15,
test16,
test17,
test18,
test17
};
int main(int argc, char **argv)

View File

@ -203,14 +203,11 @@ TF_TYPE(thread_test_complex, vn)
sprintf(b, "%d", F(n));
argv[argc++] = "../tcc.c";
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
#if 0
argv[argc++] = "-run";
argv[argc++] = "../tcc.c";
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
#endif
argv[argc++] = "-g";
argv[argc++] = "-DFIB";
argv[argc++] = "-run";
argv[argc++] = __FILE__;
@ -221,23 +218,24 @@ TF_TYPE(thread_test_complex, vn)
sleep_ms(2);
ret = tcc_add_file(s, argv[0]);
sleep_ms(3);
if (ret >= 0)
tcc_run(s, argc, argv);
if (ret < 0)
exit(1);
tcc_run(s, argc, argv);
tcc_delete(s);
fflush(stdout);
return 0;
}
void time_tcc(int n)
void time_tcc(int n, const char *src)
{
TCCState *s;
int ret;
while (--n >= 0) {
s = new_state(1);
ret = tcc_add_file(s, "../tcc.c");
ret = tcc_add_file(s, src);
tcc_delete(s);
if (ret < 0)
break;
exit(1);
}
}
@ -260,6 +258,11 @@ int main(int argc, char **argv)
g_argc = argc;
g_argv = argv;
if (argc < 2) {
fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
return 1;
}
#if 1
printf("----- libtest : mixed calls -------\n"), fflush(stdout);
t = getclock_ms();
@ -285,7 +288,7 @@ int main(int argc, char **argv)
#if 1
printf("----- compilation of tcc -----------\n"), fflush(stdout);
t = getclock_ms();
time_tcc(10);
time_tcc(10, argv[1]);
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
#endif
return 0;

View File

@ -1725,10 +1725,6 @@ void cast_test()
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
#ifdef __TINYC__
# pragma comment(option, "-w")
#endif
/* from pointer to integer types */
printf("%d %d %ld %ld %lld %lld\n",
(int)p, (unsigned int)p,
@ -1739,10 +1735,6 @@ void cast_test()
printf("%p %p %p %p\n",
(void *)a, (void *)b, (void *)c, (void *)d);
#ifdef __TINYC__
# pragma comment(option, "-W")
#endif
/* int to int with sign set */
printf("0x%lx\n", (unsigned long)(int)ul);
}
@ -3406,7 +3398,7 @@ void clobber_r12(void)
}
#endif
void test_high_clobbers(void)
void test_high_clobbers_really(void)
{
#if defined __x86_64__ && !defined _WIN64
register long val asm("r12");
@ -3422,6 +3414,20 @@ void test_high_clobbers(void)
#endif
}
void test_high_clobbers(void)
{
#if defined __x86_64__ && !defined _WIN64
long x1, x2;
asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
test_high_clobbers_really();
asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */
/* should be 0 but tcc doesn't save r12 automatically, which has
bad effects when gcc helds TCCState *s in r12 in tcc.c:main */
//printf("r12-clobber-diff: %lx\n", x2 - x1);
#endif
}
static long cpu_number;
void trace_console(long len, long len2)
{

View File

@ -0,0 +1,165 @@
#include <stdio.h>
/* ------------------------------------------------------- */
#if defined test_backtrace_1
void f3()
{
printf("* f3()\n"), fflush(stdout);
*(void**)0 = 0;
}
void f2()
{
printf("* f2()\n"), fflush(stdout);
f3();
}
void f1()
{
printf("* f1()\n"), fflush(stdout);
f2();
}
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
f1();
printf("* exit main\n"), fflush(stdout);
return 0;
}
/* ------------------------------------------------------- */
#elif defined test_bcheck_1
struct s { int a,b,c,d,e; };
struct s s[3];
struct s *ps = s;
void f1()
{
printf("* f1()\n"), fflush(stdout);
ps[3] = ps[2];
}
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
f1();
printf("* exit main\n"), fflush(stdout);
return 0;
}
/* ------------------------------------------------------- */
#elif defined test_tcc_backtrace_2
/* test custom backtrace and 'exit()' redirection */
int tcc_backtrace(const char *fmt, ...);
void exit(int);
void f2()
{
printf("* f2()\n");
printf("* exit f2\n"), fflush(stdout);
exit(34);
}
void f1()
{
printf("* f1()\n"), fflush(stdout);
tcc_backtrace("Hello from %s!", "f1");
f2();
}
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
f1();
printf("* exit main\n"), fflush(stdout);
return 0;
}
/* ------------------------------------------------------- */
#elif defined test_tcc_backtrace_3
/* this test should be run despite of the exit(34) above */
int main(int argc, char **argv)
{
printf("* main\n"), fflush(stdout);
return 1;
}
/* ------------------------------------------------------- */
#else
#include <malloc.h>
#include <string.h>
char *strdup();
int main()
{
char pad1[10];
char a[10];
char pad2[10];
char b[10];
char pad3[10];
memset (pad1, 0, sizeof(pad1));
memset (pad2, 0, sizeof(pad2));
memset (pad3, 0, sizeof(pad3));
memset (a, 'a', 10);
a[3] = 0;
a[9] = 0;
memset (b, 'b', 10);
#if defined test_bcheck_100
memcpy(&a[1],&b[0],10);
#elif defined test_bcheck_101
memcpy(&a[0],&b[1],10);
#elif defined test_bcheck_102
memcpy(&a[0],&a[3],4);
#elif defined test_bcheck_103
memcpy(&a[3],&a[0],4);
#elif defined test_bcheck_104
memcmp(&b[1],&b[0],10);
#elif defined test_bcheck_105
memcmp(&b[0],&b[1],10);
#elif defined test_bcheck_106
memmove(&b[1],&b[0],10);
#elif defined test_bcheck_107
memmove(&b[0],&b[1],10);
#elif defined test_bcheck_108
memset(&b[1],'b',10);
#elif defined test_bcheck_109
strlen(&b[0]);
#elif defined test_bcheck_110
strcpy(&a[7], &a[0]);
#elif defined test_bcheck_111
strcpy(&a[0], &b[7]);
#elif defined test_bcheck_112
strcpy(&a[0], &a[1]);
#elif defined test_bcheck_113
strcpy(&a[2], &a[0]);
#elif defined test_bcheck_114
strncpy(&a[7], &a[0], 10);
#elif defined test_bcheck_115
strncpy(&a[0], &b[7], 10);
#elif defined test_bcheck_116
strncpy(&a[0], &a[1], 10);
#elif defined test_bcheck_117
strncpy(&a[2], &a[0], 10);
#elif defined test_bcheck_118
strcmp(&b[2], &b[0]);
#elif defined test_bcheck_119
strcmp(&b[0], &b[2]);
#elif defined test_bcheck_120
strncmp(&b[5], &b[0], 10);
#elif defined test_bcheck_121
strncmp(&b[0], &b[5], 10);
#elif defined test_bcheck_122
strcat(&a[7], &a[0]);
#elif defined test_bcheck_123
strcat(&a[0], &b[5]);
#elif defined test_bcheck_124
strcat(&a[0], &a[4]);
#elif defined test_bcheck_125
strcat(&a[3], &a[0]);
#elif defined test_bcheck_126
strchr(&b[0], 'a');
#elif defined test_bcheck_127
free(strdup(&b[0]));
#endif
}
/* ------------------------------------------------------- */
#endif

View File

@ -0,0 +1,164 @@
[test_backtrace_1]
* main
* f1()
* f2()
* f3()
112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access
112_backtrace.c:14: by f2
112_backtrace.c:19: by f1
112_backtrace.c:24: by main
[returns 255]
[test_bcheck_1]
* main
* f1()
112_backtrace.c:38: at f1: BCHECK: ........ is outside of the region
112_backtrace.c:43: by main
112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x14 in memmove dest
112_backtrace.c:43: by main
[returns 255]
[test_tcc_backtrace_2]
* main
* f1()
112_backtrace.c:64: at f1: Hello from f1!
112_backtrace.c:70: by main
* f2()
* exit f2
[returns 34]
[test_tcc_backtrace_3]
* main
[returns 1]
[test_bcheck_100]
112_backtrace.c:107: at main: BCHECK: ........ is outside of the region
112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0xa in memcpy dest
[returns 255]
[test_bcheck_101]
112_backtrace.c:109: at main: BCHECK: ........ is outside of the region
112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0xa in memcpy src
[returns 255]
[test_bcheck_102]
112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy
[returns 255]
[test_bcheck_103]
112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy
[returns 255]
[test_bcheck_104]
112_backtrace.c:115: at main: BCHECK: ........ is outside of the region
112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s1
[returns 255]
[test_bcheck_105]
112_backtrace.c:117: at main: BCHECK: ........ is outside of the region
112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s2
[returns 255]
[test_bcheck_106]
112_backtrace.c:119: at main: BCHECK: ........ is outside of the region
112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0xa in memmove dest
[returns 255]
[test_bcheck_107]
112_backtrace.c:121: at main: BCHECK: ........ is outside of the region
112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0xa in memmove src
[returns 255]
[test_bcheck_108]
112_backtrace.c:123: at main: BCHECK: ........ is outside of the region
112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0xa in memset
[returns 255]
[test_bcheck_109]
112_backtrace.c:125: at main: BCHECK: ........ is outside of the region
112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0xb in strlen
[returns 255]
[test_bcheck_110]
112_backtrace.c:127: at main: BCHECK: ........ is outside of the region
112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy dest
[returns 255]
[test_bcheck_111]
112_backtrace.c:129: at main: BCHECK: ........ is outside of the region
112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy src
[returns 255]
[test_bcheck_112]
112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strcpy
[returns 255]
[test_bcheck_113]
112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcpy
[returns 255]
[test_bcheck_114]
112_backtrace.c:135: at main: BCHECK: ........ is outside of the region
112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy dest
[returns 255]
[test_bcheck_115]
112_backtrace.c:137: at main: BCHECK: ........ is outside of the region
112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy src
[returns 255]
[test_bcheck_116]
112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strncpy
[returns 255]
[test_bcheck_117]
112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strncpy
[returns 255]
[test_bcheck_118]
112_backtrace.c:143: at main: BCHECK: ........ is outside of the region
112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s1
[returns 255]
[test_bcheck_119]
112_backtrace.c:145: at main: BCHECK: ........ is outside of the region
112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s2
[returns 255]
[test_bcheck_120]
112_backtrace.c:147: at main: BCHECK: ........ is outside of the region
112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s1
[returns 255]
[test_bcheck_121]
112_backtrace.c:149: at main: BCHECK: ........ is outside of the region
112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s2
[returns 255]
[test_bcheck_122]
112_backtrace.c:151: at main: BCHECK: ........ is outside of the region
112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x6 in strcat dest
[returns 255]
[test_bcheck_123]
112_backtrace.c:153: at main: BCHECK: ........ is outside of the region
112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x6 in strcat src
[returns 255]
[test_bcheck_124]
112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x9), ........(0x6) in strcat
[returns 255]
[test_bcheck_125]
112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcat
[returns 255]
[test_bcheck_126]
112_backtrace.c:159: at main: BCHECK: ........ is outside of the region
112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0xb in strchr
[returns 255]
[test_bcheck_127]
112_backtrace.c:161: at main: BCHECK: ........ is outside of the region
112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0xb in strdup
[returns 255]

View File

@ -20,6 +20,7 @@
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
[test_63_local_enumerator_redefinition]
[returns 1]
[test_61_undefined_enum]
60_errors_and_warnings.c:46: error: unknown type size

View File

@ -24,6 +24,7 @@ ifeq (,$(filter i386,$(ARCH)))
endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
SKIP += 85_asm-outside-function.test
SKIP += 112_backtrace.test
endif
ifeq (-$(findstring gcc,$(CC))-,--)
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
@ -70,12 +71,11 @@ GEN-ALWAYS =
# constructor/destructor
108_constructor.test: NORUN = true
112_backtrace.test: FLAGS += -dt -b
112_backtrace.test: FILTER += -e 's;[0-9A-Fa-fx]\{8,\};........;g'
# Filter source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed 's,$(SRC)/,,g'
# Filter some always-warning
ifeq (-$(findstring arm,$(ARCH))-,-arm-)
FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
endif
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;

View File

@ -138,7 +138,7 @@ copy>nul tcc-win32.txt doc
@if errorlevel 1 goto :the_end
:libtcc1.a
@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o
@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o
.\tcc -m32 -c ../lib/libtcc1.c
.\tcc -m32 -c lib/crt1.c
.\tcc -m32 -c lib/crt1w.c
@ -147,7 +147,6 @@ copy>nul tcc-win32.txt doc
.\tcc -m32 -c lib/dllcrt1.c
.\tcc -m32 -c lib/dllmain.c
.\tcc -m32 -c lib/chkstk.S
.\tcc -m32 -w -c ../lib/bcheck.c
.\tcc -m32 -c ../lib/alloca86.S
.\tcc -m32 -c ../lib/alloca86-bt.S
.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o
@ -160,11 +159,14 @@ copy>nul tcc-win32.txt doc
.\tcc -m64 -c lib/dllcrt1.c
.\tcc -m64 -c lib/dllmain.c
.\tcc -m64 -c lib/chkstk.S
.\tcc -m64 -w -c ../lib/bcheck.c
.\tcc -m64 -c ../lib/alloca86_64.S
.\tcc -m64 -c ../lib/alloca86_64-bt.S
.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
@if errorlevel 1 goto :the_end
.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o
.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o
.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o
.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o
:tcc-doc.html
@if not (%DOC%)==(yes) goto :doc-done
@ -182,7 +184,7 @@ if not exist %INST% mkdir %INST%
if not exist %BIN% mkdir %BIN%
for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f
@if not exist %INST%\lib mkdir %INST%\lib
for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f
for %%f in (lib\*.a lib\*.o lib\*.def) do @copy>nul %%f %INST%\%%f
for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f
:the_end

View File

@ -99,7 +99,7 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
#if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC);
#endif
return do_main(__argc, __targv, _tenviron);
return _tmain(__argc, __targv, _tenviron);
}
// =============================================

View File

@ -191,6 +191,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
if (s1->output_type == TCC_OUTPUT_DLL) {
/* XXX: this logic may depend on TCC's codegen
now TCC uses R_X86_64_32 even for a 64bit pointer */
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
/* Use sign extension! */
qrel->r_addend = (int)read32le(ptr) + val;