【问题标题】:can't find a register in class 'CREG' while reloading 'asm' - memcpy inline asm重新加载“asm”时在“CREG”类中找不到寄存器 - memcpy inline asm
【发布时间】:2012-05-13 08:35:57
【问题描述】:

我正在尝试编译早期版本的 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 列表,但没有运气。你能帮我找出问题所在吗?谢谢!

【问题讨论】:

  • 显示 ramdisk.c 第 36-40 行及周边代码会有所帮助
  • 我删除了clobber列表。不确定您的意思是“打开优化”,但我尝试 -O[0..3] 没有运气。如果我删除内联前缀,那么我会收到“'memcpy' 的多重定义”错误。
  • memcpy 已经在标头中,即include/string.h。
  • 对不起,我错了:定义属于 *.c 源文件,在标题中只应保留声明 void * memcpy(void * dest,const void * src, int n);

标签: gcc assembly x86 inline-assembly


【解决方案1】:

GCC 的语法已经改变/进化了一点。

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

...("...instructions..."
   : "=c"(n), "=S"(src), "=D"(dest)

然后另外作为 same 注册为源操作数:

   : "0"(n), "1"(src), "2"(dest)

最后你需要破坏“内存”(如果这会影响条件代码,我不记得了,如果是这样你还需要“cc”):

   : "memory")

接下来,由于不应移动或删除此指令,因此您需要使用volatile__volatile__(我不完全确定原因,但在我的测试用例中,如果没有此指令,则会被删除)。

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

这可以编译(无论如何对我来说,在 x86-64 机器上使用有点旧的 gcc):

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;
}

【讨论】:

  • 感谢大家的回复,我学到了很多。我发现在 include/asm/memroy.h 中有另一个 memcpy 被定义为宏。注释掉 memcpy 后,ramdisk.c 错误消失了,甚至没有删除 include/string.h 中定义的 memcpy 中的 clobber 列表。
  • 这让我很困惑,为什么要删除 include/asm/memory.h 而单独留下 include/string.h 会使错误消失。编写内联汇编的正确解决方案是什么?没有编译器错误是否意味着一切正常?
  • 缺少编译器错误并不能保证一切正常;这只是意味着您可以着手解决下一个问题。 :-) 无论如何,如果您要深入研究实现细节,您将必须非常具体地了解实现,因为 gcc 2.x、3.x 和 4.x 各不相同,安装可能会指向在/usr/include 以外的地方包含文件(例如,您可能从/usr/local/include 获取标题)。
【解决方案2】:

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

Bug 43998 - inline assembler: can't set clobbering for input register

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-19
    • 2011-04-29
    • 1970-01-01
    • 2019-01-31
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2018-09-24
    相关资源
    最近更新 更多