C++內(nèi)嵌匯編示例詳解
匯編語(yǔ)言
匯編語(yǔ)言是一種功能很強(qiáng)的程序設(shè)計(jì)語(yǔ)言,也是利用了計(jì)算機(jī)所有硬件特性并能直接控制硬件的語(yǔ)言。在匯編語(yǔ)言中,用助記符(Memoni)代替操作碼,用地址符號(hào)(Symbol)或標(biāo)號(hào)(Label)代替地址碼。這樣用符號(hào)代替機(jī)器語(yǔ)言的二進(jìn)制碼,就把機(jī)器語(yǔ)言變成了匯編語(yǔ)言。
匯編語(yǔ)言比機(jī)器語(yǔ)言易于讀寫、調(diào)試和修改,同時(shí)也具有機(jī)器語(yǔ)言執(zhí)行速度快、占用內(nèi)存空間少等優(yōu)點(diǎn)。但在編寫復(fù)雜程序時(shí),相對(duì)高級(jí)語(yǔ)言來(lái)說(shuō)匯編語(yǔ)言代碼量較大,而且匯編語(yǔ)言依賴于具體的機(jī)型,不能通用,因此不能直接在不同處理機(jī)型之間移植。雖然其移植性不好,但效率非常高,針對(duì)計(jì)算機(jī)特定硬件而編制的匯編語(yǔ)言程序,能準(zhǔn)確地發(fā)揮計(jì)算機(jī)硬件的功能和特長(zhǎng),程序精煉而質(zhì)量高,所以匯編語(yǔ)言至今仍是一種常用而強(qiáng)有力的底層開(kāi)發(fā)語(yǔ)言。
匯編語(yǔ)言的特點(diǎn)
匯編語(yǔ)言指令使用一些具有相應(yīng)含義的助憶符來(lái)表達(dá)的,所以,它要比機(jī)器語(yǔ)言容易掌握和運(yùn)用。但因?yàn)橐苯邮褂肅PU資源,所以相對(duì)高級(jí)程序設(shè)計(jì)語(yǔ)言來(lái)說(shuō)它又顯得相對(duì)復(fù)雜。匯編語(yǔ)言程序歸納起來(lái)大概有以下幾個(gè)主要特點(diǎn)。
1. 與硬件相關(guān):匯編語(yǔ)言指令是指機(jī)器指令的一種符號(hào)表示,而不同類型的CPU有不同的機(jī)器指令系統(tǒng),也就有不同的匯編語(yǔ)言,所以匯編語(yǔ)言程序與機(jī)器有著密切的關(guān)系。也就是說(shuō),不同型號(hào)的CPU之間是無(wú)法通用相同匯編代碼的,因此導(dǎo)致匯編語(yǔ)言的移植性和通用性降低,這是匯編語(yǔ)言天生的缺陷。
2. 保持了機(jī)器語(yǔ)言的優(yōu)點(diǎn),具有直接和簡(jiǎn)捷的特點(diǎn):正因?yàn)閰R編語(yǔ)言有“與機(jī)器相關(guān)性”的特性,程序員用匯編語(yǔ)言編寫程序時(shí),可充分發(fā)揮自己的聰明才智,對(duì)機(jī)器內(nèi)部的各種資源進(jìn)行合理的安排,讓它們始終處于最佳的使用狀態(tài),這樣做的最終效果就是程序的執(zhí)行代碼短,執(zhí)行速度快,所以,匯編語(yǔ)言是高效的程序設(shè)計(jì)語(yǔ)言。另外匯編語(yǔ)言可有效地訪問(wèn)、控制計(jì)算機(jī)的各種硬件設(shè)備,如磁盤、存儲(chǔ)器、CPU、I/O端口等,實(shí)現(xiàn)資源利用的最大化。
3. 編寫程序復(fù)雜:匯編語(yǔ)言是一種面向機(jī)器的語(yǔ)言,其匯編指令與機(jī)器指令基本上一一對(duì)應(yīng),所以,匯編指令也同機(jī)器指令一樣既有功能單一、具體的特點(diǎn)。要想完成某件工作,就必須安排CPU的每步工作。另外,在編寫匯編語(yǔ)言程序時(shí),還要考慮具體機(jī)型的限制、匯編指令的細(xì)節(jié)和限制等。
4. 經(jīng)常與高級(jí)語(yǔ)言配合使用,應(yīng)用十分廣泛:在某些情況下,比如直接操作CPU執(zhí)行中斷以實(shí)現(xiàn)線程調(diào)度、保存CPU寄存器以存儲(chǔ)/恢復(fù)線程狀態(tài)等,僅僅使用高級(jí)語(yǔ)言是完不成的,需要借助于匯編語(yǔ)言,但是僅使用匯編語(yǔ)言的話,大型程序恐怕需要付出比高級(jí)語(yǔ)言幾倍的工作量,有時(shí)候也是沒(méi)有必要的。因此,可以在高級(jí)語(yǔ)言里嵌入?yún)R編語(yǔ)句,讓僅僅一部分需要高效率的代碼用匯編語(yǔ)言來(lái)完成,其余的框架搭建等用高級(jí)語(yǔ)言來(lái)完成,這樣既保證了效率又降低了代碼的復(fù)雜程度。這種配合使用在大型軟件開(kāi)發(fā)里經(jīng)常遇到,應(yīng)用十分廣泛。
注:
本文的所有代碼是在我自己的VS2008中測(cè)試的,由于環(huán)境的差別,不能保證能在所有的編譯器上運(yùn)行。
1.內(nèi)嵌匯編介紹
在C++中,可以通過(guò)__asm關(guān)鍵字來(lái)嵌入?yún)R編語(yǔ)言。
例如
int main(){ __asm{//匯編! mov eax,0 } return 0; }
2.匯編版本Hello, World!
我們知道,在C++中,可以使用printf函數(shù)來(lái)輸出。(如果使用cout,需要使用運(yùn)算符重載等技術(shù),在這里反而不方便)
提示:
匯編中,調(diào)用函數(shù)的指令叫做CALL。
函數(shù)的參數(shù)是保存在棧中的。
那么我們可以開(kāi)始寫了。首先,先看看C++正常版本的:
#include<stdio.h> #include<stdlib.h> const char *s1="Hello, World\n",*s2="pause"; int main(){ printf(s1); system(s2); return 0; }
為了方便,我們先把正常版本反匯編一下,結(jié)果是:
printf(s1);
00BD13CE mov esi,esp
00BD13D0 mov eax,dword ptr [s1 (0BD7038h)]
00BD13D5 push eax
00BD13D6 call dword ptr [__imp__printf (0BD82C4h)]
00BD13DC add esp,4
00BD13DF cmp esi,esp
00BD13E1 call @ILT+315(__RTC_CheckEsp) (0BD1140h)
第一句,mov esi,esp 為了后面檢查棧是否正常用
第二句,mov eax,dword ptr[s1] 括號(hào)中的0BD7038h是地址,不要管他,意思是把地址放到eax中去
第三句,push eax 把剛才放進(jìn)eax的地址放入棧, 實(shí)際就是把參數(shù)放入棧
第四句,call dword ptr [__imp__printf]
__imp__printf是printf函數(shù)編譯后的結(jié)果,下劃線開(kāi)頭表示這是一個(gè)函數(shù)
我們平時(shí)寫內(nèi)聯(lián)匯編的時(shí)候直接寫printf即可
第五句,add esp,4
其實(shí)是手動(dòng)平棧,之前往棧里面放了4字節(jié)的s1,現(xiàn)在把esp指針也就是棧頂指針下移(棧從高地址往低地址),平棧
最后兩句不管它,就是保證esi和esp相等,因?yàn)橹笆謩?dòng)平了棧,結(jié)合第一句,這里應(yīng)該是相等的,不寫應(yīng)該也沒(méi)事
最終的內(nèi)聯(lián)匯編應(yīng)該是這樣:
#include<stdio.h> #include<stdlib.h> const char *s1="Hello, World\n",*s2="pause"; int main(){ _asm{ mov eax,dword ptr [s1] push eax call dword ptr [printf] add esp,4 mov eax,dword ptr[s2] push eax call dword ptr [system] add esp,4 } return 0; }
運(yùn)行結(jié)果正常。
3.內(nèi)聯(lián)匯編A+B
A+B問(wèn)題,同時(shí)需要使用scanf和printf
首先注意一點(diǎn),函數(shù)的參數(shù)在棧中是倒著存放的。(注:這個(gè)C標(biāo)準(zhǔn)沒(méi)有規(guī)定,但是匯編語(yǔ)言本身就是非常依賴環(huán)境的一個(gè)東西,所以暫且不管它)
例如
scanf("%d %d",&a,&b);
如果翻譯成匯編,應(yīng)該是這樣(下面的是偽代碼)
push &b push &a push "%d %d" call scanf
然后我們就可以開(kāi)始寫了。
scanf的部分,注意最前面兩個(gè)參數(shù),由于放入的是地址,所以不能使用MOV指令而是要使用LEA指令
lea eax,[a]
表示把a(bǔ)的地址放入eax中。
其他部分沒(méi)有什么難度,注意最后平棧的時(shí)候,add esp到底加上多少,加上的是每個(gè)參數(shù)的大小相加。
例如scanf,每個(gè)都是4字節(jié)的地址,總共就是12字節(jié)。
完整代碼
#include<stdio.h> #include<stdlib.h> const char *s1="%d%d",*s2="%d\n",*s3="pause"; int a,b; int main(){ _asm{ lea eax,[b] push eax lea eax,[a] push eax mov eax,dword ptr [s1] push eax call dword ptr [scanf] add esp,12 mov eax,[a] add eax,[b] push eax mov eax,dword ptr [s2] push eax call dword ptr [printf] add esp,8 mov eax,dword ptr [s3] push eax call dword ptr [system] add esp,4 } return 0; }
到此這篇關(guān)于C++內(nèi)嵌匯編的文章就介紹到這了,更多相關(guān)C++內(nèi)嵌匯編內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言安全之?dāng)?shù)組長(zhǎng)度與指針實(shí)例解析
這篇文章主要介紹了C語(yǔ)言安全之?dāng)?shù)組長(zhǎng)度與指針,需要的朋友可以參考下2014-07-07MongoDB?C?驅(qū)動(dòng)程序安裝(libmongoc)?和?BSON?庫(kù)(libbson)方法
這篇文章主要介紹了安裝?MongoDB?C?驅(qū)動(dòng)程序?(libmongoc)?和?BSON?庫(kù)?(libbson),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09C語(yǔ)言求Fibonacci斐波那契數(shù)列通項(xiàng)問(wèn)題的解法總結(jié)
斐波那契數(shù)列相關(guān)問(wèn)題是考研和ACM中常見(jiàn)的算法題目,這里特地為大家整理了C語(yǔ)言求Fibonacci斐波那契數(shù)列通項(xiàng)問(wèn)題的解法總結(jié),需要的朋友可以參考下2016-06-06C++實(shí)現(xiàn)帶頭雙向循環(huán)鏈表的示例詳解
這篇文章主要介紹了如何利用C++實(shí)現(xiàn)帶頭雙向循環(huán)鏈表,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-12-12