您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“C++內嵌匯編的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“C++內嵌匯編的示例分析”這篇文章吧。
匯編語言是一種功能很強的程序設計語言,也是利用了計算機所有硬件特性并能直接控制硬件的語言。在匯編語言中,用助記符(Memoni)代替操作碼,用地址符號(Symbol)或標號(Label)代替地址碼。這樣用符號代替機器語言的二進制碼,就把機器語言變成了匯編語言。
匯編語言比機器語言易于讀寫、調試和修改,同時也具有機器語言執行速度快、占用內存空間少等優點。但在編寫復雜程序時,相對高級語言來說匯編語言代碼量較大,而且匯編語言依賴于具體的機型,不能通用,因此不能直接在不同處理機型之間移植。雖然其移植性不好,但效率非常高,針對計算機特定硬件而編制的匯編語言程序,能準確地發揮計算機硬件的功能和特長,程序精煉而質量高,所以匯編語言至今仍是一種常用而強有力的底層開發語言。
匯編語言指令使用一些具有相應含義的助憶符來表達的,所以,它要比機器語言容易掌握和運用。但因為要直接使用CPU資源,所以相對高級程序設計語言來說它又顯得相對復雜。匯編語言程序歸納起來大概有以下幾個主要特點。
1. 與硬件相關:匯編語言指令是指機器指令的一種符號表示,而不同類型的CPU有不同的機器指令系統,也就有不同的匯編語言,所以匯編語言程序與機器有著密切的關系。也就是說,不同型號的CPU之間是無法通用相同匯編代碼的,因此導致匯編語言的移植性和通用性降低,這是匯編語言天生的缺陷。
2. 保持了機器語言的優點,具有直接和簡捷的特點:正因為匯編語言有“與機器相關性”的特性,程序員用匯編語言編寫程序時,可充分發揮自己的聰明才智,對機器內部的各種資源進行合理的安排,讓它們始終處于最佳的使用狀態,這樣做的最終效果就是程序的執行代碼短,執行速度快,所以,匯編語言是高效的程序設計語言。另外匯編語言可有效地訪問、控制計算機的各種硬件設備,如磁盤、存儲器、CPU、I/O端口等,實現資源利用的最大化。
3. 編寫程序復雜:匯編語言是一種面向機器的語言,其匯編指令與機器指令基本上一一對應,所以,匯編指令也同機器指令一樣既有功能單一、具體的特點。要想完成某件工作,就必須安排CPU的每步工作。另外,在編寫匯編語言程序時,還要考慮具體機型的限制、匯編指令的細節和限制等。
4. 經常與高級語言配合使用,應用十分廣泛:在某些情況下,比如直接操作CPU執行中斷以實現線程調度、保存CPU寄存器以存儲/恢復線程狀態等,僅僅使用高級語言是完不成的,需要借助于匯編語言,但是僅使用匯編語言的話,大型程序恐怕需要付出比高級語言幾倍的工作量,有時候也是沒有必要的。因此,可以在高級語言里嵌入匯編語句,讓僅僅一部分需要高效率的代碼用匯編語言來完成,其余的框架搭建等用高級語言來完成,這樣既保證了效率又降低了代碼的復雜程度。這種配合使用在大型軟件開發里經常遇到,應用十分廣泛。
注:
本文的所有代碼是在我自己的VS2008中測試的,由于環境的差別,不能保證能在所有的編譯器上運行。
在C++中,可以通過__asm關鍵字來嵌入匯編語言。
例如
int main(){ __asm{//匯編! mov eax,0 } return 0; }
我們知道,在C++中,可以使用printf函數來輸出。(如果使用cout,需要使用運算符重載等技術,在這里反而不方便)
提示:
匯編中,調用函數的指令叫做CALL。
函數的參數是保存在棧中的。
那么我們可以開始寫了。首先,先看看C++正常版本的:
#include<stdio.h> #include<stdlib.h> const char *s1="Hello, World\n",*s2="pause"; int main(){ printf(s1); system(s2); return 0; }
為了方便,我們先把正常版本反匯編一下,結果是:
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] 括號中的0BD7038h是地址,不要管他,意思是把地址放到eax中去
第三句,push eax 把剛才放進eax的地址放入棧, 實際就是把參數放入棧
第四句,call dword ptr [__imp__printf]
__imp__printf是printf函數編譯后的結果,下劃線開頭表示這是一個函數
我們平時寫內聯匯編的時候直接寫printf即可
第五句,add esp,4
其實是手動平棧,之前往棧里面放了4字節的s1,現在把esp指針也就是棧頂指針下移(棧從高地址往低地址),平棧
最后兩句不管它,就是保證esi和esp相等,因為之前手動平了棧,結合第一句,這里應該是相等的,不寫應該也沒事
最終的內聯匯編應該是這樣:
#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; }
運行結果正常。
A+B問題,同時需要使用scanf和printf
首先注意一點,函數的參數在棧中是倒著存放的。(注:這個C標準沒有規定,但是匯編語言本身就是非常依賴環境的一個東西,所以暫且不管它)
例如
scanf("%d %d",&a,&b);
如果翻譯成匯編,應該是這樣(下面的是偽代碼)
push &b push &a push "%d %d" call scanf
然后我們就可以開始寫了。
scanf的部分,注意最前面兩個參數,由于放入的是地址,所以不能使用MOV指令而是要使用LEA指令
lea eax,[a]
表示把a的地址放入eax中。
其他部分沒有什么難度,注意最后平棧的時候,add esp到底加上多少,加上的是每個參數的大小相加。
例如scanf,每個都是4字節的地址,總共就是12字節。
完整代碼
#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; }
以上是“C++內嵌匯編的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。