Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell llvm-general JIT: calling a C function on the fly. Stephen Diehl's tutorial

Tags:

haskell

llvm

I am following Stephen Diehl's excellent LLVM Haskell tutorial on a Linux Mint box (Linux Mint 17 Qiana, GHC 7.8.4, llvm 3.4).

I cloned the project's github repo and I was able to build each chapter's example by using the included Makefile.

In chapter 4 the tutorial presents us a JIT compiler:

import qualified LLVM.General.ExecutionEngine as EE

jit :: Context -> (EE.MCJIT -> IO a) -> IO a
jit c = EE.withMCJIT c optlevel model ptrelim fastins
  where
    optlevel = Just 2  -- optimization level
    model    = Nothing -- code model ( Default )
    ptrelim  = Nothing -- frame pointer elimination
    fastins  = Nothing -- fast instruction selection

runJIT :: AST.Module -> IO (Either String ())
runJIT mod = do
    ...
    jit context $ \executionEngine ->
        ...
        EE.withModuleInEngine executionEngine m $ \ee -> do
          mainfn <- EE.getFunction ee (AST.Name "main")
          case mainfn of
            Just fn -> do
              res <- run fn
              putStrLn $ "Evaluated to: " ++ show res
            Nothing -> return ()

Then the tutorial extends the language by writing C code to implement operations.

/* cbits
$ gcc -fPIC -shared cbits.c -o cbits.so
$ clang -fPIC -shared cbits.c -o cbits.so
*/

#include "stdio.h"

// putchard - putchar that takes a double and returns 0.
double putchard(double X) {
  putchar((char)X);
  fflush(stdout);
  return 0;
}

The makefile builds the project by running:

gcc -fPIC -shared src/chapter4/cbits.c -o src/chapter4/cbits.so
ghc -no-user-package-db -package-db .cabal-sandbox/*-packages.conf.d src/chapter4/cbits.so --make src/chapter4/*.hs -o chapter4

But when I try to call putchard() I get an error:

LLVM ERROR: Program used external function 'putchard' which could not be resolved!

Am I missing something here?

I've seen people having a similar issue with the original C++ version of the tutorial. They usually solve it by adding a flag to gcc build command (-rdynamic) which is supposed to make the linker add all symbols, no only used ones, to the dynamic symbol table. I suspect ghc is stripping putchard() from the executable file.

When I follow the exact same steps on OS X I everything works fine and I can call putchard() without a problem.

What's happening?

I just tried running the project on Centos 7 and it worked. There must be something wrong with my Mint machine.

like image 274
esato1981 Avatar asked Apr 05 '15 22:04

esato1981


1 Answers

Perhaps GHC is being a bit overzealous during linking and stripping out the symbol? Can you manually add a reference using the FFI in Main.hs and then recompile.

{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign.C.Types

foreign import ccall safe "putchard" putchard
    :: CDouble -> CDouble
like image 145
Stephen Diehl Avatar answered Nov 15 '22 05:11

Stephen Diehl