当前位置: 首页>后端>正文

内存寻址方式

1. 处理字符问题

汇编中, 用'...' 的方式致命数据是以字符的形势给出的, 编译器将把他们转化为相对应的ASCII 码

assume cs:code,ds:data
data segment
       db 'unIX'
       db 'foRK'
data ends
code segment
start: mov al,'a'
       mov bl,'b'
       mov ax,4c00h
       int 21h
code ends
end start
内存寻址方式,第1张
字符串转化为对应额ASCII

大小写转换

  • 将第一个字符串, 小写字母转换为大写
  • 将第二个字符串, 大写转换为小写
assume cs:code,ds:data
data segment
       db 'BaSiC'
       db 'iNfOrMaTiOn'
data ends

code segment
start: mov ax,data
       mov ds,ax

       mov bx,0
       mov cx,5
    s: mov al,[bx]
       and al,11011111b
       mov [bx],al
       inc bx
       loop s

       mov bx,5
       mov cx,11
   s0: mov al,[bx]
       or al,00100000b
       mov [bx],al
       inc bx
       loop s0
       
       mov ax,4c00h
       int 21h
code ends
end start
内存寻址方式,第2张
大小写转换结果
内存寻址方式,第3张
大写和小写差值

逻辑与指令add dest,src, 逻辑或指令or dest,src

2. [bx+idata] 方式寻址

含义: 表示一个内存单元, 它的偏移地址为(bx)+idata, bx 中的数值加上idata

例如:

mov ax,[bx+200]

  • 将一个内存单元的内容送入ax
  • 内存单元长度为2字节
  • 内存单元段地址在ds 中, 偏移地址为200, 加上bx 中的数值
  • 描述为: (ax)=((ds)*16+200+(bx))

其他用法

mov ax,[200+bx]

mov ax,200[bx]

mov ax,[bx].200

内存寻址方式,第4张
(bx)+idata

类似c 语言中的数组

  • 将第一个字符串转换为大写
  • 第二个转换为小写
assume cs:code,ds:data
data segment
       db 'BaSiC'
       db 'MinIX'
data ends

code segment
start: mov ax,data
       mov ds,ax

       mov bx,0
       mov cx,5
    s: mov al,[bx]
       and al,11011111b
       mov [bx],al
       
       mov al,[5+bx]
       or al,00100000b
       mov [5+bx],al

       inc bx
       loop s
       
       mov ax,4c00h
       int 21h
code ends
end start
内存寻址方式,第5张
使用偏移idata结果

相当于c 语言中的数组

char a[5]="BaSiC";
char b[5]="MinIX";
main(){
  int i;
  i=0;
  do{
    a[i]=a[i]&0xDF;
    b[i]=b[i]|0x20;
    i++;
  }
  while(i<5);
}

3. SI 和DI寄存器

两个寄存器为变址寄存器

常执行与地址有关的操作

SI 和DI 是8086cpu 中和bx 功能相近的寄存器

区别为SI 和DI 不能够区分成两个8 位寄存器来使用

bx: 通用寄存器, 在计算存储器地址时, 常作为基址寄存器用

si: source index, 源变址寄存器

di: destination index, 目标变址寄存器

这三组代码含义相同

mov bx,0
mov ax,[bx]

mov si,0
mov ax,[si]

mov di,0
mov ax,[di]

====================

mov bx,0
mov ax,[bx+123]

mov si,0
mov ax,[123]

mov di,0
mov ax,[di+123]

例如, 用寄存器si 和di 实现将字符串'welcome to masm' 复制到它后面的数据区中

ds:si 指向要复制的原始字符串

ds:di 指向目的空间

使用循环完成复制

assume cs:code,ds:data
data segment
       db 'welcome to masm!'
       db '................'
data ends

code segment
start: mov ax,data
       mov ds,ax

       mov si,0
       mov di,16
    s: mov ax,[si]
       mov [di],ax
       add si,2
       add di,2
       loop s
       
       mov ax,4c00h
       int 21h
code ends
end start
内存寻址方式,第6张
使用si和di复制字符串

4. [bx+si] 和[bx+di] 方式寻址

[bx+si] 表示一个内存单元

偏移地址为(bx)+(si), bx 中的数值加上si 的数值

