匯編語(yǔ)言入門匯編指令及寄存器詳解教程
前言
我們大都是被高級(jí)語(yǔ)言慣壞了的一代,源源不斷的新特性正在逐步添加到各類高級(jí)語(yǔ)言之中,匯編作為最接近機(jī)器指令的低級(jí)語(yǔ)言,已經(jīng)很少被直接拿來(lái)寫程序了,不過(guò)我還真的遇到了一個(gè),那是之前的一個(gè)同事,因?yàn)樵趯懘a時(shí)遇到了成員函數(shù)權(quán)限及可見(jiàn)性的問(wèn)題,導(dǎo)致他無(wú)法正確調(diào)用想執(zhí)行的函數(shù),結(jié)果他就開(kāi)始在 C++
代碼里嵌入?yún)R編了,繞過(guò)了種種限制終于如愿以償,但是讀代碼的我們傻眼了…
因?yàn)轫?xiàng)目是跨平臺(tái)的,代碼推送的 Linux 上編譯的時(shí)候他才發(fā)現(xiàn),匯編代碼的語(yǔ)法在 Linux 和 Windows 上居然是不一樣的,結(jié)果他又用一個(gè)判斷平臺(tái)的宏定義“完美”的解決了,最終這些代碼肯定是重寫了啊,因?yàn)榭勺x性太差了,最近在學(xué)習(xí)左值、右值、左引用和右引用的時(shí)候,總是有人用程序編譯生成的中間匯編代碼來(lái)解釋問(wèn)題,看得我迷迷糊糊,所以決定熟悉一下簡(jiǎn)單的匯編指令,邊學(xué)習(xí)邊記錄,方便今后忘記了可以直接拿來(lái)復(fù)習(xí)。
什么是匯編語(yǔ)言
匯編語(yǔ)言是最接近機(jī)器語(yǔ)言的編程語(yǔ)言,引用百科中的一段話解釋為:
匯編語(yǔ)言(assembly language)是一種用于電子計(jì)算機(jī)、微處理器、微控制器或其他可編程器件的低級(jí)語(yǔ)言,亦稱為符號(hào)語(yǔ)言。在匯編語(yǔ)言中,用助記符代替機(jī)器指令的操作碼,用地址符號(hào)或標(biāo)號(hào)代替指令或操作數(shù)的地址。匯編語(yǔ)言又被稱為第二代計(jì)算機(jī)語(yǔ)言。
匯編語(yǔ)言產(chǎn)生的原因
對(duì)于絕大多數(shù)人來(lái)說(shuō),二進(jìn)制程序是不可讀的,當(dāng)然有能人可以讀,比如第一代程序員,但這類人快滅絕了,直接看二進(jìn)制不容易看出來(lái)究竟做了什么事情,比如最簡(jiǎn)單的加法指令二進(jìn)制表示為 00000011
,如果它混在一大串01字符串中就很難把它找出來(lái),所以匯編語(yǔ)言主要就是為了解決二進(jìn)制編碼的可讀性問(wèn)題。
匯編與二進(jìn)制的關(guān)系
換句話來(lái)說(shuō),匯編語(yǔ)言就是把給機(jī)器看的二進(jìn)制編碼翻譯成人話,匯編指令是機(jī)器指令的助記符,與機(jī)器指令是一一對(duì)應(yīng)的關(guān)系,是一種便于閱讀和記憶的書寫格式。有效地解決了機(jī)器指令編寫程序難度大的問(wèn)題,并且使用編譯器,可以很方便的把匯編程序轉(zhuǎn)譯成機(jī)器指令程序,比如之前提到的 00000011
加法指令,對(duì)應(yīng)的匯編指令是 ADD
,在調(diào)用匯編器時(shí)就會(huì)把 ADD
翻譯成 00000011
。
寄存器
說(shuō)到匯編指令不得不提到寄存器,寄存器本身是用來(lái)存數(shù)據(jù)的,因?yàn)?CPU
本身只負(fù)責(zé)邏輯運(yùn)算,數(shù)據(jù)需要單獨(dú)儲(chǔ)存在其他的地方,但是對(duì)于不熟悉寄存器的人來(lái)說(shuō)會(huì)有疑惑,數(shù)據(jù)不是存在硬盤上嗎?或者說(shuō)數(shù)據(jù)不是存在內(nèi)存中嗎?這些想法都沒(méi)錯(cuò),那么寄存器是用來(lái)做什么的呢?
寄存器作用
其實(shí)硬盤、內(nèi)存都是用來(lái)存儲(chǔ)數(shù)據(jù)的,但是 CPU
的運(yùn)算速度遠(yuǎn)高于內(nèi)存的讀寫速度,更不用說(shuō)從硬盤上取數(shù)據(jù)了,所以為了避免被拖慢速度影響效率,CPU
都自帶一級(jí)緩存和二級(jí)緩存,一些 CPU
甚至增加了三級(jí)緩存,從這些緩存中讀寫數(shù)據(jù)要比內(nèi)存快很多,但是還是無(wú)法使用飛速運(yùn)轉(zhuǎn)的 CPU
,所以才會(huì)有寄存器的存在。
寄存器不是后來(lái)增加的,在最初的計(jì)算中就已經(jīng)設(shè)計(jì)出來(lái),相比而言,多級(jí)緩存出現(xiàn)的更晚一些,通常那些最頻繁讀寫的數(shù)據(jù)都會(huì)被放在寄存器里面,CPU
優(yōu)先讀寫寄存器,再通過(guò)寄存器、緩存跟內(nèi)存來(lái)交換數(shù)據(jù),達(dá)到緩沖的目的,因?yàn)榭梢酝ㄟ^(guò)名稱訪問(wèn)寄存器,這樣訪問(wèn)速度是最快的,因此也被稱為零級(jí)緩存。
存取速度比較
通過(guò)上面的敘述我們可以知道存取速度從高到低分別是: 寄存器 > 1級(jí)緩存 > 2級(jí)緩存 > 3級(jí)緩存 > 內(nèi)存 > 硬盤
,關(guān)于它們的存取速度,舉個(gè)例子很容易就能明白了,比如我們做菜(CPU工作)時(shí),取手中(寄存器)正拿著的肉和蔬菜肯定是最快的,如果沒(méi)有就需要把案板上(1級(jí)緩存)處理好的菜拿過(guò)來(lái),如果案板上沒(méi)有就在更遠(yuǎn)一點(diǎn)的洗菜池(2級(jí)緩存)中找一找,還沒(méi)找到的話就要到冰箱(3級(jí)緩存)中看一看了,這時(shí)發(fā)現(xiàn)家里真沒(méi)有,那去樓下的菜店(內(nèi)存)去買點(diǎn)吧,轉(zhuǎn)了一圈發(fā)現(xiàn)沒(méi)有想要的,最后還是開(kāi)車去農(nóng)貿(mào)市場(chǎng)(硬盤)買吧。
通過(guò)上面這個(gè)例子應(yīng)該能明白它們的速度關(guān)系了,既然緩存這么快,為什么不用緩存代替內(nèi)存,或者將2、3級(jí)緩存都換成1級(jí)緩存呢?這里邊有一個(gè)成本問(wèn)題,速度越快對(duì)應(yīng)著價(jià)格越高,如果你買過(guò)機(jī)械硬盤和固態(tài)硬盤應(yīng)該很容易就理解了。
寄存器分類
常用的 x86 CPU
寄存器有8個(gè):EAX
、EBX
、ECX
、EDX
、EDI
、ESI
、EBP
、ESP
,據(jù)說(shuō)現(xiàn)在寄存器總數(shù)已經(jīng)超過(guò)100個(gè)了,等我找到相關(guān)資料再來(lái)補(bǔ)充,上面這幾個(gè)寄存器是最常用的,這些名字也常常出現(xiàn)在匯編的代碼中。
我們常說(shuō)的32位、64位 CPU
是指數(shù)據(jù)總線的寬度或根數(shù),而寄存器是暫存數(shù)據(jù)和中間結(jié)果的單元,因此寄存器的位數(shù)也就是處理數(shù)據(jù)的長(zhǎng)度與數(shù)據(jù)總線的根數(shù)是相同的,所以32位 CPU
對(duì)應(yīng)的寄存器也應(yīng)該是32位的。
常用寄存器用途
上面提到大8個(gè)寄存器都有其特定的用途,我們以32位 CPU
為例簡(jiǎn)單說(shuō)明下這些寄存器的作用,整理如下表:
寄存器 | 含義 | 用途 | 包含寄存器 |
---|---|---|---|
EAX | 累加(Accumulator)寄存器 | 常用于乘、除法和函數(shù)返回值 | AX(AH、AL) |
EBX | 基址(Base)寄存器 | 常做內(nèi)存數(shù)據(jù)的指針, 或者說(shuō)常以它為基址來(lái)訪問(wèn)內(nèi)存. | BX(BH、BL) |
ECX | 計(jì)數(shù)器(Counter)寄存器 | 常做字符串和循環(huán)操作中的計(jì)數(shù)器 | CX(CH、CL) |
EDX | 數(shù)據(jù)(Data)寄存器 | 常用于乘、除法和 I/O 指針 | DX(DH、DL) |
ESI | 來(lái)源索引(Source Index)寄存器 | 常做內(nèi)存數(shù)據(jù)指針和源字符串指針 | SI |
EDI | 目的索引(Destination Index)寄存器 | 常做內(nèi)存數(shù)據(jù)指針和目的字符串指針 | DI |
ESP | 堆棧指針(Stack Point)寄存器 | 只做堆棧的棧頂指針; 不能用于算術(shù)運(yùn)算與數(shù)據(jù)傳送 | SP |
EBP | 基址指針(Base Point)寄存器 | 只做堆棧指針, 可以訪問(wèn)堆棧內(nèi)任意地址, 經(jīng)常用于中轉(zhuǎn) ESP 中的數(shù)據(jù), 也常以它為基址來(lái)訪問(wèn)堆棧; 不能用于算術(shù)運(yùn)算與數(shù)據(jù)傳送 | BP |
寄存器EAX、AX、AH、AL的關(guān)系
在上面的圖標(biāo)中每個(gè)常用寄存器后面還有其他的名字,它們是同一個(gè)寄存器不同用法下的不同名字,比如在32位 CPU
上,EAX是32位的寄存器,而AX是EAX的低16位,AH是AX的高8位,而AL是AX的低8位,它們的對(duì)照關(guān)系如下:
00000000 00000000 00000000 00000000 |===============EAX===============|---4個(gè)字節(jié) |======AX=======|---2個(gè)字節(jié) |==AH===|-----------1個(gè)字節(jié) |===AL==|---1個(gè)字節(jié)
匯編語(yǔ)言指令
終于說(shuō)到匯編常用指令了,因?yàn)?linux
和 windows
下的匯編語(yǔ)法是有些不同的,所以下面我們先通過(guò) windows
下的匯編指令來(lái)簡(jiǎn)單學(xué)習(xí)一下,后續(xù)再來(lái)比較兩者的不同。
數(shù)據(jù)傳送指令
指令 | 名稱 | 示例 | 備注 |
---|---|---|---|
MOV | 傳送指令 | MOV dest, src | 將數(shù)據(jù)從src移動(dòng)到dest |
PUSH | 進(jìn)棧指令 | PUSH src | 把源操作數(shù)src壓入堆棧 |
POP | 出棧指令 | POP desc | 從棧頂彈出字?jǐn)?shù)據(jù)到dest |
算術(shù)運(yùn)算指令
指令 | 名稱 | 示例 | 備注 |
---|---|---|---|
ADD | 加法指令 | ADD dest, src | 在dest基礎(chǔ)上加src |
SUB | 減法指令 | SUB dest, src | 在dest基礎(chǔ)上減src |
INC | 加1指令 | INC dest | 在dest基礎(chǔ)上加1 |
DEC | 減1指令 | DEC dest | 在dest基礎(chǔ)上減1 |
邏輯運(yùn)算指令
指令 | 名稱 | 示例 | 備注 |
---|---|---|---|
NOT | 取反運(yùn)算指令 | NOT dest | 把操作數(shù)dest按位取反 |
AND | 與運(yùn)算指令 | AND dest, src | 把dest和src進(jìn)行與運(yùn)算之后送回dest |
OR | 或運(yùn)算指令 | OR dest, src | 把dest和src進(jìn)行或運(yùn)算之后送回dest |
XOR | 異或運(yùn)算 | XOR dest, src | 把dest和src進(jìn)行異或運(yùn)算之后送回dest |
循環(huán)控制指令
指令 | 名稱 | 示例 | 備注 |
---|---|---|---|
LOOP | 計(jì)數(shù)循環(huán)指令 | LOOP label | 使ECX的值減1,當(dāng)ECX的值不為0的時(shí)候跳轉(zhuǎn)至label,否則執(zhí)行LOOP之后的語(yǔ)句 |
轉(zhuǎn)移指令
指令 | 名稱 | 示例 | 備注 |
---|---|---|---|
JMP | 無(wú)條件轉(zhuǎn)移指令 | JMP lable | 無(wú)條件地轉(zhuǎn)移到標(biāo)號(hào)為label的位置 |
CALL | 過(guò)程調(diào)用指令 | CALL labal | 直接調(diào)用label |
JE | 條件轉(zhuǎn)移指令 | JE lable | zf =1 時(shí)跳轉(zhuǎn)到標(biāo)號(hào)為label的位置 |
JNE | 條件轉(zhuǎn)移指令 | JNE lable | zf=0 時(shí)跳轉(zhuǎn)到標(biāo)號(hào)為label的位置 |
linux 和 windows 下匯編的區(qū)別
前面說(shuō)到 linux
和 windows
下的匯編語(yǔ)法是不同的,其實(shí)兩種語(yǔ)法的不同和系統(tǒng)不同沒(méi)有絕對(duì)的關(guān)系,一般在 linux
上會(huì)使用 gcc/g++
編譯器,而在 windows
上會(huì)使用微軟的 cl
也就是 MSBUILD
,所以產(chǎn)生不同的代碼是因?yàn)榫幾g器不同,gcc
下采用的是AT&T的匯編語(yǔ)法格式,MSBUILD
采用的是Intel匯編語(yǔ)法格式。
差異 | Intel | AT&T |
---|---|---|
引用寄存器名字 | eax | %eax |
賦值操作數(shù)順序 | mov dest, src | movl src, dest |
寄存器、立即數(shù)指令前綴 | mov ebx, 0xd00d | movl $0xd00d, %ebx |
寄存器間接尋址 | [eax] | (%eax) |
數(shù)據(jù)類型大小 | 操作碼后加后綴字母,“l(fā)” 32位,“w” 16位,“b” 8位(mov dx, word ptr [eax]) | 操作數(shù)前面加dword ptr, word ptr,byte ptr的格式 (movb %bl %al) |
總結(jié)
匯編指令是機(jī)器指令的助記符,與機(jī)器指令是一一對(duì)應(yīng)的
AT&T的匯編語(yǔ)法格式和Intel匯編語(yǔ)法格式的是不同的
常用寄存器:EAX
、EBX
、ECX
、EDX
、EDI
、ESI
、EBP
、ESP
存取速度從高到低分別是: 寄存器 > 1級(jí)緩存 > 2級(jí)緩存 > 3級(jí)緩存 > 內(nèi)存 > 硬盤
的匯編指令:mov
、je
、jmp
、call
、add
、sub
、inc
、dec
、and
、or
如今的每分每秒都是人生,不要總想著將自然發(fā)生的事情拖到預(yù)定的時(shí)刻才進(jìn)行~
以上就是匯編語(yǔ)言入門匯編指令及寄存器詳解教程的詳細(xì)內(nèi)容,更多關(guān)于匯編語(yǔ)言指令及寄存器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
匯編語(yǔ)言指令集學(xué)習(xí)CMPXCHG比較并交換操作指令詳解
這篇文章主要為大家介紹了匯編語(yǔ)言指令集學(xué)習(xí)CMPXCHG比較并交換操作的指令詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11匯編語(yǔ)言中的函數(shù)調(diào)用參數(shù)傳遞及全局與局部變量與“基址”
這篇文章主要介紹了匯編眼中的函數(shù)調(diào)用參數(shù)傳遞以及全局與局部變量與“基址”,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02王爽 匯編語(yǔ)言學(xué)習(xí)筆記(詳細(xì))
王爽匯編語(yǔ)言第三版是一款高清完整版的專業(yè)編程圖書,該書結(jié)構(gòu)設(shè)計(jì)合理,內(nèi)容全面涵蓋知識(shí)點(diǎn)豐富,適合自學(xué)者使用,有需要者快來(lái)2020-01-01匯編語(yǔ)言指令大全 X86和X87匯編指令大全(帶注釋)
匯編指令集太多,如果不用就會(huì)忘記,所以將i處理器官方的指令集大全寫到博客上,有需要的人可以參考一下2021-10-10