top | item 16227182

(no title)

tiehuis | 8 years ago

  #include <stdint.h>
  #include <string.h>
	
  typedef struct {
      int32_t a;
      int32_t b;
  } Foo;
	
  int main(void)
  {
      uint8_t array[1024];
      memset(array, 1, sizeof(array));
	
      Foo *foo = (Foo*)(&array[0]);
      foo->a += 1;
  }

Using clang 3.8.0-2. Compiling examples with `clang -S llvm-ir`.

It appears that the array is aligned with the minimum ABI requirement 16 by default? May be a note of this in the standard, can't recall of the top of my head.

  %array = alloca [1024 x i8], align 16
  ...
  %6 = load i32, i32* %5, align 4
  ...
  store i32 %7, i32* %5, align 4


We can also explicitly specify the alignment required in C11.

  #include <stdalign.h>
  #include <stdint.h>
  #include <string.h>

  typedef struct {
      int32_t a;
      int32_t b;
  } Foo;

  int main(void)
  {
      uint8_t alignas(alignof(Foo)) array[1024];
      memset(array, 1, sizeof(array));

      Foo *foo = (Foo*)(&array[0]);
      foo->a += 1;
  }
Results in the following IR.

  %array = alloca [1024 x i8], align 4
  ...
  %6 = load i32, i32* %5, align 4
  ...
  store i32 %7, i32* %5, align 4

discuss

order

bjourne|8 years ago

On 64bit Linux, stack frames are always aligned at 16 byte boundaries. The first 8 bytes of the frame contains the return address then there are 8 bytes of padding and then comes the stack allocations.

I think the example is poorly constructed, because it is inconceivable that the address to the start of an array would not be aligned sizeof(int*) bytes.

dbaupp|8 years ago

The example is illustrative enough: all the array needs to be misaligned in practice is a small value on the stack near it, e.g. if the Rust code has `let x: u8 = 1;` inserted after the array (or, I imagine, `uint8_t x = 1;` in the C, etc.), then the array's address is odd.

viperscape|8 years ago

Also curious, would one ever do this in C? I understand the need in Rust and Zig, but in C is this usual?