有空自己也寫一個學習筆記,先把參考文章記下了:
http://www.cnblogs.com/aguncn/archive/2012/11/14/2769989.html
http://www.cnblogs.com/aguncn/archive/2012/11/14/2769814.html
http://segmentfault.com/q/1010000000627497
http://blog.csdn.net/herecles/article/details/6080226
我的理解:指針就是使用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(); return 0; }
對應的匯編(VC6):
void myfun() 13: { 00401780 push ebp 00401781 mov ebp,esp 00401783 sub esp,48h 00401786 push ebx 00401787 push esi 00401788 push edi 00401789 lea edi,[ebp-48h] 0040178C mov ecx,12h 00401791 mov eax,0CCCCCCCCh 00401796 rep stos dword ptr [edi] 14: int num = 5; 00401798 mov dword ptr [ebp-4],5 // 把5放到ebp-4這個地址的內存中去 15: int *ptr = # 0040179F lea eax,[ebp-4] // 計算ebp-4的值,並把這個地址值放到eax里,就這么簡單! 004017A2 mov dword ptr [ebp-8],eax // 給ptr分配了一塊內存(大小為4,地址是ebp-8),並把eax里的值放作為內容,放到這個新分配的內存里。 16: std::cout << *ptr << std::endl; 004017A5 push offset @ILT+200(std::endl) (004010cd) 004017AA mov ecx,dword ptr [ebp-8] 004017AD mov edx,dword ptr [ecx] 004017AF push edx 004017B0 mov ecx,offset std::cout (0047c0c0) 004017B5 call @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: } 004017C1 pop edi 004017C2 pop esi 004017C3 pop ebx 004017C4 add esp,48h 004017C7 cmp ebp,esp 004017C9 call __chkesp (00406830) 004017CE mov esp,ebp 004017D0 pop ebp 004017D1 ret
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;。