diff options
| author | grischka <grischka> | 2017-05-09 18:10:02 +0200 |
|---|---|---|
| committer | grischka <grischka> | 2017-05-09 18:10:02 +0200 |
| commit | d242706f3b739bcb00de1d970a01a319db6ad77d (patch) | |
| tree | 1de0c3a07502e60fde9a8c63814e3662e5e062dc /tccgen.c | |
| parent | 3f5fd305afbe63c6bc4af5e06b315f4fce60b694 (diff) | |
| download | tinycc-d242706f3b739bcb00de1d970a01a319db6ad77d.tar.gz tinycc-d242706f3b739bcb00de1d970a01a319db6ad77d.tar.bz2 | |
bitfields: one more hack and a "-Wgcc-compat" switch
bit_pos + bit_size > type_size * 8
must NEVER happen because the code generator can read/write
only the basic integral types.
Warn if tcc has to break GCC compatibility for that reason
and if -Wgcc-compat is given.
Example:
struct __attribute__((packed)) _s
{
unsigned int x : 12;
unsigned char y : 7;
unsigned int z : 28;
};
Expected (GCC) layout (sizeof struct = 6)
.xxxxxxxx.xxxxyyyy.yyyzzzzz.zzzzzzzz.zzzzzzzz.zzzzzzz0.
But we cannot read/write 'char y'from 2 bytes in memory.
So we have to adjust:
.xxxxxxxx.xxxx0000.yyyyyyyz.zzzzzzzz.zzzzzzzz.zzzzzzzz.zzz00000
Now 'int z' cannot be accessed from 5 bytes. So we arrive
at this (sizeof struct = 7):
.xxxxxxxx.xxxx0000.yyyyyyy0.zzzzzzzz.zzzzzzzz.zzzzzzzz.zzzz0000
Otherwise the bitfield load/store generator needs to be
changed to allow byte-wise accesses.
Also we may touch memory past the struct in some cases
currently. The patch adds a warning for that too.
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 81 ec 04 00 00 00 sub $0x4,%esp
9: 90 nop
struct __attribute__((packed)) { unsigned x : 5; } b = {0} ;
a: 8b 45 ff mov -0x1(%ebp),%eax
d: 83 e0 e0 and $0xffffffe0,%eax
10: 89 45 ff mov %eax,-0x1(%ebp)
This touches -0x1 ... +0x3(%ebp), hence 3 bytes beyond
stack space. Since the data is not changed, nothing
else happens here.
Diffstat (limited to 'tccgen.c')
| -rw-r--r-- | tccgen.c | 25 |
1 files changed, 19 insertions, 6 deletions
@@ -3285,6 +3285,9 @@ static void struct_layout(CType *type, AttributeDef *ad) { int align, maxalign, offset, c, bit_pos, bt, prevbt, prev_bit_size; int pcc = !tcc_state->ms_bitfields; + int packwarn = tcc_state->warn_gcc_compat; + int typealign, bit_size, size; + Sym *f; if (ad->a.aligned) maxalign = 1 << (ad->a.aligned - 1); @@ -3295,9 +3298,10 @@ static void struct_layout(CType *type, AttributeDef *ad) bit_pos = 0; prevbt = VT_STRUCT; /* make it never match */ prev_bit_size = 0; + size = 0; + for (f = type->ref->next; f; f = f->next) { - int typealign, bit_size; - int size = type_size(&f->type, &typealign); + size = type_size(&f->type, &typealign); if (f->type.t & VT_BITFIELD) bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; else @@ -3358,13 +3362,20 @@ static void struct_layout(CType *type, AttributeDef *ad) int ofs = (c * 8 + bit_pos) % (typealign * 8); int ofs2 = ofs + bit_size + (typealign * 8) - 1; if (bit_size == 0 || - ((typealign != 1 || size == 1) && + (typealign != 1 && (ofs2 / (typealign * 8)) > (size/typealign))) { c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign; bit_pos = 0; } else if (bit_pos + bit_size > size * 8) { c += bit_pos >> 3; bit_pos &= 7; + if (bit_pos + bit_size > size * 8) { + c += 1, bit_pos = 0; + if ((ad->a.packed || f->r) && packwarn) { + tcc_warning("struct layout not compatible with GCC (internal limitation)"); + packwarn = 0; + } + } } offset = c; /* In PCC layout named bit-fields influence the alignment @@ -3407,8 +3418,8 @@ static void struct_layout(CType *type, AttributeDef *ad) if (align > maxalign) maxalign = align; #if 0 - printf("set field %s offset=%d c=%d", - get_tok_str(f->v & ~SYM_FIELD, NULL), offset, c); + 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, @@ -3458,6 +3469,8 @@ static void struct_layout(CType *type, AttributeDef *ad) type->ref->c = (c + (pcc ? (bit_pos + 7) >> 3 : 0) + maxalign - 1) & -maxalign; type->ref->r = maxalign; + if (offset + size > type->ref->c) + tcc_warning("will touch memory past end of the struct (internal limitation)"); } /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ @@ -3615,7 +3628,7 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) } else if (ad1.a.packed || ad->a.packed) { alignoverride = 1; } else if (*tcc_state->pack_stack_ptr) { - if (align > *tcc_state->pack_stack_ptr) + if (align >= *tcc_state->pack_stack_ptr) alignoverride = *tcc_state->pack_stack_ptr; } if (bit_size >= 0) { |
