【问题标题】:JUMP_FORWARD or JUMP_ABSOLUTE with IF statement ? Python 2.5JUMP_FORWARD 或 JUMP_ABSOLUTE 与 IF 语句?蟒蛇2.5
【发布时间】:2013-04-17 02:30:08
【问题描述】:

我一直在使用“dis”模块来重新编写一些已编译的脚本 (.pyc)。我了解 JUMP_FORWARD 和 JUMP_ABSOLUTE 之间的区别。据我所知,IF 语句将由 JUMP_FORWARD 结束:

>>> def f():
        if a:
                print ''
>>> from dis import dis
>>> dis(f)
  2           0 LOAD_GLOBAL              0 (a)
              3 JUMP_IF_FALSE            9 (to 15)
              6 POP_TOP             

  3           7 LOAD_CONST               1 ('')
             10 PRINT_ITEM          
             11 PRINT_NEWLINE       
             12 JUMP_FORWARD             1 (to 16)
        >>   15 POP_TOP             
        >>   16 LOAD_CONST               0 (None)
             19 RETURN_VALUE    

如果 IF 语句位于另一个循环的末尾,则会出现 JUMP_ABSOLUTE。例如:

>>> def f1():
    if a:
        if b:
            print ''
>>> dis(f1)
  2           0 LOAD_GLOBAL              0 (a)
              3 JUMP_IF_FALSE           20 (to 26)
              6 POP_TOP             

  3           7 LOAD_GLOBAL              1 (b)
             10 JUMP_IF_FALSE            9 (to 22)
             13 POP_TOP             

  4          14 LOAD_CONST               1 ('')
             17 PRINT_ITEM          
             18 PRINT_NEWLINE       
             19 JUMP_ABSOLUTE           27
        >>   22 POP_TOP             
             23 JUMP_FORWARD             1 (to 27)
        >>   26 POP_TOP             
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        

从我读回写回代码的字节码中,有一个让我吃惊的 JUMP_ABSOLUTE:

121         228 LOAD_FAST               11 (a)
            231 LOAD_CONST               9 (100)
            234 COMPARE_OP               0 (<)
            237 JUMP_IF_FALSE           23 (to 263)
            240 POP_TOP             
            241 LOAD_FAST               11 (b)
            244 LOAD_CONST              11 (10)
            247 COMPARE_OP               4 (>)
            250 JUMP_IF_FALSE           10 (to 263)
            253 POP_TOP             

122         254 LOAD_CONST               3 (1)
            257 STORE_FAST               4 (ok)
            260 JUMP_ABSOLUTE           27
        >>  263 POP_TOP      

我认为代码如下:

if a<100 and b>10:
            ok=1

但它会引发 JUMP_FORWARD 而不是 JUMP_ABSOLUTE。我知道这不是 WHILE 循环,也不是 FOR 语句,因为它们都在字节码中创建了 SETUP_LOOP 行。

我的问题是:我错过了什么?为什么我得到的是 FORWARD 而不是 ABSOLUTE 跳转?

编辑:到索引 27 的绝对跳转指向(WHILE?)循环的开始,这两条线 121 和 122 属于:

106          24 SETUP_LOOP             297 (to 324)
        >>   27 LOAD_FAST                4 (ok)
             30 LOAD_CONST               1 (0)
             33 COMPARE_OP               2 (==)
             36 JUMP_IF_FALSE          283 (to 322)
             39 POP_TOP   

      

在这些行之前和之后有一个 IF 语句。这是之前的代码,同样的 JUMP_ABSOLUTE 关闭了语句。

115         170 LOAD_FAST                3 (q)
            173 LOAD_CONST              10 (1)
            176 COMPARE_OP               0 (<)
            179 JUMP_IF_FALSE           45 (to 227)
            182 POP_TOP             
            183 LOAD_FAST               11 (z)
            186 LOAD_CONST              11 (10)
            189 COMPARE_OP               4 (>)
            192 JUMP_IF_FALSE           32 (to 227)
            195 POP_TOP             

116         196 LOAD_CONST               1 (0)
            199 STORE_FAST               4 (ok)

117         202 LOAD_FAST                5 (u)
            205 LOAD_CONST               3 (1)
            208 BINARY_ADD          
            209 STORE_FAST               5 (u)

118         212 LOAD_CONST               1 (0)
            215 STORE_FAST               3 (k)

119         218 LOAD_CONST               3 (10)
            221 STORE_FAST               6 (dv)
            224 JUMP_ABSOLUTE           27
        >>  227 POP_TOP             

JUMP_FORWARD 表示“转到下一行”,JUMP_ABSOLUTE 表示“回到 WHILE 循环的开头”。问题是我不知道如何复制可以提供与上述相同字节码的代码。

