------- Comment #44 from nickc at redhat dot com 2008-10-07 10:57 ------- Subject: Re: [cygming] Invalid alignment for SSE store to .comm data generated with -O3
sherpya at netfarm dot it wrote: > I mean that with -fno-common alignment works, even with non patched 4.2, my > question is due to the fact that it's not so clear for me what no-common does -fno-common stops uninitialized variables declared in C and C++ programs from being treated in the same way as common variables declared in FORTRAN programs. > and adding -fno-common what are side effects? Essentially there are two side effects: The first is that you will get a link time error if you declare the same uninitialized variable twice in two different source files, without using the 'extern' keyword on one of them. eg: % cat foo.c int a; % cat bar.c int a; int main (void) { return 0; } % gcc foo.c bar.c % gcc -fno-common foo.c bar.c multiple definition of `a' This is often a problem with badly written header files which declare variables without using 'extern'. eg: % cat header.h int a; % cat foo.c #include "header.h" int a; % cat bar.c #include "header.h" int main (void) { return 0; } % gcc -fno-common foo.c bar.c multiple definition of `a' The other side-effect, and the one that is more interesting for our purposes, is that it forces uninitialised variables to be placed into the .bss section. This is important because symbols in the PE/COFF file format do not have an alignment attribute of their own. Instead the alignment is inherited by the containing section, with the maximum alignment of any symbol inside a section being taken as the section's alignment as a whole. Symbols are placed inside the section on suitably aligned boundaries, so that providing that the section itself is placed on an alignment boundary everything will work. eg: % cat foo.c int normal_align; int aligned_16 __attribute__((aligned(16))); % gcc -fno-common -c foo.c % objdump --syms foo.o [ 8](sec 3)(fl 0x00)(ty 0)(scl 2)(nx 0) 0x00000000 _normal_align [ 9](sec 3)(fl 0x00)(ty 0)(scl 2)(nx 0) 0x00000010 _aligned_16 Note how the 'aligned_16' variable starts at an offset of 00000010 from the start of section 3, whereas 'normal_align' starts at an offset of 00000000. Ie there is a gap of 12 bytes from offset 00000004 to 0000000f. % objdump -h foo.o Idx Name Size VMA LMA File off Algn 2 .bss 00000020 00000000 00000000 00000000 2**4 Note that the .bss section has been given an alignment of 2^4. This is because it contains 'aligned_16'. If that variable had not been declared then the .bss section would have been given its default alignment of 2^2. Also note that section numbering differs between the two uses of objdump. Ie "(sec 3)" in the "objdump --syms" output refers to the third declared section which is the section with an index of 2 in the "objdump -h" output. % cat bar.c int a; % gcc -fno-common bar.c foo.o % nm a.exe 00402000 B _a 00402020 B _aligned_16 00402010 B _normal_align So after linking 'aligned_16' still has a 16-bit alignment because of the 2^4 alignment of the .bss section in the foo.o object file. The reason that all of this is important is that when common variables are stored in a PE/COFF object file they are not assigned to any section. Since only sections, not symbols, have an alignment attribute in PE/COFF object files, any alignment requirements of common symbols are lost. This is what has been causing the problems that you have experienced. eg: % cat foo.c int normal_align; int aligned_16 __attribute__((aligned(16))); % gcc -c foo.c % objdump --syms foo.o [ 8](sec 0)(fl 0x00)(ty 0)(scl 2)(nx 0) 0x00000004 _normal_align [ 9](sec 0)(fl 0x00)(ty 0)(scl 2)(nx 0) 0x00000004 _aligned_16 Note how the variables are assigned to "(sec 0)" which does not exist and that there is no field or flag specifying the alignment for either of them. You may ask why common variables are not assigned to the .bss section. The reason is that if there are multiple declarations of the same variable and all but one of which are common, then the non-common declaration takes precedence. eg: % cat foo.c int a; % cat bar.c int a = 1; % gcc foo.c bar.c % nm a.exe 00402000 D _a Ie the 'a' variable has been placed in the .data section and not the .bss section, despite the fact that it was declared uninitialised in foo.c. So common variables are not assigned to a section until the final link takes places. If there are no non-common definitions of a variable to specify where they should be placed then they are assigned to the .bss section, but by then it is too late - the alignment requirements of the symbol have been lost. Cheers Nick -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37216