[LLVMdev] clang: call extern function using JIT
o.j.sivart at gmail.com
o.j.sivart at gmail.com
Wed Aug 18 07:42:47 PDT 2010
See my reply to your other post.
On 18/08/2010, at 11:57 PM, gafferuk wrote:
>
> Heres my full code listing, im totally stuck.
>
>
>
>
>
>
>
>
>
>
>
>
>
> // Whistle.cpp : Defines the entry point for the console application.
> //
>
> #include "stdafx.h"
> #include "clang/CodeGen/CodeGenAction.h"
> #include "clang/Driver/Compilation.h"
> #include "clang/Driver/Driver.h"
> #include "clang/Driver/Tool.h"
> #include "clang/Frontend/CompilerInvocation.h"
> #include "clang/Frontend/CompilerInstance.h"
> #include "clang/Frontend/DiagnosticOptions.h"
> #include "clang/Frontend/FrontendDiagnostic.h"
> #include "clang/Frontend/TextDiagnosticPrinter.h"
> #include "llvm/DerivedTypes.h"
> #include "llvm/Support/TypeBuilder.h"
> #include "llvm/LLVMContext.h"
> #include "llvm/Module.h"
> #include "llvm/Config/config.h"
> #include "llvm/ADT/OwningPtr.h"
> #include "llvm/ADT/SmallString.h"
> #include "llvm/Config/config.h"
> #include "llvm/ExecutionEngine/ExecutionEngine.h"
> #include "llvm/Support/ManagedStatic.h"
> #include "llvm/Support/raw_ostream.h"
> #include "llvm/System/Host.h"
> #include "llvm/System/Path.h"
> #include "llvm/Target/TargetSelect.h"
> using namespace clang;
> using namespace clang::driver;
>
> extern "C"
> int yipee(int val)
> {
> fprintf(stderr, "yipee!");
>
> return 1;
> }
>
>
> llvm::sys::Path GetExecutablePath(const char *Argv0) {
> // This just needs to be some symbol in the binary; C++ doesn't
> // allow taking the address of ::main however.
> void *MainAddr = (void*) (intptr_t) GetExecutablePath;
> return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
> }
>
> int Execute(llvm::Module *Mod, char * const *envp) {
> llvm::InitializeNativeTarget();
>
> std::string Error;
> llvm::OwningPtr<llvm::ExecutionEngine> EE(
> llvm::ExecutionEngine::createJIT(Mod, &Error));
> if (!EE) {
> llvm::errs() << "unable to make execution engine: " << Error << "\n";
> return 255;
> }
>
> // code I have added
> ---------------------------------------------------------------------------------------------
> llvm::FunctionType* ft =
> llvm::FunctionType::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()),
> std::vector<const llvm::Type*>(1,
> llvm::Type::getInt32Ty(llvm::getGlobalContext())), false);
>
> llvm::Function* F = llvm::Function::Create(ft,
> llvm::Function::ExternalLinkage, "yipee", Mod);
> EE->addGlobalMapping(F, (void*)(intptr_t)yipee);
> llvm::Function *YipeeFn = Mod->getFunction("yipee");
> if (!YipeeFn) {
> llvm::errs() << "'yipee' function not found in module.\n";
> return 255;
> }
> // end code I have added
> ---------------------------------------------------------------------------------------------
>
> llvm::Function *EntryFn = Mod->getFunction("main");
> if (!EntryFn) {
> llvm::errs() << "'main' function not found in module.\n";
> return 255;
> }
>
> // FIXME: Support passing arguments.
> std::vector<std::string> Args;
> Args.push_back(Mod->getModuleIdentifier());
>
> return EE->runFunctionAsMain(EntryFn, Args, envp);
> }
>
> int main(int argc, const char **argv, char * const *envp) {
> void *MainAddr = (void*) (intptr_t) GetExecutablePath;
> llvm::sys::Path Path = GetExecutablePath(argv[0]);
> TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions());
>
> Diagnostic Diags(&DiagClient);
> Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
> "a.out", /*IsProduction=*/false,
> /*CXXIsProduction=*/false,
> Diags);
> TheDriver.setTitle("clang interpreter");
>
> // FIXME: This is a hack to try to force the driver to do something we can
> // recognize. We need to extend the driver library to support this use
> model
> // (basically, exactly one input, and the operation mode is hard wired).
> llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
> Args.push_back("-fsyntax-only");
> llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args.size(),
> Args.data()));
> if (!C)
> return 0;
>
> // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.
>
> // We expect to get back exactly one command job, if we didn't something
> // failed. Extract that job from the compilation.
> const driver::JobList &Jobs = C->getJobs();
> if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
> llvm::SmallString<256> Msg;
> llvm::raw_svector_ostream OS(Msg);
> C->PrintJob(OS, C->getJobs(), "; ", true);
> Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
> return 1;
> }
>
> const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
> if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
> Diags.Report(diag::err_fe_expected_clang_command);
> return 1;
> }
>
> // Initialize a compiler invocation object from the clang (-cc1)
> arguments.
> const driver::ArgStringList &CCArgs = Cmd->getArguments();
> llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
> CompilerInvocation::CreateFromArgs(*CI,
> const_cast<const char
> **>(CCArgs.data()),
> const_cast<const char
> **>(CCArgs.data()) +
> CCArgs.size(),
> Diags);
>
> // Show the invocation, with -v.
> if (CI->getHeaderSearchOpts().Verbose) {
> llvm::errs() << "clang invocation:\n";
> C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
> llvm::errs() << "\n";
> }
>
> // FIXME: This is copied from cc1_main.cpp; simplify and eliminate.
>
> // Create a compiler instance to handle the actual work.
> CompilerInstance Clang;
> Clang.setLLVMContext(new llvm::LLVMContext);
> Clang.setInvocation(CI.take());
>
> // Create the compilers actual diagnostics engine.
>
> Clang.createDiagnostics(int(CCArgs.size()),const_cast<char**>(CCArgs.data()));
> if (!Clang.hasDiagnostics())
> return 1;
>
> // Infer the builtin include path if unspecified.
> if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
> Clang.getHeaderSearchOpts().ResourceDir.empty())
> Clang.getHeaderSearchOpts().ResourceDir =
> CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
>
> // Create and execute the frontend to generate an LLVM bitcode module.
> llvm::OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
> if (!Clang.ExecuteAction(*Act))
> return 1;
>
> int Res = 255;
> if (llvm::Module *Module = Act->takeModule())
> {
>
>
> Res = Execute(Module, envp);
> }
>
> // Shutdown.
>
> llvm::llvm_shutdown();
>
> return Res;
> }
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> gafferuk wrote:
>>
>> I tried what you said, now I get:
>>
>> LLVM ERROR: Program used external function 'yipee' which could not be
>> resolved!
>> Stack dump:
>> 0. Running pass 'X86 Machine Code Emitter' on function '@main'
>>
>> did not even get as far as a breakpoint.
>>
>>
>> Óscar Fuentes wrote:
>>>
>>> gafferuk <gafferuk at gmail.com> writes:
>>>
>>>> Im confused. The function i wish to call is a return type of int.
>>>> Im calling it with int dd = yipee(1);
>>>>
>>>> What's wrong?
>>>
>>> Declare the function:
>>>
>>> int yipee(int);
>>> int main()
>>> {
>>> int dd = yipee(1);
>>>
>>> return 0;
>>> }
>>>
>>>
>>> If that still crashes, put a breakpoint on `yipee' and see if the
>>> execution gets there, if the argument is right, if the crash happens
>>> inside the function or after it returns...
>>>
>>> _______________________________________________
>>> LLVM Developers mailing list
>>> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>>
>>>
>>
>>
>
> --
> View this message in context: http://old.nabble.com/clang%3A-call-extern-function-using-JIT-tp29449300p29471953.html
> Sent from the LLVM - Dev mailing list archive at Nabble.com.
>
>
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
More information about the llvm-dev
mailing list