当前位置: 首页 > 知识库问答 >
问题:

我应该如何理解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 

共有2个答案

徐兴昌
2023-03-14

我正在重新发布另一个问题的答案,以确保在搜索dis时找到答案。dis()

为了完成伟大的加雷斯·里斯的答案,这里只是一个小小的逐列摘要来解释分解字节码的输出。

例如,给定此函数:

def f(num):
    if num == 42:
        return True
    return False

这可以分解为(Python 3.6):

erlang prettyprint-override">(1)|(2)|(3)|(4)|          (5)         |(6)|  (7)
---|---|---|---|----------------------|---|-------
  2|   |   |  0|LOAD_FAST             |  0|(num)
   |-->|   |  2|LOAD_CONST            |  1|(42)
   |   |   |  4|COMPARE_OP            |  2|(==)
   |   |   |  6|POP_JUMP_IF_FALSE     | 12|
   |   |   |   |                      |   |
  3|   |   |  8|LOAD_CONST            |  2|(True)
   |   |   | 10|RETURN_VALUE          |   |
   |   |   |   |                      |   |
  4|   |>> | 12|LOAD_CONST            |  3|(False)
   |   |   | 14|RETURN_VALUE          |   |

每一栏都有一个特定的目的:

  1. 源代码中相应的行号
华峰
2023-03-14

您正在尝试反汇编包含源代码的字符串,但Python中的dis.dis不支持此操作

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是编译此字节码的源代码中的行号。左侧列中的数字是字节码中指令的偏移量,右侧的数字是oparg。让我们看看实际的字节码:

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

在字节码的偏移量0处,我们找到65,操作码为LOAD_NAME,操作码为0000;然后(在偏移量3处)6a是操作码LOAD_ATTR,操作码为0100,以此类推。请注意,操作码的顺序是小端,因此,0100是数字1。未文档化的操作码模块包含表,为每个操作码提供名称,为每个操作码提供操作码:

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

oparg的含义取决于操作码,对于完整的故事,您需要阅读ceval中的CPython虚拟机的实现。c。对于LOAD_NAMELOAD_ATTR而言,oparg是代码对象的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(但不是完全一样)。 如果我包装一个函数: 问题答案: 您正

  • 问题内容: 我写了一个小小的go脚本,并使用strace跟踪了该脚本,我试图使用netlink协议从内核中获取审核消息,就像auditd一样。 以下是我的旅途中strace的输出脚本- http://paste.ubuntu.com/8272760/ 我试图找到auditd提供给sendto函数的参数。当我在auditd上运行strace时,我得到以下输出 当我追踪我的go文件时,我得到以下输出。

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

  • 我试图理解输出,以便更好地调试。 我对这些看似随机生成的字母数字字符串的含义感到困惑。 例如: 我相信下面的字符串是图像ID。 剩下的是什么?什么是层次?每次我对Dockerfile稍作修改后构建时,它们似乎都会重新构建 从“装载”是什么意思?

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

  • 本文向大家介绍详解如何在Go项目中输出版本信息,包括了详解如何在Go项目中输出版本信息的使用技巧和注意事项,需要的朋友参考一下 我们经常在使用CLI工具的时候,都会有这样的参数输出: 可以打印出构建时对应的版本信息,比如 Version,Go Version,Git Commit等,这个是如何实现的呢? 实现 主要是通过ldflags参数来实现在构建的时候对变量进行赋值。 比如下面一段代码: 构建