[英]x64 asm how to set a function pointer to a _cdecl C function and call it?
我正在嘗試在x64 asm中做一些非常基本的事情:
有一個使用函數指針並將其設置在變量中的asm函數。 此函數從C代碼中調用。
還有另一個asm函數,如果不為null,它將調用函數指針,該函數指針也是C函數(由1中的函數設置)。
到目前為止,這是我對C方面的了解:
extern "C" void _asm_set_func_ptr(void* ptr);
void _cdecl c_call_back()
{
}
void init()
{
_asm_set_func_ptr(c_call_back);
}
和asm方面:
.DATA
g_pFuncPtr QWORD 0
.CODE ;Indicates the start of a code segment.
_asm_set_func_ptr PROC fPtr:QWORD
mov [rsp+qword ptr 8], rcx
mov rax, [rsp+qword ptr 8]
mov g_pFuncPtr, rax
ret
_asm_set_func_ptr ENDP
_asm_func PROC
push RBX
push RBP
push RDI
push RSI
push RSP
push R12
push R13
push R14
push R15
CMP g_pFuncPtr, 0
JE SkipCall
MOV RAX, [ g_pFuncPtr ];
CALL RAX;
SkipCall:
pop RBX
pop RBP
pop RDI
pop RSI
pop RSP
pop R12
pop R13
pop R14
pop R15
ret
_asm_func ENDP
但是似乎我在調用_asm_set_func_ptr()之后損壞了堆棧,也不確定在_asm_func中如何調用g_pFuncPtr是否正確? 我的代碼有什么問題? 我正在使用VS2013 MASM64構建它。
首先,通常需要按相反的順序彈出寄存器,即:
push RBX
, push RBP
... push R15
> pop R15
... pop RSI
, pop RBX
, ret
。 這肯定會破壞_asm_func
的調用者。
接下來,您應該查看Windows x64調用約定 ,進行正確的函數調用需要做些什么。 正確滿足所有需求是非常重要的,否則在某些其他代碼中事情可能會中斷甚至到很晚,這並不是調試的最大事情。
例如,您不需要保存所有寄存器。 如果回調函數銷毀了它們,它將保存並恢復它們本身。 因此,在那里沒有必要進行推送和彈出操作,無論如何, RAX
都可以無效,也無需傳遞任何參數。
但是請注意這一部分:
在Microsoft x64調用約定中,調用者有責任在調用函數之前(無論使用的實際參數數如何)在堆棧上分配32個字節的“影子空間”,並在調用后彈出堆棧。
因此,您應該在代碼之前執行SUB ESP, 32
,然后在RET
之前執行ADD ESP, 32
。
還要求“ 堆棧對齊16個字節 ”,但是您當前不需要解決這個問題,因為“ 8個返回地址+ 32個字節的影子空間+ 8個下一個返回地址”是按16個對齊的字節。
此外,Windows x64 ABI對異常處理和正確展開也有嚴格的要求。 正如Raymond在評論中指出的那樣,由於您的函數不是葉子函數(調用其他函數),因此您需要提供適當的序言和結尾-參見此處 。
不需要在_asm_set_func_ptr
的開頭臨時保存RCX
。
否則,我在那里看不到任何問題。
最后是分號;
匯編文件中的行尾不需要。
在檢查g_pFuncPtr之前,您要推入很多寄存器,但是,如果未設置它們,則不會將它們彈出堆棧。 如果您將某些東西推入堆棧,然后不撥打電話也不將其彈出,則您的堆棧將很快填滿。
您必須以與推送相反的順序彈出寄存器,否則您將取回錯誤的寄存器。
最后,除非您與它們有任何關系,否則不要浪費時間和CPU周期來推動它們:
CMP g_pFuncPtr, 0
JE SkipCall
PUSH RBX
PUSH RBP
PUSH RDI
PUSH RSI
PUSH RSP
PUSH R12
PUSH R13
PUSH R14
PUSH R15
MOV RAX, [ g_pFuncPtr ];
CALL RAX;
POP R15
POP R14
POP R13
POP R12
POP RSP
POP RSI
POP RDI
POP RBP
POP RBX
SkipCall:
ret
...而且請-請...請仔細閱讀如何設置堆棧框架以及如何在調用中管理堆棧框架。 C調用和ASM調用對堆棧幀的處理彼此非常不同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.