寻址方式

汇编进行数据操作运算时第一步是要找到对应的操作数。

操作数分为源操作数与目的操作数,一般来说改变的是目的操作数,源操作数在操作或者运算之后是不会发生变化的

操作数有多个存放地址:

  • 寄存器
  • 主存储器
  • I/O设备端口处

寄存器寻址

顾名思义,就是直接通过寄存器来寻找操作数,操作数存放在寄存器中而不是主存或者端口中

举例:

1
mov ax,bx

BX中的内容赋值赋到AX中去,而寻找内容的方式,就是去AX这个CPU自带的通用寄存器EAX中寻找低16位的寄存器AX

特点:

操作数的位数决定了操作的类型,例如,16位的寄存器就代表整个操作是字类型,8位代表字节类型

  1. 32位 - 双字
  2. 16位 - 字
  3. 8位 - 字节

相对其他的寻址方式,寄存器由于是CPU内部的存储单元,所以响应速度更快。

寄存器间接寻址

寄存器间接寻址本质上不是去往寄存器里寻找所需要的操作数,而是去主存储器中找对应的操作数!在这种方式里,寄存器相对而言只是一个跳板的作用,提供偏移地址!

举例:

1
mov ax,[bx]

内在的逻辑与顺序

  1. 读取给定的寄存器的内容
  2. 以该内容为偏移地址EA
  3. 选取对应的段首
  4. 组合之后得到物理地址PA

一些默认规定

  1. 除了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]

内在逻辑与顺序

  1. 读取出ebx中的内容
  2. 运算整个表达式ebx*2+4
  3. 以这个表达式为偏移地址,选取对应的段地址生成物理地址

注意:

  • 当选取的运算的寄存器是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的那个内存单元进行减法操作,操作类型(或者说是范围)是字类型,也就是操作对象是两个字节!

总结

分类

而已上六种寻址方式可以分为三大类:寄存器方式,存储器方式以及立即数方式。

  • 寄存器:寄存器寻址
  • 存储器方式:
    1. 寄存器间接寻址
    2. 变址寻址
    3. 基址加变址寻址
    4. 直接寻址
  • 立即数方式:立即寻址

操作数来源

双操作数的指令中的目的操作数与源操作数的类型必须是以下几种:

  1. 寄存器对寄存器
  2. 寄存器对存储器
  3. 存储器对寄存器
  4. 立即方式对寄存器–立即方式只能用于源操作数
  5. 立即方式对存储器–立即方式只能用于源操作数

其中绝对不能两个操作数均来自存储器!

操作数类型

不确定类型的操作数:
  • 寄存器间接寻址
  • 立即数
  • 直接寻址
一些规定:
  • 两个操作数至少要有一个操作数的类型是明确的
  • 如果两个操作数的类型都是明确的,那么两个操作数的类型必须都要相同(均是字类型,或者均是字节类型等等)
  • 如果都不明确那么必须要指定一个操作数的类型!