⚙️ 第十章 通过汇编语言认识程序的真面目
📄 一句话概括

汇编语言不是另一种语言,它只是给同一批字节换了一套人看得懂的写法——一条本机指令对应一条汇编写法,不多不少。

📝 本节和前面几节的关系

第九章讲的是程序站在什么之上,这一章换个方向:把程序本身翻开来,看它里面到底写了什么。

一、从【看不懂的字节】说起

一个可执行文件打开来看,全是十六进制数字——那是 CPU 唯一认识的东西,叫本机代码。 人直接读它几乎不可能,但 CPU 也只认它。 所以中间必须有一层给人看的写法——这就是汇编语言。 记住关系:本机代码是给 CPU 的,汇编语言是给眼睛的,两者说的是同一件事。

二、一一对应是什么意思

看一段最简单的对照: B8 05 00 00 00 就是 movl $5, %eax——把 5 放进去。 83 C0 03 就是 addl $3, %eax——加 3。 89 C3 就是 movl %eax, %ebx——把这个值给另一个格子。 C3 就是 ret——返回。 左边几个字节、右边一行字,一条对一条——这就是【一一对应】。

三、为什么这个性质这么重要

因为它意味着:看懂汇编,就等于看懂了本机代码在干什么。 反过来也成立:任何一段本机代码,都能翻译回汇编。 所以才有反汇编这回事——别人只给你一个可执行文件,你也能看出它在做什么。 而且它是唯一能一眼看到【程序真面目】的高度:再往下是比特,再往上就看不见细节了。

四、同一规律在别处也成立

不止 CPU 有指令集,解释器也有自己的一套。 Python 的字节码就是同一回事:一串编号,每个编号对应一个助记符。 一个是 CPU 的指令集,一个是解释器的指令集——抽象的层次不同,规律完全一样。 这也是学汇编真正的收获:你会习惯【某一层看不懂,就翻出它下一层的清单来看】。

五、动手 Demo:汇编语言和本机代码是一一对应的

汇编语言就是本机代码的人可读版本:一条本机指令对应一条汇编写法。 用 Python 的字节码对照一下——同样是编号与助记符的对应。

import dis
code = compile("a = 1\nb = a + 2\n", "<demo>", "exec")
for i, ins in enumerate(list(dis.get_instructions(code))[:6]):
    print(i, ins.opname, ins.argval)

实跑输出:

--------------------------------------------------------------------
汇编语言和本机代码是一一对应的
--------------------------------------------------------------------

**汇编语言就是本机代码的【人可读版本】。**
一条本机指令,对应一条汇编写法——**不多不少,一一对应。**

  本机代码(十六进制)     汇编写法            意思
  ---------------------------------------------------------------
  B8 05 00 00 00           movl $5, %eax       把 5 放进 eax
  83 C0 03                 addl $3, %eax       eax 加 3
  89 C3                    movl %eax, %ebx     把 eax 的值给 ebx
  C3                       ret                 返回

  所以【汇编】并不是【另一种语言】,**它只是给同一批字节换了一套写法。**
  这一点很重要:**看懂汇编,就等于看懂了本机代码在干什么。**

  用 Python 的字节码对照一下——**同样是【字节 ↔ 助记符】的一一对应:**

  字节码序号     助记符         参数
  -----------------------------------
  0              RESUME         0
  1              LOAD_CONST     1
  2              STORE_NAME     a
  3              LOAD_NAME      a
  4              LOAD_CONST     2
  5              BINARY_OP      0

  **一个是 CPU 的指令集,一个是解释器的指令集——规律完全一样。**

实测拿到的助记符正是 RESUME/LOAD_CONST/STORE_NAME/LOAD_NAME/BINARY_OP/STORE_NAME。 每个助记符背后都是一个编号——跟 movl 背后是 B8 同一个道理。

30 秒实验

  1. 把上面四条本机字节和四种汇编写法在纸上抄一遍,感受一下一一对应。
  2. 想一想:为什么【反汇编】能成立。

常见误区

  1. 以为汇编是【另一种编程语言】。它只是本机代码的可读写法。
  2. 以为本机代码和汇编之间有些地方对不上。一条对一条,没有例外。
自测三问(点开对答案) 1. 汇编语言和本机代码是什么关系? —— 一一对应:一条本机指令对应一条汇编写法,是同一件事的两种表示。 2. 为什么能反汇编? —— 因为两者一一对应,任何一段本机代码都能翻译回汇编。 3. Python 字节码和它有什么相似之处? —— 字节码是解释器的指令集,同样是一串编号对应一串助记符。

相关笔记