本文的立意僅僅是討論基本的x86匯編語法,。所以我要重申這里的匯編教程并不是深入研究匯編,本人也沒有那么大的能耐。學(xué)習(xí)基礎(chǔ)的匯編主要達(dá)到以下的程度即可。
- 讀懂常用的運(yùn)算符指令
- 讀懂存儲和加載指令
- 了解x86和x86_64常用的寄存器的用途。
- 了解基本的尋址模型。
了解基本的匯編以后,有什么用?
- 加深你對C/C++的編譯器行為和大部分內(nèi)部操作大有益處
- 讓你了解到用C/C++實(shí)現(xiàn)的高層算法在匯編層面實(shí)現(xiàn)細(xì)節(jié)。
- 讓你更深入地了解函數(shù)棧調(diào)用的細(xì)節(jié),能夠?qū)懗龈咝У拇a。
其實(shí)我這里可以提一個(gè)問題?你知道 以下簡單的語句它們在計(jì)算機(jī)底層做了寫什么操作嗎?
int *a=123; 或
double b=456;
double *pp=b;
如果你心中沒有明確的答案,請不要蠻目自信地欺騙自己C/C++的功底是如何如何地扎實(shí).....,我自己都沒自信心敢這么說?如果你打算專職用C/C++寫算法實(shí)現(xiàn)的,那么基本的匯編功底是必須的。
之前我也寫過一篇關(guān)于x64的匯編教程提交到寄存器和系統(tǒng)調(diào)用的基本關(guān)系《匯編語言基礎(chǔ):寄存器和系統(tǒng)調(diào)用》

上面的圖例是一個(gè)比較完整的示意圖,通常在IA32或x86_64中主要集中討論CPU中的寄存器與主內(nèi)存的數(shù)據(jù)交換,而其他的外部寄存器不在本文的討論范圍之內(nèi)。
加載與存儲
在匯編中mov指令主要用于在主內(nèi)存(RAM)和寄存器之間傳輸數(shù)據(jù),按照傳遞的方向可以分為兩類
- 加載(Load)指令:從主內(nèi)存(RAM)到寄存器傳輸數(shù)據(jù),以一個(gè)給定的內(nèi)存地址作為參數(shù),他從內(nèi)存中獲取該地址位置存儲的數(shù)據(jù),并將該數(shù)據(jù)放入寄存器
- 存儲(Store)指令:即從寄存器中緩存的內(nèi)存地址中所指向的目標(biāo)位置,并將另外一個(gè)寄存器中緩存的數(shù)據(jù)保存到該目標(biāo)位置,我們可以把內(nèi)存看作已經(jīng)編了號的數(shù)組,而通過索引就是內(nèi)存地址,通過指定的內(nèi)存地址可以在特定位置中的修改內(nèi)存中的數(shù)據(jù)。
IA32中的寄存器
在IA32架構(gòu)中有八個(gè)寄存器,其中有6個(gè)是通用的寄存器,另外兩個(gè)是esp和ebp有特殊的用途,如你對棧有所了解的話,就知道esp是始終指向棧頂?shù)?,ebp始終指向棧底。對于EAX,EBX,ECX和EDX寄存器,也會通常使用小字節(jié)的數(shù)據(jù)類型。 例如,EAX的最低有效2字節(jié)可被視為稱為AX的16位寄存器。 AX的最低有效字節(jié)可以用作單個(gè)8位寄存器,稱為AL,而AX的最高有效字節(jié)可以用作單個(gè)8位寄存器,稱為AH。 這些名稱指的是相同的物理寄存器。 當(dāng)將兩個(gè)字節(jié)的數(shù)量放入DX中時(shí),更新將影響DH,DL和EDX的值。 這些子寄存器主要是較舊的16位版本指令集的保留。 但是,在處理小于32位(例如1字節(jié)ASCII字符)的數(shù)據(jù)時(shí),它們有時(shí)很方便。

mov指令的長度分類
根據(jù)操作數(shù)的字長可以分為三個(gè)版本的mov指令
- movl Source Dest : L表示可以移動4個(gè)字節(jié)
- movw Source Dest: W表示可以移動2個(gè)字節(jié)
- movb Source Dest: B表示可以移動1個(gè)字節(jié)
mov指令的操作數(shù)
并且在移動指令中會用到兩個(gè)操作數(shù),Source表示移動的數(shù)據(jù)源,Dest表示移動的數(shù)據(jù)最后到達(dá)的位置。
通常在x86用的比較頻繁的mov指令版本是32位的movl,這里就以 movl Source Dest為例子
mov指令的操作數(shù)通常分為三類
-
立即數(shù)(Immediate) 可以將其視為常數(shù),和C語言的常量類似,但是以“$”為前綴,例如
-500
- 寄存器(Register)可以是以上8個(gè)整數(shù)寄存器中的其中一個(gè),例如:“%eax”,“%edx”,當(dāng)我們執(zhí)行類似“movl %eax %edx”這種情況下,eax寄存器就成為源參數(shù),而edx寄存器就成為目標(biāo)參數(shù),其含義是獲取eax中的內(nèi)容并存儲在edx中。
- 內(nèi)存(Memory):而內(nèi)存作為操作數(shù)通常是由寄存器緩存給定的內(nèi)存地址來間接去操作的,該地址占用4個(gè)字節(jié),例如(%eax),當(dāng)寄存器在一個(gè)括號中,我們就說eax持有一個(gè)指向RAM中的某個(gè)位置的地址,你可以類比為類似C/C++中的指針變量,的那么 movl (%eax) %ebx 表示的是什么意思呢?你可以考慮一下表示什么意思?
mov的操作數(shù)組合
movl指令通過不同類型的操作數(shù)組合,能夠表達(dá)出不同類型的指令類型的。

