目录
第七章:更灵活的定位内存地址的方法
📌 主要内容
本章主要介绍了汇编语言中更灵活的数据访问方式,尤其是如何通过寄存器间接访问内存地址,以及对字符串和数组等结构的处理方式。同时,还引入了与字符编码(如 ASCII)相关的处理技巧,为后续进行字符数据处理打下基础。
重点内容包括:
- 使用
AND与OR指令进行按位操作; - 理解 ASCII 编码结构及大小写转换方法;
- 使用
db指令以字符形式定义数据; - 实现字符大小写转换;
- 使用
[bx+idata]形式访问数组元素; - 引入
SI和DI作为源/目的索引寄存器; - 各种基址加变址寻址方式的组合(如
[bx+si],[bx+si+idata]); - 数组、字符串等结构的数据访问技巧;
- 本章实验中通过具体程序加深对寻址方式灵活性的理解。
📘 本章的核心是灵活寻址方式的掌握,它是汇编中处理复杂数据结构的关键能力。
7.1 AND 和 OR 指令
-
AND 和 OR 的基本用法
在汇编语言中,
AND和OR是用于按位逻辑运算的指令。AND:对两个操作数进行按位“与”运算;OR:对两个操作数进行按位“或”运算。
它们的作用对象可以是寄存器、内存或立即数,格式如下:
and 目标, 源 or 目标, 源- 运算结果保存在目标操作数中;
- 操作数必须具有相同的位宽(8位或16位);
- 可用于清零某些位,或置位某些位。
-
示例 1:清除寄存器中高 8 位
and ax, 00FFh- 效果:将
AX寄存器的高 8 位清零,低 8 位保持不变。
- 效果:将
-
示例 2:置位低 4 位
or al, 0Fh- 效果:将
AL寄存器的低 4 位设置为 1。
- 效果:将
-
常见用途
- 清除位(用 AND);
- 强制某些位为 1(用 OR);
- 可用于提取标志位、屏蔽数据、统一大小写处理等场景;
- 在字符处理中经常与 ASCII 编码结合使用。
💡 小结:AND 和 OR 是汇编中非常基础的按位逻辑指令,掌握它们的使用有助于操作位模式、控制硬件状态和处理字符数据。
7.2 关于 ASCII 码
-
ASCII 码简介
- ASCII(American Standard Code for Information Interchange)是一种字符编码标准;
- 每个英文字符、数字或符号都被映射为一个唯一的 7 位或 8 位二进制数;
- 常见字符的 ASCII 编码如下:
'A'→41H(十六进制)'a'→61H'0'→30H- 空格 →
20H
-
ASCII 编码结构特性
- 大小写英文字母之间的编码只差一个位:
'A'=0100_0001'a'=0110_0001- 可见,第五位(从右起)不同,用于区分大小写;
- 因此,大小写转换只需用 AND 或 OR 指令修改特定位。
- 大小写英文字母之间的编码只差一个位:
-
示例:将小写字母转为大写
and al, 1101_1111b ; 清除第 5 位- 或使用十六进制:
and al, 0DFh -
示例:将大写字母转为小写
or al, 0010_0000b ; 设置第 5 位- 或使用十六进制:
or al, 20h -
实用场景
- 实现大小写统一;
- 判断某个字符是否为字母或数字;
- 进行字符串处理时常需引用 ASCII 表。
💡 小结:理解 ASCII 编码规律可让我们用位操作快速完成字符转换,提高程序执行效率。
7.3 以字符形式给出的数据
-
定义字符串的方式
在汇编语言中,字符和字符串可以通过
db(define byte)伪指令直接以字符形式定义。例如:msg db 'Hello, world!', 0- 每个字符会被转换为对应的 ASCII 码;
msg是标签名,代表该字符串在段内的偏移地址;- 最后的
0是字符串结束符(通常表示空字符NULL,ASCII 值为00h)。
-
ASCII 编码查看
该定义在内存中的实际内容是:
48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 H e l l o , w o r l d ! \0 -
字符数组与访问方式
由于字符串本质上就是按字节排列的数据数组,可使用偏移或寄存器间接访问,例如:
mov si, offset msg mov al, [si] ; 取第一个字符 H inc si mov al, [si] ; 取第二个字符 e -
应用场景
- 定义提示信息、错误信息等静态文本;
- 数据缓冲区(如用户输入区);
- 字符串处理(搜索、转换、输出等);
- 配合系统调用(如
int 21h功能 09h)进行输出。
💡 小结:db 'abc' 是汇编中最常见的字符串定义方式,本质是以 ASCII 编码形式逐字节排列。理解这一点是掌握字符串处理的关键。
7.4 大小写转换的问题
-
ASCII 大小写规律
在 ASCII 编码中,大小写字母具有如下特点:
字符 二进制(高4位) 二进制(低4位) 十六进制 ‘A’ 0100 0001 41H ‘a’ 0110 0001 61H 可以看到,
'A'和'a'的唯一区别在于第 5 位(从右起)是否为 1。 -
大写转小写:设置第5位
or al, 0010_0000b ; OR 20H- 若 AL 原为
'A'(41H),执行后变为'a'(61H)
- 若 AL 原为
-
小写转大写:清除第5位
and al, 1101_1111b ; AND DFH- 若 AL 原为
'b'(62H),执行后变为'B'(42H)
- 若 AL 原为
-
大小写转换应用
可以使用循环,将整个字符串逐个字符处理:
mov si, offset msg next_char: mov al, [si] or al, 0 jz end_loop ; 遇到0,表示字符串结束 and al, 0DFh ; 转为大写 mov [si], al inc si jmp next_char end_loop: -
适用范围
- 仅适用于英文大小写英文字母;
- 若用于其他符号或数字,将无效或造成破坏性修改;
- 可用于规范用户输入、统一显示风格、搜索时忽略大小写等。
💡 小结:大小写转换是 ASCII 编码的典型应用场景,使用 OR 和 AND 可以高效地完成字符变换操作。
7.5 [bx+idata] 的使用方式
-
什么是
[bx+idata]?[bx+idata]是一种间接寻址方式,通过BX中的基址加上一个立即数偏移idata,用于灵活访问内存中的数据。bx:基址寄存器,通常保存数组或数据表的起始偏移地址;idata:常数偏移,用于访问特定位置;- 实际访问地址为:
DS × 16 + (BX + idata)
-
语法格式
mov al, [bx+0] mov al, [bx+1]如果数据为字符串或字节数组,可以通过增加
idata逐个访问:mov bx, offset msg mov al, [bx+0] ; 第一个字符 mov al, [bx+1] ; 第二个字符 -
应用:访问数组或字符串中的元素
mov bx, offset data_array mov al, [bx+3] ; 访问数组的第4个元素 -
注意事项
[bx+idata]中的idata是一个立即数,不能是变量或寄存器;- 最大偏移不能超过段的界限(一般 64KB);
DS是默认段寄存器,除非使用段前缀修改;- 运算过程中不会改变
BX的值。
-
对比
表达式 含义 [bx]访问 DS:[BX][bx+2]访问 DS:[BX+2][bx+idata]访问以 BX 为基础的某个偏移位
💡 小结:[bx+idata] 是数组处理中的关键寻址方式,灵活使用它可以在汇编中模拟 C 语言的下标访问操作。
7.6 用 [bx+idata] 的方式进行数组的处理
-
数组访问背景
在汇编语言中,没有类似 C 的数组下标语法,但可以通过
[bx+idata]实现对数组中任意元素的访问。假设有如下数组定义:
data segment db 10h, 20h, 30h, 40h, 50h data ends- 每个元素占一个字节;
10h是第 0 个元素,20h是第 1 个,以此类推。
-
访问方式:使用
BX作基址 + 偏移量assume ds:data mov ax, data mov ds, ax ; 初始化数据段 mov bx, 0 mov al, [bx+2] ; 读取第 3 个元素 → AL = 30h -
结合循环访问数组
使用循环变量控制偏移访问数组各元素:
mov bx, offset arr ; BX 指向数组首地址 mov si, 0 ; SI 用作偏移计数器 next: mov al, [bx+si] ; 读取第 SI 个元素 ; ...(处理 AL 中的数据) inc si cmp si, 5 jl next -
数组作为字符串
若数组中是字符(例如
'HELLO'),访问方式完全相同:msg db 'HELLO', 0 mov bx, offset msg mov al, [bx+1] ; AL = 'E' -
注意事项
- 访问超出数组范围可能导致错误或访问非法数据;
- 若为 word 数组,则偏移量必须为 2 的倍数;
- 操作数类型必须匹配:
AL对应byte,AX对应word。
💡 小结:通过 [bx+idata] 实现“数组名+下标”的效果,是汇编中最常见也最灵活的数组处理方式。
7.7 SI 和 DI 寄存器的使用
-
SI(Source Index)和 DI(Destination Index)
SI和DI是 8086 中专用的变址寄存器,用于支持字符串操作和更灵活的内存寻址。SI:源变址寄存器(Source Index)DI:目的变址寄存器(Destination Index)
-
默认段寄存器
寄存器 默认段寄存器 SI DS DI ES 在字符串操作(如
MOVS,LODS,STOS)中,SI用于读取源数据,DI用于写入目标数据。 -
基本访问方式
mov si, offset data mov al, [si] ; 实际是 mov al, ds:[si] mov di, offset dest mov [di], al ; 实际是 mov es:[di], al(若未改 ES)- 可以通过
inc si/inc di来遍历字符串或数组。
- 可以通过
-
应用:字符串复制伪代码
mov si, offset src mov di, offset dst next_char: mov al, [si] mov [di], al inc si inc di cmp al, 0 jne next_char- 复制以 0 结尾的字符串;
SI递增,读取源字符串;DI递增,写入目标位置。
-
与
bx+si、bx+di组合SI和DI也可以与BX组合用于地址计算,具体在后续 7.8 节详述。
💡 小结:SI 和 DI 是汇编处理字符串和数组的核心寄存器,配合段寄存器可进行高效的数据复制、比较等操作。
7.8 [bx+si] 和 [bx+di] 的使用方式
-
组合变址寻址
在处理复杂数据结构或二维数组时,常需要同时使用两个寄存器来计算地址,
[bx+si]和[bx+di]就是两种常见的基址+变址寻址方式。BX:基址寄存器,常用于记录数组起始地址;SI/DI:变址寄存器,用作偏移;- 实际访问地址:
DS × 16 + (BX + SI)或DS × 16 + (BX + DI)
-
语法示例
mov bx, offset table ; BX → 表起始 mov si, 4 ; SI → 偏移量 mov ax, [bx+si] ; AX ← table[4] -
适用场景
- 结构体数组(record array);
- 二维数组(例如 table[row][col]);
- 按段偏移组合读取数据;
- 灵活遍历内存数据结构。
-
示例:处理结构体数组
假设每个记录长度为 6 字节(3 个 word),要访问第 n 项的第二个 word:
mov bx, offset table mov si, 6 ; 第 2 项偏移 mov ax, [bx+si+2] ; 访问第 2 项的第 2 个 word -
与 SI/DI 单独使用的对比
方式 特点 [si]用于字符串读取 [bx+si]更灵活,可在 BX 上加偏移量 [bx+di]可在 DI 上控制目标数据偏移 -
注意事项
- 不支持
[si+di]这类写法; - 只能组合 BX 与 SI 或 BX 与 DI;
- 使用
bp时默认段为 SS,需要段前缀改为 DS。
- 不支持
💡 小结:[bx+si] 和 [bx+di] 为汇编带来了类似高级语言“数组+下标”的写法,是处理结构化数据和多维结构的关键寻址形式。
7.9 [bx+si+idata] 和 [bx+di+idata] 的使用方式
-
三项寻址结构
[bx+si+idata]与[bx+di+idata]是基址 + 变址 + 偏移 的寻址方式,用于访问结构更复杂或嵌套的数据结构。BX:基址寄存器SI/DI:变址寄存器idata:立即数偏移
实际访问地址:
DS × 16 + (BX + SI + idata)
或:DS × 16 + (BX + DI + idata) -
语法格式
mov ax, [bx+si+4] ; 访问 BX+SI 偏移 4 的地址 mov ax, [bx+di+2] ; 访问 BX+DI 偏移 2 的地址 -
适用场景
- 访问结构体数组中的特定字段;
- 处理二维数组中偏移较深的数据项;
- 编写通用地址计算逻辑。
-
示例:访问结构体数组中字段
假设结构体长度为 8 字节,其中前 2 字节为 ID,第 3 个字节为标志位,现在要访问第 3 个结构体的标志字段:
mov bx, offset table ; BX → 表起始 mov si, 16 ; 第 3 个结构体偏移:8×2 = 16 mov al, [bx+si+2] ; 访问该结构体的第 3 个字节 -
支持的寄存器组合(仅限以下4种)
有效组合 默认段寄存器 [bx+si+idata]DS [bx+di+idata]DS [bp+si+idata]SS [bp+di+idata]SS - 除
BX可用于数据段,BP默认用于栈段; - 若需用
BP访问数据段,需显式添加段前缀:mov ax, ds:[bp+si+4]
- 除
-
注意事项
idata必须是立即数;- 指令执行时,寄存器值不会被修改;
- 地址不能越过段的 64KB 边界。
💡 小结:三项寻址提供了极高的寻址灵活性,是编写通用内存访问例程的基础。合理设计数据结构可最大化其优势。
7.10 不同寻址方式的灵活应用
-
常见寻址方式对比
方式 形式示例 特点与用途 立即寻址 mov ax, 1234h将常数直接送入寄存器 直接寻址 mov ax, [1000h]访问固定内存地址 寄存器间接寻址 mov ax, [bx]动态访问内存,适合遍历 基址+偏移 mov ax, [bx+4]访问数组中固定位置 基址+变址 mov ax, [bx+si]支持结构体数组等二维结构 基址+变址+常数 mov ax, [bx+si+2]访问结构体数组中的特定字段 -
数组访问举例
假设定义如下数组:
data segment db 10h, 20h, 30h, 40h, 50h, 60h data ends可以使用不同寻址方式访问其中的元素:
mov bx, offset array mov al, [bx] ; 第 0 项 mov al, [bx+3] ; 第 4 项 -
字符串遍历与处理
mov si, offset msg next: mov al, [si] or al, al jz done ; 判断是否为字符串结束符(0) ; 处理字符 AL ... inc si jmp next done: -
结构体数组处理
对于结构体数组,可以使用
[bx+si+idata]进行字段级访问:mov bx, offset table mov si, 12 ; 第 3 项起始(每项 4 字节) mov ax, [bx+si+2] ; 访问第 3 项中第 2 个字段(偏移2) -
灵活性总结
- 将寻址方式与循环/跳转结构结合,可以实现复杂的数据处理;
- 能模拟高级语言中的数组下标、结构体字段访问等语法;
- 是构建子程序、内存管理、数据通信等功能的基础。
💡 小结:灵活掌握不同寻址方式的组合使用,是从“汇编入门”迈向“结构化汇编编程”的关键一步。
🧪 实验6:实践课程中的程序
-
实验目的
- 掌握
[bx+idata]、[bx+si]、[bx+si+idata]等多种寻址方式的应用; - 实际编写程序,灵活处理数组、字符串等内存结构;
- 结合循环结构,实现内存中数据的批量读取与处理。
- 掌握
-
实验背景
假设我们有一组数据存储在内存中:
data segment db 1, 2, 3, 4, 5 data ends需要编写程序将这些数据逐个读出、累加求和,并将结果显示。
-
实验示例程序
assume cs:code, ds:data data segment db 1, 2, 3, 4, 5 data ends code segment start: mov ax, data mov ds, ax mov bx, 0 ; BX 作基址 mov cx, 5 ; CX 作计数器 mov si, 0 ; SI 作偏移量 mov ax, 0 ; AX 存放累加结果 next: mov al, [bx+si] ; 访问数据段中第 si 项 cbw ; AL 扩展为 AX(符号扩展) add ax, ax ; 将数据加到 AX(累加) inc si loop next ; AX 中为结果,可在此基础上调用中断输出等 mov ax, 4C00h int 21h code ends end start -
说明
- 使用
[bx+si]寻址访问数据; SI每次递增一个字节,访问下一个数组元素;LOOP指令配合CX实现循环结构;- 通过
CBW将AL转换为AX,防止加法错误; - 最终结果保存在
AX中,可用于后续显示。
- 使用
-
调试建议
- 在 Debug 中观察
[ds:bx+si]地址变化; - 跟踪
AX每次累加的过程; - 验证最终求和是否等于
1+2+3+4+5 = 15。
- 在 Debug 中观察
-
变形任务建议
- 改为求最大值/最小值;
- 替换为
word类型数组; - 实现两个数组对应项相加、相减等操作;
- 输出结果到屏幕上(调用
int 21h功能号 02H 或 09H)。
✅ 实验6是对第七章“寻址方式”理论的实际演练,编程过程中强化了 BX、SI、寻址语法与循环配合的实际操作能力。

1541

被折叠的 条评论
为什么被折叠?



