2013-02-03 80 views
2

我正在写一个简单的,但有点具体方案:使用AT&T的内联汇编程序的GCC

目的:从它计算阶乘
要求:所有的计算必须在GCC内联汇编完成(在&吨语法)

源代码:

#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

+1

我不是内联汇编专家,但你不必告诉编译器你使用的是哪个寄存器它可以保护那些? –

+0

在MSVC我definitly不是。我试图保存用过的寄存器来堆栈并恢复它。结果是一样的 - SIGSEV。并且不要告诉我我不能使用stack =) – quizzer

+0

@quizzer:在保留内联汇编块中的寄存器(或者通知编译器你不保留哪些寄存器)方面,GCC与MSVC有不同的要求。 –

回答

1

希望有没有使用什么,但GCC内联汇编弄明白要求。您可以将您的AT & T示例翻译为nasm,然后使用objdump反汇编,并查看正确的语法。

我似乎记得mov 1,%eax应该是mov $1,%eax如果你是指文字常量而不是内存引用。

@MatsPetersson的回答对于内联程序集与编译器(clobbered/input/output寄存器)的交互非常有用。我专注于你为什么得到SIGSEGV的原因,并阅读地址1确实回答了这个问题。

+0

这工作=)谢谢。 – quizzer

4

你有你的输入和输出错误的方式。

因此,通过改变

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

开始:

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

然后我怀疑你会想告诉则会覆盖编译器(注册您所使用的不是输入或输出):

所以加:

: "eax", "ebx", "ecx" 
上面两行后面的

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

  1. 使用本地标签(1:2:等),这使得代码没有“重复标签”被复制。
  2. 使用%1而不是%%ebx - 这样,您没有使用额外的寄存器。
  3. %0直接转到%%ecx。您在后面两条指令中加载1%%eax,那么在%%eax中需要做什么?

[现在,I'ver写的太多了,而别人已经先回答...]

编辑:而且,正如安东指出,需要$1加载常数1,1手段从地址1读取,这是行不通的,最有可能是你的问题的原因

+0

除了在代码的其他版本中不需要它,它现在吗? –