diff --git a/tcc.h b/tcc.h index 7630f4cb..9b65e6d9 100644 --- a/tcc.h +++ b/tcc.h @@ -379,7 +379,7 @@ typedef struct SValue { struct Attribute { unsigned func_call : 3, /* calling convention (0..5), see below */ - aligned : 5, /* alignement (0..16) */ + aligned : 5, /* alignment as log2+1 (0 == unspecified) */ packed : 1, func_export : 1, func_import : 1, diff --git a/tccgen.c b/tccgen.c index 6ea62e2e..75959adf 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3062,6 +3062,24 @@ ST_FUNC void parse_mult_str (CString *astr, const char *msg) cstr_ccat(astr, '\0'); } +/* If I is >= 1 and a power of two, returns log2(i)+1. + If I is 0 returns 0. */ +static int exact_log2p1(int i) +{ + int ret; + if (!i) + return 0; + for (ret = 1; i >= 1 << 8; ret += 8) + i >>= 8; + if (i >= 1 << 4) + ret += 4, i >>= 4; + if (i >= 1 << 2) + ret += 2, i >>= 2; + if (i >= 1 << 1) + ret++; + return ret; +} + /* Parse GNUC __attribute__ extension. Currently, the following extensions are recognized: - aligned(n) : set data/function alignment. @@ -3131,7 +3149,9 @@ static void parse_attribute(AttributeDef *ad) } else { n = MAX_ALIGN; } - ad->a.aligned = n; + ad->a.aligned = exact_log2p1(n); + if (n != 1 << (ad->a.aligned - 1)) + tcc_error("alignment of %d is larger than implemented", n); break; case TOK_PACKED1: case TOK_PACKED2: @@ -3270,7 +3290,7 @@ static void struct_layout(CType *type, AttributeDef *ad) int pcc = !tcc_state->ms_bitfields; Sym *f; if (ad->a.aligned) - maxalign = ad->a.aligned; + maxalign = 1 << (ad->a.aligned - 1); else maxalign = 1; offset = 0; @@ -3293,6 +3313,8 @@ static void struct_layout(CType *type, AttributeDef *ad) align = f->r; } else if (ad->a.packed || f->r == 1) { align = 1; + /* Packed fields or packed records don't let the base type + influence the records type alignment. */ typealign = 1; } else { align = typealign; @@ -3587,8 +3609,9 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) /* Only remember non-default alignment. */ alignoverride = 0; if (ad1.a.aligned) { - if (align < ad1.a.aligned) - alignoverride = ad1.a.aligned; + int speca = 1 << (ad1.a.aligned - 1); + if (align < speca) + alignoverride = speca; } else if (ad1.a.packed || ad->a.packed) { alignoverride = 1; } else if (*tcc_state->pack_stack_ptr) { @@ -6594,8 +6617,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, * pointed_size(&flexible_array->type); /* take into account specified alignment if bigger */ if (ad->a.aligned) { - if (ad->a.aligned > align) - align = ad->a.aligned; + int speca = 1 << (ad->a.aligned - 1); + if (speca > align) + align = speca; } else if (ad->a.packed) { align = 1; } diff --git a/tests/tcctest.c b/tests/tcctest.c index 9fcd7a49..68f8db64 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1048,6 +1048,11 @@ int pad1; a copy of it). struct aligntest7 altest7[2] __attribute__((aligned(16)));*/ +struct aligntest8 +{ + int i; +} __attribute__((aligned(4096))); + struct Large { unsigned long flags; union { @@ -1129,6 +1134,8 @@ void struct_test() sizeof(struct aligntest6), __alignof__(struct aligntest6)); printf("aligntest7 sizeof=%d alignof=%d\n", sizeof(struct aligntest7), __alignof__(struct aligntest7)); + printf("aligntest8 sizeof=%d alignof=%d\n", + sizeof(struct aligntest8), __alignof__(struct aligntest8)); printf("altest5 sizeof=%d alignof=%d\n", sizeof(altest5), __alignof__(altest5)); printf("altest6 sizeof=%d alignof=%d\n",