我可以将现有方法绑定到LLVM函数*并从JIT编译代码中使用它吗? 我在用LLVM C++ API玩弄。我想JIT编译代码并运行它 但是,我需要从JIT编译代码中调用C++方法。通常,LLVM将方法调用视为函数调用,对象指针作为第一个参数传递,因此调用不应该是问题。真正的问题是将该函数放入LLVM

我可以将现有方法绑定到LLVM函数*并从JIT编译代码中使用它吗? 我在用LLVM C++ API玩弄。我想JIT编译代码并运行它 但是,我需要从JIT编译代码中调用C++方法。通常,LLVM将方法调用视为函数调用,对象指针作为第一个参数传递,因此调用不应该是问题。真正的问题是将该函数放入LLVM,c++,jit,llvm,C++,Jit,Llvm,就我所见,可以对函数使用外部链接并通过其名称获取它。问题是,因为它是C++方法,它的名字会被改写,所以我认为这样做不是一个好主意。 制作FunctionType对象非常简单。但是从那以后,我怎样才能将我的方法通知LLVM并为它获取一个函数对象呢?一种方法是在所需方法周围使用C包装,即 extern "C" { void wrapped_foo(bar *b, int arg1, int arg2) { b->foo(arg1, arg2); } } extern“C”位使

就我所见,可以对函数使用外部链接并通过其名称获取它。问题是,因为它是C++方法,它的名字会被改写,所以我认为这样做不是一个好主意。
制作
FunctionType
对象非常简单。但是从那以后,我怎样才能将我的方法通知LLVM并为它获取一个
函数
对象呢?

一种方法是在所需方法周围使用C包装,即

extern "C" {
  void wrapped_foo(bar *b, int arg1, int arg2) {
    b->foo(arg1, arg2);
  }
}
extern“C”
位使函数使用C调用约定并防止任何名称损坏。有关C/C++互操作的详细信息,包括外部“C”


您也应该能够在C++代码中获取函数的地址,然后将该地址存储在一个全局已知的LLVM中。

< P> HUH,使用非标准<代码> DLDRDR < /Cord>,以及一种可笑的、不安全的方法来将方法指针抛出到空洞指针中,似乎有一种方法可以从指针获取方法的名称

这肯定比枪支更危险。不要在家里(或者在工作中)这样做

C++禁止将方法指针强制转换为void*(这是dladdr工作所必需的),即使使用万能的C强制转换,但您可以欺骗它

#include <string>
#include <dlfcn.h>

template<typename T>
static void* voidify(T method)
{
    asm ("movq %rdi, %rax"); // should work on x86_64 ABI compliant platforms
}

template<typename T>
const char* getMethodName(T method)
{
    Dl_info info;
    if (dladdr(voidify(method), &info))
        return info.dli_sname;
    return "";
}
#包括
#包括
模板
静态空隙*voidify(T法)
{
asm(“movq%rdi,%rax”);//应在x86_64 ABI兼容平台上工作
}
模板
常量字符*getMethodName(T方法)
{
Dl_信息;
if(dladdr(作废(方法)和信息))
return info.dli_sname;
返回“”;
}
从那里:

int main()
{
    std::cout << getMethodName(&Foo::bar) << std::endl;
    // prints something like "_ZN3Foo3barEv"
}
intmain()
{

LLVM邮件列表中的家伙是。他们没有说如何从方法中获取指向函数的指针,但我已经解决了这一部分,所以没关系

编辑一种简洁的方法是将方法包装到函数中:

int Foo_Bar(Foo* foo)
{
    return foo->bar();
}
然后使用
Foo\u Bar
的地址,而不是尝试获取
Foo::Bar
。使用
llvm::ExecutionEngine::addGlobalMapping
添加映射,如下所示

通常,最简单的解决方案有一些有趣的好处。例如,它可以在没有打嗝的情况下与虚拟函数一起工作。(但它不那么有趣。其余的答案都是为了历史目的而保留的,主要是因为我在C++运行时的内部操作中有很多乐趣。还注意到它是不可移植的。)


您需要沿着这些思路来计算方法的地址(请注意,这是一个肮脏的黑客攻击,可能只与安腾ABI兼容):


我认为可以有一种更直接的方法。@Paul Nathan:不过它确实发出了一些警告(“控件到达非空函数的末尾”)我已经美化了它,以更好地与C++集成。你介意告诉我们你是如何解决这个问题的吗?我正在同一个问题挣扎。“FFox:当然。我已经编辑了答案,提供了一个有用的例子。@ ZNEAK,在你传递给<代码> LVV::函数::创建< /COD>函数>第一个参数中使用了什么类型?(对象指针)?是否使用void*?@lurscher,否,因为这将是一个非常麻烦的问题。模式是将类
StructType
专门化,并将
T
作为您的结构,并在那里实现
get
方法。然后可以使用
llvm::StructType::get(上下文)
获取类型并获取指向该类型的指针类型非常简单。有关实现示例,请参阅。
template<typename T>
const void* void_cast(const T& object)
{
    union Retyper
    {
        const T object;
        void* pointer;
        Retyper(T obj) : object(obj) { }
    };

    return Retyper(object).pointer;
}

template<typename T, typename M>
const void* getMethodPointer(const T* object, M method) // will work for virtual methods
{
    union MethodEntry
    {
        intptr_t offset;
        void* function;
    };

    const MethodEntry* entry = static_cast<const MethodEntry*>(void_cast(&method));

    if (entry->offset % sizeof(intptr_t) == 0) // looks like that's how the runtime guesses virtual from static
        return getMethodPointer(method);

    const void* const* const vtable = *reinterpret_cast<const void* const* const* const>(object);
    return vtable[(entry->offset - 1) / sizeof(void*)];
}

template<typename M>
const void* getMethodPointer(M method) // will only work with non-virtual methods
{
    union MethodEntry
    {
        intptr_t offset;
        void* function;
    };

    return static_cast<const MethodEntry*>(void_cast(&method))->function;
}
class Foo
{
    void Bar();
    virtual void Baz();
};

class FooFoo : public Foo
{
    virtual void Baz();
};

Foo* foo = new FooFoo;

const void* barMethodPointer = getMethodPointer(&Foo::Bar);
const void* bazMethodPointer = getMethodPointer(foo, &Foo::Baz); // will get FooFoo::Baz

llvm::ExecutionEngine* engine = llvm::EngineBuilder(module).Create();

llvm::Function* bar = llvm::Function::Create(/* function type */, Function::ExternalLinkage, "foo", module);
llvm::Function* baz = llvm::Function::Create(/* function type */, Function::ExternalLinkage, "baz", module);
engine->addGlobalMapping(bar, const_cast<void*>(barMethodPointer)); // LLVM always takes non-const pointers
engine->addGlobalMapping(baz, const_cast<void*>(bazMethodPointer));