学汇编,最怕的不是指令难记,而是环境配半天就跑不起来。这一篇我们不写任何寄存器,只把「能编译、能运行」这件事搞定。后面 6 篇会在这个环境里,一步步写出真正的汇编程序。

这是「x86 汇编入门」系列的第 0 篇。本系列基于 NASM 语法 + Linux x86_64 系统调用,在 Docker 容器中编译运行,不依赖 C 标准库。下一篇我们从 Hello World 开始,认识第一个系统调用。

一、为什么这样学?

你可能听过汇编「难学、难调试、离硬件近」。这些都没错,但入门阶段更大的障碍往往是:工具链太杂

本系列的选择很克制:

选择 原因
NASM 语法清晰,注释友好,Linux 社区资料多
Linux syscall 不链接 libc,直接跟内核对话,看清程序最底层在干什么
x86_64 64 位寄存器更多,调用约定也更规整
Docker 一次配好 nasm / ld / gdb,Mac 和 Linux 行为一致

可以把它想成学开车:我们先找一条封闭赛道(Docker),车况统一(Ubuntu 22.04 + 工具链),专心练操作,而不是先纠结「我这辆车该加几号油」。

二、项目结构

示例代码在本地 ref/asm_demo 目录(与博客同工作区)。核心文件:

1
2
3
4
5
6
7
8
9
10
ref/asm_demo/
├── Dockerfile # 构建开发镜像
├── docker_build.sh # 一键构建镜像
├── docker_run.sh # 启动容器并挂载源码
├── Makefile # 批量编译 src/*.asm
└── src/
├── 01_hello.asm
├── 02_input.asm
├── ...
└── 06_file_io.asm

容器内工作目录是 /workspace,与你本机的 ref/asm_demo 实时同步。

三、三步上手

1. 构建镜像(只需一次)

1
2
cd ref/asm_demo
./docker_build.sh

脚本会基于 ubuntu:22.04 构建名为 asm-dev 的镜像,预装 nasm、ld、gcc、gdb、make、strace。

2. 进入容器

1
./docker_run.sh

容器以交互模式启动,当前目录挂载到 /workspace。退出用 exitCtrl+D

3. 编译并运行

1
2
make
./build/01_hello

期望输出:

1
Hello, Assembly World!

如果看到这行字,说明整条链路已经通了。

四、编译流水线

每个 .asm 文件都经过两步变成可执行文件:

1
.asm  →  nasm -f elf64  →  .o  →  ld  →  可执行文件

对应命令(以 01_hello 为例):

1
2
nasm -f elf64 src/01_hello.asm -o build/01_hello.o
ld build/01_hello.o -o build/01_hello

Makefile 把这件事自动化了:make 编译 src/ 下全部 6 个程序,产物在 build/ 目录。

几个名词速记:

  • nasm:汇编器,把人类可读的 .asm 翻译成机器码目标文件 .o
  • ld:链接器,把 .o 拼成可执行文件(我们不用 C 运行时,所以只链接自己的代码)
  • elf64:64 位 Linux 可执行文件格式

五、程序学习路线

序号 程序 核心知识点
01 01_hello section 划分、寄存器、sys_write / sys_exit
02 02_input sys_read、.bss 段、缓冲区
03 03_calc 算术指令、数字转字符串
04 04_loop 条件跳转、循环
05 05_function call / ret、栈帧、递归
06 06_file_io 文件打开、读写、关闭

每篇博客对应一个 demo,建议按顺序阅读和动手。

六、常用命令备忘

1
2
3
make              # 编译全部
make clean # 清理 build/
./build/01_hello # 运行指定程序

调试时可以加 gdb ./build/01_hello,或用 strace ./build/01_hello 观察系统调用——后面几篇会频繁用到。

七、小结

本篇完成了系列的地基:Docker 环境、编译流程、6 个 demo 的全景地图。你不需要记住所有指令,只要确认 make 能过、01_hello 能跑就行。

x86 汇编入门系列第 0 篇完。下一篇我们写第一个真正的汇编程序——用不到 20 行代码,让屏幕打出 Hello World,并搞清楚 Linux 是怎么通过 syscall 帮我们干活的。