《汇编语言》第七章:更灵活的定位内存地址的方法



第七章:更灵活的定位内存地址的方法

📌 主要内容

本章主要介绍了汇编语言中更灵活的数据访问方式,尤其是如何通过寄存器间接访问内存地址,以及对字符串和数组等结构的处理方式。同时,还引入了与字符编码(如 ASCII)相关的处理技巧,为后续进行字符数据处理打下基础。

重点内容包括:

  • 使用 ANDOR 指令进行按位操作;
  • 理解 ASCII 编码结构及大小写转换方法;
  • 使用 db 指令以字符形式定义数据;
  • 实现字符大小写转换;
  • 使用 [bx+idata] 形式访问数组元素;
  • 引入 SIDI 作为源/目的索引寄存器;
  • 各种基址加变址寻址方式的组合(如 [bx+si], [bx+si+idata]);
  • 数组、字符串等结构的数据访问技巧;
  • 本章实验中通过具体程序加深对寻址方式灵活性的理解。

📘 本章的核心是灵活寻址方式的掌握,它是汇编中处理复杂数据结构的关键能力。


7.1 AND 和 OR 指令
  • AND 和 OR 的基本用法

    在汇编语言中,ANDOR 是用于按位逻辑运算的指令。

    • 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’0100000141H
    ‘a’0110000161H

    可以看到,'A''a' 的唯一区别在于第 5 位(从右起)是否为 1。

  • 大写转小写:设置第5位

    or al, 0010_0000b   ; OR 20H
    
    • 若 AL 原为 'A' (41H),执行后变为 'a' (61H)
  • 小写转大写:清除第5位

    and al, 1101_1111b  ; AND DFH
    
    • 若 AL 原为 'b' (62H),执行后变为 'B' (42H)
  • 大小写转换应用

    可以使用循环,将整个字符串逐个字符处理:

    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 对应 byteAX 对应 word

💡 小结:通过 [bx+idata] 实现“数组名+下标”的效果,是汇编中最常见也最灵活的数组处理方式。


7.7 SI 和 DI 寄存器的使用
  • SI(Source Index)和 DI(Destination Index)

    SIDI 是 8086 中专用的变址寄存器,用于支持字符串操作和更灵活的内存寻址。

    • SI:源变址寄存器(Source Index)
    • DI:目的变址寄存器(Destination Index)
  • 默认段寄存器

    寄存器默认段寄存器
    SIDS
    DIES

    在字符串操作(如 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+sibx+di 组合

    SIDI 也可以与 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 实现循环结构;
    • 通过 CBWAL 转换为 AX,防止加法错误;
    • 最终结果保存在 AX 中,可用于后续显示。
  • 调试建议

    • 在 Debug 中观察 [ds:bx+si] 地址变化;
    • 跟踪 AX 每次累加的过程;
    • 验证最终求和是否等于 1+2+3+4+5 = 15
  • 变形任务建议

    • 改为求最大值/最小值;
    • 替换为 word 类型数组;
    • 实现两个数组对应项相加、相减等操作;
    • 输出结果到屏幕上(调用 int 21h 功能号 02H 或 09H)。

✅ 实验6是对第七章“寻址方式”理论的实际演练,编程过程中强化了 BX、SI、寻址语法与循环配合的实际操作能力。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值