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
					
				
					 9 changed files with 312 additions and 225 deletions
				
			
		|  | @ -1517,7 +1517,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, | |||
|     } else if (r & VT_LVAL) { | ||||
|         reg = r & VT_VALMASK; | ||||
|         if (reg >= VT_CONST) | ||||
|             tcc_error("internal compiler error"); | ||||
|             tcc_internal_error(""); | ||||
|         snprintf(buf, sizeof(buf), "(%%%s)", | ||||
| #ifdef TCC_TARGET_X86_64 | ||||
|                  get_tok_str(TOK_ASM_rax + reg, NULL) | ||||
|  | @ -1530,7 +1530,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, | |||
|         /* register case */ | ||||
|         reg = r & VT_VALMASK; | ||||
|         if (reg >= VT_CONST) | ||||
|             tcc_error("internal compiler error"); | ||||
|             tcc_internal_error(""); | ||||
| 
 | ||||
|         /* choose register operand size */ | ||||
|         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 NORETURN void _tcc_error(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 */ | ||||
| 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 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_reserve(Section *sec, unsigned long size); | ||||
| 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); | ||||
| 
 | ||||
|  | @ -1544,8 +1545,6 @@ ST_FUNC void add_array(TCCState *s1, const char *sec, int c); | |||
| ST_FUNC void build_got_entries(TCCState *s1); | ||||
| #endif | ||||
| 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 void list_elf_symbols(TCCState *s, void *ctx, | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| #ifndef ELF_OBJ_ONLY | ||||
| /* 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) | ||||
|         section_realloc(sec, size); | ||||
|     if (size > sec->data_offset) | ||||
|         sec->data_offset = size; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| /* 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 */ | ||||
| 
 | ||||
| ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, | ||||
|                       unsigned long value) | ||||
| { | ||||
|  |  | |||
							
								
								
									
										382
									
								
								tccgen.c
									
										
									
									
									
								
							
							
						
						
									
										382
									
								
								tccgen.c
									
										
									
									
									
								
							|  | @ -123,6 +123,12 @@ static struct scope { | |||
|     Sym *lstk, *llstk; | ||||
| } *cur_scope, *loop_scope, *root_scope; | ||||
| 
 | ||||
| typedef struct { | ||||
|     Section *sec; | ||||
|     int local_offset; | ||||
|     Sym *flex_array_ref; | ||||
| } init_params; | ||||
| 
 | ||||
| /********************************************************/ | ||||
| /* 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 CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); | ||||
| static void parse_expr_type(CType *type); | ||||
| static void init_putv(CType *type, Section *sec, unsigned long c); | ||||
| static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags); | ||||
| static void init_putv(init_params *p, CType *type, unsigned long c); | ||||
| static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags); | ||||
| 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(int l); | ||||
|  | @ -2167,16 +2173,17 @@ ST_FUNC int gv(int rc) | |||
|     } else { | ||||
|         if (is_float(vtop->type.t) &&  | ||||
|             (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { | ||||
|             unsigned long offset; | ||||
|             /* CPUs usually cannot use float constants, so we store them
 | ||||
|                generically in data segment */ | ||||
|             init_params p = { data_section }; | ||||
|             unsigned long offset; | ||||
|             size = type_size(&vtop->type, &align); | ||||
|             if (NODATA_WANTED) | ||||
|                 size = 0, align = 1; | ||||
|             offset = section_add(data_section, size, align); | ||||
|             vpush_ref(&vtop->type, data_section, offset, size); | ||||
|             offset = section_add(p.sec, size, align); | ||||
|             vpush_ref(&vtop->type, p.sec, offset, size); | ||||
| 	    vswap(); | ||||
| 	    init_putv(&vtop->type, data_section, offset); | ||||
| 	    init_putv(&p, &vtop->type, offset); | ||||
| 	    vtop->r |= VT_LVAL; | ||||
|         } | ||||
| #ifdef CONFIG_TCC_BCHECK | ||||
|  | @ -5444,7 +5451,7 @@ static void parse_builtin_params(int nc, const char *args) | |||
|                 type.t = VT_SIZE_T; | ||||
|                 break; | ||||
| 	    default: | ||||
|                 tcc_error("internal error"); | ||||
|                 break; | ||||
| 	} | ||||
|         gen_assign_cast(&type); | ||||
|     } | ||||
|  | @ -6102,7 +6109,8 @@ special_math_val: | |||
|                        problems */ | ||||
|                     vseti(VT_LOCAL, loc); | ||||
| #ifdef CONFIG_TCC_BCHECK | ||||
|                     loc -= tcc_state->do_bounds_check != 0; | ||||
|                     if (tcc_state->do_bounds_check) | ||||
|                         --loc; | ||||
| #endif | ||||
|                     ret.c = vtop->c; | ||||
|                     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_ANY   2 | ||||
| 
 | ||||
