While debugging some i386 code I found some memory alignment differences.

1) The double and long long type differ inside and outside struct.

outside struct (size = 8, align = 8):
double a;
long long b;

inside struct (size = 8 align = 4)
struct {
   double a;
   long long b;
};

This only happens on x86 (and perhaps on !TCC_ARM_EABI which I cannot test).


2) The memory alignment of a struct/array depends on its size.

The memory alignment is 4 for a, 8 for b, 16 for c and 32 for d and e.
int a[1];
int b[2];
int c[4];
int d[8];
int e[16];

You can check this alignment with compiling above code with gcc -S
and check assemby code for .align/.zero/.space depending on
platform (x86/x86_64/arm/arm64/riscv).
As far as I can tell this happens for all data. So also structs
get this alignment depending on size.

See patch that fixes both problems + testcase update.

    Herman

diff --git a/tccgen.c b/tccgen.c
index 6519a46..8cacccd 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -3482,7 +3482,7 @@ done:
 }
 
 /* return type size as known at compile time. Put alignment at 'a' */
-ST_FUNC int type_size(CType *type, int *a)
+static inline int type_size_struct(CType *type, int *a, int is_struct)
 {
     Sym *s;
     int bt;
@@ -3497,7 +3497,7 @@ ST_FUNC int type_size(CType *type, int *a)
         if (type->t & VT_ARRAY) {
             int ts;
             s = type->ref;
-            ts = type_size(&s->type, a);
+            ts = type_size_struct(&s->type, a, is_struct);
             if (s->c < 0)
                 return s->c;
             return ts * s->c;
@@ -3514,7 +3514,7 @@ ST_FUNC int type_size(CType *type, int *a)
     } else if (bt == VT_DOUBLE || bt == VT_LLONG) {
 #if (defined TCC_TARGET_I386 && !defined TCC_TARGET_PE) \
  || (defined TCC_TARGET_ARM && !defined TCC_ARM_EABI)
-        *a = 4;
+        *a = is_struct ? 4 : 8;
 #else
         *a = 8;
 #endif
@@ -3535,6 +3535,11 @@ ST_FUNC int type_size(CType *type, int *a)
     }
 }
 
+ST_FUNC int type_size(CType *type, int *a)
+{
+   return type_size_struct(type, a, 0);
+}
+
 /* push type size as known at runtime time on top of value stack. Put
    alignment at 'a' */
 static void vpush_type_size(CType *type, int *a)
@@ -4220,7 +4225,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
             bit_size = BIT_SIZE(f->type.t);
         else
             bit_size = -1;
-        size = type_size(&f->type, &align);
+        size = type_size_struct(&f->type, &align, 1);
         a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0;
         packed = 0;
 
@@ -8369,6 +8374,15 @@ static void decl_initializer_alloc(CType *type, 
AttributeDef *ad, int r,
         }
 
         if (sec) {
+           /* gcc aligns sections to size */
+           if (sec != cur_text_section) {
+               if (size >= 32)
+                   section_add(sec, 0, 32);
+               else if (size >= 16)
+                   section_add(sec, 0, 16);
+               else if (size >= 8)
+                   section_add(sec, 0, 8);
+           }
            addr = section_add(sec, size, align);
 #ifdef CONFIG_TCC_BCHECK
             /* add padding if bound check */
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 4995941..5992361 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -1057,6 +1057,20 @@ struct aligntest10 {
     unsigned long long start_lba;
 };
 
+struct aligntest11 {
+    long long a[0];
+};
+
+struct aligntest12 {
+    LONG_DOUBLE a;
+};
+
+long long aligntest13[2];
+
+double aligntest14[2];
+
+LONG_DOUBLE aligntest15[2];
+
 void struct_test()
 {
     struct1 *s;
@@ -1109,12 +1123,42 @@ void struct_test()
            sizeof(struct aligntest9), __alignof__(struct aligntest9));
     printf("aligntest10 sizeof=%d alignof=%d\n",
            sizeof(struct aligntest10), __alignof__(struct aligntest10));
+    printf("aligntest11 sizeof=%d alignof=%d\n",
+           sizeof(struct aligntest11), __alignof__(struct aligntest11));
+    printf("aligntest12 sizeof=%d alignof=%d\n",
+           sizeof(struct aligntest12), __alignof__(struct aligntest12));
+    printf("aligntest13 sizeof=%d alignof=%d\n",
+           sizeof(aligntest13), __alignof__(aligntest13));
+    printf("aligntest14 sizeof=%d alignof=%d\n",
+           sizeof(aligntest14), __alignof__(aligntest14));
+    printf("aligntest15 sizeof=%d alignof=%d\n",
+           sizeof(aligntest15), __alignof__(aligntest15));
     printf("altest5 sizeof=%d alignof=%d\n",
            sizeof(altest5), __alignof__(altest5));
     printf("altest6 sizeof=%d alignof=%d\n",
            sizeof(altest6), __alignof__(altest6));
     printf("altest7 sizeof=%d alignof=%d\n",
            sizeof(altest7), __alignof__(altest7));
+    printf("altest7 sizeof=%d alignof=%d\n",
+           sizeof(altest7), __alignof__(altest7));
+    printf("altestt1 sizeof=%d alignof=%d\n",
+           sizeof(char), __alignof__(char));
+    printf("altestt2 sizeof=%d alignof=%d\n",
+           sizeof(short), __alignof__(short));
+    printf("altestt3 sizeof=%d alignof=%d\n",
+           sizeof(int), __alignof__(int));
+    printf("altestt4 sizeof=%d alignof=%d\n",
+           sizeof(long), __alignof__(long));
+    printf("altestt5 sizeof=%d alignof=%d\n",
+           sizeof(long long), __alignof__(long long));
+    printf("altestt6 sizeof=%d alignof=%d\n",
+           sizeof(float), __alignof__(float));
+    printf("altestt7 sizeof=%d alignof=%d\n",
+           sizeof(double), __alignof__(double));
+    printf("altestt8 sizeof=%d alignof=%d\n",
+           sizeof(LONG_DOUBLE), __alignof__(LONG_DOUBLE));
+    printf("altestt9 sizeof=%d alignof=%d\n",
+           sizeof(void *), __alignof__(void *));
            
     /* empty structures (GCC extension) */
     printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
_______________________________________________
Tinycc-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to