此功能" 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;
}
我尝试将行: "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,那么不应该有任何错误。它的问题是什么?
&#34;是否会破坏寄存器&#34;或早期的操作数(&amp;)有用吗?我试图删除&#34;&amp;&#34;或&#34;记忆&#34;,任何一种情况的结果都与原始情况相同:输出两行&#34; Hello_src&#34;字符串。那么我为什么要使用&#34;破坏&#34;东西?
答案 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
会发生什么:返回值将被覆盖。