[Bug inline-asm/64119] asm triggers local register variable data corruption
adam at consulting dot net.nz
gcc-bugzilla@gcc.gnu.org
Sun Nov 30 08:55:00 GMT 2014
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?
More information about the Gcc-bugs
mailing list