Python字节码反汇编程序

Python标准库中的dis模块通过将其分解为易于理解的形式,提供了各种功能,可用于分析Python字节码。这有助于执行优化。字节码是解释器的特定于版本的实现细节。

dis()函数

该函数dis() 生成任何Python代码源的反汇编表示,即模块,类,方法,函数或代码对象。

>>> def hello():
print ("hello world")
>>> import dis
>>> dis.dis(hello)
2    0 LOAD_GLOBAL 0 (print)
     3 LOAD_CONST 1 ('hello world')
     6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
     9 POP_TOP
     10 LOAD_CONST 0 (None)
     13 RETURN_VALUE

字节码分析API在Bytecode类中定义。它的构造函数返回Bytecode对象,该对象具有以下方法来分析字节码

字节码()

这是构造函数。分析与函数,生成器,方法,源代码字符串或代码对象相对应的字节码。这是许多功能的便捷包装

>>> string=dis.Bytecode(hello)
>>> for x in string:
      print (x)
Instruction(opname = 'LOAD_GLOBAL', opcode = 116, arg = 0, argval = 'print', argrepr = 'print', offset = 0, starts_line = 2, is_jump_target = False)
Instruction(opname = 'LOAD_CONST', opcode = 100, arg = 1, argval = 'hello world', argrepr = "'hello world'", offset = 3, starts_line = None, is_jump_target = False)
Instruction(opname = 'CALL_FUNCTION', opcode = 131, arg = 1, argval = 1, argrepr = '1 positional, 0 keyword pair', offset = 6, starts_line = None, is_jump_target = False)
Instruction(opname = 'POP_TOP', opcode = 1, arg = None, argval = None, argrepr = '', offset = 9, starts_line = None, is_jump_target = False)
Instruction(opname = 'LOAD_CONST', opcode = 100, arg = 0, argval = None, argrepr = 'None', offset = 10, starts_line = None, is_jump_target = False)
Instruction(opname = 'RETURN_VALUE', opcode = 83, arg = None, argval = None, argrepr = '', offset = 13, starts_line = None, is_jump_target = False)

code_info()

此函数返回Python代码对象的信息。

>>> dis.code_info(hello)
"Name: hello\nFilename: <pyshell#2>\nArgument count: 0\nKw-only arguments: 0\nNumber of locals: 0\nStack size: 2\nFlags: OPTIMIZED, NEWLOCALS, NOFREE\nConstants:\n 0: None\n 1: 'hello world'\nNames:\n 0: print"

show_code()

此函数打印Python模块,函数或类的详细代码信息。

>>> dis.show_code(hello)
Name: hello
Filename: <pyshell#2>
Argument count: 0
Kw-only arguments: 0
Number of locals: 0
Stack size: 2
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: None
   1: 'hello world'
Names:
   0: print

拆卸()

该函数反汇编一个代码对象,并提供划分为以下各列的输出-

  • 行号,用于每行的第一条指令

  • 当前指令,表示为->,

  • 带标签的指令,用>>表示

  • 指令的地址,

  • 操作代码名称,

  • 操作参数,以及

  • 括号中参数的解释。

>>> codeInString = 'a = 5\nb = 6\nsum = a + b \ nprint("sum = ",sum)'
>>> codeObejct = compile(codeInString, 'sumstring', 'exec')
>>> dis.disassemble(codeObejct)

输出结果

1    0 LOAD_CONST 0 (5)
     3 STORE_NAME 0 (a)
2    6 LOAD_CONST 1 (6)
     9 STORE_NAME 1 (b)
3    12 LOAD_NAME 0 (a)
     15 LOAD_NAME 1 (b)
     18 BINARY_ADD
     19 STORE_NAME 2 (sum)
4    22 LOAD_NAME 3 (print)
     25 LOAD_CONST 2 ('sum =')
     28 LOAD_NAME 2 (sum)
     31 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
     34 POP_TOP
     35 LOAD_CONST 3 (None)
     38 RETURN_VALUE

get_instructions()

该函数在提供的函数,方法,源代码字符串或代码对象中的指令上返回迭代器。迭代器生成一系列名为元组的指令,在提供的代码中给出每个操作的详细信息。

>>> it=dis.get_instructions(code)
>>> for i in it:
      print (i)
Instruction(opname = 'LOAD_CONST', opcode = 100, arg = 0, argval = <code object hello at 0x02A9BA70,
   file "<disassembly>", line 2>, argrepr = '<code object hello at 0x02A9BA70, file "<disassembly>",
   line 2>', offset = 0, starts_line = 2, is_jump_target = False)
Instruction(opname = 'LOAD_CONST', opcode = 100, arg = 1, argval = 'hello', argrepr = "'hello'", offset = 3, starts_line = None, is_jump_target = False)
Instruction(opname = 'MAKE_FUNCTION', opcode = 132, arg = 0, argval = 0, argrepr = '', offset = 6, starts_line = None, is_jump_target = False)
Instruction(opname = 'STORE_NAME', opcode = 90, arg = 0, argval = 'hello', argrepr = 'hello', offset = 9, starts_line = None, is_jump_target = False)
Instruction(opname = 'LOAD_CONST', opcode = 100, arg = 2, argval = None, argrepr = 'None', offset = 12, starts_line = None, is_jump_target = False)
Instruction(opname = 'RETURN_VALUE', opcode = 83, arg = None, argval = None, argrepr = '', offset = 15, starts_line = None, is_jump_target = False)

函数信息是元组形式的对象,其参数如下所示-

指令
字节码操作的详细信息
操作码
用于操作的数字代码,与下面列出的操作码值和操作码集合中的字节码值相对应。
操作名
易读的操作名称
精氨酸
操作的数字参数(如果有),否则为无
阿格瓦尔
解析的arg值(如果已知),否则与arg相同
阿格雷普
可读的操作参数描述
抵消
字节码序列内的操作开始索引
starts_line
该操作码(如果有)开头的行,否则为None
is_jump_target
如果其他代码跳到此处,则为True,否则为False