History

Split off record layouting

Such struct decl: struct S { char a; int i;} __attribute__((packed)); should be accepted and cause S to be five bytes long (i.e. the packed attribute should matter). So we can't layout the members during parsing already. Split off the offset and alignment calculation for this.

Michael Matz committed 10 years ago

Commit ddecb0e1 parent 5d6a9e72 files · +114 −82Browse files

Unified · Split

2 files
  1. tccgen.c +114 −78
  2. tests/tcctest.c +0 −4
tccgen.c+114−78
@@ -3250,13 +3250,104 @@ static Sym * find_field (CType *type, int v) · 3249 unmodified lines
32503250 return s;
32513251 }
32523252
3253+static void struct_layout(CType *type, AttributeDef *ad)
3254+{
3255+ int align, maxalign, offset, c;
3256+ Sym *f;
3257+ maxalign = 1;
3258+ offset = 0;
3259+ c = 0;
3260+ 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) {
3269+ align = f->r;
3270+ } else if (ad->a.packed) {
3271+ align = 1;
3272+ }
3273+ if (extra_bytes) c += extra_bytes;
3274+ else if (bit_pos == 0) {
3275+ if (type->ref->type.t == TOK_STRUCT) {
3276+ c = (c + align - 1) & -align;
3277+ offset = c;
3278+ if (size > 0)
3279+ c += size;
3280+ } else {
3281+ offset = 0;
3282+ if (size > c)
3283+ c = size;
3284+ }
3285+ if (align > maxalign)
3286+ maxalign = align;
3287+ }
3288+#if 0
3289+ printf("set field %s offset=%d",
3290+ get_tok_str(f->v & ~SYM_FIELD, NULL), offset);
3291+ if (f->type.t & VT_BITFIELD) {
3292+ printf(" pos=%d size=%d",
3293+ (f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
3294+ (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
3295+ }
3296+ printf("\n");
3297+#endif
3298+
3299+ if (f->v & SYM_FIRST_ANOM && (f->type.t & VT_BTYPE) == VT_STRUCT) {
3300+ Sym *ass;
3301+ /* An anonymous struct/union. Adjust member offsets
3302+ to reflect the real offset of our containing struct.
3303+ Also set the offset of this anon member inside
3304+ the outer struct to be zero. Via this it
3305+ works when accessing the field offset directly
3306+ (from base object), as well as when recursing
3307+ members in initializer handling. */
3308+ int v2 = f->type.ref->v;
3309+ if (!(v2 & SYM_FIELD) &&
3310+ (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
3311+ Sym **pps;
3312+ /* This happens only with MS extensions. The
3313+ anon member has a named struct type, so it
3314+ potentially is shared with other references.
3315+ We need to unshare members so we can modify
3316+ them. */
3317+ ass = f->type.ref;
3318+ f->type.ref = sym_push(anon_sym++ | SYM_FIELD,
3319+ &f->type.ref->type, 0,
3320+ f->type.ref->c);
3321+ pps = &f->type.ref->next;
3322+ while ((ass = ass->next) != NULL) {
3323+ *pps = sym_push(ass->v, &ass->type, 0, ass->c);
3324+ pps = &((*pps)->next);
3325+ }
3326+ *pps = NULL;
3327+ }
3328+ ass = f->type.ref;
3329+ while ((ass = ass->next) != NULL)
3330+ ass->c += offset;
3331+ f->c = 0;
3332+ } else {
3333+ f->c = offset;
3334+ }
3335+
3336+ f->r = 0;
3337+ }
3338+ /* store size and alignment */
3339+ type->ref->c = (c + maxalign - 1) & -maxalign;
3340+ type->ref->r = maxalign;
3341+}
3342+
32533343 /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
32543344 static void struct_decl(CType *type, AttributeDef *ad, int u)
32553345 {
3256− int a, v, size, align, maxalign, offset, flexible, extra_bytes;
3346+ int extra_bytes;
3347+ int a, v, size, align, flexible, alignoverride;
32573348 long c;
3258− int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;
3259− Sym *s, *ss, *ass, **ps;
3349+ int bit_size, bit_pos, bsize, bt, prevbt;
3350+ Sym *s, *ss, **ps;
32603351 AttributeDef ad1;
32613352 CType type1, btype;
32623353
@@ -3343,11 +3434,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 80 unmodified lines
33433434 s->c = type_size(seen_wide ? &size_type : &int_type, &align);
33443435 skip('}');
33453436 } else {
3346− maxalign = 1;
33473437 ps = &s->next;
33483438 prevbt = VT_INT;
33493439 bit_pos = 0;
3350− offset = 0;
33513440 flexible = 0;
33523441 while (tok != '}') {
33533442 if (!parse_btype(&btype, &ad1)) {
@@ -3355,7 +3444,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 1 unmodified line
33553444 continue;
33563445 }
33573446 while (1) {
3358− extra_bytes = 0;
3447+ extra_bytes = 0;
33593448 if (flexible)
33603449 tcc_error("flexible array member '%s' not at the end of struct",
33613450 get_tok_str(v, NULL));
@@ -3399,16 +3488,17 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 37 unmodified lines
33993488 get_tok_str(v, NULL));
34003489 }
34013490 size = type_size(&type1, &align);
3491+ /* Only remember non-default alignment. */
3492+ alignoverride = 0;
34023493 if (ad1.a.aligned) {
34033494 if (align < ad1.a.aligned)
3404− align = ad1.a.aligned;
3495+ alignoverride = ad1.a.aligned;
34053496 } else if (ad1.a.packed || ad->a.packed) {
3406− align = 1;
3497+ alignoverride = 1;
34073498 } else if (*tcc_state->pack_stack_ptr) {
34083499 if (align > *tcc_state->pack_stack_ptr)
3409− align = *tcc_state->pack_stack_ptr;
3500+ alignoverride = *tcc_state->pack_stack_ptr;
34103501 }
3411− lbit_pos = 0;
34123502 if (bit_size >= 0) {
34133503 bt = type1.t & VT_BTYPE;
34143504 if (bt != VT_INT &&
@@ -3437,96 +3527,42 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 22 unmodified lines
34373527 if ((bit_pos + bit_size) > bsize ||
34383528 bt != prevbt || a == TOK_UNION)
34393529 bit_pos = 0;
3440− lbit_pos = bit_pos;
34413530 /* XXX: handle LSB first */
34423531 type1.t |= VT_BITFIELD |
34433532 (bit_pos << VT_STRUCT_SHIFT) |
34443533 (bit_size << (VT_STRUCT_SHIFT + 6));
3445− bit_pos += bit_size;
34463534 /* without ms-bitfields, allocate the
34473535 * minimum number of bytes necessary,
34483536 * adding single bytes as needed */
34493537 if (!tcc_state->ms_bitfields) {
3450− if (lbit_pos == 0)
3538+ if (bit_pos == 0)
34513539 /* minimum bytes for new bitfield */
34523540 size = (bit_size + 7) / 8;
34533541 else {
34543542 /* enough spare bits already allocated? */
3455− bit_size = (lbit_pos - 1) % 8 + 1 + bit_size;
3456− if (bit_size > 8) /* doesn't fit */
3457− extra_bytes = (bit_size - 1) / 8;
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;
34583546 }
34593547 }
3548+ bit_pos += bit_size;
34603549 }
34613550 prevbt = bt;
34623551 } else {
34633552 bit_pos = 0;
34643553 }
34653554 if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
3466− /* add new memory data only if starting bit
3467− field or adding bytes to existing bit field */
3468− if (extra_bytes) c += extra_bytes;
3469− else if (lbit_pos == 0) {
3470− if (a == TOK_STRUCT) {
3471− c = (c + align - 1) & -align;
3472− offset = c;
3473− if (size > 0)
3474− c += size;
3475− } else {
3476− offset = 0;
3477− if (size > c)
3478− c = size;
3479− }
3480− if (align > maxalign)
3481− maxalign = align;
3482− }
3483−#if 0
3484− printf("add field %s offset=%d",
3485− get_tok_str(v, NULL), offset);
3486− if (type1.t & VT_BITFIELD) {
3487− printf(" pos=%d size=%d",
3488− (type1.t >> VT_STRUCT_SHIFT) & 0x3f,
3489− (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
3490− }
3491− printf("\n");
3492−#endif
3555+ /* Remember we've seen a real field to check
3556+ for placement of flexible array member. */
3557+ c = 1;
34933558 }
34943559 if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
3495− /* An anonymous struct/union. Adjust member offsets
3496− to reflect the real offset of our containing struct.
3497− Also set the offset of this anon member inside
3498− the outer struct to be zero. Via this it
3499− works when accessing the field offset directly
3500− (from base object), as well as when recursing
3501− members in initializer handling. */
3502− int v2 = btype.ref->v;
3503− if (!(v2 & SYM_FIELD) &&
3504− (v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
3505− Sym **pps;
3506− /* This happens only with MS extensions. The
3507− anon member has a named struct type, so it
3508− potentially is shared with other references.
3509− We need to unshare members so we can modify
3510− them. */
3511− ass = type1.ref;
3512− type1.ref = sym_push(anon_sym++ | SYM_FIELD,
3513− &type1.ref->type, 0,
3514− type1.ref->c);
3515− pps = &type1.ref->next;
3516− while ((ass = ass->next) != NULL) {
3517− *pps = sym_push(ass->v, &ass->type, 0, ass->c);
3518− pps = &((*pps)->next);
3519− }
3520− *pps = NULL;
3521− }
3522− ass = type1.ref;
3523− while ((ass = ass->next) != NULL)
3524− ass->c += offset;
3525− offset = 0;
3560+ /* See struct_layout for special casing
3561+ anonymous member of struct type. */
35263562 v = anon_sym++;
35273563 }
35283564 if (v) {
3529− ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
3565+ ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
35303566 *ps = ss;
35313567 ps = &ss->next;
35323568 }
@@ -3537,9 +3573,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 4 unmodified lines
35373573 skip(';');
35383574 }
35393575 skip('}');
3540− /* store size and alignment */
3541− s->c = (c + maxalign - 1) & -maxalign;
3542− s->r = maxalign;
3576+ if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
3577+ parse_attribute(ad);
3578+ struct_layout(type, ad);
35433579 }
35443580 }
35453581 }
tests/tcctest.c+0−4
@@ -3539,7 +3539,6 @@ typedef struct __attribute__((__packed__)) { · 3538 unmodified lines
35393539 int c;
35403540 } Spacked2;
35413541 Spacked2 spacked2;
3542−#ifdef BROKEN
35433542 /* This doesn't work for now. Requires adjusting field offsets/sizes
35443543 after parsing the struct members. */
35453544 typedef struct Spacked3_s {
@@ -3548,14 +3547,11 @@ typedef struct Spacked3_s { · 2 unmodified lines
35483547 int c;
35493548 } __attribute__((__packed__)) Spacked3;
35503549 Spacked3 spacked3;
3551−#endif
35523550 void attrib_test(void)
35533551 {
35543552 printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
35553553 sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
3556−#ifdef BROKEN
35573554 printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
3558−#endif
35593555 }
35603556 extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
35613557 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