LLVMでJITアドレス空間にある関数に別の関数へのポインタを渡して呼び出す

LLVMで(ry

ものすごくどうでも良いようなことをやっているような気がしないでもないのだが、とりあえずできたので書く。

前回二つ分の合わせ技で行けるらしい。LLVMには関数ポインタを表す型は用意されていないっぽい(?)ので、代わりにi8*を使用する。ソースコードは以下の通り。

void printInteger(unsigned int i) {
	printf("printInteger() : %d\n", i);
}

extern "C"
__declspec(dllexport) void callPrintInteger(void (*function)(unsigned int), unsigned int i) {
	function(i);
}

int main() {
	InitializeNativeTarget();

	LLVMContext Context;

	Module *M = new Module("test", Context);

	Function *testFunction = cast<Function>(M->getOrInsertFunction("testFunction", Type::getVoidTy(Context), (Type *)0));
	BasicBlock *BB = BasicBlock::Create(Context, "EntryBlock", testFunction);
	IRBuilder<> builder(BB);

	Value *One = ConstantInt::get(Type::getInt32Ty(Context), 1);

	std::vector<const Type*> Params;
	Params.push_back(Type::getInt8PtrTy(Context));
	Params.push_back(Type::getInt32Ty(Context));
	FunctionType *FT = FunctionType::get(Type::getVoidTy(Context), Params, false);
	Function *F = Function::Create(FT, Function::ExternalLinkage, "callPrintInteger", M);
	Constant* integer = ConstantInt::get(Type::getInt64Ty(Context), (unsigned long long)&printInteger);
	Value* pointer = ConstantExpr::getIntToPtr(integer, PointerType::getUnqual(Type::getInt8Ty(Context)));
	builder.CreateCall2(M->getFunction("callPrintInteger"), pointer, One);

	builder.CreateRetVoid();

	ExecutionEngine* EE = EngineBuilder(M).create();

	std::vector<GenericValue> noargs;
	EE->runFunction(testFunction, noargs);

	outs() << "Module:\n" << *M;

	EE->freeMachineCodeForFunction(testFunction);
	delete EE;
	llvm_shutdown();
	return 0;
}

一度キャストしているところがどうにも気持ち悪い。どうにかならないものだろうか・・・。