Hello all,

> > > If one changes anything at all then it only makes sense to change
> > > it so as to be layout compatible with GCC.  A third layout (GCC,
> > > TCC-old, TCC-new) wouldn't help.  Although the rules of GCC are
> > > relatively obscure and complex in corner cases.
> > 
> > Actually I have to correct myself here.  After studying the layout
> > code a bit I see that TCC implements mostly microsoft's bit-field
> > layout.  We don't want to get rid of that capability, so GCCs layout
> > (which is PCC layout for i386 and arm AAPCS, and funky layout for
> > legacy arm) would have to be implemented in addition.
> 
> OK, I'll give it a try during the next week.

Hum, 'next week' is well over, but here is the patch! :)

Please find attached, a patch that modify TCC so that it can pack bit
fields the way GCC does. The mechanism is optional and off by default.
It can be enabled with the -fgcc-packing option.

I added this mechanism because I want to use TCC to compile some code
that manages IPv4 headers [1]. The code uses the 'struct iphdr' of the
GNU libc, and relies on its size doing exactly 20 bytes. TCC does not
compute the structure length the same way GCC does, and the program
fails.

Someone told me that I can add code to mimic the behaviour of GCC. The
attached patch is an attempt to do so. It is probably not very good as
I didn't known TCC's codebase before, but it seems to work. I'm open
for comments on it. I tested my modifications with the attached test
program.

Regards,
Didier

[1] http://rohc-lib.org/
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.
 
+@item -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;
#include <stdint.h>
#include <assert.h>

struct mystruct1
{
	unsigned int mystruct1_foo:4;
	unsigned int mystruct1_bar:4;
	uint8_t mystruct1_other;
	uint16_t mystruct1_other2;
};

struct mystruct2
{
	unsigned int mystruct2_foo:4;
	unsigned int mystruct2_bar:4;
};

struct mystruct3
{
	uint8_t mystruct3_other;
	uint16_t mystruct3_other2;
	unsigned int mystruct3_foo:4;
	unsigned int mystruct3_bar:4;
};

struct mystruct4
{
	unsigned int mystruct4_foo1:7;
	unsigned int mystruct4_foo2:1;
	unsigned int mystruct4_bar1:5;
	unsigned int mystruct4_bar2:3;
	uint8_t mystruct4_other;
	uint16_t mystruct4_other2;
};

struct mystruct5
{
	struct mystruct1 mystruct5_one;
	struct mystruct2 mystruct5_two;
};

struct mystruct6
{
	struct mystruct1 mystruct6_one;
	struct mystruct2 mystruct6_two;
	uint8_t mystruct6_other;
	uint16_t mystruct6_other2;
};

int main(int argc, char *argv[])
{
	struct mystruct1 test;

	assert(sizeof(struct mystruct1) == 4);
	assert(sizeof(struct mystruct2) == 1);
	assert(sizeof(struct mystruct3) == 4);
	assert(sizeof(struct mystruct4) == 5);
	assert(sizeof(struct mystruct5) == (sizeof(struct mystruct1) + sizeof(struct mystruct2)));
	assert(sizeof(struct mystruct6) == (sizeof(struct mystruct1) + sizeof(struct mystruct2) + 3));

	test.mystruct1_other2 = 0xffff;

	return 0;
}

Attachment: signature.asc
Description: PGP signature

_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to