Convertir un puntero de función en invocable

Bueno, se obtiene la dirección de memoria de una función compilada, pero cómo convertirla en Python llamable que se puede usar como una extensión. La respuesta a esto es el uso del módulo ctypes que puede crear un Python invocable y puede envolver una dirección de memoria arbitraria.

El siguiente código muestra cómo obtener la dirección sin procesar de bajo nivel de una función de C y cómo volver a convertirla en un objeto invocable.

Código #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)

Producción :

addr : 140735505915760

 
Código #2: Convierte la dirección en una función invocable

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

Producción :

Function : <CFunctionType object at 0x1006816d0>

 
Código #3: llama a la función resultante

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

Producción :

func(2) : 0.9092974268256817

func(0) : 0.0

Primero se debe crear una instancia de CFUNCTYPE para que sea invocable. El primer argumento para CFUNCTYPE()es el tipo de retorno. Los siguientes argumentos son los tipos de argumentos. Después de definir el tipo de función, se envuelve alrededor de una dirección de memoria entera para crear un objeto invocable. El objeto resultante se usa como cualquier función normal a la que se acceda a través de ctypes .
Cada vez es más común que los programas y las bibliotecas utilicen técnicas avanzadas de generación de código, como la compilación justo a tiempo, como se encuentra en bibliotecas como LLVM (LLVM en sí no es un acrónimo; es el nombre completo del proyecto).

El siguiente código usa la extensión llvmpy para hacer una función de ensamblado, obtener un puntero de función y convertirlo en un Python invocable.

Código #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)

Producción :

<llvm.core.Instruction object at 0x10078e990>

 
Código #5:

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

Producción :

4325863440

Código #6: llama a la función resultante

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))

Producción :

13.0

41.0

5.0

Publicación traducida automáticamente

Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *