我们说到寻址,不外乎就三种:
立即数寻址
寄存器寻址
存储器寻址
那到底什么是寻址?通过地址访问数据或者指令,就是寻址!
我们先看看这个寻址方式:
.data
const=64
bvar byte 87h,64h
.code
mov ax,1234h
mov al,'d'
mov ecx,const
mov esi,offset bvar
非常直接,可以是:
前面三个我还明白,offset为什么也算???这里就得插句题外话了
我们要比较的就是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]
直接书写变量名 == 在其偏移的有效地址的存储单元读写操作数
也就是说,在汇编后,变量名会被直接翻译为非常直接的地址
该段代码的执行过程是怎样的呢?
一定要分清和立即数寻址的区别!
那为什么要叫直接寻址?我认为是因为在汇编后,它就是一个非常直接的地址了,直接去找就行,是个静态的过程(相比于下面的寄存器间接寻址)
相比于前面的直接寻址,寄存器间接寻址是个动态的过程,我不可能在汇编时就知道寄存器里应该是多少,运行到特定代码了我才知道,因而是间接的
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];带比例的相对基址变址、
记住,我们寻址,目的就是找到地址,换句话说,关键就在如何生成地址