我没有组装经验,但这是我一直在努力的工作。如果我缺少传递参数和通过汇编中的指针调用函数的任何基本方面,请输入。
比如我想知道如果我应该恢复ecx
,edx
,esi
,edi
。我读到它们是通用寄存器,但是我找不到它们是否需要还原?通话后我应该进行任何形式的清理吗?
这是我现在拥有的代码,它确实有效:
#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)
);
}
最初的问题是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调用很困难。
如果此处的目标是“学习”,请随时尝试。但是我不知道在生产代码中这样做会不会很舒服。即使它看起来可行,我也永远不会有信心我不会错过任何奇怪的案例。除了我通常对完全使用嵌入式asm的担心之外。
我知道,这是很多信息。作为gccasm
命令的介绍,它可能比您想要的要多,但您已经选择了一个具有挑战性的起点。
如果您尚未这样做,请花一些时间在gcc的汇编语言界面中查看所有文档。那里有很多很好的信息以及一些示例,试图解释它们是如何工作的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句