|  | @ -7343,10 +7334,22 @@ static void parse_init_elem(int expr_type) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /* put zeros for variable based init */ | ||||
| static void init_putz(Section *sec, unsigned long c, int size) | ||||
| #if 1 | ||||
| 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 */ | ||||
|     } else { | ||||
|         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_SIZE_ONLY 2 | ||||
| #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
 | ||||
|    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. | ||||
|    'al' contains the already initialized length of the | ||||
|    current container (starting at c).  This returns the new length of that.  */ | ||||
| static int decl_designator(CType *type, Section *sec, unsigned long c, | ||||
|                            Sym **cur_field, int flags, int al, int size) | ||||
| static int decl_designator(init_params *p, CType *type, unsigned long c, | ||||
|                            Sym **cur_field, int flags, int al) | ||||
| { | ||||
|     Sym *s, *f; | ||||
|     int index, index_last, align, l, nb_elems, elem_size; | ||||
|     unsigned long corig = c; | ||||
|     TokenString *init_str = NULL; | ||||
| 
 | ||||
|     elem_size = 0; | ||||
|     nb_elems = 1; | ||||
|  | @ -7406,9 +7439,9 @@ static int decl_designator(CType *type, Section *sec, unsigned long c, | |||
|             } | ||||
|             skip(']'); | ||||
|             s = type->ref; | ||||
| 	    if (index < 0 || (s->c >= 0 && index_last >= s->c) || | ||||
| 		index_last < index) | ||||
| 	        tcc_error("invalid index"); | ||||
|             decl_design_flex(p, s, index_last); | ||||
|             if (index < 0 || index_last >= s->c || index_last < index) | ||||
| 	        tcc_error("index exceeds array bounds or range is empty"); | ||||
|             if (cur_field) | ||||
| 		(*cur_field)->c = index_last; | ||||
|             type = pointed_type(type); | ||||
|  | @ -7444,72 +7477,82 @@ static int decl_designator(CType *type, Section *sec, unsigned long c, | |||
|     no_designator: | ||||
|         if (type->t & VT_ARRAY) { | ||||
| 	    index = (*cur_field)->c; | ||||
| 	    if (type->ref->c >= 0 && index >= type->ref->c) | ||||
| 	        tcc_error("index too large"); | ||||
|             s = type->ref; | ||||
|             decl_design_flex(p, s, index); | ||||
|             if (index >= s->c) | ||||
|                 tcc_error("too many initializers"); | ||||
|             type = pointed_type(type); | ||||
|             c += index * type_size(type, &align); | ||||
|             elem_size = type_size(type, &align); | ||||
|             c += index * elem_size; | ||||
|         } else { | ||||
|             f = *cur_field; | ||||
| 	    while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD)) | ||||
| 	        *cur_field = f = f->next; | ||||
|             if (!f) | ||||
|                 tcc_error("too many field init"); | ||||
|                 tcc_error("too many initializers"); | ||||
| 	    type = &f->type; | ||||
|             c += f->c; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* must put zero in holes (note that doing it that way
 | ||||
|        ensures that it even works with designators) */ | ||||
|     if (!(flags & DIF_SIZE_ONLY)) { | ||||
|         int zlen = c - (corig + al); | ||||
|         if (type->t & VT_BITFIELD) { /* must include current field too */ | ||||
|             zlen += type_size(type, &align); | ||||
|             if (al + zlen > size) | ||||
|                 zlen = size - al; | ||||
|         } | ||||
|         if (zlen > 0) | ||||
| 	    init_putz(sec, corig + al, zlen); | ||||
|     if (!elem_size) /* for structs */ | ||||
|         elem_size = type_size(type, &align); | ||||
| 
 | ||||
|     /* Using designators the same element can be initialized more
 | ||||
|        than once.  In that case we need to delete possibly already | ||||
|        existing relocations. */ | ||||
|     if (!(flags & DIF_SIZE_ONLY) && c - corig < al) { | ||||
|         decl_design_delrels(p->sec, c, elem_size * nb_elems); | ||||
|         flags &= ~DIF_CLEAR; /* mark stack dirty too */ | ||||
|     } | ||||
| 
 | ||||
|     if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) { | ||||
|         get_init_string(&init_str, tok == TOK_STR || tok == TOK_LSTR ? 2 : 0); | ||||
|         begin_macro(init_str, 1); | ||||
|         next(); | ||||
|     } | ||||
| 
 | ||||
|     decl_initializer(type, sec, c, flags & ~DIF_FIRST); | ||||
|     decl_initializer(p, type, c, flags & ~DIF_FIRST); | ||||
| 
 | ||||
|     if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) { | ||||
|         Sym aref = {0}; | ||||
|         CType t1; | ||||
|         int i; | ||||
| 
 | ||||
|         for(i = 1; i < nb_elems; i++) { | ||||
|             macro_ptr = init_str->str; | ||||
|             next(); | ||||
|             decl_initializer(type, sec, c + i * elem_size, flags & ~DIF_FIRST); | ||||
|         if (p->sec || (type->t & VT_ARRAY)) { | ||||
|             /* make init_putv/vstore believe it were a struct */ | ||||
|             aref.c = elem_size; | ||||
|             t1.t = VT_STRUCT, t1.ref = &aref; | ||||
|             type = &t1; | ||||
|         } | ||||
|         end_macro(); | ||||
|         next(); | ||||
|         if (p->sec) | ||||
|             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) | ||||
|       al = c - corig; | ||||
|     return al; | ||||
| } | ||||
| 
 | ||||
| /* 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; | ||||
|     void *ptr; | ||||
|     CType dtype; | ||||
|     int size, align; | ||||
|     Section *sec = p->sec; | ||||
| 
 | ||||
|     dtype = *type; | ||||
|     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) { | ||||
| 	int size, align; | ||||
|         /* XXX: not portable */ | ||||
|         /* XXX: generate error if incorrect relocation */ | ||||
|         gen_assign_cast(&dtype); | ||||
|  | @ -7529,8 +7572,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c) | |||
|             return; | ||||
|         } | ||||
| 
 | ||||
