问题
So I was messing around with inline assembly and compiled this using GCC 9. The result was that the two variables a and b were swapped without actually issuing any direct commands.
#include<cstdio>
int main(){
int a(1),b(2),c(3);
asm ("": "=r"(c):"r"(a));
asm ("": "=r"(a):"r"(b));
asm ("": "=r"(b):"r"(c));
printf("%d %d %d", a,b,c);
}
Can somebody explain what is going on here?
回答1:
Basically random chance of variable allocation. (Or actually GCC's internal machinery's first choices).
You used output-only "=r"
asm operands but then your asm template doesn't actually write that register so you get whatever value was sitting in the register GCC picked.
This is a lot like C undefined behaviour for using an uninitialized varible.
To see what happened, put asm comments in the asm template that expand %0
and %1
inside the template inside an asm comment. This will have no impact on how GCC does register allocation: it doesn't care if the template uses the registers it picks implicitly or explicitly; it's up to you to write a useful template and match that to the operand constraints.
With your code on the Godbolt compiler explorer, with gcc9.2 -O3 -fverbose-asm:
.intel_syntax noprefix
.LC0:
.string "%d %d %d"
main:
sub rsp, 8 #,
mov edi, OFFSET FLAT:.LC0 #,
xor eax, eax #
mov ecx, 1 # tmp87,
mov esi, 2 # tmp89,
nop #ecx ecx # c, tmp87
nop #esi esi # a, tmp89
nop #edx ecx # b, c
call printf #
xor eax, eax #
add rsp, 8 #,
ret
(Instead of a bare asm comment, I put the comments on NOP instructions likeasm ("nop #%0 %1": "=r"(c):"r"(a));
so compiler-explorer filtering wouldn't remove them. asm templates are pure text substitution before feeding it to the assembler so again this is still exactly equivalent to how GCC would have compiled your original source with the same options.)
In the first 2 cases, gcc decided to pick the same register for output as for input so those happened to work like assignments.
In the 3rd case, c
was already in a register, and putting a 3
anywhere was optimized away because "=r"(c)
overwrite that value before it was ever read.
Perhaps you were compiling with optimization disabled? You could do that too, and follow what happened. (Probably GCC would pick eax
for both input and output each time). I normally don't bother looking at anti-optimized -O0
asm because its full of store/reload noise.
来源:https://stackoverflow.com/questions/58679320/why-does-issuing-empty-asm-commands-swap-variables