【问题标题】:GCC Assembly Inline: Function Body with Only Inlined Assembly CodeGCC 汇编内联:只有内联汇编代码的函数体
【发布时间】:2017-07-25 01:55:38
【问题描述】:

我正在尝试在我的 C 项目中重用一些汇编代码。假设我有一系列指令,我想将它们组织成一个函数:

void foo() {
  __asm__ (
   "mov %eax, %ebx"
   "push %eax"
   ...
   );
}

然而,一个障碍是在函数foo的编译后的汇编代码中,除了内联汇编代码之外,编译器还会为这个函数生成一些序言指令,整个汇编程序会变成这样:

foo:
   push %ebp          <---- routine code generated by compilers
   mov  %ebp, %esp    <---- routine code generated by compilers
   mov %eax, %ebx
   push %eax

鉴于我的使用场景,这样的例程代码实际上破坏了内联程序集的原始语义。

所以这是我的问题,有什么方法可以阻止编译器生成那些函数序言和结尾指令,并且只包含内联的汇编代码?

【问题讨论】:

  • 不,你不能那样使用内联汇编。只需在您的 C 项目中使用普通汇编,这样就不会生成额外的指令。
  • 最好在汇编文件中创建函数,单独汇编,然后将汇编对象链接到您的C文件。话虽如此,您可以按照您的要求进行操作。关于以这种方式编写中断处理程序的相关问题有一个couple of answers。您可以对您打算完全用汇编编写的任何 C 函数执行此操作。我强烈推荐单独的程序集文件。
  • @old_timer:用汇编代码(或至少部分函数)编写裸 C 函数有时很有用。但是,我同意,这不是初学者(或不是 RTM 的人)应该使用的任何东西,而且对于所有以这种方式编写的代码来说绝对没有任何意义..
  • 如果您打算在汇编中编写多个函数,这看起来像一个 XY 问题。

标签: c gcc x86 inline-assembly


【解决方案1】:

您提到您使用 gcc 进行编译。 在这种情况下,您可以使用-O2 优化级别。这将导致编译器进行堆栈优化,如果您的内联汇编很简单,它将不会插入序言和结尾。虽然,这可能无法保证在所有情况下,因为优化不断变化。 (我的 gcc 与 -O2 做到了)。

另一种选择是您可以将整个函数(包括foo:)作为

__asm__ (
    "foo:\n"
    "mov ..."
);

使用此选项,您需要知道名称修饰规范(如果有)。如果您希望函数是非静态的,您还必须在函数开始之前添加.globl foo

最后你可以检查函数声明中的 gcc __attribute__ ((naked)) 属性。但正如MichaelPetch 所述,这不适用于 X86 目标。

【讨论】:

  • GCC 中的 __attribute__((naked)) 不适用于 x86 目标。虽然这个问题没有用 x86 标记,但显示的代码是 x86。您应该在当前版本的 GCC 上收到 warning: 'naked' attribute directive ignored 警告
  • @MichaelPetch 谢谢,我把这个点移到了最后,并添加了一个关于它对 X86 不可用的提示。
【解决方案2】:

内联 asm 代码的全部意义在于以合理的方式与 C 编译器的调度程序和寄存器分配器交互,通过为您提供一种方法来指定如何将汇编代码连接到编译器的约束解决机制。这就是为什么在其中包含特定寄存器的内联 asm 代码很少有意义的原因。相反,您想使用约束来分配一些寄存器并让编译器告诉您它们是什么。

如果您真的想编写通过系统 ABI 与程序的其余部分通信的独立 asm 代码,请将该代码写入项目中包含的单独的 .s(或 .S)文件中,而不是尝试使用内联 asm 代码。

【讨论】:

  • 我真的不确定这是一个好答案还是一个坏答案。有些用例可以在没有前置/后置码的情况下使用单一功能。但是当然,像 OP 那样编写一个像这样的整个装配项目似乎是一个非常糟糕的主意。如果你想要 ABI,前导/后导是必要的。
  • @Olaf:然后将单个函数写入单个小 .s 文件并将其链接到结果中。无需将所有内容都放在一个甚至几个源文件中。
  • 您应该注意,如果该函数仅在单个编译单元中使用,这将不必要地混淆全局命名空间并违反局部性原则。这种方法非常有争议,即固执己见。对此没有单一、简单的答案。在没有更多信息的情况下援引一个普遍接受的单一解决方案的印象是不光彩的。 (或者你可能没有注意到我试图区分不同的用例。
猜你喜欢
  • 2012-10-20
  • 2012-06-16
  • 1970-01-01
  • 1970-01-01
  • 2019-05-11
  • 2012-02-12
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多