在线文档教程

dis

dis - 用于Python字节码的反汇编程序

源代码: Lib / dis.py

dis模块通过反汇编来支持CPython 字节码的分析。该模块用作输入的CPython字节码在文件中定义Include/opcode.h并由编译器和解释器使用。

CPython实现细节: Bytecode是CPython解释器的实现细节!没有保证不会在不同版本的Python之间添加,删除或更改字节码。不应该认为这个模块的使用适用于Python VM或Python发行版。

示例:给定函数myfunc()

def myfunc(alist): return len(alist)

可以使用以下命令来获得反汇编myfunc()

>>> dis.dis(myfunc) 2 0 LOAD_GLOBAL 0 (len) 3 LOAD_FAST 0 (alist) 6 CALL_FUNCTION 1 9 RETURN_VALUE

(“2”是行号)。

dis模块定义了以下功能和常量:

dis.dis([bytesource])

反汇编bytesource对象。bytesource可以表示模块,类,方法,函数或代码对象。对于一个模块,它会分解所有功能。对于一个班级,它会分解所有的方法。对于单个代码序列,每个字节代码指令打印一行。如果没有提供对象,则它会拆卸最后一个回溯。

dis.distb([tb])

反汇编堆栈的顶层函数,如果没有传递,则使用最后的回溯。指示引发异常的指令。

dis.disassemble(code[, lasti])

反汇编一个代码对象,指出如果提供了lasti的最后一条指令。输出分为以下几列:

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

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

  • 带标签的说明>>,

  • 指令的地址,

  • 操作代码名称,

  • 操作参数和

  • 括号中的参数解释。

参数解释可识别本地和全局变量名称,常量值,分支目标和比较运算符。

dis.disco(code[, lasti])

一个同义词disassemble()。键入更方便,并保持与早期Python版本的兼容性。

dis.findlinestarts(code)

这种发生器函数使用co_firstlinenoco_lnotab代码对象的属性代码到发现其是在源代码的行开始的偏移量。它们以(offset, lineno)成对的方式生成。

dis.findlabels(code)

检测作为跳转目标的代码对象代码 中的所有偏移量,并返回这些偏移量的列表。

dis.opname

操作名称的顺序,可使用字节码进行索引。

dis.opmap

字典映射操作名称到字节码。

dis.cmp_op

所有比较操作名称的顺序。

dis.hasconst

具有常数参数的字节码序列。

dis.hasfree

访问自由变量的字节码序列。

dis.hasname

通过名称访问属性的字节码序列。

dis.hasjrel

具有相对跳转目标的字节码序列。

dis.hasjabs

具有绝对跳转目标的字节码序列。

dis.haslocal

访问局部变量的字节码序列。

dis.hascompare

布尔运算的字节码序列。

1. Python字节码指令

Python编译器当前生成以下字节码指令。

STOP_CODE()

指示编译器的结束代码,不被解释器使用。

NOP()

不做任何代码。用作字节码优化器的占位符。

POP_TOP()

删除顶部堆栈(TOS)项目。

ROT_TWO()

交换两个最上面的堆栈项。

ROT_THREE()

将第二个和第三个堆叠物品向上提升一个位置,从上至下移动到第三个位置。

ROT_FOUR()

将第二,第三和第四个堆叠物品向上提升一个位置,从上到下移动到第四个位置。

DUP_TOP()

复制堆栈顶部的引用。

一元操作占据堆栈的顶部,应用操作并将结果推回到堆栈上。

UNARY_POSITIVE()

实现TOS = +TOS

UNARY_NEGATIVE()

实现TOS = -TOS

UNARY_NOT()

实现TOS = not TOS

UNARY_CONVERT()

实现TOS = `TOS`

UNARY_INVERT()

实现TOS = ~TOS

GET_ITER()

实现TOS = iter(TOS)

二进制操作会从堆栈中删除堆栈顶部(TOS)和第二个最顶端堆栈项(TOS1)。他们执行操作,并将结果放回堆栈。

BINARY_POWER()

实现TOS = TOS1 ** TOS

BINARY_MULTIPLY()

实现TOS = TOS1 * TOS

BINARY_DIVIDE()

from __future__ import division实施TOS = TOS1 / TOS。

BINARY_FLOOR_DIVIDE()

实现TOS = TOS1 // TOS

BINARY_TRUE_DIVIDE()

from __future__ import division实施TOS = TOS1 / TOS。

BINARY_MODULO()

实现TOS = TOS1 % TOS

BINARY_ADD()

