[英]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.