4. 汇编语言基础(x86):常用指令集、寄存器结构、堆栈操作与中断调用

汇编语言是BIOS/UEFI固件开发的核心工具。x86汇编直接操作CPU寄存器、内存和I/O端口,是理解固件启动流程、硬件抽象层(HAL)和实模式/保护模式切换的基石。本章聚焦于最常用的指令集、寄存器架构、堆栈操作以及BIOS中断调用机制。

4.1 x86寄存器结构

x86架构的寄存器分为通用寄存器、段寄存器、指令指针寄存器和标志寄存器。在BIOS开发的实模式(16位)下,寄存器宽度为16位;进入保护模式后,扩展为32位(EAX、EBX等)。

类别寄存器16位名称32位名称主要用途
通用寄存器累加器AXEAX算术运算、I/O操作、中断服务
基址寄存器BXEBX内存基址、查表
计数寄存器CXECX循环计数、移位次数
数据寄存器DXEDXI/O端口地址、乘除扩展
索引/指针源变址SIESI字符串操作源地址
目的变址DIEDI字符串操作目的地址
堆栈指针堆栈指针SPESP栈顶偏移地址
基址指针BPEBP栈帧基址
指令指针程序计数器IPEIP下一条指令偏移地址
标志寄存器状态标志FLAGSEFLAGS运算结果状态(CF、ZF、SF等)
BIOS开发提示: 在实模式下,段寄存器(CS、DS、ES、SS)与通用寄存器组合形成20位物理地址(段基址×16 + 偏移)。这是理解BIOS中断调用参数传递的关键。

4.2 常用指令集

4.2.1 数据传送指令:MOV

MOV 是最基础的指令,用于在寄存器、内存和立即数之间复制数据。注意:源操作数和目的操作数不能同时为内存地址。

; 立即数送寄存器
MOV AX, 0x1234      ; AX = 0x1234

; 寄存器间传送
MOV BX, AX          ; BX = AX

; 内存到寄存器
MOV CX, [0x7C00]    ; 将地址0x7C00处的字数据送入CX

; 寄存器到内存
MOV [0x6000], DX    ; 将DX内容存入地址0x6000

4.2.2 算术运算指令:ADD / SUB

ADD 和 SUB 影响标志寄存器中的 CF(进位)、ZF(零)、SF(符号)和 OF(溢出)位。

MOV AX, 0x1000
ADD AX, 0x2000      ; AX = 0x3000, ZF=0, CF=0

MOV BX, 0x0005
SUB BX, 0x0008      ; BX = 0xFFFD (补码), CF=1 (借位)

4.2.3 控制转移指令:JMP / CALL / RET

  • JMP:无条件跳转,改变IP(或EIP)的值。
  • CALL:先将返回地址(下一条指令的地址)压入堆栈,然后跳转到目标地址。
  • RET:从堆栈弹出返回地址,恢复执行流。
; 无条件跳转
JMP 0x7C00          ; 跳转到绝对地址0x7C00

; 调用子程序
CALL delay_loop     ; 调用子程序,返回地址自动入栈

; 子程序返回
RET                 ; 从栈顶弹出地址并跳转

4.2.4 中断调用指令:INT

INT n 触发编号为 n 的软件中断。BIOS在实模式下通过中断向量表(IVT)提供服务。最常用的是 INT 0x10(视频服务)和 INT 0x13(磁盘服务)。

; 使用INT 0x10显示一个字符
MOV AH, 0x0E        ; 功能号:TTY输出
MOV AL, 'A'         ; 要显示的字符
MOV BH, 0x00        ; 页码
INT 0x10            ; 调用BIOS视频中断
关键点: 调用BIOS中断前,必须将功能号放入AH寄存器,参数放入其他指定寄存器。中断返回后,结果通常存放在AX或标志寄存器中。

4.3 堆栈操作

