LLVM程序集:使用varargs调用函数

时间:2011-08-10 17:54:32

标签: assembly llvm variadic-functions

我想在LLVM程序集中定义一个函数,该函数作为参数:

  • 子功能的标识符
  • a vararg

此函数应该进行一些预处理,找到标识符的正确函数并使用vararg调用它,并返回其结果。

类似的东西:

define ??? @1 (i32 %identifier, ...vararg...)
{
  switch i32 %identifier, label %def, i32 1, label %a
a:
  %1 = tail call @function_for_a, ...vararg...
  ret ??? %1
def:
  ret void
}

似乎不可能。还有办法吗?我认为应该可以使用普通的汇编程序。

这是一个面向对象语言的调度函数。我希望它快。

我想要的是一种方式:

  • 从堆栈中删除@ 1
  • 使用的第一个参数
  • 分支到第二个功能。

然后执行第二个函数代替第一个函数(它是一个尾调用),但是带有一个参数列表,该参数列表与第一个函数(第一个函数的vararg)不完全相同。

2 个答案:

答案 0 :(得分:3)

首先:如果你想传递varargs,你不能使用尾调用:

http://llvm.org/docs/LangRef.html

  
      
  1. 可选的“tail”标记表示被调用者函数不访问调用者中的任何allocas或varargs。
  2.   

第二:你的电话会议是什么?

第三:要处理varargs(如C语言),您需要使用va_*函数创建一个新的va_list并将所有参数复制到其中:

http://llvm.org/docs/LangRef.html#int-varargs

Last:此调度程序将调用的每个函数都必须使用va_*函数来获取其参数。

更新:

在您说堆栈作为函数参数的存储之前,您应该知道将使用哪个调用约定(默认值是什么)。然后。如果没有va_ *函数,则无法访问不传递“...”参数,因为它是在LLVM程序集中访问它们的唯一方法。

有一种方法可以像在C中那样做smth,这里printf将调用带有所有“...”参数的vfprintf,而不知道要传递多少个参数

// 3-clause BSD licensed to The Regents of the University of California.

int
printf(const char *fmt, ...)
{
        int ret;
        va_list ap;

        va_start(ap, fmt);
        ret = vfprintf(stdout, fmt, ap);
        va_end(ap);
        return (ret);
}

以特殊方式声明Vfprintf以获取“...”并从中提取参数:

int
vfprintf(FILE *fp, const char *fmt0, __va_list ap)
{
...
va_arg(ap, type) //to get next arg of type `type`

答案 1 :(得分:1)

(这对评论来说太大了。我担心我对LLVM没有多少实际经验,所以请大家多加一点)

我一直在考虑这个,我怀疑你是否能够写出这样的功能。

考虑使用C调用约定以x86_64汇编语言编写此函数,或者实际上任何支持varargs的函数(请参阅pg. 20示例)。通常你会在分支之前移位寄存器(rdi< -rsi,rsi< -rdx等),但是如果参数是例如你不应该这样做。漂浮,所以你必须知道类型!或者你必须使用类似vfprintf的函数。

其他架构存在类似的论点,因此我会考虑另一种解决问题的方法。特别是你不能只用一个跳转表中的查找替换对@1的调用,并将分支替换为%identifier指定的函数指针吗?这可以成为一个函数,它检查%identifier并返回正确的函数指针并适当地处理无效的标识符。