History

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.

grischka committed 9 years ago

Commit d2427061 parent 3f5fd303 files · +21 −6Browse files

Unified · Split

3 files
  1. libtcc.c +1 −0
  2. tcc.h +1 −0
  3. tccgen.c +19 −6
libtcc.c+1−0
@@ -1578,6 +1578,7 @@ static const FlagDef options_W[] = { · 1577 unmodified lines
15781578 { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
15791579 { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
15801580 { offsetof(TCCState, warn_error), 0, "error" },
1581+ { offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" },
15811582 { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
15821583 "implicit-function-declaration" },
15831584 { 0, 0, NULL }
tcc.h+1−0
@@ -660,6 +660,7 @@ struct TCCState { · 659 unmodified lines
660660 int warn_error;
661661 int warn_none;
662662 int warn_implicit_function_declaration;
663+ int warn_gcc_compat;
663664
664665 /* compile with debug symbol (and use them if error during execution) */
665666 int do_debug;
tccgen.c+19−6
@@ -3285,6 +3285,9 @@ static void struct_layout(CType *type, AttributeDef *ad) · 3284 unmodified lines
32853285 {
32863286 int align, maxalign, offset, c, bit_pos, bt, prevbt, prev_bit_size;
32873287 int pcc = !tcc_state->ms_bitfields;
3288+ int packwarn = tcc_state->warn_gcc_compat;
3289+ int typealign, bit_size, size;
3290+
32883291 Sym *f;
32893292 if (ad->a.aligned)
32903293 maxalign = 1 << (ad->a.aligned - 1);
@@ -3295,9 +3298,10 @@ static void struct_layout(CType *type, AttributeDef *ad) · 4 unmodified lines
32953298 bit_pos = 0;
32963299 prevbt = VT_STRUCT; /* make it never match */
32973300 prev_bit_size = 0;
3301+ size = 0;
3302+
32983303 for (f = type->ref->next; f; f = f->next) {
3299− int typealign, bit_size;
3300− int size = type_size(&f->type, &typealign);
3304+ size = type_size(&f->type, &typealign);
33013305 if (f->type.t & VT_BITFIELD)
33023306 bit_size = (f->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
33033307 else
@@ -3358,13 +3362,20 @@ static void struct_layout(CType *type, AttributeDef *ad) · 54 unmodified lines
33583362 int ofs = (c * 8 + bit_pos) % (typealign * 8);
33593363 int ofs2 = ofs + bit_size + (typealign * 8) - 1;
33603364 if (bit_size == 0 ||
3361− ((typealign != 1 || size == 1) &&
3365+ (typealign != 1 &&
33623366 (ofs2 / (typealign * 8)) > (size/typealign))) {
33633367 c = (c + ((bit_pos + 7) >> 3) + typealign - 1) & -typealign;
33643368 bit_pos = 0;
33653369 } else if (bit_pos + bit_size > size * 8) {
33663370 c += bit_pos >> 3;
33673371 bit_pos &= 7;
3372+ if (bit_pos + bit_size > size * 8) {
3373+ c += 1, bit_pos = 0;
3374+ if ((ad->a.packed || f->r) && packwarn) {
3375+ tcc_warning("struct layout not compatible with GCC (internal limitation)");
3376+ packwarn = 0;
3377+ }
3378+ }
33683379 }
33693380 offset = c;
33703381 /* In PCC layout named bit-fields influence the alignment
@@ -3407,8 +3418,8 @@ static void struct_layout(CType *type, AttributeDef *ad) · 36 unmodified lines
34073418 if (align > maxalign)
34083419 maxalign = align;
34093420 #if 0
3410− printf("set field %s offset=%d c=%d",
3411− get_tok_str(f->v & ~SYM_FIELD, NULL), offset, c);
3421+ printf("set field %s offset=%d",
3422+ get_tok_str(f->v & ~SYM_FIELD, NULL), offset);
34123423 if (f->type.t & VT_BITFIELD) {
34133424 printf(" pos=%d size=%d",
34143425 (f->type.t >> VT_STRUCT_SHIFT) & 0x3f,
@@ -3458,6 +3469,8 @@ static void struct_layout(CType *type, AttributeDef *ad) · 43 unmodified lines
34583469 type->ref->c = (c + (pcc ? (bit_pos + 7) >> 3 : 0)
34593470 + maxalign - 1) & -maxalign;
34603471 type->ref->r = maxalign;
3472+ if (offset + size > type->ref->c)
3473+ tcc_warning("will touch memory past end of the struct (internal limitation)");
34613474 }
34623475
34633476 /* 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) · 151 unmodified lines
36153628 } else if (ad1.a.packed || ad->a.packed) {
36163629 alignoverride = 1;
36173630 } else if (*tcc_state->pack_stack_ptr) {
3618− if (align > *tcc_state->pack_stack_ptr)
3631+ if (align >= *tcc_state->pack_stack_ptr)
36193632 alignoverride = *tcc_state->pack_stack_ptr;
36203633 }
36213634 if (bit_size >= 0) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t