谢谢!

【问题讨论】:

  • 您的.pyc 是否使用与您现在使用的相同版本的 Python 创建?那是哪个版本?
  • 我很确定它是用 Python 2.5 创建的,我现在正在使用。我检查了幻数。
  • 你提到你知道这不是一个循环。但是 JUMP_ABSOLUTE 27 表示跳转将带您回到代码中很长的路要走。您是否回溯到索引为 27 的操作码以查看它实际跳回的位置,以确保这不是循环?包含更多反汇编代码以提供完整图片可能会有所帮助,尤其是这样可以查看跳转到的位置。
  • IF 语句实际上是在 WHILE 循环内,绝对跳转指向它的初始化,我在帖子中添加了更多代码。感谢@ReinierTorenbeek 抽出宝贵时间
  • 我更新了答案以反映您的更改,但这是一个乏味的过程,我想知道您的最终目标是什么。也许你应该试试uncompyle?它是“用 Python 2.7 编写的 Python 2.5、2.6、2.7 字节码反编译器”。我自己没有尝试过,但会对您的体验感兴趣。

标签: python if-statement bytecode


【解决方案1】:

我接受了挑战,并在您的帮助下使用以下(废话)功能重现了您的情况(或非常相似的情况):

>>> def f():
...    while ok==0:
...      if q<1 and z>10:
...        ok=0
...        u=u+1
...        k=0
...        dv=10
...      elif a<100 and b>10:
...        ok=1
...
>>> dis(f)
  2           0 SETUP_LOOP             112 (to 115)
        >>    3 LOAD_FAST                0 (ok)
              6 LOAD_CONST               1 (0)
              9 COMPARE_OP               2 (==)
             12 JUMP_IF_FALSE           98 (to 113)
             15 POP_TOP

  3          16 LOAD_GLOBAL              0 (q)
             19 LOAD_CONST               2 (1)
             22 COMPARE_OP               0 (<)
             25 JUMP_IF_FALSE           45 (to 73)
             28 POP_TOP
             29 LOAD_GLOBAL              1 (z)
             32 LOAD_CONST               3 (10)
             35 COMPARE_OP               4 (>)
             38 JUMP_IF_FALSE           32 (to 73)
             41 POP_TOP

  4          42 LOAD_CONST               1 (0)
             45 STORE_FAST               0 (ok)

  5          48 LOAD_FAST                1 (u)
             51 LOAD_CONST               2 (1)
             54 BINARY_ADD
             55 STORE_FAST               1 (u)

  6          58 LOAD_CONST               1 (0)
             61 STORE_FAST               2 (k)

  7          64 LOAD_CONST               3 (10)
             67 STORE_FAST               3 (dv)
             70 JUMP_ABSOLUTE            3
        >>   73 POP_TOP

  8          74 LOAD_GLOBAL              2 (a)
             77 LOAD_CONST               4 (100)
             80 COMPARE_OP               0 (<)
             83 JUMP_IF_FALSE           23 (to 109)
             86 POP_TOP
             87 LOAD_GLOBAL              3 (b)
             90 LOAD_CONST               3 (10)
             93 COMPARE_OP               4 (>)
             96 JUMP_IF_FALSE           10 (to 109)
             99 POP_TOP

  9         100 LOAD_CONST               2 (1)
            103 STORE_FAST               0 (ok)
            106 JUMP_ABSOLUTE            3
        >>  109 POP_TOP
            110 JUMP_ABSOLUTE            3
        >>  113 POP_TOP
            114 POP_BLOCK
        >>  115 LOAD_CONST               0 (None)
            118 RETURN_VALUE

第 8 行和第 11 行包含您要求的 JUMP_ABSOLUTELOAD_GLOBALLOAD_FAST 之类的细微差别是由变量的范围引起的。

请注意,我必须切换到 Python 2.5 才能重现这一点。较新的版本会产生不同的结果。

如果continue似乎不适用于您的情况,我建议您在Python的源代码中进行一些研究,并在Python/compile.c中查找ADDOP_JABS,以了解在其他情况下绝对跳转是什么插入。

如果您的目标是“仅仅”反编译这个.pyc,那么您应该尝试uncompyle2,它自称“A Python 2.5、2.6、2.7 字节码反编译器,用 Python 2.7 编写”

【讨论】:

  • 我还没想过用continue,差不多就解决了!问题是它没有删除由 IF 语句引起的JUMP_FORWARD,它添加了一个绝对跳转。第 8 行的 JUMP_FORWARD 仍然指向下一行。
  • 虽然您已经接受了答案(谢谢)我更新了答案并插入了您自己的elif 建议以供将来参考。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
相关资源
最近更新 更多