Skip to main content
 首页 » 编程设计

python之反汇编 Python 代码到字典

2025年05月04日10powertoolsteam

我想为 Python 程序开发一个小型调试工具。对于“动态切片”功能,我需要找到在语句中访问的变量,并找到这些变量的访问类型(读取或写入)。

但 Python 中内置的唯一反汇编功能是 dis.disassemble ,这只是将反汇编打印到标准输出:

>>> dis.disassemble(compile('x = a + b', '', 'single')) 
  1           0 LOAD_NAME                0 (a) 
              3 LOAD_NAME                1 (b) 
              6 BINARY_ADD           
              7 STORE_NAME               2 (x) 
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE         

我希望能够将反汇编转换为描述每条指令使用哪些变量的集合字典,如下所示:

>>> my_disassemble('x = a + b') 
{'LOAD_NAME': set(['a', 'b']), 'STORE_NAME': set(['x'])} 

我该怎么做?

请您参考如下方法:

阅读the source code for the dis module并且您会发现很容易进行自己的反汇编并生成您喜欢的任何输出格式。下面是一些在代码对象中生成指令序列及其参数的代码:

from opcode import * 
 
def disassemble(co): 
    """ 
    Disassemble a code object and generate its instructions. 
    """ 
    code = co.co_code 
    n = len(code) 
    extended_arg = 0 
    i = 0 
    free = None 
    while i < n: 
        c = code[i] 
        op = ord(c) 
        i = i+1 
        if op < HAVE_ARGUMENT: 
            yield opname[op], 
        else: 
            oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg 
            extended_arg = 0 
            i = i+2 
            if op == EXTENDED_ARG: 
                extended_arg = oparg*65536L 
            if op in hasconst: 
                arg = co.co_consts[oparg] 
            elif op in hasname: 
                arg = co.co_names[oparg] 
            elif op in hasjrel: 
                arg = repr(i + oparg) 
            elif op in haslocal: 
                arg = co.co_varnames[oparg] 
            elif op in hascompare: 
                arg = cmp_op[oparg] 
            elif op in hasfree: 
                if free is None: 
                    free = co.co_cellvars + co.co_freevars 
                arg = free[oparg] 
            else: 
                arg = oparg 
            yield opname[op], arg 

这是一个示例反汇编。

>>> def f(x): 
...     return x + 1 
...  
>>> list(disassemble(f.func_code)) 
[('LOAD_FAST', 'x'), ('LOAD_CONST', 1), ('BINARY_ADD',), ('RETURN_VALUE',)] 

您可以轻松地将其转换为您想要的集合字典数据结构:

>>> from collections import defaultdict 
>>> d = defaultdict(set) 
>>> for op in disassemble(f.func_code): 
...     if len(op) == 2: 
...         d[op[0]].add(op[1]) 
...  
>>> d 
defaultdict(<type 'set'>, {'LOAD_FAST': set(['x']), 'LOAD_CONST': set([1])}) 

(或者您可以直接生成集合字典数据结构。)

请注意,在您的应用程序中,您实际上可能不需要查找每个操作码的名称。相反,您可以在 opcode.opmap 字典中查找所需的操作码并创建命名常量,也许像这样:

LOAD_FAST = opmap['LOAD_FAST'] # actual value is 124 
... 
for var in disassembly[LOAD_FAST]: 
    ... 

更新:在 Python 3.4 中,您可以使用新的 dis.get_instructions :

>>> def f(x): 
...     return x + 1 
>>> import dis 
>>> list(dis.get_instructions(f)) 
[Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='x', 
             argrepr='x', offset=0, starts_line=1, is_jump_target=False), 
 Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=1, 
             argrepr='1', offset=3, starts_line=None, is_jump_target=False), 
 Instruction(opname='BINARY_ADD', opcode=23, arg=None, argval=None, 
             argrepr='', offset=6, starts_line=None, is_jump_target=False), 
 Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, 
             argrepr='', offset=7, starts_line=None, is_jump_target=False)]