基本的Python汇编要理解

时间:2018-08-17 03:10:58

标签: python cpython

我有一个python文件:

$ cat main.py 
def foo():
    x = 10
    y = 20
    return x+y

foo()

python的反汇编如下:

$ python -m dis main.py 
  1           0 LOAD_CONST               0 (<code object foo at 0x109a933b0, file "main.py", line 1>)
              3 MAKE_FUNCTION            0
              6 STORE_NAME               0 (foo)

  6           9 LOAD_NAME                0 (foo)
             12 CALL_FUNCTION            0
             15 POP_TOP             
             16 LOAD_CONST               1 (None)
             19 RETURN_VALUE 

这是我的问题:

1)在反汇编中,1main.py中的行号,LOAD_CONST指可读格式的操作码。 0之后的(foo)的大部分是什么?

2)看来python加载了函数名foo,然后调用了操作码CALL_FUNCTIONLOAD_CONST-> STORE_NAME在堆栈/堆中发生了什么。 python在后台保留什么记录(请尽可能低级别,欢迎指向CPython源代码)?

我在https://docs.python.org/2/library/dis.html上看到STORE_NAME

  

STORE_NAME(namei)

     

实现name = TOS。 namei是name中的索引   代码对象的属性co_names。编译器尝试使用   STORE_FAST或STORE_GLOBAL(如果可能)。

但是,除了我们正在做类似foo = Top Of Stack的事情之外,这对我来说还不清楚。那么foo实际上就是co_nameco_name[namei]中的东西。如果我们进入LOAD_NAME,它将把co_name的东西带到TOS上。什么是co_name(已分配堆unordered_mapdict)?

我觉得自己正在钻研越来越深的漏洞,我认为我应该退后一步,看看社区可以提供什么,然后再继续。

更新:现在我想到了,因为我们正在做类似co_name[namei]的事情,并且如果namei是and index。 co_name仅仅是一个内存管理的数组吗?

1 个答案:

答案 0 :(得分:1)

Jason harper的评论解释了您的前两个问题。但是,换句话说,操作码名称后面的数字是它们的参数,括号中的内容指示这些参数实际指的是什么。事实证明,大多数操作码都接受一个参数,对于您的特殊情况,所有索引都索引为0。

关于您的另一个问题,如果可以的话,LOAD_NAME实际上就是LOAD_BY_NAME。它将函数foo推送到TOS上,以便CALL_FUNCTION知道要调用的内容。

Python将名称存储在名为co_names的元组中,并进一步维护locals字典,也称为f_locals(在Python中可通过locals()访问)。 LOAD_NAME在co_names中的特定索引处获取名称,然后在locals中查找名称。常量直接存储在另一个元组中,并进行数字索引。

关于代码参考,请参考CPython发行版中的$PYPATH/Python/ceval.c,或直接在GitHub上进行检查。