此汇编函数调用安全/完整吗?

用户名

我没有组装经验,但这是我一直在努力的工作。如果我缺少传递参数和通过汇编中的指针调用函数的任何基本方面,请输入。

比如我想知道如果我应该恢复ecxedxesiedi我读到它们是通用寄存器,但是我找不到它们是否需要还原?通话后我应该进行任何形式的清理吗?

这是我现在拥有的代码,它确实有效:

#include "stdio.h"

void foo(int a, int b, int c, int d)
{
  printf("values = %d and %d and %d and %d\r\n", a, b, c, d);
}

int main()
{

  int a=3,b=6,c=9,d=12;
  __asm__(
          "mov %3, %%ecx;"
          "mov %2, %%edx;"
          "mov %1, %%esi;"
          "mov %0, %%edi;"
          "call %4;"
          :
          : "g"(a), "g"(b), "g"(c), "g"(d), "a"(foo)
          );

}
大卫·沃尔弗德(David Wohlferd)

最初的问题是Is this assembly function call safe/complete?答案是:不会。尽管在这个简单的示例中它似乎可以工作(尤其是禁用优化功能),但是您违反的规则最终会导致失败(确实很难跟踪的规则)。

我想解决如何使其安全的(显而易见的)后续问题,但是如果没有OP的实际意图反馈,我将无法做到这一点。

因此,我将尽我们所能尽一切努力,并尝试描述使它变得不安全的事情以及您可以对此做的一些事情。

让我们从简化asm开始:

 __asm__(
          "mov %0, %%edi;"
          :
          : "g"(a)
          );

即使只有这一条语句,该代码也已经是不安全的。为什么?因为我们在不通知编译器的情况下更改了寄存器(edi)的值。

编译器怎么不知道您的要求?毕竟,它就在asm中!答案来自gcc docs中的这一行

GCC不会自行解析汇编程序指令,也不知道它们的含义,甚至不知道它们是否为有效的汇编程序输入。

在这种情况下,您如何让gcc知道发生了什么事?答案在于使用约束条件(冒号后面的内容)来描述asm的影响。

修复此代码的最简单方法可能是这样的:

  __asm__(
          "mov %0, %%edi;"
          :
          : "g"(a)
          : edi
          );

这就将edi添加到了clobber列表中简而言之,这告诉gcc edi的值将被代码更改,并且当asm退出时,gcc不应假定其中会包含任何特定的值。

现在,虽然这是最简单的方法,但不一定是最好的方法。考虑以下代码:

  __asm__(
          ""
          :
          : "D"(a)
          );

这使用机器约束来告诉gcca为您将变量的值放入edi寄存器。这样,gcc会在“方便”的时候为您加载寄存器,也许总是保持a在edi中。

此代码有一个(重要的)警告:通过将参数放在第二个冒号之后,我们将其声明为输入。输入参数必须是只读的(即,退出asm时它们必须具有相同的值)。

在您的情况下,该call语句意味着我们将无法保证不会更改edi,因此这不太可行。有几种方法可以解决这个问题。最简单的方法是将约束向上移动到第一个冒号之后,使其成为输出,并指定"+D"以指示该值是可读写的。但是a,在asm之后,print的内容几乎是不确定的(printf可以将其设置为任何内容)。如果破坏a是不可接受的,那么总会有这样的事情:

int junk;
  __asm__ volatile (
          ""
          : "=D" (junk)
          : "0"(a)
          );

这告诉gcc,启动asm时,应将变量的值a与输出约束#0(即edi)放在同一位置。它还说,在输出时,edi将不再存在a,它将包含变量junk

编辑:由于实际上不会使用“垃圾”变量,因此我们需要添加volatile限定符。没有任何输出参数时,Volatile是隐式的。

该行的另一点:您以分号结尾。这是合法的,并且会按预期工作。但是,如果您想使用-S命令行选项来确切地查看生成了什么代码(并且如果想更好地使用内联汇编,那么您会发现),这会产生难以阅读的代码。我建议使用\n\t而不是分号。

所有这些,我们仍然处于第一线...

显然,其他两个mov语句也是如此。

这使我们进入了call声明。

我和Michael都列举了许多原因来进行内联asm调用很困难。

  • 处理所有可能被函数调用的ABI破坏的寄存器。
  • 处理红色区域。
  • 处理对齐。
  • 内存破坏者。

如果此处的目标是“学习”,请随时尝试。但是我不知道在生产代码中这样做会不会很舒服。即使它看起来可行,我也永远不会有信心我不会错过任何奇怪的案例。除了我通常对完全使用嵌入式asm的担心之外

我知道,这是很多信息。作为gccasm命令的介绍,它可能比您想要的要多,但您已经选择了一个具有挑战性的起点。

如果您尚未这样做,请花一些时间在gcc的汇编语言界面中查看所有文档那里有很多很好的信息以及一些示例,试图解释它们是如何工作的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

此汇编函数调用安全/完整吗?

来自分类Dev

从C调用汇编函数

来自分类Dev

从C调用内联汇编函数

来自分类Dev

从C调用汇编函数

来自分类Dev

从 c 调用的汇编函数被忽略

来自分类Dev

在子类构造函数中调用getClass()总是安全吗?

来自分类Dev

汇编函数调用会导致所有寄存器都被压入堆栈吗?

来自分类Dev

您可以使用取消引用来调用指向汇编中函数的指针吗?

来自分类Dev

在调用Delete函数后,可以安全地在vtkObject上调用成员函数吗?

来自分类Dev

此扩展方法安全吗?

来自分类Dev

汇编x86-调用C函数

来自分类Dev

如何从汇编中调用C函数

来自分类Dev

如何从C代码调用汇编函数?

来自分类Dev

从调用C代码汇编函数在linux

来自分类Dev

汇编函数调用x64 VC ++

来自分类Dev

如何在汇编中正确调用函数

来自分类Dev

汇编x86-调用C函数

来自分类Dev

如何从C代码调用汇编函数?

来自分类Dev

从swift调用在汇编中定义的函数

来自分类Dev

从 c 链接和调用汇编函数

来自分类Dev

SSL对AJAX调用安全吗?

来自分类Dev

从onCreateView调用getActivity()安全吗?

来自分类Dev

在表单外部调用此函数

来自分类Dev

如何正确调用此函数?

来自分类Dev

如何正确调用此函数?

来自分类Dev

了解此x86汇编函数的作用,递归

来自分类Dev

使用基于堆栈的调用约定进行汇编函数调用

来自分类Dev

此函数重载正确吗?

来自分类Dev

gcc与clang,msvc和icc:此函数调用不明确吗?