【问题标题】:What does the GCC error message, "Error: unsupported for `mov'", mean?GCC 错误消息“错误:‘mov’不支持”是什么意思?
【发布时间】:2012-07-07 11:48:50
【问题描述】:

我只是想编译一些我从书中输入的简单示例代码,而 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-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

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'

【问题讨论】:

  • 这是全部信息吗?这是哪一行代码?
  • 请不要发布带有行号的代码;它使复制和粘贴变得更加困难。只需添加一条注释,显示哪一行是 #25。
  • 我在我的系统上尝试过(Ubuntu 12.04,gcc 版本 4.6 和 4.7)。当我将它编译为as C(使用.c,而不是.cpp,文件扩展名)时,它编译和链接没有错误。运行时出现奇怪的段错误;我不太了解它应该做什么来理解这一点。

标签: linux assembly gcc system-calls inline-assembly


【解决方案1】:

您正试图在 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 位寄存器。 (What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?)。因此,您可以使用mov %k0, %%ecx 强制它在扩展 %0 时打印 32 位寄存器名称,而不是根据 C 变量选择的任何宽度。
    • 或者更好的是,首先使用"c"(str)约束来请求ECX/RCX中的指针,所以你不需要任何mov只需 asm("int $0x80" : "=a"(retval) : ... ) 作为不需要破坏者的模板,不强制编译器为输入找到不同的寄存器。
    • 另请注意,关键是使用 64 位目标寄存器,而不仅仅是 movq 助记符。您可以使用普通的mov 并让汇编器推断操作数大小。所以是的,这确实回答了关于mov 大小的问题,但是对于系统调用包装器来说,这是最糟糕的解决方法,并且对于 64 位代码使用 int 0x80 而不是 syscall 基本上是错误的。不过,希望对出于其他原因使用 mov 的人有用。
    • 另外,Linux 只使用\n 换行,而不是DOS \r\n,当然也不是\n\r(无处使用)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多