嵌入式asm代码中的运行时检查失败#0 我对汇编程序有点陌生,但是我尝试用嵌入汇编代码从代码< ESP < /Cuff>堆栈中从C++方法中查找参数。到目前为止,我甚至无法复制指向ebp的esp指针,这样我就可以控制堆栈(以防它发生变化)。即使是这段代码也让我感到失败: #include <stdlib.h> int main(int argc, char* argv[]) { __asm { mov ebp, esp } system("pause"); return 0; } #包括 int main(int argc,char*argv[]) { __asm { 电动汽车 } 系统(“暂停”); 返回0; }
运行此操作后,我得到: 运行时检查失败#0-未在函数调用中正确保存ESP的值。这通常是调用使用一个调用约定声明的函数以及使用另一个调用约定声明的函数指针的结果嵌入式asm代码中的运行时检查失败#0 我对汇编程序有点陌生,但是我尝试用嵌入汇编代码从代码< ESP < /Cuff>堆栈中从C++方法中查找参数。到目前为止,我甚至无法复制指向ebp的esp指针,这样我就可以控制堆栈(以防它发生变化)。即使是这段代码也让我感到失败: #include <stdlib.h> int main(int argc, char* argv[]) { __asm { mov ebp, esp } system("pause"); return 0; } #包括 int main(int argc,char*argv[]) { __asm { 电动汽车 } 系统(“暂停”); 返回0; },c++,visual-studio-2010,assembly,stack,stack-pointer,C++,Visual Studio 2010,Assembly,Stack,Stack Pointer,运行此操作后,我得到: 运行时检查失败#0-未在函数调用中正确保存ESP的值。这通常是调用使用一个调用约定声明的函数以及使用另一个调用约定声明的函数指针的结果 不知道该怎么办。请帮助我,并提前感谢。通常,在将ESP的值移动到EBP之前,您应该在堆栈上推送EBP的当前值EBP是32位平台上的“被调用方保存”寄存器,这意味着如果要在函数中修改它,必须先保存它 如果希望函数返回堆栈指向的位置(或函数调用后返回的位置)的值,最好执行以下操作: void* get_stack_addr() {
不知道该怎么办。请帮助我,并提前感谢。通常,在将
ESP
的值移动到EBP
之前,您应该在堆栈上推送EBP
的当前值EBP
是32位平台上的“被调用方保存”寄存器,这意味着如果要在函数中修改它,必须先保存它
如果希望函数返回堆栈指向的位置(或函数调用后返回的位置)的值,最好执行以下操作:
void* get_stack_addr()
{
void* stack_ptr = NULL;
//on 32-bit systems
//EBP is pointing at top of stack frame
//EBP + 4 is the return instruction address
//EBP + 8 is the value that was in ESP before function call for a function with no arguments
__asm__
(
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
: "=r" (stack_ptr)
);
return stack_ptr;
}
这样,EAX
现在保存了调用get\u stack\u addr()
之前堆栈指向的值的地址。如果您只是在函数中返回了ESP
的值,那么实际上您不知道您指向的是哪里,因为编译器通常在C/C++函数中填充堆栈以保持堆栈的正确对齐。它还经常在堆栈上为所有局部变量保留空间,这将再次中断堆栈的计算。通过使用位于堆栈帧顶部的EBP
,您可以在32位平台上准确计算函数调用前堆栈的值。最后,我们将返回值放在EAX
中,因为在大多数用于C/C++的操作系统应用程序二进制接口上,EAX
保存函数的返回值,而不是EBP
还有一件事。。。如果要为调用get\u stack\u addr()
的实际函数启动堆栈上的参数,请将movl%%ebp,%0\n\t
更改为movl(%%ebp),%0)\n\t
。通过这种方式,您现在可以获得上一个堆栈帧基指针(即调用方的堆栈帧基指针),并且通过向该地址添加+8的值,可以获得存储在返回地址上方的参数的开头,或者您正在查看指向当前函数调用方堆栈帧的地址(即,前一个堆栈帧)
作为增强功能,%0\n\t““leal 8(%%ebp)”可以替换:
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
此
leal
指令将EBP值加8,并将结果存储在输出操作数中。非常感谢Jason,现在我对如何实现我的解决方案有了更好的想法。再次感谢您的帮助和时间。没问题:)。。。顺便说一句,我的在线组装是针对GNUtoochain的,所以对于微软来说,会有一些语法上的差异。此外,您还应该引用Windows ABI,尤其是C++,以确保您获得堆栈地址的正确值(即,您正在从代码< EBP <代码> >正确的偏移量,这指向函数的参数的开始等)。整个函数体将是\uu asm{mov eax,ebp\n add eax,8}
。结果可以简单地留在eax
中,因为所有Windows调用约定都使用它来返回整数大小的值。您的代码实际上假设存在一个帧指针,并且返回值将通过EAX通过函数的出口传递。如果编译器选择通过内联优化函数,那么结果不一定会出现在EAX中。您使用了输出约束=r
您应该将%%eax
更改为%0
以使用GCC分配给模板的实际寄存器。从技术上讲,您的代码可以简化为leal 8(%%ebp),%0
。如果优化器消除堆栈帧,请注意%ebp
可能不是有用的值感谢@MichaelPetch为我的原始答案提供了此附录。当涉及到组装时,可能会遇到很多不同的场景。在本例中,我只是试图帮助OP完成他的基本场景,其中不包括内联、积极的编译器优化等。请随意编辑我的答案,并提供您的建议,您看到的任何其他改进都可以使其他读者受益。