📄 一句话概括
汇编只做了一件事:给每个机器码配一个人能读的名字——长度差不多,价值在能读、在标签。
📝 本节和前面几节的关系
3.2 是机器码,这一节是第一次抽象:还是同一批指令,只是换了个写法。
一、给字节起名字
B8 05 00 00 00 换成 movl $5, %eax——同一个东西,两种写法。
83 C0 03 换成 addl $3, %eax。
89 C3 换成 movl %eax, %ebx。
汇编和机器码是一一对应的(第 10 章会把这条讲透)。
二、价值不在省字
实测四行代码:汇编 49 个字符,机器码 41 个字符——量级差不多。
所以汇编不是【缩写】,是【翻译】。
addl $3, %eax 一眼能看出在加;83 C0 03 看不出来。这就是全部差别。
三、标签是真正的进步
机器码里跳转写偏移,汇编里可以写标签:jmp loop。
汇编器负责把标签算成偏移——中间插指令,偏移会自动重算。
这一小步解决的是维护,不是书写:改动不再牵一发动全身。
这是程序员第一次不用替机器算账。
四、留下的死穴
汇编仍然一条意图要写好多行:total = a + b 要三行(搬、加、存)。
而且它绑死在一颗 CPU 上:换 ARM,整份重写。
这两个死穴,就是 3.4 高级语言要解决的。
顺便说一句:今天汇编没死——驱动、嵌入式、性能热点、反汇编分析,都还在用。
五、动手 Demo:编程语言的第一步是汇编语言
把机器码和汇编并排放,看它们是不是同一样东西的两种写法。 再数一数字符数,验证【汇编不省字、只翻译】。
pairs = [
("B8 05 00 00 00", "movl $5, %eax"),
("83 C0 03", "addl $3, %eax"),
("89 C3", "movl %eax, %ebx"),
("E9 F6 FF FF FF", "jmp loop"),
]
for mc, asm in pairs:
print(mc.ljust(18), asm)
print("机器码字符", sum(len(a) for a, b in pairs))
print("汇编字符 ", sum(len(b) for a, b in pairs))
实跑输出:
--------------------------------------------------------------------
编程语言的第一步是汇编语言
--------------------------------------------------------------------
汇编只做了一件事:**给每个机器码配一个人能读的名字。**
机器码 汇编 做的什么
-----------------------------------------------------
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
E9 F6 FF FF FF jmp 某个标签 跳到别处去
实测四行代码:**汇编 49 个字符,机器码 41 个字符**——量级差不多。
**所以汇编的价值不在省字,在【能读】:**
`addl $3, %eax` 一眼能看出在加;`83 C0 03` 看不出来。
**而且标签让跳转不用自己算地址**——这是最实在的一步进步。
但汇编仍然有一个死穴:**一条意图要写好多行。**
`total = a + b` 在汇编里是三行。**这就是 3.4 要解决的。**
实测:机器码 45 个字符、汇编 56 个字符——汇编反而更长。 它的价值不在省字,在能读;而标签让跳转不用自己算偏移,解决的问题是维护。
30 秒实验
- 把
addl $3, %eax反查成机器码,看看能不能对得上。 - 想一想:为什么有了汇编,程序员还是觉得累。
常见误区
- 以为汇编是机器码的缩写。它是同一样东西的人可读写法。
- 以为汇编已经过时。驱动、嵌入式、性能热点还在用。
自测三问(点开对答案)
1. 汇编相对机器码做了什么? —— 给每个机器码配一个人能读的名字,一一对应;标签让跳转不必手算偏移。 2. 汇编省字吗? —— 不省——实测反而更长(56 对 45 个字符),它的价值在能读和维护。 3. 汇编的死穴是什么? —— 一条意图要好几行,而且绑死在一颗 CPU 上,换平台要整份重写。- ☐ 下一节(3.4 高级语言使程序更加接近人类语言)
相关笔记
- 最初使用机器语言编写程序 — 上一步
- 高级语言使程序更加接近人类语言 — 下一步
- ⚙️ 程序是怎样跑起来的(第3版) · 索引 — 第 10 章真讲了一遍汇编
- 🧩 面向对象是怎样工作的 · 索引