汇编学习笔记(八)
内存寻址方式
因为CPU的寄存器就那么几个,所以汇编时很多操作是和内存打交道,或将数据赋值给内存变量,或读取内存等等,归纳下内存寻址方式主要有以下几种方式:
- 立即数寻址
立即数寻址就是用立即数idata来标识一个内存地址,如:mov ax, [0800H]
,将DS:0800H(段地址:偏移地址)处的数据传送到AX寄存器中,一般立即数寻址默认的段寄存器是DS寄存器,当然也可以显式指定另外一个段寄存器,如:mov ax, es:[0800H]
指定段寄存器为ES。
- 寄存器AX表明了是传送2个字节数据,低字节传送到AL中,高字节传送到AH中,如果此处的AX换成AL则传送1个字节数据。
- 如果是从内存到内存则必须使用byte ptr 或者 word ptr等来标识,否则CPU不知道该传送几个字节的数据,如:
mov ds:[0800H], es:[0200H]
这样的代码是错误的,因为不知道到底是传送多长的数据,如传送1个字节数据可以写成这样:mov byte ptr ds:[0800H], es:[0200H]
- 注意NASM和MASM中写法的不同:
masm中显式指定段寄存器是es:[0800H]
,nasm中的写法是[es:0800H]
,另外,masm中使用byte ptr
,nasm中使用byte
没有ptr。 - 立即数寻址一般用的较多的是使用标号,一般会用标号来定义变量等,标号一般代表了偏移地址,汇编器在编译的时候会将标号翻译成1个立即数,如下nasm代码片段:
msg_hello db 'Hello world', 0x00
mov bx, msg_hello ; msg_hello是个标号,在nasm中代表偏移地址,masm中要加上offset 关键字才等价
call show_str ; 调用打印字符串子函数
- 基址寄存器寻址
基址寄存器寻址就是通过寄存器来间接的寻址,如上mov ax, [0800H]
也可表示成如下:
mov bx, 0800H
mov ax, [bx]
注意:基址寄存器寻址一般使用BX寄存器,AX,CX, DX寄存器均不行,如:mov ax, [cx]
这样的写法是错误的,因为这就是BX叫做基址寄存器的缘故,另外一个可以使用的寄存器是BP,如:mov ax, [bp]
这样的写法没有问题,但是BP寄存器默认的段地址是SS,即以上是将SS:BP处的数据传送到AX中。BP(Base Pointer)叫做基址指针寄存器。
- 变址寄存器寻址
8086中有两个变址寄存器SI和DI,SI叫做Source Index(源变址寄存器),DI叫做Destination Index(目的变址寄存器),所以这种写法没有问题:mov ax, [si]
将ds:si处的数据传送到AX寄存器中,SI和DI默认的段寄存器是DS,当然也可以显式指定其他段寄存器。
- 基址寄存器/变址寄存器+立即数寻址
基址寄存器可以和立即数搭配使用来寻址,如,在一个数组中,数组的首地址一般是一个固定的地址,即立即数,可以搭配一个变址寄存器来遍历数组。如可以使用[si+idata]
定位数组中的某个变量,idata是数组的首地址,si指示数组中的下标。
- 基址寄存器+变址寄存器寻址
搭配方式有[bx+si], [bx+di], [bp+si],[bp+di],注意,使用BX时默认的段地址是DS,使用BP时默认的段地址是SS
- 基址寄存器+变址寄存器+立即数寻址
搭配方式有[bx+si+idata], [bx+di+idata],[bp+si+idata],[bp+di+idata],同样,注意BP默认使用的段地址是SS
几个指令
1、逻辑指令and,or, xor
and指令:逻辑与指令,and dst, src,将src和dst按位做与运算,结果存放在dst中。
如:and al, 01010111
, 原al=11010011B,与运算后,al=01010011
or指令:逻辑或指令,or dst,src,将src和dst按位做或运算,结果存放在dst中。
xor指令:逻辑异或指令,xor dst, src 将src和dst按位做异或运算,结果存在dst中。
异或可以理解为 当两个值同为0或者同为1时,结果为1,0和1的异或结果为0.
2、算术移位指令
算术左移指令shl:将一个寄存器或者内存单元中的数据向左移位,低位用0补位。
如:shl al, 2
, 原al=01011101,左移后al=01110100
算术右移指令shr:将一个寄存器或者内存单元中的数据向右移位,高位用0补位。
注意:8086/8088 CPU中shl和shr可能只支持1位位移即如shl ax, 1
,如多于1位需要借助CL寄存器间接实现,例如debug中,shl ax, 2
通不过,多于1位的位移需要借助寄存器CL间接实现,如下:
mov cl, 2
shl ax, cl ; shl ax, 2
80286后CPU基本上都支持如:shl ax, 2
之类的指令。
参考教材
[1]: 王爽老师的 汇编语言(第3版)
[2]: 李忠 / 王晓波 / 余洁 x86汇编语言-从实模式到保护模式