3 ms·
List of times we've seen the loch ness monster here? Fun! gcc's __attribute__(aligned(N)) Whenever you see it if you assume it doesn't do what you think it do
by harry8 9y ago
List of times we've seen the loch ness monster here? Fun!
gcc's __attribute__(aligned(N))
Whenever you see it if you assume it doesn't do what you think it does from reading the docs that's probably a sound strategy.[1][2]
I'd love it if I'm wrong and there is a way of understanding what it is meant to do and successfully predicting behavior.
[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82914 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82914
[2] https://gcc.gnu.org/ml/gcc/2014-06/msg00308.html https://gcc.gnu.org/ml/gcc/2014-06/msg00308.html
- DSMan195276 9y agoMy understanding (and usage) of `__attribute__((aligned(N)))` has been that it applies differently when used in the declaration of a `struct` type vs. the declaration of a variable (And applies the same whether or not the variable is of type `struct`). Thus my understanding is: When declaring variables, `__attribute__((aligned(N)))` indicates you want the variable in whatever format it was defined in aligned to that value. If it is less then the default alignment, it will be allowed to be aligned to that instead. For `struct`s, this would mean that the `struct` is kept in the exact same format (with the same padding, in particular) as the declaration would require, but the entire entity itself is instead aligned to whatever alignment you give. When declaring a `struct` type, however, the individual members all still have their own alignment constraints, which is where `struct` padding comes in. So when you just apply `__attribute__((aligned(N)))` to a `struct` type declaration, it's not clear how you want to achieve that alignment. If that alignment is a multiple of the required alignment for the `struct` then there is no problem, because you implicitly meet the alignment requirements already. If it is less, however, then it is not clear when you want alignment requirements met and when you do not (IE. Where should the compiler insert the padding bytes in the `struct`? Should it unalign the first member and then correctly align all the rest? Or pack it as though everything is correctly aligned, and then allow the entire thing and all the members to be unaligned?). There is already an attribute to solve this problem, `__attribute__((packed))`. All `packed` does is force the alignment of all the members in a`struct` to be 1, which both tells the compiler no padding bytes are necessary, and also means that `__attribute__((aligned(N)))` always works, because every `N` will always be some multiple of 1. So with that in mind, in my opinion the bug largely on EMACS' side (Assuming I'm reading those messages and code correctly). In my opinion, they shouldn't be using the `aligned` attribute on the variable declaration at all, and instead they should just ensure the `struct thread_state` type itself already has the proper alignment. The fact that they are using `__attribute__((aligned(8)))` seems to indicate to me that somewhere align the line a `struct thread_state` type was defined with the incorrect alignment, and it was fixed by adding the alignment to the variable declaration. But if you just apply the attribute to the declaration of the `struct thread_state` type instead, then everything would be fine, and architectures with a `struct thread_state` with a higher-alignment (like 32, in this example) wouldn't be affected by the alignment requirements of architectures with a lower alignment. That said, there is something I found very interesting in those posts, though I don't believe it is a `gcc` bug. But it is this syntax: struct __attribute__((aligned(N))) s var; I didn't actually know you could even put the attribute in-between the `struct` and the structure name. That said, it does make some sense when you realize what it is doing, even though the syntax is kinda screwy - it is for applying `struct` attributes after-the-fact. So while this does work for `aligned(N)` (which has variable and `struct` variants) it would also probably work for `packed`. This would likely make most sense to use in a `typedef`, which would allow you to declare the 'normal' version of a `struct`, and then `typedef` a `packed` version or `aligned` version as well. I've never really had a need to do that, but it is interesting to see. It does technically fix the problem here, but it is the same as attaching an `aligned` attribute to the `struct` type declaration after-the-fact, and I really do think if possible they should be looking at putting it on the declaration of `struct thread_state` instead. All that said, I wouldn't consider myself an expert, so if you think I'm wrong please let me know. That said I believe it all fits into what the documentation says about this attribute. I hope the above wasn't too confusing, I attempted to make it clear when I was talking about a "variable declaration" vs. a "struct type declaration", but I'm not sure I was always successful.
- ghewgill 9y agoGCC isn't the only one with aligned() bugs: https://bugs.llvm.org/show_bug.cgi?id=23868 https://bugs.llvm.org/show_bug.cgi?id=23868 Over two years and no forward progress! Admittedly, I haven't re-tested this with a newer compiler. But apparently neither has anybody else.
- DSMan195276 9y agoSorry for responding again, but I was really curious about that "inline" struct type attribute format so I figured I would do some tests. It looks like it actually doesn't do anything! And the warnings are definitely wrong in at least one case. To get straight to the point, some code: #include <stdio.h> #include <stddef.h> struct s { char b; int k; }; int main() { printf("offsetof packed k: %zd\n", offsetof(struct __attribute__((packed)) s, k)); printf("offsetof regular k: %zd\n", offsetof(struct s, k)); printf("alignof inline: %zd\n", __alignof__(struct __attribute__((aligned(32))) s)); printf("alignof before: %zd\n", __alignof__(__attribute__((aligned(32))) struct s)); printf("alignof regular: %zd\n", __alignof__(struct s)); return 0; } The outputs of this program (Just the numbers) are 4, 4, 4, 32, 4. If the 'inline' attributes were actually respected, the results would be 2, 4, 32, 32, 4. Meaning, the attributes in test's 1 and 3 are completely ignored but do not produce warnings. Also interesting, test 4 actually produces a warning about the `aligned` attribute being ignored even though it actually respects it (as it should). I think this is a just weird issue edge-case with the `alignof` operator specific to `gcc`, since `alignof` takes a 'type' as input, but it's definitely a bug. If you declare a variable with that type there is no warning. Besides the warnings this doesn't surprise me too much, AFAIK it is not legal to put anything between the `struct` and the structure name in usages of a `struct` type. But from the response gotten over at the `gcc` Bugzilla I would wager the 'inline' versions are in the uncharted waters of "Nobody really knows what that should do anymore, don't do that". Reading the `gcc` bug report again, it seems the last response does actually indicate the error I'm pointing out above, where the attribute is silently ignored, I missed that when I skimmed it the first time. With that said, the fix EMACS implemented was the same as just removing the attribute completely. If the EMACS code really does need that alignment forced for one of its architectures, it should probably take a look at that fix again and apply the `aligned` attribute on the `struct thread_state` for the architecture(s) that need the 8-byte alignment (If they actually exist), and then remove the attribute completely from the variable declaration.