简体   繁体   English

如何获取函数内的函数返回地址?

[英]How to get function return address within function?

I want to print return value in my tracer, there are two questions 我想在我的示踪剂中打印返回值,有两个问题

  1. How to get return address ? 如何获得退货地址?
  2. The return position is updated before OR after ~Tracer() ? 返回位置在~Tracer()之后的OR之前更新?

Need text here so Stackoverflow formats the code: 这里需要文本,所以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 ???
}

You can't portably or reliably do this in C++. 您无法在C ++中移植或可靠地执行此操作。 The return value may be in memory or in a register and may or may not be indirected in different cases. 返回值可以在存储器中或寄存器中,并且在不同情况下可以或可以不在间接。

You could probably use inline assembly to make something work on certain hardware/compilers. 您可以使用内联汇编来使某些东西在某些硬件/编译器上运行。

One possible way is to make your Tracer a template that takes a reference to a return value variable (when appropriate) and prints that out before destructing. 一种可能的方式是让你的Tracer的模板花费的返回值变量(适当的时候),并打印出破坏前的参考。

Also note that identifiers with __ (double underscore) are reserved for the implementation. 另请注意,带有__ (双下划线)的标识符保留用于实现。

I found some hints for Question-1, checking Vc code now 我找到了问题1的一些提示,现在检查Vc代码

For gcc, __builtin_return_address http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html 对于gcc,__ builtin_return_address http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html

For Visual C++, _ReturnAddress 对于Visual C ++,_ ReturnAddress

Your question is rather confusing, you're interchangeably using the terms "address" and "value", which are not interchangeable. 你的问题相当令人困惑,你可以互换使用“地址”和“价值”这两个不可互换的术语。

Return value is what the function spits out, in x86(_64) that comes in the form of a 4/8 byte value in E/RAX, or EDX:EAX, or XMM0, etc, you can read more about it here . 返回值是函数吐出的函数,在x86(_64)中,在E / RAX或EDX:EAX或XMM0等中以4/8字节值的形式出现,您可以在此处阅读更多相关信息。

Return address on the other hand, is what E/RSP point to when a call is made (aka thing on top of the stack), and holds the address of where the function "jumps" back to when it's done (what is by definition called returning). 另一方面,返回地址是E / RSP在进行调用时指向的(也就是堆栈顶部的东西),并且保存了函数“跳转”到其完成时的地址(根据定义)叫回归)。

Now I don't even know what a tracer is tbh, but I can tell you how you'd get either, it's all about hooks. 现在我甚至不知道什么是跟踪器,但是我可以告诉你如何得到它,这都是关于钩子的。

For the value, and assuming you're doing it internally, just hook the function with one with the same definition, and once it returns you'll have your result. 对于值,假设你在内部执行它,只需将函数与具有相同定义的函数挂钩,一旦它返回,你就会得到你的结果。

For the address it's a bit more complicated because you'll have to go a bit lower, and possibly do some asm shenanigains, I really have no idea what exactly you are looking to acomplish, but I made a little "stub" if you will, to provide the callee with the return pointer. 对于地址而言,它有点复杂,因为你必须降低一些,并且可能做一些asm shenanigains,我真的不知道你究竟想要什么,但是如果你愿意,我会做一点“存根” ,为被调用者提供返回指针。

Here is: 这是:

 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);  
}

Now sure, you could and maybe should use _ReturnAddress() or any different compiler's intrinsics, but if that's not available (which should be a really rare scenario depending on your work) and you know your ASM, this concept should work for any architecture, since however different the instruction set may be, they all follow the same Program Counter design. 现在可以肯定,你可以并且可能应该使用_ReturnAddress()或任何不同的编译器的内在函数,但是如果它不可用(这应该是一个非常罕见的场景,取决于你的工作)并且你知道你的ASM,这个概念应该适用于任何架构,但是,由于指令集可能不同,它们都遵循相同的程序计数器设计。

I wrote this more because I was looking for an answer for this quite a long time ago for a certain purpose, and I couldn't find a good one since most people just go "hurr durr it's not possible or portable or whatever", and I feel like this would have helped. 我之所以写这个是因为我很久以前为了某个目的而寻找答案,而且我找不到一个好的答案,因为大多数人只是“匆匆而去,它不可能或便携或其他什么”,以及我觉得这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM