代码之家  ›  专栏  ›  技术社区  ›  zneak

我可以将现有方法绑定到LLVM函数*并从JIT编译的代码中使用它吗?

  •  19
  • zneak  · 技术社区  · 14 年前

    我在玩弄LLVM C++ API。我想JIT编译代码并运行它。

    据我所知,可以对函数使用外部链接并按其名称获取它。问题是,因为它是C++方法,它的名字会被改写,所以我认为这样做不是一个好主意。

    制造 FunctionType Function

    3 回复  |  直到 11 年前
        1
  •  16
  •   zneak    8 年前

    LLVM邮件列表中的人 helpful enough to provide a better solution . 他们没有说如何从方法中获取指向函数的指针,但是我已经理解了这一部分,所以没关系。

    编辑

    int Foo_Bar(Foo* foo)
    {
        return foo->bar();
    }
    

    Foo_Bar 的地址,而不是试图获取 Foo::bar llvm::ExecutionEngine::addGlobalMapping 添加映射,如下所示。

    像往常一样,最简单的解决方案有一些有趣的好处。例如,它可以与虚拟函数一起工作,而不会出现问题(但它没有那么有趣。其余的答案都是为了历史目的而保留的,主要是因为我在我的C++运行时内部有很多乐趣。另外请注意,它是不可携带的。)


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

    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));
    
        2
  •  8
  •   Geoff Reedy    14 年前

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

    extern "C" {
      void wrapped_foo(bar *b, int arg1, int arg2) {
        b->foo(arg1, arg2);
      }
    }
    

    这个 extern "C" 位使函数使用C调用约定并防止任何名称损坏。看到了吗 http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6 有关C/C++互操作的详细内容,包括 外部“C”

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

        3
  •  4
  •   zneak    14 年前

    嗯,用非标准的 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 "";
    }
    

    从那里开始:

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

    …aa您应该能够将该符号名与LLVM一起使用。但是它不能与虚拟方法一起工作(不使用它的另一个很好的理由)。

    编辑 我深入研究了虚拟方法指针的处理方式,并为它们编写了一个更为复杂的函数。只有最勇敢的人 follow this link .