__attribute__((aligned)) always aligns to 16 bytes

Hi all,

While trying to solve a thorny alignment issue on 32-bit ARM Android, it was discovered that Clang always aligns to 16 bytes when using __attribute__((aligned)) without a specified alignment.
The GCC documentation states that for __attribute__((aligned)) on variables:

"Alternatively, you can leave out the alignment factor and just ask the compiler to align a variable or field to the default alignment for the target architecture you are compiling for. The default alignment is sufficient for all scalar types, but may not be enough for all vector types on a target that supports vector operations. The default alignment is fixed for a particular target ABI."

GCC also provides the __BIGGEST_ALIGNMENT__ macro, which is "the largest alignment ever used for any data type on the target machine you are compiling for”.

When compiling on 32-bit ARM with GCC, both result in an 8-byte alignment.
Clang instead aligns __attribute__((aligned)) to 16 bytes, but __attribute__((aligned(__BIGGEST_ALIGNMENT__))) to 8 bytes.
This results in ABI incompatibilities and, at least in one case, in crashes due to SIGBUS.

Note that when used on types, the GCC documentation for __attribute__((aligned)) is different:

"Whenever you leave out the alignment factor in an aligned attribute specification, the compiler automatically sets the alignment for the type to the largest alignment that is ever used for any data type on the target machine you are compiling for.”

This is identical to the wording used for __BIGGEST_ALIGNMENT__.
I am unsure whether GCC has different behavior when __attribute__((aligned)) is used on types vs variables, as the documentation wording indicates, or not. Behavior at least appears to be identical on 32-bit ARM.

In any case, I’d like to confirm whether this is actually a Clang bug and is unintended?

See https://github.com/axboe/fio/issues/356 for discussion on issues encountered with fio
See https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html for GCC variable attributes
See https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html for GCC type attributes

Test case:

#include <stdint.h>
#include <stdio.h>

struct S {
  int8_t s;
} __attribute__((aligned));

struct T {
  int8_t t;
} __attribute__((aligned(__BIGGEST_ALIGNMENT__)));

int main(int argc, char *argv[])
{
  int8_t a __attribute__((aligned));
  int8_t b __attribute__((aligned(__BIGGEST_ALIGNMENT__)));
  printf("a: %zu\n", __alignof__(a));
  printf("b: %zu\n", __alignof__(b));
  printf("struct S: %zu\n", __alignof__(struct S));
  printf("struct T: %zu\n", __alignof__(struct T));
  return 0;
}

GCC:
b: 8
struct S: 8
struct T: 8

Clang:
b: 8
struct S: 16
struct T: 8

Thanks!
Omri Mor

Hi all,

While trying to solve a thorny alignment issue on 32-bit ARM Android, it was discovered that Clang always aligns to 16 bytes when using __attribute__((aligned)) without a specified alignment.
The GCC documentation states that for __attribute__((aligned)) on variables:

"Alternatively, you can leave out the alignment factor and just ask the compiler to align a variable or field to the default alignment for the target architecture you are compiling for. The default alignment is sufficient for all scalar types, but may not be enough for all vector types on a target that supports vector operations. The default alignment is fixed for a particular target ABI."

GCC also provides the __BIGGEST_ALIGNMENT__ macro, which is "the largest alignment ever used for any data type on the target machine you are compiling for”.

When compiling on 32-bit ARM with GCC, both result in an 8-byte alignment.
Clang instead aligns __attribute__((aligned)) to 16 bytes, but __attribute__((aligned(__BIGGEST_ALIGNMENT__))) to 8 bytes.
This results in ABI incompatibilities and, at least in one case, in crashes due to SIGBUS.

Note that when used on types, the GCC documentation for __attribute__((aligned)) is different:

"Whenever you leave out the alignment factor in an aligned attribute specification, the compiler automatically sets the alignment for the type to the largest alignment that is ever used for any data type on the target machine you are compiling for.”

This is identical to the wording used for __BIGGEST_ALIGNMENT__.
I am unsure whether GCC has different behavior when __attribute__((aligned)) is used on types vs variables, as the documentation wording indicates, or not. Behavior at least appears to be identical on 32-bit ARM.

In any case, I’d like to confirm whether this is actually a Clang bug and is unintended?

If Clang is using a different alignment from GCC for default __attribute__((aligned)) on a target, that's a bug in whichever compiler is not the canonical system compiler for that target.

John.