x86匯編基礎(chǔ)-Move指令和基本尋址

本文的立意僅僅是討論基本的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í)很方便。


圖片來源于網(wǎng)絡(luò)

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語言的常量類似,但是以“$”為前綴,例如0x400,-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á)出不同類型的指令類型的。


mov的參數(shù)組合
  • 例如源參數(shù)是立即數(shù),而目標(biāo)參數(shù)是的寄存器,即“movl $123,%eax ”表示將常量保存在寄存器eax中,等價(jià)于C/C++聲明并初始化一個(gè)變量例如
     int a=123;
    
    其實(shí)在C編譯器對每個(gè)聲明的基本數(shù)據(jù)類型的變量會映射到一個(gè)寄存器中,例如一個(gè)int類型4字節(jié),會選擇一個(gè)32位的寄存器類裝載int整數(shù)等待CPU中的運(yùn)算單元(AU)處理。
  • 源參數(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。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.地址總線,數(shù)據(jù)總線,控制總線在哪里,它們有什么作用?答:它們都是cpu連接外部組件的線路。地址總線:地址總線A...
    MagicalGuy閱讀 1,672評論 0 1
  • Return-Oriented-Programming(ROP FTW) Author: Saif El-Sher...
    RealSys閱讀 3,516評論 0 2
  • Java原子類中CAS的底層實(shí)現(xiàn) - GoldArowana - 博客園 Java原子類中CAS的底層實(shí)現(xiàn) 從Ja...
    聽一首老歌閱讀 829評論 0 1
  • 寄存器 用于解決處理器與內(nèi)存之前的數(shù)據(jù)存儲效率問題存在的。IA-32平臺寄存器核心組有下面幾種. 通用寄存器 8個(gè)...
    dodomix閱讀 1,804評論 0 0
  • 《中國式眾籌》中第四章“眾籌十一個(gè)常見問題”:先找人,還是先找場地? 對于這個(gè)問題,我認(rèn)為應(yīng)該先選人,后選地...
    朝夕得閑大王閱讀 371評論 0 2

友情鏈接更多精彩內(nèi)容