汇编语⾔理解指针(指针就是汇编的间接寻址,其实就是⼀个简单⽅便的运算指令,计算完毕直接就赋。。。
有空⾃⼰也写⼀个学习笔记,先把参考⽂章记下了:
我的理解:指针就是使⽤mov⽅法的间接寻址。想要明⽩指针,必须懂得LEA和MOV指令的区别。然后就觉得已经豁然开朗。
mov 和 lea 的区别
mov ecx,[eax+0x30]表⽰先运算eax+0x30得到⼀个结果,以这个结果为地址⼀个ecx长度的内存数赋给ecx
lea ecx,[eax+0x30]表⽰先运算eax+0x30得到⼀个结果,把这个结果(mov时地址)赋给ecx
效果为ecx=eax+0x30 (这⾥eax参与了运算却没有改变值)
dword 双字就是四个字节
ptr pointer缩写即指针
[]⾥的数据是⼀个地址值,这个地址指向⼀个双字型数据
⽐如mov eax, dword ptr [12345678] 把内存地址12345678中的双字型(32位)数据赋给eax
----------------------------------------------------
MOV与LEA的区别
可以说,mov 这个汇编指令在汇编语⾔程序中是⾮常⾮常常见的⼀个指令. 打个最简单的⽐⽅,就好⽐我
们⼈要每天说话⼀样..在汇编语⾔中,Mov 指令就好⽐我们⼈要每天说话⼀样。每⼀个程序都离不开 Mov
指令。
Mov指令:
传送指令,可以⽤于传送寄存器,也可以⽤于传送内存地址.
lea指令:
传送指令。
如果是刚刚学习汇编语⾔的朋友,看到上⾯的解释⼀定会很疑惑,Mov 和 Lea都是传送指令,那么它们直
接的区别在哪⾥?
下⾯详细解释 Mov 与Lea 汇编指令的区别.
先作举⼀个⽣活中的例⼦, ⽐如你要坐车去电影院,你可以告诉司机电影院的地址,然后司机根据地址将你送
到电影院. 你还可以,告诉司机电影院的名字,司机通过名字将你送到电影院. 我们⽤这两种⽅式都可以顺
利的到达⾃⼰想到底的电影院.
Mov 和lea 的作⽤就是像上⾯例⼦说的⼀样.⽤不同的⽅式(传送⽅式),达到同⼀个⽬的(传送数据).换句话
说,Mov 指令传送⽅式,是将存放内存数据的地址进⾏传送. ⽽Lea则是恰恰相反,Lea是直接将内存数据进⾏传
递.
下⾯⽤⼀个例⼦说明 lea与mov 的区别:
mov ecx,30
汇编指令有多少个add ecx,eax
----------------------------------------------------
lea ecx,[eax+30]
----------------------------------------------------
mov ecx,[eax+30]表⽰先运算eax+30得到⼀个结果,以这个结果为地址传递到⼀个ecx长度的内存地址存放ecx
lea ecx,[eax+30]表⽰先运算eax+30得到⼀个结果,把这个结果传递到ecx中。相当于ecx=eax+30
希望这篇⽂章能够帮助正在为mov 和lea区别⽽烦恼的朋友们. 这篇⽂章花费 2个晚上,完成排版,整理。
1 . MOV 的右值必须是常量,⽽不能是表达式,⽐如可以写MOV EAX, EBP,但不能写MOV EAX, EBP + 8
这是因为EBP + 8本⾝也需要⼀条指令来计算,所以不能跟MOV写在⼀条指令⾥。
2 . 注意到在汇编指令的内存地址符 [ ] 内可以做算术运算,那是因为内存地址的计算在CPU⾥是由专门的处理单元AGU来处理的,并不占⽤算术运算单元ALU的时钟周期。但如果⽤MOV 接内存地址符号[]的话,会把[]⾥的地址指向的内存的内容取出来放⼊寄存器。⽐如 mov eax, [ebx+ecx*4h-20h],会把ebx+ecx*4h-20h计算的结果当成⼀个内存地址,然后去内存把该地址的内容取出送往eax。
3 . 如果我们只是想得到算术运算结果怎么办呢?这时候就可以⽤到LEA指令了。因为LEA后⾯接内存地址符[]会把地址,⽽不是地址⾥的内容送⼊寄存器。⽐如,我们想计算ebx+ecx*4h-20h的结果,就可以这样写: lea eax,[ebx+ecx*4h-20h]。当然如果不⽤lea指令也可以达到⽬的,不过那样写起来就⿇烦多了: imul ecx,
4 add ebx, ecx sub ebx, 20h mov eax, ebx
-
---------------------------------------------------
死记硬背:
#include "stdafx.h"
#include <iostream>
using namespace std;
void myfun()
{
int num = 5;
int *ptr = #
std::cout << *ptr << std::endl;
}
int main(){
myfun();
return0;
}
对应的汇编(VC6):
void myfun()
13: {
00401780push ebp
00401781mov ebp,esp
00401783sub esp,48h
00401786push ebx
00401787push esi
00401788push edi
00401789lea edi,[ebp-48h]
0040178C mov ecx,12h
00401791mov eax,0CCCCCCCCh
00401796rep stos dword ptr [edi]
14: int num = 5;
00401798mov dword ptr [ebp-4],5 // 把5放到ebp-4这个地址的内存中去
15: int *ptr = #
0040179F lea eax,[ebp-4] // 计算ebp-4的值,并把这个地址值放到eax⾥,就这么简单!
004017A2mov dword ptr [ebp-8],eax // 给ptr分配了⼀块内存(⼤⼩为4,地址是ebp-8),并把eax⾥的值放作为内容,放到这个新分配的内存⾥。
16: std::cout << *ptr << std::endl;
004017A5push offset @ILT+200(std::endl) (004010cd)
004017AA mov ecx,dword ptr [ebp-8]
004017AD mov edx,dword ptr [ecx]
004017AF push edx
004017B0mov ecx,offset std::cout (0047c0c0)
004017B5call @ILT+255(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401104)
004017BA mov ecx,eax
004017BC call @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
17: }
004017C1pop edi
004017C2pop esi
004017C3pop ebx
004017C4add esp,48h
004017C7cmp ebp,esp
004017C9call __chkesp (00406830)
004017CE mov esp,ebp
004017D0pop ebp
004017D1ret
lea的英⽂解释是: Load Effective Address. 这个有效地址是指,四则运算后得到有效地址,然后就赋值,并不是从某个有效地址⾥去取数据。
-------------------------------------------------------
下⼀句是pointer = &count;,将pointer指向count的内存地址,我们看对应的汇编代码:
代码:
lea eax,[ebp-4]
mov dword ptr [ebp-0Ch],eax
前⾯说过,ebp-4是count变量的内存地址,为了直观点,我把上⾯的汇编代码改⼀下:
代码:
lea eax,[count]
mov dword ptr [pointer],eax
lea指令就是把⼀个内存变量有效的地址传送给指定的寄存器。第⼀句lea eax,[ebp-4]是把count的地址传到eax寄存器,根据刚才在Watch 窗⼝中看到的count地址是0012ff7c,那么eax⾥⾯的值就是0012ff7c。第⼆句mov dword ptr [ebp-0Ch],eax是把eax中的值传到ebp-
0Ch(pointer)中。很明显,pointer = &count;这句代码就等同于pointer = 0012ff7c;。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论