2015-10-26 7 views
6

मैं सोच रहा था कि बाइट कोड को कैसे संशोधित किया जाए, फिर उस कोड को फिर से सम्मिलित करें ताकि मैं इसे फ़िथन में फ़ंक्शन के रूप में उपयोग कर सकूं? मैं कोशिश कर रहा है:पाइथन बाइटकोड संशोधित

a = """ 
def fact(): 
    a = 8 
    a = 0 
""" 
c = compile(a, '<string>', 'exec') 
w = c.co_consts[0].co_code 
dis(w) 

जो करने के लिए decompiles: मान मैं लाइनों 0 और 3 से छुटकारा पाने के लिए चाहते हैं

 0 LOAD_CONST   1 (1) 
     3 STORE_FAST   1 (1) 
     6 LOAD_CONST   2 (2) 
     9 STORE_FAST   1 (1) 
    12 LOAD_CONST   0 (0) 
    15 RETURN_VALUE 

, मैं फोन:

x = c.co_consts[0].co_code[6:16] 
dis(x) 

जिसमें परिणाम:

 0 LOAD_CONST   2 (2) 
     3 STORE_FAST   1 (1) 
     6 LOAD_CONST   0 (0) 
     9 RETURN_VALUE 

मेरी समस्या क्या है x के साथ करने के लिए, यदि मैं exec x का प्रयास करता हूं तो मुझे 'nullbytes के बिना अपेक्षित स्ट्रिंग मिलती है और मुझे exec w, x संकलित करने का प्रयास करने के लिए मिलता है परिणाम: संकलित() अपेक्षित स्ट्रिंग बिना शून्य बाइट्स के।

मुझे यकीन नहीं है कि आगे बढ़ने का सबसे अच्छा तरीका क्या है, सिवाय इसके कि मुझे किसी प्रकार का कोड-ऑब्जेक्ट बनाना होगा, लेकिन मुझे यकीन नहीं है कि, लेकिन मुझे लगता है कि यह संभव उर्फ ​​बाइटप्ले होना चाहिए, पायथन एंबलर एट अल

मैं अजगर 2.7.10 का उपयोग कर रहा हूं, लेकिन अगर यह संभव हो तो मैं भविष्य में संगत (जैसे पायथन 3) बनना चाहता हूं।

+0

मुझे उत्सुकता है कि आप ऐसा क्यों करेंगे, आपका उपयोग केस क्या है? – shuttle87

+1

पायथन बाइटकोड को एक कार्यान्वयन विस्तार माना जाता है और संस्करण से संस्करण और दुभाषिया को दुभाषिया में बदल सकता है। दुभाषिया स्रोत को छोड़कर कोई दस्तावेज नहीं है। क्या आप वास्तव में इसे करना चाहते हैं? – Antimony

+0

@ शटल 87, मैं स्क्रिप्ट के साथ एक गेम इंजन लिख रहा हूं जिसे मैं पाइथन में लिखने की उम्मीद कर रहा हूं, लेकिन मैं स्क्रिप्ट्स बाइटकोड पर कुछ ऑप्टिमाइज़ेशन चलाने के लिए चाहता हूं जो कमजोर बोलने से पहले ही ज्ञात नहीं होंगे (हालांकि मूल संरचना जाना जाता है क्योंकि वे सभी एक सामान्य आधार वर्ग साझा करते हैं)। मेरे पास अन्य सभी घटक काम कर रहे हैं, बस इस प्रयोज्य बाइटकोड को उपयोग करने योग्य फ़ंक्शन में अंतिम बाधा है। –

उत्तर

6

अद्यतन: सैंड्री कारणों से मैंने क्रॉस-पायथन-संस्करण असेंबलर लिखना शुरू कर दिया है। https://github.com/rocky/python-xasm देखें यह अभी भी बहुत शुरुआती बीटा में है।

जहाँ तक मुझे पता के रूप में वहाँ कोई वर्तमान में बनाए रखा अजगर कोडांतरक है। PEAK's Bytecode Disassembler पायथन 2.6 के लिए विकसित किया गया था, और बाद में प्रारंभिक पायथन 2.7 का समर्थन करने के लिए संशोधित किया गया।

