在VC中使用內聯彙編

2021-06-02 00:34:21 字數 4629 閱讀 6107

一、內聯彙編的優缺點

因為在visual c++中使用內聯彙編不需要額外的編譯器和聯接器,且可以處理visual c++中不能處理的一些事情,而且可以使用在c/c++中的變數,所以非常方便。內聯彙編主要用於如下場合:

1.使用組合語言寫函式;

2.對速度要求非常高的**;

3.裝置驅動程式中直接訪問硬體;

4."naked" call的初始化和結束**。

//(."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++中的陣列中的元素個數,如果不是乙個陣列,則結果為一。

使用type用來取得乙個變數的大小,如果是乙個陣列,它得到的乙個陣列中的單個元素的大小。

使用size來取得c/c++中變數的大小,乙個變數的大小是length和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[5 * type int], 0     ; store 0 at array + 5*2

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++寫。

八、乙個例子

引自:   

在Visual C 中使用內聯彙編

一 內聯彙編的優缺點 因為在visual c 中使用內聯彙編不需要額外的編譯器和聯接器,且可以處理visual c 中不能處理的一些事情,而且可以使用在c c 中的變數,所以非常方便。內聯彙編主要用於如下場合 1.使用組合語言寫函式 2.對速度要求非常高的 3.裝置驅動程式中直接訪問硬體 4.nak...

在C中使用內聯彙編

在visual c 使用內聯彙編用到的是 a 關鍵字,這個關鍵字有兩種使用方法 1.簡單 a 塊 a 2.在每條彙編指令之前加 a 關鍵字 a mov al,2 a mov dx,0xd007 a out al,dx 因為 a 關鍵字是語句分隔符,因此你可以把彙編指令放在同一行 a mov al,2...

在C中使用內聯彙編

在visual c 使用內聯彙編用到的是 a 關鍵字,這個關鍵字有兩種使用方法 1.簡單 a 塊 a 2.在每條彙編指令之前加 a 關鍵字 a mov al,2 a mov dx,0xd007 a out al,dx 因為 a 關鍵字是語句分隔符,因此你可以把彙編指令放在同一行 a mov al,2...