Die Leute von der LLVM-Mailingliste waren helpful enough to provide a better solution. Sie haben nicht gesagt, wie man den Zeiger von der Methode zur Funktion bringt, aber ich habe diesen Teil bereits herausgefunden, also ist es in Ordnung.
EDIT Eine saubere Art und Weise, dies zu tun ist einfach Ihre Methode in eine Funktion zu wickeln:
int Foo_Bar(Foo* foo)
{
return foo->bar();
}
Dann Foo_Bar
‚s-Adresse anstatt zu versuchen, Foo::bar
zu bekommen‘ verwenden s. Verwenden Sie llvm::ExecutionEngine::addGlobalMapping
, um die Zuordnung wie unten gezeigt hinzuzufügen.
Wie üblich, hat die einfachste Lösung einige interessante Vorteile. Zum Beispiel funktioniert es mit virtuellen Funktionen ohne einen Schluckauf. (Aber es ist so viel weniger unterhaltsam. Der Rest der Antwort wird für historische Zwecke gehalten, vor allem weil ich viel Spaß beim Stöbern auf die Interna meiner C++ Laufzeit hatte.)
Sie werden etwas in dieser Richtung müssen die Adresse einer Methode Abbildung (seien Sie gewarnt, dass ist ein schmutziger Hack, der wahrscheinlich nur mit dem Itanium ABI kompatibel sein wird):
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;
}
Dann nutzen llvm::ExecutionEngine::addGlobalMapping
ein zur Karte Funktion zu der Adresse, die Sie bekommen haben. Um es aufzurufen, geben Sie Ihr Objekt als ersten Parameter und den Rest wie gewohnt weiter. Hier ist ein kurzes Beispiel.
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));
Würde es Ihnen etwas ausmachen, uns zu zeigen, wie Sie das Problem am Ende gelöst haben? Ich kämpfe mit dem gleichen Problem. – FFox
@FFox: sicher. Ich habe die Antwort bearbeitet, um ein hilfreiches Beispiel zu geben. – zneak
@zneak, im Funktionstyp übergeben Sie 'llvm :: Function :: Create' welchen Typ haben Sie für das erste Argument (den Objektzeiger) verwendet? hast du void * benutzt? – lurscher