mirror of
https://github.com/frida/tinycc
synced 2025-01-05 03:24:25 +03:00
Fix struct layout some more
Anonymous sub-sub-members weren't handled correctly. Bit-fields neither: this implements PCC layout for now. It temporarily disables MS-compatible bit-field layout.
This commit is contained in:
parent
ddecb0e685
commit
78c7096162
153
tccgen.c
153
tccgen.c
@ -3239,7 +3239,9 @@ static Sym * find_field (CType *type, int v)
|
|||||||
Sym *s = type->ref;
|
Sym *s = type->ref;
|
||||||
v |= SYM_FIELD;
|
v |= SYM_FIELD;
|
||||||
while ((s = s->next) != NULL) {
|
while ((s = s->next) != NULL) {
|
||||||
if ((s->v & SYM_FIELD) && (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
|
if ((s->v & SYM_FIELD) &&
|
||||||
|
(s->type.t & VT_BTYPE) == VT_STRUCT &&
|
||||||
|
(s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
|
||||||
Sym *ret = find_field (&s->type, v);
|
Sym *ret = find_field (&s->type, v);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -3250,44 +3252,131 @@ static Sym * find_field (CType *type, int v)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void struct_add_offset (Sym *s, int offset)
|
||||||
|
{
|
||||||
|
while ((s = s->next) != NULL) {
|
||||||
|
if ((s->v & SYM_FIELD) &&
|
||||||
|
(s->type.t & VT_BTYPE) == VT_STRUCT &&
|
||||||
|
(s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) {
|
||||||
|
struct_add_offset(s->type.ref, offset);
|
||||||
|
} else
|
||||||
|
s->c += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void struct_layout(CType *type, AttributeDef *ad)
|
static void struct_layout(CType *type, AttributeDef *ad)
|
||||||
{
|
{
|
||||||
int align, maxalign, offset, c;
|
int align, maxalign, offset, c, bit_pos;
|
||||||
Sym *f;
|
Sym *f;
|
||||||
maxalign = 1;
|
if (ad->a.aligned)
|
||||||
|
maxalign = ad->a.aligned;
|
||||||
|
else
|
||||||
|
maxalign = 1;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
c = 0;
|
c = 0;
|
||||||
|
bit_pos = 0;
|
||||||
for (f = type->ref->next; f; f = f->next) {
|
for (f = type->ref->next; f; f = f->next) {
|
||||||
int extra_bytes = f->c;
|
int extra_bytes = 0;
|
||||||
int bit_pos;
|
int typealign, bit_size;
|
||||||
int size = type_size(&f->type, &align);
|
int size = type_size(&f->type, &typealign);
|
||||||
if (f->type.t & VT_BITFIELD)
|
int pcc = !tcc_state->ms_bitfields;
|
||||||
bit_pos = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f;
|
if (f->type.t & VT_BITFIELD) {
|
||||||
else
|
bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
|
||||||
bit_pos = 0;
|
/* without ms-bitfields, allocate the
|
||||||
if (f->r) {
|
* minimum number of bytes necessary,
|
||||||
|
* adding single bytes as needed */
|
||||||
|
if (!tcc_state->ms_bitfields) {
|
||||||
|
if (bit_pos == 0)
|
||||||
|
/* minimum bytes for new bitfield */
|
||||||
|
size = (bit_size + 7) / 8;
|
||||||
|
else {
|
||||||
|
/* enough spare bits already allocated? */
|
||||||
|
int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
|
||||||
|
if (add_size > 8) /* doesn't fit */
|
||||||
|
extra_bytes = (add_size - 1) / 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
bit_size = -1;
|
||||||
|
if (bit_size == 0 && pcc) {
|
||||||
|
/* Zero-width bit-fields in PCC mode aren't affected
|
||||||
|
by any packing (attribute or pragma). */
|
||||||
|
align = typealign;
|
||||||
|
} else if (f->r > 1) {
|
||||||
align = f->r;
|
align = f->r;
|
||||||
} else if (ad->a.packed) {
|
} else if (ad->a.packed || f->r == 1) {
|
||||||
align = 1;
|
align = 1;
|
||||||
|
typealign = 1;
|
||||||
|
} else {
|
||||||
|
align = typealign;
|
||||||
}
|
}
|
||||||
if (extra_bytes) c += extra_bytes;
|
/*if (extra_bytes) c += extra_bytes;
|
||||||
else if (bit_pos == 0) {
|
else*/ if (bit_size < 0) {
|
||||||
|
int addbytes = (bit_pos + 7) >> 3;
|
||||||
if (type->ref->type.t == TOK_STRUCT) {
|
if (type->ref->type.t == TOK_STRUCT) {
|
||||||
c = (c + align - 1) & -align;
|
c = (c + addbytes + align - 1) & -align;
|
||||||
offset = c;
|
offset = c;
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
c += size;
|
c += size;
|
||||||
} else {
|
} else {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
if (addbytes > c)
|
||||||
|
c = addbytes;
|
||||||
if (size > c)
|
if (size > c)
|
||||||
c = size;
|
c = size;
|
||||||
}
|
}
|
||||||
if (align > maxalign)
|
if (align > maxalign)
|
||||||
maxalign = align;
|
maxalign = align;
|
||||||
|
bit_pos = 0;
|
||||||
|
} else {
|
||||||
|
/* A bit-field. Layout is more complicated. There are two
|
||||||
|
options TCC implements: PCC compatible and MS compatible
|
||||||
|
(PCC compatible is what GCC uses for almost all targets). */
|
||||||
|
if (!bit_pos) {
|
||||||
|
if (type->ref->type.t == TOK_STRUCT) {
|
||||||
|
/* Don't align c here. That's only to be done
|
||||||
|
in certain cases. */
|
||||||
|
offset = c;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pcc) {
|
||||||
|
/* In PCC layout a non-packed bit-field is placed adjacent
|
||||||
|
to the preceding bit-fields, except if it would overflow
|
||||||
|
its container (depending on base type) or it's a zero-width
|
||||||
|
bit-field. Packed non-zero-width bit-fields always are
|
||||||
|
placed adjacent. */
|
||||||
|
if (typealign != 1 &&
|
||||||
|
(bit_pos + bit_size > size * 8 ||
|
||||||
|
bit_size == 0)) {
|
||||||
|
c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign;
|
||||||
|
offset = c;
|
||||||
|
bit_pos = 0;
|
||||||
|
}
|
||||||
|
/* In PCC layout named bit-fields influence the alignment
|
||||||
|
of the containing struct using the base types alignment,
|
||||||
|
except for packed fields or zero-width fields. */
|
||||||
|
if (bit_size > 0) {
|
||||||
|
if (align > maxalign)
|
||||||
|
maxalign = align;
|
||||||
|
if (typealign > maxalign)
|
||||||
|
maxalign = typealign;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcc_error("ms bit-field layout not implemented");
|
||||||
|
}
|
||||||
|
f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT))
|
||||||
|
| (bit_pos << VT_STRUCT_SHIFT);
|
||||||
|
bit_pos += bit_size;
|
||||||
|
if (bit_pos >= size * 8) {
|
||||||
|
c += size;
|
||||||
|
bit_pos -= size * 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
printf("set field %s offset=%d",
|
printf("set field %s offset=%d c=%d",
|
||||||
get_tok_str(f->v & ~SYM_FIELD, NULL), offset);
|
get_tok_str(f->v & ~SYM_FIELD, NULL), offset, c);
|
||||||
if (f->type.t & VT_BITFIELD) {
|
if (f->type.t & VT_BITFIELD) {
|
||||||
printf(" pos=%d size=%d",
|
printf(" pos=%d size=%d",
|
||||||
(f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
|
(f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
|
||||||
@ -3325,9 +3414,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
|
|||||||
}
|
}
|
||||||
*pps = NULL;
|
*pps = NULL;
|
||||||
}
|
}
|
||||||
ass = f->type.ref;
|
struct_add_offset(f->type.ref, offset);
|
||||||
while ((ass = ass->next) != NULL)
|
|
||||||
ass->c += offset;
|
|
||||||
f->c = 0;
|
f->c = 0;
|
||||||
} else {
|
} else {
|
||||||
f->c = offset;
|
f->c = offset;
|
||||||
@ -3336,7 +3423,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
|
|||||||
f->r = 0;
|
f->r = 0;
|
||||||
}
|
}
|
||||||
/* store size and alignment */
|
/* store size and alignment */
|
||||||
type->ref->c = (c + maxalign - 1) & -maxalign;
|
type->ref->c = (c + ((bit_pos + 7) >> 3) + maxalign - 1) & -maxalign;
|
||||||
type->ref->r = maxalign;
|
type->ref->r = maxalign;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3515,11 +3602,6 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
} else if (bit_size == bsize) {
|
} else if (bit_size == bsize) {
|
||||||
/* no need for bit fields */
|
/* no need for bit fields */
|
||||||
bit_pos = 0;
|
bit_pos = 0;
|
||||||
} else if (bit_size == 0) {
|
|
||||||
/* XXX: what to do if only padding in a
|
|
||||||
structure ? */
|
|
||||||
/* zero size: means to pad */
|
|
||||||
bit_pos = 0;
|
|
||||||
} else {
|
} else {
|
||||||
/* if type change, union, or will overrun
|
/* if type change, union, or will overrun
|
||||||
* allignment slot, start at a newly
|
* allignment slot, start at a newly
|
||||||
@ -3531,20 +3613,6 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
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));
|
||||||
/* without ms-bitfields, allocate the
|
|
||||||
* minimum number of bytes necessary,
|
|
||||||
* adding single bytes as needed */
|
|
||||||
if (!tcc_state->ms_bitfields) {
|
|
||||||
if (bit_pos == 0)
|
|
||||||
/* minimum bytes for new bitfield */
|
|
||||||
size = (bit_size + 7) / 8;
|
|
||||||
else {
|
|
||||||
/* enough spare bits already allocated? */
|
|
||||||
int add_size = (bit_pos - 1) % 8 + 1 + bit_size;
|
|
||||||
if (add_size > 8) /* doesn't fit */
|
|
||||||
extra_bytes = (add_size - 1) / 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bit_pos += bit_size;
|
bit_pos += bit_size;
|
||||||
}
|
}
|
||||||
prevbt = bt;
|
prevbt = bt;
|
||||||
@ -3561,6 +3629,11 @@ static void struct_decl(CType *type, AttributeDef *ad, int u)
|
|||||||
anonymous member of struct type. */
|
anonymous member of struct type. */
|
||||||
v = anon_sym++;
|
v = anon_sym++;
|
||||||
}
|
}
|
||||||
|
if (v == 0 && bit_size >= 0) {
|
||||||
|
/* Need to remember anon bit-fields as well.
|
||||||
|
They influence layout. */
|
||||||
|
v = anon_sym++;
|
||||||
|
}
|
||||||
if (v) {
|
if (v) {
|
||||||
ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
|
ss = sym_push(v | SYM_FIELD, &type1, alignoverride, extra_bytes);
|
||||||
*ps = ss;
|
*ps = ss;
|
||||||
|
@ -1026,10 +1026,67 @@ struct aligntest4 {
|
|||||||
double a[0];
|
double a[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct __attribute__((aligned(16))) aligntest5
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
struct aligntest6
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
} __attribute__((aligned(16)));
|
||||||
|
struct aligntest7
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
struct aligntest5 altest5[2];
|
||||||
|
struct aligntest6 altest6[2];
|
||||||
|
int pad1;
|
||||||
|
/* altest7 is correctly aligned to 16 bytes also with TCC,
|
||||||
|
but __alignof__ returns the wrong result (4) because we
|
||||||
|
can't store the alignment yet when specified on symbols
|
||||||
|
directly (it's stored in the type so we'd need to make
|
||||||
|
a copy of it).
|
||||||
|
struct aligntest7 altest7[2] __attribute__((aligned(16)));*/
|
||||||
|
|
||||||
|
struct Large {
|
||||||
|
unsigned long flags;
|
||||||
|
union {
|
||||||
|
void *u1;
|
||||||
|
int *u2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
union {
|
||||||
|
unsigned long index;
|
||||||
|
void *freelist;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
unsigned long counters;
|
||||||
|
struct {
|
||||||
|
int bla;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
long u3;
|
||||||
|
long u4;
|
||||||
|
};
|
||||||
|
void *u5;
|
||||||
|
struct {
|
||||||
|
unsigned long compound_head;
|
||||||
|
unsigned int compound_dtor;
|
||||||
|
unsigned int compound_order;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} __attribute__((aligned(2 * sizeof(long))));
|
||||||
|
|
||||||
void struct_test()
|
void struct_test()
|
||||||
{
|
{
|
||||||
struct1 *s;
|
struct1 *s;
|
||||||
union union2 u;
|
union union2 u;
|
||||||
|
struct Large ls;
|
||||||
|
|
||||||
printf("struct:\n");
|
printf("struct:\n");
|
||||||
printf("sizes: %d %d %d %d\n",
|
printf("sizes: %d %d %d %d\n",
|
||||||
@ -1037,6 +1094,7 @@ void struct_test()
|
|||||||
sizeof(struct struct2),
|
sizeof(struct struct2),
|
||||||
sizeof(union union1),
|
sizeof(union union1),
|
||||||
sizeof(union union2));
|
sizeof(union union2));
|
||||||
|
printf("offsets: %d\n", (int)((char*)&st1.u.v1 - (char*)&st1));
|
||||||
st1.f1 = 1;
|
st1.f1 = 1;
|
||||||
st1.f2 = 2;
|
st1.f2 = 2;
|
||||||
st1.f3 = 3;
|
st1.f3 = 3;
|
||||||
@ -1065,10 +1123,27 @@ void struct_test()
|
|||||||
sizeof(struct aligntest3), __alignof__(struct aligntest3));
|
sizeof(struct aligntest3), __alignof__(struct aligntest3));
|
||||||
printf("aligntest4 sizeof=%d alignof=%d\n",
|
printf("aligntest4 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest4), __alignof__(struct aligntest4));
|
sizeof(struct aligntest4), __alignof__(struct aligntest4));
|
||||||
|
printf("aligntest5 sizeof=%d alignof=%d\n",
|
||||||
|
sizeof(struct aligntest5), __alignof__(struct aligntest5));
|
||||||
|
printf("aligntest6 sizeof=%d alignof=%d\n",
|
||||||
|
sizeof(struct aligntest6), __alignof__(struct aligntest6));
|
||||||
|
printf("aligntest7 sizeof=%d alignof=%d\n",
|
||||||
|
sizeof(struct aligntest7), __alignof__(struct aligntest7));
|
||||||
|
printf("altest5 sizeof=%d alignof=%d\n",
|
||||||
|
sizeof(altest5), __alignof__(altest5));
|
||||||
|
printf("altest6 sizeof=%d alignof=%d\n",
|
||||||
|
sizeof(altest6), __alignof__(altest6));
|
||||||
|
/*printf("altest7 sizeof=%d alignof=%d\n",
|
||||||
|
sizeof(altest7), __alignof__(altest7));*/
|
||||||
|
|
||||||
/* empty structures (GCC extension) */
|
/* empty structures (GCC extension) */
|
||||||
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
||||||
printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
|
printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
|
||||||
|
|
||||||
|
printf("Large: sizeof=%d\n", sizeof(ls));
|
||||||
|
memset(&ls, 0, sizeof(ls));
|
||||||
|
ls.compound_head = 42;
|
||||||
|
printf("Large: offsetof(compound_head)=%d\n", (int)((char*)&ls.compound_head - (char*)&ls));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: depend on endianness */
|
/* XXX: depend on endianness */
|
||||||
@ -3547,11 +3622,22 @@ typedef struct Spacked3_s {
|
|||||||
int c;
|
int c;
|
||||||
} __attribute__((__packed__)) Spacked3;
|
} __attribute__((__packed__)) Spacked3;
|
||||||
Spacked3 spacked3;
|
Spacked3 spacked3;
|
||||||
|
struct gate_struct64 {
|
||||||
|
unsigned short offset_low;
|
||||||
|
unsigned short segment;
|
||||||
|
unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
|
||||||
|
unsigned short offset_middle;
|
||||||
|
unsigned offset_high;
|
||||||
|
unsigned zero1;
|
||||||
|
} __attribute__((packed));
|
||||||
|
typedef struct gate_struct64 gate_desc;
|
||||||
|
gate_desc a_gate_desc;
|
||||||
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));
|
||||||
printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
|
printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
|
||||||
|
printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc));
|
||||||
}
|
}
|
||||||
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