彙編與C互操作

2021-09-07 22:24:48 字數 2853 閱讀 2373

彙編與c互操作

c語言內嵌彙編**

c語言呼叫彙編過程

彙編呼叫c語言過程

1)開啟vs2008,建立乙個vc++空工程。

2)在solution explorer上右擊工程名,選擇custom build rules…,在彈出的對話方塊上勾選microsoft macro assembler。

3)在solution explorer上右擊工程名,選擇屬性,在彈出的對話方塊上選擇configuration properties->linker->system->subsystem,選擇console (/subsystem:console)

4)如果需要建立彙編原始檔,在solution explorer上右擊工程名->add->new item,在開啟的對話方塊上選擇c++ file(.cpp),命名為***.asm。

在c語言中可以通過__asm偽指令插入彙編**,語法如下

__asm 彙編指令
或者:

__asm

我發現,vc編譯器不會為在__asm段中用到的暫存器儲存/恢復狀態,這意味著什麼呢?比如在__asm中使用了ecx暫存器,在函式字首和字尾中很可能沒有儲存/恢復ecx的**(除非函式的c**部分用到了ecx),那麼對於呼叫者來說,ecx暫存器的狀態在呼叫該函式後被破壞了,所以我們最好自己在__asm段中儲存/恢復用到的暫存器,看下面的例子:

int addnumber(int number1,int number2)

}

在進入正題前,我們需要先來簡單講解一下c語言的名字修飾規則。在c/c++編譯時,vc編譯器會把函式名根據一定規則進行修飾應用到生成的物件檔案、列表檔案等檔案中。在鏈結時,鏈結器只知道函式的修飾名並用它進行鏈結。函式的修飾規則根據函式採用的呼叫約定不同而不同,我們介紹2中常用的呼叫約定的名字修飾:

c語言的__cdecl呼叫約定:在函式名前加下劃線」_」。

c語言的__stdcall呼叫約定:在函式名前加下劃線」_」,在後面加@,後面跟引數的位元組數總和,如_getstdhandle@4。

為什麼要提到名字修飾呢?我們來考慮下面這種情形:在c中宣告了採用__cdecl呼叫規範的外部過程addnumber,這個外部過程是在彙編原始檔中定義的。由於c語言採用了名字修飾,在生成的物件檔案中addnumber的修飾名為_addnumber。然而,在彙編原始檔中,過程沒有使用名字修飾(我們也可以為彙編使用名字修飾,稍後再涉及),生成的物件檔案中函式名依然為addnumber,顯然,這時候鏈結出錯。解決的辦法很簡單,在彙編**中,把函式名命名為_addnumber即可。看下面的例子:

#include "iostream"

using namespace std;

extern "c" int __cdecl addnumber(int number1,int number2);

int main()

以上**除了前言中的配置外,還要進行以下配置才能執行:

1)在addnumber.cpp上右擊屬性,在開啟的對話方塊上選擇c/c++->advanced->compile as,把compile as c++ code修改為 compile as c code。這就使用c而不是c++的名字修飾規則來編譯addnumber.cpp。

2)在工程上右擊屬性,在開啟的對話方塊上選擇configuration properties->linker->command line,在文字框中新增:msvcrtd.lib,這樣,程式鏈結時將鏈結c執行時庫,就能使用c語言的庫函式了。其實,這一步也可以省略,如果我們檢視編譯器用addnumber.cpp生成的彙編**,你會發現這樣的語句:includelib msvcrtd。由於cpp原始檔都會預設新增對c執行時庫的引用,這就是為什麼這步可以省略。但是,如果工程中沒有任何引用c執行時庫的原始檔,而我們又希望使用c語言的庫函式,那麼就需要這一步配置。

現在,我們來研究我們上面的**。我們通過」extrn」來宣告外部過程,如c語言庫函式printf,由於名字修飾,因此這裡宣告為_printf。

這裡最關鍵的是程式的入口點問題。使用c執行時庫的程式(也就是一般的c/c++程式),實際的程式入口點為mainrtsetup,然後mainrtsetup呼叫main函式或者wmain函式(如果是視窗程式而非控制台,則為winmain或者wwinmain)。我們的工程由於使用了c執行時庫,再考慮到名字修飾,因此主函式名必須是_main或者_wmain。在彙編工程中,我們會在原始檔中用「end _main」結尾來標識_main為入口點函式,但是這個工程中_main並不是入口點函式,所以需要以end結尾。同樣的道理,彙編工程中我們會以語句invoke exitprocess,0來結束入口點函式,而這裡_main函式則不需要。相反的,由於_main函式結束後會返回到mainrtsetup函式,因此_main應該加上必要的字首和字尾來儲存/恢復暫存器,而彙編工程的入口點函式我們不儲存/恢復暫存器也沒有關係。

或許,仍然有辦法在使用c執行時庫的情況下直接把_main直接設定為入口點函式,但是我的嘗試都失敗了,就不贅述。

作者在寫本文時也遇到了許多問題,或許大家還會遇到一些其他問題,如果你的彙編原始檔不能通過編譯或鏈結,嘗試這個辦法:首先,寫乙個c語言版的原始檔來替代彙編原始檔,例如先用addnumber.cpp取代addnumber.asm,然後確保整個工程能夠編譯並執行。再右擊addnumber.cpp,開啟屬性對話方塊,選擇c/c++->output files->assembler output,選擇assembly with source code (/fas)。編譯addnumber.cpp,然後在addnumber.cpp目錄的debug子目錄中你可以發現乙個叫做addnumber.asm的檔案,這是編譯器為addnumber.cpp生成的彙編原始檔,可以參考這個檔案對你的彙編**進行排錯。

C 與C DLL的互操作

c 呼叫c dll要點 1.c 自己編寫的函式必須為匯出函式.2.為把c 函式編譯為匯出函式,在函式前面加上 extern c declspec dllexport extern c 按c語言的進行編譯 declspec dllexport 表示匯出函式,另外匯入函式為 declspec dllim...

C 平台互操作大全

新增引用using system.runtime.interopservices dllimport user32.dll charset charset.unicode windows dllimport coredll.dll charset charset.unicode mobile pub...

C 互操作性

互操作性使您能夠保留和利用在現有非託管 中的投入。託管 執行在公共語言執行庫 clr 的控制之下的 非託管 執行在 clr 之外的 稱為 非託管 com com c 元件 activex 元件 和 win32 api 都是非託管 的示例。為什麼要使用互操作性呢?net 是建立在作業系統的之上的乙個開...