内存寻址方式

一、处理字符

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)

实际转换

assume cs:codesg,ds:datasg
datasg segment
    db 'BaSiC'
    db 'iNfOrMaTiOn' //内存中保存的都是16进制的ascii码值
datasg ends
    
codesg segment
start:
    mov ax,datasg
    mov ds,ax
//第一个字符串,小写字母全部转为大写字母
    mov bx,0
    mov cx,5    //5个字符循环5次
s:  mov al,[bx] //将第一个字符放到al寄存器里面
    and al,11011111b    //进行逻辑与的操作,可以将小写字母转为大写字母
    mov [bx],al //再将结果写回到原来的地址处
    inc bx
    loop  
//第二个字符串,大写字母全部转为小写字母 
    mov bx,5
    mov cx,11
s0: mov al,[bx]
    or al,00100000b //进行逻辑或的操作,可以将大写字母转为小写字母
    mov [bx],al
    inc bx
    loop s
    
    mov ax,4c00h
    int 21h
codesg ends
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.使用

第一个字符串转化为大写

第二个字符串转化为小写

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    ;循环执行5次
​
    mov ax,0    ;初始化ax寄存器
​
s:  mov al,[bx] ;将第一串字符中的第一个字符放入al寄存器中
    and al,11011111b    ;将小写字符转为大写字符
    mov [bx],al ;再写回到原来的字符串
​
    mov al,[bx+5]   ;再来处理第二个字符串
    or al,00100000b ;将大写字符转换为小写字符
    mov [bx+5],al
    
    inc bx
    loop s
​
    mov ax,4c00h
    int 21h
​
code ends
end start

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

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

三、[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里的值存储起来

//编程将datasg段中每个单词改为大写字母
assume cs:codesg,ds:datasg
datasg segment
	db 'ibm '
	db 'dec '
	db 'dos '
	db 'vax '
datasg ends
    
codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov bx,0 	//初始化bx
	mov cx,4	//有4个字符串
    
    //要有两层循环
s0: mov dx,cx	//将外层循环的cx值保存在dx中
	mov si,0	//源地址
	mov cx,3	//内层循环3次,因为一行要处理3个字符
    
s: mov al,[bx+si]
	and al,11011111b
	mov [bx+si],al
	inc si
	loop s
    
	add bx,4 //4个位置之后,是下一个字符串
	mov cx,dx//再把外层循环要用的取出来
	loop s0

    mov ax,4c00h
	int 21h
codesg ends
end starttrh

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

//编程将datasg段中每个单词改为大写字母
assume cs:codesg,ds:datasg
datasg segment
	db 'ibm '
	db 'dec '
	db 'dos '
	db 'vax '
datasg ends
    
codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov bx,0 	//初始化bx
	mov cx,4	//有4个字符串
    
    //要有两层循环
s0: mov ds:[40h],cx	//将外层循环的cx值保存在datasg:40h单元中
	mov si,0	//源地址
	mov cx,3	//内层循环3次,因为一行要处理3个字符
    
s: mov al,[bx+si]
	and al,11011111b
	mov [bx+si],al
	inc si
	loop s
    
	add bx,4 //4个位置之后,是下一个字符串
	mov cx,ds:[40h]//再把外层循环要用的cx值取出来
	loop s0

    mov ax,4c00h
	int 21h
codesg ends
end starttrh

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

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

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

3.使用栈来保存数据

//编程将datasg段中每个单词改为大写字母
assume cs:codesg,ds:datasg,ss:stack
stack segment
    dw 0,0,0,0,0,0,0,0
stack ends

datasg segment
	db 'ibm '
	db 'dec '
	db 'dos '
	db 'vax '
datasg ends
    
codesg segment
start:
	mov ax,stack
	mov ss,ax
	mov sp,16	//初始化ss和sp寄存器
        
	mov ax,datasg
	mov ds,ax
	mov bx,0 	//初始化bx
	mov cx,4	//有4个字符串
    
    //要有两层循环
s0: push cx		//将外层循环的cx值压栈
	mov si,0	//源地址
	mov cx,3	//内层循环3次,因为一行要处理3个字符
    
s: mov al,[bx+si]
	and al,11011111b
	mov [bx+si],al
	inc si
	loop s
    
	add bx,4 //4个位置之后,是下一个字符串
	pop cx	//从栈顶弹出原cx的值,恢复cx
	loop s0

    mov ax,4c00h
	int 21h
codesg ends
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'
15 11
32 13
‘SHH' 'HOU'

汇编

assume cs:code,ds:data
data segment
	db 'Yao'
	db '19800912'
	dw 15
	dw 32
	db 'SHH'
data ends

code segment
start:
	mov ax,data
	mov ds ax

	mov bx,0	;从0开始改变数据
	
	mov word ptr [bx+11],11
	mov word ptr [bx+13],13

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

	mov ax,4c00h
	int 21h
code ends
end start

C语言

#incldue

struct player
{
    char name[3];
    char birthday[9];
    int num;//球衣号
    int ppg;//point per game 场均得分
    char team[3];//所在队名
}

struct player yao={"Yao",'19800912',15,32,'SHH'};

int main()
{
    int i=0;
    //开始修改数据
    yao.num=11;
    yao.ppg=13;
    yao.team[i]='H';
    i++;
    yao.team[i]='O';
    i++;
    yao.team[i]='U';
    return 0;
}

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

对汇编来说:
1.用bx基地址寄存器,定位整个结构体
2.用idata定位结构体中的某一个数据项
3.用si定位数据项中的元素
*/

十、div-除法指令

1.概念

指令格式:

1.div 寄存器

2.div 内存单元

数据存放位置

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

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

数据 存放位置(除数为8位) 存放位置(除数为16位)
被除数 ax dx和ax
除数 8位内存或寄存器 16位内存或寄存器
al ax
余数 ah dx

2.使用

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

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

示例程序 被除数 除数 余数
div bl(8位) ax bl al ah
div byte ptr ds:[0] ax ds*16+0 al ah
div bx(16位) dx*10000h+ax bx ax dx
div word ptr es:[0] dx*10000h+ax es*16+0 ax dx

问题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个数据的存储单元中

assume cs:code,ds:data
data segment
	dd 100001	//4个字节
	dw 100		//2个字节
	dw 0		//2个字节
	data ends
  
code segment
start:
	mov ax,data
	mov ds,ax
	
	mov ax,ds:[0]	//将前两个字节的数据读取到ax中
	mov dx,ds:[2]	//将后两个字节的数据读取到dx中

	div word ptr ds:[4]	//再将100作为字单元数据读出,进行16位的除法

	mov ds:[6],ax	//再将结果保存到指定位置

	mov ax,4c00h
	int 21h
code ends
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’

你可能感兴趣的:(汇编,开发语言)