我对汇编程序有点新意,但我正在尝试使用嵌入式汇编代码从esp
堆栈中的C ++方法查找参数。到目前为止,我甚至无法将esp
指针复制到ebp
,因此我可以在堆栈上保留(如果它发生更改)。即便是这一小段代码也让我失败了:
#include <stdlib.h>
int main(int argc, char* argv[])
{
__asm
{
mov ebp, esp
}
system("pause");
return 0;
}
在我运行之后,我得到:
运行时检查失败#0 - ESP的值未在函数调用中正确保存。这通常是调用使用一个调用约定声明的函数的结果,函数指针使用不同的调用约定声明。
不知道该怎么做。请帮助我,并提前感谢。
答案 0 :(得分:2)
一般情况下,在将EBP
的值移至ESP
之前,您应该在堆栈上推送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_stack_addr()
之前保存堆栈指向的值的地址。如果你刚刚在函数中返回ESP
的值,你实际上不知道你指向的位置,因为编译器经常在C / C ++函数中填充堆栈以保持正确的堆栈对齐。它还经常在堆栈上为所有局部变量保留空间,这将再次甩掉堆栈的计算。通过使用指向堆栈框架顶部的EBP
,您可以在32位平台上准确计算函数调用之前的堆栈值。最后,我们将返回值放在EAX
中,因为在C / C ++的大多数OS应用程序二进制接口上,EAX
保存函数的返回值,而不是EBP
。
还有一件事......如果您想要在堆栈上为调用get_stack_addr()
的实际函数启动参数,请将movl %%ebp, %0\n\t
更改为movl (%%ebp), %0)\n\t
。这样你现在可以获得前一个堆栈帧基指针(即调用者的堆栈帧基指针),并通过向该地址添加+8值,您可以获得存储的参数的开头在返回地址之上,或者您正在查看指向当前函数调用者(即前一个堆栈帧)的堆栈帧的地址。
作为增强版"leal 8(%%ebp), %0\n\t"
可以取代:
"movl %%ebp, %0\n\t"
"addl $8, %0\n\t"
此leal
指令将 EBP 的值加8,并将结果存储在输出操作数中。