mirror of
https://github.com/mirror/tinycc.git
synced 2025-02-04 06:30:10 +08:00
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.
This commit is contained in:
parent
5d6a9e797a
commit
ddecb0e685
192
tccgen.c
192
tccgen.c
@ -3250,13 +3250,104 @@ static Sym * find_field (CType *type, int v)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void struct_layout(CType *type, AttributeDef *ad)
|
||||||
|
{
|
||||||
|
int align, maxalign, offset, c;
|
||||||
|
Sym *f;
|
||||||
|
maxalign = 1;
|
||||||
|
offset = 0;
|
||||||
|
c = 0;
|
||||||
|
for (f = type->ref->next; f; f = f->next) {
|
||||||
|
int extra_bytes = f->c;
|
||||||
|
int bit_pos;
|
||||||
|
int size = type_size(&f->type, &align);
|
||||||
|
if (f->type.t & VT_BITFIELD)
|
||||||
|
bit_pos = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
||||||
|
else
|
||||||
|
bit_pos = 0;
|
||||||
|
if (f->r) {
|
||||||
|
align = f->r;
|
||||||
|
} else if (ad->a.packed) {
|
||||||
|
align = 1;
|
||||||
|
}
|
||||||
|
if (extra_bytes) c += extra_bytes;
|
||||||
|
else if (bit_pos == 0) {
|
||||||
|
if (type->ref->type.t == TOK_STRUCT) {
|
||||||
|
c = (c + align - 1) & -align;
|
||||||
|
offset = c;
|
||||||
|
if (size > 0)
|
||||||
|
c += size;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
if (size > c)
|
||||||
|
c = size;
|
||||||
|
}
|
||||||
|
if (align > maxalign)
|
||||||
|
maxalign = align;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
printf("set field %s offset=%d",
|
||||||
|
get_tok_str(f->v & ~SYM_FIELD, NULL), offset);
|
||||||
|
if (f->type.t & VT_BITFIELD) {
|
||||||
|
printf(" pos=%d size=%d",
|
||||||
|
(f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
|
||||||
|
(f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (f->v & SYM_FIRST_ANOM && (f->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
|
Sym *ass;
|
||||||
|
/* An anonymous struct/union. Adjust member offsets
|
||||||
|
to reflect the real offset of our containing struct.
|
||||||
|
Also set the offset of this anon member inside
|
||||||
|
the outer struct to be zero. Via this it
|
||||||
|
works when accessing the field offset directly
|
||||||
|
(from base object), as well as when recursing
|
||||||
|
members in initializer handling. */
|
||||||
|
int v2 = f->type.ref->v;
|
||||||
|
if (!(v2 & SYM_FIELD) &&
|
||||||
|
(v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||||
|
Sym **pps;
|
||||||
|
/* This happens only with MS extensions. The
|
||||||
|
anon member has a named struct type, so it
|
||||||
|
potentially is shared with other references.
|
||||||
|
We need to unshare members so we can modify
|
||||||
|
them. */
|
||||||
|
ass = f->type.ref;
|
||||||
|
f->type.ref = sym_push(anon_sym++ | SYM_FIELD,
|
||||||
|
&f->type.ref->type, 0,
|
||||||
|
f->type.ref->c);
|
||||||
|
pps = &f->type.ref->next;
|
||||||
|
while ((ass = ass->next) != NULL) {
|
||||||
|
*pps = sym_push(ass->v, &ass->type, 0, ass->c);
|
||||||
|
pps = &((*pps)->next);
|
||||||
|
}
|
||||||
|
*pps = NULL;
|
||||||
|
}
|
||||||
|
ass = f->type.ref;
|
||||||
|
while ((ass = ass->next) != NULL)
|
||||||
|
ass->c += offset;
|
||||||
|
f->c = 0;
|
||||||
|
} else {
|
||||||
|
f->c = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->r = 0;
|
||||||
|
}
|
||||||
|
/* store size and alignment */
|
||||||
|
type->ref->c = (c + maxalign - 1) & -maxalign;
|
||||||
|
type->ref->r = maxalign;
|
||||||
|
}
|
||||||
|
|
||||||
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
|
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
|
||||||
static void struct_decl(CType *type, AttributeDef *ad, int u)
|
static void struct_decl(CType *type, AttributeDef *ad, int u)
|
||||||
{
|
{
|
||||||
int a, v, size, align, maxalign, offset, flexible, extra_bytes;
|
int extra_bytes;
|
||||||
|
int a, v, size, align, flexible, alignoverride;
|
||||||
long c;
|
long c;
|
||||||
int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;
|
int bit_size, bit_pos, bsize, bt, prevbt;
|
||||||
Sym *s, *ss, *ass, **ps;
|
Sym *s, *ss, **ps;
|
||||||
AttributeDef ad1;
|
AttributeDef ad1;
|
||||||
CType type1, btype;
|
CType type1, btype;
|
||||||
|
|
||||||
@ -3343,11 +3434,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
s->c = type_size(seen_wide ? &size_type : &int_type, &align);
|
s->c = type_size(seen_wide ? &size_type : &int_type, &align);
|
||||||
skip('}');
|
skip('}');
|
||||||
} else {
|
} else {
|
||||||
maxalign = 1;
|
|
||||||
ps = &s->next;
|
ps = &s->next;
|
||||||
prevbt = VT_INT;
|
prevbt = VT_INT;
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
offset = 0;
|
|
||||||
flexible = 0;
|
flexible = 0;
|
||||||
while (tok != '}') {
|
while (tok != '}') {
|
||||||
if (!parse_btype(&btype, &ad1)) {
|
if (!parse_btype(&btype, &ad1)) {
|
||||||
@ -3355,7 +3444,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
extra_bytes = 0;
|
extra_bytes = 0;
|
||||||
if (flexible)
|
if (flexible)
|
||||||
tcc_error("flexible array member '%s' not at the end of struct",
|
tcc_error("flexible array member '%s' not at the end of struct",
|
||||||
get_tok_str(v, NULL));
|
get_tok_str(v, NULL));
|
||||||
@ -3399,16 +3488,17 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
get_tok_str(v, NULL));
|
get_tok_str(v, NULL));
|
||||||
}
|
}
|
||||||
size = type_size(&type1, &align);
|
size = type_size(&type1, &align);
|
||||||
|
/* Only remember non-default alignment. */
|
||||||
|
alignoverride = 0;
|
||||||
if (ad1.a.aligned) {
|
if (ad1.a.aligned) {
|
||||||
if (align < ad1.a.aligned)
|
if (align < ad1.a.aligned)
|
||||||
align = ad1.a.aligned;
|
alignoverride = ad1.a.aligned;
|
||||||
} else if (ad1.a.packed || ad->a.packed) {
|
} else if (ad1.a.packed || ad->a.packed) {
|
||||||
align = 1;
|
alignoverride = 1;
|
||||||
} else if (*tcc_state->pack_stack_ptr) {
|
} else if (*tcc_state->pack_stack_ptr) {
|
||||||
if (align > *tcc_state->pack_stack_ptr)
|
if (align > *tcc_state->pack_stack_ptr)
|
||||||
align = *tcc_state->pack_stack_ptr;
|
alignoverride = *tcc_state->pack_stack_ptr;
|
||||||
}
|
}
|
||||||
lbit_pos = 0;
|
|
||||||
if (bit_size >= 0) {
|
if (bit_size >= 0) {
|
||||||
bt = type1.t & VT_BTYPE;
|
bt = type1.t & VT_BTYPE;
|
||||||
if (bt != VT_INT &&
|
if (bt != VT_INT &&
|
||||||
@ -3437,96 +3527,42 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
if ((bit_pos + bit_size) > bsize ||
|
if ((bit_pos + bit_size) > bsize ||
|
||||||
bt != prevbt || a == TOK_UNION)
|
bt != prevbt || a == TOK_UNION)
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
lbit_pos = bit_pos;
|
|
||||||
/* XXX: handle LSB first */
|
/* XXX: handle LSB first */
|
||||||
type1.t |= VT_BITFIELD |
|
type1.t |= VT_BITFIELD |
|
||||||
(bit_pos << VT_STRUCT_SHIFT) |
|
(bit_pos << VT_STRUCT_SHIFT) |
|
||||||
(bit_size << (VT_STRUCT_SHIFT + 6));
|
(bit_size << (VT_STRUCT_SHIFT + 6));
|
||||||
bit_pos += bit_size;
|
|
||||||
/* without ms-bitfields, allocate the
|
/* without ms-bitfields, allocate the
|
||||||
* minimum number of bytes necessary,
|
* minimum number of bytes necessary,
|
||||||
* adding single bytes as needed */
|
* adding single bytes as needed */
|
||||||
if (!tcc_state->ms_bitfields) {
|
if (!tcc_state->ms_bitfields) {
|
||||||
if (lbit_pos == 0)
|
if (bit_pos == 0)
|
||||||
/* minimum bytes for new bitfield */
|
/* minimum bytes for new bitfield */
|
||||||
size = (bit_size + 7) / 8;
|
size = (bit_size + 7) / 8;
|
||||||
else {
|
else {
|
||||||
/* enough spare bits already allocated? */
|
/* enough spare bits already allocated? */
|
||||||
bit_size = (lbit_pos - 1) % 8 + 1 + bit_size;
|
int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
|
||||||
if (bit_size > 8) /* doesn't fit */
|
if (add_size > 8) /* doesn't fit */
|
||||||
extra_bytes = (bit_size - 1) / 8;
|
extra_bytes = (add_size - 1) / 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bit_pos += bit_size;
|
||||||
}
|
}
|
||||||
prevbt = bt;
|
prevbt = bt;
|
||||||
} else {
|
} else {
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
}
|
}
|
||||||
if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
|
if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
/* add new memory data only if starting bit
|
/* Remember we've seen a real field to check
|
||||||
field or adding bytes to existing bit field */
|
for placement of flexible array member. */
|
||||||
if (extra_bytes) c += extra_bytes;
|
c = 1;
|
||||||
else if (lbit_pos == 0) {
|
|
||||||
if (a == TOK_STRUCT) {
|
|
||||||
c = (c + align - 1) & -align;
|
|
||||||
offset = c;
|
|
||||||
if (size > 0)
|
|
||||||
c += size;
|
|
||||||
} else {
|
|
||||||
offset = 0;
|
|
||||||
if (size > c)
|
|
||||||
c = size;
|
|
||||||
}
|
|
||||||
if (align > maxalign)
|
|
||||||
maxalign = align;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
printf("add field %s offset=%d",
|
|
||||||
get_tok_str(v, NULL), offset);
|
|
||||||
if (type1.t & VT_BITFIELD) {
|
|
||||||
printf(" pos=%d size=%d",
|
|
||||||
(type1.t >> VT_STRUCT_SHIFT) & 0x3f,
|
|
||||||
(type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
|
if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
|
||||||
/* An anonymous struct/union. Adjust member offsets
|
/* See struct_layout for special casing
|
||||||
to reflect the real offset of our containing struct.
|
anonymous member of struct type. */
|
||||||
Also set the offset of this anon member inside
|
|
||||||
the outer struct to be zero. Via this it
|
|
||||||
works when accessing the field offset directly
|
|
||||||
(from base object), as well as when recursing
|
|
||||||
members in initializer handling. */
|
|
||||||
int v2 = btype.ref->v;
|
|
||||||
if (!(v2 & SYM_FIELD) &&
|
|
||||||
(v2 & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
|
||||||
Sym **pps;
|
|
||||||
/* This happens only with MS extensions. The
|
|
||||||
anon member has a named struct type, so it
|
|
||||||
potentially is shared with other references.
|
|
||||||
We need to unshare members so we can modify
|
|
||||||
them. */
|
|
||||||
ass = type1.ref;
|
|
||||||
type1.ref = sym_push(anon_sym++ | SYM_FIELD,
|
|
||||||
&type1.ref->type, 0,
|
|
||||||
type1.ref->c);
|
|
||||||
pps = &type1.ref->next;
|
|
||||||
while ((ass = ass->next) != NULL) {
|
|
||||||
*pps = sym_push(ass->v, &ass->type, 0, ass->c);
|
|
||||||
pps = &((*pps)->next);
|
|
||||||
}
|
|
||||||
*pps = NULL;
|
|
||||||
}
|
|
||||||
ass = type1.ref;
|
|
||||||
while ((ass = ass->next) != NULL)
|
|
||||||
ass->c += offset;
|
|
||||||
offset = 0;
|
|
||||||
v = anon_sym++;
|
v = anon_sym++;
|
||||||
}
|
}
|
||||||
if (v) {
|
if (v) {
|
||||||
ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
|
ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
|
||||||
*ps = ss;
|
*ps = ss;
|
||||||
ps = &ss->next;
|
ps = &ss->next;
|
||||||
}
|
}
|
||||||
@ -3537,9 +3573,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
skip(';');
|
skip(';');
|
||||||
}
|
}
|
||||||
skip('}');
|
skip('}');
|
||||||
/* store size and alignment */
|
if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
|
||||||
s->c = (c + maxalign - 1) & -maxalign;
|
parse_attribute(ad);
|
||||||
s->r = maxalign;
|
struct_layout(type, ad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3539,7 +3539,6 @@ typedef struct __attribute__((__packed__)) {
|
|||||||
int c;
|
int c;
|
||||||
} Spacked2;
|
} Spacked2;
|
||||||
Spacked2 spacked2;
|
Spacked2 spacked2;
|
||||||
#ifdef BROKEN
|
|
||||||
/* This doesn't work for now. Requires adjusting field offsets/sizes
|
/* This doesn't work for now. Requires adjusting field offsets/sizes
|
||||||
after parsing the struct members. */
|
after parsing the struct members. */
|
||||||
typedef struct Spacked3_s {
|
typedef struct Spacked3_s {
|
||||||
@ -3548,14 +3547,11 @@ typedef struct Spacked3_s {
|
|||||||
int c;
|
int c;
|
||||||
} __attribute__((__packed__)) Spacked3;
|
} __attribute__((__packed__)) Spacked3;
|
||||||
Spacked3 spacked3;
|
Spacked3 spacked3;
|
||||||
#endif
|
|
||||||
void attrib_test(void)
|
void attrib_test(void)
|
||||||
{
|
{
|
||||||
printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
|
printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
|
||||||
sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
|
sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
|
||||||
#ifdef BROKEN
|
|
||||||
printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
|
printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
|
extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
|
||||||
strange_attrib_placement (void);
|
strange_attrib_placement (void);
|
||||||
|
Loading…
Reference in New Issue
Block a user