--- ingested: true ingestedAt: 2026-05-17 --- 标题: 汇编语言 - 寄存器 链接: https://www.runoob.com/assembly/assembly-registers.html 内容: 寄存器(Register)是 CPU 内部的高速存储单元,是汇编编程中最频繁操作的对象。理解寄存器是学好汇编语言的关键第一步。 --- ## 什么是寄存器 寄存器是 CPU 芯片内部集成的 超高速小型存储器,用于暂存指令、数据和地址。 与内存不同,寄存器就嵌在 CPU 内部,CPU 访问寄存器几乎零延迟,而访问内存则需要几十到几百个时钟周期。 在汇编语言中,绝大多数运算都是围绕寄存器展开的——数据从内存加载到寄存器,在寄存器中完成运算,再将结果存回内存。 > 可以把寄存器理解为 CPU 的"工作台"。工作台上的工具随时可用,而内存则像是仓库,需要走过去取放。 --- ## x86 32 位寄存器分类 x86 32 位架构提供了多种类型的寄存器,各有不同的用途。 下面分别详细介绍各类寄存器: --- ## 通用寄存器 通用寄存器(General Purpose Registers) 是最常用的寄存器,用于存放运算数据和临时结果。 x86 提供了 8 个 32 位通用寄存器: | 32位 | 16位 | 低8位 | 高8位(低16位) | 主要用途 | | --- | --- | --- | --------- | ------------------ | | EAX | AX | AL | AH | 累加器,存放函数返回值、算术运算结果 | | EBX | BX | BL | BH | 基址寄存器,常用于存放内存基地址 | | ECX | CX | CL | CH | 计数器,常用于循环计数和移位 | | EDX | DX | DL | DH | 数据寄存器,存放乘除法的高位结果 | | ESI | SI | SIL | \- | 源变址寄存器,字符串操作的源地址 | | EDI | DI | DIL | \- | 目的变址寄存器,字符串操作的目标地址 | | EBP | BP | BPL | \- | 基址指针,指向当前栈帧的底部 | | ESP | SP | SPL | \- | 栈指针,始终指向栈顶 | 名称规律:E 前缀表示 Extended(扩展到 32 位),X 后缀表示可拆分为高低字节。 ## 实例 ; 文件路径:register\_parts.asm ; 演示寄存器的各部分访问 section .text global \_start \_start: mov eax, 0x12345678 ; 完整的 32 位寄存器 ; 此时:EAX = 0x12345678 ; AX = 0x5678 (低 16 位) ; AH = 0x56 (高 8 位,指 AX 的高 8 位) ; AL = 0x78 (低 8 位) mov ax, 0xAABB ; 修改 AX(低 16 位) ; 此时:EAX = 0x1234AABB (高 16 位保持不变!) ; AX = 0xAABB ; AL = 0xBB mov al, 0xCC ; 修改 AL(最低 8 位) ; 此时:EAX = 0x1234AACC (只有低 8 位变了) ; AX = 0xAACC ; AL = 0xCC mov eax, 1 mov ebx, 0 int 0x80 > 修改 32 位寄存器的低 16 位(如 AX)时,高 16 位保持不变。但将 32 位寄存器作为目标操作数时,会覆盖整个 32 位。这是初学者容易出错的地方。 --- ## 段寄存器 段寄存器用于指定当前使用的内存段: | 寄存器 | 名称 | 用途 | | --- | ------ | ------------ | | CS | 代码段寄存器 | 指向当前指令所在的段 | | DS | 数据段寄存器 | 指向数据所在的段 | | SS | 栈段寄存器 | 指向栈所在的段 | | ES | 附加段寄存器 | 额外的数据段 | | FS | 附加段寄存器 | 通用,常用于线程局部存储 | | GS | 附加段寄存器 | 通用,常用于线程局部存储 | 在 32 位保护模式下编程时,操作系统已经设置好了段寄存器,你通常不需要手动修改它们。 --- ## 指针和变址寄存器 这些寄存器主要用于访问内存,存放内存地址: | 寄存器 | 全称 | 用途 | | --- | ------------------------- | -------------------------- | | EIP | 指令指针(Instruction Pointer) | 指向 CPU 下一条要执行的指令地址(不可直接访问) | | ESP | 栈指针(Stack Pointer) | 指向栈顶,PUSH/POP 指令自动调整它 | | EBP | 基址指针(Base Pointer) | 指向当前函数栈帧的底部,用于访问函数参数和局部变量 | | ESI | 源变址(Source Index) | 字符串/内存操作的源地址 | | EDI | 目的变址(Destination Index) | 字符串/内存操作的目标地址 | > ESP 和 EBP 不能当作普通通用寄存器随意使用。ESP 指向栈顶,push/pop/call/ret 都会改变它;EBP 是访问函数参数的关键。随意修改它们会导致程序崩溃。 --- ## 标志寄存器(EFLAGS) EFLAGS 是一个 32 位寄存器,每个比特位代表一个状态标志(Flag)。 你不能直接读写整个 EFLAGS,但 CPU 会根据运算结果自动更新这些标志位,条件跳转指令则根据标志位决定是否跳转。 | 标志位 | 名称 | 含义 | | --- | ------------------- | --------------------- | | CF | 进位标志(Carry Flag) | 无符号运算产生进位/借位时置 1 | | PF | 奇偶标志(Parity Flag) | 结果低 8 位中 1 的个数为偶数时置 1 | | AF | 辅助进位标志 | 低 4 位向高 4 位进位/借位时置 1 | | ZF | 零标志(Zero Flag) | 运算结果为 0 时置 1 | | SF | 符号标志(Sign Flag) | 运算结果为负数时置 1(等于结果的最高位) | | OF | 溢出标志(Overflow Flag) | 有符号运算溢出时置 1 | ## 实例 ; 文件路径:flags\_demo.asm ; 演示运算对标志位的影响 section .text global \_start \_start: mov eax, 10 sub eax, 10 ; 10 - 10 = 0 ; ZF = 1(结果为零) ; SF = 0(结果非负) ; CF = 0(无借位) mov eax, 0xFFFFFFFF add eax, 1 ; 0xFFFFFFFF + 1 = 0x100000000(超出了 32 位) ; ZF = 1(32位结果为0) ; CF = 1(产生进位) ; OF = 0(有符号角度看无溢出) mov eax, 1 mov ebx, 0 int 0x80 --- ## 寄存器使用约定 在实际编程中,一些寄存器有约定俗成的用法——称为 调用约定(Calling Convention): | 寄存器 | 调用约定中的用途 | | --------------- | ------------------------- | | EAX | 存放函数返回值 | | ECX | 计数器(循环计数) | | EDX | 存放除法的高位结果、扩展 EAX | | EBX、ESI、EDI、EBP | 被调用函数必须保存和恢复(callee-saved) | | EAX、ECX、EDX | 调用者负责保存(caller-saved) | > 在编写自己的汇编程序时,不一定严格遵循调用约定。但如果你要和 C 语言混合编程,就必须遵守 cdecl 等调用约定。