实现TOS = TOS1 + TOS

BINARY_SUBTRACT()

实现TOS = TOS1 - TOS

BINARY_SUBSCR()

实现TOS = TOS1[TOS]

BINARY_LSHIFT()

实现TOS = TOS1 << TOS。

BINARY_RSHIFT()

实现TOS = TOS1 >> TOS。

BINARY_AND()

实现TOS = TOS1 & TOS

BINARY_XOR()

实现TOS = TOS1 ^ TOS

BINARY_OR()

实现TOS = TOS1 | TOS

就地操作就像二元操作,因为它们删除TOS和TOS1,并将结果重新放回堆栈,但操作在TOS1支持它时在原地完成,并且生成的TOS可能(但没有是)原来的TOS1。

INPLACE_POWER()

实现就地TOS = TOS1 ** TOS

INPLACE_MULTIPLY()

实现就地TOS = TOS1 * TOS

INPLACE_DIVIDE()

从from __future__ import division时,实施就地TOS = TOS1 / TOS。

INPLACE_FLOOR_DIVIDE()

实现就地TOS = TOS1 // TOS

INPLACE_TRUE_DIVIDE()

从_from __future__ import division时实施就地TOS = TOS1 / TOS。

INPLACE_MODULO()

实现就地TOS = TOS1 % TOS

INPLACE_ADD()

实现就地TOS = TOS1 + TOS

INPLACE_SUBTRACT()

实现就地TOS = TOS1 - TOS

INPLACE_LSHIFT()

实现就地TOS = TOS1 << TOS。

INPLACE_RSHIFT()

实现就地TOS = TOS1 >> TOS。

INPLACE_AND()

实现就地TOS = TOS1 & TOS

INPLACE_XOR()

实现就地TOS = TOS1 ^ TOS

INPLACE_OR()

实现就地TOS = TOS1 | TOS

切片操作码最多需要三个参数。

SLICE+0()

实现TOS = TOS[:]

SLICE+1()

实现TOS = TOS1[TOS:]

SLICE+2()

实现TOS = TOS1[:TOS]

SLICE+3()

实现TOS = TOS2[TOS1:TOS]

切片分配甚至需要额外的参数。至于任何声明,他们都没有放任何东西。

STORE_SLICE+0()

实现TOS[:] = TOS1

STORE_SLICE+1()

实现TOS1[TOS:] = TOS2

STORE_SLICE+2()

实现TOS1[:TOS] = TOS2

STORE_SLICE+3()

实现TOS2[TOS1:TOS] = TOS3

DELETE_SLICE+0()

实现del TOS[:]

DELETE_SLICE+1()

实现del TOS1[TOS:]

DELETE_SLICE+2()

实现del TOS1[:TOS]

DELETE_SLICE+3()

实现del TOS2[TOS1:TOS]

STORE_SUBSCR()

实现TOS1[TOS] = TOS2

DELETE_SUBSCR()

实现del TOS1[TOS]

其他操作码。

PRINT_EXPR()

为交互模式实现表达式语句。服务条款从堆栈中删除并打印。在非交互模式下,表达式语句以POP_TOP结束。

PRINT_ITEM()

将TOS打印到绑定到sys.stdout的类文件对象。 打印语句中的每个项目都有一个这样的指令。

PRINT_ITEM_TO()

类似于PRINT_ITEM,但将TOS中的项目从TOS打印到TOS中的类文件对象。这由扩展打印语句使用。

PRINT_NEWLINE()

打印新的一行sys.stdout。这是作为print语句的最后一个操作生成的,除非语句以逗号结尾。

PRINT_NEWLINE_TO()

类似于PRINT_NEWLINE,但在TOS上的文件类对象上打印新行。这由扩展打印语句使用。

BREAK_LOOP()

由于break声明而终止循环。

CONTINUE_LOOP(target)

由于continue陈述而继续循环。目标 是要跳转到的地址(这应该是一条FOR_ITER指令)。

LIST_APPEND(i)

调用list.append(TOS[-i], TOS)。用于实现列表推导。当附加值被弹出时,列表对象保留在堆栈上,以便它可用于循环的进一步迭代。

LOAD_LOCALS()

将引用推送到堆栈上当前作用域的当地人。这用于类定义的代码中:在对类体进行求值后,局部变量将被传递给类定义。

RETURN_VALUE()

将TOS返回给函数的调用者。

YIELD_VALUE()

弹出TOS并从发生器中产生它。

IMPORT_STAR()

