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_firstlineno
和co_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 = TOS
。namei
是代码对象属性中名称
的索引co_names
。如果可能,编译器会尝试使用STORE_FAST或STORE_GLOBAL。
DELETE_NAME(namei)
实现del name
,其中namei
是co_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的操作码之间的分界线。