mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-17 05:20:08 +08:00
tccgen: flex arrays etc.
Fixes potential writes past the allocated space with mostly illegal flex array initializers. (60_errors_and_warnings.c :test_var_array) In exchange suspicious precautions such as section_reserve or checks with sec->data_allocated were removed. (There is an hard check 'init_assert()' for now but it's meant to be just temporary) Also, instead of filling holes, always memset(0) structures & arrays on stack. Sometimes more efficient, sometimes isn't. At least we can omit putting null initializers. About array range inititializers: Reparsing tokens has a small problem with sideeffects, for example int c = 0, dd[] = { [0 ... 1] = ++c, [2 ... 3] = ++c }; Also, instead of 'squeeze_multi_relocs()', delete pre-existing relocations in advance. This works even if secondary initializers don't even have relocations, as with [0 ... 7] = &stuff, [4] = NULL Also, in tcc.h: new macro "tcc_internal_error()"
This commit is contained in:
parent
40395511d7
commit
72b520e709
@ -1517,7 +1517,7 @@ ST_FUNC void subst_asm_operand(CString *add_str,
|
|||||||
} else if (r & VT_LVAL) {
|
} else if (r & VT_LVAL) {
|
||||||
reg = r & VT_VALMASK;
|
reg = r & VT_VALMASK;
|
||||||
if (reg >= VT_CONST)
|
if (reg >= VT_CONST)
|
||||||
tcc_error("internal compiler error");
|
tcc_internal_error("");
|
||||||
snprintf(buf, sizeof(buf), "(%%%s)",
|
snprintf(buf, sizeof(buf), "(%%%s)",
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
get_tok_str(TOK_ASM_rax + reg, NULL)
|
get_tok_str(TOK_ASM_rax + reg, NULL)
|
||||||
@ -1530,7 +1530,7 @@ ST_FUNC void subst_asm_operand(CString *add_str,
|
|||||||
/* register case */
|
/* register case */
|
||||||
reg = r & VT_VALMASK;
|
reg = r & VT_VALMASK;
|
||||||
if (reg >= VT_CONST)
|
if (reg >= VT_CONST)
|
||||||
tcc_error("internal compiler error");
|
tcc_internal_error("");
|
||||||
|
|
||||||
/* choose register operand size */
|
/* choose register operand size */
|
||||||
if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
|
if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
|
||||||
|
5
tcc.h
5
tcc.h
@ -1237,6 +1237,8 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
|
|||||||
PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2);
|
PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) PRINTF_LIKE(1,2);
|
||||||
PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2);
|
PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...) PRINTF_LIKE(1,2);
|
||||||
PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2);
|
PUB_FUNC void _tcc_warning(const char *fmt, ...) PRINTF_LIKE(1,2);
|
||||||
|
#define tcc_internal_error(msg) tcc_error("internal compiler error\n"\
|
||||||
|
"%s:%d: in %s(): " msg, __FILE__,__LINE__,__FUNCTION__)
|
||||||
|
|
||||||
/* other utilities */
|
/* other utilities */
|
||||||
ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
|
ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
|
||||||
@ -1507,7 +1509,6 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
|
|||||||
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
|
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
|
||||||
ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
|
ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
|
||||||
ST_FUNC void *section_ptr_add(Section *sec, addr_t size);
|
ST_FUNC void *section_ptr_add(Section *sec, addr_t size);
|
||||||
ST_FUNC void section_reserve(Section *sec, unsigned long size);
|
|
||||||
ST_FUNC Section *find_section(TCCState *s1, const char *name);
|
ST_FUNC Section *find_section(TCCState *s1, const char *name);
|
||||||
ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
|
ST_FUNC Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags);
|
||||||
|
|
||||||
@ -1544,8 +1545,6 @@ ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
|
|||||||
ST_FUNC void build_got_entries(TCCState *s1);
|
ST_FUNC void build_got_entries(TCCState *s1);
|
||||||
#endif
|
#endif
|
||||||
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
|
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
|
||||||
ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
|
|
||||||
|
|
||||||
ST_FUNC addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc);
|
ST_FUNC addr_t get_sym_addr(TCCState *s, const char *name, int err, int forc);
|
||||||
ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
|
ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
|
||||||
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
||||||
|
42
tccelf.c
42
tccelf.c
@ -321,14 +321,16 @@ ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
|
|||||||
return sec->data + offset;
|
return sec->data + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ELF_OBJ_ONLY
|
||||||
/* reserve at least 'size' bytes from section start */
|
/* reserve at least 'size' bytes from section start */
|
||||||
ST_FUNC void section_reserve(Section *sec, unsigned long size)
|
static void section_reserve(Section *sec, unsigned long size)
|
||||||
{
|
{
|
||||||
if (size > sec->data_allocated)
|
if (size > sec->data_allocated)
|
||||||
section_realloc(sec, size);
|
section_realloc(sec, size);
|
||||||
if (size > sec->data_offset)
|
if (size > sec->data_offset)
|
||||||
sec->data_offset = size;
|
sec->data_offset = size;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static Section *find_section_create (TCCState *s1, const char *name, int create)
|
static Section *find_section_create (TCCState *s1, const char *name, int create)
|
||||||
{
|
{
|
||||||
@ -762,45 +764,7 @@ ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
|
|||||||
put_elf_reloca(symtab, s, offset, type, symbol, 0);
|
put_elf_reloca(symtab, s, offset, type, symbol, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove relocations for section S->reloc starting at oldrelocoffset
|
|
||||||
that are to the same place, retaining the last of them. As side effect
|
|
||||||
the relocations are sorted. Possibly reduces the number of relocs. */
|
|
||||||
ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
|
|
||||||
{
|
|
||||||
Section *sr = s->reloc;
|
|
||||||
ElfW_Rel *r, *dest;
|
|
||||||
ssize_t a;
|
|
||||||
ElfW(Addr) addr;
|
|
||||||
|
|
||||||
if (oldrelocoffset + sizeof(*r) >= sr->data_offset)
|
|
||||||
return;
|
|
||||||
/* The relocs we're dealing with are the result of initializer parsing.
|
|
||||||
So they will be mostly in order and there aren't many of them.
|
|
||||||
Secondly we need a stable sort (which qsort isn't). We use
|
|
||||||
a simple insertion sort. */
|
|
||||||
for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) {
|
|
||||||
ssize_t i = a - sizeof(*r);
|
|
||||||
ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a);
|
|
||||||
addr = tmp.r_offset;
|
|
||||||
for (; i >= (ssize_t)oldrelocoffset &&
|
|
||||||
((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) {
|
|
||||||
*(ElfW_Rel*)(sr->data + i + sizeof(*r)) = *(ElfW_Rel*)(sr->data + i);
|
|
||||||
}
|
|
||||||
*(ElfW_Rel*)(sr->data + i + sizeof(*r)) = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (ElfW_Rel*)(sr->data + oldrelocoffset);
|
|
||||||
dest = r;
|
|
||||||
for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) {
|
|
||||||
if (dest->r_offset != r->r_offset)
|
|
||||||
dest++;
|
|
||||||
*dest = *r;
|
|
||||||
}
|
|
||||||
sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* put stab debug information */
|
/* put stab debug information */
|
||||||
|
|
||||||
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc,
|
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc,
|
||||||
unsigned long value)
|
unsigned long value)
|
||||||
{
|
{
|
||||||
|
380
tccgen.c
380
tccgen.c
@ -123,6 +123,12 @@ static struct scope {
|
|||||||
Sym *lstk, *llstk;
|
Sym *lstk, *llstk;
|
||||||
} *cur_scope, *loop_scope, *root_scope;
|
} *cur_scope, *loop_scope, *root_scope;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Section *sec;
|
||||||
|
int local_offset;
|
||||||
|
Sym *flex_array_ref;
|
||||||
|
} init_params;
|
||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
/* stab debug support */
|
/* stab debug support */
|
||||||
|
|
||||||
@ -218,8 +224,8 @@ static int is_compatible_types(CType *type1, CType *type2);
|
|||||||
static int parse_btype(CType *type, AttributeDef *ad);
|
static int parse_btype(CType *type, AttributeDef *ad);
|
||||||
static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);
|
static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);
|
||||||
static void parse_expr_type(CType *type);
|
static void parse_expr_type(CType *type);
|
||||||
static void init_putv(CType *type, Section *sec, unsigned long c);
|
static void init_putv(init_params *p, CType *type, unsigned long c);
|
||||||
static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags);
|
static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags);
|
||||||
static void block(int is_expr);
|
static void block(int is_expr);
|
||||||
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
|
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
|
||||||
static void decl(int l);
|
static void decl(int l);
|
||||||
@ -2167,16 +2173,17 @@ ST_FUNC int gv(int rc)
|
|||||||
} else {
|
} else {
|
||||||
if (is_float(vtop->type.t) &&
|
if (is_float(vtop->type.t) &&
|
||||||
(vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
(vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
|
||||||
unsigned long offset;
|
|
||||||
/* CPUs usually cannot use float constants, so we store them
|
/* CPUs usually cannot use float constants, so we store them
|
||||||
generically in data segment */
|
generically in data segment */
|
||||||
|
init_params p = { data_section };
|
||||||
|
unsigned long offset;
|
||||||
size = type_size(&vtop->type, &align);
|
size = type_size(&vtop->type, &align);
|
||||||
if (NODATA_WANTED)
|
if (NODATA_WANTED)
|
||||||
size = 0, align = 1;
|
size = 0, align = 1;
|
||||||
offset = section_add(data_section, size, align);
|
offset = section_add(p.sec, size, align);
|
||||||
vpush_ref(&vtop->type, data_section, offset, size);
|
vpush_ref(&vtop->type, p.sec, offset, size);
|
||||||
vswap();
|
vswap();
|
||||||
init_putv(&vtop->type, data_section, offset);
|
init_putv(&p, &vtop->type, offset);
|
||||||
vtop->r |= VT_LVAL;
|
vtop->r |= VT_LVAL;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
@ -5444,7 +5451,7 @@ static void parse_builtin_params(int nc, const char *args)
|
|||||||
type.t = VT_SIZE_T;
|
type.t = VT_SIZE_T;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tcc_error("internal error");
|
break;
|
||||||
}
|
}
|
||||||
gen_assign_cast(&type);
|
gen_assign_cast(&type);
|
||||||
}
|
}
|
||||||
@ -6102,7 +6109,8 @@ special_math_val:
|
|||||||
problems */
|
problems */
|
||||||
vseti(VT_LOCAL, loc);
|
vseti(VT_LOCAL, loc);
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
loc -= tcc_state->do_bounds_check != 0;
|
if (tcc_state->do_bounds_check)
|
||||||
|
--loc;
|
||||||
#endif
|
#endif
|
||||||
ret.c = vtop->c;
|
ret.c = vtop->c;
|
||||||
if (ret_nregs < 0)
|
if (ret_nregs < 0)
|
||||||
@ -7296,23 +7304,6 @@ static void skip_or_save_block(TokenString **str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_init_string(TokenString **str, int has_init)
|
|
||||||
{
|
|
||||||
if (has_init == 2) {
|
|
||||||
*str = tok_str_alloc();
|
|
||||||
/* only get strings */
|
|
||||||
while (tok == TOK_STR || tok == TOK_LSTR) {
|
|
||||||
tok_str_add_tok(*str);
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
tok_str_add(*str, -1);
|
|
||||||
tok_str_add(*str, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
skip_or_save_block(str);
|
|
||||||
unget_tok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXPR_CONST 1
|
#define EXPR_CONST 1
|
||||||
#define EXPR_ANY 2
|
#define EXPR_ANY 2
|
||||||
|
|
||||||
@ -7343,10 +7334,22 @@ static void parse_init_elem(int expr_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put zeros for variable based init */
|
#if 1
|
||||||
static void init_putz(Section *sec, unsigned long c, int size)
|
static void init_assert(init_params *p, int offset)
|
||||||
{
|
{
|
||||||
if (sec) {
|
if (p->sec ? !NODATA_WANTED && offset > p->sec->data_offset
|
||||||
|
: !nocode_wanted && offset > p->local_offset)
|
||||||
|
tcc_internal_error("initializer overflow");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define init_assert(sec, offset)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* put zeros for variable based init */
|
||||||
|
static void init_putz(init_params *p, unsigned long c, int size)
|
||||||
|
{
|
||||||
|
init_assert(p, c + size);
|
||||||
|
if (p->sec) {
|
||||||
/* nothing to do because globals are already set to zero */
|
/* nothing to do because globals are already set to zero */
|
||||||
} else {
|
} else {
|
||||||
vpush_global_sym(&func_old_type, TOK_memset);
|
vpush_global_sym(&func_old_type, TOK_memset);
|
||||||
@ -7365,6 +7368,37 @@ static void init_putz(Section *sec, unsigned long c, int size)
|
|||||||
#define DIF_FIRST 1
|
#define DIF_FIRST 1
|
||||||
#define DIF_SIZE_ONLY 2
|
#define DIF_SIZE_ONLY 2
|
||||||
#define DIF_HAVE_ELEM 4
|
#define DIF_HAVE_ELEM 4
|
||||||
|
#define DIF_CLEAR 8
|
||||||
|
|
||||||
|
/* delete relocations for specified range c ... c + size. Unfortunatly
|
||||||
|
in very special cases, relocations may occur unordered */
|
||||||
|
static void decl_design_delrels(Section *sec, int c, int size)
|
||||||
|
{
|
||||||
|
ElfW_Rel *rel, *rel2, *rel_end;
|
||||||
|
if (!sec || !sec->reloc)
|
||||||
|
return;
|
||||||
|
rel = rel2 = (ElfW_Rel*)sec->reloc->data;
|
||||||
|
rel_end = (ElfW_Rel*)(sec->reloc->data + sec->reloc->data_offset);
|
||||||
|
while (rel < rel_end) {
|
||||||
|
if (rel->r_offset >= c && rel->r_offset < c + size) {
|
||||||
|
sec->reloc->data_offset -= sizeof *rel;
|
||||||
|
} else {
|
||||||
|
if (rel2 != rel)
|
||||||
|
memcpy(rel2, rel, sizeof *rel);
|
||||||
|
++rel2;
|
||||||
|
}
|
||||||
|
++rel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decl_design_flex(init_params *p, Sym *ref, int index)
|
||||||
|
{
|
||||||
|
if (ref == p->flex_array_ref) {
|
||||||
|
if (index >= ref->c)
|
||||||
|
ref->c = index + 1;
|
||||||
|
} else if (ref->c < 0)
|
||||||
|
tcc_error("flexible array has zero size in this context");
|
||||||
|
}
|
||||||
|
|
||||||
/* t is the array or struct type. c is the array or struct
|
/* t is the array or struct type. c is the array or struct
|
||||||
address. cur_field is the pointer to the current
|
address. cur_field is the pointer to the current
|
||||||
@ -7372,13 +7406,12 @@ static void init_putz(Section *sec, unsigned long c, int size)
|
|||||||
index. 'flags' is as in decl_initializer.
|
index. 'flags' is as in decl_initializer.
|
||||||
'al' contains the already initialized length of the
|
'al' contains the already initialized length of the
|
||||||
current container (starting at c). This returns the new length of that. */
|
current container (starting at c). This returns the new length of that. */
|
||||||
static int decl_designator(CType *type, Section *sec, unsigned long c,
|
static int decl_designator(init_params *p, CType *type, unsigned long c,
|
||||||
Sym **cur_field, int flags, int al, int size)
|
Sym **cur_field, int flags, int al)
|
||||||
{
|
{
|
||||||
Sym *s, *f;
|
Sym *s, *f;
|
||||||
int index, index_last, align, l, nb_elems, elem_size;
|
int index, index_last, align, l, nb_elems, elem_size;
|
||||||
unsigned long corig = c;
|
unsigned long corig = c;
|
||||||
TokenString *init_str = NULL;
|
|
||||||
|
|
||||||
elem_size = 0;
|
elem_size = 0;
|
||||||
nb_elems = 1;
|
nb_elems = 1;
|
||||||
@ -7406,9 +7439,9 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
|
|||||||
}
|
}
|
||||||
skip(']');
|
skip(']');
|
||||||
s = type->ref;
|
s = type->ref;
|
||||||
if (index < 0 || (s->c >= 0 && index_last >= s->c) ||
|
decl_design_flex(p, s, index_last);
|
||||||
index_last < index)
|
if (index < 0 || index_last >= s->c || index_last < index)
|
||||||
tcc_error("invalid index");
|
tcc_error("index exceeds array bounds or range is empty");
|
||||||
if (cur_field)
|
if (cur_field)
|
||||||
(*cur_field)->c = index_last;
|
(*cur_field)->c = index_last;
|
||||||
type = pointed_type(type);
|
type = pointed_type(type);
|
||||||
@ -7444,72 +7477,82 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
|
|||||||
no_designator:
|
no_designator:
|
||||||
if (type->t & VT_ARRAY) {
|
if (type->t & VT_ARRAY) {
|
||||||
index = (*cur_field)->c;
|
index = (*cur_field)->c;
|
||||||
if (type->ref->c >= 0 && index >= type->ref->c)
|
s = type->ref;
|
||||||
tcc_error("index too large");
|
decl_design_flex(p, s, index);
|
||||||
|
if (index >= s->c)
|
||||||
|
tcc_error("too many initializers");
|
||||||
type = pointed_type(type);
|
type = pointed_type(type);
|
||||||
c += index * type_size(type, &align);
|
elem_size = type_size(type, &align);
|
||||||
|
c += index * elem_size;
|
||||||
} else {
|
} else {
|
||||||
f = *cur_field;
|
f = *cur_field;
|
||||||
while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD))
|
while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD))
|
||||||
*cur_field = f = f->next;
|
*cur_field = f = f->next;
|
||||||
if (!f)
|
if (!f)
|
||||||
tcc_error("too many field init");
|
tcc_error("too many initializers");
|
||||||
type = &f->type;
|
type = &f->type;
|
||||||
c += f->c;
|
c += f->c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* must put zero in holes (note that doing it that way
|
if (!elem_size) /* for structs */
|
||||||
ensures that it even works with designators) */
|
elem_size = type_size(type, &align);
|
||||||
if (!(flags & DIF_SIZE_ONLY)) {
|
|
||||||
int zlen = c - (corig + al);
|
/* Using designators the same element can be initialized more
|
||||||
if (type->t & VT_BITFIELD) { /* must include current field too */
|
than once. In that case we need to delete possibly already
|
||||||
zlen += type_size(type, &align);
|
existing relocations. */
|
||||||
if (al + zlen > size)
|
if (!(flags & DIF_SIZE_ONLY) && c - corig < al) {
|
||||||
zlen = size - al;
|
decl_design_delrels(p->sec, c, elem_size * nb_elems);
|
||||||
}
|
flags &= ~DIF_CLEAR; /* mark stack dirty too */
|
||||||
if (zlen > 0)
|
|
||||||
init_putz(sec, corig + al, zlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decl_initializer(p, type, c, flags & ~DIF_FIRST);
|
||||||
|
|
||||||
if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) {
|
if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) {
|
||||||
get_init_string(&init_str, tok == TOK_STR || tok == TOK_LSTR ? 2 : 0);
|
Sym aref = {0};
|
||||||
begin_macro(init_str, 1);
|
CType t1;
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
decl_initializer(type, sec, c, flags & ~DIF_FIRST);
|
|
||||||
|
|
||||||
if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) {
|
|
||||||
int i;
|
int i;
|
||||||
|
if (p->sec || (type->t & VT_ARRAY)) {
|
||||||
for(i = 1; i < nb_elems; i++) {
|
/* make init_putv/vstore believe it were a struct */
|
||||||
macro_ptr = init_str->str;
|
aref.c = elem_size;
|
||||||
next();
|
t1.t = VT_STRUCT, t1.ref = &aref;
|
||||||
decl_initializer(type, sec, c + i * elem_size, flags & ~DIF_FIRST);
|
type = &t1;
|
||||||
}
|
}
|
||||||
end_macro();
|
if (p->sec)
|
||||||
next();
|
vpush_ref(type, p->sec, c, elem_size);
|
||||||
|
else
|
||||||
|
vset(type, VT_LOCAL|VT_LVAL, c);
|
||||||
|
for (i = 1; i < nb_elems; i++) {
|
||||||
|
vdup();
|
||||||
|
init_putv(p, type, c + elem_size * i);
|
||||||
|
}
|
||||||
|
vpop();
|
||||||
}
|
}
|
||||||
|
|
||||||
c += nb_elems * type_size(type, &align);
|
c += nb_elems * elem_size;
|
||||||
if (c - corig > al)
|
if (c - corig > al)
|
||||||
al = c - corig;
|
al = c - corig;
|
||||||
return al;
|
return al;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store a value or an expression directly in global data or in local array */
|
/* store a value or an expression directly in global data or in local array */
|
||||||
static void init_putv(CType *type, Section *sec, unsigned long c)
|
static void init_putv(init_params *p, CType *type, unsigned long c)
|
||||||
{
|
{
|
||||||
int bt;
|
int bt;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
CType dtype;
|
CType dtype;
|
||||||
|
int size, align;
|
||||||
|
Section *sec = p->sec;
|
||||||
|
|
||||||
dtype = *type;
|
dtype = *type;
|
||||||
dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
|
dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
|
||||||
|
|
||||||
|
size = type_size(type, &align);
|
||||||
|
if (type->t & VT_BITFIELD)
|
||||||
|
size = (BIT_POS(type->t) + BIT_SIZE(type->t) + 7) / 8;
|
||||||
|
init_assert(p, c + size);
|
||||||
|
|
||||||
if (sec) {
|
if (sec) {
|
||||||
int size, align;
|
|
||||||
/* XXX: not portable */
|
/* XXX: not portable */
|
||||||
/* XXX: generate error if incorrect relocation */
|
/* XXX: generate error if incorrect relocation */
|
||||||
gen_assign_cast(&dtype);
|
gen_assign_cast(&dtype);
|
||||||
@ -7529,8 +7572,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = type_size(type, &align);
|
|
||||||
section_reserve(sec, c + size);
|
|
||||||
ptr = sec->data + c;
|
ptr = sec->data + c;
|
||||||
|
|
||||||
/* XXX: make code faster ? */
|
/* XXX: make code faster ? */
|
||||||
@ -7567,12 +7608,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
continue;
|
continue;
|
||||||
if (rel->r_offset < esym->st_value)
|
if (rel->r_offset < esym->st_value)
|
||||||
break;
|
break;
|
||||||
/* Note: if the same fields are initialized multiple
|
|
||||||
times (possible with designators) then we possibly
|
|
||||||
add multiple relocations for the same offset here.
|
|
||||||
That would lead to wrong code, the last reloc needs
|
|
||||||
to win. We clean this up later after the whole
|
|
||||||
initializer is parsed. */
|
|
||||||
put_elf_reloca(symtab_section, sec,
|
put_elf_reloca(symtab_section, sec,
|
||||||
c + rel->r_offset - esym->st_value,
|
c + rel->r_offset - esym->st_value,
|
||||||
ELFW(R_TYPE)(rel->r_info),
|
ELFW(R_TYPE)(rel->r_info),
|
||||||
@ -7610,10 +7645,10 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
case VT_BOOL:
|
case VT_BOOL:
|
||||||
vtop->c.i = vtop->c.i != 0;
|
vtop->c.i = vtop->c.i != 0;
|
||||||
case VT_BYTE:
|
case VT_BYTE:
|
||||||
*(char *)ptr |= vtop->c.i;
|
*(char *)ptr = vtop->c.i;
|
||||||
break;
|
break;
|
||||||
case VT_SHORT:
|
case VT_SHORT:
|
||||||
*(short *)ptr |= vtop->c.i;
|
*(short *)ptr = vtop->c.i;
|
||||||
break;
|
break;
|
||||||
case VT_FLOAT:
|
case VT_FLOAT:
|
||||||
*(float*)ptr = vtop->c.f;
|
*(float*)ptr = vtop->c.f;
|
||||||
@ -7642,7 +7677,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
break;
|
break;
|
||||||
#if PTR_SIZE != 8
|
#if PTR_SIZE != 8
|
||||||
case VT_LLONG:
|
case VT_LLONG:
|
||||||
*(long long *)ptr |= vtop->c.i;
|
*(long long *)ptr = vtop->c.i;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
case VT_LLONG:
|
case VT_LLONG:
|
||||||
@ -7654,11 +7689,11 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM)
|
||||||
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
||||||
else
|
else
|
||||||
*(addr_t *)ptr |= val;
|
*(addr_t *)ptr = val;
|
||||||
#else
|
#else
|
||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM)
|
||||||
greloc(sec, vtop->sym, c, R_DATA_PTR);
|
greloc(sec, vtop->sym, c, R_DATA_PTR);
|
||||||
*(addr_t *)ptr |= val;
|
*(addr_t *)ptr = val;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -7669,11 +7704,11 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM)
|
||||||
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
greloca(sec, vtop->sym, c, R_DATA_PTR, val);
|
||||||
else
|
else
|
||||||
*(int *)ptr |= val;
|
*(int *)ptr = val;
|
||||||
#else
|
#else
|
||||||
if (vtop->r & VT_SYM)
|
if (vtop->r & VT_SYM)
|
||||||
greloc(sec, vtop->sym, c, R_DATA_PTR);
|
greloc(sec, vtop->sym, c, R_DATA_PTR);
|
||||||
*(int *)ptr |= val;
|
*(int *)ptr = val;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -7693,8 +7728,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
|
|||||||
allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi
|
allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi
|
||||||
dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if
|
dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if
|
||||||
size only evaluation is wanted (only for arrays). */
|
size only evaluation is wanted (only for arrays). */
|
||||||
static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags)
|
||||||
int flags)
|
|
||||||
{
|
{
|
||||||
int len, n, no_oblock, i;
|
int len, n, no_oblock, i;
|
||||||
int size1, align1;
|
int size1, align1;
|
||||||
@ -7702,13 +7736,17 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
Sym indexsym;
|
Sym indexsym;
|
||||||
CType *t1;
|
CType *t1;
|
||||||
|
|
||||||
|
/* generate line number info */
|
||||||
|
if (!p->sec && tcc_state->do_debug)
|
||||||
|
tcc_debug_line(tcc_state);
|
||||||
|
|
||||||
if (!(flags & DIF_HAVE_ELEM) && tok != '{' &&
|
if (!(flags & DIF_HAVE_ELEM) && tok != '{' &&
|
||||||
/* In case of strings we have special handling for arrays, so
|
/* In case of strings we have special handling for arrays, so
|
||||||
don't consume them as initializer value (which would commit them
|
don't consume them as initializer value (which would commit them
|
||||||
to some anonymous symbol). */
|
to some anonymous symbol). */
|
||||||
tok != TOK_LSTR && tok != TOK_STR &&
|
tok != TOK_LSTR && tok != TOK_STR &&
|
||||||
!(flags & DIF_SIZE_ONLY)) {
|
!(flags & DIF_SIZE_ONLY)) {
|
||||||
parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
|
parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST);
|
||||||
flags |= DIF_HAVE_ELEM;
|
flags |= DIF_HAVE_ELEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7718,23 +7756,21 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
The source type might have VT_CONSTANT set, which is
|
The source type might have VT_CONSTANT set, which is
|
||||||
of course assignable to non-const elements. */
|
of course assignable to non-const elements. */
|
||||||
is_compatible_unqualified_types(type, &vtop->type)) {
|
is_compatible_unqualified_types(type, &vtop->type)) {
|
||||||
init_putv(type, sec, c);
|
goto init_putv;
|
||||||
|
|
||||||
} else if (type->t & VT_ARRAY) {
|
} else if (type->t & VT_ARRAY) {
|
||||||
|
no_oblock = 1;
|
||||||
|
if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) ||
|
||||||
|
tok == '{') {
|
||||||
|
skip('{');
|
||||||
|
no_oblock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
s = type->ref;
|
s = type->ref;
|
||||||
n = s->c;
|
n = s->c;
|
||||||
t1 = pointed_type(type);
|
t1 = pointed_type(type);
|
||||||
size1 = type_size(t1, &align1);
|
size1 = type_size(t1, &align1);
|
||||||
|
|
||||||
no_oblock = 1;
|
|
||||||
if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) ||
|
|
||||||
tok == '{') {
|
|
||||||
if (tok != '{')
|
|
||||||
tcc_error("character array initializer must be a literal,"
|
|
||||||
" optionally enclosed in braces");
|
|
||||||
skip('{');
|
|
||||||
no_oblock = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* only parse strings here if correct type (otherwise: handle
|
/* only parse strings here if correct type (otherwise: handle
|
||||||
them as ((w)char *) expressions */
|
them as ((w)char *) expressions */
|
||||||
if ((tok == TOK_LSTR &&
|
if ((tok == TOK_LSTR &&
|
||||||
@ -7744,7 +7780,6 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
(t1->t & VT_BTYPE) == VT_INT
|
(t1->t & VT_BTYPE) == VT_INT
|
||||||
#endif
|
#endif
|
||||||
) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
|
) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
|
||||||
int nb;
|
|
||||||
len = 0;
|
len = 0;
|
||||||
cstr_reset(&initstr);
|
cstr_reset(&initstr);
|
||||||
if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t)))
|
if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t)))
|
||||||
@ -7766,54 +7801,61 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR);
|
unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR);
|
||||||
tokc.str.size = initstr.size;
|
tokc.str.size = initstr.size;
|
||||||
tokc.str.data = initstr.data;
|
tokc.str.data = initstr.data;
|
||||||
indexsym.c = 0;
|
goto do_init_array;
|
||||||
f = &indexsym;
|
|
||||||
goto do_init_list;
|
|
||||||
}
|
}
|
||||||
nb = len;
|
|
||||||
if (n >= 0 && len > n)
|
|
||||||
nb = n;
|
|
||||||
if (!(flags & DIF_SIZE_ONLY)) {
|
if (!(flags & DIF_SIZE_ONLY)) {
|
||||||
if (sec && !NODATA_WANTED &&
|
int nb = n;
|
||||||
(c + nb > sec->data_allocated))
|
if (len < nb)
|
||||||
nb = sec->data_allocated - c;
|
nb = len;
|
||||||
if (len > nb)
|
if (len > nb)
|
||||||
tcc_warning("initializer-string for array is too long");
|
tcc_warning("initializer-string for array is too long");
|
||||||
/* in order to go faster for common case (char
|
/* in order to go faster for common case (char
|
||||||
string in global variable, we handle it
|
string in global variable, we handle it
|
||||||
specifically */
|
specifically */
|
||||||
if (sec && size1 == 1) {
|
if (p->sec && size1 == 1) {
|
||||||
|
init_assert(p, c + nb);
|
||||||
if (!NODATA_WANTED)
|
if (!NODATA_WANTED)
|
||||||
memcpy(sec->data + c, initstr.data, nb);
|
memcpy(p->sec->data + c, initstr.data, nb);
|
||||||
} else {
|
} else {
|
||||||
for(i=0;i<nb;i++) {
|
for(i=0;i<n;i++) {
|
||||||
if (size1 == 1)
|
if (i >= nb) {
|
||||||
|
/* only add trailing zero if enough storage (no
|
||||||
|
warning in this case since it is standard) */
|
||||||
|
if (flags & DIF_CLEAR)
|
||||||
|
break;
|
||||||
|
if (n - i >= 4) {
|
||||||
|
init_putz(p, c + i * size1, (n - i) * size1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ch = 0;
|
||||||
|
} else if (size1 == 1)
|
||||||
ch = ((unsigned char *)initstr.data)[i];
|
ch = ((unsigned char *)initstr.data)[i];
|
||||||
else
|
else
|
||||||
ch = ((nwchar_t *)initstr.data)[i];
|
ch = ((nwchar_t *)initstr.data)[i];
|
||||||
vpushi(ch);
|
vpushi(ch);
|
||||||
init_putv(t1, sec, c + i * size1);
|
init_putv(p, t1, c + i * size1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* only add trailing zero if enough storage (no
|
|
||||||
warning in this case since it is standard) */
|
|
||||||
if (n < 0 || len < n) {
|
|
||||||
if (!(flags & DIF_SIZE_ONLY)) {
|
|
||||||
vpushi(0);
|
|
||||||
init_putv(t1, sec, c + (len * size1));
|
|
||||||
}
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
len *= size1;
|
|
||||||
} else {
|
} else {
|
||||||
|
decl_design_flex(p, s, len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
do_init_array:
|
||||||
indexsym.c = 0;
|
indexsym.c = 0;
|
||||||
f = &indexsym;
|
f = &indexsym;
|
||||||
|
|
||||||
do_init_list:
|
do_init_list:
|
||||||
|
/* zero memory once in advance */
|
||||||
|
if (!(flags & (DIF_CLEAR | DIF_SIZE_ONLY))) {
|
||||||
|
init_putz(p, c, n*size1);
|
||||||
|
flags |= DIF_CLEAR;
|
||||||
|
}
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
while (tok != '}' || (flags & DIF_HAVE_ELEM)) {
|
while (tok != '}' || (flags & DIF_HAVE_ELEM)) {
|
||||||
len = decl_designator(type, sec, c, &f, flags, len, n*size1);
|
len = decl_designator(p, type, c, &f, flags, len);
|
||||||
flags &= ~DIF_HAVE_ELEM;
|
flags &= ~DIF_HAVE_ELEM;
|
||||||
if (type->t & VT_ARRAY) {
|
if (type->t & VT_ARRAY) {
|
||||||
++indexsym.c;
|
++indexsym.c;
|
||||||
@ -7836,16 +7878,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
skip(',');
|
skip(',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* put zeros at the end */
|
|
||||||
if (!(flags & DIF_SIZE_ONLY) && len < n*size1)
|
|
||||||
init_putz(sec, c + len, n*size1 - len);
|
|
||||||
if (!no_oblock)
|
if (!no_oblock)
|
||||||
skip('}');
|
skip('}');
|
||||||
/* patch type size if needed, which happens only for array types */
|
|
||||||
if (n < 0)
|
|
||||||
s->c = size1 == 1 ? len : ((len + size1 - 1)/size1);
|
|
||||||
} else if ((type->t & VT_BTYPE) == VT_STRUCT) {
|
} else if ((type->t & VT_BTYPE) == VT_STRUCT) {
|
||||||
size1 = 1;
|
|
||||||
no_oblock = 1;
|
no_oblock = 1;
|
||||||
if ((flags & DIF_FIRST) || tok == '{') {
|
if ((flags & DIF_FIRST) || tok == '{') {
|
||||||
skip('{');
|
skip('{');
|
||||||
@ -7854,12 +7889,13 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
s = type->ref;
|
s = type->ref;
|
||||||
f = s->next;
|
f = s->next;
|
||||||
n = s->c;
|
n = s->c;
|
||||||
|
size1 = 1;
|
||||||
goto do_init_list;
|
goto do_init_list;
|
||||||
} else if (tok == '{') {
|
} else if (tok == '{') {
|
||||||
if (flags & DIF_HAVE_ELEM)
|
if (flags & DIF_HAVE_ELEM)
|
||||||
skip(';');
|
skip(';');
|
||||||
next();
|
next();
|
||||||
decl_initializer(type, sec, c, flags & ~DIF_HAVE_ELEM);
|
decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM);
|
||||||
skip('}');
|
skip('}');
|
||||||
} else if ((flags & DIF_SIZE_ONLY)) {
|
} else if ((flags & DIF_SIZE_ONLY)) {
|
||||||
/* If we supported only ISO C we wouldn't have to accept calling
|
/* If we supported only ISO C we wouldn't have to accept calling
|
||||||
@ -7877,9 +7913,17 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
|||||||
string constant to memory too early. */
|
string constant to memory too early. */
|
||||||
if (tok != TOK_STR && tok != TOK_LSTR)
|
if (tok != TOK_STR && tok != TOK_LSTR)
|
||||||
expect("string constant");
|
expect("string constant");
|
||||||
parse_init_elem(!sec ? EXPR_ANY : EXPR_CONST);
|
parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST);
|
||||||
}
|
}
|
||||||
init_putv(type, sec, c);
|
init_putv:
|
||||||
|
if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */
|
||||||
|
&& (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST
|
||||||
|
&& vtop->c.i == 0
|
||||||
|
&& btype_size(type->t & VT_BTYPE) /* not for fp constants */
|
||||||
|
)
|
||||||
|
vpop();
|
||||||
|
else
|
||||||
|
init_putv(p, type, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7903,38 +7947,60 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
|
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
|
||||||
#endif
|
#endif
|
||||||
|
init_params p = {0};
|
||||||
|
|
||||||
/* Always allocate static or global variables */
|
/* Always allocate static or global variables */
|
||||||
if (v && (r & VT_VALMASK) == VT_CONST)
|
if (v && (r & VT_VALMASK) == VT_CONST)
|
||||||
nocode_wanted |= 0x80000000;
|
nocode_wanted |= 0x80000000;
|
||||||
|
|
||||||
flexible_array = NULL;
|
flexible_array = NULL;
|
||||||
if ((type->t & VT_BTYPE) == VT_STRUCT) {
|
size = type_size(type, &align);
|
||||||
|
|
||||||
|
/* exactly one flexible array may be initialized, either the
|
||||||
|
toplevel array or the last member of the toplevel struct */
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
/* If the base type itself was an array type of unspecified size
|
||||||
|
(like in 'typedef int arr[]; arr x = {1};') then we will
|
||||||
|
overwrite the unknown size by the real one for this decl.
|
||||||
|
We need to unshare the ref symbol holding that size. */
|
||||||
|
type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
|
||||||
|
p.flex_array_ref = type->ref;
|
||||||
|
|
||||||
|
} else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) {
|
||||||
Sym *field = type->ref->next;
|
Sym *field = type->ref->next;
|
||||||
if (field) {
|
if (field) {
|
||||||
while (field->next)
|
while (field->next)
|
||||||
field = field->next;
|
field = field->next;
|
||||||
if (field->type.t & VT_ARRAY && field->type.ref->c < 0)
|
if (field->type.t & VT_ARRAY && field->type.ref->c < 0) {
|
||||||
flexible_array = field;
|
flexible_array = field;
|
||||||
|
p.flex_array_ref = field->type.ref;
|
||||||
|
size = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size = type_size(type, &align);
|
if (size < 0) {
|
||||||
/* If unknown size, we must evaluate it before
|
/* If unknown size, do a dry-run 1st pass */
|
||||||
evaluating initializers because
|
|
||||||
initializers can generate global data too
|
|
||||||
(e.g. string pointers or ISOC99 compound
|
|
||||||
literals). It also simplifies local
|
|
||||||
initializers handling */
|
|
||||||
if (size < 0 || (flexible_array && has_init)) {
|
|
||||||
if (!has_init)
|
if (!has_init)
|
||||||
tcc_error("unknown type size");
|
tcc_error("unknown type size");
|
||||||
get_init_string(&init_str, has_init);
|
if (has_init == 2) {
|
||||||
|
/* only get strings */
|
||||||
|
init_str = tok_str_alloc();
|
||||||
|
while (tok == TOK_STR || tok == TOK_LSTR) {
|
||||||
|
tok_str_add_tok(init_str);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
tok_str_add(init_str, -1);
|
||||||
|
tok_str_add(init_str, 0);
|
||||||
|
} else
|
||||||
|
skip_or_save_block(&init_str);
|
||||||
|
unget_tok(0);
|
||||||
|
|
||||||
/* compute size */
|
/* compute size */
|
||||||
begin_macro(init_str, 1);
|
begin_macro(init_str, 1);
|
||||||
next();
|
next();
|
||||||
decl_initializer(type, NULL, 0, DIF_FIRST | DIF_SIZE_ONLY);
|
decl_initializer(&p, type, 0, DIF_FIRST | DIF_SIZE_ONLY);
|
||||||
/* prepare second initializer parsing */
|
/* prepare second initializer parsing */
|
||||||
macro_ptr = init_str->str;
|
macro_ptr = init_str->str;
|
||||||
next();
|
next();
|
||||||
@ -7943,13 +8009,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
size = type_size(type, &align);
|
size = type_size(type, &align);
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
tcc_error("unknown type size");
|
tcc_error("unknown type size");
|
||||||
}
|
|
||||||
/* If there's a flex member and it was used in the initializer
|
/* If there's a flex member and it was used in the initializer
|
||||||
adjust size. */
|
adjust size. */
|
||||||
if (flexible_array &&
|
if (flexible_array && flexible_array->type.ref->c > 0)
|
||||||
flexible_array->type.ref->c > 0)
|
|
||||||
size += flexible_array->type.ref->c
|
size += flexible_array->type.ref->c
|
||||||
* pointed_size(&flexible_array->type);
|
* pointed_size(&flexible_array->type);
|
||||||
|
}
|
||||||
|
|
||||||
/* take into account specified alignment if bigger */
|
/* take into account specified alignment if bigger */
|
||||||
if (ad->a.aligned) {
|
if (ad->a.aligned) {
|
||||||
int speca = 1 << (ad->a.aligned - 1);
|
int speca = 1 << (ad->a.aligned - 1);
|
||||||
@ -7972,6 +8039,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
#endif
|
#endif
|
||||||
loc = (loc - size) & -align;
|
loc = (loc - size) & -align;
|
||||||
addr = loc;
|
addr = loc;
|
||||||
|
p.local_offset = addr + size;
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (bcheck && v) {
|
if (bcheck && v) {
|
||||||
/* add padding between stack variables for bound checking */
|
/* add padding between stack variables for bound checking */
|
||||||
@ -8088,12 +8156,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
cur_scope->vla.loc = addr;
|
cur_scope->vla.loc = addr;
|
||||||
cur_scope->vla.num++;
|
cur_scope->vla.num++;
|
||||||
} else if (has_init) {
|
} else if (has_init) {
|
||||||
size_t oldreloc_offset = 0;
|
p.sec = sec;
|
||||||
if (sec && sec->reloc)
|
decl_initializer(&p, type, addr, DIF_FIRST);
|
||||||
oldreloc_offset = sec->reloc->data_offset;
|
|
||||||
decl_initializer(type, sec, addr, DIF_FIRST);
|
|
||||||
if (sec && sec->reloc)
|
|
||||||
squeeze_multi_relocs(sec, oldreloc_offset);
|
|
||||||
/* patch flexible array member size back to -1, */
|
/* patch flexible array member size back to -1, */
|
||||||
/* for possible subsequent similar declarations */
|
/* for possible subsequent similar declarations */
|
||||||
if (flexible_array)
|
if (flexible_array)
|
||||||
@ -8288,14 +8352,6 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
|||||||
}
|
}
|
||||||
while (1) { /* iterate thru each declaration */
|
while (1) { /* iterate thru each declaration */
|
||||||
type = btype;
|
type = btype;
|
||||||
/* If the base type itself was an array type of unspecified
|
|
||||||
size (like in 'typedef int arr[]; arr x = {1};') then
|
|
||||||
we will overwrite the unknown size by the real one for
|
|
||||||
this decl. We need to unshare the ref symbol holding
|
|
||||||
that size. */
|
|
||||||
if ((type.t & VT_ARRAY) && type.ref->c < 0) {
|
|
||||||
type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c);
|
|
||||||
}
|
|
||||||
ad = adbase;
|
ad = adbase;
|
||||||
type_decl(&type, &ad, &v, TYPE_DIRECT);
|
type_decl(&type, &ad, &v, TYPE_DIRECT);
|
||||||
#if 0
|
#if 0
|
||||||
|
15
tccpp.c
15
tccpp.c
@ -2586,7 +2586,7 @@ static void parse_number(const char *p)
|
|||||||
tokc.i = n;
|
tokc.i = n;
|
||||||
}
|
}
|
||||||
if (ch)
|
if (ch)
|
||||||
tcc_error("invalid number\n");
|
tcc_error("invalid number");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3674,20 +3674,20 @@ static void tcc_predefs(CString *cstr)
|
|||||||
"#define __builtin_va_copy(dest,src) (dest)=(src)\n"
|
"#define __builtin_va_copy(dest,src) (dest)=(src)\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#ifdef __leading_underscore\n"
|
"#ifdef __leading_underscore\n"
|
||||||
"#define RENAME(X) __asm__(\"_\"X)\n"
|
"#define __RENAME(X) __asm__(\"_\"X)\n"
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"#define RENAME(X) __asm__(X)\n"
|
"#define __RENAME(X) __asm__(X)\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
/* TCC BBUILTIN AND BOUNDS ALIASES */
|
/* TCC BBUILTIN AND BOUNDS ALIASES */
|
||||||
"#ifdef __BOUNDS_CHECKING_ON\n"
|
"#ifdef __BOUNDS_CHECKING_ON\n"
|
||||||
"#define __BUILTINBC(ret,name,params) ret __builtin_##name params RENAME(\"__bound_\"#name);\n"
|
"#define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(\"__bound_\"#name);\n"
|
||||||
"#define __BOUND(ret,name,params) ret name params RENAME(\"__bound_\"#name);\n"
|
"#define __BOUND(ret,name,params) ret name params __RENAME(\"__bound_\"#name);\n"
|
||||||
"#else\n"
|
"#else\n"
|
||||||
"#define __BUILTINBC(ret,name,params) ret __builtin_##name params RENAME(#name);\n"
|
"#define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name);\n"
|
||||||
"#define __BOUND(ret,name,params)\n"
|
"#define __BOUND(ret,name,params)\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)\n"
|
"#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)\n"
|
||||||
"#define __BUILTIN(ret,name,params) ret __builtin_##name params RENAME(#name);\n"
|
"#define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name);\n"
|
||||||
"__BOTH(void*,memcpy,(void*,const void*,__SIZE_TYPE__))\n"
|
"__BOTH(void*,memcpy,(void*,const void*,__SIZE_TYPE__))\n"
|
||||||
"__BOTH(void*,memmove,(void*,const void*,__SIZE_TYPE__))\n"
|
"__BOTH(void*,memmove,(void*,const void*,__SIZE_TYPE__))\n"
|
||||||
"__BOTH(void*,memset,(void*,int,__SIZE_TYPE__))\n"
|
"__BOTH(void*,memset,(void*,int,__SIZE_TYPE__))\n"
|
||||||
@ -3731,6 +3731,7 @@ static void tcc_predefs(CString *cstr)
|
|||||||
"#undef __BOUND\n"
|
"#undef __BOUND\n"
|
||||||
"#undef __BOTH\n"
|
"#undef __BOTH\n"
|
||||||
"#undef __MAYBE_REDIR\n"
|
"#undef __MAYBE_REDIR\n"
|
||||||
|
"#undef __RENAME\n"
|
||||||
, -1);
|
, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,4 +346,13 @@ static struct var_len { int i; const char str[]; } var_array[] =
|
|||||||
{ 2, "longlonglonglonglong" },
|
{ 2, "longlonglonglonglong" },
|
||||||
{ 3, "tst3" } };
|
{ 3, "tst3" } };
|
||||||
|
|
||||||
|
#elif defined test_var_array2
|
||||||
|
|
||||||
|
struct c1 { int a; int b[]; };
|
||||||
|
struct c1 c1 = { 1, { 2, 3, 4 } };
|
||||||
|
|
||||||
|
struct c2 { int c; struct c1 c1; };
|
||||||
|
struct c2 c2 = { 1, { 2, { 3, 4, 5 }}};
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
#endif
|
#endif
|
||||||
|
@ -161,4 +161,7 @@ bar : 3 ; 3
|
|||||||
\n
|
\n
|
||||||
|
|
||||||
[test_var_array]
|
[test_var_array]
|
||||||
60_errors_and_warnings.c:345: warning: initializer-string for array is too long
|
60_errors_and_warnings.c:345: error: flexible array has zero size in this context
|
||||||
|
|
||||||
|
[test_var_array2]
|
||||||
|
60_errors_and_warnings.c:355: error: flexible array has zero size in this context
|
||||||
|
@ -221,19 +221,66 @@ void sys_ni(void) { printf("ni\n"); }
|
|||||||
void sys_one(void) { printf("one\n"); }
|
void sys_one(void) { printf("one\n"); }
|
||||||
void sys_two(void) { printf("two\n"); }
|
void sys_two(void) { printf("two\n"); }
|
||||||
void sys_three(void) { printf("three\n"); }
|
void sys_three(void) { printf("three\n"); }
|
||||||
|
void sys_four(void) { printf("four\n"); }
|
||||||
typedef void (*fptr)(void);
|
typedef void (*fptr)(void);
|
||||||
const fptr table[3] = {
|
|
||||||
[0 ... 2] = &sys_ni,
|
#define array_size(a) (sizeof a / sizeof a[0])
|
||||||
[0] = sys_one,
|
|
||||||
[1] = sys_two,
|
|
||||||
[2] = sys_three,
|
|
||||||
};
|
|
||||||
|
|
||||||
void test_multi_relocs(void)
|
void test_multi_relocs(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < sizeof(table)/sizeof(table[0]); i++)
|
|
||||||
table[i]();
|
static const fptr tabl1[4] = {
|
||||||
|
[0 ... 3] = &sys_ni,
|
||||||
|
[0] = sys_one,
|
||||||
|
[1] = sys_two,
|
||||||
|
[2] = sys_three,
|
||||||
|
sys_four,
|
||||||
|
[1 ... 2] = &sys_ni,
|
||||||
|
[1] = 0,
|
||||||
|
};
|
||||||
|
for (i = 0; i < array_size(tabl1); i++)
|
||||||
|
if (tabl1[i])
|
||||||
|
tabl1[i]();
|
||||||
|
else
|
||||||
|
printf("(0)\n");
|
||||||
|
|
||||||
|
const fptr tabl2[4] = {
|
||||||
|
[0 ... 3] = &sys_ni,
|
||||||
|
[0] = sys_one,
|
||||||
|
[1] = sys_two,
|
||||||
|
[2] = sys_three,
|
||||||
|
sys_four,
|
||||||
|
[1 ... 2] = &sys_ni,
|
||||||
|
[1] = 0,
|
||||||
|
};
|
||||||
|
for (i = 0; i < array_size(tabl2); i++)
|
||||||
|
if (tabl2[i])
|
||||||
|
tabl2[i]();
|
||||||
|
else
|
||||||
|
printf("(0)\n");
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
int dd[] = {
|
||||||
|
[0 ... 1] = ++c,
|
||||||
|
[2 ... 3] = ++c
|
||||||
|
};
|
||||||
|
for (i = 0; i < array_size(dd); i++)
|
||||||
|
printf(" %d", dd[i]);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* multi-dimensional flex array with range initializers */
|
||||||
|
static char m1[][2][3] = {[0 ... 2]={{3,4,5},{6,7,8}},{{9},10},"abc"};
|
||||||
|
char m2[][2][3] = {[0 ... 2]={{3,4,5},{6,7,8}},{{9},10},"abc"};
|
||||||
|
int g, j, k;
|
||||||
|
for (g = 2; g-- > 0;) {
|
||||||
|
printf("mdfa %s: %d -", "locl\0glob" + g * 5, sizeof m1);
|
||||||
|
for (i = 0; i < array_size(m1); i++)
|
||||||
|
for (j = 0; j < array_size(m1[0]); j++)
|
||||||
|
for (k = 0; k < array_size(m1[0][0]); k++)
|
||||||
|
printf(" %d", (g ? m1:m2)[i][j][k]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_init_ranges(void) {
|
void test_init_ranges(void) {
|
||||||
|
@ -41,8 +41,16 @@ lssu2: 5 0 0 0 3 0 0 0
|
|||||||
flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0
|
flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0
|
||||||
ls4: 1 2 3 4
|
ls4: 1 2 3 4
|
||||||
one
|
one
|
||||||
two
|
(0)
|
||||||
three
|
ni
|
||||||
|
four
|
||||||
|
one
|
||||||
|
(0)
|
||||||
|
ni
|
||||||
|
four
|
||||||
|
1 1 2 2
|
||||||
|
mdfa glob: 30 - 3 4 5 6 7 8 3 4 5 6 7 8 3 4 5 6 7 8 9 0 0 10 0 0 97 98 99 0 0 0
|
||||||
|
mdfa locl: 30 - 3 4 5 6 7 8 3 4 5 6 7 8 3 4 5 6 7 8 9 0 0 10 0 0 97 98 99 0 0 0
|
||||||
sea_fill0: okay
|
sea_fill0: okay
|
||||||
sea_fill1: okay
|
sea_fill1: okay
|
||||||
sea_fill2: okay
|
sea_fill2: okay
|
||||||
|
Loading…
Reference in New Issue
Block a user