【发布时间】:2014-04-05 20:46:31
【问题描述】:
我正在尝试对我正在开发的微控制器的解释器进行一些改进。为了执行内置函数,我目前有这样的东西(虽然快一点):
function executeBuiltin(functionName, functionArgs) {
if (functionName=="foo") foo(getIntFromArg(functionArgs[0]));
if (functionName=="bar") bar(getIntFromArg(functionArgs[0]),getBoolFromArg(functionArgs[1]),getFloatFromArg(functionArgs[2]));
if (functionName=="baz") baz();
...
}
但它适用于资源非常有限的嵌入式设备 (ARM),我需要大幅缩减代码大小。我想做的是有一个通用函数来调用具有不同参数的其他函数 - 像这样:
function executeBuiltin(functionName, functionArgs) {
functionData = fast_lookup(functionName);
call_with_args(functionData.functionPointer, functionData.functionArgumentTypes, functionArgs);
}
所以我希望能够调用一个标准的 C 函数并将它需要的任何参数传递给它(它们都可以是不同的类型)。为此,我需要一个call_with_args 函数。
我想避免重写每个函数来获取 argc+argv。理想情况下,被调用的每个函数都是完全标准的 C 函数。
有一个discussion about this here - 但自 1993 年写该帖子以来有什么变化吗?特别是当我在 ARM 上运行时,参数位于寄存器中而不是堆栈中。即使它不在标准 C 中,有什么 GCC 特定的可以做的吗?
更新: 似乎尽管行为根据规范是“未定义的”,但由于 C 调用的工作方式,您可以向函数传递比预期更多的参数,并且一切都会好起来的,因此您可以将所有参数解压缩到一个 uint32 数组中,然后只需将每个 uint32 传递给函数。
这使得为调用编写“漂亮”代码变得更加容易,而且看起来运行良好(在 32 位平台上)。唯一的问题似乎是在传递 64 位数字并为 64 位 x86 编译时,因为在这种情况下它似乎做了一些特别奇怪的事情。
【问题讨论】:
-
libffi 可能会有所帮助。如果你必须减少内存占用,它可能太大而无法包含,但源代码应该会给你一些指示。
-
是的!我发现与您的更新相同,使用 vararg 函数指针。事实上,在link I have already referred on arm arch 中,它声明“始终按照基本标准编组可变参数函数”。但在发布之前,我想进一步调查一下。你已经得到它在我面前 - 好! xf86_64 又是另一个野兽,因为它使用(在 linux 上)cdecl 约定——一些操作数(肯定是 FP 值)在寄存器上传递。见这里:en.wikipedia.org/wiki/X86_calling_conventions#cdecl.
-
谢谢!所以这有点像噩梦——如果浮点和整数的处理方式不同,那就特别痛苦。我想我可能必须为 x86(代码大小无关紧要)创建一个基于签名的调用程序,然后我可以在 ARM 上使用更简单的东西。
标签: c function gcc argument-passing variadic-functions