4 内存寻址方式

学习笔记
作者: MingXiao

寻址方式分类

  1. 直接寻址:mov ax, [0001]
  2. 寄存器间接寻址:mov ax, [bx]
  3. 寄存器相对寻址:mov ax, [bx+idata]
  4. 基址变址寻址:mov ax, [bx+si]
  5. 相对基址变址寻址:mov ax, [bx+si+idata]
  6. 立即数寻址:mov ax, 1
  7. 寄存器寻址:mov ax, bx

4.1 处理字符问题

汇编语言中,用'xxxxx'的形式指明数据的字符类型,长度为5(没有'\0')

编译器将字符转化为ASCII

data segment
	db 'HelloWorld'
data ends	

大小写转换

大写+20H=小写,所有大写字母第六位=0,所有小写字母第六位=1

20H=0010 0000 B

故大写变小写只需要将第6位变1,其余位不变,若本身就是小写经过上述流程还是小写

故有:任意字母 | 0010 0000 = 小写,|表示按位或

同理,任意字母 ^ 1101 1111 = 大写,^表示按位与

在汇编中的表示

and al, 11011111b

表示将al中的字符转为大写

or  al, 00100000b

表示将al中的字符转为小写

4.2 [bx+idata]方式寻址

idata是一个数字类型的常量

mov ax, [bx+200]

表示将内存地址位ds:[bx+200]处的内容存入ax中,以下写法等价

mov ax, [200+bx]
mov ax, 200[bx]
mov ax, [bx].200

这个方式可以用作一维数组,idata为0地址

4.3 si,di寄存器寻址

SI,DI作为变址寄存器,和bx的用法功能相近(唯一区别,bx可以分为两个8为寄存器bh+bl)

SI:source index,源变址寄存器;DI:destination index,目标变址寄存器

mov si, 0
mov di, 16
mov cx, 8
s:	mov ax, [si]
	mov [di], ax
	add si, 2
	add di, 2
loop s

这个代码实现了将一个16B的字符串从ds:0000移动到ds:0010,每次移动一个字

用[bx+si]和[bx+di]方式寻址

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

这两个方式等价,两个都是变量,相当于实现了一个二维数组

4.4 [bx+si+idata]和[bx+di+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

以上写法等价,只有当idata位于第二/三位时,需要.

结构体

使用[bx+idata+si]定位结构体,[bx]定位结构体基地址,.idata定位某一个数据项,[si]定位这个数据的某一个字节(数组的下标)

多重循环次数储存

由于只有一个cx用于存储循环次数,当存在循环嵌套时,会丢失上一次的次数信息

需要将cx保存下来

  1. 用其他合法寄存器
  2. 用固定内存空间
  3. 用栈

推荐第三种

4.5 BP寄存器

BP,Base Pointer,基指针寄存器,于BX类似,区别是不能当成2*8来用,且默认指向SS:BP

只有BX,BP,SI,DI可以在[]中寻址,且只能一个基地址一个变址,不能[BX+BP][SI+DI]

4.6 数据的位置

立即数idata

直接保存在指令中

mov ax, 1
add bx, 2000

寄存器

保存在CPU内部的寄存器,使用时不需要外部的dataBus传递

mov ax, bx

内存

保存在内存中

mov ax, [bx]		;ds:[bx]
mov cx, [bp]		;ss:[bp]

4.7 数据的长度

add/mov指令最多只能使用一个内存地址作为操作数,另一个必须是reg或idata

word

涉及到16b寄存器的操作,都是字型

mov ax, 1
mov ds:[0], ax

当不涉及寄存器时,可以用word ptr显式地指出

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

byte

涉及到8b寄存器的操作,都是字节型

mov al, 1
add bl, [bp]

同理可用byte ptr显式指出

mov byte ptr ds:[0000], 1
add byte ptr [bx], 2

4.8 DIV和MUL指令

在寄存器中使用DIV

mov ax, 1234
mov dx, 0001
mov bx, 0209
div bx

实现了将(dx*10000H+ax)/bx的商存在ax中,将余数存在dx

实测div ax会将ax作为除数,结果储存不变

mov al, 12
mov ah, 34
mov bl, 23
div bl

实现了将ax/bl的商保存在al中,将余数保存在ah

当商超过了axal的存储范围,结果溢出,程序自动产生一个中断(表现为指令地址跳跃很大的距离)

在内存单元中使用div

data segmemt
	dd 100001h				;定义一个double变量,占4B,ds:[0]-ds:[3]为(01,00,10,00)
	dw 100h					;定义一个word变量,占2B,ds:[4]-ds:[5]为(00,01)
	dw 0h					;定义一个word变量,占2B,ds:[6]-ds:[7]为(00,00),用于存放结果
data ends

code segment
	mov ax, data			
	mov ds, ax				;这两步将ds指向定义的数据段地址
	mov ax, ds:[0]			;由于一个寄存器不足以存放dd,用ax存在后四位,一定是后四位
	mov dx, ds:[2]			;用dx存放前四位,一定是前四位
	div word ptr ds:[4]		;没有寄存器参与,指明类型,这是除数
	mov ds:[6], ax			;将商保存在事先定义的结果空间
	
	mov ax, 4c00h
	int 21h
code ends

end

MUL指令

与DIV类似

mul bl	;或任意8b寄存器

表示将al*bl的结果存放在ax

mul bx	;或任意16b寄存器

表示将ax*bx的结果存放在dx,ax中,dx是高位

mul是无符号数的乘法,imul是有符号数的乘法

4.9 使用DUP设置内存空间

dd,db,dw伪指令一起使用,定义数据重复次数,这个是给编译器读的

db 3 dup (0)				;db 0,0,0
db 3 dup (0,1,2)			;db 0,1,2,0,1,2,0,1,2
db 3 dup ('abc','ABC')		;db 'abcABCabcABCabcABC'

dup前面跟的是重复的次数

一个典型用法是开辟一个空的数据空间

stack segment
	db 200 dup (0)
stack ends

开辟了一个200B的空栈段

数据定义语句

将操作数存入变量名指定的存储单元,或分配空间

还能在定义时计算,如5*20H=A0H



Comments