Los tipos de la lista de correo de LLVM eran helpful enough to provide a better solution. No dijeron cómo sacar el puntero del método a la función, pero ya descubrí esta parte, así que está bien.
EDITAR una forma limpia de hacer esto es simplemente para envolver su método en una función:
int Foo_Bar(Foo* foo)
{
return foo->bar();
}
A continuación, utilice 'dirección de s en lugar de tratar de obtener Foo::bar
' Foo_Bar
s. Use llvm::ExecutionEngine::addGlobalMapping
para agregar la asignación como se muestra a continuación.
Como siempre, la solución más simple tiene algunos beneficios interesantes. Por ejemplo, funciona con funciones virtuales sin interrupciones. (Pero es mucho menos entretenido. El resto de la respuesta se mantiene con propósitos históricos, principalmente porque me divertí mucho hurgando en el funcionamiento interno de C++. También tenga en cuenta que no es portátil.)
tendrá algo en este sentido para averiguar la dirección de un método (se advirtió, eso es un truco sucio que probablemente sólo será compatible con el 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;
}
a continuación, utilice llvm::ExecutionEngine::addGlobalMapping
para asignar una función a la dirección que ha recibido. Para llamarlo, páselo como el primer parámetro y el resto como de costumbre. Aquí hay un ejemplo rápido.
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));
¿Te importaría mostrarnos cómo resolvió el problema al final? Estoy luchando con el mismo problema. – FFox
@FFox: seguro. He editado la respuesta para proporcionar un ejemplo útil. – zneak
@zneak, en el tipo de función que pasa a 'llvm :: Function :: Create' ¿qué tipo usó para el primer argumento (el puntero del objeto)? usaste void *? – lurscher