diff --git a/tcc.h b/tcc.h index 02619ba..45d62e6 100644 --- a/tcc.h +++ b/tcc.h @@ -470,7 +470,6 @@ typedef struct Sym { /* special flag, too */ #define SECTION_ABS ((void *)1) -#define SECTION_COMMON ((void *)2) typedef struct Section { unsigned long data_offset; /* current data offset */ @@ -1360,6 +1359,7 @@ typedef struct { } Stab_Sym; ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ +ST_DATA Section *common_section; ST_DATA Section *cur_text_section; /* current section where function code is generated */ #ifdef CONFIG_TCC_ASM ST_DATA Section *last_text_section; /* to handle .previous asm directive */ @@ -1381,6 +1381,7 @@ ST_FUNC void tccelf_stab_new(TCCState *s); ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); 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); diff --git a/tccelf.c b/tccelf.c index 57bf0f1..76f3da6 100644 --- a/tccelf.c +++ b/tccelf.c @@ -27,6 +27,7 @@ /* global variables */ ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ +ST_DATA Section *common_section; ST_DATA Section *cur_text_section; /* current section where function code is generated */ #ifdef CONFIG_TCC_ASM ST_DATA Section *last_text_section; /* to handle .previous asm directive */ @@ -55,6 +56,8 @@ ST_FUNC void tccelf_new(TCCState *s) text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); + common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); + common_section->sh_num = SHN_COMMON; /* symbols are always generated for linking stage */ symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, @@ -208,17 +211,27 @@ ST_FUNC void section_realloc(Section *sec, unsigned long new_size) sec->data_allocated = size; } +/* reserve at least 'size' bytes aligned per 'align' in section + 'sec' from current offset, and return the aligned offset */ +ST_FUNC size_t section_add(Section *sec, addr_t size, int align) +{ + size_t offset, offset1; + + offset = (sec->data_offset + align - 1) & -align; + offset1 = offset + size; + if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated) + section_realloc(sec, offset1); + sec->data_offset = offset1; + if (align > sec->sh_addralign) + sec->sh_addralign = align; + return offset; +} + /* reserve at least 'size' bytes in section 'sec' from sec->data_offset. */ ST_FUNC void *section_ptr_add(Section *sec, addr_t size) { - size_t offset, offset1; - - offset = sec->data_offset; - offset1 = offset + size; - if (offset1 > sec->data_allocated) - section_realloc(sec, offset1); - sec->data_offset = offset1; + size_t offset = section_add(sec, size, 1); return sec->data + offset; } @@ -702,18 +715,13 @@ static void sort_syms(TCCState *s1, Section *s) ST_FUNC void relocate_common_syms(void) { ElfW(Sym) *sym; - unsigned long offset, align; for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { if (sym->st_shndx == SHN_COMMON) { - /* align symbol */ - align = sym->st_value; - offset = bss_section->data_offset; - offset = (offset + align - 1) & -align; - sym->st_value = offset; + /* symbol alignment is in st_value for SHN_COMMONs */ + sym->st_value = section_add(bss_section, sym->st_size, + sym->st_value); sym->st_shndx = bss_section->sh_num; - offset += sym->st_size; - bss_section->data_offset = offset; } } } diff --git a/tccgen.c b/tccgen.c index 942f912..30a8969 100644 --- a/tccgen.c +++ b/tccgen.c @@ -76,6 +76,7 @@ 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 first, int size_only); static void block(int *bsym, int *csym, int is_expr); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); @@ -302,8 +303,6 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, sh_num = SHN_UNDEF; else if (section == SECTION_ABS) sh_num = SHN_ABS; - else if (section == SECTION_COMMON) - sh_num = SHN_COMMON; else sh_num = section->sh_num; @@ -1065,7 +1064,7 @@ static void gbound(void) register value (such as structures). */ ST_FUNC int gv(int rc) { - int r, bit_pos, bit_size, size, align, i; + int r, bit_pos, bit_size, size, align; int rc2; /* NOTE: get_reg can modify vstack[] */ @@ -1096,44 +1095,15 @@ ST_FUNC int gv(int rc) } else { if (is_float(vtop->type.t) && (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { - Sym *sym; - int *ptr; unsigned long offset; -#if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP) - CValue check; -#endif - - /* XXX: unify with initializers handling ? */ /* CPUs usually cannot use float constants, so we store them generically in data segment */ size = type_size(&vtop->type, &align); - offset = (data_section->data_offset + align - 1) & -align; - data_section->data_offset = offset; - /* XXX: not portable yet */ -#if defined(__i386__) || defined(__x86_64__) - /* Zero pad x87 tenbyte long doubles */ - if (size == LDOUBLE_SIZE) { - vtop->c.tab[2] &= 0xffff; -#if LDOUBLE_SIZE == 16 - vtop->c.tab[3] = 0; -#endif - } -#endif - ptr = section_ptr_add(data_section, size); - size = size >> 2; -#if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP) - check.d = 1; - if(check.tab[0]) - for(i=0;ic.tab[size-1-i]; - else -#endif - for(i=0;ic.tab[i]; - sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); - vtop->r |= VT_LVAL | VT_SYM; - vtop->sym = sym; - vtop->c.i = 0; + offset = section_add(data_section, size, align); + vpush_ref(&vtop->type, data_section, offset, size); + vswap(); + init_putv(&vtop->type, data_section, offset); + vtop->r |= VT_LVAL; } #ifdef CONFIG_TCC_BCHECK if (vtop->r & VT_MUSTBOUND) @@ -4351,7 +4321,7 @@ ST_FUNC void unary(void) t = VT_LLONG; goto push_tokc; case TOK_CULLONG: - t =VT_LLONG | VT_UNSIGNED; + t = VT_LLONG | VT_UNSIGNED; goto push_tokc; case TOK_CFLOAT: t = VT_FLOAT; @@ -6098,9 +6068,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c) gen_assign_cast(&dtype); bt = type->t & VT_BTYPE; size = type_size(type, &align); - if (c + size > sec->data_allocated) { - section_realloc(sec, c + size); - } + section_reserve(sec, c + size); ptr = sec->data + c; /* XXX: make code faster ? */ if (!(type->t & VT_BITFIELD)) { @@ -6190,6 +6158,9 @@ static void init_putv(CType *type, Section *sec, unsigned long c) case VT_SHORT: *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; break; + case VT_FLOAT: + *(float*)ptr = vtop->c.f; + break; case VT_DOUBLE: *(double *)ptr = vtop->c.d; break; @@ -6475,7 +6446,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c, static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope) { - int size, align, addr, data_offset; + int size, align, addr; ParseState saved_parse_state = {0}; TokenString *init_str = NULL; Section *sec; @@ -6624,41 +6595,24 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, } if (sec) { - data_offset = sec->data_offset; - data_offset = (data_offset + align - 1) & -align; - addr = data_offset; - /* very important to increment global pointer at this time - because initializers themselves can create new initializers */ - data_offset += size; + addr = section_add(sec, size, align); #ifdef CONFIG_TCC_BCHECK /* add padding if bound check */ if (tcc_state->do_bounds_check) - data_offset++; + section_add(sec, 1, 1); #endif - sec->data_offset = data_offset; - /* allocate section space to put the data */ - if (sec->sh_type != SHT_NOBITS && - data_offset > sec->data_allocated) - section_realloc(sec, data_offset); - /* align section if needed */ - if (align > sec->sh_addralign) - sec->sh_addralign = align; } else { - addr = 0; /* avoid warning */ + addr = align; /* SHN_COMMON is special, symbol value is align */ + sec = common_section; } if (v) { - if (scope != VT_CONST || !sym) { + if (!sym) { sym = sym_push(v, type, r | VT_SYM, 0); sym->asm_label = ad->asm_label; } /* update symbol definition */ - if (sec) { - put_extern_sym(sym, sec, addr, size); - } else { - put_extern_sym(sym, SECTION_COMMON, align, size); - } - + put_extern_sym(sym, sec, addr, size); } else { /* push global reference */ sym = get_sym_ref(type, sec, addr, size);