使用AT& T内联汇编程序为GCC

时间:2013-02-03 22:35:04

标签: c++ c assembly x86 inline-assembly

我正在写一个简单但有点特定的程序:

目的:从它的阶乘计算数字
要求:所有计算必须在gcc内联asm上完成(在& t语法中)

源代码:

#include <iostream>

int main()
{
        unsigned n = 0, f = 0;

        std::cin >> n;

        asm
        (
                "mov %0, %%eax \n"
                "mov %%eax, %%ecx \n"
                "mov 1, %%ebx \n"
                "mov 1, %%eax \n"
                "jmp cycle_start\n"
                "cycle:\n"
                "inc %%ebx\n"
                "mul %%ebx\n"
                "cycle_start:\n"
                "cmp %%ecx, %%eax\n"
                "jnz cycle\n"
                "mov %%ebx, %1 \n":

                "=r" (n):
                 "r" (f)

       );

       std::cout << f;

       return 0;
}

此代码导致SIGSEV。

关于intel asm语法(http://pastebin.com/2EqJmGAV)的Identic程序运行正常。为什么我的“AT&amp; T程序”失败了,我该如何解决?

#include <iostream>

int main()
{
   unsigned n = 0, f = 0;

   std::cin >> n;

   __asm
   {
      mov eax, n

      mov ecx, eax
      mov eax, 1
      mov ebx, 1
      jmp cycle_start

      cycle:

      inc ebx
      mul ebx

      cycle_start:

      cmp eax, ecx
      jnz cycle

      mov f, ebx
   };
   std::cout << f;

   return 0;
}

UPD:推送堆栈和恢复使用的寄存器会产生相同的结果:SIGSEV

2 个答案:

答案 0 :(得分:4)

你的输入输出错误。

所以,首先要改变

            "=r" (n):
             "r" (f)

为:

             "=r" (f) :
             "r" (n)

然后我怀疑你想告诉编译器有关clobbers(你使用的寄存器不是输入或输出):

添加:

  : "eax", "ebx", "ecx" 

以上两行之后。

我个人会做出一些其他的改变:

  1. 使用本地标签(1:2:等),这样就可以复制代码而无需“重复标签”。
  2. 使用%1代替%%ebx - 这样,您就不会使用额外的注册。
  3. %0直接移至%%ecx。您稍后将1加载到%%eax两个说明中,那么它在%%eax中的目的是什么?
  4. [现在,我写的太多了,其他人先回答了......]

    编辑:而且,正如Anton指出的那样,你需要$1加载常量1,1意味着从地址1读取,这不能很好地工作,并且很可能是你的问题

答案 1 :(得分:1)

希望没有任何要求只使用gcc inline asm来解决它。您可以使用nasm翻译您的AT&amp; T示例,然后使用objdump反汇编并查看正确的语法。

我似乎记得mov 1,%eax应该是mov $1,%eax,如果你的意思是文字常量而不是内存参考。

@MatsPetersson的答案对于内联汇编与编译器(破坏/输入/输出寄存器)的交互非常有用。我专注于您获得SIGSEGV的原因,并且阅读地址1确实回答了问题。