一、內聯彙編的優缺點
因為在visual c++中使用內聯彙編不需要額外的編譯器和聯接器,且可以處理visual c++中不能處理的一些事情,而且可以使用在c/c++中的變數,所以非常方便。內聯彙編主要用於如下場合:
1.使用組合語言寫函式;
2.對速度要求非常高的**;
3.裝置驅動程式中直接訪問硬體;
4."naked" call的初始化和結束**。 (_declspec(naked))
//(."naked",不需要c/c++的編譯器(自作聰明)生成的函式初始化和收尾**,請參看msdn的"naked functions"的說明)
內聯彙編**不易於移植,如果你的程式打算在不同型別的機器(比如x86和alpha)上執行,應當盡量避免使用內聯彙編。這時候你可以使用masm,因為masm支援更方便的的巨集指令和資料指示符。
二、內聯彙編關鍵字
在visual c++使用內聯彙編用到的是__asm關鍵字,這個關鍵字有兩種使用方法:
1.簡單__asm塊
__asm
2.在每條彙編指令之前加__asm關鍵字
__asm mov al, 2
__asm mov dx, 0xd007
__asm out al, dx
因為__asm關鍵字是語句分隔符,因此你可以把彙編指令放在同一行:
__asm mov al, 2 __asm mov dx, 0xd007 __asm out al, dx
顯然,第一種方法和c/c++的風格很一致,並且有很多其它優點,因此推薦使用第一種方法。
不象在c/c++中的"{}",__asm塊的"{}"不會影響c/c++變數的作用範圍。同時,__asm塊可以巢狀,巢狀也不會影響變數的作用範圍。
三、在__asm塊中使用組合語言
1.內聯彙編指令集
內聯彙編完全支援的intel 486指令集,允許使用mmx指令。不支援的指令可以使用_emit偽指令定義(_emit偽指令說明見下文)。
2.masm表示式
內聯彙編可以使用masm中的表示式。比如: mov eax, 1。
3.資料指示符和操作符
雖然__asm塊中允許使用c/c++的資料型別和物件,但它不能用masm指示符和操作符定義資料物件。這裡特別指出,__asm塊中不允許masm中的定義指示符:db、dw、dd、dq、dt和df,也不允許dup和this操作符。masm結構和記錄也不再有效,內聯彙編不接受struc、record、width或者mask。
4.even和align指示符
儘管內聯彙編不支援大多數masm指示符,但它支援even和align,當需要的時候,這些指示符在彙編**裡面加入nop(空操作)指令使標號對齊到特定邊界。這樣可以使某些處理器取指令時具有更高的效率。
5.masm巨集指示符
內聯彙編不是巨集彙編,不能使用masm巨集指示符(macro、rept、irc、irp和endm)和巨集操作符(<>、!、&、%和.type)。
6.段說明
必須使用暫存器來說明段,跨越段必須顯式地說明,如es:[bx]。
7.型別和變數大小
我們可以使用length來取得c/c++中的陣列中的元素個數,如果不是乙個陣列,則結果為一。使用size來取得c/c++中變數的大小,乙個變數的大小是length和type的乘積。type用來取得乙個變數的大小,如果是乙個陣列,它得到的乙個陣列中的單個元素的大小。
8.注釋
可以使用c/c++的注釋,但推薦用asm的注釋,即";"號。
9._emit偽指令
_emit偽指令相當於masm中的db,但一次只能定義乙個位元組,比如:
__asm
四、在__asm塊中使用c/c++語言元素
c/c++與彙編可以混合使用,在內聯彙編可以使用c/c++的變數和很多其它c/c++的元素。在__asm塊中可以使用以下c/c++元素:
1.符號,包括標號、變數和函式名;
2.常量,包括符號常量和列舉型(enum)成員;
3.巨集定義和預處理指示符;
4.注釋,包括"/**/"和"//";
5.型別名,包括所有masm中合法的型別
6.typedef名稱, 像ptr、type、特定的結構成員或列舉成員這樣的通用操作符。
在__asm塊中,可以使用c/c++或asm的基數計數法(比如: 0x100和100h是相等的)。
__asm塊中不能使用像《一類的c/c++操作符。c/c++和masm通用的操作符,比如"*"和""操作符,都被認為是組合語言的操作符。舉個例子:
int array[10];
__asm mov array[6], bx ; store bx at array+6 (not scaled)
array[6] = 0; /* store 0 at array+12 (scaled) */
* 小技巧: 內聯彙編中,你可以使用type操作符使作其與c一致。比如,下面兩條語句是一樣的:
__asm mov array[6 * type int], 0 ; store 0 at array + 12
array[6] = 0; /* store 0 at array + 12 */
內聯彙編能通過變兩名直接引用c/c++的變數。__asm塊中可以引用任何符號,包括變數名。
如果c/c++中的類、結構或者列舉成員具有唯一的名稱,如果在"."操作符之前不指定變數或者typedef名稱,則__asm塊中只能引用成員名稱。然而,如果成員不是唯一的,你必須在"."操作符之前加上變數名或typedef名稱。例如,下面的兩個結構都具有same_name這個成員變數:
struct first_type
; struct second_type ;
如果按下面宣告變數:
struct first_type hal;
struct second_type oat;
那麼,所有引用same_name成員的地方都必須使用變數名,因為same_name不是唯一的。另外,上面的weasel變數具有唯一的名稱,你可以僅僅使用它的成員名稱來引用它:
__asm
注意,省略了變數名僅僅是為了寫**的方便,生成的彙編指令的還是一樣的。
可以不受限制地訪問c++成員變數,但是不能呼叫c++的成員函式。
五、暫存器使用
一般來說,在__asm塊開始的時候,暫存器是空的,不能在兩個__asm之間儲存暫存器的值。(這是msdn上說的,我在實際使用時發現,好像並不是這樣。不過它是說"一般",我是特殊:))
如果乙個函式被宣告成了__fastcall,則其引數將放在暫存器中,這將給暫存器的管理帶來問題。所以,如果要將乙個函式宣告成__fastcall,必須儲存ecx暫存器。為了避免以上的衝突,在宣告為__fastcall的函式中不要有__asm塊。如果用了/gr編譯選項(它全域性的變成__fastcall),將每個函式宣告成__cdecl或者__stdcall,這個屬性告訴編譯器用傳統的c方法。
如果使用eax、ebx、ecx、edx、esi和edi暫存器,你不需要儲存它;但如果你用到了ds、 ss、sp、bp和標誌暫存器,那就應該push儲存這些暫存器。
如果程式中改變了用於std和cld的方向標誌,你必須將其恢復到原來的值。
六、轉跳
可以在c裡面使用goto調到__asm塊中的標號處,也可以在__asm塊中轉跳到__asm塊裡面和外面的標號處。__asm塊內的標號是不區分大小寫的(指令、指示符等也是不區分大小寫的)。例:
void func()
c_dest: /* c的標號 */
return; }
不要使用函式名稱當作標號,否則將使其跳到函式執行而不是標號處。如下所示:
; 錯誤: 使用函式名作為標號
jne exit
. .
. exit:
; 下面是更多的asm**
美元符號$用於指定當前位置,如下所用,常用於條件跳**
jne $+5 ; 下面這條指令的長度是5個位元組
jmp farlabel
;$+5,跳到了這裡
. .
. farlabel:
七、呼叫函式
內聯彙編呼叫c/c++函式必須自己清除堆疊,下面是乙個呼叫c/c++函式例子:
#include
char szformat = "%s %s/n";
char szhello = "hello";
char szworld = " world";
void main() }
注意:函式引數是從右向左壓棧。
不能夠訪問c++中的類成員函式,但是可以訪問extern "c"函式。
如果呼叫windows api函式,則不需要自己清除堆疊,因為api的返回指令是ret n,會自動清除堆疊
比如下面的例子:
一般來說,在visual c++中使用內聯彙編是為了提高速度,因此這些函式呼叫盡可能用c/c++寫。
八、乙個例子
內嵌彙編和內聯彙編的使用
有時為了高效,有時為了直接控制硬體,有些模組我們不得不直接用組合語言來編寫,並且對外提供呼叫的介面,隱藏細節,這其實就是內聯彙編。如何使用內聯彙編?我們就以 gcc 為例,一窺其中奧秘!一 關鍵字 如何讓 gcc 知道 中內嵌的彙編呢?借助關鍵字!來看下面的例子 asm volatile hlt a...
Linux C語言內聯彙編使用
最近要改個c語言演算法的關鍵部分用組合語言實現,linux裡嵌入彙編基本使用at t彙編,比如linux系統的啟動部分用的就是at t彙編 以前學過at t彙編,但學過一段時間就忘了,但對intel彙編基礎比較熟悉,兩者使用方法基本相似,所以對著intel彙編,花點時間看at t彙編也就容易了。下面...
Linux C語言內聯彙編使用
最近要改個c語言演算法的關鍵部分用組合語言實現,linux裡嵌入彙編基本使用at t彙編,比如linux系統的啟動部分用的就是at t彙編 以前學過at t彙編,但學過一段時間就忘了,但對intel彙編基礎比較熟悉,兩者使用方法基本相似,所以對著intel彙編,花點時間看at t彙編也就容易了。下面...