Jan*_*zer 6 c++ x86 assembly visual-c++
我试图弄清楚如何在MSVC中获取调用方的返回地址。我可以使用_ReturnAddress()来获取函数的返回地址,但似乎找不到找到调用方的方法。
我曾尝试使用CaptureStackBackTrace,但由于某些原因,它在多次调用后崩溃。我也希望通过内联汇编解决方案。
void my_function(){
cout << "return address of caller_function: " << [GET CALLER'S RETURN VALUE];
} // imaginary return address: 0x15AF7C0
void caller_function(){
my_function();
}// imaginary return address: 0x15AFA70
Run Code Online (Sandbox Code Playgroud)
输出:
return address of caller_function: 0x15AFA70
到目前为止,我还没有运气。谢谢你的帮助
如果存在保留的调用堆栈(即在调试版本中或不存在优化时),并且考虑将MSVC x86作为目标PE,则可以执行以下操作:
// getting our own return address is easy, and should always work
// using inline asm at all forces MSVC to set up EBP as a frame pointer even with optimization enabled
// But this function might still inline into its caller
__cdecl void *get_own_retaddr()
{
// consider you can put this asm inline snippet inside the function you want to get its return address
__asm
{
MOV EAX, DWORD PTR SS:[EBP + 4]
}
// fall off the end of a non-void function after asm writes EAX:
// supported by MSVC but not clang's -fasm-blocks option
}
Run Code Online (Sandbox Code Playgroud)
在调试版本中,当在编译器上禁用优化时(MSVC编译器参数:),/Od并且不省略帧指针(MSVC编译器参数:),/Oy-对cdecl函数的函数调用将始终将返回地址保存+4在被调用方堆栈帧的偏移量处。寄存器EBP存储正在运行的函数的堆栈帧的开头。因此在上面的代码foo中将返回其调用者的返回地址。
通过再次阅读您的问题,我认为您可能需要呼叫者的返回地址。您可以通过访问直接调用者的堆栈框架,然后获取其返回地址来实现。像这样:
// only works if *the caller* was compiled in debug mode
__cdecl void *get_caller_retaddr_unsafe_debug_mode_only()
{
__asm
{
MOV ECX, DWORD PTR SS:[EBP + 0] // [EBP+0] points to caller stack frame pointer
MOV EAX, DWORD PTR SS:[ECX + 4] // get return address of the caller of the caller
}
}
Run Code Online (Sandbox Code Playgroud)
重要的是要注意,这要求调用者将EBP设置为具有传统堆栈框架布局的框架指针。这不是现代操作系统中的调用约定或ABI的一部分;堆栈展开异常使用不同的元数据。但是,如果禁用了调用方的优化功能,情况将会如此。
如Michael Petch所述,MSVC不允许在x86-64 C / C ++代码上使用asm内联构造。尽管如此,编译器允许使用一组完整的内部函数来处理该问题。