- 例如源參數(shù)是立即數(shù),而目標(biāo)參數(shù)是的寄存器,即“movl $123,%eax ”表示將常量保存在寄存器eax中,等價(jià)于C/C++聲明并初始化一個(gè)變量例如
其實(shí)在C編譯器對每個(gè)聲明的基本數(shù)據(jù)類型的變量會映射到一個(gè)寄存器中,例如一個(gè)int類型4字節(jié),會選擇一個(gè)32位的寄存器類裝載int整數(shù)等待CPU中的運(yùn)算單元(AU)處理。int a=123; - 源參數(shù)是立即數(shù),而目標(biāo)參數(shù)是一個(gè)主內(nèi)存中的地址,即“movl $123,%(eax) ”表示將常量保存到eax寄存器中的存儲的內(nèi)存位置所指向的內(nèi)存位置,同理等價(jià)的C/C++語句如下:
int *a=123; - 源參數(shù)是寄存器,而目標(biāo)參數(shù)也是寄存器,例如“movl %edx,%eax”其實(shí)就是在寄存器之間拷貝數(shù)據(jù)。
- 源參數(shù)是寄存器,而目標(biāo)參數(shù)是內(nèi)存。其實(shí)就是一種存儲類型,例如“movl %eax,(%edx)”,表示當(dāng)前寄存器eax中的數(shù)據(jù)寫回主內(nèi)存中的某個(gè)位置,而這個(gè)位置是由寄存器edx保存的地址所指向的。
- 源參數(shù)是內(nèi)存,而目標(biāo)參數(shù)是寄存器,例如“movl (%edx),%eax”這是從內(nèi)存中加載數(shù)據(jù)到eax寄存器當(dāng)中。因此表示加載指令的其中一種。
可能你會想到最后一種,有從“內(nèi)存”到“內(nèi)存”傳遞的指令類型嗎?單一的一條指令是不可能的。只能通過兩步實(shí)現(xiàn)
- 首先“內(nèi)存”到“寄存器”例如:“movl (%edx),%eax”
- 然后“寄存器”到“內(nèi)存” 例如:“movl %eax,(%ecx)”
基本的內(nèi)存尋址模型
間接訪問
就是“(R)”這種格式,R表示一個(gè)寄存器名稱。寄存器中保存著一個(gè)內(nèi)存地址,我們用mov指令操作主內(nèi)存時(shí),只能通過使用該寄存器中的內(nèi)容去實(shí)現(xiàn)對該地址指向的RAM中位置進(jìn)行讀/寫操作。對于操作系統(tǒng)來說,內(nèi)存其實(shí)就是一個(gè)連續(xù)的字節(jié)數(shù)組,每個(gè)字節(jié)都有對應(yīng)的編號,而這個(gè)編號就是內(nèi)存地址,也可以理解為該字節(jié)數(shù)組的索引。
我們用“RAM”表示主內(nèi)存,那么 (R) 其實(shí)等價(jià)于 RAM[Reg[R]],
那么“movl (%edx),%eax”類似這樣的指令的含義到這里應(yīng)該不用多說了吧!
移位尋址
英文名稱叫“Displacement”,這個(gè)其實(shí)就是在間接尋址表達(dá)式的基礎(chǔ)是加上一個(gè)有符號的整數(shù)N。在匯編中抽象的移位尋址表達(dá)式“N(R)”
我們用“RAM”表示主內(nèi)存,那么 N(R) 其實(shí)等價(jià)于 RAM[Reg[R]+N],
那么具體的例子就是
- 例如 “-4(%ebp)”:表示ebp寄存器中緩存的內(nèi)存地址向低地址方向移動了4個(gè)字節(jié)
- 例如“8(%ebp)”:表示ebp寄存器中緩存的內(nèi)存地址向高地址方向移動8個(gè)字節(jié)。
- 那么像這種“movl 4(%esp),%ecx”其實(shí)就是寄存器esp的指針向高地址方向偏移4個(gè)字節(jié)后的個(gè)新的地址,從該新地址指向的內(nèi)存位置獲取數(shù)據(jù)并保存到寄存器ecx。