在gcc中扩展asm:'asm'操作数有不可能的约束

时间:2014-10-04 08:57:45

标签: c gcc assembly

此功能" strcpy"旨在将 src 的内容复制到 dest ,并且效果很好:显示两行" Hello_src"。

#include <stdio.h>

static inline char * strcpy(char * dest,const char *src)
{
    int d0, d1, d2;
    __asm__ __volatile__("1:\tlodsb\n\t"
                         "stosb\n\t"
                         "testb %%al,%%al\n\t"
                         "jne 1b"
                         : "=&S" (d0), "=&D" (d1), "=&a" (d2)
                         : "0"(src),"1"(dest)
                         : "memory");
    return dest;
}

int main(void) {
    char src_main[] = "Hello_src";
    char dest_main[] = "Hello_des";
    strcpy(dest_main, src_main);
    puts(src_main);
    puts(dest_main);
    return 0;
}
  1. 我尝试将行: "0"(src),"1"(dest)更改为: "S"(src),"D"(dest),错误发生在:‘asm’ operand has impossible constraints。我只是无法理解。我认为&#34; 0&#34; /&#34; 1&#34;这里指定了与第0个/第1个输出变量相同的约束。第0个输出的约束是=&S,第1个输出的约束是=&D。如果我改变0 - &gt; S,1 - &gt; D,那么不应该有任何错误。它的问题是什么?

  2. &#34;是否会破坏寄存器&#34;或早期的操作数(&amp;)有用吗?我试图删除&#34;&amp;&#34;或&#34;记忆&#34;,任何一种情况的结果都与原始情况相同:输出两行&#34; Hello_src&#34;字符串。那么我为什么要使用&#34;破坏&#34;东西?

1 个答案:

答案 0 :(得分:1)

earlyclobber &表示在输入消耗之前写入特定输出。因此,编译器可能不会将任何输入分配给同一寄存器。显然使用0 / 1样式会覆盖该行为。

当然,clobber列表也有重要用途。编译器不会解析汇编代码。它需要clobber列表来确定代码将修改哪些寄存器。你最好不要撒谎,否则微妙的错误可能会蔓延。如果你想看到它的影响,试着欺骗编译器在你的asm块周围使用一个寄存器:

extern int foo();
int bar()
{
    int x = foo();
    asm("nop" ::: "eax");
    return x;
}

生成的汇编代码的相关部分:

call    foo
movl    %eax, %edx
nop
movl    %edx, %eax

请注意编译器必须如何将foo的返回值保存到edx,因为它认为eax将被修改。通常情况下,它会留在eax,因为之后会需要它。在这里,您可以想象如果您的asm代码在不告诉编译器的情况下修改eax会发生什么:返回值将被覆盖。