यह documentation से बहुत अच्छा है। लेकिन यह अन्य पीक पुस्तकालयों पर निर्भर करता है जो समस्याग्रस्त हो सकते हैं।

मैं आपको पूरा करने के लिए एक उदाहरण देने के लिए पूरे उदाहरण के माध्यम से जाऊंगा। यह सुंदर नहीं है, लेकिन फिर आपको इसकी उम्मीद करनी चाहिए।

मूल रूप से बाइटकोड को संशोधित करने के बाद, आपको एक नया types.CodeType ऑब्जेक्ट बनाना होगा। आपको एक नया कारण चाहिए क्योंकि कोड प्रकार में कई ऑब्जेक्ट्स, अच्छे कारण के लिए, आप नहीं बदल सकते हैं। उदाहरण के लिए दुभाषिया में इन ऑब्जेक्ट मानों में से कुछ कैश हो सकते हैं।

कोड बनाने के बाद, आप इसे ऐसे कोडों में उपयोग कर सकते हैं जो कोड प्रकार का उपयोग करते हैं जिसका उपयोग exec या eval में किया जा सकता है।

या आप इसे एक बाइटकोड फ़ाइल में लिख सकते हैं। हां कोड प्रारूप Python 2 और पायथन 3 के बीच बदल गया है और वैसे भी अनुकूलन और बाइटकोड है। वास्तव में, पायथन 3.6 में वे शब्द कोड बाइटकोड नहीं होंगे।

3   0 LOAD_CONST    1 (8) 
       3 STORE_FAST    0 (a) 

    4   6 LOAD_CONST    2 (0) 
       9 STORE_FAST    0 (a) 

    5   12 LOAD_FAST    0 (a) 
      15 RETURN_VALUE 
============================== 
    3   0 LOAD_CONST    2 (0) 
       3 STORE_FAST    0 (a) 

    4   6 LOAD_FAST    0 (a) 
       9 RETURN_VALUE 
============================== 
('Result is', 0) 
    3   0 LOAD_CONST    2 (10) 
       3 STORE_FAST    0 (a) 

    4   6 LOAD_FAST    0 (a) 
       9 RETURN_VALUE 
============================== 
('Result is now', 10) 

सूचना है कि लाइन नंबर नहीं है:

a = """ 
def fact(): 
    a = 8 
    a = 0 
    return a 
""" 
c = compile(a, '<string>', 'exec') 
fn_code = c.co_consts[0] # Pick up the function code from the main code 
from dis import dis 
dis(fn_code) 
print("=" * 30) 

x = fn_code.co_code[6:16] # modify bytecode 

import types 
opt_fn_code = types.CodeType(fn_code.co_argcount, 
          # c.co_kwonlyargcount, Add this in Python3 
          fn_code.co_nlocals, 
          fn_code.co_stacksize, 
          fn_code.co_flags, 
          x, # fn_code.co_code: this you changed 
          fn_code.co_consts, 
          fn_code.co_names, 
          fn_code.co_varnames, 
          fn_code.co_filename, 
          fn_code.co_name, 
          fn_code.co_firstlineno, 
          fn_code.co_lnotab, # In general, You should adjust this 
          fn_code.co_freevars, 
          fn_code.co_cellvars) 
dis(opt_fn_code) 
print("=" * 30) 
print("Result is", eval(opt_fn_code)) 

# Now let's change the value of what's returned 
co_consts = list(opt_fn_code.co_consts) 
co_consts[-1] = 10 

opt_fn_code = types.CodeType(fn_code.co_argcount, 
          # c.co_kwonlyargcount, Add this in Python3 
          fn_code.co_nlocals, 
          fn_code.co_stacksize, 
          fn_code.co_flags, 
          x, # fn_code.co_code: this you changed 
          tuple(co_consts), # this is now changed too 
          fn_code.co_names, 
          fn_code.co_varnames, 
          fn_code.co_filename, 
          fn_code.co_name, 
          fn_code.co_firstlineno, 
          fn_code.co_lnotab, # In general, You should adjust this 
          fn_code.co_freevars, 
          fn_code.co_cellvars) 

dis(opt_fn_code) 
print("=" * 30) 
print("Result is now", eval(opt_fn_code)) 

