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
3250 return s;3250 return s;
3251}3251}
3252 3252
3253static 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
3253/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */3343/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
3254static void struct_decl(CType *type, AttributeDef *ad, int u)3344static void struct_decl(CType *type, AttributeDef *ad, int u)
3255{3345{
3256 int a, v, size, align, maxalign, offset, flexible, extra_bytes;3346 int extra_bytes;
3347 int a, v, size, align, flexible, alignoverride;
3257 long c;3348 long c;
3258 int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;3349 int bit_size, bit_pos, bsize, bt, prevbt;
3259 Sym *s, *ss, *ass, **ps;3350 Sym *s, *ss, **ps;
3260 AttributeDef ad1;3351 AttributeDef ad1;
3261 CType type1, btype;3352 CType type1, btype;
3262 3353
@@ -3343,11 +3434,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 80 unmodified lines
3343 s->c = type_size(seen_wide ? &size_type : &int_type, &align);3434 s->c = type_size(seen_wide ? &size_type : &int_type, &align);
3344 skip('}');3435 skip('}');
3345 } else {3436 } else {
3346 maxalign = 1;
3347 ps = &s->next;3437 ps = &s->next;
3348 prevbt = VT_INT;3438 prevbt = VT_INT;
3349 bit_pos = 0;3439 bit_pos = 0;
3350 offset = 0;
3351 flexible = 0;3440 flexible = 0;
3352 while (tok != '}') {3441 while (tok != '}') {
3353 if (!parse_btype(&btype, &ad1)) {3442 if (!parse_btype(&btype, &ad1)) {
@@ -3355,7 +3444,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 1 unmodified line
3355 continue;3444 continue;
3356 }3445 }
3357 while (1) {3446 while (1) {
3358 extra_bytes = 0;3447 extra_bytes = 0;
3359 if (flexible)3448 if (flexible)
3360 tcc_error("flexible array member '%s' not at the end of struct",3449 tcc_error("flexible array member '%s' not at the end of struct",
3361 get_tok_str(v, NULL));3450 get_tok_str(v, NULL));
@@ -3399,16 +3488,17 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 37 unmodified lines
3399 get_tok_str(v, NULL));3488 get_tok_str(v, NULL));
3400 }3489 }
3401 size = type_size(&type1, &align);3490 size = type_size(&type1, &align);
3491 /* Only remember non-default alignment. */
3492 alignoverride = 0;
3402 if (ad1.a.aligned) {3493 if (ad1.a.aligned) {
3403 if (align < ad1.a.aligned)3494 if (align < ad1.a.aligned)
3404 align = ad1.a.aligned;3495 alignoverride = ad1.a.aligned;
3405 } else if (ad1.a.packed || ad->a.packed) {3496 } else if (ad1.a.packed || ad->a.packed) {
3406 align = 1;3497 alignoverride = 1;
3407 } else if (*tcc_state->pack_stack_ptr) {3498 } else if (*tcc_state->pack_stack_ptr) {
3408 if (align > *tcc_state->pack_stack_ptr)3499 if (align > *tcc_state->pack_stack_ptr)
3409 align = *tcc_state->pack_stack_ptr;3500 alignoverride = *tcc_state->pack_stack_ptr;
3410 }3501 }
3411 lbit_pos = 0;
3412 if (bit_size >= 0) {3502 if (bit_size >= 0) {
3413 bt = type1.t & VT_BTYPE;3503 bt = type1.t & VT_BTYPE;
3414 if (bt != VT_INT && 3504 if (bt != VT_INT &&
@@ -3437,96 +3527,42 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 22 unmodified lines
3437 if ((bit_pos + bit_size) > bsize ||3527 if ((bit_pos + bit_size) > bsize ||
3438 bt != prevbt || a == TOK_UNION)3528 bt != prevbt || a == TOK_UNION)
3439 bit_pos = 0;3529 bit_pos = 0;
3440 lbit_pos = bit_pos;
3441 /* XXX: handle LSB first */3530 /* XXX: handle LSB first */
3442 type1.t |= VT_BITFIELD | 3531 type1.t |= VT_BITFIELD |
3443 (bit_pos << VT_STRUCT_SHIFT) |3532 (bit_pos << VT_STRUCT_SHIFT) |
3444 (bit_size << (VT_STRUCT_SHIFT + 6));3533 (bit_size << (VT_STRUCT_SHIFT + 6));
3445 bit_pos += bit_size;
3446 /* without ms-bitfields, allocate the3534 /* without ms-bitfields, allocate the
3447 * minimum number of bytes necessary,3535 * minimum number of bytes necessary,
3448 * adding single bytes as needed */3536 * adding single bytes as needed */
3449 if (!tcc_state->ms_bitfields) {3537 if (!tcc_state->ms_bitfields) {
3450 if (lbit_pos == 0)3538 if (bit_pos == 0)
3451 /* minimum bytes for new bitfield */3539 /* minimum bytes for new bitfield */
3452 size = (bit_size + 7) / 8;3540 size = (bit_size + 7) / 8;
3453 else {3541 else {
3454 /* enough spare bits already allocated? */3542 /* enough spare bits already allocated? */
3455 bit_size = (lbit_pos - 1) % 8 + 1 + bit_size;3543 int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
3456 if (bit_size > 8) /* doesn't fit */3544 if (add_size > 8) /* doesn't fit */
3457 extra_bytes = (bit_size - 1) / 8;3545 extra_bytes = (add_size - 1) / 8;
3458 }3546 }
3459 }3547 }
3548 bit_pos += bit_size;
3460 }3549 }
3461 prevbt = bt;3550 prevbt = bt;
3462 } else {3551 } else {
3463 bit_pos = 0;3552 bit_pos = 0;
3464 }3553 }
3465 if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {3554 if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
3466 /* add new memory data only if starting bit3555 /* Remember we've seen a real field to check
3467 field or adding bytes to existing bit field */3556 for placement of flexible array member. */
3468 if (extra_bytes) c += extra_bytes;3557 c = 1;
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
3493 }3558 }
3494 if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {3559 if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
3495 /* An anonymous struct/union. Adjust member offsets3560 /* See struct_layout for special casing
3496 to reflect the real offset of our containing struct.3561 anonymous member of struct type. */
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;
3526 v = anon_sym++;3562 v = anon_sym++;
3527 }3563 }
3528 if (v) {3564 if (v) {
3529 ss = sym_push(v | SYM_FIELD, &type1, 0, offset);3565 ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
3530 *ps = ss;3566 *ps = ss;
3531 ps = &ss->next;3567 ps = &ss->next;
3532 }3568 }
@@ -3537,9 +3573,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 4 unmodified lines
3537 skip(';');3573 skip(';');
3538 }3574 }
3539 skip('}');3575 skip('}');
3540 /* store size and alignment */3576 if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
3541 s->c = (c + maxalign - 1) & -maxalign; 3577 parse_attribute(ad);
3542 s->r = maxalign;3578 struct_layout(type, ad);
3543 }3579 }
3544 }3580 }
3545}3581}
tests/tcctest.c+0−4
@@ -3539,7 +3539,6 @@ typedef struct __attribute__((__packed__)) { · 3538 unmodified lines
3539 int c;3539 int c;
3540} Spacked2;3540} Spacked2;
3541Spacked2 spacked2;3541Spacked2 spacked2;
3542#ifdef BROKEN
3543/* This doesn't work for now. Requires adjusting field offsets/sizes3542/* This doesn't work for now. Requires adjusting field offsets/sizes
3544 after parsing the struct members. */3543 after parsing the struct members. */
3545typedef struct Spacked3_s {3544typedef struct Spacked3_s {
@@ -3548,14 +3547,11 @@ typedef struct Spacked3_s { · 2 unmodified lines
3548 int c;3547 int c;
3549} __attribute__((__packed__)) Spacked3;3548} __attribute__((__packed__)) Spacked3;
3550Spacked3 spacked3;3549Spacked3 spacked3;
3551#endif
3552void attrib_test(void)3550void attrib_test(void)
3553{3551{
3554 printf("attr: %d %d %d %d\n", sizeof(struct Spacked),3552 printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
3555 sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));3553 sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
3556#ifdef BROKEN
3557 printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));3554 printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
3558#endif
3559}3555}
3560extern __attribute__((__unused__)) char * __attribute__((__unused__)) *3556extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
3561strange_attrib_placement (void);3557strange_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