• 内存寻址方式


    一、处理字符

    1.存储形式

    汇编程序中,用 '……' 的方式指明数据是以字符的形式给出的,编译器将 把它们转化为相对应的ASCII码

    assume ds:data
    data segment
        db 'unIX'
    data ends

    2.大小写

    概念

    大写     二进制    小写    二进制
     A      01000001    a     01100001
     B      01000010    b     01100010
     C      01000011    c     01100011
     D      01000100    d     01100100

    小写字母的ASCII码值比大写字母的ASCII码值大20H ,所以:

    大写+20h->小写

    小写-20h->大写

    逻辑指令

    b转换为B

    and:逻辑与指令 and dest src

    全为1则为1,其他都为0

         0110 0010 (b)
    and  1101 1111
    --------------
    =    0100 0010 (B)

    I转换为i

    or:逻辑或指令 or dest src

    全为0则为0,其他都为1

       0100 1001 (I)
    or 0010 0000
    --------------
    =  0110 1001 (i)

    实际转换

    1. assume cs:codesg,ds:datasg
    2. datasg segment
    3. db 'BaSiC'
    4. db 'iNfOrMaTiOn' //内存中保存的都是16进制的ascii码值
    5. datasg ends
    6.    
    7. codesg segment
    8. start:
    9. mov ax,datasg
    10. mov ds,ax
    11. //第一个字符串,小写字母全部转为大写字母
    12. mov bx,0
    13. mov cx,5 //5个字符循环5次
    14. s:  mov al,[bx] //将第一个字符放到al寄存器里面
    15. and al,11011111b //进行逻辑与的操作,可以将小写字母转为大写字母
    16. mov [bx],al //再将结果写回到原来的地址处
    17. inc bx
    18. loop  
    19. //第二个字符串,大写字母全部转为小写字母
    20.    mov bx,5
    21. mov cx,11
    22. s0: mov al,[bx]
    23. or al,00100000b //进行逻辑或的操作,可以将大写字母转为小写字母
    24. mov [bx],al
    25. inc bx
    26. loop s
    27.    
    28.    mov ax,4c00h
    29. int 21h
    30. codesg ends
    31. end star

    二、[bx+idata]方式寻址

    1.含义

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

    mov ax,[bx+200] / mov ax, [200+bx] 的含义 ;

    1.将一个内存单元的内容送入ax ;

    2.这个内存单元的长度为2字节(字单元),存放一个字 ;

    3.内存单元的段地址在ds中,偏移地址为200加上bx中的数值 ;

    4.数学化的描述为: (ax)=((ds)*16+200+(bx)

    [bx+200]的其他写法:

    200[bx],[bx].200

    2.使用

    第一个字符串转化为大写

    第二个字符串转化为小写

    1. assume cs:code,ds:data
    2. data segment
    3. db 'BaSic'
    4. db 'MinIx'
    5. data ends
    6. code segment
    7. start:
    8. mov ax ,data
    9. mov ds ,ax
    10. mov bx,0
    11. mov cx,5 ;循环执行5
    12. mov ax,0 ;初始化ax寄存器
    13. s: mov al,[bx] ;将第一串字符中的第一个字符放入al寄存器中
    14. and al,11011111b ;将小写字符转为大写字符
    15. mov [bx],al ;再写回到原来的字符串
    16. mov al,[bx+5] ;再来处理第二个字符串
    17. or al,00100000b ;将大写字符转换为小写字符
    18. mov [bx+5],al
    19. inc bx
    20. loop s
    21. mov ax,4c00h
    22. int 21h
    23. code ends
    24. end start

    对比C语言实现大小写转换

    1. char a[5]="BaSiC";
    2. char b[5]="MinIX";
    3. int main()
    4. {
    5. int i;
    6. i=0;
    7. do
    8.   {
    9. a[i]=a[i]&0xDF;
    10. b[i]=b[i]|0x20;
    11. i++;
    12.   }
    13.    while(i<5);
    14. }

    三、[bx+si]和[bx+di]方式寻址

    1.变址寄存器

    主要用于存放存储单元在段内的偏移量

    SI——Source Index 源变址寄存器

    DI——Destination Index 目的变址寄存器

    2.含义

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

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

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

    1.将一个内存单元的内容送入ax

    2.这个内存单元的长度为2字节(字单元),存放一个字

    3.偏移地址为bx中的数值加上si中的数值

    4.段地址在ds中

    5.数学化的描述 : (ax)=( (ds)*16+(bx)+(si) )

    6.其他写法 :mov ax,[bx][si

    四、[bx+si+idata]和 [bx+di+idata]

    1.含义

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

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

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

    1.将一个内存单元的内容送入ax

    2.这个内存单元的长度为2字节(字单元),存放一个字

    3.偏移地址为bx中的数值加上si中的数值再加上idata,段地址在ds中

    4.数学化的描述 ; (ax)=( (ds)*16+(bx)+(si)+idata )

    5.其他写法

    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

    五、不同寻址方式的运用

    1.总结

    1.[idata]:直接寻址,用于直接指定一个内存单元

    2.[bx]:寄存器间接寻址,用于间接定位一个内存单元

    3.[bx+idata]:寄存器相对寻址,可在一个起始地址的基础上用变量间接定位一个内存单元

    4.[bx+si]:基址变址寻址,用两个变量表示地址

    5.[bx+si+idata]:相对基址变址寻址

    2.多重循环的问题

    循环次数是由寄存器cx的值决定的。而cx只有一个,那么面对多重循环的时候,要怎么解决这个问题呢?

    1.用其他寄存器暂时把cx里的值存储起来

    1. //编程将datasg段中每个单词改为大写字母
    2. assume cs:codesg,ds:datasg
    3. datasg segment
    4. db 'ibm '
    5. db 'dec '
    6. db 'dos '
    7. db 'vax '
    8. datasg ends
    9. codesg segment
    10. start:
    11. mov ax,datasg
    12. mov ds,ax
    13. mov bx,0 //初始化bx
    14. mov cx,4 //有4个字符串
    15. //要有两层循环
    16. s0: mov dx,cx //将外层循环的cx值保存在dx中
    17. mov si,0 //源地址
    18. mov cx,3 //内层循环3次,因为一行要处理3个字符
    19. s: mov al,[bx+si]
    20. and al,11011111b
    21. mov [bx+si],al
    22. inc si
    23. loop s
    24. add bx,4 //4个位置之后,是下一个字符串
    25. mov cx,dx//再把外层循环要用的取出来
    26. loop s0
    27. mov ax,4c00h
    28. int 21h
    29. codesg ends
    30. end starttrh

    2.用固定的内存空间保存数据

    1. //编程将datasg段中每个单词改为大写字母
    2. assume cs:codesg,ds:datasg
    3. datasg segment
    4. db 'ibm '
    5. db 'dec '
    6. db 'dos '
    7. db 'vax '
    8. datasg ends
    9. codesg segment
    10. start:
    11. mov ax,datasg
    12. mov ds,ax
    13. mov bx,0 //初始化bx
    14. mov cx,4 //有4个字符串
    15. //要有两层循环
    16. s0: mov ds:[40h],cx //将外层循环的cx值保存在datasg:40h单元中
    17. mov si,0 //源地址
    18. mov cx,3 //内层循环3次,因为一行要处理3个字符
    19. s: mov al,[bx+si]
    20. and al,11011111b
    21. mov [bx+si],al
    22. inc si
    23. loop s
    24. add bx,4 //4个位置之后,是下一个字符串
    25. mov cx,ds:[40h]//再把外层循环要用的cx值取出来
    26. loop s0
    27. mov ax,4c00h
    28. int 21h
    29. codesg ends
    30. end starttrh

    上面的两种方法都有一定的问题:

    1.寄存器数量太少,或者使用某个寄存器的时候,这个寄存器正在做其他事情

    2.内存空间单元可能正在被使用

    3.使用栈来保存数据

    1. //编程将datasg段中每个单词改为大写字母
    2. assume cs:codesg,ds:datasg,ss:stack
    3. stack segment
    4. dw 0,0,0,0,0,0,0,0
    5. stack ends
    6. datasg segment
    7. db 'ibm '
    8. db 'dec '
    9. db 'dos '
    10. db 'vax '
    11. datasg ends
    12. codesg segment
    13. start:
    14. mov ax,stack
    15. mov ss,ax
    16. mov sp,16 //初始化ss和sp寄存器
    17. mov ax,datasg
    18. mov ds,ax
    19. mov bx,0 //初始化bx
    20. mov cx,4 //有4个字符串
    21. //要有两层循环
    22. s0: push cx //将外层循环的cx值压栈
    23. mov si,0 //源地址
    24. mov cx,3 //内层循环3次,因为一行要处理3个字符
    25. s: mov al,[bx+si]
    26. and al,11011111b
    27. mov [bx+si],al
    28. inc si
    29. loop s
    30. add bx,4 //4个位置之后,是下一个字符串
    31. pop cx //从栈顶弹出原cx的值,恢复cx
    32. loop s0
    33. mov ax,4c00h
    34. int 21h
    35. codesg ends
    36. end start

    六、用于内存寻址的寄存器

    1.寄存器

    1.BX——Base 基地址寄存器

    主要用于存放存储单元在段内的偏移量:

    2.SI——Source Index 源变址寄存器

    3.DI——Destination Index 目的变址寄存器

    4.BP——Base Pointer 基指针寄存器

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

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

    //正确的指令
    mov ax,[bx]
    mov ax,[bx+si]
    mov ax,[bx+di]
    mov ax,[bp]
    mov ax,[bp+si]
    mov ax,[bp+di]
     
    //错误的指令
    mov ax,[cx]
    mov ax,[ax]
    mov ax,[dx]
    mov ax,[ds]

    2.注意

    //错误的指令
    mov ax,[bx+bp]
    mov ax,[si+di]

    这四个寄存器可以单独使用,也可以混合着使用。但是以上两种方式不可行

    原因:

    bx,bp两个相当于是基地址,自然不能两个基地址相加

    si,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

    3.区别

    bx和bp寄存器的区别:

    1.bx默认指ds作为段地址

    2.bp默认指ss作为段地址

    但是也可以给这二者指定某一个寄存器作为段地址

    mov ax,[bp] 			(ax)=((ss)*16+(bp))
    mov ax,ds:[bp] 			(ax)=((ds)*16+(bp))
    mov ax,es:[bp] 			(ax)=((es)*16+(bp))
    mov ax,[bx] 			(ax)=((ds)*16+(bx))
    mov ax,ss:[bx] 			(ax)=((ss)*16+(bx))
    mov ax,[bp+idata] 		(ax)=((ss)*16+(bp)+idata)
    mov ax,[bp+si] 			(ax)=((ss)*16+(bp)+(si))
    mov ax,[bp+si+idata] 	 (ax)=((ss)*16+(bp)+(si)+idata

    七、数据位置的表达

    1.立即数-idata

    对于直接包含在机器指令中的数据,称为立即数 (idata ),数据包含在指令z中

    mov ax,1
    add bx,2000h
    or bx,00010000b
    mov al,'a'

    2.寄存器

    指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。

    mov ax,bx
    mov ds,ax
    push bx
    mov ds:[0],bx
    push ds
    mov ss,ax
    mov sp,ax

    3.内存

    内存:段地址(SA)和偏移地址(EA)

    指令要处理的数据在内存中,由SA:EA确定内存单元

    mov ax,[0]
    mov ax,[di]
    mov ax,[bx+8]
    mov ax,[bx+si]
    mov ax,[bx+si+8]
    //段地址默认在ds中
        
    mov ax,[bp]
    mov ax,[bp+8]
    mov ax,[bp+si]
    mov ax,[bp+si+8]
    //段地址默认在ss中    
        
    mov ax,ds:[bp] 			(ax)=((ds)*16+(bp))
    mov ax,es:[bx] 			(ax)=((es)*16+(bx))
    mov ax,ss:[bx+si] 		(ax)=((ss)*16+(bx)+(si))
    mov ax,cs:[bx+si+8] 	(ax)=((cs)*16+(bx)+(si)+8)
    //显性的给出存放段地址的寄存器
    

    八、指令处理的数据的长度

    1.字word

    mov ax,1
    mov bx,ds:[0]
    mov ds,ax
    mov ds:[0],ax
    inc ax
    add ax,100

    因为上述寄存器都是16位的寄存器,所以对数据的处理都是字操作

    2.字节byte

    mov al,1
    mov al,bl
    mov al,ds:[0]
    mov ds:[0],al
    inc al
    add al,10

    因为上述寄存器都是8位的寄存器,所以对数据的处理都是字节操作

    3.用word ptr或byte ptr指

    mov word ptr ds:[0],1
    inc word ptr [bx]
    inc word ptr ds:[0]
    add word ptr [bx],2
        
    mov byte ptr ds:[0],1
    inc byte ptr [bx]
    inc byte ptr ds:[0]
    add byte ptr [bx],

    在没有寄存器参与的内存单元访问指令中,用 word ptr或byte ptr显性地指明所要访问的内存单元的长度是很必要的,否则,CPU无法得知所要访问的单元是字单元,还是字节单元

    九、不同寻址方式的综合运用

    编程修改姚明的数据

    2001年数据2002年数据
    'Yao''Yao'
    '19800912''19800912'
    1511
    3213
    ‘SHH''HOU'

    汇编

    1. assume cs:code,ds:data
    2. data segment
    3. db 'Yao'
    4. db '19800912'
    5. dw 15
    6. dw 32
    7. db 'SHH'
    8. data ends
    9. code segment
    10. start:
    11. mov ax,data
    12. mov ds ax
    13. mov bx,0 ;从0开始改变数据
    14. mov word ptr [bx+11],11
    15. mov word ptr [bx+13],13
    16. mov si,0
    17. mov byte ptr [bx+15+si],'H'
    18. inc si
    19. mov byte ptr [bx+15+si],'O'
    20. inc si
    21. mov byte ptr [bx+15+si],'U'
    22. mov ax,4c00h
    23. int 21h
    24. code ends
    25. end start

    C语言

    1. #incldue
    2. struct player
    3. {
    4. char name[3];
    5. char birthday[9];
    6. int num;//球衣号
    7. int ppg;//point per game 场均得分
    8. char team[3];//所在队名
    9. }
    10. struct player yao={"Yao",'19800912',15,32,'SHH'};
    11. int main()
    12. {
    13. int i=0;
    14. //开始修改数据
    15. yao.num=11;
    16. yao.ppg=13;
    17. yao.team[i]='H';
    18. i++;
    19. yao.team[i]='O';
    20. i++;
    21. yao.team[i]='U';
    22. return 0;
    23. }
    24. /*
    25. yao.team[i]
    26. 1.yao是一个变量名,指明了结构体变量的地址
    27. 2.team是一个名称,指明了数据项team的地址
    28. 3.i是用来定位team中的字符
    29. 对汇编来说:
    30. 1.用bx基地址寄存器,定位整个结构体
    31. 2.用idata定位结构体中的某一个数据项
    32. 3.用si定位数据项中的元素
    33. */

    十、div-除法指令

    1.概念

    指令格式:

    1.div 寄存器

    2.div 内存单元

    数据存放位置

    1.被除数:(默认)放在AX 或 (DX和AX)中 ;

    2.除数:8位或16位,在寄存器或内存单元中

    数据存放位置(除数为8位)存放位置(除数为16位)
    被除数axdx和ax
    除数8位内存或寄存器16位内存或寄存器
    alax
    余数ahdx

    2.使用

    切记提前在默认的寄存器中设置好被除数,且默认寄存器不作别的用处。

    //除法的位数示例:
    6879H÷A2H:商A5,余FH
    12345678H÷2EF7H:商633AH,余2D82H

    示例程序被除数除数余数
    div bl(8位)axblalah
    div byte ptr ds:[0]axds*16+0alah
    div bx(16位)dx*10000h+axbxaxdx
    div word ptr es:[0]dx*10000h+axes*16+0axdx

    问题1:计算100001/100

    100001d=186A1h,100d=64h,需要16位的除法

    mov dx,1	//dx存放高位数据
    mov ax,86a1	//ax存放低位数据
    mov bx,64	//除数
    div bx

    问题2:计算1001/100

    1001d=3e9h,100d=64h,进行8位除法

    mov ax.3e9	//ax中存放被除数
    mov bl,64	//bl中存放除数
    div bl

    用div 计算data段中第一个数据除以第二个数据后的结果,商存放在第3个数据的存储单元中

    1. assume cs:code,ds:data
    2. data segment
    3. dd 100001 //4个字节
    4. dw 100 //2个字节
    5. dw 0 //2个字节
    6. data ends
    7. code segment
    8. start:
    9. mov ax,data
    10. mov ds,ax
    11. mov ax,ds:[0] //将前两个字节的数据读取到ax中
    12. mov dx,ds:[2] //将后两个字节的数据读取到dx中
    13. div word ptr ds:[4] //再将100作为字单元数据读出,进行16位的除法
    14. mov ds:[6],ax //再将结果保存到指定位置
    15. mov ax,4c00h
    16. int 21h
    17. code ends
    18. end start

    十一、dup设置内存空间

    1.概念

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

    1.db 3 dup (0) :定义了3个字节,它们的值都是0,相当于 db 0,0,0

    2.db 3 dup (0,1,2) :定义了9个字节,由0、1、2重复3次构成,相当于db 0,1,2,0,1,2,0,1,2

    3.db 3 dup (‘abc’ , ’ABC’): 定义了18个字节,构成'abcABCabcABCabcABC' ,相当于db ‘abcABCabcABCabcABC’

  • 相关阅读:
    乐观锁思想在JAVA中的实现——CAS
    「PAT乙级真题解析」Basic Level 1098 岩洞施工 (问题分析+完整步骤+伪代码描述+提交通过代码)
    考华为云认证的必要条件、注意事项
    【51单片机】利用【时间延迟】的原理规避【按键抖动问题】
    直播背后的原理是?初识视频流协议 HLS 和 RTMP
    【算法-链表2】反转链表 和 两两交换链表节点
    ubuntu搭建安卓开发环境
    AC自动机
    2023 “华为杯” 中国研究生数学建模竞赛(E题)深度剖析|数学建模完整代码+建模过程全解全析
    【owt】owt-p2p的vs工程构建
  • 原文地址:https://blog.csdn.net/m0_52559870/article/details/126260809