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

时间:2021-03-09 06:58:07

This function "strcpy" aims to copy the content of src to dest, and it works out just fine: display two lines of "Hello_src".

这个函数“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. I tried to change the line : "0"(src),"1"(dest) to : "S"(src),"D"(dest), the error occurred: ‘asm’ operand has impossible constraints. I just cannot understand. I thought that "0"/"1" here specified the same constraint as the 0th/1th output variable. the constraint of 0th output is =&S, te constraint of 1th output is =&D. If I change 0-->S, 1-->D, there shouldn't be any wrong. What's the matter with it?

    我试着改变线路:“0”(src),“1”(最大)到:“S”(src),“D”(最大),错误发生:“asm”操作,有不可能的约束。我只是不能理解。我认为这里的“0”/“1”指定了与第0 /1输出变量相同的约束。第0个输出的约束是=&S,第1个输出的约束是=&D。如果我改变0 >S 1 >D,应该没有错。这是怎么回事?

  2. Does "clobbered registers" or the earlyclobber operand(&) have any use? I try to remove "&" or "memory", the result of either circumstance is the same as the original one: output two lines of "Hello_src" strings. So why should I use the "clobbered" things?

    “阻塞寄存器”或早期的clobber操作数(&)有什么用吗?我尝试删除“&”或“内存”,任何一种情况的结果都与原始情况相同:输出两行“Hello_src”字符串。那么,我为什么要用那些“垃圾”的东西呢?

1 个解决方案

#1


1  

The earlyclobber & means that the particular output is written before the inputs are consumed. As such, the compiler may not allocate any input to the same register. Apparently using the 0/1 style overrides that behavior.

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

Of course the clobber list also has important use. The compiler does not parse your assembly code. It needs the clobber list to figure out which registers your code will modify. You'd better not lie, or subtle bugs may creep in. If you want to see its effect, try to trick the compiler into using a register around your asm block:

当然,clobber列表也有重要的用途。编译器不会解析汇编代码。它需要clobber列表来确定要修改哪个寄存器的代码。你最好不要撒谎,否则小虫子会爬进来。如果你想看到它的效果,试着欺骗编译器在你的asm块周围使用寄存器:

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

Relevant part of the generated assembly code:

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

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

Notice how the compiler had to save the return value from foo into edx because it believed that eax will be modified. Normally it would just leave it in eax, since that's where it will be needed later. Here you can imagine what would happen if your asm code did modify eax without telling the compiler: the return value would be overwritten.

注意,编译器必须将foo返回值保存到edx中,因为它认为eax将被修改。通常它会把它留在eax中,因为这是以后需要它的地方。在这里,您可以想象,如果asm代码确实修改了eax,而不告诉编译器:返回值将被覆盖。

#1


1  

The earlyclobber & means that the particular output is written before the inputs are consumed. As such, the compiler may not allocate any input to the same register. Apparently using the 0/1 style overrides that behavior.

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

Of course the clobber list also has important use. The compiler does not parse your assembly code. It needs the clobber list to figure out which registers your code will modify. You'd better not lie, or subtle bugs may creep in. If you want to see its effect, try to trick the compiler into using a register around your asm block:

当然,clobber列表也有重要的用途。编译器不会解析汇编代码。它需要clobber列表来确定要修改哪个寄存器的代码。你最好不要撒谎,否则小虫子会爬进来。如果你想看到它的效果,试着欺骗编译器在你的asm块周围使用寄存器:

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

Relevant part of the generated assembly code:

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

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

Notice how the compiler had to save the return value from foo into edx because it believed that eax will be modified. Normally it would just leave it in eax, since that's where it will be needed later. Here you can imagine what would happen if your asm code did modify eax without telling the compiler: the return value would be overwritten.

注意,编译器必须将foo返回值保存到edx中,因为它认为eax将被修改。通常它会把它留在eax中,因为这是以后需要它的地方。在这里,您可以想象,如果asm代码确实修改了eax,而不告诉编译器:返回值将被覆盖。