Gcc can';在类'中找不到寄存器;CREG和#x27;重新加载时';asm';-memcpy内联asm

Gcc can';在类'中找不到寄存器;CREG和#x27;重新加载时';asm';-memcpy内联asm,gcc,assembly,x86,inline-assembly,Gcc,Assembly,X86,Inline Assembly,我正在尝试做一个较早的verion Linux编译,你可以从git://github.com/azru0512/linux-0.12.git. 编译“kernel/blk_drv/ramdisk.c”时,我收到下面的错误消息 ramdisk.c:36:10: error: can't find a register in class 'CREG' while reloading 'asm' ramdisk.c:40:10: error: can't find a register in clas

我正在尝试做一个较早的verion Linux编译,你可以从git://github.com/azru0512/linux-0.12.git. 编译“kernel/blk_drv/ramdisk.c”时,我收到下面的错误消息

ramdisk.c:36:10: error: can't find a register in class 'CREG' while reloading 'asm'
ramdisk.c:40:10: error: can't find a register in class 'CREG' while reloading 'asm'
ramdisk.c:36:10: error: 'asm' operand has impossible constraints
ramdisk.c:40:10: error: 'asm' operand has impossible constraints
在ramdisk.c中是什么

  if (CURRENT-> cmd == WRITE) {
    (void) memcpy(addr,
            CURRENT->buffer,
            len);
  } else if (CURRENT->cmd == READ) {
    (void) memcpy(CURRENT->buffer,
            addr,
            len);
  } else
    panic("unknown ramdisk-command");
而memcpy是

extern inline void * memcpy(void * dest,const void * src, int n)
{
__asm__("cld\n\t"
  "rep\n\t"
  "movsb"
  ::"c" (n),"S" (src),"D" (dest)
  :"cx","si","di");
return dest;
}

我想这是memcpy(include/string.h)内联asm的问题,所以我从中删除了clobber列表,但运气不好。你能帮我找出哪里出了问题吗?谢谢

GCC对此的语法有点变化/演变

现在必须将每个特殊目标寄存器指定为输出操作数:

...("...instructions..."
   : "=c"(n), "=S"(src), "=D"(dest)
然后作为与源操作数相同的寄存器:

   : "0"(n), "1"(src), "2"(dest)
最后,你需要重击“记忆”(我不记得这是否会影响条件代码,如果是这样,你也需要“cc”):

接下来,由于不应移动或删除此指令,您需要使用
volatile
\uuuuuvolatile\uuuuuuu
(我不完全确定为什么在我的测试用例中,如果没有此命令,这些指令会被删除)

最后,尝试重写
memcpy
不再是一个好主意,因为gcc“知道”如何实现该函数。您可以使用
-fno-builtin
覆盖gcc的知识

这将编译(对我来说,在x86-64机器上使用一个有点旧的gcc):


GCC的bugzilla中讨论了这个确切的问题及其原因:

gcc不允许输入和输出寄存器作为缓冲寄存器。 如果您损坏了输入寄存器,请对同一寄存器进行虚拟输出:

unsigned int operation;
unsigned int dummy;
asm ("cpuid" : "=a" (dummy) : "0" ( operation) :);

显示ramdisk.c第36-40行和周围的代码会很有帮助。我删除了clobber列表。不确定“打开优化”是什么意思,但我没有运气尝试了-O[0..3]。如果删除内联前缀,则会出现“memcpy的多个定义”错误。memcpy已在标头中,即include/string.h。对不起,我错了:该定义属于*.c源文件,在标头中只有声明
void*memcpy(void*dest,const void*src,int n)应该再次感谢你的回复,我学到了很多。我发现在include/asm/memroy.h中还有一个定义为宏的memcpy。在注释掉memcpy之后,ramdisk.c错误消失了,甚至没有删除include/string.h中定义的memcpy中的clobber列表。这让我感到困惑,为什么要删除include/asm/memory.h,而不删除include/string.h会使错误消失。编写内联asm的正确解决方案是什么?没有编译器错误是否意味着一切正常?没有编译器错误并不保证一切正常;这只意味着你要着手解决下一个层次的问题。:-)无论如何,如果您要深入研究实现细节,您必须非常具体地了解实现,因为gcc 2.x、3.x和4.x各不相同,并且安装可能会指向包含文件而不是
/usr/include
(例如,您可能从
/usr/local/include
获取标题)。
extern inline void * memcpy(void * dest,const void * src, int n)
{
    __asm__ volatile("cld\n\t"
        "rep\n\tmovsb\n\t"
        : "=c" (n), "=S" (src), "=D" (dest)
        : "0" (n), "1" (src), "2" (dest)
        : "memory", "cc");
    return dest;
}
unsigned int operation;
unsigned int dummy;
asm ("cpuid" : "=a" (dummy) : "0" ( operation) :);