在 x86(32位)架构中,寄存器是 CPU 内部存储数据的"核心阵地"。为了方便理解,我们可以将常用的寄存器分为四组。随着 64 位(x64)的普及,这些寄存器在名字前加了 R(如 RAX),但逻辑功能依然延续。
- CPU 四组核心寄存器
第一组:通用寄存器 (General Purpose Registers)
这组寄存器最常用,主要用于算术运算和数据传送。
EAX (Accumulator):累加器。它是很多加减乘除指令的默认寄存器,也是函数返回值的存放地。
EBX (Base):基址寄存器。常用于内存寻址时存放基地址。
ECX (Count):计数器。在循环(LOOP)指令或字符串操作中,用来记录剩余次数。
EDX (Data):数据寄存器。在长整数乘除法中与 EAX 配合使用,也常用于 I/O 端口操作。
第二组:变址/指针寄存器 (Index & Pointer Registers)
这组寄存器主要负责"定位",即寻找内存地址。
ESI / EDI (Source/Destination Index):源/目的变址寄存器。常用于字符串拷贝(把数据从 ESI 指向的地址搬到 EDI 指向的地址)。
EBP (Base Pointer):栈底指针。指向当前函数栈帧的底部,是访问局部变量的参照点。
ESP (Stack Pointer):栈顶指针。永远指向当前堆栈的最顶部。
第三组:指令指针与标志寄存器
EIP (Instruction Pointer):指令指针(我们之前聊过)。指向 CPU 下一步要执行的指令地址。
EFLAGS:状态标志寄存器。它不是存数值的,而是存"状态"。比如:
ZF (Zero Flag):上一步计算结果是否为 0。
CF (Carry Flag):是否有进位。
SF (Sign Flag):结果是正还是负。
第四组:段寄存器 (Segment Registers)
在现代保护模式下,它们通常指向段描述符表。
CS (Code):代码段。
DS (Data):数据段。
SS (Stack):堆栈段。
ES/FS/GS:附加段,常用于特殊内存寻址(如 Linux 内核用 GS 存储 Per-CPU 变量)。
- 常用汇编指令(基础六大类)
掌握了寄存器,指令就是操作它们的"动词"。
A. 数据传送类
MOV eax, 10:把 10 放到 EAX。
PUSH eax:把 EAX 的值压入堆栈,ESP 减小。
POP ebx:从栈顶弹出一个值送到 EBX,ESP 增大。
LEA eax, [ebx+4]:取地址指令。把 ebx+4 计算出的地址值给 EAX,而不是去取那个地址里的数据。
B. 算术运算类
ADD eax, ebx:eax = eax + ebx。
SUB eax, 1:eax = eax - 1。
INC / DEC:自增 1 或自减 1(常用于循环)。
CMP eax, ebx:比较两个数。本质是做减法,但不保存结果,只影响 EFLAGS 标志位。
C. 逻辑运算类
AND / OR / XOR:与、或、异或。
TEST:逻辑比较。常用于检查某个位是否为 1(比如 TEST eax, eax 常用来判断 EAX 是否为 0)。
D. 控制流类(改变 EIP)
JMP label:无条件跳转。
JZ / JNZ:结果为 0 跳转 / 结果不为 0 跳转(依赖 ZF 标志)。
CALL / RET:调用函数 / 从函数返回。CALL 会自动把当前的 EIP 压栈。
- 实战案例:C 语言与汇编的转化
如果你写一句 C 语言:a = b + 1;
汇编视角下的动作可能是这样的:
代码段
mov eax, [ebp-8] ; 从内存(局部变量b)加载到寄存器EAX
add eax, 1 ; EAX加1
mov [ebp-4], eax ; 将结果存回内存(局部变量a)
- 历史趣闻:为什么寄存器名字这么怪?
在 1970 年代的 8086 时代,寄存器只有 16 位(AX, BX...)。到了 80386 时代,Intel 升级到了 32 位。
为了兼容老代码,他们没有改名,而是在前面加了个 E(Extended)。
AX 是 16 位。
AL 是 AX 的低 8 位(Low)。
AH 是 AX 的高 8 位(High)。
EAX 是整个 32 位。
在芯片行业,有一个很形象的比喻:指令集是"菜谱",而 CPU 架构是"厨房"。
- 指令集 (ISA - Instruction Set Architecture) :设计规范
指令集是一套标准和规范。它规定了这颗芯片能听懂哪些命令,比如"加法"、"跳转"、"从内存读数据"等。
它是接口: 它是硬件(CPU)和软件(编译器/操作系统)之间的"协议"。
常见的指令集:
x86: Intel 和 AMD 在用,复杂指令集(CISC),性能强但功耗高。
ARM: 手机、嵌入式(如你关心的 MCU)都在用,精简指令集(RISC),省电高效。
RISC-V: 开源指令集,近年来国内(包括工控领域)非常火。
- CPU 架构 (Microarchitecture) :硬件实现
架构(也叫微架构)是具体的电路实现。它决定了如何用晶体管把指令集里的命令"做"出来。
它是执行者: 同样是实现"加法"指令,不同的架构可以用不同的方式。
核心组成: 包含流水线深度、缓存(Cache)大小、分支预测器、运算单元(ALU)的数量等。
- 两者的关系:灵魂与肉体
我们可以通过以下三个层面来理解它们的关系:
A. 一对多:一个指令集可以有多种架构实现就像"宫保鸡丁"是一道菜(指令集规范),但不同的大厨(架构设计)可以有不同的炒法。
ARMv8 指令集(规范):
苹果设计的 M1/M2 架构(非常强悍)。
高通设计的 Oryon/Kryo 架构。
ARM 公司自己设计的 Cortex-A78 架构。
虽然内部电路(架构)完全不同,但它们都能运行相同的 ARM 软件代码。
B. 决定性能的是架构,决定生态的是指令集
为什么国产芯片要自研架构?因为架构决定了芯片跑得快不快、省不省电。
为什么大家很难放弃 x86/ARM?因为指令集决定了生态。如果换了指令集,原本的 Windows 或 Android 软件就通通跑不起来了。
C. 软硬件的界限
指令集定义了 CPU "能做什么",架构决定了 CPU "怎么去做" 以及 "做得多好"。
- 在 MCU 开发中的实际体现
当你接触设备或普通的单片机开发时,你会发现:
内核(Core): 比如 Cortex-M4。这既包含了 ARMv7-M 指令集,也包含了 ARM 公司设计的这款微架构。
驱动开发: 作为驱动工程师,你通常不需要修改架构,但你需要理解指令集(通过 C 语言编译器生成的汇编代码),并利用架构提供的外设(如 DMA、硬件乘法器)来压榨性能。
总结
指令集 (ISA): 软件与硬件沟通的语言(如 ARMv8, x86)。
架构 (Microarchitecture): 硬件内部的电路构造(如 Apple M2, Intel Alder Lake)。