JUMP_FORWARD or JUMP_ABSOLUTE with IF statement? Python 2.5

I used the dis ' module to overwrite the compiled script (.pyc). I understand the difference between JUMP_FORWARD and JUMP_ABSOLUTE. As far as I know, the IF statement will be closed by 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 

And JUMP_ABSOLUTE will appear if the IF statement is at the end of another loop. For example:

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

From the Bytecode I'm reading for writing code, there is JUMP_ABSOLUTE that surprises me:

 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 

I think the code is as follows:

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

but it calls JUMP_FORWARD, not JUMP_ABSOLUTE. I know this is not a WHILE loop, not a FOR statement, because they both create a SETUP_LOOP string in Bytecode.

My question is: what am I missing? Why do I get FORWARD instead of ABSOLUTE transition?

EDIT: An absolute jump to index 27 indicates the beginning of a loop (WHILE?), In which the two lines 121 and 122 belong:

 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 

Before this line there is an IF-operator and one more. Here is the code before, with the same closure of the JUMP_ABSOLUTE statement.

 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 says go to the next line, and JUMP_ABSOLUTE says go back to the beginning of the WHILE loop. The problem is that I don’t know how to replicate the code that will give the same bytecode as above.

Thanks!

+7
source share
1 answer

I took the call and with your help I was able to reproduce your situation (or something very similar) using the following (meaningless) function:

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

Lines 8 and 11 have the JUMP_ABSOLUTE you requested. Slight differences, such as LOAD_GLOBAL compared to LOAD_FAST , are caused by the variable scope.

Note that I had to switch to Python 2.5 in order to reproduce this. New versions give different results.

If continue doesn't seem to apply to your situation, I suggest you do some research in the Python source code and look for ADDOP_JABS in Python/compile.c to find out in what other cases the absolute jump is inserted.

If your goal is to β€œsimply” decompile this .pyc , then you should try uncompyle2 , which describes itself as β€œA Python 2.5, 2.6, 2.7 bytecode decompiler written in Python 2.7”

+3
source

All Articles