我想在我的示踪剂中打印返回值,有两个问题
此处需要文字,因此Stackoverflow格式化代码:
struct Tracer
{
int* _retval;
~Tracer()
{ printf("return value is %d", *_retval); }
};
int foo()
{
Tracer __tracter = { __Question_1_how_to_get_return_address_here__ };
if(cond) {
return 0;
} else {
return 99;
}
//Question-2:
// return postion is updated before OR after ~Tracer() called ???
}
答案 0 :(得分:3)
您无法在C ++中移植或可靠地执行此操作。返回值可能在内存中或寄存器中,在不同情况下可能会或可能不会出现。
你可以使用内联汇编来使某些东西在某些硬件/编译器上运行。
一种可能的方法是让你的Tracer
模板引用一个返回值变量(在适当的时候)并在破坏之前输出 。
另请注意,__
(双下划线)的标识符是为实现保留的。
答案 1 :(得分:3)
我找到了问题1的一些提示,现在检查Vc代码
对于gcc,__ builtin_return_address http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html
对于Visual C ++,_ ReturnAddress
答案 2 :(得分:1)
您的问题相当混乱,您可以互换使用术语“地址”和“值”,这两个术语不能互换。
函数x86(_64)中返回值是函数吐出的值,在E / RAX或EDX:EAX或XMM0等中以4/8字节值的形式出现,您可以阅读有关它的更多信息here。
另一方面,返回地址是E / RSP在调用时指向的地址(又称堆栈顶部的内容),并保存函数完成时“跳回”位置的地址(什么按照定义称为返回)。
现在,我什至不知道什么是示踪剂,但是我可以告诉您如何获取示踪剂,这全都与钩子有关。
对于值,并假设您在内部进行操作,只需将函数与具有相同定义的函数挂钩,然后返回该值即可。
对于地址来说,它有点复杂,因为您必须降低位置,并可能要进行一些asm修改,我真的不知道您要完成什么,但是我做了一个“存根”如果可以的话,向被调用方提供返回指针。
这里是:
void __declspec(noinline) __declspec(naked) __stdcall _replaceFirstArgWithRetPtrAndJump_() {
__asm { //let's call the function we jump to "callee", and the function that called us "caller"
push ebp //save ebp, ESP IS NOW -4
mov ebp, [esp + 4] //save return address
mov eax, [esp + 8] //get callee's address (which is the first param) - eax is volatile so iz fine
mov[esp + 8], ebp //put the return address where the callee's address was (to the callee, it will be the caller)
pop ebp //restore ebp
jmp eax //jump to callee
} }
#define CallFunc_RetPtr(Function, ...) ((decltype(&Function))_replaceFirstArgWithRetPtrAndJump_)(Function, __VA_ARGS__)
unsigned __declspec(noinline) __stdcall printCaller(void* caller, unsigned param1, unsigned param2) {
printf("I'm printCaller, Called By %p; Param1: %u, Param2: %u\n", caller, param1, param2);
return 20;
}
void __declspec(noinline) doshit() {
printf("us: %p\nFunction we're calling: %p\n", doshit, printCaller);
CallFunc_RetPtr(printCaller, 69, 420);
}
现在确定,您可以并且可能应该使用_ReturnAddress()或任何其他编译器的内部函数,但是如果不可用(根据您的工作,这应该是一种非常罕见的情况),并且您知道您的ASM,则此概念应适用任何架构,由于指令集可能不同,因此它们都遵循相同的程序计数器设计。
我写这封信的原因更多,是因为我很久以前一直在为某个目的寻找答案,而我找不到很好的答案,因为大多数人只会说“这是不可能的,无法携带的或其他任何东西” ”,我觉得这会有所帮助。