* [Bug inline-asm/64119] asm triggers local register variable data corruption
2014-11-30 2:38 [Bug inline-asm/64119] New: asm triggers local register variable data corruption adam at consulting dot net.nz
@ 2014-11-30 3:33 ` pinskia at gcc dot gnu.org
2014-11-30 3:34 ` pinskia at gcc dot gnu.org
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: pinskia at gcc dot gnu.org @ 2014-11-30 3:33 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119
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> ---
You are not using local register assembly variables as documented.
From
https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Explicit-Reg-Vars.html#Explicit-Reg-Vars:
Local register variables in specific registers do not reserve the registers,
except at the point where they are used as input or output operands in an asm
statement and the asm statement itself is not deleted. The compiler's data flow
analysis is capable of determining where the specified registers contain live
values, and where they are available for other uses. Stores into local register
variables may be deleted when they appear to be dead according to dataflow
analysis. References to local register variables may be deleted or moved or
simplified.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug inline-asm/64119] asm triggers local register variable data corruption
2014-11-30 2:38 [Bug inline-asm/64119] New: asm triggers local register variable data corruption adam at consulting dot net.nz
2014-11-30 3:33 ` [Bug inline-asm/64119] " pinskia at gcc dot gnu.org
@ 2014-11-30 3:34 ` pinskia at gcc dot gnu.org
2014-11-30 8:55 ` adam at consulting dot net.nz
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: pinskia at gcc dot gnu.org @ 2014-11-30 3:34 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119
--- Comment #2 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
This is the part that matters in this case:
References to local register variables may be deleted or moved or simplified.
In this case they are moved and simplified.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug inline-asm/64119] asm triggers local register variable data corruption
2014-11-30 2:38 [Bug inline-asm/64119] New: asm triggers local register variable data corruption adam at consulting dot net.nz
2014-11-30 3:33 ` [Bug inline-asm/64119] " pinskia at gcc dot gnu.org
2014-11-30 3:34 ` pinskia at gcc dot gnu.org
@ 2014-11-30 8:55 ` adam at consulting dot net.nz
2014-11-30 19:42 ` pinskia at gcc dot gnu.org
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: adam at consulting dot net.nz @ 2014-11-30 8:55 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119
Adam Warner <adam at consulting dot net.nz> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|RESOLVED |UNCONFIRMED
Resolution|INVALID |---
--- Comment #3 from Adam Warner <adam at consulting dot net.nz> ---
Seriously Andrew? Here's an opportunity to reconsider your closing of the bug
report.
//asm triggers local register variable data corruption
#include <stdio.h>
__attribute__((noinline)) void fn(int inputa, int inputb, int inputc) {
register int a asm ("rax");
register int b asm ("rbx");
register int c asm ("rcx");
a = inputa; b = inputb; c = inputc;
printf("The values of a, b and c are %d, %d and %d respectively\n", a, b, c);
a = inputa; b = inputb; c = inputc;
printf("The values of a, b and c are %d, %d and %d respectively\n", a, b, c);
a = inputa; b = inputb; c = inputc;
asm volatile ("mov %0, %0; mov %1, %1; mov %2, %2" : "+r" (a), "+r" (b), "+r"
(c));
printf("The values of a, b and c are %d, %d and %d respectively\n", a, b, c);
a = inputa; b = inputb; c = inputc;
printf("The values of a, b and c are %d, %d and %d respectively\n", a, b, c);
}
int main(void) {
fn(1, 2, 3);
return 0;
}
$ clang-3.6 -O3 gcc-asm-reg-var-data-corruption_b.c && ./a.out
The values of a, b and c are 1, 2 and 3 respectively
The values of a, b and c are 1, 2 and 3 respectively
The values of a, b and c are 1, 2 and 3 respectively
The values of a, b and c are 1, 2 and 3 respectively
$ gcc-4.9 -O3 gcc-asm-reg-var-data-corruption_b.c && ./a.out
The values of a, b and c are 1, 2 and 3 respectively
The values of a, b and c are 1, 2 and 3 respectively
The values of a, b and c are 53, 2 and 39 respectively
The values of a, b and c are 1, 2 and 3 respectively
Do you claim that one may not assign values to explicit register variables?
(which clearly appears to be happening when a, b and c are again set to a =
inputa; b = inputb; c = inputc; as evidenced by the output of the fourth printf
statement)
GCC is ignoring the variable assignments in the presence of a harmless asm
statement.
At this stage I cannot accept your justification for the compiler output. What
is your computational model?
Let's look at the relevant portions of clang's compiler output:
400537: 41 89 d6 mov %edx,%r14d
40053a: 41 89 f7 mov %esi,%r15d
40053d: 89 fd mov %edi,%ebp
... the input variables are saved in ebp, r14d and r15d.
400562: e8 99 fe ff ff callq 400400 <printf@plt>
400567: 89 e8 mov %ebp,%eax
400569: 44 89 fb mov %r15d,%ebx
40056c: 44 89 f1 mov %r14d,%ecx
... eax, ebx and ecx are set to the input values as per the variable
assignments
(this is a requirement of the asm input constraints)
40056f: 48 89 c0 mov %rax,%rax
400572: 48 89 db mov %rbx,%rbx
400575: 48 89 c9 mov %rcx,%rcx
... the harmless inline asm is output
400578: 48 89 c2 mov %rax,%rdx
40057b: bf 54 06 40 00 mov $0x400654,%edi
400580: 31 c0 xor %eax,%eax
400582: 89 d6 mov %edx,%esi
400584: 89 da mov %ebx,%edx
400586: e8 75 fe ff ff callq 400400 <printf@plt>
... and the register variables moved into the ABI registers for the printf.
Let's look at gcc's compiler output around the asm statement:
400534: 41 89 d5 mov %edx,%r13d
400537: 55 push %rbp
400538: 53 push %rbx
400539: 41 89 fc mov %edi,%r12d
40053c: 89 f5 mov %esi,%ebp
... the input variables are saved in ebp, r12d and r13d.
400565: e8 76 fe ff ff callq 4003e0 <printf@plt>
... The code a = inputa; b = inputb; c = inputc; has been completely thrown
away.
eax, ebx and ecx have not been set with the correct values to satisfy the
input
constraints of the inline asm:
40056a: 89 c0 mov %eax,%eax
40056c: 89 db mov %ebx,%ebx
40056e: 89 c9 mov %ecx,%ecx
... eax, ebx and ecx have not been primed with the correct values so copying
incorrect values achieves nothing.
400570: bf 28 06 40 00 mov $0x400628,%edi
400575: 89 da mov %ebx,%edx
400577: 89 c6 mov %eax,%esi
400579: 31 c0 xor %eax,%eax
40057b: e8 60 fe ff ff callq 4003e0 <printf@plt>
... thus garbage is printed.
I've only used features supported by both gcc and clang. clang's output is
sensible and fits my mental model of the C virtual machine. gcc's output is
really surprising and I've had a lot of experience manipulating gcc via inline
asm. Are you sure gcc's output is justified?
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug inline-asm/64119] asm triggers local register variable data corruption
2014-11-30 2:38 [Bug inline-asm/64119] New: asm triggers local register variable data corruption adam at consulting dot net.nz
` (2 preceding siblings ...)
2014-11-30 8:55 ` adam at consulting dot net.nz
@ 2014-11-30 19:42 ` pinskia at gcc dot gnu.org
2014-11-30 22:57 ` adam at consulting dot net.nz
2014-12-01 9:06 ` trippels at gcc dot gnu.org
5 siblings, 0 replies; 7+ messages in thread
From: pinskia at gcc dot gnu.org @ 2014-11-30 19:42 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119
Andrew Pinski <pinskia at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |RESOLVED
Resolution|--- |INVALID
--- Comment #4 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Adam Warner from comment #3)
> Seriously Andrew? Here's an opportunity to reconsider your closing of the
> bug report.
Did you read the documentation I pointed out? Because it is obvious you did
not.
>
> //asm triggers local register variable data corruption
> #include <stdio.h>
>
> __attribute__((noinline)) void fn(int inputa, int inputb, int inputc) {
> register int a asm ("rax");
> register int b asm ("rbx");
> register int c asm ("rcx");
>
> a = inputa; b = inputb; c = inputc;
> printf("The values of a, b and c are %d, %d and %d respectively\n", a, b,
> c);
>
> a = inputa; b = inputb; c = inputc;
> printf("The values of a, b and c are %d, %d and %d respectively\n", a, b,
> c);
>
> a = inputa; b = inputb; c = inputc;
> asm volatile ("mov %0, %0; mov %1, %1; mov %2, %2" : "+r" (a), "+r" (b),
> "+r" (c));
> printf("The values of a, b and c are %d, %d and %d respectively\n", a, b,
> c);
>
> a = inputa; b = inputb; c = inputc;
> printf("The values of a, b and c are %d, %d and %d respectively\n", a, b,
> c);
> }
>
> int main(void) {
> fn(1, 2, 3);
> return 0;
> }
>
> $ clang-3.6 -O3 gcc-asm-reg-var-data-corruption_b.c && ./a.out
> The values of a, b and c are 1, 2 and 3 respectively
> The values of a, b and c are 1, 2 and 3 respectively
> The values of a, b and c are 1, 2 and 3 respectively
> The values of a, b and c are 1, 2 and 3 respectively
>
> $ gcc-4.9 -O3 gcc-asm-reg-var-data-corruption_b.c && ./a.out
> The values of a, b and c are 1, 2 and 3 respectively
> The values of a, b and c are 1, 2 and 3 respectively
> The values of a, b and c are 53, 2 and 39 respectively
> The values of a, b and c are 1, 2 and 3 respectively
What GCC is optimizing it to:
#include <stdio.h>
__attribute__((noinline)) void fn(int inputa, int inputb, int inputc) {
register int a asm ("rax");
register int b asm ("rbx");
register int c asm ("rcx");
a = inputa; b = inputb; c = inputc;
printf("The values of a, b and c are %d, %d and %d respectively\n", a, b, c);
printf("The values of a, b and c are %d, %d and %d respectively\n", inputa,
inputb, inputc);
asm volatile ("mov %0, %0; mov %1, %1; mov %2, %2" : "+r" (a), "+r" (b), "+r"
(c));
printf("The values of a, b and c are %d, %d and %d respectively\n", a, b, c);
printf("The values of a, b and c are %d, %d and %d respectively\n", inputa,
inputb, inputc);
}
Aka it is treating the local register variables as normal variables except for
inline-asm.
>
> Do you claim that one may not assign values to explicit register variables?
> (which clearly appears to be happening when a, b and c are again set to a =
> inputa; b = inputb; c = inputc; as evidenced by the output of the fourth
> printf statement)
No you can assign them, except they got optimized like normal variables in most
cases that means the assignments might be optimized away if there is already an
assignment.
>
> GCC is ignoring the variable assignments in the presence of a harmless asm
> statement.
No it is not see above on how GCC optimizes it and read the documentation again
about what is going on.
>
> At this stage I cannot accept your justification for the compiler output.
> What is your computational model?
It is standard C one.
...
clang output which is not useful this for discussion because this is about the
documentation of GCC and use in GCC
....
>
> I've only used features supported by both gcc and clang. clang's output is
> sensible and fits my mental model of the C virtual machine. gcc's output is
> really surprising and I've had a lot of experience manipulating gcc via
> inline asm. Are you sure gcc's output is justified?
Yes re-read the documentation. I explicitly put it here for you to understand
what GCC is doing.
I will again copy and paste the most important part of the documentation for
you to understand what is going on here:
References to local register variables may be deleted or moved or simplified.
--- CUT ---
They are being moved and simplified to only assigned before the first printf.
If you don't like that then create a new local register variable each time and
GCC won't optimize them away.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug inline-asm/64119] asm triggers local register variable data corruption
2014-11-30 2:38 [Bug inline-asm/64119] New: asm triggers local register variable data corruption adam at consulting dot net.nz
` (3 preceding siblings ...)
2014-11-30 19:42 ` pinskia at gcc dot gnu.org
@ 2014-11-30 22:57 ` adam at consulting dot net.nz
2014-12-01 9:06 ` trippels at gcc dot gnu.org
5 siblings, 0 replies; 7+ messages in thread
From: adam at consulting dot net.nz @ 2014-11-30 22:57 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119
Adam Warner <adam at consulting dot net.nz> changed:
What |Removed |Added
----------------------------------------------------------------------------
Resolution|INVALID |FIXED
--- Comment #5 from Adam Warner <adam at consulting dot net.nz> ---
The documentation is not clear. But your explanation is fantastic. Thank you
Andrew.
It's a big step to fully comprehend that reassignment to a local register
variable in GCC *does not work* to again make the register live for dataflow
analysis. The approach GCC has chosen is one of maximum surprise.
Thank you for describing a workaround: "create a new local register variable
each time and GCC won't optimize them away."
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Bug inline-asm/64119] asm triggers local register variable data corruption
2014-11-30 2:38 [Bug inline-asm/64119] New: asm triggers local register variable data corruption adam at consulting dot net.nz
` (4 preceding siblings ...)
2014-11-30 22:57 ` adam at consulting dot net.nz
@ 2014-12-01 9:06 ` trippels at gcc dot gnu.org
5 siblings, 0 replies; 7+ messages in thread
From: trippels at gcc dot gnu.org @ 2014-12-01 9:06 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119
Markus Trippelsdorf <trippels at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |trippels at gcc dot gnu.org
Resolution|FIXED |INVALID
^ permalink raw reply [flat|nested] 7+ messages in thread