为什么发出空asm命令会交换变量
Why does issuing empty asm commands swap variables?
所以我在处理内联汇编,并使用GCC 9编译它。结果是,两个变量a和b被交换,而实际上没有发出任何直接命令。
#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);
}
有人能解释一下这里发生了什么吗?
变量分配的基本随机机会。(或者实际上是GCC内部机制的首选(。
您只使用了输出"=r"
asm操作数,但您的asm模板实际上并没有写入该寄存器,因此您可以获得GCC选择的寄存器中的任何值
这很像使用未初始化变量的C未定义行为。
要查看发生了什么,将asm注释放在asm模板中,将%0
和%1
扩展到asm注释内的模板中。这将对GCC如何进行寄存器分配没有影响:它不在乎模板是隐式还是显式使用它选择的寄存器;这取决于您编写一个有用的模板,并将其与操作数约束相匹配。
使用Godbolt编译器资源管理器上的代码,使用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
(我把注释放在NOP指令上,而不是简单的asm注释,比如asm ("nop #%0 %1": "=r"(c):"r"(a));
,这样编译器资源管理器过滤就不会删除它们。asm模板在将其提供给汇编程序之前是纯文本替换,所以这仍然与GCC使用相同选项编译原始源代码的方式完全相同。(
在前两种情况下,gcc决定为输出和输入选择相同的寄存器,这样这些寄存器的工作方式就像赋值一样
在第三种情况下,c
已经在寄存器中,并且将3
放在任何位置都被优化掉了,因为"=r"(c)
在读取之前覆盖了该值。
也许您在编译时禁用了优化功能?你也可以这样做,然后跟随发生的事情。(GCC可能每次都会为输入和输出选择eax
(。我通常不会去看反优化的-O0
asm,因为它充满了存储/重新加载噪音。
相关文章:
- 交换N个变量
- 为什么发出空asm命令会交换变量
- 是否可以通过使用移动/交换 c++11 来延长返回的临时变量的生命周期
- 如果静态变量只为程序的整个部分存储了一个副本,为什么我不能使用静态变量交换 2 个数字?
- swap(int&, int&) 函数不起作用,当交换不使用临时变量时?
- 是否可以在C++中使用宏交换两个变量的出现?
- 尝试使用 {} 和 std::make_pair() 交换两个变量时的行为不同
- 使用C++简洁地交换变量的值
- 无需先声明函数,我可以交换变量的值
- 使用指针交换字符变量
- 比较和交换三个原子变量
- 通过 xor 运算符使用引用或指针交换两个变量的值
- 交换两个数字而不使用临时变量
- 在类之间交换变量的正确方法是什么?
- 使用 if 语句交换循环变量
- 在不使用第三个变量作为中间位置的情况下交换两个变量
- 什么是用于交换2个整数变量的C代码
- 交换变量(C++,处理器级)
- 用异或交换两个变量
- 在cpp程序之间交换变量