- 汇编的诞生
- 汇编全景图
- 核心主干: CPU架构
- 主要分支: 语法和工具
- 共同的地貌: 核心概念
- 延伸: 跨平台 & 跨架构
- 跨平台
- 跨架构
- 总结
- 以 GAS vs. NASM 为例
- NASM 不支持跨架构 ≠ 无法在ARM架构上的系统安装
汇编的诞生
- 机器语言的困境
- 早期的程序员直接使用机器语言进行编程
- 机器语言由纯粹的数字(0, 1) 组成, 对应着CPU可以直接执行的指令和数据
- 繁琐, 反人类, 难以记忆
- 汇编语言的诞生
- 为了解决上述问题, 人们发明了汇编语言(Assembly Language)
- 核心思想: 为那些晦涩的二进制机器指令起一个简单易记的英文缩写, 助记符(Mnemonic)
- 例如:
- ADD 代表 加法 操作
- MOV 代表 移动 数据
- 10110000 01100001 -> MOV AL, 97 大大提高编程效率和可读性
- 汇编器的作用
- CPU只能理解二进制机器码, 看不懂 MOV AL, 97 这样的指令
- 汇编器被创造: 将汇编语言写的源代码汇编(翻译)成机器语言目标代码
汇编全景图
核心主干: CPU架构
汇编语言不是一种标准化的语言, 不同的CPU架构有不同的指令集, 因此有完全不同的汇编语言.
- x86/x86-64 (CISC 复杂指令集)
- 领地: Windows, Linux.
- 特点: 历史悠久, 指令集庞大且复杂, 变长指令, 寄存器数量小但功能强大
- 厂商: Inter 和 AMD 自行设计, 制造和销售芯片
- ARM (RISC 精简指令集)
- 领地: 智能手机, 嵌入式设备, 物联网. 今年来凭借 Apple M系列芯片进入桌面领域
- 特点: 设计简洁, 指令定长, 寄存器数量多, 采用 "加载-存储"架构
- 厂商: ARM公司只设计IP核(架构蓝图), 授权给其他公司(苹果, 高通, 三星, 华为等), 由这些公司自行生产
- 其他架构
- MIPS: 经典的RISC设计, 曾在路由器, 嵌入式广泛应用
- RISC-V: 开源的精简指令集架构, 非常简单化和简洁, 发展迅猛
- AVR/PIC: 主要用于微控制器(MCU), 是 Arduino 等开发板的核心
主要分支: 语法和工具
确定了架构主干后, 你会遇到具体的 “方言” 和工具
除了不同风格的语法, 不同的汇编器也有会自己的宏和处理指令
- x86 分支下两条路
- Inter 语法
- 特点: 指令 目标操作数, 源操作数, 例: mov eax, 5
- 代表汇编器
- NASM: 跨平台, 开源, 语法清晰一致
- MASN: 微软官方工具, 主要用于Windows环境
- AN&T 语法
- 特点: 指令 源操作数, 目标操作数, 例: mov $5, %eax
- 代表编译器
- GAS (GNU Assembler): Linux 和 GCC 编译器的默认后端
- Inter 语法
- ARM 分支下的路
- 语法: 语法风格相对统一, 主要是 GNU 汇编风格
- 编译器:
- GAS: Linux 下编译 ARM 代码的标准工具
共同的地貌: 核心概念
无论你走在哪条主干和分支上, 有些地貌特征是共通的, 这就是汇编语言的 核心概念, 也是学习的重点
- 寄存器(Registers): CPU 内部高速存储单元
- 内存寻址模式(Memory Addressing Modes): 如何计算出操作数在内存中的地址. 如 直接寻址, 寄存器间接寻址, 基址变址寻址等.
- 指令集(Instruction Set)
- 数据传送: MOV, PUSH, POP, LEA
- 算数运算: ADD, SUB, INC, DEC, MUL, DIV
- 逻辑运算: AND, OR, XOR, NOT
- 控制流: JMP, CALL, RET, 以及各种条件跳转
- 程序结构(Program Structure): 如何划分代码段, 数据段; 如何使用标签(Labels)
- 系统调用与中断(Syscalls & Interrupts): 如何让操作系统内核为你服务(例: 输出文字, 读取文件)
延伸: 跨平台 & 跨架构
- 架构(Architecture): 底层硬件蓝图, 指的是CPU的设计, 它定义了:
- 指令集: CPU 能够理解和执行的基本命令集合(例: ADD, MOV 等), 不同架构之间最根本的区别
- 寄存器
- 内存访问方式
- 平台(Platform): 完整的运行环境, 指的是硬件架构和操作系统的组合, 它提供了软件运行的完整生态系统
- Windows on x86-64: 最常见的PC平台
- Linux on x86-64: 笔记本电脑, 服务器
- Linux on ARM: 智能手机, 平板, 嵌入式等
- MaxOS on x86-64: 2019年之前的苹果Mac电脑
- MaxOS on ARM: 搭载M系列芯片的苹果Mac电脑
跨平台
同一份源代码编译出来的程序, 或者同一个解释型程序, 能够在不同的操作系统上运行, 不需要修改代码
关心的是: 操作系统的差异, 例: 文件路径(c:\ vs /), 动态库格式(.dll vs .so), GUI框架等
如何实现:
- 用户需要先安装一个 运行时环境 或 虚拟机 (如 JVM, Python解释器), 这个运行时环境本身是需要为特定平台专门编译的
- 你的源代码被编译成一种中间格式(如java的.class字节码). 这个中间格式是跨平台, 跨架构的. 当用户在具体平台运行它时, 本地的运行环境会负责将中间格式 “翻译” 成当前平台能理解的本地指令
跨架构
同一份源代码编译出来的程序, 能够在不同的CPU架构上运行
关心的是: CPU指令集的差异, 软件必须被编译成目标架构能理解的机器码
如何实现:
-
方案一: 分发代码
- 提供程序的源代码, 用户在自己的机器上针对自己的架构自行编译
- 例: Linux 开源软件
-
方案二: 提供多个二进制版本
- 开发者提前为不同的架构分别编译好, 用户根据自己的CPU下载对应的版本
- 例: Python 官网同时提供 x86-64 和 ARM64 的安装包
总结
以 GAS vs. NASM 为例
特性 | GAS (GNU Assembler) | NASM (Netwide Assembler) |
---|---|---|
跨架构 | 是。一个工具,多种架构 | 否。只专注于x86/x86-64架构 |
跨平台 | 是。可在Win, Linux, macOS等系统上运行 | 是。可在Win, Linux, macOS等系统上运行 |
默认语法 | AT&T 语法 | Intel 语法 |
“家族” | 属于庞大的GNU工具链(GCC, ld, objdump等) | 是一个独立的、专注的汇编器 |
NASM 不支持跨架构 ≠ 无法在ARM架构上的系统安装
让我们分两层理解:
- NASM 本身是一个程序, 可以被编译为特定操作系统和架构上运行的版本. 这也是跨平台的特性
- NASM 的功能, 无论NASM在哪个操作系统上运行, 它的核心功能只有一个: 将 Inter 语法格式的 x86/x86-64 汇编源代码 汇编成 x86/x86-64 架构的机器码
因此, 会产生以下情况:- 在 x86 Linux 上: 可以运行 NASM, 它正常工作, 生成 x86 的 .o 目标文件
- 在 ARM Linux 上: 你也可以安装和运行一个专门为 ARM 架构编译的 NASM 程序, 但是, 这个 NASM 程序仍然智能处理 x86汇编代码, 并试图输出 x86 机器码.
- 这在大多数情况下是没有意义的, 生成的x86机器码在 ARM CPU上无法直接执行
- 这种操作通常只用于 交叉编译的特殊场景, 比如你在一个 ARM 服务器上为 x86 电脑编译程序