From 3783b335084ef69447c8703c7b9a94687d80b1cb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Gl=C3=B6ckner?= Date: Thu, 11 Sep 2008 19:18:58 +0200 Subject: [PATCH] Fix bitfields with non-int types and in unions The ISO C draft allow only signed/unsigned int and _Bool as base type for bitfields. TinyCC ever since allowed a wider range of types, but there were many bugs that shifted values when they shouldn't, etc.. The patch introduces a restriction to the layout of bitfields with mixed types that makes it incompatible with GCC. In struct { typeA x:1; typeB y:1; }; y is combined with x in the same byte iff typeA is typeB (neglecting signedness). This is done to avoid alignment issues and exceeding the width of typeA. --- tcc.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/tcc.c b/tcc.c index 81237a9f..cd9048a1 100644 --- a/tcc.c +++ b/tcc.c @@ -4929,10 +4929,17 @@ int gv(int rc) /* NOTE: get_reg can modify vstack[] */ if (vtop->type.t & VT_BITFIELD) { + CType type; bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; /* remove bit field info to avoid loops */ vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); + /* cast to int to propagate signedness in following ops */ + type.t = VT_INT; + if((vtop->type.t & VT_UNSIGNED) || + (vtop->type.t & VT_BTYPE) == VT_BOOL) + type.t |= VT_UNSIGNED; + gen_cast(&type); /* generate shifts */ vpushi(32 - (bit_pos + bit_size)); gen_op(TOK_SHL); @@ -6465,7 +6472,7 @@ void vstore(void) (sbt == VT_INT && dbt == VT_SHORT)) { /* optimize char/short casts */ delayed_cast = VT_MUSTCAST; - vtop->type.t = ft & VT_TYPE; + vtop->type.t = ft & (VT_TYPE & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT))); /* XXX: factorize */ if (ft & VT_CONSTANT) warning("assignment of read-only location"); @@ -6522,13 +6529,20 @@ void vstore(void) vswap(); vrott(3); + if((ft & VT_BTYPE) == VT_BOOL) { + gen_cast(&vtop[-1].type); + vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); + } + /* duplicate destination */ vdup(); vtop[-1] = vtop[-2]; /* mask and shift source */ - vpushi((1 << bit_size) - 1); - gen_op('&'); + if((ft & VT_BTYPE) != VT_BOOL) { + vpushi((1 << bit_size) - 1); + gen_op('&'); + } vpushi(bit_pos); gen_op(TOK_SHL); /* load destination, mask and or with source */ @@ -6724,7 +6738,7 @@ static void parse_attribute(AttributeDef *ad) static void struct_decl(CType *type, int u) { int a, v, size, align, maxalign, c, offset; - int bit_size, bit_pos, bsize, bt, lbit_pos; + int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; Sym *s, *ss, *ass, **ps; AttributeDef ad; CType type1, btype; @@ -6787,6 +6801,7 @@ static void struct_decl(CType *type, int u) } else { maxalign = 1; ps = &s->next; + prevbt = VT_INT; bit_pos = 0; offset = 0; while (tok != '}') { @@ -6845,11 +6860,13 @@ static void struct_decl(CType *type, int u) /* XXX: what to do if only padding in a structure ? */ /* zero size: means to pad */ - if (bit_pos > 0) - bit_pos = bsize; + bit_pos = 0; } else { - /* we do not have enough room ? */ - if ((bit_pos + bit_size) > bsize) + /* we do not have enough room ? + did the type change? + is it a union? */ + if ((bit_pos + bit_size) > bsize || + bt != prevbt || a == TOK_UNION) bit_pos = 0; lbit_pos = bit_pos; /* XXX: handle LSB first */ @@ -6858,6 +6875,7 @@ static void struct_decl(CType *type, int u) (bit_size << (VT_STRUCT_SHIFT + 6)); bit_pos += bit_size; } + prevbt = bt; } else { bit_pos = 0; } @@ -8684,6 +8702,8 @@ static void init_putv(CType *type, Section *sec, unsigned long c, (bt == VT_INT && bit_size != 32))) error("initializer element is not computable at load time"); switch(bt) { + case VT_BOOL: + vtop->c.i = (vtop->c.i != 0); case VT_BYTE: *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; break; -- 2.11.4.GIT