2013-04-17 14 views
7

Używam modułu "dis", aby ponownie napisać skompilowany skrypt (.pyc). Rozumiem różnicę między JUMP_FORWARD i JUMP_ABSOLUTE. Według mojej wiedzy instrukcji IF będzie zamknięty przez JUMP_FORWARD:JUMP_FORWARD lub JUMP_ABSOLUTE z instrukcją IF? Python 2.5

>>> 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  

A JUMP_ABSOLUTE pojawi się, jeśli oświadczenie IF jest na końcu innej pętli. Na przykład:

>>> 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   

Z Bytecode czytam odpisać kod, istnieje JUMP_ABSOLUTE która mnie zaskakuje:

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  

Myślę kod jest następujący:

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

ale powoduje to JUMP_FORWARD, a nie JUMP_ABSOLUTE. Wiem, że nie jest to pętla WHILE, ani instrukcja FOR, ponieważ oba tworzą linię SETUP_LOOP w kodzie Bajt.

Moje pytanie brzmi: czego mi brakuje? dlaczego dostaję DO PRZODU zamiast skoku ABSOLUTE?

EDIT: absolutny skok do indeksu 27 punktów na początku (gdy?) Pętli, w którym te dwie linie 121 i 122 należą do:

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 

Jest IF-oświadczenie przed i innym jeden po tych liniach. Oto kod wcześniej, z tym samym JUMP_ABSOLUTE zamykającym instrukcję.

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 mówi „przejść do następnej linii” i JUMP_ABSOLUTE mówi „wróć do początku pętli while”. Problem polega na tym, że nie wiem, jak skopiować kod, który dałby ten sam kod bajtowy, jak powyżej.

Dziękujemy!

+0

był twój ' .pyc' stworzone z tą samą wersją Pythona, jakiego używasz teraz? Która to jest wersja? –

+0

Jestem całkiem pewien, że został utworzony za pomocą Pythona 2.5, tego samego używam właśnie teraz.Sprawdziłem magiczną liczbę. – Alex

+0

Wspomniałeś, że wiesz, że to nie jest pętla. Ale JUMP_ABSOLUTE 27 wskazuje, że skok zabiera cię z powrotem daleko w kodzie. Czy wyglądałeś tak daleko jak opcode z indeksem 27, aby zobaczyć, do czego faktycznie wskakiwał, aby upewnić się, że to nie jest pętla? Korzystne może być dodanie większej ilości zdemontowanego kodu, aby uzyskać pełny obraz, zwłaszcza, że ​​można zobaczyć, do czego przeskakuje. –

Odpowiedz

3

wziąłem wyzwanie iz waszą pomocą udało się odtworzyć sytuację (lub coś bardzo podobnego), wykonując poniższą (nonsense) Funkcja:

>>> 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 

linie 8 i 11 mają JUMP_ABSOLUTE że pytałeś dla. Nieznaczne różnice, takie jak LOAD_GLOBAL i LOAD_FAST, są spowodowane zakresem zmiennych.

Zauważ, że musiałem przejść na Python 2.5, aby to odtworzyć. Nowsze wersje dają różne wyniki.

Jeśli continue nie wydaje się mieć zastosowanie do sytuacji, proponuję zrobić rozeznanie w kodzie źródłowym Pythona i szukać ADDOP_JABS w Python/compile.c aby dowiedzieć się, w jakich innych przypadkach wprowadza absolutny skok.

Jeśli twoim celem jest „tylko” dekompilować tego .pyc, należy spróbować uncompyle2, który opisuje siebie jako „Python 2.5, 2.6, 2.7 bajt-kodu dekompilator, napisany w Pythonie 2.7”

+0

Nie myślałem o użyciu 'continue', to prawie rozwiązanie! Problem polega na tym, że nie usuwa "JUMP_FORWARD" spowodowanego przez instrukcję IF, dodaje skok bezwzględny. Nadal masz 'JUMP_FORWARD' na linii 8 wskazując na następną linię. – Alex

+0

Mimo, że już zaakceptowałeś odpowiedź (dziękuję), zaktualizowałem odpowiedź i wstawiłem twoją własną sugestię 'elif' na przyszłość. –

Powiązane problemy