我有一些 C 代碼,我想將它移植到 C ,問題是在 C 中我不能使用匯編函式,因為它是動態使用的
C版
extern asmFunc(); // C function prototype version
//actual use example
asmFunc(var1,ptr2,HANDLE);
asmFunc(ptr4,var2,NULL,eg ...); //everything works
C 版本
extern "C" VOID asmFunc(); // C function prototype version
//actual use example
asmFunc(var1,ptr2,HANDLE); // E0140 too many arguments in function call
asmFunc(ptr4,var2,NULL,eg ...); // E0140 too many arguments in function call
匯編函式在單獨的 asm 檔案中宣告,它使用來自 ntdll.dll 函式的直接系統呼叫,這就是它需要動態引數的原因
如何讓它發揮作用?
uj5u.com熱心網友回復:
在引數串列中使用...來指定函式是采用未指定引數的可變引數函式,例如:
extern "C" VOID asmFunc(...); // C function prototype version
//actual use example
asmFUNC(var1,ptr2,HANDLE);
asmFUNC(ptr4,var2,NULL,eg);
uj5u.com熱心網友回復:
同一個地址可以有多個標簽。 您可以有多個具有不同名稱的原型,它們都恰好具有相同的地址(因此由相同的機器代碼實作)。在您的.asm檔案中,您輸入:
global foo_int, foo_long, foo_float ; NASM syntax for putting these in the symbol table
foo_int:
foo_long:
foo_float:
your code goes here
ret
您也可以使用匯編指令來為符號創建別名,例如 GAS .set foo_long, foo。
您可以將其視為同一函式的多個名稱,或者將其實作為真正的函式的其他函式,作為優化的尾呼叫,您甚至可以jmp通過使它們在 asm 中連續來優化它們。
或者使用GNU 擴展,宣告多個 C 或 C 名稱,它們都使用相同的 asm 符號名稱。編譯器生成.obj的每個呼叫點都會參考相同的符號名稱。(您完全手動設定,所以即使extern "C"沒有名稱修改和前導下劃線,除非您選擇一個。)
// GNU C or C ; compatible with the mainstream compilers other than MSVC
int foo_int(...) asm ("foo");
long foo_long(...) asm ("foo");
float foo_float(...) asm ("foo");
使用 clang 和 GCC在 Godbolt 上查看它,注意return foo_float('a', 1);在 C 源代碼中編譯為call foo編譯器生成的 asm 中的 a。(Godbolt 可以正常為 Linux 編譯,但我曾經-mabi=ms讓 GCC 使用 Windows x64 呼叫約定。)
如果這是在一個單獨的 DLL 中,每個名稱將被單獨決議,為多個 DLL 匯入條目浪費一點空間(無論 Windows 呼叫什么函式指標,都相當于 Linux 動態鏈接中的 GOT。)GNU Casm("name")方式沒有沒有這個缺點,因為只有一個 asm 符號名稱。
但是,如果您只是將此.asm檔案鏈接到與 C 呼叫者相同的可執行檔案或庫中,則單獨的符號表條目會在構建時得到決議并消失,而不是每次運行時。
您可以為每個不同的函式簽名提供一個完整的原型(和名稱)。
或者,您可以為每種不同的回傳型別命名,如 Remy
的extern "C" int foo_int(...);回答所示。請注意,這(...)將觸發默認引數提升,例如float將提升到double,因此不可能傳遞實際的float. (這就是為什么printf's "%f" 轉換需要雙倍的原因。)
促銷是無害的,并且對于整數來說非常便宜,不過,只是符號或零擴展為int. 主流的 x86 和 x86-64 呼叫約定被設計成將 args 傳遞給可變引數函式,就像它們傳遞給具有相同 arg 型別的原型函式一樣(在將 float 提升為 double 之后)。x86-64 System V 要求可變引數函式的呼叫者設定 AL = # of XMM args,一個從 0 到 8 的數字;沒有任何 FP 或向量引數,這意味著每個呼叫站點將獲得一個額外的xor eax,eax. 這與 2 位元組 NOP 一樣便宜,尤其是在 Intel 上。
假設回傳型別對于任何給定的呼叫站點都是靜態已知的,這應該可以解決您的整個問題。如果沒有,那就更麻煩了!
union回傳 a并在運行時決定使用哪個回傳值不一定有效。一些呼叫約定會float在不同的暫存器(例如 xmm0)中回傳一個 pure,而不是為與float成員的聯合選擇。即使對于純整數, anint和更大的結構的聯合也會在記憶體中回傳,這與普通的 不同int。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/509971.html
標籤:C C视窗部件温纳皮
下一篇:如何使用更改名稱的變數地址
