Solución:
Una forma de hacer esto sería escribir una extensión (C) para Python. Puede echar un vistazo a esta documentación para obtener detalles completos sobre cómo hacerlo.
Otra forma de desarrollar extensiones de Python basadas en C sería interactuar directamente con una biblioteca externa usando el módulo ctypes.
En cualquier caso, necesitaría algo de código C compilado en una biblioteca o una extensión y una forma de llamarlo desde Python. Claramente, para lo que desea lograr, esto probablemente no sea óptimo, pero en realidad no es mucho trabajo exponer algunas funciones.
Puede incrustar el ensamblaje directamente dentro de su programa Python:
- https://github.com/Maratyszcza/PeachPy
- https://github.com//pycca/pycca
- http://codeflow.org/entries/2009/jul/31/pyasm-python-x86-assembler/
- https://github.com/AmihaiN/pyAsm
Estos funcionan compilando el ensamblado y cargándolo en la memoria ejecutable en tiempo de ejecución. Los primeros tres proyectos implementan ensambladores x86-64 o x86 en Python, mientras que el último llama a un compilador externo.
Como ejemplo específico, aquí se explica cómo llamar a una función que tomará un int y lo devolverá incrementado en uno.
Para obtener memoria con la bandera ejecutable establecida, mmap
se utiliza el módulo.
Para llamar a la función, ctypes
se utiliza el módulo.
Para poner el código de máquina en la memoria, hay una cadena de bytes codificada de código de máquina x86-64.
El código imprimirá 43.
En la práctica, escribiría el código en la biblioteca de objetos compartidos de C y usaría el ensamblaje en línea en C. Luego usaría cffi
para cargar y ejecutar la biblioteca. La ventaja de este ejemplo es que es autónomo y solo necesita la biblioteca estándar de Python.
import ctypes
import mmap
buf = mmap.mmap(-1, mmap.PAGESIZE, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC)
ftype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
fpointer = ctypes.c_void_p.from_buffer(buf)
f = ftype(ctypes.addressof(fpointer))
buf.write(
b'x8bxc7' # mov eax, edi
b'x83xc0x01' # add eax, 1
b'xc3' # ret
)
r = f(42)
print(r)
del fpointer
buf.close()