8

我一直在使用' 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 循环的开头”。问题是我不知道如何复制可以提供与上述相同字节码的代码。

谢谢 !

4

1 回答 1

4

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

>>> 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_ABSOLUTE您要求的内容。LOAD_GLOBAL像vs这样的细微差别LOAD_FAST是由变量的范围引起的。

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

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

如果您的目标是“只是”反编译 this .pyc,那么您应该尝试uncompyle2,它将自己描述为“A Python 2.5、2.6、2.7 字节码反编译器,用 Python 2.7 编写”

于 2013-04-17T15:00:02.693 回答