This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
First, the question: if I use "#pragma STRUCT_ALIGN( x, 8), is it my responsibility to pad out 'x' to a multiple of 8 bytes?". I'm using the TI C6 compiler and running the code on the DSP in a DM6443.
Here's a minimal example to show what I mean:
struct S1 {
char c;
};
#pragma STRUCT_ALIGN (S1, 8);
struct S1 s1[2];
int after_s1[100];
syslog_info("&(s1[1].c)=%p &(after_s1[0])=%p\n",
&(s1[1].c), &(after_s1[0]));
This prints
&(s1[1].c)=841bce00 &(after_s1[0])=841bce00
i.e. I seem to have two variables at the same memory location. Writing to one changes the other. This is not what I expected.
Looking at 'out.map', I can see:
841bcdf8 _s1
841bce00 _after_s1
which agrees with the printout---i.e. s1[0] is at 841bcdf8 and s1[1] is 8 bytes later, i.e. at 841bce00.
One way to work around this is to pad the S1 struct so that it is the same size as I'm aligning to, e.g.:
struct S1 {
char c;
char pad[7];
};
I'm using the code generation tools 6.1.22, here's my command line, redacted to remove input filenames and local include directories:
/usr/local/src//c6_6.1.22/bin/cl6x --gcc -DTARGET_DSP -i/usr/local/src//c6_6.1.22/include -i/usr/local/src//c6_6.1.22/csl -i/usr/local/src//c6_6.1.22/csl/include -DDAVINCI -DLITTLE_ENDIAN -mv6400+ -pdv -pdr -fs asm_junk -fr asm_junk -O3 -pm -on2 -op2 -ms1 -mi -mw -mh -s --c64p_l1d_workaround=off -z -i/usr/local/src//c6_6.1.22/lib -i/usr/local/src//c6_6.1.22/csl/lib_3x -s -c -heap 0x10000 -stack 0x10000 -m out.map -o dsp_core.out core/linkcore_davinci.cmd -l rts64plus.lib
Matt
Matthias Lang said:if I use "#pragma STRUCT_ALIGN( x, 8), is it my responsibility to pad out 'x' to a multiple of 8 bytes?
No. You've discovered a bug. I've submitted SDSCM00045596 to track this issue. This problem persists to 7.4.1
Note that you can't rely on the compiler allocating those two objects adjacent to each other in memory. Here is a conforming self-testing version:
struct S1 { char c; }; #pragma STRUCT_ALIGN (S1, 8); struct { struct S1 s1[2]; int s2[100]; } X; #include <stdio.h> #include <assert.h> int main() { printf("&X.s1[0]\t%p\n", &X.s1[0]); printf("&X.s1[1]\t%p\n", &X.s1[1]); printf("&X.s2[0]\t%p\n", &X.s2[0]); /* assert that X.s2 does not overlap any part of X.s1 */ if ((unsigned)X.s2 < (unsigned)X.s1) assert((unsigned)&X.s2[99] < (unsigned)&X.s1[0]); else assert((unsigned)&X.s2[0] > (unsigned)&X.s1[1]); return 0; }
I get the same on CGT 6000 7.3.4. Note that sizeof(struct S1) always returns 1. It should return the size of the padded structure.
Update:
STRUCT_ALIGN is not what you want here. Use this instead:
struct S1 { char c; } __attribute__((aligned(8)));
I'll explain this more fully later.
Looking forward to the explanation.
I just re-read the part in SPRU187u about STRUCT_ALIGN, and it sounds exactly the same as GCC's aligned attribute---they both specify the desired minimum alignment for a type. So it'll be interesting to see what the difference is.
I've rejected SDSCM00045596; the pragma is working as designed.
I've submitted SDSCM00045669 as a bug against the documentation.
The documentation is a bit unclear on what STRUCT_ALIGN actually does. Here is what it actually does:
STRUCT_ALIGN may only be applied to a struct or union type declaration. Any top-level object of that type (or a typedef of it) will be aligned as requested. However, the type will not be padded to the alignment (as is usual for a struct), nor does the alignment propagate to derived aggregate types (arrays, parent structs).
In other words, the pragma doesn't really apply to the struct type, it applies to top-level objects declared with that struct type (or a typedef of it).
You want to create a struct type that is properly padded, and which will contribute to its parent struct's align. This is exactly what __attribute___((aligned())) does, and in addition it works on any type or object.
So...STRUCT_ALIGN is used for structure definitions and DATA_ALIGN is used for declared variables. Is this an example usage?
typedef struct st_tag
{
int a;
short b;
} st_typedef;
#pragma STRUCT_ALIGN (st_tag, 128);
struct st_tag my_aligned_struct;
st_typedef my_unaligned_typedef;
st_typedef my_aligned_typedef;
#pragma DATA_ALIGN (my_aligned_typedef, 128);
I think the problem is with arrays of aligned structures. The STRUCT_ALIGN pragma appears to inconsistently affect the offset calculation and allocation. The offset calculation uses a padded side but the allocation uses an unpadded size. The intent of STRUCT_ALIGN is to only align the base address of an array of structures? If so, the offset calculation should use the unpadded size.
Good that the docs will be improved.
The GCC extensions were only added fairly recently (a few years ago), so I'm probably not the only one to be a bit surprised that TI now support them. A 'see also' to the 'aligned' attribute in the STRUCT_ALIGN would have helped me.
Given the difficulty of debugging "compiler puts two objects at overlapping addresses", an error or warning would have been nice too.
Out of curiosity, can you give an example where I wouldn't want to use the 'aligned' attribute but would want to use the STRUCT_ALIGN pragma? Or: is STRUCT_ALIGN just a historical relic?
Norman Wong said:The STRUCT_ALIGN pragma appears to inconsistently affect the offset calculation and allocation.
You are correct, it is inconsistent. I rejected SDSCM00045596 too hastily. Regardless of how STRUCT_ALIGN works, objects should never overlap.
Matthias Lang said:Given the difficulty of debugging "compiler puts two objects at overlapping addresses", an error or warning would have been nice too.
For reasons I won't go into here, it's not feasible to add checks for that sort of thing.
We are now internally discussing whether the behavior of STRUCT_ALIGN should be changed, which would change the sense of what I've said so far, so I need to wait for that to settle down.
As someone who has fallen foul of this, here are my views.
What is the point of STRUCT_ALIGN? It clearly does not do what its name implies and as such is dangerous in its current form. I can see no benefits of the existing (truly bizarre) definition and restrictions of STRUCT_ALIGN; the cynic and one-time professional compiler-writer in me reads the definition as a post hoc rationalisation of an implementor's error or oversight.
I feel that having two vaguely-similar mechanisms to align structures is an unnecessary complication, but they now exist. I believe the simplest and only sensible answer is to make STRUCT_ALIGN do what it says on the tin: align the structure to the given boundary. Clearly this cannot be honoured for objects on the stack as that would imply the stack being aligned on a boundary demanded by the largest alignment requirement in any called function; a warning (or even error) would be appropriate in such circumstances.