public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data
@ 2023-11-19 1:23 gandalf at winds dot org
2023-11-19 1:48 ` [Bug target/112615] " pinskia at gcc dot gnu.org
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: gandalf at winds dot org @ 2023-11-19 1:23 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112615
Bug ID: 112615
Summary: gcc incorrectly assumes char *x[2]={"str1", "str2"}
has 16-byte minimum alignment and generates SSE
instructions (e.g. movaps) when accessing this data
Product: gcc
Version: 13.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: gandalf at winds dot org
Target Milestone: ---
I ran into the following problem while trying to get Oracle 21c to run on
Gentoo OS under glibc-2.38 and GCC 13.2 on x86-64 with SSE instructions
enabled.
glibc-2.38's time/tzset.c file (see
https://github.com/bminor/glibc/blob/master/time/tzset.c) has the following
non-static declaration on line 31:
char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
GCC wrongly assumes that this variable __tzname has a minimum alignment of 16
bytes instead of 8. GCC thus generates the following assembly instructions for
this portion of __tzset_parse_tz() when compiling with -march=x86-64:
327 /* Get the standard time zone abbreviations. */
328 if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
0x0000000000000a6f <+63>: movups %xmm0,0x0(%rip) # 0xa76
<__tzset_parse_tz+70>
0x0000000000000a76 <+70>: movups %xmm0,0x0(%rip) # 0xa7d
<__tzset_parse_tz+77>
0x0000000000000a7d <+77>: movups %xmm0,0x0(%rip) # 0xa84
<__tzset_parse_tz+84>
0x0000000000000a84 <+84>: movups %xmm0,0x0(%rip) # 0xa8b
<__tzset_parse_tz+91>
0x0000000000000a8b <+91>: call 0x440 <parse_tzname>
0x0000000000000a90 <+96>: test %al,%al
0x0000000000000a92 <+98>: jne 0xac8 <__tzset_parse_tz+152>
0x0000000000000a94 <+100>: movq 0x0(%rip),%xmm0 # 0xa9c
<__tzset_parse_tz+108>
132 __tzname[1] = (char *) tz_rules[1].name;
0x0000000000000a9c <+108>: xor %eax,%eax
0x0000000000000a9e <+110>: xor %edx,%edx
0x0000000000000aa0 <+112>: pinsrq $0x1,0x0(%rip),%xmm0 # 0xaab
<__tzset_parse_tz+123>
129 __daylight = tz_rules[0].offset != tz_rules[1].offset;
0x0000000000000aab <+123>: mov %edx,0x0(%rip) # 0xab1
<__tzset_parse_tz+129>
130 __timezone = -tz_rules[0].offset;
0x0000000000000ab1 <+129>: mov %rax,0x0(%rip) # 0xab8
<__tzset_parse_tz+136>
131 __tzname[0] = (char *) tz_rules[0].name;
132 __tzname[1] = (char *) tz_rules[1].name;
0x0000000000000ab8 <+136>: movaps %xmm0,0x0(%rip) # 0xabf
<__tzset_parse_tz+143>
In the above, line 131 and 132 are combined into a "movaps" instruction that
requires 16-byte alignment to work properly. However, if a C program is
compiled with a variable called __tzname that is not 16-byte aligned (due to
the fact that char* only requires 8-byte alignment), and this is then linked to
glibc (causing the locally defined __tzname to override the one declared in
glibc), and the if(parse_tzname()) check on line 328 fails due to an invalid TZ
environment variable setting (such as is the case when using Oracle 21c on
Gentoo), the movaps instruction above causes a segmentation fault. Here is an
example test.c C program:
#include <stdio.h>
#include <time.h>
/* Specifically align __tzname to a non-16-byte boundary */
__attribute__((aligned(8))) char *__tzname[2]={"GMT", "GMT"};
char *x="xx"; // This is here to take up the first 8 bytes in .data
int main()
{
struct tm tm={};
printf("%ld\n", mktime(&tm));
return 0;
}
$ gcc -O3 -march=x86-64 test.c -o test -Wall -ggdb3
$ nm test | grep __tzname
0000000000404028 D __tzname
$ ./test
-2209057200
$ TZ=xx ./test
Segmentation fault (core dumped)
Removing the __attribute__((aligned(8))) from the test.c program, as follows,
causes the following change:
#include <stdio.h>
#include <time.h>
/* GCC now aligns __tzname to 16 bytes */
char *__tzname[2]={"GMT", "GMT"};
char *x="xx";
int main()
{
struct tm tm={};
printf("%ld\n", mktime(&tm));
return 0;
}
$ gcc -O3 -march=x86-64 test.c -o test -Wall -ggdb3
$ nm test | grep __tzname
0000000000404030 D __tzname
$ ./test
-2209057200
$ TZ=xx ./test
-2209057200
In the examples above, the "x" variable is used to consume 8 bytes in .data, so
that the next available address for "__tzname" is 0x404028.
Assuming a minimum alignment of 16 for __tzname only makes sense when you're
either compiling the whole program or when __tzname is static, but GCC should
not do this when the variable is non-static (as is the case when tzset.o is
compiled inside the glibc source package).
I should clarify that optimizing the variable's address to use 16-byte
alignment can be ideal for data storage vs cache-line boundaries and so this
optimization should likely remain. But the instructions acting on this data
area must assume an 8-byte minimum alignment here, not 16.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug target/112615] gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data
2023-11-19 1:23 [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data gandalf at winds dot org
@ 2023-11-19 1:48 ` pinskia at gcc dot gnu.org
2023-11-19 1:58 ` pinskia at gcc dot gnu.org
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-11-19 1:48 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112615
Andrew Pinski <pinskia at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |RESOLVED
Resolution|--- |INVALID
--- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Well the x86_64 SYSV ABI says:
An array uses the same alignment as its elements, except that a local or
global array variable that requires at least 16 bytes, or a C99 local or
global variable-length array variable, always has alignment of at least 16
bytes.[4]
So I think this is not a bug in GCC or glibc but rather `Oracle 21c`.
Notice how it says global array variable.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug target/112615] gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data
2023-11-19 1:23 [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data gandalf at winds dot org
2023-11-19 1:48 ` [Bug target/112615] " pinskia at gcc dot gnu.org
@ 2023-11-19 1:58 ` pinskia at gcc dot gnu.org
2023-11-19 2:12 ` gandalf at winds dot org
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-11-19 1:58 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112615
--- Comment #2 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
>Assuming a minimum alignment of 16 for __tzname only makes sense when you're either compiling the whole program or when __tzname is static
Not if you follow the ABI which has had this in the ABI for years now (more
than 20).
You can workaround the issue inside glibc by adding the attribute but GCC is
producing correct code according to the ABI.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug target/112615] gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data
2023-11-19 1:23 [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data gandalf at winds dot org
2023-11-19 1:48 ` [Bug target/112615] " pinskia at gcc dot gnu.org
2023-11-19 1:58 ` pinskia at gcc dot gnu.org
@ 2023-11-19 2:12 ` gandalf at winds dot org
2023-11-19 2:15 ` gandalf at winds dot org
2023-11-19 2:17 ` pinskia at gcc dot gnu.org
4 siblings, 0 replies; 6+ messages in thread
From: gandalf at winds dot org @ 2023-11-19 2:12 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112615
gandalf at winds dot org changed:
What |Removed |Added
----------------------------------------------------------------------------
Resolution|INVALID |FIXED
--- Comment #3 from gandalf at winds dot org ---
Thank you for the insight. Sounds like a bug in Oracle's compiler then.
I have just finished adding the aligned(8) attribute to glibc's __tzname on my
system and recompiled glibc. I verified this fixed the problem (no segfault).
Thanks much.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug target/112615] gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data
2023-11-19 1:23 [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data gandalf at winds dot org
` (2 preceding siblings ...)
2023-11-19 2:12 ` gandalf at winds dot org
@ 2023-11-19 2:15 ` gandalf at winds dot org
2023-11-19 2:17 ` pinskia at gcc dot gnu.org
4 siblings, 0 replies; 6+ messages in thread
From: gandalf at winds dot org @ 2023-11-19 2:15 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112615
gandalf at winds dot org changed:
What |Removed |Added
----------------------------------------------------------------------------
Resolution|FIXED |INVALID
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Bug target/112615] gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data
2023-11-19 1:23 [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data gandalf at winds dot org
` (3 preceding siblings ...)
2023-11-19 2:15 ` gandalf at winds dot org
@ 2023-11-19 2:17 ` pinskia at gcc dot gnu.org
4 siblings, 0 replies; 6+ messages in thread
From: pinskia at gcc dot gnu.org @ 2023-11-19 2:17 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112615
--- Comment #4 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
.
Or their sources for Oracle DB ...
I suspect they have an assembly file that contains that variable and didn't
realize the alignment rules.
Note GCC 4.1.2 even sets the alignment to 16 for a simple:
char *x[2]={"str1", "str2"};
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-11-19 2:17 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-19 1:23 [Bug c/112615] New: gcc incorrectly assumes char *x[2]={"str1", "str2"} has 16-byte minimum alignment and generates SSE instructions (e.g. movaps) when accessing this data gandalf at winds dot org
2023-11-19 1:48 ` [Bug target/112615] " pinskia at gcc dot gnu.org
2023-11-19 1:58 ` pinskia at gcc dot gnu.org
2023-11-19 2:12 ` gandalf at winds dot org
2023-11-19 2:15 ` gandalf at winds dot org
2023-11-19 2:17 ` pinskia at gcc dot gnu.org
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).