Превращение указателя функции в вызываемый

Опубликовано: 12 Апреля, 2022

Что ж, адрес памяти скомпилированной функции получен, но как превратить его в вызываемый Python, который можно использовать как расширение. Ответ на этот вопрос - использование модуля ctypes, который может создавать вызываемый Python и переносить произвольный адрес памяти.

В приведенном ниже коде показано, как получить необработанный низкоуровневый адрес функции C и как превратить его обратно в вызываемый объект.

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)

Выход :

адрес: 140735505915760


Код # 2: превратить адрес в вызываемую функцию

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

Выход :

Функция: <объект CFunctionType в 0x1006816d0>

 
Code #3 : Call the resulting function

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

Выход :

func (2): 0.9092974268256817

функция (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.)

В приведенном ниже коде расширение llvmpy используется для создания функции сборки, получения на нее указателя функции и превращения ее в вызываемый Python.

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)

Выход :

<llvm.core.Instruction объект по адресу 0x10078e990>

 
Code #5 :

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

Выход :

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 (" ", foo(4, 5))
  
print (" ", foo(1, 2))

Выход :

13,0

41,0

5.0

Внимание компьютерщик! Укрепите свои основы с помощью базового курса программирования Python и изучите основы.

Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS. А чтобы начать свое путешествие по машинному обучению, присоединяйтесь к курсу Машинное обучение - базовый уровень.