1

更新:请参阅 Eric Postpischil 的回答,我认为他是对的。

当我学习内联汇编代码时,我在这个页面上找到了它。

static inline char * strcpy(char * dest,const char *src)
{
    int d0, d1, d2;
    __asm__ __volatile__(  "1:\n\t"
                           "lodsb\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;
}

我很困惑为什么需要三个临时变量?我尝试在不使用它们的情况下实现。

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

但是用 gcc 编译时出现错误。

inline.c: In function ‘strcpy’:
inline.c:6:9: error: can't find a register in class ‘SIREG’ while reloading ‘asm’
inline.c:6:9: error: ‘asm’ operand has impossible constraints
4

2 回答 2

2

事情真的很简单。让我们回想一下,该约束S代表esia和寄存器。当您通知编译器这些家伙将被破坏时,您必须明确指出将它们溢出的位置(是临时存储 for ,for ,for )。alDedid0esid1edid2al

接下来在寄存器分配过程中,编译器决定他是否真的需要溢出并寻找可用的寄存器。例如我的编译器(gcc 4.7.2)如下:

movq  %rdi, %rdx
1:
lodsb
stosb
testb %al,%al
jne 1b
movq  %rdx, %rax
ret

您可能会看到,它d1被分配给rdxd0并被d2淘汰为过度。

如果您不向编译器提供该信息,它就无法猜测,因此会输出错误。

于 2013-01-25T09:35:39.090 回答
2

原始代码试图处理lodsbandstosb指令修改寄存器 %ESI、%EDI 和 %AL 的事实。为此,它定义了d0d1和 ,d2以便可以将它们声明为汇编代码的输出。它实际上并不希望这些值作为输出,因此它不会在组装后使用它们。但是,因为它们是输出,编译器知道它们是由汇编代码修改的,所以编译器知道不要在那些它希望通过汇编代码保持不变的寄存器中保留任何值。

应该可以用另一种方式执行此操作,并且您的代码可以更好地表达语义:它说输入是在 %ESI 和 %EDI 中提供的,并且内存、%ESI、%EDI 和 %AL 被更改。原始代码断言 %ESI、%EDI 和 %AL 是输出,这不是真正的意图;它们是不需要的副产品,不是想要的输出。

但是,您的 GCC 版本与我的不同(Apple/clang-418.0.60);我的接受您编写的代码而没有错误。我怀疑您的 GCC 会因为 %ESI 被指定为输入寄存器("S"在第二个冒号之后)和被破坏的东西("esi"在第三个冒号之后)而感到困惑。也许这是 GCC 中的一个缺点,后来被修复了,原始代码正在解决这个缺点。

于 2013-01-25T15:18:43.070 回答