指令mov ax,[bx+si] 含义

  • 将一个内存单元的内容送入ax
  • 这个内存单元长度为2 个字节
  • 偏移地址为bx 中的数值加上si 中的数值
  • 段地址在ds 中
  • 数学化描述为(ax)=((ds)*16+(bx)+(si)), 其他写法mov ax,[bx][si]
内存寻址方式,第7张
[bx+si]和[bx+di]方式寻址

5. [bx+si+idata] 和[bx+di+idata]

[bx+si+idata] 表示一个内存单元

偏移地址为(bx)+(si)+idata, bx 中的数值加上si 数值再加idata

指令mov ax,[bx+si+idata] 含义

  • 将一个内存单元内容送入ax
  • 这个内存单元长度为2 个字节
  • 偏移地址为bx 中的数值加si 数值再加idata, 段地址在ds 中
  • 描述为(ax)=((ds)*16+(bx)+(si)+idata)

其他写法

mov ax,[bx+200+si]
mov ax,[200+bx+si]
mov ax,200[bx][si]
mov ax,[bx].200[si]
mov ax,[bx][si].200
mov ax,[bx][si]
内存寻址方式,第8张
[bx+si+idata]和[bx+di+idata]寻址

6. 不同寻址方式的应用

形式 名称 特点 意义 示例
[idata] 直接寻址 用一个常量/立即数表示地址 用于直接定位一个内存单元 mov ax,[200]
[bx] 寄存器间接寻址 一个变量表示内存地址 间接定位一个内存单元 mov bx,0
mov ax,[bx]
[bx+idata] 寄存器相对寻址 一个变量和常量表示地址 可在一个起始地址的基础上用变了间接定位一个内存单元 mov bx,4
mov ax,[bx+200]
[bx+si] 基址变址寻址 两个变量表示地址 mov ax,[bx+si]
[bx+si+idata] 相对基址变址寻址 两个变量和一个常量表示地址 mov ax,[bx+si+200]

案例1:

将data 段中的每个单词头一个字母改为大写

assume cs:code,ds:data
data segment
       db '1. file         '
       db '2. edit         '
       db '3. search       '
       db '4. view         '
       db '5. options      '
       db '6. help         '
data ends

code segment
start: mov ax,data
       mov ds,ax

       mov bx,0
       mov cx,6
    s: mov al,[bx+3]
       and al,11011111b
       mov [bx+3],al
       
       add bx,16
       loop s
       
       mov ax,4c00h
       int 21h
code ends
end start
内存寻址方式,第9张
每个单词头一个字母改为大写

案例2:

将data 段中的每个单词都改为大写

assume cs:code,ds:data
data segment
       db 'ibm             '
       db 'dec             '
       db 'dox             '
       db 'vax             '
data ends

code segment
start: mov ax,data
       mov ds,ax

       mov bx,0
       mov cx,4
   s0: mov si,0
       mov cx,3
    s: mov al,[bx+si]
       and al,110111111b
       mov [bx+si],al
       inc si 
       loop s
       add bx,16
       loop s0
       
       mov ax,4c00h
       int 21h
code ends
end start

4 个字符串, 看成一个4 行16 列的二维数组, 只要修改二维数组的每一行的前三列, 构造4*3 的二重循环

但是循环次数由cx 决定, cx 只有一个, 此段代码有问题

如何解决

将外层循环的cx 保存到dx 中, 再将cx 设置为内循环次数3, 内循环完, 再将dx 的值赋值给cx

     s0: mov dx,cx ;将外层cx 保存到dx 中
       mov si,0
       mov cx,3 ;设置内层循环次数
    s: mov al,[bx+si]
       and al,110111111b
       mov [bx+si],al
       inc si 
       loop s
       add bx,16
       mov cx,dx ;恢复cx 外层循环次数
       loop s0

但是寄存器只有14 个, 如果dx 也已经被使用, 还是有问题

如果使用固定的内存空间保存数据, 但是这个内存空间也会被占用的可能

最终的解决方法

使用栈来管理数据

stack segment
       dw 0,0,0,0,0,0,0,0
stack ends

code segment
start: mov ax,data
       mov ds,ax

       mov bx,0
       mov cx,4
   s0: push cx ;将外层循环cx 压栈
       mov si,0
       mov cx,3
    s: mov al,[bx+si]
       and al,11011111b
       mov [bx+si],al
       inc si 
       loop s
       add bx,16
       pop cx ;从栈顶弹出原cx 值, 恢复cx
       loop s0

