8

コンパイル済みスクリプト (.pyc) を書き直すために「 dis 」モジュールを使用しています。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_ABSOLUTE ではなく JUMP_FORWARD を引き起こします。どちらもバイトコードで SETUP_LOOP 行を作成するため、WHILE ループでも FOR ステートメントでもないことはわかっています。

私の質問は次のとおりです。何が欠けていますか? ABSOLUTE jump ではなく FORWARD jump を取得するのはなぜですか?

編集: インデックス 27 への絶対ジャンプは、これらの 2 つの行 121 と 122 が属する (WHILE?) ループの先頭を指します。

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_GLOBALvsのようなわずかな違いLOAD_FASTは、変数のスコープによって引き起こされます。

これを再現するには、Python 2.5 に切り替える必要があったことに注意してください。新しいバージョンでは、異なる結果が生成されます。

あなたcontinueの状況に当てはまらないと思われる場合は、Python のソース コードを調べて、他の場合に絶対ジャンプが挿入されているかどうかを調べることをお勧めしADDOP_JABSますPython/compile.c

あなたの目標がこれを「ただ」逆コンパイルすることである場合は、それ自体を「Python 2.7で書かれたPython 2.5、2.6、2.7バイトコード逆コンパイラ」と説明.pycする を試してください。uncompyle2

于 2013-04-17T15:00:02.693 に答える