diff --git a/libtcc.c b/libtcc.c index b0a9b1a..721b20b 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1023,6 +1023,7 @@ LIBTCCAPI TCCState *tcc_new(void) #if defined(TCC_TARGET_PE) && 0 s->leading_underscore = 1; #endif + s->gcc_packing = 0; if (s->section_align == 0) s->section_align = ELF_PAGE_SIZE; #ifdef TCC_TARGET_I386 @@ -1414,6 +1415,7 @@ static const FlagDef flag_defs[] = { { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, { offsetof(TCCState, nocommon), FD_INVERT, "common" }, { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, + { offsetof(TCCState, gcc_packing), 0, "gcc-packing" }, }; /* set/reset a flag */ diff --git a/tcc-doc.texi b/tcc-doc.texi index 4d4a029..a74f84f 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -239,6 +239,9 @@ Do not generate common symbols for uninitialized data. @item -fleading-underscore Add a leading underscore at the beginning of each C symbol. address@hidden -fgcc-packing +Pack bit fields the way GCC does. + @end table Warning options: diff --git a/tcc.h b/tcc.h index 8bca9ae..2ee977f 100644 --- a/tcc.h +++ b/tcc.h @@ -567,7 +567,8 @@ struct TCCState { /* C language options */ int char_is_unsigned; int leading_underscore; - + int gcc_packing; + /* warning switches */ int warn_write_strings; int warn_unsupported; diff --git a/tccgen.c b/tccgen.c index 7295267..41db5ba 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2740,6 +2740,7 @@ static void struct_decl(CType *type, int u) prevbt = VT_INT; bit_pos = 0; offset = 0; + int bf_req_size = -1; while (tok != '}') { parse_btype(&btype, &ad); while (1) { @@ -2770,7 +2771,7 @@ static void struct_decl(CType *type, int u) if (ad.aligned) { if (align < ad.aligned) align = ad.aligned; - } else if (ad.packed) { + } else if (ad.packed || tcc_state->gcc_packing == 1) { align = 1; } else if (*tcc_state->pack_stack_ptr) { if (align > *tcc_state->pack_stack_ptr) @@ -2820,11 +2821,32 @@ static void struct_decl(CType *type, int u) /* add new memory data only if starting bit field */ if (lbit_pos == 0) { + /* pack bit-fields the same way GCC does */ + if (tcc_state->gcc_packing == 1 && bf_req_size > 0) { + if (bf_req_size <= 8) + bf_req_size = 8; + else if (bf_req_size <= 16) + bf_req_size = 16; + else if (bf_req_size <= 32) + bf_req_size = 32; + else + tcc_error("bitfield larger than 32 bits"); + c += bf_req_size / 8; + } + bf_req_size = bit_size; + if (a == TOK_STRUCT) { c = (c + align - 1) & -align; offset = c; - if (size > 0) - c += size; + if (size > 0) { + /* pack bit-fields the same way GCC does */ + if (tcc_state->gcc_packing == 1) { + if (bf_req_size == -1) + c += size; + } else { + c += size; + } + } } else { offset = 0; if (size > c) @@ -2832,6 +2854,9 @@ static void struct_decl(CType *type, int u) } if (align > maxalign) maxalign = align; + } else { + /* bit-field continuation */ + bf_req_size += bit_size; } #if 0 printf("add field %s offset=%d", @@ -2863,6 +2888,20 @@ static void struct_decl(CType *type, int u) skip(';'); } skip('}'); + + /* pack bit-fields the same way GCC does */ + if (tcc_state->gcc_packing == 1 && bf_req_size > 0) { + if (bf_req_size <= 8) + bf_req_size = 8; + else if (bf_req_size <= 16) + bf_req_size = 16; + else if (bf_req_size <= 32) + bf_req_size = 32; + else + tcc_error("bitfield larger than 32 bits"); + c += bf_req_size / 8; + } + /* store size and alignment */ s->c = (c + maxalign - 1) & -maxalign; s->r = maxalign;