汇编-1 寻址方式
寻址方式
汇编进行数据操作运算时第一步是要找到对应的操作数。
操作数分为源操作数与目的操作数,一般来说改变的是目的操作数,源操作数在操作或者运算之后是不会发生变化的
操作数有多个存放地址:
- 寄存器
- 主存储器
- I/O设备端口处
寄存器寻址
顾名思义,就是直接通过寄存器来寻找操作数,操作数存放在寄存器中而不是主存或者端口中
举例:
1 | mov ax,bx |
将BX
中的内容赋值赋到AX
中去,而寻找内容的方式,就是去AX
这个CPU自带的通用寄存器EAX
中寻找低16位
的寄存器AX
。
特点:
操作数的位数决定了操作的类型,例如,16位的寄存器就代表整个操作是字类型,8位代表字节类型
32位 - 双字
16位 - 字
8位 - 字节
相对其他的寻址方式,寄存器由于是CPU内部的存储单元,所以响应速度更快。
寄存器间接寻址
寄存器间接寻址本质上不是去往寄存器里寻找所需要的操作数,而是去主存储器中找对应的操作数!在这种方式里,寄存器相对而言只是一个跳板的作用,提供偏移地址!
举例:
1 | mov ax,[bx] |
内在的逻辑与顺序
- 读取给定的寄存器的内容
- 以该内容为偏移地址
EA
- 选取对应的段首
- 组合之后得到物理地址
PA
一些默认规定
- 除了
EBP,BP,ESP
三个寄存器默认选取的段寄存器是SS
之外,其他的32位/16位寄存器
选取的段寄存器都默认位DS
注意:
这里的寄存器可以选择任意的32位的寄存器(EDI,ESI,EBP,ESP
等等都是可以使用的)
或者是四个十六位存储器:BX,DI,SI,BP
(少了一个SP
,多了一个BX
)
但是不可以选择八位的存储器,因为八位存储器只能存储一个字节的内容,而偏移地址至少需要16位两个字节的内容,所以不能使用。
变址寻址
变址寻址所搜寻的操作数存放于主存储器中,而事实上,除了寄存器(直接)寻址以为,介绍的全部的寻址方式均是在主存储器中寻找操作数!
举例:
1 | 格式[R*F+V] V[R*F] [R*F]+V |
除了带有运算符的两个数外,其他的运算全部都是加法运算,只要全部加起来就好了。
其中F
为比例因子,R
为寄存器, V
为偏移量。而整个运算操作的对象是R寄存器中的内容!!
寄存器中的内容读取并不需要通过段地址:偏移地址
的方式,因为寄存器的地址都早已经被读取入计算机,因此相对而言速度更快!
1 | mov al,[ebx*2+4] |
内在逻辑与顺序
- 读取出
ebx
中的内容 - 运算整个表达式
ebx*2+4
- 以这个表达式为偏移地址,选取对应的段地址生成物理地址
注意:
- 当选取的运算的寄存器是EBP或者16位寄存器时,比例因子
F
只能为1,并且缩略不写 V
偏移量不能过长,否则会被截断- 关于偏移量:
- 由于在内存中默认的单元是字而不是字节!因此一般而言需要跳转到下一个单元时需要改变两个字节,而不是一个字节,当有相对应的操作时也应该乘以二!
基址加变址寻址
相当于上面的变址寻址多了一个基址罢了
举例:
格式:V[BR][IR*F] V[IR*F+BR]
1 | mov al,4[ebx*2+ecx] |
原理:将变址寄存器IR
的内容乘以比例因子F
,再与基址寄存器BR
的内容还有偏移量V
相加,得到的结果作为整个的偏移地址。然后再根据基址寄存器寻找默认的段寄存器。
注意:
当使用的基址寄存器为BX或者BP中的一个时,IR只能选择SI或者DI,而且根据变址寻址的规则,当选用16位的寄存器时,比例系数只能为1!
默认段寄存器的选用:
BX - DS
BP - SS
ESP,EBP - SS
其他的32位寄存器全部使用DS作为默认的段寄存器
立即寻址
实际上立即寻址并不用到任何一个主存储器或者寄存器,因为它的操作数已经直接被读入到操作码中,这应该是最快的操作方式?
举例:
1 | mov word ptr [si],12H |
其中的12H
就是立即数,它会直接赋值给以si寄存器
的内容为偏移地址的内存块(这里的目的操作数使用的是寄存器间接寻址)
注意:
- 其中有一块代码是
word ptr
是为了指定操作数的类型为字类型,也就是有两个字节,两块内存单元,即以[SI]
为首地址向下寻找一个字单元,然后放入对应的立即数! - 操作的时候会将
12H
翻译成0012H
以适应字类型的操作要求,这里的翻译原因就是前面的word ptr
,当使用的是byte ptr
时就不会翻译了 - 其中当遇到负数时会有翻译成补码的要求,而实际上所有的立即数的操作都是以补码的形式进行的,只不过无符号数和正数的补码与原码相同罢了!
直接寻址
这个直接寻址有点类似于上面的寄存器间接寻址,只不过把寄存器的内容换成了立即数,相当于:立即数(间接)寻址。
举例:
1 | mov ds:[20H],cl |
相当于把立即数当作偏移地址,然后去指定的段寄存器中寻找需要的操作数。这里的操作数是存放于主存储器中!
注意:
当使用直接寻址给内存单元赋值/运算的时候需要指定操作类型。
1 | sub word ptr ds:[1000H],55AAH |
这里就是指定了为偏移地址为1000H
,段寄存器为DS
的那个内存单元进行减法操作,操作类型(或者说是范围)是字类型,也就是操作对象是两个字节!
总结
分类
而已上六种寻址方式可以分为三大类:寄存器方式,存储器方式以及立即数方式。
- 寄存器:寄存器寻址
- 存储器方式:
- 寄存器间接寻址
- 变址寻址
- 基址加变址寻址
- 直接寻址
- 立即数方式:立即寻址
操作数来源
双操作数的指令中的目的操作数与源操作数的类型必须是以下几种:
- 寄存器对寄存器
- 寄存器对存储器
- 存储器对寄存器
- 立即方式对寄存器–立即方式只能用于源操作数
- 立即方式对存储器–立即方式只能用于源操作数
其中绝对不能两个操作数均来自存储器!
操作数类型
不确定类型的操作数:
- 寄存器间接寻址
- 立即数
- 直接寻址
一些规定:
- 两个操作数至少要有一个操作数的类型是明确的
- 如果两个操作数的类型都是明确的,那么两个操作数的类型必须都要相同(均是字类型,或者均是字节类型等等)
- 如果都不明确那么必须要指定一个操作数的类型!