繁体   English   中英

将AT&T内联汇编程序用于GCC

[英]Using AT&T inline assembler for GCC

我正在编写一个简单但有点具体的程序:

目的:根据阶乘计算数字
要求:所有计算都必须在gcc内联asm上完成(at&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 )可以正常工作。 为什么我的“ AT&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

您的输入和输出方式错误。

所以,从改变开始

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

至:

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

然后,我怀疑您将要告诉编译器有关Clobbers(您正在使用的不是输入或输出的寄存器):

因此添加:

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

在以上两行之后。

我个人将做出其他一些更改:

  1. 使用本地标签( 1:2:等),这样可以复制代码而无需“重复标签”。
  2. 使用%1代替%%ebx这样,您就不会使用额外的寄存器。
  3. %0直接移动到%%ecx 要装载1%%eax两个指令后,所以有它得到了在做什么样的目的%%eax

[现在,我写的太多了,其他人先回答了...]

编辑:而且,正如安东指出,需要$1加载常数1, 1是指从地址1,读不很好地工作,而且最有可能是你的问题的原因

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

我似乎还记得,如果您的意思是字面常量而不是内存引用mov 1,%eax那么mov 1,%eax应该是mov $1,%eax

@MatsPetersson的答案对于内联程序集与编译器(填充/输入/输出寄存器)的交互非常有用。 我一直在关注您得到SIGSEGV的原因,并且读取地址1确实可以回答问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM