Cobra —— super dis

在Python的标准库中,有许多库是用于Python的编译和反编译(呃,确切地说,是反汇编)。在Python自带的文档中“Python Library Reference”的“Python Language Services”一部分中,列出了这些库。dis是其中一个,官方的描述是“disassembler for python byte code”

通俗地说,dis是python编译后结果中字节码指令序列的反汇编器 。Python的运行机制和Java、C#在本质上是一样的,都是一种基于stack的虚拟机,都有自己定义的字节码指令。既然有了字节码指令,那么这些字节码指令如同汇编语言一样,我们可以利用字节码指令直接编写成学。C#中我们可以直接用MSIL编写.NET程序;Java中也有开源的诸如Jasmin这样的汇编器。Python中没有提供这样的汇编器,但是这并不妨碍Python在标准库中提供一个dis这样的反汇编器,毕竟很对人对驱动Python底层运作的字节码指令还是很感兴趣的。

但是不幸的是,dis并不是一个使用非常方便的库。在dis中,提供了很多方法,这些方法之间大同小异,最常使用的一个唤作dis(通过dis.dis调用),官方的描述是这样的:

For a module, it disassembles all functions.

For a class, it disassembles all methods.

For a single code sequence, it prints one line per byte code instruction.

似乎很强大,对于module,class,function等都能进行反汇编,但实践中你会发现使用上及其不方便,考虑下面的例子:

def  f():
    
pass
    
def  g():
    
print   ' hello world '
    
def  func():
        
print   ' this is a nested function '
    
class  MyClass(object):
    
def   __init__ (self):
        
pass
    
=   1
+=   1
print  a

如果我们想查看module一级的字节码指令,似乎可以如下进行:

import  demo
import  dis
dis.dis(demo)

很遗憾,这样是不行的,这样反汇编的结果是将demo这个module中所有的方法进行反汇编,结果如下:

Disassembly of f:
  2           0 LOAD_CONST               0 (None)
               3 RETURN_VALUE

Disassembly of g:
  5           0 LOAD_CONST               1 ('hello world')
               3 PRINT_ITEM
               4 PRINT_NEWLINE

  6           5 LOAD_CONST               2 (<code object fun at 00BCABF0, file "demo.py", line 6>)
               8 MAKE_FUNCTION            0
               11 STORE_FAST               0 (fun)
               14 LOAD_CONST               0 (None)
               17 RETURN_VALUE

但是我们的目的是想查看“def f()”,“a += 1”这些表达式的字节码指令,dis不能方便地看到我们期望的目标。当然,利用dis还是可以看奥“a += 1”的字节码指令的,方法是先将demo.py通过文件方式读入,将读入后的字符串利用builtin的compile编译成一个code对象,然后利用dis反汇编这个code对象,你看到了,这将非常麻烦。

另一方面,如果你想查看MyClass.__init__和内嵌函数fun的字节码指令,那么过程也将会非常繁复。在我进行“Python源码剖析”的过程中,我需要一个方便的工具,能够方便快捷地看到任何一个函数、类、module对应的字节码指令。这个工具就是我自己编写的sdis(super dis)。在sdis中,利用了dis提供的功能:

 

import  dis as pydis
import  types

code 
=  None
def  read(filename):
    f 
=  open(filename)
    content 
=  f.read()
    
global  code
    code 
=  compile(content, filename,  ' exec ' )
    f.close()

def  find_code(code, name):
    
for  item  in  code.co_consts:
        
if  isinstance(item, types.CodeType):
            
if  item.co_name  ==  name:
                
return  item
    
return  None
    
def  dis(code_name = None):
    
if  code_name  is  None:
        co 
=  code
        pydis.dis(co)
        
return
    names 
=  code_name.split( " . " )
    co 
=  code
    
for  name  in  names:
        co 
=  find_code(co, name)
        
if   not  co:
            
print   ' %s is not a valid name '   %  code_name
    
if  co:
        
print  ( "   byte code for %s   "   %  code_name).center( 60 ' * ' )
        pydis.dis(co)

原理非常简单,sdis将python源文件读入并进行编译,从《Python源码剖析》系列中我们已经得知,编译的结果是一个code对象,在code对象中,包含了一个co_consts,其中有别的code对象。类、函数、module在demo.py中层怎样的嵌套结构,code对象在co_consts中也呈现出相同的嵌套结构。有了这个工具,对python的反汇编就方便多了,下面是几个例子:

Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sdis
>>> import demo
2
>>> sdis.read('demo.py')
>>> sdis.dis() #这个是module一级的反汇编结果
  1           0 LOAD_CONST               0 (<code object f at 00BE7530, file "demo.py", line 1>)
              3 MAKE_FUNCTION            0
              6 STORE_NAME               0 (f)

  4           9 LOAD_CONST               1 (<code object g at 00BE7650, file "demo.py", line 4>)
             12 MAKE_FUNCTION            0
             15 STORE_NAME               1 (g)

  9          18 LOAD_CONST               2 ('MyClass')
             21 LOAD_NAME                2 (object)
             24 BUILD_TUPLE              1
             27 LOAD_CONST               3 (<code object MyClass at 00BE76E0, fi
le "demo.py", line 9>)
             30 MAKE_FUNCTION            0
             33 CALL_FUNCTION            0
             36 BUILD_CLASS
             37 STORE_NAME               3 (MyClass)

 13          40 LOAD_CONST               4 (1)
             43 STORE_NAME               4 (a)

 14          46 LOAD_NAME                4 (a)
             49 LOAD_CONST               4 (1)
             52 INPLACE_ADD
             53 STORE_NAME               4 (a)

 15          56 LOAD_NAME                4 (a)
             59 PRINT_ITEM
             60 PRINT_NEWLINE
             61 LOAD_CONST               5 (None)
             64 RETURN_VALUE
>>>
>>> sdis.dis('MyClass.__init__')
*************  byte code for MyClass.__init__  *************
 11           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE
>>>
>>> sdis.dis('g.fun')
******************  byte code for g.fun  *******************
  7           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE
>>>

Cobra将使用sdis这个工具完成对python源文件的反汇编和显示工作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值