Güncelleme: Çeşitli nedenlerden ötürü bir Cross-Python sürümü derleyicisini yazmaya başladım. https://github.com/rocky/python-xasm'a bakın. Hala çok erken beta.
Bildiğim kadarıyla şu anda bakımsız Python assembler var. PEAK's Bytecode Disassembler, Python 2.6 için geliştirilmiş ve daha sonra Python 2.7'in erken dönemini desteklemek üzere değiştirilmiştir.
documentation'dan oldukça havalıdır. Ancak sorun yaratabilecek diğer PEAK kütüphanelerine dayanır.
Yapacağınız şey için size bir fikir vermek için tüm örneği gözden geçireceğim. Güzel değil, ama sonra bunu beklemelisin.
Temel olarak bayt kodunu değiştirdikten sonra, yeni bir types.CodeType
nesnesi oluşturmanız gerekir. Yeni bir tanesine ihtiyacınız var çünkü kod türündeki birçok nesne, iyi bir sebepten dolayı değişemezsiniz. Örneğin yorumcunun önbelleğe alınmış bu nesne değerlerinden bazıları olabilir.
Kod oluşturduktan sonra, exec
veya eval
'da kullanılabilen bir kod türü kullanan işlevlerde kullanabilirsiniz.
Veya bunu bir bytecode dosyasına yazabilirsiniz. Ne yazık ki Python 2 ve Python 3 arasında kod formatı değişmiştir. Bu arada optimizasyon ve bayt kodları da vardır. Aslında, Python 3.6'da kelime kodları bayt kodları olmayacaktır.Satır numaralarını yapmadıysanız
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)
Bildirim o: Bu buraya sığındılar
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))
ne var: Yani burada
Eğer örneğin yapmak zorunda kalacak ne kodda birkaç satır kaldırılmış olsa bile değişti. Bunun nedeni, fn_code.co_lnotab
'u güncellemedim.
Bundan böyle bir Python bayt kodu dosyası yazmak istiyorsanız. Burada ne yaparım geçerli:
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))
yukarıdaki Demirbaş baytkodu, ben xdis denilen write_python_file() için bir rutin ekledik yazma basitleştirmek için. Şimdi
sonuçları kontrol etmek:
$ 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
$
optimizasyonu için alternatif bir yaklaşım Abstract Syntax Tree seviyesinde (AST) de optimize etmektir. Ancak, bunu doğrudan uygulayacağınızdan da emin değilim. Bazı modül rutinleri yapabildiğinizi öneriyor gibi görünüyor. Ya da bir AST'den nasıl bir bytecode dosyası oluşturursunuz. Bu yüzden bunu Python kaynağı olarak yazdığınızı varsayalım.
Bunu neden yaptığınızı merak ediyorum, kullanım durumunuz nedir? – shuttle87
Python bytecode bir uygulama detayı olarak kabul edilir ve versiyondan sürüme ve tercümana tercüman olarak değişebilir. Tercüman kaynağı dışında dokümantasyon yoktur. Bunu yapmak istediğine emin misin? – Antimony
@ shuttle87, Ben python yazmayı umuyoruz komut dosyaları ile bir oyun motoru yazıyorum, ama ben gevşek konuşma önceden bilinmeyecek betik bytecode bazı optimizasyonlar çalıştırmak istiyorum (her ne kadar temel yapısı olacak rağmen hepsinin ortak bir temel sınıfı paylaştığı bilinmelidir). Diğer tüm bileşenleri çalışıyorum, sadece bu bytecode'u kullanılabilir bir işleve dönüştürmek son engel. –