堆栈是一种后进先出(LIFO)的数据结构,由SS(堆栈段)和SP(堆栈指针)共同管理。堆栈在子程序调用、中断处理和临时数据保存中至关重要。

4.3.1 压栈与出栈

  • PUSH:先将SP减2(16位)或4(32位),然后将数据存入SP指向的地址。
  • POP:从SP指向的地址读取数据,然后将SP加2或4。
PUSH AX             ; 将AX压入堆栈
PUSH BX             ; 将BX压入堆栈
POP BX              ; 弹出到BX(后进先出,BX恢复原值)
POP AX              ; 弹出到AX

4.3.2 堆栈在子程序调用中的作用

CALL指令自动将返回地址压栈,RET指令自动弹出。嵌套调用时,堆栈保存了完整的调用链。

堆栈操作示意图(CALL / RET 过程) 堆栈(SS:SP) SP(栈顶) BP(栈底) 返回地址(高) 返回地址(低) 局部变量/参数 保存的BP CALL func 执行子程序 RET 压入返回地址 弹出返回地址

4.4 BIOS中断调用详解

BIOS中断是固件提供给实模式程序的标准化服务接口。每个中断对应一个功能类别,通过AH寄存器选择具体功能。

中断号服务类别常用功能(AH)输入参数输出结果
INT 0x10视频服务0x0E:TTY输出
0x00:设置显示模式
AL=字符
AL=模式号
无
无
INT 0x13磁盘服务0x02:读扇区
0x03:写扇区
CH=柱面, CL=扇区, DH=磁头, DL=驱动器, ES:BX=缓冲区AH=状态码, CF=0成功/1失败
INT 0x16键盘服务0x00:读按键
0x01:检测按键
无AH=扫描码, AL=ASCII码
INT 0x1A时间服务0x00:读系统时间无CX:DX=时钟滴答数
实模式限制: BIOS中断只能在实模式下使用。进入保护模式或长模式后,必须通过UEFI Runtime Services或直接硬件访问来替代。在UEFI BIOS开发中,传统INT调用被EFI Boot Services和Protocol接口取代。

4.5 综合示例:使用BIOS中断读取磁盘引导扇区

以下代码展示了如何在实模式下使用 INT 0x13 读取硬盘的主引导记录(MBR)到内存地址 0x7C00:

; 读取磁盘第一个扇区(MBR)到 0x7C00
mov ax, 0x07C0
mov es, ax          ; ES = 0x07C0
xor bx, bx          ; BX = 0, 缓冲区 = ES:BX = 0x7C00

mov ah, 0x02        ; 功能号:读扇区
mov al, 0x01        ; 读取1个扇区
mov ch, 0x00        ; 柱面0
mov cl, 0x01        ; 扇区1
mov dh, 0x00        ; 磁头0
mov dl, 0x80        ; 驱动器:第一个硬盘

int 0x13            ; 调用BIOS磁盘中断

jc read_error       ; 如果CF=1,跳转到错误处理

; 读取成功,跳转到0x7C00执行MBR
jmp 0x07C0:0x0000

read_error:
; 错误处理代码(略)
hlt
调试建议: 在QEMU或Bochs中单步执行上述代码,观察寄存器变化和内存内容。使用 info registers 和 xp /16xw 0x7C00 验证读取结果。

4.6 本章小结

  • 寄存器:通用寄存器(AX/BX/CX/DX)、指针寄存器(SP/BP)、段寄存器(CS/DS/ES/SS)和标志寄存器(FLAGS)构成了x86编程的基础。
  • 指令集:MOV负责数据搬运,ADD/SUB执行算术运算,JMP/CALL/RET控制程序流程,INT触发系统服务。
  • 堆栈:通过PUSH/POP实现LIFO管理,是子程序嵌套和中断处理的核心机制。
  • 中断调用:BIOS通过INT指令提供标准硬件抽象层,实模式下是访问磁盘、键盘、显示器的唯一标准途径。