| 	size = type_size(type, &align); | ||||
| 	section_reserve(sec, c + size); | ||||
|         ptr = sec->data + c; | ||||
| 
 | ||||
|         /* XXX: make code faster ? */ | ||||
|  | @ -7567,12 +7608,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c) | |||
| 		      continue; | ||||
| 		    if (rel->r_offset < esym->st_value) | ||||
| 		      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, | ||||
| 				   c + rel->r_offset - esym->st_value, | ||||
| 				   ELFW(R_TYPE)(rel->r_info), | ||||
|  | @ -7610,10 +7645,10 @@ static void init_putv(CType *type, Section *sec, unsigned long c) | |||
| 	    case VT_BOOL: | ||||
| 		vtop->c.i = vtop->c.i != 0; | ||||
| 	    case VT_BYTE: | ||||
| 		*(char *)ptr |= vtop->c.i; | ||||
| 		*(char *)ptr = vtop->c.i; | ||||
| 		break; | ||||
| 	    case VT_SHORT: | ||||
| 		*(short *)ptr |= vtop->c.i; | ||||
| 		*(short *)ptr = vtop->c.i; | ||||
| 		break; | ||||
| 	    case VT_FLOAT: | ||||
| 		*(float*)ptr = vtop->c.f; | ||||
|  | @ -7642,7 +7677,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) | |||
| 		break; | ||||
| #if PTR_SIZE != 8 | ||||
| 	    case VT_LLONG: | ||||
| 		*(long long *)ptr |= vtop->c.i; | ||||
| 		*(long long *)ptr = vtop->c.i; | ||||
| 		break; | ||||
| #else | ||||
| 	    case VT_LLONG: | ||||
|  | @ -7654,11 +7689,11 @@ static void init_putv(CType *type, Section *sec, unsigned long c) | |||
| 		    if (vtop->r & VT_SYM) | ||||
| 		      greloca(sec, vtop->sym, c, R_DATA_PTR, val); | ||||
| 		    else | ||||
| 		      *(addr_t *)ptr |= val; | ||||
| 		      *(addr_t *)ptr = val; | ||||
| #else | ||||
| 		    if (vtop->r & VT_SYM) | ||||
| 		      greloc(sec, vtop->sym, c, R_DATA_PTR); | ||||
| 		    *(addr_t *)ptr |= val; | ||||
| 		    *(addr_t *)ptr = val; | ||||
| #endif | ||||
| 		    break; | ||||
| 		} | ||||
|  | @ -7669,11 +7704,11 @@ static void init_putv(CType *type, Section *sec, unsigned long c) | |||
| 		    if (vtop->r & VT_SYM) | ||||
| 		      greloca(sec, vtop->sym, c, R_DATA_PTR, val); | ||||
| 		    else | ||||
| 		      *(int *)ptr |= val; | ||||
| 		      *(int *)ptr = val; | ||||
| #else | ||||
| 		    if (vtop->r & VT_SYM) | ||||
| 		      greloc(sec, vtop->sym, c, R_DATA_PTR); | ||||
| 		    *(int *)ptr |= val; | ||||
| 		    *(int *)ptr = val; | ||||
| #endif | ||||
| 		    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 | ||||
|    dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if | ||||
|    size only evaluation is wanted (only for arrays). */ | ||||
| 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) | ||||
| { | ||||
|     int len, n, no_oblock, i; | ||||
|     int size1, align1; | ||||
|  | @ -7702,13 +7736,17 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, | |||
|     Sym indexsym; | ||||
|     CType *t1; | ||||
| 
 | ||||
|     /* generate line number info */ | ||||
|     if (!p->sec && tcc_state->do_debug) | ||||
|         tcc_debug_line(tcc_state); | ||||
| 
 | ||||
|     if (!(flags & DIF_HAVE_ELEM) && tok != '{' && | ||||
| 	/* In case of strings we have special handling for arrays, so
 | ||||
| 	   don't consume them as initializer value (which would commit them | ||||
| 	   to some anonymous symbol).  */ | ||||
| 	tok != TOK_LSTR && tok != TOK_STR && | ||||
| 	!(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; | ||||
|     } | ||||
| 
 | ||||
|  | @ -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 | ||||
| 	   of course assignable to non-const elements.  */ | ||||
| 	is_compatible_unqualified_types(type, &vtop->type)) { | ||||
|         init_putv(type, sec, c); | ||||
|         goto init_putv; | ||||
| 
 | ||||
|     } 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; | ||||
|         n = s->c; | ||||
|         t1 = pointed_type(type); | ||||
|         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
 | ||||
|            them as ((w)char *) expressions */ | ||||
|         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 | ||||
| #endif | ||||
|             ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) { | ||||
|             int nb; | ||||
| 	    len = 0; | ||||
|             cstr_reset(&initstr); | ||||
|             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); | ||||
|                 tokc.str.size = initstr.size; | ||||
|                 tokc.str.data = initstr.data; | ||||
|                 indexsym.c = 0; | ||||
|                 f = &indexsym; | ||||
|                 goto do_init_list; | ||||
|                 goto do_init_array; | ||||
|             } | ||||
|             nb = len; | ||||
|             if (n >= 0 && len > n) | ||||
|               nb = n; | ||||
| 
 | ||||
