History

Fix struct layout some more

Anonymous sub-sub-members weren't handled correctly. Bit-fields neither: this implements PCC layout for now. It temporarily disables MS-compatible bit-field layout.

Michael Matz committed 10 years ago

Commit 78c70961 parent ddecb0e2 files · +199 −40Browse files

Unified · Split

2 files
  1. tccgen.c +113 −40
  2. tests/tcctest.c +86 −0
tccgen.c+113−40
@@ -3239,7 +3239,9 @@ static Sym * find_field (CType *type, int v) · 3238 unmodified lines
32393239 Sym *s = type->ref;
32403240 v |= SYM_FIELD;
32413241 while ((s = s->next) != NULL) {
3242− if ((s->v & SYM_FIELD) && (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
3242+ if ((s->v & SYM_FIELD) &&
3243+ (s->type.t & VT_BTYPE) == VT_STRUCT &&
3244+ (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
32433245 Sym *ret = find_field (&s->type, v);
32443246 if (ret)
32453247 return ret;
@@ -3250,44 +3252,131 @@ static Sym * find_field (CType *type, int v) · 4 unmodified lines
32503252 return s;
32513253 }
32523254
3255+static void struct_add_offset (Sym *s, int offset)
3256+{
3257+ while ((s = s->next) != NULL) {
3258+ if ((s->v & SYM_FIELD) &&
3259+ (s->type.t & VT_BTYPE) == VT_STRUCT &&
3260+ (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
3261+ struct_add_offset(s->type.ref, offset);
3262+ } else
3263+ s->c += offset;
3264+ }
3265+}
3266+
32533267 static void struct_layout(CType *type, AttributeDef *ad)
32543268 {
3255− int align, maxalign, offset, c;
3269+ int align, maxalign, offset, c, bit_pos;
32563270 Sym *f;
3257− maxalign = 1;
3271+ if (ad->a.aligned)
3272+ maxalign = ad->a.aligned;
3273+ else
3274+ maxalign = 1;
32583275 offset = 0;
32593276 c = 0;
3277+ bit_pos = 0;
32603278 for (f = type->ref->next; f; f = f->next) {
3261− int extra_bytes = f->c;
3262− int bit_pos;
3263− int size = type_size(&f->type, &align);
3264− if (f->type.t & VT_BITFIELD)
3265− bit_pos = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f;
3266− else
3267− bit_pos = 0;
3268− if (f->r) {
3279+ int extra_bytes = 0;
3280+ int typealign, bit_size;
3281+ int size = type_size(&f->type, &typealign);
3282+ int pcc = !tcc_state->ms_bitfields;
3283+ if (f->type.t & VT_BITFIELD) {
3284+ bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
3285+ /* without ms-bitfields, allocate the
3286+ * minimum number of bytes necessary,
3287+ * adding single bytes as needed */
3288+ if (!tcc_state->ms_bitfields) {
3289+ if (bit_pos == 0)
3290+ /* minimum bytes for new bitfield */
3291+ size = (bit_size + 7) / 8;
3292+ else {
3293+ /* enough spare bits already allocated? */
3294+ int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
3295+ if (add_size > 8) /* doesn't fit */
3296+ extra_bytes = (add_size - 1) / 8;
3297+ }
3298+ }
3299+ } else
3300+ bit_size = -1;
3301+ if (bit_size == 0 && pcc) {
3302+ /* Zero-width bit-fields in PCC mode aren't affected
3303+ by any packing (attribute or pragma). */
3304+ align = typealign;
3305+ } else if (f->r > 1) {
32693306 align = f->r;
3270− } else if (ad->a.packed) {
3307+ } else if (ad->a.packed || f->r == 1) {
32713308 align = 1;
3309+ typealign = 1;
3310+ } else {
3311+ align = typealign;
32723312 }
3273− if (extra_bytes) c += extra_bytes;
3274− else if (bit_pos == 0) {
3313+ /*if (extra_bytes) c += extra_bytes;
3314+ else*/ if (bit_size < 0) {
3315+ int addbytes = (bit_pos + 7) >> 3;
32753316 if (type->ref->type.t == TOK_STRUCT) {
3276− c = (c + align - 1) & -align;
3317+ c = (c + addbytes + align - 1) & -align;
32773318 offset = c;
32783319 if (size > 0)
32793320 c += size;
32803321 } else {
32813322 offset = 0;
3323+ if (addbytes > c)
3324+ c = addbytes;
32823325 if (size > c)
32833326 c = size;
32843327 }
32853328 if (align > maxalign)
32863329 maxalign = align;
3330+ bit_pos = 0;
3331+ } else {
3332+ /* A bit-field. Layout is more complicated. There are two
3333+ options TCC implements: PCC compatible and MS compatible
3334+ (PCC compatible is what GCC uses for almost all targets). */
3335+ if (!bit_pos) {
3336+ if (type->ref->type.t == TOK_STRUCT) {
3337+ /* Don't align c here. That's only to be done
3338+ in certain cases. */
3339+ offset = c;
3340+ } else {
3341+ offset = 0;
3342+ }
3343+ }
3344+ if (pcc) {
3345+ /* In PCC layout a non-packed bit-field is placed adjacent
3346+ to the preceding bit-fields, except if it would overflow
3347+ its container (depending on base type) or it's a zero-width
3348+ bit-field. Packed non-zero-width bit-fields always are
3349+ placed adjacent. */
3350+ if (typealign != 1 &&
3351+ (bit_pos + bit_size > size * 8 ||
3352+ bit_size == 0)) {
3353+ c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign;
3354+ offset = c;
3355+ bit_pos = 0;
3356+ }
3357+ /* In PCC layout named bit-fields influence the alignment
3358+ of the containing struct using the base types alignment,
3359+ except for packed fields or zero-width fields. */
3360+ if (bit_size > 0) {
3361+ if (align > maxalign)
3362+ maxalign = align;
3363+ if (typealign > maxalign)
3364+ maxalign = typealign;
3365+ }
3366+ } else {
3367+ tcc_error("ms bit-field layout not implemented");
3368+ }
3369+ f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
3370+ | (bit_pos << VT_STRUCT_SHIFT);
3371+ bit_pos += bit_size;
3372+ if (bit_pos >= size * 8) {
3373+ c += size;
3374+ bit_pos -= size * 8;
3375+ }
32873376 }
32883377 #if 0
3289− printf("set field %s offset=%d",
3290− get_tok_str(f->v & ~SYM_FIELD, NULL), offset);
3378+ printf("set field %s offset=%d c=%d",
3379+ get_tok_str(f->v & ~SYM_FIELD, NULL), offset, c);
32913380 if (f->type.t & VT_BITFIELD) {
32923381 printf(" pos=%d size=%d",
32933382 (f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
@@ -3325,9 +3414,7 @@ static void struct_layout(CType *type, AttributeDef *ad) · 31 unmodified lines
33253414 }
33263415 *pps = NULL;
33273416 }
3328− ass = f->type.ref;
3329− while ((ass = ass->next) != NULL)
3330− ass->c += offset;
3417+ struct_add_offset(f->type.ref, offset);
33313418 f->c = 0;
33323419 } else {
33333420 f->c = offset;
@@ -3336,7 +3423,7 @@ static void struct_layout(CType *type, AttributeDef *ad) · 2 unmodified lines
33363423 f->r = 0;
33373424 }
33383425 /* store size and alignment */
3339− type->ref->c = (c + maxalign - 1) & -maxalign;
3426+ type->ref->c = (c + ((bit_pos + 7) >> 3) + maxalign - 1) & -maxalign;
33403427 type->ref->r = maxalign;
33413428 }
33423429
@@ -3515,11 +3602,6 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 172 unmodified lines
35153602 } else if (bit_size == bsize) {
35163603 /* no need for bit fields */
35173604 bit_pos = 0;
3518− } else if (bit_size == 0) {
3519− /* XXX: what to do if only padding in a
3520− structure ? */
3521− /* zero size: means to pad */
3522− bit_pos = 0;
35233605 } else {
35243606 /* if type change, union, or will overrun
35253607 * allignment slot, start at a newly
@@ -3531,20 +3613,6 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 5 unmodified lines
35313613 type1.t |= VT_BITFIELD |
35323614 (bit_pos << VT_STRUCT_SHIFT) |
35333615 (bit_size << (VT_STRUCT_SHIFT + 6));
3534− /* without ms-bitfields, allocate the
3535− * minimum number of bytes necessary,
3536− * adding single bytes as needed */
3537− if (!tcc_state->ms_bitfields) {
3538− if (bit_pos == 0)
3539− /* minimum bytes for new bitfield */
3540− size = (bit_size + 7) / 8;
3541− else {
3542− /* enough spare bits already allocated? */
3543− int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
3544− if (add_size > 8) /* doesn't fit */
3545− extra_bytes = (add_size - 1) / 8;
3546− }
3547− }
35483616 bit_pos += bit_size;
35493617 }
35503618 prevbt = bt;
@@ -3561,6 +3629,11 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 10 unmodified lines
35613629 anonymous member of struct type. */
35623630 v = anon_sym++;
35633631 }
3632+ if (v == 0 && bit_size >= 0) {
3633+ /* Need to remember anon bit-fields as well.
3634+ They influence layout. */
3635+ v = anon_sym++;
3636+ }
35643637 if (v) {
35653638 ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
35663639 *ps = ss;
tests/tcctest.c+86−0
@@ -1026,10 +1026,67 @@ struct aligntest4 { · 1025 unmodified lines
10261026 double a[0];
10271027 };
10281028
1029+struct __attribute__((aligned(16))) aligntest5
1030+{
1031+ int i;
1032+};
1033+struct aligntest6
1034+{
1035+ int i;
1036+} __attribute__((aligned(16)));
1037+struct aligntest7
1038+{
1039+ int i;
1040+};
1041+struct aligntest5 altest5[2];
1042+struct aligntest6 altest6[2];
1043+int pad1;
1044+/* altest7 is correctly aligned to 16 bytes also with TCC,
1045+ but __alignof__ returns the wrong result (4) because we
1046+ can't store the alignment yet when specified on symbols
1047+ directly (it's stored in the type so we'd need to make
1048+ a copy of it).
1049+struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
1050+
1051+struct Large {
1052+ unsigned long flags;
1053+ union {
1054+ void *u1;
1055+ int *u2;
1056+ };
1057+
1058+ struct {
1059+ union {
1060+ unsigned long index;
1061+ void *freelist;
1062+ };
1063+ union {
1064+ unsigned long counters;
1065+ struct {
1066+ int bla;
1067+ };
1068+ };
1069+ };
1070+
1071+ union {
1072+ struct {
1073+ long u3;
1074+ long u4;
1075+ };
1076+ void *u5;
1077+ struct {
1078+ unsigned long compound_head;
1079+ unsigned int compound_dtor;
1080+ unsigned int compound_order;
1081+ };
1082+ };
1083+} __attribute__((aligned(2 * sizeof(long))));
1084+
10291085 void struct_test()
10301086 {
10311087 struct1 *s;
10321088 union union2 u;
1089+ struct Large ls;
10331090
10341091 printf("struct:\n");
10351092 printf("sizes: %d %d %d %d\n",
@@ -1037,6 +1094,7 @@ void struct_test() · 1 unmodified line
10371094 sizeof(struct struct2),
10381095 sizeof(union union1),
10391096 sizeof(union union2));
1097+ printf("offsets: %d\n", (int)((char*)&st1.u.v1 - (char*)&st1));
10401098 st1.f1 = 1;
10411099 st1.f2 = 2;
10421100 st1.f3 = 3;
@@ -1065,10 +1123,27 @@ void struct_test() · 22 unmodified lines
10651123 sizeof(struct aligntest3), __alignof__(struct aligntest3));
10661124 printf("aligntest4 sizeof=%d alignof=%d\n",
10671125 sizeof(struct aligntest4), __alignof__(struct aligntest4));
1126+ printf("aligntest5 sizeof=%d alignof=%d\n",
1127+ sizeof(struct aligntest5), __alignof__(struct aligntest5));
1128+ printf("aligntest6 sizeof=%d alignof=%d\n",
1129+ sizeof(struct aligntest6), __alignof__(struct aligntest6));
1130+ printf("aligntest7 sizeof=%d alignof=%d\n",
1131+ sizeof(struct aligntest7), __alignof__(struct aligntest7));
1132+ printf("altest5 sizeof=%d alignof=%d\n",
1133+ sizeof(altest5), __alignof__(altest5));
1134+ printf("altest6 sizeof=%d alignof=%d\n",
1135+ sizeof(altest6), __alignof__(altest6));
1136+ /*printf("altest7 sizeof=%d alignof=%d\n",
1137+ sizeof(altest7), __alignof__(altest7));*/
10681138
10691139 /* empty structures (GCC extension) */
10701140 printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
10711141 printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
1142+
1143+ printf("Large: sizeof=%d\n", sizeof(ls));
1144+ memset(&ls, 0, sizeof(ls));
1145+ ls.compound_head = 42;
1146+ printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
10721147 }
10731148
10741149 /* XXX: depend on endianness */
@@ -3547,11 +3622,22 @@ typedef struct Spacked3_s { · 2472 unmodified lines
35473622 int c;
35483623 } __attribute__((__packed__)) Spacked3;
35493624 Spacked3 spacked3;
3625+struct gate_struct64 {
3626+ unsigned short offset_low;
3627+ unsigned short segment;
3628+ unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
3629+ unsigned short offset_middle;
3630+ unsigned offset_high;
3631+ unsigned zero1;
3632+} __attribute__((packed));
3633+typedef struct gate_struct64 gate_desc;
3634+gate_desc a_gate_desc;
35503635 void attrib_test(void)
35513636 {
35523637 printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
35533638 sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
35543639 printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
3640+ printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc));
35553641 }
35563642 extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
35573643 strange_attrib_placement (void);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t