diff --git a/tcc.h b/tcc.h index 3f8647d..eeeb01c 100644 --- a/tcc.h +++ b/tcc.h @@ -1036,7 +1036,8 @@ struct filespec { #define VT_STATIC 0x00002000 /* static variable */ #define VT_TYPEDEF 0x00004000 /* typedef definition */ #define VT_INLINE 0x00008000 /* inline definition */ -/* currently unused: 0x000[1248]0000 */ +#define VT_PACKED 0x00010000 /* packed struct */ +/* currently unused: 0x000[248]0000 */ #define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */ #define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD) diff --git a/tccgen.c b/tccgen.c index 33a91f8..39bb682 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2316,11 +2316,18 @@ ST_FUNC int gv(int rc) int bit_pos, bit_size, size, align; /* NOTE: get_reg can modify vstack[] */ - if (vtop->type.t & VT_BITFIELD) { + if (vtop->type.t & (VT_BITFIELD | VT_PACKED)) { CType type; - bit_pos = BIT_POS(vtop->type.t); - bit_size = BIT_SIZE(vtop->type.t); + if (vtop->type.t & VT_BITFIELD) { + bit_pos = BIT_POS(vtop->type.t); + bit_size = BIT_SIZE(vtop->type.t); + } + else { + size = type_size(&vtop->type, &align); + bit_pos = 0; + bit_size = size * 8; + } /* remove bit field info to avoid loops */ vtop->type.t &= ~VT_STRUCT_MASK; @@ -2329,12 +2336,17 @@ ST_FUNC int gv(int rc) if ((vtop->type.t & VT_BTYPE) == VT_BOOL) type.t |= VT_UNSIGNED; - r = adjust_bf(vtop, bit_pos, bit_size); - - if ((vtop->type.t & VT_BTYPE) == VT_LLONG) - type.t |= VT_LLONG; - else - type.t |= VT_INT; + if (vtop->type.t & VT_PACKED) { + type.t |= VT_BYTE; + r = VT_STRUCT; + } + else { + r = adjust_bf(vtop, bit_pos, bit_size); + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) + type.t |= VT_LLONG; + else + type.t |= VT_INT; + } if (r == VT_STRUCT) { load_packed_bf(&type, bit_pos, bit_size); @@ -2528,7 +2540,7 @@ static void gv_dup(void) t = vtop->type.t; #if PTR_SIZE == 4 if ((t & VT_BTYPE) == VT_LLONG) { - if (t & VT_BITFIELD) { + if (t & (VT_BITFIELD | VT_PACKED)) { gv(RC_INT); t = vtop->type.t; } @@ -3679,7 +3691,7 @@ static void gen_cast(CType *type) force_charshort_cast(); /* bitfields first get cast to ints */ - if (vtop->type.t & VT_BITFIELD) + if (vtop->type.t & (VT_BITFIELD | VT_PACKED)) gv(RC_INT); dbt = type->t & (VT_BTYPE | VT_UNSIGNED); @@ -4151,14 +4163,21 @@ ST_FUNC void vstore(void) gfunc_call(3); /* leave source on stack */ - } else if (ft & VT_BITFIELD) { + } else if (ft & (VT_BITFIELD | VT_PACKED)) { /* bitfield store handling */ /* save lvalue as expression result (example: s.b = s.a = n;) */ vdup(), vtop[-1] = vtop[-2]; - bit_pos = BIT_POS(ft); - bit_size = BIT_SIZE(ft); + if (ft & VT_BITFIELD) { + bit_pos = BIT_POS(ft); + bit_size = BIT_SIZE(ft); + } + else { + size = type_size(&vtop[-1].type, &align); + bit_pos = 0; + bit_size = size * 8; + } /* remove bit field info to avoid loops */ vtop[-1].type.t = ft & ~VT_STRUCT_MASK; @@ -4166,11 +4185,17 @@ ST_FUNC void vstore(void) gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); } - r = adjust_bf(vtop - 1, bit_pos, bit_size); + r = ft & VT_PACKED ? VT_STRUCT : adjust_bf(vtop - 1, bit_pos, bit_size); if (dbt != VT_BOOL) { gen_cast(&vtop[-1].type); dbt = vtop[-1].type.t & VT_BTYPE; - } + } + + if (ft & VT_PACKED) { + vtop->type.t = vtop->type.t & ~VT_PACKED; + vtop[-1].type.t = (vtop[-1].type.t & ~(VT_BTYPE | VT_PACKED)) | VT_BYTE; + } + if (r == VT_STRUCT) { store_packed_bf(bit_pos, bit_size); } else { @@ -4603,6 +4628,10 @@ static void struct_layout(CType *type, AttributeDef *ad) if (pcc && pragma_pack < a) a = 0; } +#ifdef TCC_TARGET_ARM + if (packed) + f->type.t |= VT_PACKED; +#endif } /* some individual align was specified */ if (a) diff --git a/tests/tests2/96_nodata_wanted.c b/tests/tests2/96_nodata_wanted.c index 1a4cd33..4e95603 100644 --- a/tests/tests2/96_nodata_wanted.c +++ b/tests/tests2/96_nodata_wanted.c @@ -58,10 +58,7 @@ ts1:; void *p = (void*)&main; char cc[] = "static string"; double d = 8.0; - struct -#ifndef __arm__ - __attribute__((packed)) -#endif + struct __attribute__((packed)) { unsigned x : 12; unsigned char y : 7;