将所有不以'_'开始的符号直接从模块TOS加载到本地命名空间。 加载所有名称后,模块弹出。 这个操作码从模块导入*实现。

EXEC_STMT()

实现exec TOS2,TOS1,TOS。编译器使用填充缺少的可选参数None

POP_BLOCK()

从块堆栈中删除一个块。每帧有一堆块,表示嵌套循环,try语句等等。

END_FINALLY()

终止一个finally条款。解释器回顾是否必须重新提出异常,或函数是否返回,并继续执行外部下一个块。

BUILD_CLASS()

创建一个新的类对象。TOS是方法字典,TOS1是基类名称的元组,TOS2是类名。

SETUP_WITH(delta)

该操作码在块启动之前执行多个操作。 首先,它从上下文管理器加载__exit __(),并将其压入堆栈以便稍后由WITH_CLEANUP使用。 然后,__enter __()被调用,并且指向delta的finally块被推入。 最后,调用enter方法的结果被压入堆栈。 下一个操作码将忽略它(POP_TOP),或将其存储在(a)个变量(STORE_FAST,STORE_NAME或UNPACK_SEQUENCE)中。

WITH_CLEANUP()

with语句块退出时清理堆栈。在堆栈顶部有1-3个值,指示如何/为什么输入finally子句:

  • TOP = None

  • (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval

  • TOP = WHY_*; 它下面没有retval

  • (TOP, SECOND, THIRD) = exc_info()

在它们下面是EXIT,上下文管理器的__exit__()绑定方法。

在最后一种情况下,EXIT(TOP, SECOND, THIRD)被调用,否则为EXIT(None, None, None)

从堆栈中删除EXIT,并将其上面的值保持相同的顺序。另外,如果堆栈 表示一个异常,并且 函数调用返回一个'true'值,那么这个信息将被“zapped”,以防止END_FINALLY重新引发异常。(但非本地gotos仍应该恢复。)

以下所有的操作码都需要参数。参数是两个字节,最后一个字节是更重要的字节。

STORE_NAME(namei)

实现name = TOSnamei是代码对象属性中名称的索引co_names。如果可能,编译器会尝试使用STORE_FAST或STORE_GLOBAL。

DELETE_NAME(namei)

实现del name,其中nameico_names代码对象的索引属性。

UNPACK_SEQUENCE(count)

解压缩到TOS 计算个人的价值 (放到堆栈从右到左)。

DUP_TOPX(count)

重复计数 项目,使它们保持相同的顺序。由于实施限制,计数应该在1到5之间(包括1和5)。

STORE_ATTR(namei)

实现TOS.name = TOS1,其中namei 是名称的索引co_names

DELETE_ATTR(namei)

实现del TOS.name,使用namei 作为索引co_names

STORE_GLOBAL(namei)

作为STORE_NAME那样工作,但将名称存储为全局名称。

DELETE_GLOBAL(namei)

作为DELETE_NAME那样工作,但删除全局名称。

LOAD_CONST(consti)

co_consts[consti]入堆栈。

LOAD_NAME(namei)

将关联的值co_names[namei]推入堆栈。

BUILD_TUPLE(count)

创建一个从堆栈中消耗计数 项的元组,并将生成的元组推入堆栈。

BUILD_LIST(count)

作为BUILD_TUPLE,但创建一个列表。

BUILD_SET(count)

作为BUILD_TUPLE,但创建一个集合。

2.7版本的新功能。

BUILD_MAP(count)

将新的字典对象推入堆栈。该字典预设大小以容纳计数条目。

LOAD_ATTR(namei)

getattr(TOS, co_names[namei])替换TOS 。

COMPARE_OP(opname)

执行布尔操作。操作名称可以在cmp_op[opname]中找到。

IMPORT_NAME(namei)

导入模块co_names [namei]。 TOS和TOS1弹出并提供__import __()的fromlist和level参数。 模块对象被压入堆栈。 当前名称空间不受影响:对于正确的导入语句,后续的STORE_FAST指令修改名称空间。

IMPORT_FROM(namei)

co_names[namei]从TOS中找到的模块加载属性。产生的对象被压入堆栈,随后被STORE_FAST指令存储。

JUMP_FORWARD(delta)

增量字节码计数器增量

POP_JUMP_IF_TRUE(target)

如果TOS为真,则将字节码计数器设置为目标。服务条款被弹出。

POP_JUMP_IF_FALSE(target)

如果TOS为false,则将字节码计数器设置为目标。服务条款被弹出。

JUMP_IF_TRUE_OR_POP(target)

如果TOS为真,则将字节码计数器设置为目标并将TOS保留在堆栈上。否则(TOS是错误的),TOS弹出。

JUMP_IF_FALSE_OR_POP(target)

如果TOS为false,则将字节码计数器设置为目标并将TOS保留在堆栈上。否则(TOS为真),TOS弹出。

JUMP_ABSOLUTE(target)

将字节码计数器设置为目标

FOR_ITER(delta)

TOS是一个迭代器。调用它的next()方法。如果这产生一个新值,把它推到堆栈上(将迭代器留在它下面)。如果迭代器指示已耗尽TOS,则字节码计数器将增量增量

LOAD_GLOBAL(namei)

将指定的全局加载co_names[namei]到堆栈上。

SETUP_LOOP(delta)

将块的一个循环推入块堆栈。块从当前指令跨越delta 字节的大小。

SETUP_EXCEPT(delta)

将try-except子句中的try块推入块堆栈。delta 指向第一个除了块。

SETUP_FINALLY(delta)

将try-except子句中的try块推入块堆栈。delta 指向finally块。

STORE_MAP()

将键值和值对存储在字典中。弹出键和值,同时将字典留在堆栈上。

LOAD_FAST(var_num)

将对本地的引用co_varnames[var_num]推入堆栈。

STORE_FAST(var_num)

将TOS存储在本地co_varnames[var_num]

DELETE_FAST(var_num)

删除本地co_varnames[var_num]

LOAD_CLOSURE(i)

将参照推送到单元格的槽位i中的单元格,并释放可变的存储空间。 如果 i 小于co_cellvars的长度,变量的名称是co_cellvars [i]。 否则它是co_freevars [我 - len(co_cellvars)]。

LOAD_DEREF(i)

加载单元格的槽位i中的单元格并释放可变的存储空间。将参考推送到单元包含在堆栈上的对象。

STORE_DEREF(i)

将TOS存储到单元格的槽位i中的单元格中并免费存储变量。

SET_LINENO(lineno)

这个操作码已经过时了。

RAISE_VARARGS(argc)

引发一个例外。argc表示raise语句的参数数量,范围从0到3.处理程序将查找回溯为TOS2,参数为TOS1,异常为TOS。

CALL_FUNCTION(argc)

调用一个函数。argc 的低字节表示位置参数的数量,高字节表示关键字参数的数量。在堆栈中,操作码首先查找关键字参数。对于每个关键字参数,该值都位于该键的顶部。在关键字参数下面,位置参数位于堆栈上,最右边的参数在最上面。在参数下面,要调用的函数对象位于堆栈上。弹出所有函数参数,并将函数本身从堆栈中弹出,并推送返回值。

MAKE_FUNCTION(argc)

推入堆栈中的新函数对象。TOS是与该功能相关的代码。函数对象被定义为具有argc默认参数,这些参数位于TOS下方。

MAKE_CLOSURE(argc)

创建一个新的函数对象,设置其func_closure插槽,并将其推入堆栈。TOS是与函数关联的代码,TOS1是包含闭包自由变量单元的元组。该函数还具有argc默认参数,这些参数位于单元格下方。

BUILD_SLICE(argc)

推入堆栈中的切片对象。 argc必须是2或3.如果是2,则切片(TOS1,TOS)被按下; 如果是3,则切片(TOS2,TOS1,TOS)被按下。 有关更多信息,请参见slice()内置函数。

EXTENDED_ARG(ext)

前缀任何操作码的参数太大,无法放入默认的两个字节。ext包含两个额外的字节,与后面的操作码参数一起构成一个四字节参数,ext是两个最重要的字节。

CALL_FUNCTION_VAR(argc)

调用一个函数。 argc被解释为在CALL_FUNCTION中。 堆栈顶部的元素包含变量参数列表,后跟关键字和位置参数。

CALL_FUNCTION_KW(argc)

调用一个函数。argc被解释为in CALL_FUNCTION。堆栈顶部的元素包含关键字参数字典,后跟明确的关键字和位置参数。

CALL_FUNCTION_VAR_KW(argc)

调用一个函数。argc被解释为 CALL_FUNCTION。堆栈顶部的元素包含关键字参数字典,其后跟随变量参数元组,接着是显式关键字和位置参数。

HAVE_ARGUMENT()

这不是一个真正的操作码。 它标识不带参数<HAVE_ARGUMENT的操作码和具有> = HAVE_ARGUMENT的操作码之间的分界线。