Các dudes từ danh sách gửi thư của LLVM là helpful enough to provide a better solution. Họ đã không nói làm thế nào để có được con trỏ từ phương pháp này đến hàm, nhưng tôi đã tìm ra phần này để nó ổn.
EDIT Một cách sạch để làm điều này chỉ đơn giản là quấn phương pháp của bạn thành một chức năng:
int Foo_Bar(Foo* foo)
{
return foo->bar();
}
Sau đó sử dụng 'địa chỉ s thay vì cố gắng để có được Foo::bar
' Foo_Bar
s. Sử dụng llvm::ExecutionEngine::addGlobalMapping
để thêm ánh xạ như được hiển thị bên dưới.
Như thường lệ, giải pháp đơn giản nhất có một số lợi ích thú vị. Ví dụ, nó hoạt động với các chức năng ảo mà không có trục trặc. (Nhưng nó ít giải trí hơn nhiều. Phần còn lại của câu trả lời được giữ cho mục đích lịch sử, chủ yếu là vì tôi đã có rất nhiều niềm vui poking tại internals của thời gian chạy C++ của tôi. Cũng lưu ý rằng nó không di động.)
Bạn sẽ cần một cái gì đó dọc theo những dòng để tìm địa chỉ của một phương pháp (được cảnh báo, đó là một bẩn hack mà có lẽ sẽ chỉ tương thích với các bộ xử lý 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;
}
Sau đó sử dụng llvm::ExecutionEngine::addGlobalMapping
để ánh xạ một đến địa chỉ bạn đã nhận được. Để gọi nó, chuyển đối tượng của bạn làm tham số đầu tiên và phần còn lại như bình thường. Đây là một ví dụ nhanh.
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));
Bạn có thể cho chúng tôi biết cách bạn giải quyết vấn đề cuối cùng không. Tôi đang đấu tranh với cùng một vấn đề. – FFox
@FFox: chắc chắn rồi. Tôi đã chỉnh sửa câu trả lời để cung cấp một ví dụ hữu ích. – zneak
@zneak, trong kiểu hàm bạn chuyển đến 'llvm :: Function :: Create' bạn đã sử dụng kiểu nào cho đối số đầu tiên (đối tượng con trỏ)? bạn đã sử dụng void *? – lurscher