aboutsummaryrefslogtreecommitdiff
path: root/tcc.c
diff options
context:
space:
mode:
authorbellard <bellard>2002-01-04 20:17:24 +0000
committerbellard <bellard>2002-01-04 20:17:24 +0000
commit4124f1a1c172408d74832d97d2b66a84c7c2985c (patch)
tree6a9373058b633e52db4d349b448704fca0d40c46 /tcc.c
parent60f781c443cb23fae546afdfe4482d9b3d5fd070 (diff)
downloadtinycc-4124f1a1c172408d74832d97d2b66a84c7c2985c.tar.gz
tinycc-4124f1a1c172408d74832d97d2b66a84c7c2985c.tar.bz2
added minimal debug info support
Diffstat (limited to 'tcc.c')
-rw-r--r--tcc.c584
1 files changed, 562 insertions, 22 deletions
diff --git a/tcc.c b/tcc.c
index 6f7547a..166c00a 100644
--- a/tcc.c
+++ b/tcc.c
@@ -1,7 +1,7 @@
/*
* TCC - Tiny C Compiler
*
- * Copyright (c) 2001 Fabrice Bellard
+ * Copyright (c) 2001, 2002 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,12 @@
#include <string.h>
#include <errno.h>
#include <math.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ucontext.h>
#include <sys/mman.h>
+#include <elf.h>
+#include <stab.h>
#ifndef CONFIG_TCC_STATIC
#include <dlfcn.h>
#endif
@@ -109,6 +114,11 @@ typedef struct Section {
char name[64]; /* section name */
unsigned char *data; /* section data */
unsigned char *data_ptr; /* current data pointer */
+ int sh_num; /* elf section number */
+ int sh_type; /* elf section type */
+ int sh_flags; /* elf section flags */
+ int sh_entsize; /* elf entry size */
+ struct Section *link; /* link to another section */
struct Section *next;
} Section;
@@ -148,9 +158,13 @@ CValue tokc, tok1c;
/* sections */
Section *first_section;
+int section_num;
Section *text_section, *data_section, *bss_section; /* predefined sections */
Section *cur_text_section; /* current section where function code is
generated */
+Section *bounds_section; /* contains global data bound description */
+/* debug sections */
+Section *stab_section, *stabstr_section, *symtab_section, *strtab_section;
/* loc : local variable index
ind : output code index
@@ -163,6 +177,7 @@ int global_expr; /* true if compound literals must be allocated
globally (used during initializers parsing */
int func_vt, func_vc; /* current function return type (used by
return instruction) */
+int last_line_num, last_ind, func_ind; /* debug last line number and pc */
int tok_ident;
TokenSym **table_ident;
TokenSym *hash_ident[TOK_HASH_SIZE];
@@ -178,6 +193,13 @@ IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
char *include_paths[INCLUDE_PATHS_MAX];
int nb_include_paths;
+int char_pointer_type;
+
+/* compile with debug symbol (and use them if error during execution) */
+int do_debug = 0;
+
+/* compile with built-in memory and bounds checker */
+int do_bounds_check = 0;
/* use GNU C extensions */
int gnu_ext = 1;
@@ -380,6 +402,7 @@ void decl_initializer(int t, int r, int c, int first, int size_only);
int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init);
int gv(int rc);
void move_reg(int r, int s);
+void save_regs(void);
void save_reg(int r);
void vpop(void);
void vswap(void);
@@ -407,10 +430,19 @@ int type_decl(int *v, int t, int td);
void error(const char *fmt, ...);
void vpushi(int v);
void vset(int t, int r, int v);
-void greloc(Sym *s, int addr, int type);
void type_to_str(char *buf, int buf_size,
int t, const char *varstr);
+/* section generation */
+void greloc(Sym *s, int addr, int type);
+static int put_elf_str(Section *s, const char *sym);
+static void put_elf_sym(Section *s,
+ unsigned long value, unsigned long size,
+ int info, int other, int shndx, const char *name);
+static void put_stabs(const char *str, int type, int other, int desc, int value);
+static void put_stabn(int type, int other, int desc, int value);
+static void put_stabd(int type, int other, int desc);
+
/* true if float/double/long double type */
static inline int is_float(int t)
{
@@ -419,6 +451,8 @@ static inline int is_float(int t)
return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT;
}
+#include "bcheck.c"
+
#include "i386-gen.c"
#ifdef CONFIG_TCC_STATIC
@@ -571,7 +605,7 @@ char *pstrcat(char *buf, int buf_size, const char *s)
return buf;
}
-Section *new_section(const char *name)
+Section *new_section(const char *name, int sh_type, int sh_flags)
{
Section *sec, **psec;
void *data;
@@ -579,7 +613,12 @@ Section *new_section(const char *name)
sec = malloc(sizeof(Section));
if (!sec)
error("memory full");
+ memset(sec, 0, sizeof(Section));
pstrcpy(sec->name, sizeof(sec->name), name);
+ sec->link = NULL;
+ sec->sh_num = ++section_num;
+ sec->sh_type = sh_type;
+ sec->sh_flags = sh_flags;
data = mmap(NULL, SECTION_VSIZE,
PROT_EXEC | PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
@@ -606,7 +645,8 @@ Section *find_section(const char *name)
if (!strcmp(name, sec->name))
return sec;
}
- return new_section(name);
+ /* sections are created as PROGBITS */
+ return new_section(name, SHT_PROGBITS, SHF_ALLOC);
}
/* add a new relocation entry to symbol 's' */
@@ -936,6 +976,10 @@ int handle_eof(void)
{
if (include_stack_ptr == include_stack)
return -1;
+ /* add end of include file debug info */
+ if (do_debug) {
+ put_stabd(N_EINCL, 0, 0);
+ }
/* pop include stack */
fclose(file);
free(filename);
@@ -1288,6 +1332,10 @@ void preprocess(void)
file = f;
filename = strdup(buf1);
line_num = 1;
+ /* add include file debug info */
+ if (do_debug) {
+ put_stabs(filename, N_BINCL, 0, 0, 0);
+ }
} else if (tok == TOK_IFNDEF) {
c = 1;
goto do_ifdef;
@@ -2831,7 +2879,17 @@ void gen_op(int op)
/* XXX: cast to int ? (long long case) */
vpushi(pointed_size(vtop[-1].t));
gen_op('*');
- gen_opc(op);
+ if (do_bounds_check) {
+ /* if bounded pointers, we generate a special code to test bounds */
+ if (op == '-') {
+ vpushi(0);
+ vswap();
+ gen_op('-');
+ }
+ gen_bounded_ptr_add();
+ } else {
+ gen_opc(op);
+ }
/* put again type if gen_opc() swaped operands */
vtop->t = t1;
}
@@ -4184,7 +4242,7 @@ void unary(void)
if (!s)
error("field not found");
/* add field offset to pointer */
- vtop->t = VT_INT; /* change type to int */
+ vtop->t = char_pointer_type; /* change type to 'char *' */
vpushi(s->c);
gen_op('+');
/* change type to field type, and set to lvalue */
@@ -4524,6 +4582,14 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
int a, b, c, d;
Sym *s;
+ /* generate line number info */
+ if (do_debug &&
+ (last_line_num != line_num || last_ind != ind)) {
+ put_stabn(N_SLINE, 0, line_num, ind - func_ind);
+ last_ind = ind;
+ last_line_num = line_num;
+ }
+
if (tok == TOK_IF) {
/* if test */
next();
@@ -5138,6 +5204,17 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
initializers themselves can create new
initializers */
data_offset += size;
+ /* handles bounds */
+ if (do_bounds_check) {
+ int *bounds_ptr;
+ /* first, we need to add at least one byte between each region */
+ data_offset++;
+ /* then add global data info */
+ bounds_ptr = (int *)bounds_section->data_ptr;
+ *bounds_ptr++ = addr;
+ *bounds_ptr++ = size;
+ bounds_section->data_ptr = (unsigned char *)bounds_ptr;
+ }
sec->data_ptr = (unsigned char *)data_offset;
}
if (has_init) {
@@ -5152,6 +5229,28 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
return addr;
}
+void put_func_debug(int t)
+{
+ int bind;
+ char buf[512];
+
+ if (t & VT_STATIC)
+ bind = STB_LOCAL;
+ else
+ bind = STB_GLOBAL;
+ put_elf_sym(symtab_section, ind, 0,
+ ELF32_ST_INFO(bind, STT_FUNC), 0,
+ cur_text_section->sh_num, funcname);
+ /* stabs info */
+ /* XXX: we put here a dummy type */
+ snprintf(buf, sizeof(buf), "%s:%c1",
+ funcname, t & VT_STATIC ? 'f' : 'F');
+ put_stabs(buf, N_FUN, 0, line_num, ind);
+ func_ind = ind;
+ last_ind = 0;
+ last_line_num = 0;
+}
+
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */
void decl(int l)
{
@@ -5213,6 +5312,9 @@ void decl(int l)
}
sym->r = VT_CONST;
funcname = get_tok_str(v, NULL);
+ /* put debug symbol */
+ if (do_debug)
+ put_func_debug(t);
/* push a dummy symbol to enable local sym storage */
sym_push1(&local_stack, 0, 0, 0);
gfunc_prolog(t);
@@ -5224,6 +5326,10 @@ void decl(int l)
cur_text_section->data_ptr = (unsigned char *)ind;
sym_pop(&label_stack, NULL); /* reset label stack */
sym_pop(&local_stack, NULL); /* reset local stack */
+ /* end of function */
+ if (do_debug) {
+ put_stabn(N_FUN, 0, 0, ind - func_ind);
+ }
funcname = ""; /* for safety */
func_vt = VT_VOID; /* for safety */
break;
@@ -5330,7 +5436,8 @@ void resolve_global_syms(void)
int tcc_compile_file(const char *filename1)
{
Sym *define_start;
-
+ char buf[512];
+
line_num = 1;
funcname = "";
filename = (char *)filename1;
@@ -5343,7 +5450,18 @@ int tcc_compile_file(const char *filename1)
vtop = vstack - 1;
anon_sym = SYM_FIRST_ANOM;
-
+
+ /* file info: full path + filename */
+ if (do_debug) {
+ getcwd(buf, sizeof(buf));
+ pstrcat(buf, sizeof(buf), "/");
+ put_stabs(buf, N_SO, 0, 0, (unsigned long)text_section->data_ptr);
+ put_stabs(filename, N_SO, 0, 0, (unsigned long)text_section->data_ptr);
+ }
+ /* define common 'char *' type because it is often used internally
+ for arrays and struct dereference */
+ char_pointer_type = mk_pointer(VT_BYTE);
+
define_start = define_stack.top;
inp();
ch = '\n'; /* needed to parse correctly first preprocessor command */
@@ -5353,6 +5471,11 @@ int tcc_compile_file(const char *filename1)
expect("declaration");
fclose(file);
+ /* end of translation unit info */
+ if (do_debug) {
+ put_stabn(N_SO, 0, 0, (unsigned long)text_section->data_ptr);
+ }
+
/* reset define stack, but leave -Dsymbols (may be incorrect if
they are undefined) */
sym_pop(&define_stack, define_start);
@@ -5429,6 +5552,17 @@ void open_dll(char *libname)
error((char *)dlerror());
}
+static void *resolve_sym(const char *sym)
+{
+ void *ptr;
+ if (do_bounds_check) {
+ ptr = bound_resolve_sym(sym);
+ if (ptr)
+ return ptr;
+ }
+ return dlsym(NULL, sym);
+}
+
void resolve_extern_syms(void)
{
Sym *s, *s1;
@@ -5443,7 +5577,7 @@ void resolve_extern_syms(void)
and patch it */
if (s->c) {
str = get_tok_str(s->v, NULL);
- addr = (int)dlsym(NULL, str);
+ addr = (int)resolve_sym(str);
if (!addr)
error("unresolved external reference '%s'", str);
greloc_patch(s, addr);
@@ -5453,25 +5587,403 @@ void resolve_extern_syms(void)
}
}
-/* output a binary file (for testing) */
+static int put_elf_str(Section *s, const char *sym)
+{
+ int c, offset;
+ offset = s->data_ptr - s->data;
+ for(;;) {
+ c = *sym++;
+ *s->data_ptr++ = c;
+ if (c == '\0')
+ break;
+ }
+ return offset;
+}
+
+static void put_elf_sym(Section *s,
+ unsigned long value, unsigned long size,
+ int info, int other, int shndx, const char *name)
+{
+ int name_offset;
+ Elf32_Sym *sym;
+
+ sym = (Elf32_Sym *)s->data_ptr;
+ if (name)
+ name_offset = put_elf_str(s->link, name);
+ else
+ name_offset = 0;
+ sym->st_name = name_offset;
+ sym->st_value = value;
+ sym->st_size = size;
+ sym->st_info = info;
+ sym->st_other = other;
+ sym->st_shndx = shndx;
+ s->data_ptr += sizeof(Elf32_Sym);
+}
+
+/* put stab debug information */
+
+typedef struct {
+ unsigned long n_strx; /* index into string table of name */
+ unsigned char n_type; /* type of symbol */
+ unsigned char n_other; /* misc info (usually empty) */
+ unsigned short n_desc; /* description field */
+ unsigned long n_value; /* value of symbol */
+} Stab_Sym;
+
+static void put_stabs(const char *str, int type, int other, int desc, int value)
+{
+ Stab_Sym *sym;
+
+ sym = (Stab_Sym *)stab_section->data_ptr;
+ if (str) {
+ sym->n_strx = put_elf_str(stabstr_section, str);
+ } else {
+ sym->n_strx = 0;
+ }
+ sym->n_type = type;
+ sym->n_other = other;
+ sym->n_desc = desc;
+ sym->n_value = value;
+
+ stab_section->data_ptr += sizeof(Stab_Sym);
+}
+
+static void put_stabn(int type, int other, int desc, int value)
+{
+ put_stabs(NULL, type, other, desc, value);
+}
+
+static void put_stabd(int type, int other, int desc)
+{
+ put_stabs(NULL, type, other, desc, 0);
+}
+
+/* output an ELF file (currently, only for testing) */
void build_exe(char *filename)
{
+ Elf32_Ehdr ehdr;
FILE *f;
+ int shnum, i, phnum, file_offset, offset, size, j;
+ Section *sec, *strsec;
+ Elf32_Shdr *shdr, *sh;
+ Elf32_Phdr *phdr, *ph;
+
+ memset(&ehdr, 0, sizeof(ehdr));
+
+ /* we add a section for symbols */
+ strsec = new_section(".shstrtab", SHT_STRTAB, 0);
+ put_elf_str(strsec, "");
+
+ /* count number of sections and compute number of program segments */
+ shnum = 1; /* section index zero is reserved */
+ phnum = 0;
+ for(sec = first_section; sec != NULL; sec = sec->next) {
+ shnum++;
+ if (sec->sh_flags & SHF_ALLOC)
+ phnum++;
+ }
+ /* allocate section headers */
+ shdr = malloc(shnum * sizeof(Elf32_Shdr));
+ if (!shdr)
+ error("memory full");
+ memset(shdr, 0, shnum * sizeof(Elf32_Shdr));
+ /* allocate program segment headers */
+ phdr = malloc(phnum * sizeof(Elf32_Phdr));
+ if (!phdr)
+ error("memory full");
+ memset(phdr, 0, phnum * sizeof(Elf32_Phdr));
+
+ /* XXX: find correct load order */
+ file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
+ for(sec = first_section, i = 1; sec != NULL; sec = sec->next, i++) {
+ sh = &shdr[i];
+ sh->sh_name = put_elf_str(strsec, sec->name);
+ sh->sh_type = sec->sh_type;
+ sh->sh_flags = sec->sh_flags;
+ sh->sh_entsize = sec->sh_entsize;
+ if (sec->link)
+ sh->sh_link = sec->link->sh_num;
+ if (sh->sh_type == SHT_STRTAB) {
+ sh->sh_addralign = 1;
+ } else if (sh->sh_type == SHT_SYMTAB ||
+ (sh->sh_flags & SHF_ALLOC) == 0) {
+ sh->sh_addralign = 4;
+ } else {
+ sh->sh_addr = (Elf32_Word)sec->data;
+ sh->sh_addralign = 4096;
+ }
+ sh->sh_size = (Elf32_Word)sec->data_ptr - (Elf32_Word)sec->data;
+ /* align to section start */
+ file_offset = (file_offset + sh->sh_addralign - 1) &
+ ~(sh->sh_addralign - 1);
+ sh->sh_offset = file_offset;
+ file_offset += sh->sh_size;
+ }
+ /* build program headers (simplistic - not fully correct) */
+ j = 0;
+ for(i=1;i<shnum;i++) {
+ sh = &shdr[i];
+ if (sh->sh_type == SHT_PROGBITS &&
+ (sh->sh_flags & SHF_ALLOC) != 0) {
+ ph = &phdr[j++];
+ ph->p_type = PT_LOAD;
+ ph->p_offset = sh->sh_offset;
+ ph->p_vaddr = sh->sh_addr;
+ ph->p_paddr = ph->p_vaddr;
+ ph->p_filesz = sh->sh_size;
+ ph->p_memsz = sh->sh_size;
+ ph->p_flags = PF_R;
+ if (sh->sh_flags & SHF_WRITE)
+ ph->p_flags |= PF_W;
+ if (sh->sh_flags & SHF_EXECINSTR)
+ ph->p_flags |= PF_X;
+ ph->p_align = sh->sh_addralign;
+ }
+ }
+
+ /* align to 4 */
+ file_offset = (file_offset + 3) & -4;
+
+ /* fill header */
+ ehdr.e_ident[0] = ELFMAG0;
+ ehdr.e_ident[1] = ELFMAG1;
+ ehdr.e_ident[2] = ELFMAG2;
+ ehdr.e_ident[3] = ELFMAG3;
+ ehdr.e_ident[4] = ELFCLASS32;
+ ehdr.e_ident[5] = ELFDATA2LSB;
+ ehdr.e_ident[6] = EV_CURRENT;
+ ehdr.e_type = ET_EXEC;
+ ehdr.e_machine = EM_386;
+ ehdr.e_version = EV_CURRENT;
+ ehdr.e_entry = 0; /* XXX: patch it */
+ ehdr.e_phoff = sizeof(Elf32_Ehdr);
+ ehdr.e_shoff = file_offset;
+ ehdr.e_ehsize = sizeof(Elf32_Ehdr);
+ ehdr.e_phentsize = sizeof(Elf32_Phdr);
+ ehdr.e_phnum = phnum;
+ ehdr.e_shentsize = sizeof(Elf32_Shdr);
+ ehdr.e_shnum = shnum;
+ ehdr.e_shstrndx = shnum - 1;
+
+ /* write elf file */
f = fopen(filename, "w");
- fwrite(text_section->data, 1, text_section->data_ptr - text_section->data, f);
+ if (!f)
+ error("could not write '%s'", filename);
+ fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
+ fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
+ offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
+ for(sec = first_section, i = 1; sec != NULL; sec = sec->next, i++) {
+ sh = &shdr[i];
+ while (offset < sh->sh_offset) {
+ fputc(0, f);
+ offset++;
+ }
+ size = sec->data_ptr - sec->data;
+ fwrite(sec->data, 1, size, f);
+ offset += size;
+ }
+ while (offset < ehdr.e_shoff) {
+ fputc(0, f);
+ offset++;
+ }
+ fwrite(shdr, 1, shnum * sizeof(Elf32_Shdr), f);
fclose(f);
}
+/* print the position in the source file of PC value 'pc' by reading
+ the stabs debug information */
+static void rt_printline(unsigned long wanted_pc)
+{
+ Stab_Sym *sym, *sym_end;
+ char func_name[128];
+ unsigned long func_addr, last_pc, pc;
+ const char *incl_files[INCLUDE_STACK_SIZE];
+ int incl_index, len, last_line_num, i;
+ const char *str, *p;
+
+ func_name[0] = '\0';
+ func_addr = 0;
+ incl_index = 0;
+ last_pc = 0xffffffff;
+ last_line_num = 1;
+ sym = (Stab_Sym *)stab_section->data + 1;
+ sym_end = (Stab_Sym *)stab_section->data_ptr;
+ while (sym < sym_end) {
+ switch(sym->n_type) {
+ /* function start or end */
+ case N_FUN:
+ if (sym->n_strx == 0) {
+ func_name[0] = '\0';
+ func_addr = 0;
+ } else {
+ str = stabstr_section->data + sym->n_strx;
+ p = strchr(str, ':');
+ if (!p) {
+ pstrcpy(func_name, sizeof(func_name), str);
+ } else {
+ len = p - str;
+ if (len > sizeof(func_name) - 1)
+ len = sizeof(func_name) - 1;
+ memcpy(func_name, str, len);
+ func_name[len] = '\0';
+ }
+ func_addr = sym->n_value;
+ }
+ break;
+ /* line number info */
+ case N_SLINE:
+ pc = sym->n_value + func_addr;
+ if (wanted_pc >= last_pc && wanted_pc < pc)
+ goto found;
+ last_pc = pc;
+ last_line_num = sym->n_desc;
+ break;
+ /* include files */
+ case N_BINCL:
+ str = stabstr_section->data + sym->n_strx;
+ add_incl:
+ if (incl_index < INCLUDE_STACK_SIZE) {
+ incl_files[incl_index++] = str;
+ }
+ break;
+ case N_EINCL:
+ if (incl_index > 1)
+ incl_index--;
+ break;
+ case N_SO:
+ if (sym->n_strx == 0) {
+ incl_index = 0; /* end of translation unit */
+ } else {
+ str = stabstr_section->data + sym->n_strx;
+ /* do not add path */
+ len = strlen(str);
+ if (len > 0 && str[len - 1] != '/')
+ goto add_incl;
+ }
+ break;
+ }
+ sym++;
+ }
+ /* did not find line number info: */
+ fprintf(stderr, "(no debug info, pc=0x%08lx) ", wanted_pc);
+ return;
+ found:
+ for(i = 0; i < incl_index - 1; i++)
+ fprintf(stderr, "In file included from %s\n",
+ incl_files[i]);
+ if (incl_index > 0) {
+ fprintf(stderr, "%s:%d: ",
+ incl_files[incl_index - 1], last_line_num);
+ }
+ if (func_name[0] != '\0') {
+ fprintf(stderr, "in function '%s()': ", func_name);
+ }
+}
+
+
+/* signal handler for fatal errors */
+static void sig_error(int signum, siginfo_t *siginf, void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+
+#ifdef __i386__
+ pc = uc->uc_mcontext.gregs[14];
+#else
+#error please put the right sigcontext field
+#endif
+
+ rt_printline(pc);
+
+ switch(signum) {
+ case SIGFPE:
+ switch(siginf->si_code) {
+ case FPE_INTDIV:
+ case FPE_FLTDIV:
+ fprintf(stderr, "division by zero\n");
+ break;
+ default:
+ fprintf(stderr, "floating point exception\n");
+ break;
+ }
+ break;
+ case SIGBUS:
+ case SIGSEGV:
+ fprintf(stderr, "dereferencing invalid pointer\n");
+ break;
+ case SIGILL:
+ fprintf(stderr, "illegal instruction\n");
+ break;
+ case SIGABRT:
+ fprintf(stderr, "abort() called\n");
+ break;
+ default:
+ fprintf(stderr, "signal %d\n", signum);
+ break;
+ }
+ exit(255);
+}
+
+/* launch the compiled program with the given arguments */
+int launch_exe(int argc, char **argv)
+{
+ Sym *s;
+ int (*t)();
+ struct sigaction sigact;
+
+ s = sym_find1(&extern_stack, TOK_MAIN);
+ if (!s || (s->r & VT_FORWARD))
+ error("main() not defined");
+
+ if (do_debug) {
+ /* install TCC signal handlers to print debug info on fatal
+ runtime errors */
+ sigact.sa_flags = SA_SIGINFO | SA_ONESHOT;
+ sigact.sa_sigaction = sig_error;
+ sigemptyset(&sigact.sa_mask);
+ sigaction(SIGFPE, &sigact, NULL);
+ sigaction(SIGILL, &sigact, NULL);
+ sigaction(SIGSEGV, &sigact, NULL);
+ sigaction(SIGBUS, &sigact, NULL);
+ sigaction(SIGABRT, &sigact, NULL);
+ }
+
+ if (do_bounds_check) {
+ int *p, *p_end;
+ __bound_init();
+ /* add all known static regions */
+ p = (int *)bounds_section->data;
+ p_end = (int *)bounds_section->data_ptr;
+ while (p < p_end) {
+ __bound_new_region((void *)p[0], p[1]);
+ p += 2;
+ }
+ }
+
+ t = (int (*)())s->c;
+ return (*t)(argc, argv);
+}
+
+
void help(void)
{
printf("tcc version 0.9.3 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
- "usage: tcc [-Idir] [-Dsym[=val]] [-Usym] [-llib] [-i infile] infile [infile_args...]\n");
+ "usage: tcc [-Idir] [-Dsym[=val]] [-Usym] [-llib] [-g] [-b]\n"
+ " [-i infile] infile [infile_args...]\n"
+ "\n"
+ "-Idir : add include path 'dir'\n"
+ "-Dsym[=val] : define 'sym' with value 'val'\n"
+ "-Usym : undefine 'sym'\n"
+ "-llib : link with dynamic library 'lib'\n"
+ "-g : generate debug info\n"
+ "-b : compile with built-in memory and bounds checker (implies -g)\n"
+ "-i infile : compile infile\n"
+ );
}
int main(int argc, char **argv)
{
- Sym *s;
- int (*t)();
char *p, *r, *outfile;
int optind;
@@ -5499,9 +6011,10 @@ int main(int argc, char **argv)
define_symbol("__TINYC__");
/* create standard sections */
- text_section = new_section(".text");
- data_section = new_section(".data");
- bss_section = new_section(".bss");
+ text_section = new_section(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
+ data_section = new_section(".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
+ /* XXX: should change type to SHT_NOBITS */
+ bss_section = new_section(".bss", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
optind = 1;
outfile = NULL;
@@ -5529,6 +6042,37 @@ int main(int argc, char **argv)
if (optind >= argc)
goto show_help;
tcc_compile_file(argv[optind++]);
+ } else if (r[1] == 'b') {
+ if (!do_bounds_check) {
+ do_bounds_check = 1;
+ /* create bounds section for global data */
+ bounds_section = new_section(".bounds",
+ SHT_PROGBITS, SHF_ALLOC);
+ /* debug is implied */
+ goto debug_opt;
+ }
+ } else if (r[1] == 'g') {
+ debug_opt:
+ if (!do_debug) {
+ do_debug = 1;
+
+ /* stab symbols */
+ stab_section = new_section(".stab", SHT_PROGBITS, 0);
+ stab_section->sh_entsize = sizeof(Stab_Sym);
+ stabstr_section = new_section(".stabstr", SHT_STRTAB, 0);
+ put_elf_str(stabstr_section, "");
+ stab_section->link = stabstr_section;
+ /* put first entry */
+ put_stabs("", 0, 0, 0, 0);
+
+ /* elf symbols */
+ symtab_section = new_section(".symtab", SHT_SYMTAB, 0);
+ symtab_section->sh_entsize = sizeof(Elf32_Sym);
+ strtab_section = new_section(".strtab", SHT_STRTAB, 0);
+ put_elf_str(strtab_section, "");
+ symtab_section->link = strtab_section;
+ put_elf_sym(symtab_section, 0, 0, 0, 0, 0, NULL);
+ }
} else if (r[1] == 'o') {
/* currently, only for testing, so not documented */
if (optind >= argc)
@@ -5548,10 +6092,6 @@ int main(int argc, char **argv)
build_exe(outfile);
return 0;
} else {
- s = sym_find1(&extern_stack, TOK_MAIN);
- if (!s || (s->r & VT_FORWARD))
- error("main() not defined");
- t = (int (*)())s->c;
- return (*t)(argc - optind, argv + optind);
+ return launch_exe(argc - optind, argv + optind);
}
}