汇编之寻址方式
前言
寻址方式真的是汇编里最基础最重要的内容,一开始觉得听懂了,用着用着又糊涂了,所以总结一下。
所谓寻址,就是寻找操作数所在地址的方法。
源操作数:运算数据的来源
目标操作数:运算结果的去向或另一个运算数据
先目的后源
操作数可能的来源或运算结果可能的去处只有三个:
- 由指令直接给出
- 寄存器
- 内存单元
由此寻找操作数所在地址的方法可以有三种类型:
- 指令直接给出的方式
- 存放于寄存器中的寻址方式
- 存放于存储器中的寻址方式
与数据有关的寻址方式
立即寻址
由指令直接给出运算的数据(操作数是立即数)。为常数形式或字符形式。
立即数只表示运算的数据,无地址含义。
立即寻址仅适合于源操作数(后面的那个操作数)。即源操作数是参加操作的数据本身。
立即数可以是16位的,也可以是8位的,可以是有符号数,也可以是无符号数,是比较自由的。
而且立即数没有确定的长度,1200H可以是1200H,也可以是00001200H
注意:操作数涉及立即数的指令,指令长度为:寄存器类型+1个字节
8位寄存器,寄存器类型=1,如:mov al,8;指令长度为2个字节
16位寄存器,寄存器类型=2,如:mov ax,8;指令长度为3个字节
因此涉及立即数的指令通常比较长,所以它在程序中的应用范围有限,一般只用于给某个寄存器或内存单元赋初值
例
MOV AX,1200H
把立即数1200H送入AX
立即数是由指令直接给出的,因此在编译的时候它会和指令码一起被放到内存的代码段。
注意高地址存放高字节,低地址存放低字节。
寄存器寻址
参与运算的数据被存放在CPU的某个通用寄存器中
例:MOV AX,BX
此种寻址方式中的寄存器主要是通用寄存器,不会是控制寄存器,偶尔是段寄存器。
寄存器间接寻址
寄存器相对寻址
存储器寻址
存储器寻址
指令操作的对象在内存中,表现形式为**[ ]**
指令中给出运算对象在内存某个逻辑段中的偏移地址:[偏移地址]
逻辑段的段基地址通过默认或重设方式给出
存储器操作数的字长本身不确定,其字长取决于指令中另一个寄存器操作数,或通过其他方式指定字长。
直接寻址
指令中直接给出操作数的偏移地址
方括号里的就是操作数的偏移地址
例:MOV AX,[1200H]
因为AX是16位,会取出两个字节的数据。
直接寻址方式下,操作数默认在数据段,但允许段重设,即由指令给出所在逻辑段
例:MOV AX,ES:[1200H]
ES:就是段重设符
寄存器间接寻址
操作数存放在内存中,数据在内存中的偏移地址为方括号中通用寄存器的内容。
仅有四个通用寄存器可用于存放数据的偏移地址,它们不仅是用用寄存器还是间址寄存器——BX,BP,SI,DI,它们用来存放数据在内存中的偏移地址
或者说,能放在[ ]里的只有这四个寄存器!
间接寻址的一般格式:
[ 间址寄存器 ]
操作数的段地址(数据处于哪个段)取决于选择哪个间址寄存器。
BX,SI,DI——默认在数据段
BP——默认在堆栈段
扩展一下:
BP和SP都指向堆栈区,SP固定指向栈顶,而BP可以指向堆栈区的任何一个位置。
注意这里说的是“默认”,我们还是可以通过段重设的方法,来让它们处于其他的段。
寄存器相对寻址
间接寻址在对数组元素求和等程序时很好用。间接寻址用间址寄存器来表示数据的存放地址,可以不断DX+1,DX+2实现一组数据的操作,这样比直接寻址方便多了。如果用间接寻址求100个数相加,那就至少需要写100条指令。
例
MOV BX,1200H
MOV AX,[BX]
看见方括号[ ]就知道要找的数在内存里,在内存的什么地方?这就要看[ ]里面。
在这里,BX里的值就是数据的偏移地址。1200H就是操作数的偏移地址。