public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug inline-asm/64119] New: asm triggers local register variable data corruption
@ 2014-11-30  2:38 adam at consulting dot net.nz
  2014-11-30  3:33 ` [Bug inline-asm/64119] " pinskia at gcc dot gnu.org
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: adam at consulting dot net.nz @ 2014-11-30  2:38 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64119

            Bug ID: 64119
           Summary: asm triggers local register variable data corruption
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: major
          Priority: P3
         Component: inline-asm
          Assignee: unassigned at gcc dot gnu.org
          Reporter: adam at consulting dot net.nz

//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 ("" : "+r" (a), "+r" (b), "+r" (c));
  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;
}

$ gcc-4.9 -O0 gcc-asm-reg-var-data-corruption.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

$ gcc-4.9 -O1 gcc-asm-reg-var-data-corruption.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

$ clang-3.6 -O0 gcc-asm-reg-var-data-corruption.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

$ clang-3.6 -O1 gcc-asm-reg-var-data-corruption.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

I think it's unfortunate that gcc allows library routines to clobber local
register variables (does clang save/restore values between library calls?)
Note: This code restores the variable values after each library call.

The asm statement should be harmless. At input it says: make sure rax, rbx and
rcx hold the values of a, b and c respectively. Since the inline assembly is
empty the asm output trivially satisfies the same constraint.

I upped the severity because I don't consider data corruption "normal" and this
kind of data corruption is difficult to isolate.


^ 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 ` 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

end of thread, other threads:[~2014-12-01  9:06 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
2014-11-30 22:57 ` adam at consulting dot net.nz
2014-12-01  9:06 ` trippels 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).