汇编语言不是另一种语言,它只是给同一批字节换了一套人看得懂的写法——一条本机指令对应一条汇编写法,不多不少。
第九章讲的是程序站在什么之上,这一章换个方向:把程序本身翻开来,看它里面到底写了什么。
一、从【看不懂的字节】说起
一个可执行文件打开来看,全是十六进制数字——那是 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. 为什么能反汇编? —— 因为两者一一对应,任何一段本机代码都能翻译回汇编。 3. Python 字节码和它有什么相似之处? —— 字节码是解释器的指令集,同样是一串编号对应一串助记符。- ☐ 下一节(10.2 用C编译器输出汇编语言源代码)
相关笔记
- 用C编译器输出汇编语言源代码 — 怎么亲眼看到这些汇编
- 计算机只能执行本机代码 — CPU 只认这一层
- CPU的处理其实很简单 — 它认得的动作只有四类
- 🔵 计算机基础 · 索引 — 硬件底层的入门课
- ⚙️ 程序是怎样跑起来的 · 索引