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 | return s; | 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 | /* 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 */ |
| 3254 | static void struct_decl(CType *type, AttributeDef *ad, int u) | 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 | 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 the | 3534 | /* 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 bit | 3555 | /* 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 offsets | 3560 | /* 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 | } |
| @@ -3539,7 +3539,6 @@ typedef struct __attribute__((__packed__)) { · 3538 unmodified lines | |||
| 3539 | int c; | 3539 | int c; |
| 3540 | } Spacked2; | 3540 | } Spacked2; |
| 3541 | Spacked2 spacked2; | 3541 | Spacked2 spacked2; |
| 3542 | #ifdef BROKEN | ||
| 3543 | /* This doesn't work for now. Requires adjusting field offsets/sizes | 3542 | /* This doesn't work for now. Requires adjusting field offsets/sizes |
| 3544 | after parsing the struct members. */ | 3543 | after parsing the struct members. */ |
| 3545 | typedef struct Spacked3_s { | 3544 | typedef 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; |
| 3550 | Spacked3 spacked3; | 3549 | Spacked3 spacked3; |
| 3551 | #endif | ||
| 3552 | void attrib_test(void) | 3550 | void 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 | } |
| 3560 | extern __attribute__((__unused__)) char * __attribute__((__unused__)) * | 3556 | extern __attribute__((__unused__)) char * __attribute__((__unused__)) * |
| 3561 | strange_attrib_placement (void); | 3557 | strange_attrib_placement (void); |