[cfe-dev] Calling Extern Function

o.j.sivart at gmail.com o.j.sivart at gmail.com
Thu Aug 19 01:23:23 PDT 2010


On 19/08/2010, at 1:07 AM, Paul Griffiths wrote:

> I don't know what nm means.

By nm I mean the GNU tool nm which lists the symbols in object files. Are you on a platform that has nm or are you on windows, osx, or something else?

> Im not stripping anything.

Good so the symbols should be in the executable.

> Honistly, I would of thought an example of this would be provided, it
> must be used often.

The example you have should work, the code seems fine. The extern C should overcome any name mangling, which is why I was asking you to check what you get from listing the symbols, asking that you hadn't stripped symbols, and suggesting that if at that stage everything looks good then the only issue could be that dlopen can't see the symbols, which is why I suggested that you may been the equivalent of gcc's -rdynamic flag for your compiler.

> On 18 August 2010 14:56,  <o.j.sivart at gmail.com> wrote:
>> What does nm on your application binary give in terms of the name yipee?
>> You are not by any chance stripping symbols from your binary?
>> 
>> Possibly you need the equivalent of gcc's -rdynamic flag for your compiler.
>> 
>> On 19/08/2010, at 12:14 AM, Paul Griffiths wrote:
>> 
>>> Yes, it is c++;
>>> ave also tried it with
>>> 
>>> extern "C"
>>> int yipee(int aVar)
>>> {
>>>    return 5;
>>> }
>>> 
>>> but still no luck.
>>> 
>>> 
>>> 
>>> heres my full listing, im 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;
>>> }
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> On 18 August 2010 14:36,  <o.j.sivart at gmail.com> wrote:
>>>> I assume you are compiling your program as c++. In this case your problem is that "yipee" will have been name mangled by the c++ compiler.
>>>> 
>>>> On 18/08/2010, at 9:08 PM, Paul Griffiths wrote:
>>>> 
>>>>> Can someone please tell me what I am doing wrong?
>>>>> 
>>>>> Im trying to register an external function with the JIT, so can call
>>>>> functions in my music application(heres an image :
>>>>> http://img534.imageshack.us/img534/3995/87647073.jpg).
>>>>> 
>>>>> Here my functions
>>>>> 
>>>>> int yipee(int aVar)
>>>>> {
>>>>>    return 5;
>>>>> }
>>>>> 
>>>>> 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*>(0,
>>>>> llvm::Type::getInt32Ty(llvm::getGlobalContext())), false);
>>>>> 
>>>>>       llvm::Function* f = llvm::Function::Create(ft,
>>>>> llvm::Function::ExternalLinkage, "yipee", Mod);
>>>>>       EE->addGlobalMapping(f, 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);
>>>>> }
>>>>> 
>>>>> 
>>>>> 
>>>>> // here the C code to be ran with JIT
>>>>> -------------------------------------------------------------------
>>>>> 
>>>>> int main() {
>>>>>       int dd = yipee(1);
>>>>>  return 1;
>>>>> }
>>>>> _______________________________________________
>>>>> cfe-dev mailing list
>>>>> cfe-dev at cs.uiuc.edu
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>> 
>>>> 
>>> 
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>> 
>> 





More information about the cfe-dev mailing list