जब मैं इस यहाँ भाग गया मैं क्या मिल गया है:

तो यहाँ आप अपने उदाहरण के लिए क्या करना होगा क्या है हालांकि मैंने कोड में दो पंक्तियों को हटा दिया। ऐसा इसलिए है क्योंकि मैंने fn_code.co_lnotab अपडेट नहीं किया था।

यदि आप अब से एक पायथन बाइटकोड फ़ाइल लिखना चाहते हैं। आपको यह होता क्या है:

co_consts = list(c.co_consts) 
co_consts[0] = opt_fn_code 
c1 = types.CodeType(c.co_argcount, 
        # c.co_kwonlyargcount, Add this in Python3 
        c.co_nlocals, 
        c.co_stacksize, 
        c.co_flags, 
        c.co_code, 
        tuple(co_consts), 
        c.co_names, 
        c.co_varnames, 
        c.co_filename, 
        c.co_name, 
        c.co_firstlineno, 
        c.co_lnotab, # In general, You should adjust this 
        c.co_freevars, 
        c.co_cellvars) 

from struct import pack 
with open('/tmp/testing.pyc', 'w') as fp: 
     fp.write(pack('Hcc', 62211, '\r', '\n')) # Python 2.7 magic number 
     import time 
     fp.write(pack('I', int(time.time()))) 
     # In Python 3 you need to write out the size mod 2**32 here 
     import marshal 
     fp.write(marshal.dumps(c1)) 

लिख ऊपर बॉयलरप्लेट बाईटकोड, मैं करने के लिए कहा जाता है xdiswrite_python_file() एक नियमित जोड़ दिया है आसान बनाने के लिए।

अब परिणामों की जांच करने के लिए:

$ uncompyle6 /tmp/testing.pyc 
# uncompyle6 version 2.9.2 
# Python bytecode 2.7 (62211) 
# Disassembled from: Python 2.7.12 (default, Jul 26 2016, 22:53:31) 
# [GCC 5.4.0 20160609] 
# Embedded file name: <string> 
# Compiled at: 2016-10-18 05:52:13 


def fact(): 
    a = 0 
# okay decompiling /tmp/testing.pyc 
$ pydisasm /tmp/testing.pyc 
# pydisasm version 3.1.0 
# Python bytecode 2.7 (62211) disassembled from Python 2.7 
# Timestamp in code: 2016-10-18 05:52:13 
# Method Name:  <module> 
# Filename:   <string> 
# Argument count: 0 
# Number of locals: 0 
# Stack size:  1 
# Flags:    0x00000040 (NOFREE) 
# Constants: 
# 0: <code object fact at 0x7f815843e4b0, file "<string>", line 2> 
# 1: None 
# Names: 
# 0: fact 
    2   0 LOAD_CONST    0 (<code object fact at 0x7f815843e4b0, file "<string>", line 2>) 
       3 MAKE_FUNCTION   0 
       6 STORE_NAME    0 (fact) 
       9 LOAD_CONST    1 (None) 
      12 RETURN_VALUE 


# Method Name:  fact 
# Filename:   <string> 
# Argument count: 0 
# Number of locals: 1 
# Stack size:  1 
# Flags:    0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED) 
# Constants: 
# 0: None 
# 1: 8 
# 2: 10 
# Local variables: 
# 0: a 
    3   0 LOAD_CONST    2 (10) 
       3 STORE_FAST    0 (a) 

    4   6 LOAD_CONST    0 (None) 
       9 RETURN_VALUE 
$ 

अनुकूलन के लिए एक वैकल्पिक दृष्टिकोण Abstract Syntax Tree स्तर (एएसटी) में अनुकूलन करने के लिए है। हालांकि मुझे यकीन नहीं है कि आप इसे सीधे निष्पादित कर सकते हैं। कुछ मॉड्यूल दिनचर्या ऐसा सुझाव देते हैं कि आप कर सकते हैं। या आप एएसटी से बाइटकोड फ़ाइल कैसे उत्पन्न करेंगे। तो मुझे लगता है कि आप इसे वापस पायथन स्रोत के रूप में लिखते हैं।

संबंधित मुद्दे