Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get the address of a function (without interfacing C)

Having a rather low level application, I came into a sitatuion where I needed to determine the address of a Haskell function. I was able to do that with FFI, that is C, but I would like to do it directly in Haskell.

Here is my current solution with FFI:

main.hs:

{-# LANGUAGE ForeignFunctionInterface #-}
module Main where

import Foreign
import Foreign.C.Types
import Text.Printf

foreign import ccall "getFuncAddr"
  getFuncAddr :: CULong

main :: IO ()
main = do
  printf "0x%016x\n" (fromIntegral getFuncAddr :: Word64)

foreign export ccall func :: IO ()
func :: IO ()
func = do
  printf "hello world\n"

ffi.c:

void func(void);

unsigned long getFuncAddr(void)
{
    return (unsigned long) func;
}

Makefile:

all: main
    ./$<
    objdump -D $< | grep '<func>'

main: main.hs ffi.c
    ghc --make -O2 $^ -o $@

as always, also available as a gist.

like image 548
lewurm Avatar asked Feb 21 '23 05:02

lewurm


2 Answers

Try this:

{-# LANGUAGE ForeignFunctionInterface #-}
module Main where

import Foreign
import Foreign.C.Types
import Text.Printf

foreign import ccall "&func"
  funcaddr :: FunPtr (IO ())

main :: IO ()
main = do
  printf "0x%016x\n" (fromIntegral (ptrToIntPtr (castFunPtrToPtr funcaddr)) :: Int)

foreign export ccall func :: IO ()
func :: IO ()
func = do
  printf "hello world\n"

See this section of the Haskell 2010 report, and look for "Static Addresses."

like image 108
Simon Marlow Avatar answered Mar 05 '23 17:03

Simon Marlow


I think the documentation for FunPtr has pretty much what you want. The short version is you use foreign import "wrapper", as follows:

foreign import ccall "wrapper"
  getFuncAddr :: IO () -> IO (FunPtr (IO ()))

and then if you're done with it later, use freeHaskellFunPtr.

like image 38
Ben Millwood Avatar answered Mar 05 '23 18:03

Ben Millwood