mirror of
https://github.com/frida/tinycc
synced 2024-12-25 06:26:49 +03:00
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.
This commit is contained in:
parent
43a34d354a
commit
3783b33508
36
tcc.c
36
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;
|
||||
|
Loading…
Reference in New Issue
Block a user