2013-04-17 40 views
7

Tôi đã sử dụng mô-đun 'dis' để viết lại một số tập lệnh được biên dịch (.pyc). Tôi hiểu sự khác biệt giữa JUMP_FORWARD và JUMP_ABSOLUTE. Theo hiểu biết của tôi một IF tuyên bố sẽ đóng cửa bởi một JUMP_FORWARD:JUMP_FORWARD hoặc JUMP_ABSOLUTE với câu lệnh 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  

Và JUMP_ABSOLUTE sẽ xuất hiện nếu IF tuyên bố là ở phần cuối của vòng lặp khác. Ví dụ:

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

Từ Bytecode Tôi đọc để viết lại mã, có một JUMP_ABSOLUTE rằng tôi ngạc nhiên:

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  

Tôi nghĩ rằng các mã như sau:

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

nhưng nó kích hoạt JUMP_FORWARD chứ không phải JUMP_ABSOLUTE. Tôi biết nó không phải là một vòng lặp WHILE, cũng như một câu lệnh FOR vì cả hai đều tạo ra một dòng SETUP_LOOP trong Bytecode.

Câu hỏi của tôi là: tôi đang thiếu gì? tại sao tôi nhận được FORWARD thay vì nhảy ABSOLUTE?

EDIT: Các bước nhảy tuyệt đối để chỉ số 27 điểm để khởi đầu của một (KHI?) Vòng lặp trong đó hai dòng 121 và 122 thuộc về:

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 

Có một IF-tuyên bố trước và khác một sau những dòng này. Đây là mã trước, với cùng một JUMP_ABSOLUTE đóng câu lệnh.

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 nói "đi tới dòng tiếp theo" và JUMP_ABSOLUTE nói "quay lại phần đầu của vòng WHILE". Vấn đề là tôi không biết làm thế nào để tái tạo một mã mà sẽ cung cấp cho cùng một bytecode như trên.

Cảm ơn bạn!

+0

Là bạn ' .pyc' được tạo bằng cùng phiên bản Python như bạn đang sử dụng? Phiên bản nào vậy? –

+0

Tôi khá chắc chắn nó đã được tạo bằng Python 2.5, giống như tôi đang sử dụng ngay bây giờ.Tôi đã kiểm tra số ma thuật. – Alex

+0

Bạn đã đề cập rằng bạn biết đây không phải là vòng lặp. Nhưng JUMP_ABSOLUTE 27 chỉ ra rằng bước nhảy đang đưa bạn trở lại khá lâu trong đoạn mã. Bạn đã nhìn xa như opcode với chỉ mục 27 để xem nó thực sự nhảy trở lại, để đảm bảo đây không phải là một vòng lặp? Nó có thể mang lại lợi ích khi bao gồm thêm mã tháo rời để cung cấp cho bức tranh hoàn chỉnh, đặc biệt là để có thể nhìn thấy nơi nhảy tới. –

Trả lời

3

Tôi đã thử thách và với sự giúp đỡ của bạn đã có thể để tái tạo tình hình của bạn (hoặc một cái gì đó rất giống nhau) bằng cách sử dụng sau đây (vô nghĩa) chức năng:

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

dòng 8 và 11 có JUMP_ABSOLUTE mà bạn đã yêu cầu cho. Các khác biệt nhỏ như LOAD_GLOBAL so với LOAD_FAST là do phạm vi của các biến.

Lưu ý rằng tôi phải chuyển sang Python 2.5 để tạo lại điều này. Các phiên bản mới hơn tạo ra các kết quả khác nhau.

Nếu continue dường như không áp dụng cho trường hợp của bạn, tôi đề nghị bạn thực hiện một số nghiên cứu trong mã nguồn của Python và tìm kiếm ADDOP_JABS trong Python/compile.c để tìm hiểu xem trường hợp nào khác được chèn vào.

Nếu mục tiêu của bạn là để "chỉ là" dịch ngược .pyc này, sau đó bạn nên cố gắng uncompyle2, trong đó mô tả chính nó như là "Một Python 2.5, 2.6, 2.7 byte-code decompiler, viết bằng Python 2.7"

+0

Tôi đã không nghĩ đến việc sử dụng 'tiếp tục', nó gần như là giải pháp! Vấn đề là nó không loại bỏ 'JUMP_FORWARD' gây ra bởi câu lệnh IF, nó thêm một bước nhảy tuyệt đối. Bạn vẫn có 'JUMP_FORWARD' trên dòng 8 trỏ tới dòng kế tiếp. – Alex

+0

Mặc dù bạn đã chấp nhận câu trả lời (cảm ơn) Tôi đã cập nhật câu trả lời và chèn đề xuất 'elif' của riêng bạn để tham khảo trong tương lai. –

Các vấn đề liên quan