📄 一句话概括
手工汇编=查操作码表+摆地址:把每条汇编指令翻成机器码、按字节连续装填,这一步就是汇编器干的事。
📝 本节和前面几节的关系
前三节把语言、寄存器、执行循环都讲清了,这一节全部合起来用:亲手做一次汇编器的活。
一、手工汇编的流程
第一步:查操作码表,把每条助记符指令翻成机器码——3E 80、D3 02、76; 第二步:按字节连续摆放地址,从 0x0000 起——每摆一个字节地址加一; 第三步:逐格核对,装填完成。 整件事一句话:照着表填空,按地址摆位。
二、为什么说这是汇编器干的事
你手工做的两步(翻译+定位),正是汇编器程序自动完成的——它读入汇编源码,输出机器码,还能给出每行的地址。 现代工具链里这一步只是开始:汇编器之后还有链接器(把多个模块拼起来)和装载器(放进内存)。
三、手工汇编的意义
做一遍才知道:高级语言的编译过程再复杂,终究要落到【地址加字节】这一层。 【⚠️ 2026 现状】现在当然不再手敲机器码,但【翻译+定位】这两个动作,一切编译器都在做。
四、动手 Demo:手工汇编器:翻译加定位
把三条汇编指令翻成机器码,再按地址连续装填——两步走完看结果。
# 第一步: 翻译 第二步: 定位
asm = ["LD A, 128", "OUT (2), A", "HALT"]
opcode = {"LD A, 128": [0x3E, 0x80],
"OUT (2), A": [0xD3, 0x02],
"HALT": [0x76]}
addr = 0
for ins in asm:
code = opcode[ins]
print(hex(addr), ins, "->", " ".join("%02X" % b for b in code))
addr += len(code)
实跑输出:
--------------------------------------------------------------------
手工汇编器——把人话翻成机器码
--------------------------------------------------------------------
动手把一串汇编指令【人肉翻译】成机器码,再装填进内存:
源程序(汇编):
1. LD A, 128
2. OUT (2), A
3. HALT
逐条汇编结果:
汇编指令 机器码 长度(字节)
-------------------------------------
LD A, 128 3E 80 2
OUT (2), A D3 02 2
HALT 76 1
装填进内存(地址从 0x0000 起连续摆放):
地址 字节 来源
-------------------------------
0x0000 3E LD A, 128
0x0001 80 LD A, 128
0x0002 D3 OUT (2), A
0x0003 02 OUT (2), A
0x0004 76 HALT
合计 5 个字节 —— 与第二章手敲进内存的完全一致。
手工汇编的功夫全在查表:操作码查手册、操作数照抄,一条条摆对地址。
输出里每一行左边是地址、右边是机器码——真实汇编器还会生成一张【符号表】记录每个标号的位置。 装填顺序不能乱:0x0000 起连续摆,中间留空会导致 PC 取到空洞。
30 秒实验
- 给 opcode 字典再加一条指令(比如 JP 0x0000,机器码 C3 00 00),体会【带地址的指令】要摆多少字节。
- 算一算三条指令共占几个字节(答案:5)——与第二章手敲进内存的字节数对照。
常见误区
- 以为手工汇编是【背下所有机器码】——不需要,查表即可,关键是流程与地址账。
- 以为汇编器只做翻译——它同时负责地址分配(定位),两件事一起干。
自测三问(点开对答案)
1. 手工汇编的两个步骤是什么? —— 查表翻译(助记符到机器码)+按地址定位(连续装填)。 2. 汇编器与我们手工做的是同一件事吗? —— 是——它自动完成翻译与定位,还能输出符号表。 3. 三条指令共占几个字节? —— 5 个:LD A,128 占 2、OUT 占 2、HALT 占 1。- ☐ 下一节(3.6 尝试估算程序的执行时间)
相关笔记
- 输入测试程序并进行调试 — 上一章亲手装填的那 5 个字节
- ⌨️ 编程原理 · 索引 — 从源码到可执行文件的完整工具链在那边
- 💻 计算机是怎样跑起来的 · 索引