|             if (!(flags & DIF_SIZE_ONLY)) { | ||||
|                 if (sec && !NODATA_WANTED && | ||||
|                     (c + nb > sec->data_allocated)) | ||||
|                   nb = sec->data_allocated - c; | ||||
|                 int nb = n; | ||||
|                 if (len < nb) | ||||
|                     nb = len; | ||||
|                 if (len > nb) | ||||
|                   tcc_warning("initializer-string for array is too long"); | ||||
|                 /* in order to go faster for common case (char
 | ||||
|                    string in global variable, we handle it | ||||
|                    specifically */ | ||||
|                 if (sec && size1 == 1) { | ||||
|                 if (p->sec && size1 == 1) { | ||||
|                     init_assert(p, c + nb); | ||||
|                     if (!NODATA_WANTED) | ||||
|                       memcpy(sec->data + c, initstr.data, nb); | ||||
|                       memcpy(p->sec->data + c, initstr.data, nb); | ||||
|                 } else { | ||||
|                     for(i=0;i<nb;i++) { | ||||
|                         if (size1 == 1) | ||||
|                     for(i=0;i<n;i++) { | ||||
|                         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]; | ||||
|                         else | ||||
|                           ch = ((nwchar_t *)initstr.data)[i]; | ||||
|                         vpushi(ch); | ||||
|                         init_putv(t1, sec, c + i * size1); | ||||
|                         init_putv(p, t1, c + i * size1); | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 decl_design_flex(p, s, len); | ||||
|             } | ||||
|             /* 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 { | ||||
| 
 | ||||
|           do_init_array: | ||||
| 	    indexsym.c = 0; | ||||
| 	    f = &indexsym; | ||||
| 
 | ||||
|           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; | ||||
| 	    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; | ||||
| 		if (type->t & VT_ARRAY) { | ||||
| 		    ++indexsym.c; | ||||
|  | @ -7836,16 +7878,9 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, | |||
| 		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) | ||||
|             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) { | ||||
| 	size1 = 1; | ||||
|         no_oblock = 1; | ||||
|         if ((flags & DIF_FIRST) || tok == '{') { | ||||
|             skip('{'); | ||||
|  | @ -7854,12 +7889,13 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, | |||
|         s = type->ref; | ||||
|         f = s->next; | ||||
|         n = s->c; | ||||
|         size1 = 1; | ||||
| 	goto do_init_list; | ||||
|     } else if (tok == '{') { | ||||
|         if (flags & DIF_HAVE_ELEM) | ||||
|           skip(';'); | ||||
|         next(); | ||||
|         decl_initializer(type, sec, c, flags & ~DIF_HAVE_ELEM); | ||||
|         decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM); | ||||
|         skip('}'); | ||||
|     } else if ((flags & DIF_SIZE_ONLY)) { | ||||
| 	/* 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.  */ | ||||
| 	    if (tok != TOK_STR && tok != TOK_LSTR) | ||||
| 	      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 | ||||
|     int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED; | ||||
| #endif | ||||
|     init_params p = {0}; | ||||
| 
 | ||||
|     /* Always allocate static or global variables */ | ||||
|     if (v && (r & VT_VALMASK) == VT_CONST) | ||||
|         nocode_wanted |= 0x80000000; | ||||
| 
 | ||||
|     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; | ||||
|         if (field) { | ||||
|             while (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; | ||||
|                 p.flex_array_ref = field->type.ref; | ||||
|                 size = -1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     size = type_size(type, &align); | ||||
|     /* If unknown size, we must evaluate it before
 | ||||
|        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 (size < 0) { | ||||
|         /* If unknown size, do a dry-run 1st pass */ | ||||
|         if (!has_init)  | ||||
|             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 */ | ||||
|         begin_macro(init_str, 1); | ||||
|         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 */ | ||||
|         macro_ptr = init_str->str; | ||||
|         next(); | ||||
|  | @ -7943,13 +8009,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, | |||
|         size = type_size(type, &align); | ||||
|         if (size < 0)  | ||||
|             tcc_error("unknown type size"); | ||||
| 
 | ||||
|         /* If there's a flex member and it was used in the initializer
 | ||||
|            adjust size.  */ | ||||
|         if (flexible_array && flexible_array->type.ref->c > 0) | ||||
|             size += flexible_array->type.ref->c | ||||
|                     * pointed_size(&flexible_array->type); | ||||
|     } | ||||
|     /* If there's a flex member and it was used in the initializer
 | ||||
|        adjust size.  */ | ||||
|     if (flexible_array && | ||||
| 	flexible_array->type.ref->c > 0) | ||||
|         size += flexible_array->type.ref->c | ||||
| 	        * pointed_size(&flexible_array->type); | ||||
| 
 | ||||
|     /* take into account specified alignment if bigger */ | ||||
|     if (ad->a.aligned) { | ||||
| 	int speca = 1 << (ad->a.aligned - 1); | ||||
|  | @ -7972,6 +8039,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, | |||
| #endif | ||||
|         loc = (loc - size) & -align; | ||||
|         addr = loc; | ||||
|         p.local_offset = addr + size; | ||||
| #ifdef CONFIG_TCC_BCHECK | ||||
|         if (bcheck && v) { | ||||
|             /* 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.num++; | ||||
|     } else if (has_init) { | ||||
| 	size_t oldreloc_offset = 0; | ||||
| 	if (sec && sec->reloc) | ||||
| 	  oldreloc_offset = sec->reloc->data_offset; | ||||
|         decl_initializer(type, sec, addr, DIF_FIRST); | ||||
| 	if (sec && sec->reloc) | ||||
| 	  squeeze_multi_relocs(sec, oldreloc_offset); | ||||
|         p.sec = sec; | ||||
|         decl_initializer(&p, type, addr, DIF_FIRST); | ||||
|         /* patch flexible array member size back to -1, */ | ||||
|         /* for possible subsequent similar declarations */ | ||||
|         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 */ | ||||
|             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; | ||||
|             type_decl(&type, &ad, &v, TYPE_DIRECT); | ||||
| #if 0 | ||||
|  |  | |||
							
								
								
									
										15
									
								
								tccpp.c
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								tccpp.c
									
										
									
									
									
								
							|  | @ -2586,7 +2586,7 @@ static void parse_number(const char *p) | |||
|         tokc.i = n; | ||||
|     } | ||||
|     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" | ||||
|     "#endif\n" | ||||
|     "#ifdef __leading_underscore\n" | ||||
|     "#define RENAME(X) __asm__(\"_\"X)\n" | ||||
|     "#define __RENAME(X) __asm__(\"_\"X)\n" | ||||
|     "#else\n" | ||||
|     "#define RENAME(X) __asm__(X)\n" | ||||
|     "#define __RENAME(X) __asm__(X)\n" | ||||
|     "#endif\n" | ||||
|     /* TCC BBUILTIN AND BOUNDS ALIASES */ | ||||
|     "#ifdef __BOUNDS_CHECKING_ON\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 __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(\"__bound_\"#name);\n" | ||||
|     "#define __BOUND(ret,name,params) ret name params __RENAME(\"__bound_\"#name);\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" | ||||
|     "#endif\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*,memmove,(void*,const void*,__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 __BOTH\n" | ||||
|     "#undef __MAYBE_REDIR\n" | ||||
|     "#undef __RENAME\n" | ||||
|     , -1); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -346,4 +346,13 @@ static struct var_len { int i; const char str[]; } var_array[] = | |||
|   { 2, "longlonglonglonglong" }, | ||||
|   { 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 | ||||
|  |  | |||
|  | @ -161,4 +161,7 @@ bar  : 3 ; 3 | |||
| \n | ||||
| 
 | ||||
| [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_two(void) { printf("two\n"); } | ||||
| void sys_three(void) { printf("three\n"); } | ||||
| void sys_four(void) { printf("four\n"); } | ||||
| typedef void (*fptr)(void); | ||||
| const fptr table[3] = { | ||||
|     [0 ... 2] = &sys_ni, | ||||
|     [0] = sys_one, | ||||
|     [1] = sys_two, | ||||
|     [2] = sys_three, | ||||
| }; | ||||
| 
 | ||||
| #define array_size(a) (sizeof a / sizeof a[0]) | ||||
| 
 | ||||
| void test_multi_relocs(void) | ||||
| { | ||||
|   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) { | ||||
|  |  | |||
|  | @ -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 | ||||
| ls4: 1 2 3 4 | ||||
| one | ||||
| two | ||||
| three | ||||
| (0) | ||||
| 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_fill1: okay | ||||
| sea_fill2: okay | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue