added multiple files compile - various symbol related fixes

This commit is contained in:
bellard 2001-12-08 15:04:01 +00:00
parent 5d7f7bb5ef
commit 3c9ab729ae

197
tcc.c
View File

@ -87,8 +87,9 @@ typedef struct Reloc {
#define RELOC_REL32 2 /* 32 bits relative relocation */
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
#define SYM_FIRST_ANOM (1 << (31 - VT_STRUCT_SHIFT)) /* first anonymous sym */
#define FUNC_NEW 1 /* ansi function prototype */
#define FUNC_OLD 2 /* old function prototype */
@ -130,6 +131,8 @@ TokenSym **table_ident;
TokenSym *hash_ident[521];
char token_buf[STRING_MAX_SIZE + 1];
char *filename, *funcname;
/* contains global symbols which remain between each translation unit */
SymStack extern_stack;
SymStack define_stack, global_stack, local_stack, label_stack;
int vstack[VSTACK_SIZE], *vstack_ptr;
@ -169,14 +172,13 @@ int gnu_ext = 1;
#define VT_SHORT 0x004000 /* short type */
#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
#define VT_TYPE 0xfffc7fc0 /* type mask */
/* storage */
#define VT_EXTERN 0x00008000 /* extern definition */
#define VT_STATIC 0x00010000 /* static variable */
#define VT_TYPEDEF 0x00020000 /* typedef definition */
#define VT_TYPE 0xfffc7fc0 /* type mask */
#define VT_TYPEN 0x0000003f /* ~VT_TYPE */
#define VT_FUNCN -4097 /* ~VT_FUNC */
/* token values */
@ -613,6 +615,21 @@ void sym_pop(SymStack *st, Sym *b)
st->top = b;
}
/* undefined a hashed symbol (used for #undef). Its name is set to
zero */
void sym_undef(SymStack *st, Sym *s)
{
Sym **ss;
ss = &st->hash[s->v % SYM_HASH_SIZE];
while (*ss != NULL) {
if (*ss == s)
break;
ss = &(*ss)->hash_next;
}
*ss = s->hash_next;
s->v = 0;
}
/* no need to put that inline */
int handle_eof(void)
{
@ -884,7 +901,7 @@ void preprocess()
s = sym_find1(&define_stack, tok);
/* undefine symbol by putting an invalid name */
if (s)
s->v = 0;
sym_undef(&define_stack, s);
} else if (tok == TOK_INCLUDE) {
skip_spaces();
if (ch == '<') {
@ -934,7 +951,7 @@ void preprocess()
if (f)
goto found;
}
error("include file not found");
error("include file '%s' not found", buf1);
f = NULL;
found:
/* push current file in stack */
@ -1488,7 +1505,7 @@ void next()
}
}
}
#ifdef DEBUG
#if defined(DEBUG)
printf("token = %s\n", get_tok_str(tok, tokc));
#endif
}
@ -2120,7 +2137,7 @@ void gen_op(int op)
vpush();
gen_opc(op);
/* put again type if gen_opc() swaped operands */
vt = (vt & VT_TYPEN) | (t1 & VT_TYPE);
vt = (vt & ~VT_TYPE) | (t1 & VT_TYPE);
} else {
gen_opc(op);
}
@ -2173,7 +2190,7 @@ void gen_cast(int t)
}
}
the_end:
vt = (vt & VT_TYPEN) | t;
vt = (vt & ~VT_TYPE) | t;
}
/* return type size. Put alignment at 'a' */
@ -2209,7 +2226,7 @@ int pointed_type(int t)
{
Sym *s;
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
return s->t | (t & VT_TYPEN);
return s->t | (t & ~VT_TYPE);
}
int mk_pointer(int t)
@ -2217,7 +2234,7 @@ int mk_pointer(int t)
int p;
p = anon_sym++;
sym_push(p, t, -1);
return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & VT_TYPEN);
return VT_PTR | (p << VT_STRUCT_SHIFT) | (t & ~VT_TYPE);
}
/* store value in lvalue pushed on stack */
@ -2336,7 +2353,8 @@ int struct_decl(int u)
next();
c = expr_const();
}
sym_push(v, VT_CONST, c);
/* enum symbols have static storage */
sym_push(v, VT_CONST | VT_STATIC, c);
if (tok == ',')
next();
c++;
@ -2427,9 +2445,9 @@ int ist(void)
return t;
}
int post_type(t)
int post_type(int t)
{
int p, n, pt, l;
int p, n, pt, l, t1;
Sym **plast, *s, *first;
if (tok == '(') {
@ -2474,12 +2492,13 @@ int post_type(t)
}
}
skip(')');
t = post_type(t);
t1 = t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN);
t = post_type(t & ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN));
/* we push a anonymous symbol which will contain the function prototype */
p = anon_sym++;
s = sym_push(p, t, l);
s->next = first;
t = VT_FUNC | (p << VT_STRUCT_SHIFT);
t = t1 | VT_FUNC | (p << VT_STRUCT_SHIFT);
} else if (tok == '[') {
/* array definition */
next();
@ -2590,6 +2609,7 @@ void unary(void)
vset(VT_CONST | mk_pointer(VT_BYTE), glo);
strcpy((void *)glo, funcname);
glo += strlen(funcname) + 1;
next();
} else if (tok == TOK_LSTR) {
t = VT_INT;
goto str_init;
@ -2732,12 +2752,12 @@ void unary(void)
if (!s)
error("field not found");
/* add field offset to pointer */
vt = vt & VT_TYPEN; /* change type to int */
vt = (vt & ~VT_TYPE) | VT_INT; /* change type to int */
vpush();
vset(VT_CONST, s->c);
gen_op('+');
/* change type to field type, and set to lvalue */
vt = (vt & VT_TYPEN) | s->t;
vt = (vt & ~VT_TYPE) | s->t;
/* an array is never an lvalue */
if (!(vt & VT_ARRAY))
vt |= VT_LVAL;
@ -2808,6 +2828,8 @@ void unary(void)
macro_ptr = (int *)args->c;
next();
expr_eq();
if (tok != -1)
expect("',' or ')'");
gfunc_param(&gf);
s1 = args->prev;
free((int *)args->c);
@ -3353,7 +3375,7 @@ void decl_designator(int t, int c,
expect("field");
if (!notfirst)
*cur_field = f;
t = f->t | (t & VT_TYPEN);
t = f->t | (t & ~VT_TYPE);
c += f->c;
}
notfirst = 1;
@ -3374,7 +3396,7 @@ void decl_designator(int t, int c,
f = *cur_field;
if (!f)
error("too many field init");
t = f->t | (t & VT_TYPEN);
t = f->t | (t & ~VT_TYPE);
c += f->c;
}
}
@ -3747,7 +3769,8 @@ void decl(int l)
break;
} else {
if (b & VT_TYPEDEF) {
/* save typedefed type */
/* save typedefed type */
/* XXX: test storage specifiers ? */
sym_push(v, t | VT_TYPEDEF, 0);
} else if (t & VT_FUNC) {
/* external function definition */
@ -3795,6 +3818,89 @@ void decl(int l)
}
}
/* put all global symbols in the extern stack and do all the
resolving which can be done without using external symbols from DLLs */
/* XXX: could try to verify types, but would not to save them in
extern_stack too */
void resolve_global_syms(void)
{
Sym *s, *s1, *ext_sym;
Reloc **p;
s = global_stack.top;
while (s != NULL) {
s1 = s->prev;
/* do not save static or typedefed symbols or types */
if (!(s->t & (VT_STATIC | VT_TYPEDEF)) &&
!(s->v & (SYM_FIELD | SYM_STRUCT)) &&
(s->v < SYM_FIRST_ANOM)) {
ext_sym = sym_find1(&extern_stack, s->v);
if (!ext_sym) {
/* if the symbol do not exist, we simply save it */
sym_push1(&extern_stack, s->v, s->t, s->c);
} else if (ext_sym->t & VT_FORWARD) {
/* external symbol already exists, but only as forward
definition */
if (!(s->t & VT_FORWARD)) {
/* s is not forward, so we can relocate all symbols */
greloc_patch(ext_sym, s->c);
} else {
/* the two symbols are forward: merge them */
p = (Reloc **)&ext_sym->c;
while (*p != NULL)
p = &(*p)->next;
*p = (Reloc *)s->c;
}
} else {
/* external symbol already exists and is defined :
patch all references to it */
if (!(s->t & VT_FORWARD))
error("'%s' defined twice", get_tok_str(s->v, 0));
greloc_patch(s, ext_sym->c);
}
}
s = s1;
}
}
/* compile a C file. Return non zero if errors. */
int tcc_compile_file(const char *filename1)
{
Sym *define_start;
filename = (char *)filename1;
line_num = 1;
funcname = "";
file = fopen(filename, "r");
if (!file)
error("file '%s' not found", filename);
include_stack_ptr = include_stack;
ifdef_stack_ptr = ifdef_stack;
vstack_ptr = vstack;
anon_sym = SYM_FIRST_ANOM;
define_start = define_stack.top;
inp();
ch = '\n'; /* needed to parse correctly first preprocessor command */
next();
decl(VT_CONST);
if (tok != -1)
expect("declaration");
fclose(file);
/* reset define stack, but leave -Dsymbols (may be incorrect if
they are undefined) */
sym_pop(&define_stack, define_start);
resolve_global_syms();
sym_pop(&global_stack, NULL);
return 0;
}
/* open a dynamic library so that its symbol are available for
compiled programs */
void open_dll(char *libname)
@ -3808,13 +3914,13 @@ void open_dll(char *libname)
error((char *)dlerror());
}
void reloc_external_syms(void)
void resolve_extern_syms(void)
{
Sym *s, *s1;
char *str;
int addr;
s = global_stack.top;
s = extern_stack.top;
while (s != NULL) {
s1 = s->prev;
if (s->t & VT_FORWARD) {
@ -3868,14 +3974,21 @@ int main(int argc, char **argv)
#ifdef __i386__
define_symbol("__i386__");
#endif
/* tiny C specific defines */
define_symbol("__TINYC__");
glo = (int)malloc(DATA_SIZE);
memset((void *)glo, 0, DATA_SIZE);
prog = (int)malloc(TEXT_SIZE);
ind = prog;
optind = 1;
outfile = NULL;
while (1) {
if (optind >= argc) {
show_help:
printf("tcc version 0.9.1 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n"
"usage: tcc [-Idir] [-Dsym] [-llib] infile [infile_arg...]\n");
"usage: tcc [-Idir] [-Dsym] [-llib] [-i infile]... infile [infile_args...]\n");
return 1;
}
r = argv[optind];
@ -3890,6 +4003,10 @@ int main(int argc, char **argv)
define_symbol(r + 2);
} else if (r[1] == 'l') {
open_dll(r + 2);
} else if (r[1] == 'i') {
if (optind >= argc)
goto show_help;
tcc_compile_file(argv[optind++]);
} else if (r[1] == 'o') {
/* currently, only for testing, so not documented */
if (optind >= argc)
@ -3901,36 +4018,16 @@ int main(int argc, char **argv)
}
}
filename = argv[optind];
line_num = 1;
funcname = "";
file = fopen(filename, "r");
if (!file) {
perror(filename);
exit(1);
}
include_stack_ptr = include_stack;
ifdef_stack_ptr = ifdef_stack;
tcc_compile_file(argv[optind]);
resolve_extern_syms();
glo = (int)malloc(DATA_SIZE);
memset((void *)glo, 0, DATA_SIZE);
prog = (int)malloc(TEXT_SIZE);
vstack_ptr = vstack;
anon_sym = 1 << (31 - VT_STRUCT_SHIFT);
ind = prog;
inp();
ch = '\n'; /* needed to parse correctly first preprocessor command */
next();
decl(VT_CONST);
if (tok != -1)
expect("declaration");
reloc_external_syms();
if (outfile) {
build_exe(outfile);
return 0;
} else {
s = sym_find(TOK_MAIN);
if (!s)
s = sym_find1(&extern_stack, TOK_MAIN);
if (!s || (s->t & VT_FORWARD))
error("main() not defined");
t = (int (*)())s->c;
return (*t)(argc - optind, argv + optind);