当前位置: 首页 > 面试题库 >

我应该如何理解dis.dis的输出?

昝存
2023-03-14
问题内容

我想了解如何使用dis(Python字节码的反汇编程序)。具体来说,应该如何解释dis.dis(或dis.disassemble)的输出?

这是一个非常具体的示例(在Python 2.7.3中):

dis.dis("heapq.nsmallest(d,3)")

      0 BUILD_SET             24933
      3 JUMP_IF_TRUE_OR_POP   11889
      6 JUMP_FORWARD          28019 (to 28028)
      9 STORE_GLOBAL          27756 (27756)
     12 LOAD_NAME             29811 (29811)
     15 STORE_SLICE+0  
     16 LOAD_CONST            13100 (13100)
     19 STORE_SLICE+1

我看到JUMP_IF_TRUE_OR_POP等是字节码指令
(尽管有趣的是,BUILD_SET它没有出现在此列表中,尽管我希望它可以作为BUILD_TUPLE。我认为右侧的数字是内存分配,而左侧的数字是goto数字…我注意到它们每次
几乎 增加3(但不是完全一样)。

如果我包装dis.dis("heapq.nsmallest(d,3)")一个函数:

def f_heapq_nsmallest(d,n):
    return heapq.nsmallest(d,n)

dis.dis("f_heapq(d,3)")

      0 BUILD_TUPLE            26719
      3 LOAD_NAME              28769 (28769)
      6 JUMP_ABSOLUTE          25640
      9 <44>                                      # what is <44> ?  
     10 DELETE_SLICE+1 
     11 STORE_SLICE+1

问题答案:

您正在尝试拆解内含源代码的字符串,但是这不支持dis.dis在Python
2.用字符串参数,它把字符串,如果它包含字节码(见函数disassemble_stringdis.py)。因此,您会看到基于将源代码误解为字节码而产生的无意义的输出。

Python 3中的情况有所不同,Python
3在反汇编之前先dis.dis编译字符串参数:

Python 3.2.3 (default, Aug 13 2012, 22:28:10) 
>>> import dis
>>> dis.dis('heapq.nlargest(d,3)')
  1           0 LOAD_NAME                0 (heapq) 
              3 LOAD_ATTR                1 (nlargest) 
              6 LOAD_NAME                2 (d) 
              9 LOAD_CONST               0 (3) 
             12 CALL_FUNCTION            2 
             15 RETURN_VALUE

在Python 2中,您需要先自行编译代码,然后再将其传递给dis.dis

Python 2.7.3 (default, Aug 13 2012, 18:25:43) 
>>> import dis
>>> dis.dis(compile('heapq.nlargest(d,3)', '<none>', 'eval'))
  1           0 LOAD_NAME                0 (heapq)
              3 LOAD_ATTR                1 (nlargest)
              6 LOAD_NAME                2 (d)
              9 LOAD_CONST               0 (3)
             12 CALL_FUNCTION            2
             15 RETURN_VALUE

这些数字是什么意思?数1在最左边是在从其中该字节代码被编译的源代码的行号。左列中的数字是指令在字节码中的偏移量,而右列中的数字是 opargs
。让我们看一下实际的字节码:

>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'

我们在字节码的偏移量0处找到了oparg65的操作码; 那么(在偏移量3处)是操作码,操作参数,以此类推。请注意,opargs的顺序为little-
endian,即数字1。未记录的模块包含一些表,这些表为您提供每个操作码的名称,并为您提供每个名称的操作码:LOAD_NAME``0000``6a``LOAD_ATTR``0100``0100``opcode``opname``opmap

>>> opcode.opname[0x65]
'LOAD_NAME'

oparg的含义取决于操作码,对于全文,您需要阅读中的CPython虚拟机的实现ceval.c。ForLOAD_NAMELOAD_ATTRoparg是co_names代码对象属性的索引:

>>> co.co_names
('heapq', 'nlargest', 'd')

因为LOAD_CONST它是co_consts代码对象属性的索引:

>>> co.co_consts
(3,)

对于CALL_FUNCTION,它是传递给函数的参数数目,以16位编码,低字节为普通参数的数目,高字节为关键字参数的数目。



 类似资料:
  • 我想了解如何使用dis(Python字节码的伪装者),具体来说,应该如何解释(或)的输出? . 下面是一个非常具体的例子(在Python 2.7.3中): 我看到等是字节码指令(尽管有趣的是,没有出现在这个列表中,尽管我希望它作为工作)。我认为右手边的数字是内存分配,左边的数字是goto数字...我注意到它们每次几乎增加3(但不完全是)。 如果我将包装在函数中:

  • 问题内容: 有人可以为我指出一份良好的初学者指南,以安全地运行部分由用户输入构成的SQL查询吗?我正在使用Java,但是语言无关的指南也很好。 期望的行为是,如果有人在GUI中键入类似 数据库应将其视为文字字符串,并安全地存储它而不会删除任何表。 问题答案: 您肯定要使用PreparedStatement。他们很方便。这是一个例子。

  • 问题内容: 我正在学习MySQL并尝试使用子句。当我如下使用它时: 我收到以下错误: MySQL服务器正在使用–secure-file-priv选项运行,因此它无法执行此语句 我该如何解决这个错误? 我已经检查了关于同一错误消息的另一个问题,但仍然找不到解决方案。 我正在使用MySQL 5.6 问题答案: 它按预期工作。您的MySQL服务器已使用--secure-file- priv 选项启动,该

  • 例如,我有这样的代码 如何将“\on the”替换为replace eAll()?

  • 问题内容: 我有一种算法,当前会分配很大的双精度数组,它会经常更新和搜索。数组的大小为N ^ 2/2,其中N是算法在其上进行操作的行数。为了与算法周围的应用程序相关联,我还必须保留整个内容的副本。 当然,这对我的算法可以处理的行数施加了限制,因为我要应对堆的限制。到现在为止,我还没有要求使用该算法的人员更新- Xmx设置以分配更多的空间,并且效果很好。但是,我现在遇到了一个真正的问题,我需要此数组

  • 问题内容: Java开发人员大家好, 我知道这个主题可能有点,因为JDK8尚未发布(无论如何现在还没有。),但是我正在阅读一些有关Lambda表达式的文章,尤其是与与称为Stream的新集合API相关的部分。 这是《Java杂志》文章中给出的示例(这是一种水獭种群算法。): 我的问题是,如果在Set内部迭代的中间,水獭之一为null,会发生什么情况? 我希望抛出NullPointerExcepti