【问题标题】:LLVM assembly: call a function using varargsLLVM 程序集:使用可变参数调用函数
【发布时间】:2011-10-24 08:02:21
【问题描述】:

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

  • 子功能的标识符
  • 可变参数

这个函数应该做一些预处理,找到标识符的正确函数并使用可变参数调用它,并返回它的结果。

类似:

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)。

【问题讨论】:

  • 是否可以选择用 C 语言编写此类代码,使用 clang/llvm-gcc 编译并反汇编 .bc
  • 有一个llvm反汇编程序:llvm-dis。我想做的事在 C 中是做不到的。

标签: assembly llvm variadic-functions


【解决方案1】:

首先:如果要传递可变参数,则不能使用尾调用:

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

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

第二:你的调用约定是什么?

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

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

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

更新:

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

有一种类似 C 的方法,这里 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`

【讨论】:

  • 我已经看到了所有这些......我修改了我的问题以更好地解释我想要什么
  • 我的调用约定是默认值。而且我不想使用 va_* 函数,因为它们不能做我想做的事情。
  • osgx 你应该更加通灵。让读心术更好一点!
  • andrew cooke,请解释一下,我该怎么办?
【解决方案2】:

(这对于评论来说太大了。恐怕我对 LLVM 没有太多的实践经验,所以对此持保留态度)

我一直在考虑这个问题,但我怀疑你是否能够编写这样的函数。

考虑使用 C 调用约定或任何支持可变参数的 x86_64 汇编语言编写此函数(参见 pg. 20 示例)。通常,您会在分支之前移动寄存器(rdivfprintf的函数。

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

【讨论】:

  • 我认为你是对的,在 LLVM 汇编中没有办法做到这一点,我会尝试找到另一种方法来做事。我希望@1 的实现对调用者保持不透明,因此它可能会返回一个函数指针,而由调用者来调用它。如果它认为它更好,我会让 LLVM 内联它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
相关资源
最近更新 更多