【问题标题】:Strange behavior of ADD in asmADD 在 asm 中的奇怪行为
【发布时间】:2018-02-25 05:09:09
【问题描述】:

这段代码的输出:

int i=0;
while(i<5)
    {
    asm volatile
        (
        "addl $1,%0"
        :"=r"(i)
        :
        :"memory"
        );
    printf("%d\n",i);
    }

是这样的:

2
3
3
3
.
.
.

但应该是这样的:

1
2
3
4
5

为什么会这样?我似乎无法理解问题出在哪里。

【问题讨论】:

  • 检查反汇编。尽管编译器可以/会有所不同,但它并没有初始化寄存器,而是每次通过循环都会增加它。当您使用 jlahd 的答案时,您会看到它在循环之前添加了一条将寄存器归零的指令。

标签: c gcc x86 inline-assembly


【解决方案1】:

您将i 指定为仅输出操作数。也就是说,编译器使用寄存器%0 的输出作为变量,但如果i 的当前值没有复制到开头的寄存器。

对于同一个寄存器,也将i 指定为输入:

asm volatile
    (
    "addl $1,%0"
    :"=r"(i)
    :"0"(i)
    :"memory"
    );

【讨论】:

  • 谢谢,但它是您代码第 5 行的错字吗?不应该是 :"r"(i) 吗?
  • 或者更简单地说,"+r"(i) 声明一个读写操作数。您通常只对单独的变量使用单独的匹配约束,即当语义匹配该语法时。
  • 等等,ADD 在这段代码中不接受任何寄存器操作数。这是一个内存操作数。你说的是什么寄存器?如果涉及任何寄存器,不应该被破坏吗?
  • @Tuhnri:不,你只在你修改的那些 不是 输出的东西上声明 clobbers。 (顺便说一句,这个 asm 语句不应该声明为 volatile,也不应该有 "memory" clobber。如果不需要 i 的值,可以让编译器优化它。)顺便说一句,不:"r"(i) 作为输入将使编译器选择与目标不同的寄存器,因此您必须将其写为 lea 1(%1), %0 才能使用这两个操作数。 "0" 是一个匹配约束:选择任何寄存器 %0gcc.gnu.org/onlinedocs/gcc/…
  • @Tuhnri:另外,WTF 你说的是内存操作数吗? r 表示注册。您是否还没有查看您在最近的问题中尝试编写的内联 asm 的编译器的 asm 输出?
猜你喜欢
  • 1970-01-01
  • 2021-10-02
  • 2018-03-03
  • 2017-05-08
  • 1970-01-01
  • 2015-09-22
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多