Skip to content
Related Articles

Related Articles

Improve Article
Save Article
Like Article

Turning a Function Pointer to Callable

  • Last Updated : 02 Apr, 2019

Well, the memory address of a compiled function is obtained but how to turn it to Python callable that can be used as an extension. The answer to this the use of ctypes module that can create a Python callable and can wrap arbitrary memory address.

The code below shows how to obtain the raw, low-level address of a C function and how to turn it back into a callable object.

 Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.  

To begin with, your interview preparations Enhance your Data Structures concepts with the Python DS Course. And to begin with your Machine Learning Journey, join the Machine Learning - Basic Level Course

Code #1:






import ctypes
lib = ctypes.cdll.LoadLibrary(None)
  
# Get the address of sin() from the C math library
addr = ctypes.cast(lib.sin, ctypes.c_void_p).value
print ("addr : ", addr)

Output :

addr : 140735505915760

 
Code #2 : Turn the address into a callable function




functype = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double)
func = functype(addr)
print ("Function : ", func)

Output :

Function : <CFunctionType object at 0x1006816d0>

 
Code #3 : Call the resulting function




print ("func(2) : ", func(2))
  
print ("func(0) : ", func(0))

Output :

func(2) : 0.9092974268256817

func(0) : 0.0

A CFUNCTYPE instance has to be created first to make a callable. The first argument to CFUNCTYPE() is the return type. Next arguments are the types of arguments. After defining the function type, it is wrapped around an integer memory address to create a callable object. The resulting object is used like any normal function accessed through ctypes.
It is becoming increasingly common for programs and libraries to utilize advanced code generation techniques like just-in-time compilation, as found in libraries such as LLVM (LLVM itself is not an acronym; it is the full name of the project.)

The code below uses the llvmpy extension to make an assembly function, obtain a function pointer to it, and turn it into a Python callable.

Code #4 :




from llvm.core import Module, Function, Type, Builder
  
mod = Module.new('example')
f = Function.new(mod, Type.function(
                  Type.double(), [Type.double(), Type.double()], False), 'foo')
  
block = f.append_basic_block('entry')
builder = Builder.new(block)
  
x2 = builder.fmul(f.args[0], f.args[0])
y2 = builder.fmul(f.args[1], f.args[1])
  
r = builder.fadd(x2, y2)
builder.ret(r)

Output :

<llvm.core.Instruction object at 0x10078e990>

 
Code #5 :




from llvm.ee import ExecutionEngine
  
engine = ExecutionEngine.new(mod)
ptr = engine.get_pointer_to_function(f)
ptr

Output :

4325863440

Code #6 : Call the resulting function




foo = ctypes.CFUNCTYPE(ctypes.c_double, 
                       ctypes.c_double, 
                       ctypes.c_double)(ptr)
  
print (foo(2, 3))
  
print ("\n", foo(4, 5))
  
print ("\n", foo(1, 2))

Output :

13.0

41.0

5.0



My Personal Notes arrow_drop_up
Recommended Articles
Page :