gcc中的扩展asm:‘;asm&x2019;操作数具有不可能的约束
这个函数“strcpy”的目的是将src的内容复制到dest,结果很好:显示两行“Hello\u src”gcc中的扩展asm:‘;asm&x2019;操作数具有不可能的约束,c,gcc,assembly,C,Gcc,Assembly,这个函数“strcpy”的目的是将src的内容复制到dest,结果很好:显示两行“Hello\u src” #包括 静态内联字符*strcpy(字符*dest,常量字符*src) { int d0、d1、d2; __asm\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu “stosb\n\t” testb%%al,%%al\n\t “jne 1b” :“=&S”(d0)、“=&D”(d1)、“
#包括
静态内联字符*strcpy(字符*dest,常量字符*src)
{
int d0、d1、d2;
__asm\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
“stosb\n\t”
testb%%al,%%al\n\t
“jne 1b”
:“=&S”(d0)、“=&D”(d1)、“=&a”(d2)
:“0”(src),“1”(目的地)
:“记忆”);
返回目的地;
}
内部主(空){
char src_main[]=“Hello_src”;
char dest_main[]=“你好”;
strcpy(目的地总管、src总管);
puts(src_干管);
put(dest_main);
返回0;
}
:“0”(src)、“1”(dest)
更改为:“S”(src)、“D”(dest)
,出现错误:“asm”操作数具有不可能的约束。我就是不明白。我认为这里的“0”/“1”指定了与第0/1个输出变量相同的约束。第0次输出的约束是=&S
,第1次输出的约束是=&D
。如果我更改0-->S,1-->D,则不会有任何错误。怎么了
earlyclobber
&
表示在使用输入之前写入特定输出。因此,编译器不能将任何输入分配到同一寄存器。显然,使用0
/1
样式会覆盖该行为
当然,打击者列表也有重要用途。编译器不会解析您的汇编代码。它需要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
会发生什么:返回值将被覆盖。该:“=&S”(d0)、“=&D”(d1)、“=&a”(d2)
行无效,删除它后,您可以更改“0”和“1”那么,这是否意味着编译器将尝试将每个被破坏的寄存器恢复到其原始值,从而确保内联汇编代码不会影响任何寄存器?如果是这样,我只是尝试了另一行:asm(“addl%%ebx,%%eax”:::%eax,%ebx”)代码>,但我发现编译器没有做任何事情来恢复“%eax”或“%ebx”的值。它只恢复它需要的值的寄存器。它可能只是改变代码生成,从而避免使用被破坏的寄存器。谢谢。我得到了它。但我还是有点困惑。对于&
和0/1
操作数,我认为它们完全相互冲突&
告诉输出变量不要使用与输入变量相同的寄存器,但是0/1
告诉输入变量使用与输出变量相同的寄存器。怎么解释呢?
call foo
movl %eax, %edx
nop
movl %edx, %eax