---
ingested: true
ingestedAt: 2026-05-17
---
标题: 汇编语言 - 寻址方式
UP主: 菜鸟教程
链接: https://www.runoob.com/assembly/assembly-addressing.html
提取方式: WebFetch
内容: ## 汇编语言 - 寻址方式
寻址方式(Addressing Mode)决定了 CPU 如何定位指令的操作数——数据从哪里来、结果存到哪里去。
---
## 什么是寻址方式
每条汇编指令的操作数可以是立即数、寄存器中的值或内存中的数据。
寻址方式 就是告诉 CPU 如何计算操作数的实际地址或直接给出操作数值。
x86 架构提供了多种灵活的寻址方式,理解每种方式的使用场景是写出高效汇编代码的基础。
---
## 立即寻址(Immediate Addressing)
操作数直接包含在指令中,是一个常量值。
源操作数是立即数,CPU 直接从指令中读取,不需要访问内存或寄存器。
## 实例
; 立即寻址示例
mov eax, 42 ; 42 是立即数,直接编码在指令中
add ebx, 100 ; 100 是立即数
mov ecx, 0x2A ; 十六进制立即数
mov edx, 'A' ; 字符 'A' = 0x41,也是立即数
> 立即寻址是最快的"寻址方式",因为数据就在指令流中,CPU 取指令的同时就拿到了数据。但立即数只能作为源操作数,不能作为目标操作数。不能写 `mov 42, eax`。
---
## 寄存器寻址(Register Addressing)
操作数存放在寄存器中,CPU 直接操作寄存器。
这同样是最快的操作方式之一,因为没有内存访问开销。
## 实例
; 寄存器寻址示例
mov eax, ebx ; 将 ebx 的值复制到 eax(两个操作数都是寄存器寻址)
add ecx, edx ; ecx = ecx + edx
push eax ; 将 eax 的值压入栈
inc ebx ; ebx = ebx + 1
> 寄存器寻址速度最快,在写汇编代码时优先使用寄存器存放频繁访问的数据。但寄存器数量有限,不能把所有数据都塞在寄存器中。
---
## 直接寻址(Direct Addressing)
操作数是一个内存地址,地址直接写在指令中(以变量标签的形式)。
CPU 需要访问一次内存来读取或写入数据。
## 实例
; 文件路径:direct\_addr.asm
; 直接寻址示例
section .data
value dd 12345678 ; 在内存中定义一个双字变量
name db 'runoob', 0
section .text
global \_start
\_start:
; 直接寻址读取内存
mov eax, \[value\] ; 从内存地址 value 读取 4 字节到 eax
; eax 现在是 12345678
; 直接寻址写入内存
mov dword \[value\], 98765 ; 将 98765 写入 value 所在的内存地址
; 直接寻址读取字节
mov al, \[name\] ; 读取 name 的第一个字节 'r' = 0x72
mov bl, \[name + 1\] ; 读取 name 的第二个字节 'u' = 0x75
mov eax, 1
mov ebx, 0
int 0x80
---
## 寄存器间接寻址(Register Indirect Addressing)
寄存器中存放的是一个内存地址,CPU 用该地址去访问内存。
方括号内的寄存器被当作指针使用。
## 实例
; 文件路径:indirect\_addr.asm
; 寄存器间接寻址示例
section .data
msg db 'Hello, RUNOOB!', 0xA
len equ $ \- msg
section .text
global \_start
\_start:
mov eax, msg ; 将 msg 的地址(指针)放入 eax
mov al, \[eax\] ; 间接寻址:读取 eax 指向的内存字节
; 现在 al = 'H' = 0x48
; 遍历字符串,将小写字母转为大写
mov esi, msg ; esi 指向字符串起始位置
mov ecx, len ; ecx 存放字符串长度
convert\_loop:
mov al, \[esi\] ; 间接寻址:读取 esi 指向的字符
cmp al, 'a' ; 是否大于等于 'a'
jb next\_char ; 否,跳过
cmp al, 'z' ; 是否小于等于 'z'
ja next\_char ; 否,跳过
sub al, 32 ; 转为大写(ASCII 表中小写-大写=32)
mov \[esi\], al ; 间接寻址:写回 esi 指向的位置
next\_char:
inc esi ; 指针移动到下一个字符
loop convert\_loop ; 继续循环直到全部处理完
; 输出转换后的字符串
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, len
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
> 间接寻址是数组遍历、字符串操作和数据结构访问的基础。ESI 和 EDI 是专门设计用来配合间接寻址的寄存器,配合 `inc esi` 可以轻松遍历连续内存。
---
## 基址寻址(Base Addressing)
有效地址 = 基址寄存器的值 + 偏移量(位移量)。
基址寄存器可以是 EBX、EBP、ESI、EDI 等。
## 实例
; 基址寻址示例:访问结构体成员
section .data
; 模拟一个简单的结构体:{id, age, score}
; id = 2 字节
; age = 2 字节
; score = 4 字节
student db 0x01, 0x00 ; id = 1
db 0x14, 0x00 ; age = 20
dd 95 ; score = 95
section .text
global \_start
\_start:
mov ebx, student ; ebx 存放结构体基址
; 基址 + 偏移量访问各成员
mov ax, \[ebx\] ; 读取 id(偏移 0)
mov ax, \[ebx + 2\] ; 读取 age(偏移 2)
mov eax, \[ebx + 4\] ; 读取 score(偏移 4)
; 修改 age
mov word \[ebx + 2\], 21 ; age = 21
; 修改 score
mov dword \[ebx + 4\], 98 ; score = 98
mov eax, 1
mov ebx, 0
int 0x80
---
## 变址寻址(Indexed Addressing)
使用变址寄存器(ESI 或 EDI)加上偏移量来访问数组元素。
## 实例
; 变址寻址示例:遍历数组
section .data
array dd 10, 20, 30, 40, 50 ; 5 个双字元素的数组
array\_len equ ($ \- array) / 4 ; 元素个数 = 总字节数 / 4
section .text
global \_start
\_start:
mov ecx, array\_len ; 循环计数器
mov esi, 0 ; 变址(下标从 0 开始)
mov ebx, 0 ; 累加和
sum\_loop:
mov eax, \[array + esi \* 4\] ; 变址寻址:array + 下标 \* 元素大小
; esi \* 4 因为每个元素是 4 字节
add ebx, eax ; 累加到 ebx
inc esi ; 下标加 1
loop sum\_loop
; ebx = 10+20+30+40+50 = 150
; 变址 + 偏移:访问第二个元素
; array + 2\*4 = array + 8,即 30
mov eax, \[array + 2\*4\] ; eax = 30
mov eax, 1
mov ebx, 0
int 0x80
---
## 基址变址寻址(Base-Indexed Addressing)
有效地址 = 基址寄存器 + 变址寄存器 × 比例因子 + 偏移量。
这是 x86 中最强大的寻址方式,可以在一条指令中完成地址计算。
**注意:x86 仅支持一个变址寄存器 × 比例因子,不支持多个带比例因子的寄存器。**
## 实例
; 基址变址寻址示例:二维数组访问
section .data
; 3 行 4 列的二维数组
matrix dd 1, 2, 3, 4
dd 5, 6, 7, 8
dd 9, 10, 11, 12
section .text
global \_start
\_start:
; 访问 matrix\[1\]\[2\](第 2 行第 3 列,下标从 0 开始)
; 地址 = matrix + 行\*每行字节数 + 列\*每元素字节数
; = matrix + 1\*16 + 2\*4
; = matrix + 24
mov ebx, matrix ; 基址寄存器
mov esi, 24 ; 计算好的总偏移量
; 正确格式:基址 + 偏移量
mov eax, \[ebx + esi\] ; eax = 7
; 标准基址变址寻址格式:\[基址 + 变址\*比例因子 + 偏移量\]
; 直接访问第 6 个元素(matrix\[6\] = 7)
mov edi, 6
mov eax, \[matrix + edi\*4\] ; eax = 7
; 程序退出
mov eax, 1
mov ebx, 0
int 0x80
---
## 寻址方式总览
下图完整展示了 x86 的 7 种寻址方式及其工作原理:

| 寻址方式 | 语法格式 | 有效地址/值 | 典型用途 |
| ----- | ------------------------- | ---------------------- | ---------- |
| 立即寻址 | mov eax, 42 | 42(常数值) | 初始化、常量运算 |
| 寄存器寻址 | mov eax, ebx | 寄存器 ebx 的值 | 寄存器间数据传递 |
| 直接寻址 | mov eax, \[var\] | 内存地址 var 处的值 | 访问全局变量 |
| 间接寻址 | mov eax, \[ebx\] | 地址 = ebx 的值 | 指针操作、遍历内存 |
| 基址寻址 | mov eax, \[ebx+8\] | 地址 = ebx + 8 | 结构体成员访问 |
| 变址寻址 | mov eax, \[arr+esi\*4\] | 地址 = arr + esi × 4 | 一维数组访问 |
| 基址变址 | mov eax, \[ebx+esi\*4+8\] | 地址 = ebx + esi × 4 + 8 | 二维数组、复杂结构体 |
> 在 32 位保护模式下,所有的通用寄存器都可以作为基址或变址寄存器。这与16位实模式有很大不同(16位模式下只有 BX、BP、SI、DI 可用于寻址)。32 位的灵活性让寻址变得更加方便。