Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are stack variables aligned by the GCC __attribute__((aligned(x)))?

i have the following code:

#include <stdio.h>  int main(void) {         float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0};         printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); } 

And i have the following output:

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

Why the address of a[0] is not a multiple of 0x1000?

What exactly __attribute__((aligned(x))) does? I misunderstood this explanation?

I'm using gcc 4.1.2.

like image 261
cojocar Avatar asked May 08 '09 19:05

cojocar


People also ask

How is the stack aligned?

IIRC, stack alignment is when variables are placed on the stack "aligned" to a particular number of bytes. So if you are using a 16 bit stack alignment, each variable on the stack is going to start from a byte that is a multiple of 2 bytes from the current stack pointer within a function.

What does attribute aligned do?

The aligned attribute only increases the alignment for a struct or struct member. For a variable that is not in a structure, the minimum alignment is the natural alignment of the variable type. To set the alignment in a structure to any value greater than 0, use the packed variable attribute.


2 Answers

I believe the problem is that your array is on the stack, and that your compiler is too old to support over-aligned stack variables. GCC 4.6 and later fixed that bug.

C11/C++11 alignas(64) float a[4]; Just Works for any power of 2 alignment.
So does the GNU C __attribute__((aligned(x))) as you were using it.

(In C11, #include <stdalign.h> for the #define alignas _Alignas: cppref).


But in your case of a very large alignment, to a 4k page boundary, you may not want it on the stack.

Because the stack pointer could be anything when the function starts, there is no way to align the array without allocating a lot more than you need and adjusting it. (Compilers will and rsp, -4096 or equivalent and not use any of the 0 to 4088 bytes that allocated; branching on whether that space is large enough or not would be possible but isn't done because huge alignments much larger than the size of the array or other locals are not the normal case.)

If you move the array out of the function and into a global variable, it should work. The other thing you could do is keep it as a local variable (which is a very good thing), but make it static. This will prevent it from being stored on the stack. Beware that both of these ways are not thread-safe or recursion-safe, since there will be only one copy of the array.

With this code:

#include <stdio.h>  float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0};  int main(void) {         printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); } 

I get this:

0x804c000 0x804c004 0x804c008 0x804c00c 

which is what is expected. With your original code, I just get random values like you did.

like image 175
Zifre Avatar answered Sep 26 '22 21:09

Zifre


There was a bug in gcc that caused attribute aligned to not work with stack variables. It appears to be fixed with the patch linked below. The link below also contains quite a bit of discussion for the problem as well.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660

I have tried your code above with two different versions of gcc: 4.1.2 from a RedHat 5.7 box, and it failed similarly to your problem (the local arrays wre in no way aligned on 0x1000 byte boundaies). I then tried your code with gcc 4.4.6 on RedHat 6.3, and it worked flawlessly (the local arrays were aligned). The Myth TV folks had a similar problem (that the gcc patch above seemed to fix):

http://code.mythtv.org/trac/ticket/6535

Anyway, it looks like you found a bug in gcc, that appears to be fixed in later versions.

like image 29
rts1 Avatar answered Sep 23 '22 21:09

rts1