Парни из списка рассылки LLVM были достаточно полезны, чтобы обеспечить лучшее решение .Они не сказали, как получить указатель от метода к функции, но я уже разобрался с этой частью, так что все в порядке.
РЕДАКТИРОВАТЬ Чистый способ сделать этопросто превратить ваш метод в функцию:
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;
}
Затем используйтеllvm::ExecutionEngine::addGlobalMapping
для сопоставления функции с полученным адресом.Чтобы вызвать его, передайте ему свой объект в качестве первого параметра, а остальные как обычно.Вот быстрый пример.
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));