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.
Unified · Split
| @@ -3250,13 +3250,104 @@ static Sym * find_field (CType *type, int v) · 3249 unmodified lines | ||
| 3250 | 3250 | return s; |
| 3251 | 3251 | } |
| 3252 | 3252 | |
| 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 | + | |
| 3253 | 3343 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
| 3254 | 3344 | static 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 | 3348 | 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; | |
| 3260 | 3351 | AttributeDef ad1; |
| 3261 | 3352 | CType type1, btype; |
| 3262 | 3353 | |
| @@ -3343,11 +3434,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 80 unmodified lines | ||
| 3343 | 3434 | s->c = type_size(seen_wide ? &size_type : &int_type, &align); |
| 3344 | 3435 | skip('}'); |
| 3345 | 3436 | } else { |
| 3346 | − maxalign = 1; | |
| 3347 | 3437 | ps = &s->next; |
| 3348 | 3438 | prevbt = VT_INT; |
| 3349 | 3439 | bit_pos = 0; |
| 3350 | − offset = 0; | |
| 3351 | 3440 | flexible = 0; |
| 3352 | 3441 | while (tok != '}') { |
| 3353 | 3442 | if (!parse_btype(&btype, &ad1)) { |
| @@ -3355,7 +3444,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 1 unmodified line | ||
| 3355 | 3444 | continue; |
| 3356 | 3445 | } |
| 3357 | 3446 | while (1) { |
| 3358 | − extra_bytes = 0; | |
| 3447 | + extra_bytes = 0; | |
| 3359 | 3448 | if (flexible) |
| 3360 | 3449 | tcc_error("flexible array member '%s' not at the end of struct", |
| 3361 | 3450 | get_tok_str(v, NULL)); |
| @@ -3399,16 +3488,17 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 37 unmodified lines | ||
| 3399 | 3488 | get_tok_str(v, NULL)); |
| 3400 | 3489 | } |
| 3401 | 3490 | size = type_size(&type1, &align); |
| 3491 | + /* Only remember non-default alignment. */ | |
| 3492 | + alignoverride = 0; | |
| 3402 | 3493 | if (ad1.a.aligned) { |
| 3403 | 3494 | if (align < ad1.a.aligned) |
| 3404 | − align = ad1.a.aligned; | |
| 3495 | + alignoverride = ad1.a.aligned; | |
| 3405 | 3496 | } else if (ad1.a.packed || ad->a.packed) { |
| 3406 | − align = 1; | |
| 3497 | + alignoverride = 1; | |
| 3407 | 3498 | } else if (*tcc_state->pack_stack_ptr) { |
| 3408 | 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 | 3502 | if (bit_size >= 0) { |
| 3413 | 3503 | bt = type1.t & VT_BTYPE; |
| 3414 | 3504 | if (bt != VT_INT && |
| @@ -3437,96 +3527,42 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 22 unmodified lines | ||
| 3437 | 3527 | if ((bit_pos + bit_size) > bsize || |
| 3438 | 3528 | bt != prevbt || a == TOK_UNION) |
| 3439 | 3529 | bit_pos = 0; |
| 3440 | − lbit_pos = bit_pos; | |
| 3441 | 3530 | /* XXX: handle LSB first */ |
| 3442 | 3531 | type1.t |= VT_BITFIELD | |
| 3443 | 3532 | (bit_pos << VT_STRUCT_SHIFT) | |
| 3444 | 3533 | (bit_size << (VT_STRUCT_SHIFT + 6)); |
| 3445 | − bit_pos += bit_size; | |
| 3446 | 3534 | /* without ms-bitfields, allocate the |
| 3447 | 3535 | * minimum number of bytes necessary, |
| 3448 | 3536 | * adding single bytes as needed */ |
| 3449 | 3537 | if (!tcc_state->ms_bitfields) { |
| 3450 | − if (lbit_pos == 0) | |
| 3538 | + if (bit_pos == 0) | |
| 3451 | 3539 | /* minimum bytes for new bitfield */ |
| 3452 | 3540 | size = (bit_size + 7) / 8; |
| 3453 | 3541 | else { |
| 3454 | 3542 | /* 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; | |
| 3458 | 3546 | } |
| 3459 | 3547 | } |
| 3548 | + bit_pos += bit_size; | |
| 3460 | 3549 | } |
| 3461 | 3550 | prevbt = bt; |
| 3462 | 3551 | } else { |
| 3463 | 3552 | bit_pos = 0; |
| 3464 | 3553 | } |
| 3465 | 3554 | 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; | |
| 3493 | 3558 | } |
| 3494 | 3559 | 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. */ | |
| 3526 | 3562 | v = anon_sym++; |
| 3527 | 3563 | } |
| 3528 | 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 | 3566 | *ps = ss; |
| 3531 | 3567 | ps = &ss->next; |
| 3532 | 3568 | } |
| @@ -3537,9 +3573,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) · 4 unmodified lines | ||
| 3537 | 3573 | skip(';'); |
| 3538 | 3574 | } |
| 3539 | 3575 | 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); | |
| 3543 | 3579 | } |
| 3544 | 3580 | } |
| 3545 | 3581 | } |
| @@ -3539,7 +3539,6 @@ typedef struct __attribute__((__packed__)) { · 3538 unmodified lines | ||
| 3539 | 3539 | int c; |
| 3540 | 3540 | } Spacked2; |
| 3541 | 3541 | Spacked2 spacked2; |
| 3542 | −#ifdef BROKEN | |
| 3543 | 3542 | /* This doesn't work for now. Requires adjusting field offsets/sizes |
| 3544 | 3543 | after parsing the struct members. */ |
| 3545 | 3544 | typedef struct Spacked3_s { |
| @@ -3548,14 +3547,11 @@ typedef struct Spacked3_s { · 2 unmodified lines | ||
| 3548 | 3547 | int c; |
| 3549 | 3548 | } __attribute__((__packed__)) Spacked3; |
| 3550 | 3549 | Spacked3 spacked3; |
| 3551 | −#endif | |
| 3552 | 3550 | void attrib_test(void) |
| 3553 | 3551 | { |
| 3554 | 3552 | printf("attr: %d %d %d %d\n", sizeof(struct Spacked), |
| 3555 | 3553 | sizeof(spacked), sizeof(Spacked2), sizeof(spacked2)); |
| 3556 | −#ifdef BROKEN | |
| 3557 | 3554 | printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3)); |
| 3558 | −#endif | |
| 3559 | 3555 | } |
| 3560 | 3556 | extern __attribute__((__unused__)) char * __attribute__((__unused__)) * |
| 3561 | 3557 | strange_attrib_placement (void); |