Ответ 1
Чуваки из списка рассылки LLVM были достаточно полезны, чтобы обеспечить лучшее решение. Они не сказали, как получить указатель от метода к функции, но я уже понял эту часть, так что все в порядке.
РЕДАКТИРОВАТЬ Чистый способ сделать это - просто превратить ваш метод в функцию:
int Foo_Bar(Foo* foo)
{
return foo->bar();
}
Затем используйте Foo_Bar
адрес вместо того, чтобы пытаться получить Foo::bar
. Используйте llvm::ExecutionEngine::addGlobalMapping
, чтобы добавить отображение, как показано ниже.
Как обычно, простейшее решение имеет некоторые интересные преимущества. Например, он работает с виртуальными функциями без икоты. (Но это гораздо менее интересно. Остальная часть ответа хранится в исторических целях, главным образом потому, что мне было очень весело возиться с внутренними средами моей С++. Также обратите внимание, что она не переносима.)
Вам понадобится что-то в этих строках, чтобы указать адрес метода (будьте осторожны, что грязный хак, который, вероятно, будет совместим только с 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 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));