意外的GCC内联ASM行为(已覆盖Clobbred变量)

意外的GCC内联ASM行为(已覆盖Clobbred变量),gcc,assembly,inline-assembly,i386,Gcc,Assembly,Inline Assembly,I386,在我的计算机上,编译后的可执行文件省略了在循环顶部执行“mov%2,%%ax” 当“添加%1,%%ax”未注释时 有人要重复检查或评论吗 #include <stdio.h> int main() { short unsigned result, low ,high; low = 0; high = 1; __asm__ ( "movl $10, %%ecx \n\t" "loop: mov %2, %%ax

在我的计算机上,编译后的可执行文件省略了在循环顶部执行“mov%2,%%ax”

当“添加%1,%%ax”未注释时

有人要重复检查或评论吗

#include <stdio.h>

int main() {

short unsigned result, low ,high;

    low  = 0;
    high = 1;

    __asm__ (   
        "movl $10, %%ecx \n\t"

        "loop: mov  %2, %%ax \n\t"

//      "add    %1, %%ax \n\t"      // uncomment and result = 10
        "mov    %%ax, %0     \n\t"

        "subl   $1, %%ecx \n\t"                 
        "jnz loop"                              
        : "=r" (result)
        : "r" (low) , "r" (high)
        : "%ecx" ,"%eax" );        

    printf("%d\n", result);  
    return 0;
}
感谢Jester提供了解决方案:

    : "=&r" (result)        // early clober modifier

GCC内联汇编是一种高级编程,有很多缺陷。确保您确实需要它,并且不能用独立的汇编模块或使用Intrinsic的C代码替换它。或者向量支持

如果您坚持内联汇编,您至少应该准备好查看生成的汇编代码,并尝试从中找出任何错误。显然,编译器不会忽略写入asm块的任何内容,它只是替换参数。如果查看生成的代码,您可能会看到如下内容:

    add    %dx, %ax
    mov    %ax, %dx
显然,编译器为参数
0
1
都选择了
dx
。允许这样做,因为默认情况下,它假定在写入任何输出之前使用输入参数。要表明情况并非如此,必须对输出操作数使用,因此它看起来像
“=&r”


PS:即使内联汇编看起来可以工作,它也可能有隐藏的问题,当编译器碰巧做出其他选择时,这些问题会在以后的某一天困扰你。你真的应该避免它。

没有线索,完全猜测:它应该是
$1
而不是
%1
?%1表示低、%2表示高哪个汇编器或汇编器语法?这是我的新版本。这是GCC编译器上的内联ASM,AT&T汇编语法。本质上是对您答案的重复投票。我仍在试图弄清楚
%1
%0
语法在做什么。欢迎使用指向源代码的指针来了解这些内容。感谢您提供的解决方案!我还没有找到如何在minGW上启动汇编程序。我在早期测试中使用内联汇编来了解内部循环的运行速度。我将研究独立ASM模块和其他指针。@User.1如果您正在查找有关gcc内联ASM的文档,我建议直接查找源代码:您关于应避免内联汇编的声明让我感到困惑。当您只想优化汇编中的几个函数,并且希望这些函数内联时,还有什么其他选项?例如,假设您想要使用add和adc进行256位大整数加法。你显然希望这个函数是内联的。@Zboson:我认为他的意思是“当你可以用另一种方式做它时避免”,这一点我是同意的。内联asm在测试条件下很容易出现错误。不过,在本例中,没有其他方法可以让编译器发出
add/adc/adc/adc
。gcc和clang将发出
adc
,如果您编写类似
hiAdd+(low
,但只有在实际执行
cmp
设置CF之后,因为它没有意识到add将以相同的方式设置CF。
    add    %dx, %ax
    mov    %ax, %dx