PyAsm是由Python写的动态编译器,使用PyAsm还可以在Python中嵌入汇编语言,用汇编语言来编写Python函数。这听起来很疯狂,但也许你真的需要在python中使用汇编语言。起官方网站为http://members.verizon.net/~olsongt/usersGuide.html
其实很久之前就发现了PyAsm,但是初期的尝试并不成功。官方网站并没有给太多的例子,刚开始也没有完全搞懂PyAsm的原理。昨天又突然想起 PyAsm来,终于有了发现。要用好PyAsm首先要了解PyAsm,根据我的不完全理解,PyAsm中的汇编代码应该是被编译成了Python扩展,然 后读入内存,并执行。这样,如何通过PyAsm在Python中使用汇编也就比较清晰了。其实就是将汇编代码作为Python的扩展函数来写。
初次尝试PyAsm失败就是因为没法处理传入的参数,当时没有搞清楚,只是简单的使用!ARG来获取参数,而实际上PyAsm所编译的函数应当是 Python扩展函数的原型即static PyObject * ext_func(PyObject *self, PyObject *args),主要有两个参数self和args,其中args就是传入的参数列表,需要用Python API PyArg_ParseTuple来解析。
同样,PyAsm中的函数返回值则需要用Py_BuildValue来创建。
好,下面给出一个简单sum函数,求两个参数之和。
# -*- coding:utf-8 -*-
# file: test.py
# by: bluebanboom 0(0
# mail: bluebanboom@gmail.com ~
# date: 2008-11-06
# note:
import pyasm.excmem
from pyasm.x86asm import assembler, CDECL, STDCALL, PYTHON
from pyasm.x86cpToMemory import CpToMemory
def main():
a = assembler()
a.ADStr("in_fmt", "ii/0")
a.ADStr("out_fmt", "i/0")
a.AP("sum", PYTHON)
a.ARG("self")
a.ARG("args")
a.AddLocal("x")
a.AddLocal("y")
#a.AI("INT 3")
a.AI("LEA EAX, x")
a.AI("PUSH EAX")
a.AI("LEA EAX, y")
a.AI("PUSH EAX")
a.AI("PUSH in_fmt")
a.AI("PUSH args")
a.AI("CALL PyArg_ParseTuple")
a.AI("ADD ESP, 0xC")
a.AI("MOV EAX, x")
a.AI("MOV EBX, y")
a.AI("ADD EAX, EBX")
a.AI("PUSH EAX")
a.AI("PUSH out_fmt")
a.AI("CALL Py_BuildValue")
a.AI("ADD ESP, 0x8")
a.EP()
mem = CpToMemory(a.Compile())
mem.MakeMemory()
mem.BindPythonFunctions(globals())
print sum(1, 2)
print sum(2, 2)
if __name__ == "__main__":
main()
上边的这个例子修改自PyAsm中的测试函数,运行后输出如下
很好,不是吗?
有个问题要注意,官方给的简单例子用的是PyAsm直接大段写代码,但这样有问题,通过调试我发现在函数的开头没有经典的
并没有实现官方说的This will generate the boilerplate function startup code, which consists of PUSHing the EBP register, copying the current location of ESP, and translating arguments and local variables into references via the offset of the EBP pointer.但意外的是在函数结束却有那么一段,看来是一个bug,把位置搞错了。
另外调用函数要自己清除堆栈。
上边的代码中将INT 3给注释掉,如果需要调试代码可以去掉注释,这样就是出错,然后加载调试器就可以了。
这样,在使用PyAsm的时候几乎就没有任何问题了。另外,PyAsm还可以充当编译器使用,真是强悍啊。