聊聊汇编的寻址方式

我们说到寻址,不外乎就三种:

  • 立即数寻址

  • 寄存器寻址

  • 存储器寻址

那到底什么是寻址?通过地址访问数据或者指令,就是寻址!

立即数寻址

我们先看看这个寻址方式:

.data
const=64
bvar byte 87h,64h

.code
mov ax,1234h
mov al,'d'
mov ecx,const
mov esi,offset bvar

非常直接,可以是:

  • 直接把数字写明白的
  • 常量
  • 字符
  • offset

前面三个我还明白,offset为什么也算???这里就得插句题外话了


取地址

我们要比较的就是offsetlea

同样都是获得偏移首地址,二者有何不同呢?

最关键就在于offset是静态的,而lea是动态的

offset

它在汇编时期就能确定,把地址在运行前就算出来并作出相应转换,运行效率也更高,但前提是,你也得能获得确认的地址啊

lea

相反,它是动态的,运行效率虽然低,但它可以用来对付可变情况,比较灵活


立即数寻址很容易和(存储器)直接寻址搞混,不能搞错啊,不是一个大类的!

立即数的特点就是:

  • 直接
  • 无类型,类型由目的操作数决定
  • 只出现在源操作数

(老钢铁直男了)

寄存器寻址

这个其实没什么好说的:

mov al,bl
mov ecx,eax
mov di,si

但要注意的是,不能mov edi,si,按照正常思路走,位少至位多的位扩展是可以的,其实不行,硬件设计不允许

存储器寻址

究极重难点!!!!!!

存储器特性就在于[](在它是变量名的时候可以省略)

直接寻址

我们先来看这个最容易理解错,搞混淆的

COUNT dword 12345678H
mov ecx,COUNT	;同于mov ecx,[COUNT]

该段代码的机器语言为:8B OD 00 50 40 00,反汇编之后得到的代码是:mov ecx,DS:[405000H]

直接书写变量名 == 在其偏移的有效地址的存储单元读写操作数

也就是说,在汇编后,变量名会被直接翻译为非常直接的地址

该段代码的执行过程是怎样的呢?

  1. 在CS段中,读到源操作数的偏移地址
  2. 到指定的DS段中的有效偏移地址
  3. 读出该地址内的数据

一定要分清和立即数寻址的区别!

  • 立即数寻址
    • 给的是数据
    • 直接赋值,直接做存储
  • (存储器)直接寻址
    • 给的是变量名(本质是地址)
    • 要先到指定地址,才能做存储或者读取,其实是间接的

那为什么要叫直接寻址?我认为是因为在汇编后,它就是一个非常直接的地址了,直接去找就行,是个静态的过程(相比于下面的寄存器间接寻址)

寄存器间接寻址

相比于前面的直接寻址,寄存器间接寻址是个动态的过程,我不可能在汇编时就知道寄存器里应该是多少,运行到特定代码了我才知道,因而是间接的

mov al,[esi]
mov [edi],al

寄存器寻址要区别开来:一个有[],一个没有

寄存器间接寻址需要我们先到指定寄存器读出地址的值,才能确定地址,做出跳转,有别于上文的直接寻址

寄存器相对寻址

主要有两种:

mov esi,[ebx+4]	;第一种
mov eax,count[esi]	;第二种

其实第二种也是第一种,变种罢了,看起来更符合我们平时的编码规范,但它本质就是mov eax,[count+esi]

为什么要叫相对呢?

其实也是基于上面的寄存器间接寻址,也得先找到寄存器里存放的实际地址,并以此为基址,做出相对这个基址的偏移,所以叫相对寻址

变址寻址

本质就是:相对基址变址寻址【相对基址|变址|寻址】

上一个相对寻址常用于构造【一维数组】,那么这个变址寻址就会用来构造【二维数组】

mov eax,[ebx+esi];基址变址寻址
mov eax,[ebx+edx+80h];相对基址变址

;当然也可以这样
mov eax,[ebx][esi];基址变址寻址
mov eax,80h[ebx][edx];相对基址变址

当然,也可以用一个比例因子搭配【变址寄存器】使用(1、2、4、8)

mov eax,[ebx+edx*4+80h];带比例的相对基址变址、

总结

记住,我们寻址,目的就是找到地址,换句话说,关键就在如何生成地址

  • 立即数:找都不用找,皆大欢喜
  • 寄存器:找寄存器
  • 存储器:找内存

你可能感兴趣的:(汇编)