mirror of
https://github.com/frida/tinycc
synced 2024-12-24 05:56:49 +03:00
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.
This commit is contained in:
parent
3f5fd305af
commit
d242706f3b
1
libtcc.c
1
libtcc.c
@ -1578,6 +1578,7 @@ static const FlagDef options_W[] = {
|
||||
{ offsetof(TCCState, warn_unsupported), 0, "unsupported" },
|
||||
{ offsetof(TCCState, warn_write_strings), 0, "write-strings" },
|
||||
{ offsetof(TCCState, warn_error), 0, "error" },
|
||||
{ offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" },
|
||||
{ offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
|
||||
"implicit-function-declaration" },
|
||||
{ 0, 0, NULL }
|
||||
|
1
tcc.h
1
tcc.h
@ -660,6 +660,7 @@ struct TCCState {
|
||||
int warn_error;
|
||||
int warn_none;
|
||||
int warn_implicit_function_declaration;
|
||||
int warn_gcc_compat;
|
||||
|
||||
/* compile with debug symbol (and use them if error during execution) */
|
||||
int do_debug;
|
||||
|
25
tccgen.c
25
tccgen.c
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user