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 RELOC_REL32 2 /* 32 bits relative relocation */
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ #define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
#define SYM_FIELD 0x20000000 /* struct/union field 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_NEW 1 /* ansi function prototype */
#define FUNC_OLD 2 /* old function prototype */ #define FUNC_OLD 2 /* old function prototype */
@ -130,6 +131,8 @@ TokenSym **table_ident;
TokenSym *hash_ident[521]; TokenSym *hash_ident[521];
char token_buf[STRING_MAX_SIZE + 1]; char token_buf[STRING_MAX_SIZE + 1];
char *filename, *funcname; char *filename, *funcname;
/* contains global symbols which remain between each translation unit */
SymStack extern_stack;
SymStack define_stack, global_stack, local_stack, label_stack; SymStack define_stack, global_stack, local_stack, label_stack;
int vstack[VSTACK_SIZE], *vstack_ptr; int vstack[VSTACK_SIZE], *vstack_ptr;
@ -169,14 +172,13 @@ int gnu_ext = 1;
#define VT_SHORT 0x004000 /* short type */ #define VT_SHORT 0x004000 /* short type */
#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */ #define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
#define VT_TYPE 0xfffc7fc0 /* type mask */
/* storage */ /* storage */
#define VT_EXTERN 0x00008000 /* extern definition */ #define VT_EXTERN 0x00008000 /* extern definition */
#define VT_STATIC 0x00010000 /* static variable */ #define VT_STATIC 0x00010000 /* static variable */
#define VT_TYPEDEF 0x00020000 /* typedef definition */ #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 */ /* token values */
@ -613,6 +615,21 @@ void sym_pop(SymStack *st, Sym *b)
st->top = 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 */ /* no need to put that inline */
int handle_eof(void) int handle_eof(void)
{ {
@ -884,7 +901,7 @@ void preprocess()
s = sym_find1(&define_stack, tok); s = sym_find1(&define_stack, tok);
/* undefine symbol by putting an invalid name */ /* undefine symbol by putting an invalid name */
if (s) if (s)
s->v = 0; sym_undef(&define_stack, s);
} else if (tok == TOK_INCLUDE) { } else if (tok == TOK_INCLUDE) {
skip_spaces(); skip_spaces();
if (ch == '<') { if (ch == '<') {
@ -934,7 +951,7 @@ void preprocess()
if (f) if (f)
goto found; goto found;
} }
error("include file not found"); error("include file '%s' not found", buf1);
f = NULL; f = NULL;
found: found:
/* push current file in stack */ /* 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)); printf("token = %s\n", get_tok_str(tok, tokc));
#endif #endif
} }
@ -2120,7 +2137,7 @@ void gen_op(int op)
vpush(); vpush();
gen_opc(op); gen_opc(op);
/* put again type if gen_opc() swaped operands */ /* put again type if gen_opc() swaped operands */
vt = (vt & VT_TYPEN) | (t1 & VT_TYPE); vt = (vt & ~VT_TYPE) | (t1 & VT_TYPE);
} else { } else {
gen_opc(op); gen_opc(op);
} }
@ -2173,7 +2190,7 @@ void gen_cast(int t)
} }
} }
the_end: the_end:
vt = (vt & VT_TYPEN) | t; vt = (vt & ~VT_TYPE) | t;
} }
/* return type size. Put alignment at 'a' */ /* return type size. Put alignment at 'a' */
@ -2209,7 +2226,7 @@ int pointed_type(int t)
{ {
Sym *s; Sym *s;
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT)); 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) int mk_pointer(int t)
@ -2217,7 +2234,7 @@ int mk_pointer(int t)
int p; int p;
p = anon_sym++; p = anon_sym++;
sym_push(p, t, -1); 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 */ /* store value in lvalue pushed on stack */
@ -2336,7 +2353,8 @@ int struct_decl(int u)
next(); next();
c = expr_const(); c = expr_const();
} }
sym_push(v, VT_CONST, c); /* enum symbols have static storage */
sym_push(v, VT_CONST | VT_STATIC, c);
if (tok == ',') if (tok == ',')
next(); next();
c++; c++;
@ -2427,9 +2445,9 @@ int ist(void)
return t; 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; Sym **plast, *s, *first;
if (tok == '(') { if (tok == '(') {
@ -2474,12 +2492,13 @@ int post_type(t)
} }
} }
skip(')'); 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 */ /* we push a anonymous symbol which will contain the function prototype */
p = anon_sym++; p = anon_sym++;
s = sym_push(p, t, l); s = sym_push(p, t, l);
s->next = first; s->next = first;
t = VT_FUNC | (p << VT_STRUCT_SHIFT); t = t1 | VT_FUNC | (p << VT_STRUCT_SHIFT);
} else if (tok == '[') { } else if (tok == '[') {
/* array definition */ /* array definition */
next(); next();
@ -2590,6 +2609,7 @@ void unary(void)
vset(VT_CONST | mk_pointer(VT_BYTE), glo); vset(VT_CONST | mk_pointer(VT_BYTE), glo);
strcpy((void *)glo, funcname); strcpy((void *)glo, funcname);
glo += strlen(funcname) + 1; glo += strlen(funcname) + 1;
next();
} else if (tok == TOK_LSTR) { } else if (tok == TOK_LSTR) {
t = VT_INT; t = VT_INT;
goto str_init; goto str_init;
@ -2732,12 +2752,12 @@ void unary(void)
if (!s) if (!s)
error("field not found"); error("field not found");
/* add field offset to pointer */ /* add field offset to pointer */
vt = vt & VT_TYPEN; /* change type to int */ vt = (vt & ~VT_TYPE) | VT_INT; /* change type to int */
vpush(); vpush();
vset(VT_CONST, s->c); vset(VT_CONST, s->c);
gen_op('+'); gen_op('+');
/* change type to field type, and set to lvalue */ /* 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 */ /* an array is never an lvalue */
if (!(vt & VT_ARRAY)) if (!(vt & VT_ARRAY))
vt |= VT_LVAL; vt |= VT_LVAL;
@ -2808,6 +2828,8 @@ void unary(void)
macro_ptr = (int *)args->c; macro_ptr = (int *)args->c;
next(); next();
expr_eq(); expr_eq();
if (tok != -1)
expect("',' or ')'");
gfunc_param(&gf); gfunc_param(&gf);
s1 = args->prev; s1 = args->prev;
free((int *)args->c); free((int *)args->c);
@ -3353,7 +3375,7 @@ void decl_designator(int t, int c,
expect("field"); expect("field");
if (!notfirst) if (!notfirst)
*cur_field = f; *cur_field = f;
t = f->t | (t & VT_TYPEN); t = f->t | (t & ~VT_TYPE);
c += f->c; c += f->c;
} }
notfirst = 1; notfirst = 1;
@ -3374,7 +3396,7 @@ void decl_designator(int t, int c,
f = *cur_field; f = *cur_field;
if (!f) if (!f)
error("too many field init"); error("too many field init");
t = f->t | (t & VT_TYPEN); t = f->t | (t & ~VT_TYPE);
c += f->c; c += f->c;
} }
} }
@ -3747,7 +3769,8 @@ void decl(int l)
break; break;
} else { } else {
if (b & VT_TYPEDEF) { if (b & VT_TYPEDEF) {
/* save typedefed type */ /* save typedefed type */
/* XXX: test storage specifiers ? */
sym_push(v, t | VT_TYPEDEF, 0); sym_push(v, t | VT_TYPEDEF, 0);
} else if (t & VT_FUNC) { } else if (t & VT_FUNC) {
/* external function definition */ /* 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 /* open a dynamic library so that its symbol are available for
compiled programs */ compiled programs */
void open_dll(char *libname) void open_dll(char *libname)
@ -3808,13 +3914,13 @@ void open_dll(char *libname)
error((char *)dlerror()); error((char *)dlerror());
} }
void reloc_external_syms(void) void resolve_extern_syms(void)
{ {
Sym *s, *s1; Sym *s, *s1;
char *str; char *str;
int addr; int addr;
s = global_stack.top; s = extern_stack.top;
while (s != NULL) { while (s != NULL) {
s1 = s->prev; s1 = s->prev;
if (s->t & VT_FORWARD) { if (s->t & VT_FORWARD) {
@ -3868,14 +3974,21 @@ int main(int argc, char **argv)
#ifdef __i386__ #ifdef __i386__
define_symbol("__i386__"); define_symbol("__i386__");
#endif #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; optind = 1;
outfile = NULL; outfile = NULL;
while (1) { while (1) {
if (optind >= argc) { if (optind >= argc) {
show_help: show_help:
printf("tcc version 0.9.1 - Tiny C Compiler - Copyright (C) 2001 Fabrice Bellard\n" 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; return 1;
} }
r = argv[optind]; r = argv[optind];
@ -3890,6 +4003,10 @@ int main(int argc, char **argv)
define_symbol(r + 2); define_symbol(r + 2);
} else if (r[1] == 'l') { } else if (r[1] == 'l') {
open_dll(r + 2); 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') { } else if (r[1] == 'o') {
/* currently, only for testing, so not documented */ /* currently, only for testing, so not documented */
if (optind >= argc) if (optind >= argc)
@ -3901,36 +4018,16 @@ int main(int argc, char **argv)
} }
} }
filename = argv[optind]; tcc_compile_file(argv[optind]);
line_num = 1;
funcname = ""; resolve_extern_syms();
file = fopen(filename, "r");
if (!file) {
perror(filename);
exit(1);
}
include_stack_ptr = include_stack;
ifdef_stack_ptr = ifdef_stack;
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) { if (outfile) {
build_exe(outfile); build_exe(outfile);
return 0; return 0;
} else { } else {
s = sym_find(TOK_MAIN); s = sym_find1(&extern_stack, TOK_MAIN);
if (!s) if (!s || (s->t & VT_FORWARD))
error("main() not defined"); error("main() not defined");
t = (int (*)())s->c; t = (int (*)())s->c;
return (*t)(argc - optind, argv + optind); return (*t)(argc - optind, argv + optind);