7. 用于内存寻址的寄存器

正确的指令

mov ax,[bx]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp]
mov ax,[bp+si]
mov ax,[bp+di]
mov ax,[bx]
mov ax,[si]
mov ax,[di]
mov ax,[bp]
mov ax,[bx+si]
mov ax,[bx+di]

mov ax,[bp+si]
mov ax,[bp+di]
mov ax,[bx+si+idata]
mov ax,[bx+di+idata]
mov ax,[bp+si+idata]
mov ax,[bp+di+idata]

只有bx, bp, si, di 可以用在[...] 对内存单元寻址

bx 以外的通用寄存器, 段寄存器不可以用在[...] 中

bx 和bp 区别

  • bx 默认指ds 段
  • bp 默认指ss 段

或者直接指定段地址

mov ax,ds:[bp]

mov ax,es"[bp]

8. 处理数据的位置和长度

数据位置的表达

立即数 寄存器 内存:段地址(SA) 和偏移地址(EA)
对于直接包含在机器指令中的数据, 称为立即数idata, 数据包含在指令中
mov ax,1
mov al,'a'
指令要处理的数据在寄存器中, 在汇编指令中给相应的寄存器名
mov ax,bx
mov ds:[0],bx
指令要处理的数据在内存中, 由SA:EA 确定内存单元
内存寻址方式,第10张
段地址偏移地址

要处理数据的长度

内存寻址方式,第11张
要处理数据的长度

9. 寻址方式的案例

一条记录

姓名: yao

生日: 19800912

球衣号码: 15

场均得分: 32

球队: SHH

修改为:

球衣 -> 11

得分 -> 13

球队 -> HOU

内存寻址方式,第12张
修改这条记录
mov ax,seg
mov ds,ax
mov bx,60h
mov word ptr [bx+0ch],11
mov word ptr [bx+0eh],13

mov si,0
mov byte ptr [bx+10h+si],'H'
inc si
mov byte ptr [bx+10h+si],'O'
inc si
mov byte ptr [bx+10h+si],'U'

如果是c 语言则是

#include <stdio.h>
struct Player{
    char name[3];
    char birthday[9];
    int num;
    int ppg;
    char team[3];
};
struct Player yao={"Yao", "19800912", 15, 32, "SHH"}
int main()
{
    int i;
    yao.num = 11;
    yao.ppg = 13;
    i = 0;
    yao.team[i] = "H";
    i++;
    yao.team[i] = "O";
    i++;
    yao.team[i] = "U";
    return 0;
}

yao.team[i]: yao是一个变量名, 指明了结构体变量的地址, team 是一个名称, 指明数据项team 的地址, i 用来定位team 中的字符

用bx 定位整个结构体, 用idata 定位结构体中的某一个数据项, 用si 定位数据项中的元素

10. div 指令实现除法

  • 被除数: 默认放在ax 或dx 和ax 中
  • 除数: 8 位或16 位, 在寄存器或内存单元中

格式为

  • div 寄存器
  • div 内存单元

结果

被除数 ax dx 和ax
除数 8 位内存或寄存器 16 位内存或寄存器
al ax
余数 ah dx
指令 被除数 除数 余数
div bl (ax) (bl) (al) (ah)
div byte ptr ds:[0] (ax) ((ds)*16+0) (al) (ah)
div byte ptr [bx+si+8] (ax) ((ds)*16+(bx) +(si)+8) (al) (ah)
div bx (dx)*10000H+(ax) (bx) (ax) (dx)
div word ptr es:[0] (dx)*10000H+(ax) ((ds)*16+0) (ax) (dx)
div word ptr [bx+si+8] (dx)*10000H+(ax) ((ds)*16+(bx) +(si)+8) (ax) (dx)

注意: 提前在默认的寄存器中设置好被除数, 且不能用在别处

11. dup 设置内存空间

dup 和db, dw, dd 等数据定义伪指令配合使用, 用来进行数据的重复

指令 功能 相当于
db 3 dup(0) 定义3 个字节, 值都是0 db 0,0,0
db 3 dup(0,1,2) 定义9 个字节, 由0,1,2 重复3 次 db 0,1,2,0,1,2,0,1,2
db 3 dup('abc','ABC') 定义18 个字节, 构成'abcABCabcABCabcABC' db 'abcABCabcABCabcABC'

https://www.xamrdz.com/backend/3xe1995264.html

相关文章: