使用 AT&T 内联汇编器 for GCC

Using AT&T inline assembler for GCC

本文关键字:汇编器 for GCC AT 使用      更新时间:2023-10-16

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

目的:根据它的阶乘
计算数字 要求:所有计算必须在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_startn"
                "cycle:n"
                "inc %%ebxn"
                "mul %%ebxn"
                "cycle_start:n"
                "cmp %%ecx, %%eaxn"
                "jnz cyclen"
                "mov %%ebx, %1 n":
                "=r" (n):
                 "r" (f)
       );
       std::cout << f;
       return 0;
}

此代码会导致 SIGSEV。

英特尔 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中有什么目的?

【现在,我写的太多了,别人先回答了...

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

希望不需要只使用 gcc 内联 asm 来弄清楚。你可以用nasm翻译你的AT&T示例,然后用objdump反汇编,看看什么是正确的语法。

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

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