I have some C code:
#include "stdio.h"
typedef struct num {
unsigned long long x;
} num;
int main(int argc, char **argv) {
struct num anum;
anum.x = 0;
__asm__("movq %%rax, %0\n" : "=m" (anum.x) : "rax"(2));
printf("%llu\n",anum.x);
}
which I'm compiling and running on my (Intel) Mac laptop.
The output from the code seems to be different depending on whether I compile with (GNU) GCC or Clang.
I compile with gnucc -o gnu-test test.c for GCC (I built gnucc from source on my Mac after downloading the source from https://gcc.gnu.org/install/download.html) and clang -o clang-test test.c for Clang (built-in macOS Clang).
On my Mac, with GNU, the result is 2 (which is what I expect). With Clang, the result is 140701838959608.
The Clang result seems wrong to me, but I'm also wondering if, perhaps, my inline assembly isn't quite correct and GCC just happens to not expose my error.
I tried out the same code on Compiler Explorer and the output there is also different for GCC (x86-64 GCC 13.2 gives 2) and Clang (x86-64 Clang 16.0.0 gives 140726522786920).
I tried disassembling the Clang binary with objdump -d:
clang-test: file format mach-o 64-bit x86-64
Disassembly of section __TEXT,__text:
0000000100003f60 <_main>:
100003f60: 55 pushq %rbp
100003f61: 48 89 e5 movq %rsp, %rbp
100003f64: 48 83 ec 20 subq $32, %rsp
100003f68: 89 7d fc movl %edi, -4(%rbp)
100003f6b: 48 89 75 f0 movq %rsi, -16(%rbp)
100003f6f: 48 c7 45 e8 00 00 00 00 movq $0, -24(%rbp)
100003f77: 48 8d 45 e8 leaq -24(%rbp), %rax
100003f7b: b9 02 00 00 00 movl $2, %ecx
100003f80: 48 89 00 movq %rax, (%rax)
100003f83: 48 8b 75 e8 movq -24(%rbp), %rsi
100003f87: 48 8d 3d 16 00 00 00 leaq 22(%rip), %rdi ## 0x100003fa4 <_printf+0x100003fa4>
100003f8e: b0 00 movb $0, %al
100003f90: e8 09 00 00 00 callq 0x100003f9e <_printf+0x100003f9e>
100003f95: 31 c0 xorl %eax, %eax
100003f97: 48 83 c4 20 addq $32, %rsp
100003f9b: 5d popq %rbp
100003f9c: c3 retq
Disassembly of section __TEXT,__stubs:
0000000100003f9e <__stubs>:
100003f9e: ff 25 5c 00 00 00 jmpq *92(%rip) ## 0x100004000 <_printf+0x100004000>
and 100003f80: 48 89 00 movq %rax, (%rax) seems to be the issue? Clang has the correct value in ecx and the correct address to write to in rax, but it does movq %rax, (%rax) instead of movq %rcx, (%rax)?
Clang is generating correct code, but you specified the incorrect constraint on the input operand.
The constraint ("rax") is not interpreted as a register name. Instead, each letter in the constraint specifies an allowed operand type. The first letter here, r, allows using any general register, which makes the choice of rcx valid.
To constrain to the rax register, you need to use the "a" constraint. See the x86 section in the machine constraints page.
__asm__("movq %%rax, %0\n" : "=m" (anum.x) : "a"(2));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With