primitive fastcall functions support - -fno-common option - -Ttext linker option - bit field fixes - section alignment fixes

tcc-xref
bellard 2004-10-18 00:18:20 +00:00
parent 72a88fbab0
commit 9668499b9f
1 changed files with 120 additions and 10 deletions

130
tcc.c
View File

@ -205,12 +205,12 @@ typedef struct DLLReference {
typedef struct AttributeDef {
int aligned;
Section *section;
unsigned char func_call; /* FUNC_CDECL or FUNC_STDCALL */
unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */
} AttributeDef;
#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 SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
/* stored in 'Sym.c' field */
#define FUNC_NEW 1 /* ansi function prototype */
@ -220,6 +220,9 @@ typedef struct AttributeDef {
/* stored in 'Sym.r' field */
#define FUNC_CDECL 0 /* standard c call */
#define FUNC_STDCALL 1 /* pascal c call */
#define FUNC_FASTCALL1 2 /* first param in %eax */
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
/* field 'Sym.t' for macros */
#define MACRO_OBJ 0 /* object like macro */
@ -299,10 +302,12 @@ static int parse_flags;
#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a
token. line feed is also
returned at eof */
#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */
static Section *text_section, *data_section, *bss_section; /* predefined sections */
static Section *cur_text_section; /* current section where function code is
generated */
static Section *last_text_section; /* to handle .previous asm directive */
/* bound check related sections */
static Section *bounds_section; /* contains global data bound description */
static Section *lbounds_section; /* contains local data bound description */
@ -413,6 +418,8 @@ struct TCCState {
int nostdinc; /* if true, no standard headers are added */
int nostdlib; /* if true, no standard libraries are added */
int nocommon; /* if true, do not use common symbols for .bss data */
/* if true, static linking is performed */
int static_link;
@ -422,6 +429,10 @@ struct TCCState {
/* if true, only link in referenced objects from archive */
int alacarte_link;
/* address of text section */
unsigned long text_addr;
int has_text_addr;
/* C language options */
int char_is_unsigned;
@ -789,9 +800,12 @@ typedef struct ASMOperand {
char asm_str[16]; /* computed asm string for operand */
SValue *vt; /* C value of the expression */
int ref_index; /* if >= 0, gives reference to a output constraint */
int input_index; /* if >= 0, gives reference to an input constraint */
int priority; /* priority, used to assign registers */
int reg; /* if >= 0, register number used for this operand */
int is_llong; /* true if double register value */
int is_memory; /* true if memory operand */
int is_rw; /* for '+' modifier */
} ASMOperand;
static void asm_expr(TCCState *s1, ExprValue *pe);
@ -804,6 +818,7 @@ static int tcc_assemble(TCCState *s1, int do_preprocess);
#endif
static void asm_instr(void);
static void asm_global_instr(void);
/* true if float/double/long double type */
static inline int is_float(int t)
@ -914,6 +929,22 @@ static char *pstrcat(char *buf, int buf_size, const char *s)
return buf;
}
static int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
/* memory management */
#ifdef MEM_DEBUG
int mem_cur_size;
@ -1086,6 +1117,8 @@ Section *find_section(TCCState *s1, const char *name)
return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
}
#define SECTION_ABS ((void *)1)
/* update sym->c so that it points to an external symbol in section
'section' with value 'value' */
static void put_extern_sym(Sym *sym, Section *section,
@ -1095,10 +1128,12 @@ static void put_extern_sym(Sym *sym, Section *section,
Elf32_Sym *esym;
const char *name;
if (section)
sh_num = section->sh_num;
else
if (section == NULL)
sh_num = SHN_UNDEF;
else if (section == SECTION_ABS)
sh_num = SHN_ABS;
else
sh_num = section->sh_num;
if (!sym->c) {
if ((sym->type.t & VT_BTYPE) == VT_FUNC)
sym_type = STT_FUNC;
@ -2850,7 +2885,8 @@ static void preprocess(int is_bof)
/* '!' is ignored to allow C scripts. numbers are ignored
to emulate cpp behaviour */
} else {
error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc));
if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS))
error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc));
}
break;
}
@ -3367,7 +3403,12 @@ static inline void next_nomacro1(void)
p++;
tok = TOK_TWOSHARPS;
} else {
tok = '#';
if (parse_flags & PARSE_FLAG_ASM_COMMENTS) {
p = parse_line_comment(p - 1);
goto redo_no_start;
} else {
tok = '#';
}
}
}
break;
@ -3815,7 +3856,6 @@ static int macro_subst_tok(TokenString *tok_str,
char buf[32];
/* if symbol is a macro, prepare substitution */
/* special macros */
if (tok == TOK___LINE__) {
snprintf(buf, sizeof(buf), "%d", file->line_num);
@ -5745,6 +5785,9 @@ static int is_compatible_func(CType *type1, CType *type2)
s2 = type2->ref;
if (!is_compatible_types(&s1->type, &s2->type))
return 0;
/* check func_call */
if (s1->r != s2->r)
return 0;
/* XXX: not complete */
if (s1->c == FUNC_OLD || s2->c == FUNC_OLD)
return 1;
@ -5985,7 +6028,8 @@ void vstore(void)
warning("assignment of read-only location");
} else {
delayed_cast = 0;
gen_assign_cast(&vtop[-1].type);
if (!(ft & VT_BITFIELD))
gen_assign_cast(&vtop[-1].type);
}
if (sbt == VT_STRUCT) {
@ -6164,6 +6208,20 @@ static void parse_attribute(AttributeDef *ad)
case TOK_STDCALL3:
ad->func_call = FUNC_STDCALL;
break;
#ifdef TCC_TARGET_I386
case TOK_REGPARM1:
case TOK_REGPARM2:
skip('(');
n = expr_const();
if (n > 3)
n = 3;
else if (n < 0)
n = 0;
if (n > 0)
ad->func_call = FUNC_FASTCALL1 + n - 1;
skip(')');
break;
#endif
default:
if (tcc_state->warn_unsupported)
warning("'%s' attribute ignored", get_tok_str(t, NULL));
@ -6280,6 +6338,8 @@ static void struct_decl(CType *type, int u)
get_tok_str(v, NULL));
}
size = type_size(&type1, &align);
if (align < ad.aligned)
align = ad.aligned;
lbit_pos = 0;
if (bit_size >= 0) {
bt = type1.t & VT_BTYPE;
@ -8418,6 +8478,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (sym->type.t & VT_EXTERN) {
/* if the variable is extern, it was not allocated */
sym->type.t &= ~VT_EXTERN;
/* set array size if it was ommited in extern
declaration */
if ((sym->type.t & VT_ARRAY) &&
sym->type.ref->c < 0 &&
type->ref->c >= 0)
sym->type.ref->c = type->ref->c;
} else {
/* we accept several definitions of the same
global variable. this is tricky, because we
@ -8437,6 +8503,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (!sec) {
if (has_init)
sec = data_section;
else if (tcc_state->nocommon)
sec = bss_section;
}
if (sec) {
data_offset = sec->data_offset;
@ -8453,6 +8521,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (sec->sh_type != SHT_NOBITS &&
data_offset > sec->data_allocated)
section_realloc(sec, data_offset);
/* align section if needed */
if (align > sec->sh_addralign)
sec->sh_addralign = align;
} else {
addr = 0; /* avoid warning */
}
@ -8646,6 +8717,12 @@ static void decl(int l)
next();
continue;
}
if (l == VT_CONST &&
(tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
/* global asm block */
asm_global_instr();
continue;
}
/* special test for old K&R protos without explicit int
type. Only accepted when defining global data */
if (l == VT_LOCAL || tok < TOK_DEFINE)
@ -8683,7 +8760,6 @@ static void decl(int l)
ParseState saved_parse_state;
int block_level;
#endif
if (l == VT_LOCAL)
error("cannot use local functions");
if (!(type.t & VT_FUNC))
@ -8738,6 +8814,19 @@ static void decl(int l)
funcname = get_tok_str(v, NULL);
sym = sym_find(v);
if (sym) {
if ((sym->type.t & VT_BTYPE) != VT_FUNC)
goto func_error1;
/* specific case: if not func_call defined, we put
the one of the prototype */
/* XXX: should have default value */
if (sym->type.ref->r != FUNC_CDECL &&
type.ref->r == FUNC_CDECL)
type.ref->r = sym->type.ref->r;
if (!is_compatible_types(&sym->type, &type)) {
func_error1:
error("incompatible types for redefinition of '%s'",
get_tok_str(v, NULL));
}
/* if symbol is already defined, then put complete type */
sym->type = type;
} else {
@ -8790,6 +8879,9 @@ static void decl(int l)
sym->type.t |= VT_TYPEDEF;
} else if ((type.t & VT_BTYPE) == VT_FUNC) {
/* external function definition */
/* specific case for func_call attribute */
if (ad.func_call)
type.ref->r = ad.func_call;
external_sym(v, &type, 0);
} else {
/* not lvalue if array */
@ -9013,6 +9105,10 @@ static void asm_instr(void)
{
error("inline asm() not supported");
}
static void asm_global_instr(void)
{
error("inline asm() not supported");
}
#endif
#include "tccelf.c"
@ -9794,6 +9890,7 @@ int tcc_set_warning(TCCState *s, const char *warning_name, int value)
static const FlagDef flag_defs[] = {
{ offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
{ offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
{ offsetof(TCCState, nocommon), FD_INVERT, "common" },
};
/* set/reset a flag */
@ -9897,6 +9994,7 @@ enum {
TCC_OPTION_shared,
TCC_OPTION_o,
TCC_OPTION_r,
TCC_OPTION_Wl,
TCC_OPTION_W,
TCC_OPTION_O,
TCC_OPTION_m,
@ -9932,6 +10030,7 @@ static const TCCOption tcc_options[] = {
{ "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "rdynamic", TCC_OPTION_rdynamic, 0 },
{ "r", TCC_OPTION_r, 0 },
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
@ -10144,6 +10243,17 @@ int parse_args(TCCState *s, int argc, char **argv)
case TCC_OPTION_rdynamic:
s->rdynamic = 1;
break;
case TCC_OPTION_Wl:
{
const char *p;
if (strstart(optarg, "-Ttext,", &p)) {
s->text_addr = strtoul(p, NULL, 16);
s->has_text_addr = 1;
} else {
error("unsupported ld option '%s'", optarg);
}
}
break;
default:
if (s->warn_unsupported) {
unsupported_option: