GCC错误信息“Error: unsupported for `mov'”是什么意思?

9

我只是在尝试从一本书中输入一些简单的示例代码,但GCC给了我上面的错误。以下是我的代码:

$ cat -n test.cpp

 1  #define READ_COMMAND    3
 2  
 3  #define MSG_LENGTH  128
 4  
 5  #include <stdlib.h>
 6  #include <stdio.h>
 7  
 8  int main(int argc, char *arg[])
 9  {
10      int syslog_command = READ_COMMAND;
11      int bytes_to_read = MSG_LENGTH;
12      int retval;
13      char buffer[MSG_LENGTH];
14  
15      asm volatile(
16          "movl %1, %%ebx\n\t"
17          "movl %2, %%ecx\n\t"
18          "movl %3, %%edx\n\t"
19          "movl $103, %%eax\n\t"
20          "int $128\n\t"
21          "movl %%eax, %0"
22          :"=r" (retval)
23          :"m"(syslog_command),"r"(buffer),"m"(bytes_to_read)
24          :"%eax","%ebx","%ecx","%edx");
25      if (retval > 0) printf("%s\n", buffer);
26  
27  }
28  
29  

该代码应该调用syslog()系统调用来从内核的printk()环形缓冲区中读取最后128个字节。以下是有关我的操作系统和系统配置的一些信息:

uname -a

Linux 3.2.0-26-generic #41-Ubuntu SMP Thu Jun 14 17:49:24 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

gcc -v

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu

配置参数: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu

此为gcc编译器的配置参数,其中包含了编译器版本、语言支持、安装路径等信息。
Thread model: posix

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 

以下是完整的错误信息:

$ gcc test.cpp

test.cpp: Assembler messages:

test.cpp:25: Error: unsupported for `mov'

这是整个消息吗?它对应哪行代码? - Alexey Frunze
3
请不要在代码中添加行号,这会使得复制粘贴变得更加困难。只需添加一条注释来标注第 25 行即可。注意保持原文意思的前提下,让语言通俗易懂。 - Keith Thompson
我在我的系统上尝试了它(Ubuntu 12.04,gcc版本为4.6和4.7)。当我将其编译为C语言(使用.c而不是.cpp文件扩展名)时,它可以编译和链接而没有错误。但是当我运行它时,会出现奇怪的段错误;我对它应该做什么不够了解,无法理解其中原因。 - Keith Thompson
同样的问题,但是由于手写指令时寄存器大小不匹配而引起:不支持的指令 `mov` - Peter Cordes
2个回答

27

您正在尝试在64位机器上编译32位汇编代码。您列出的内联汇编编译为:

movl -24(%rbp), %ebx
movl %rsi, %ecx       <--- error here
movl -28(%rbp), %edx
movl $103, %eax
int $128
movl %eax, %r12d

你正在尝试将一个64位寄存器存储在一个32位寄存器中,这是不合法的。更重要的是,这也不是64位ABI系统调用协议。

尝试使用-m32编译以强制使用32位ABI。


2

您应该使用"movq"来移动64位的值。

看起来像这样:

int main(void) 
{
  long str_len = 15;
  const char* str = "hello world!\n\r";

asm volatile(
    "movl $4, %%eax\n\t"
    "movl $1, %%ebx\n\t"
    "movq %0, %%rcx\n\t"
    "movq %1, %%rdx\n\t"
    "int      $0x80\n\t"
    :       
    :"r"(str), "r"(str_len)
    :"eax","ebx", "rcx", "rdx"
);
return 0;

}


是的,这样可以编译通过,但请注意,对于 int 0x80,使用64位寄存器是没有意义的;32位系统调用只会查看32位寄存器。 (如果在64位代码中使用32位int 0x80 Linux ABI会发生什么?)。因此,您可以执行 mov %k0, %%ecx 来强制它打印32位寄存器名称,而不是根据C变量选择的任何宽度来扩展 %0 - Peter Cordes
或者更好的方法是,使用“c”(str)约束在第一时间要求ECX / RCX中的指针,这样您就不需要任何mov,只需将asm(“int $ 0x80”: “= a”(retval):...)作为模板,无需清除器即可使用,不强制编译器为输入查找不同的寄存器。 - Peter Cordes
还要注意的是,关键的一点是使用64位目标寄存器,而不仅仅是movq助记符。您可以使用普通的mov并让汇编器推断操作数大小。所以,是的,这确实回答了有关mov大小的问题,但对于系统调用包装器来说,这是最糟糕的方法,而且在64位代码中使用int 0x80而不是syscall基本上是错误的。希望对那些出于其他原因使用mov的人有所帮助。 - Peter Cordes
此外,Linux 仅使用 \n 表示换行,而不是 DOS 的 \r\n,更不会用到 \n\r(在任何地方都没有使用)。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接