1

I would like to know how to retrieve the address of the function that called my function with inline assembly. My idea is to get the address to where the function that called mine will return and using the instruction before it (that is a call to the function that called mine) retrieving the address of the one that called mine adding to the offset given to that call, to the address of the next instruction (the address to where the function that called mine will return). So far I was able to make this but to get the address of mine. It is fairly simple and it works:

_asm
{
    mov eax, [ebp+4]
    mov returnTo,eax
}

long addressOfMine = (*((long*)(returnTo - sizeof(long)))) + returnTo)

This retrieves the address of mine just fine. (By knowing that [ebp+4] is the address to where mine will return)

To do the same but one step above I tried to get the old ebp and do the same. I saw in a site that [ebp+0] is the old ebp so I tried:

_asm
{ 
    mov eax, [ebp]
    mov ebx, [eax+4]
    mov returnTo,ebx
}

long addressOfCaller = (*((long*)(returnTo - sizeof(long)))) + returnTo)

But it doesn't work. So, my assumption is wrong or I'm doing something wrong so I would like to ask your help.

user246100
  • 670
  • 1
  • 11
  • 20
  • 2
    You know, with global, cross-function optimization there may be some really interesting problems here. If a compiler is doing cross-function CSE, the code might not strictly lie in any user-defined function. – Omnifarious Jan 31 '10 at 02:36
  • I understand that things are not always plain but the truth is that my function will return to a function and that function will return to another. So, the value that I want must be somewhere. – user246100 Jan 31 '10 at 02:38
  • If it's inlined it is no longer a function. But they aren't. – user246100 Jan 31 '10 at 02:45
  • Why are you trying to do this? I hope it's not for some misguided attempt at security: http://blogs.msdn.com/oldnewthing/archive/2004/01/01/47042.aspx – bk1e Jan 31 '10 at 02:46
  • Also, my x86 is a bit fuzzy, but isn't `[ebp+4]` exactly what you're looking for? It should be the value which was pushed onto the stack just before the function was called - that is, the return-point in the function that called you. There is no way to get the start-address of that function, though, as the "start" of a subroutine is not something that's reall well-defined in ASM. You could try passing function pointers around? – BlueRaja - Danny Pflughoeft Jan 31 '10 at 02:48
  • [ebp+4] is the address to where my function returns. So the value I retrieve in the call before it is the address of mine. I want to do this one step above. – user246100 Jan 31 '10 at 02:49
  • Oh, I understand now. No, there is no way of knowing that without knowing the size of the stack of the function which called you (which is not something you can determine at runtime). Perhaps there is a better way of solving whatever problem you are trying to solve with this - what is it you're trying to do? – BlueRaja - Danny Pflughoeft Jan 31 '10 at 02:51
  • What you said may make sense but I'm not conviced. What I want to do is "To know the address of the function that called mine" – user246100 Jan 31 '10 at 02:53
  • 3
    I understand that; but since I'm fairly certain the answer is "it can't be done," perhaps I can help you find a different solution to whatever problem it is you're trying to solve by doing this? – BlueRaja - Danny Pflughoeft Jan 31 '10 at 03:18
  • 6
    "Not your business"? That's just silly. Answering your question isn't any of our business either. We do it out of interest. Drop the attitude, please – jalf Jan 31 '10 at 04:13
  • 5
    -1 Marked your comment offensive. We aren't your bell boys to service you with programming answers. We are a group of people that happen to enjoy answering programming questions. Until you start paying us, you can't be rude like that. (even then, most people wouldn't take it.) – Earlz Jan 31 '10 at 05:10
  • Whoa. I don't care what kind of application you're trying to write, but it's easier to help someone solve their problem when you have some idea of what problem they're *really* trying to solve, not just a half-working solution to an unstated problem. For example, "I want to record/display the call stack" would get a different response than "I want to write my own stack walking function as a learning exercise". With the first question, if you step back, you can approach it an easier way: "Is there a function that will give me a stack backtrace so I don't have to write my own?" – bk1e Jan 31 '10 at 14:18
  • Nothing to do with this. The question is simple "How to get the address of the function that called mine". – user246100 Jan 31 '10 at 17:47

5 Answers5

6

Ok, so as long as you know you are doing something non-portable. You know that right?

I mean, it's not like a dozen people haven't said it already...

so. for functions on x86 (but not X64) when frame pointer omission and other optimizations aren't enabled, this should work. doesn't work for all calling conventions, but it should work for standard C/C++ calling convention.

void ** puEBP = NULL;
__asm { mov puEBP, ebp };
void * pvReturn = puEBP[1]; // this is the caller of my function

puEBP = (void**)puEBP[0];    // walk back to the previous frame
void * pvReturn2 = puEBP[1]; // this is the caller's caller

edit: Ok I'm officially confused now. I looked again at your question, and as far as I can tell, the your first code fragment is functionally the same as what I just wrote. But you say that that code gives you the address of your function - but that shouldn't be true. that code fragment should be returning the address of the caller to your function.

edit2: added code to get the caller of the caller.

By the way this code that you show in your question

long addressOfCaller = (*((long*)(returnTo - sizeof(long)))) + returnTo)

won't work. It's based on the assumption that the only way to make a call is

call symbol

where symbol is a 4 byte absolute address of a function. But thats not the only way to make a call. it's also possible to call indirect

mov eax, symbol
call [eax]

or

call [ref_symbol]

And it also possible to call relative to the current instruction

call +12

But you don't need to do this, once you know any address within the calling function, you can use the Debug Help Library to find the address of the function that called you.

In order to use DebugHelp, you must have the debug symbols for the code. then just use SymFromAddr.

John Knoeller
  • 33,512
  • 4
  • 61
  • 92
2

Why don't just use the function provided by your OS? here are a pair of links How can one grab a stack trace in C?

You may try something more complicated http://www.yosefk.com/blog/getting-the-call-stack-without-a-frame-pointer.html

But you have to be aware that in x86 mode the calling conventions are not easier, it depends on some factors like your OS, your compiler, the calling convention used, etc.

Community
  • 1
  • 1
Ismael
  • 2,995
  • 29
  • 45
1

It's not easy to do. You must know how many arguments and local variables the caller has, which in most cases, is not trivial to figure out programmatically. If you make the possibly wrong assumption that the compiler keeps EBP as the stackframe holder and never alters it(as in, this wouldn't work with -O3/2/1 probably)

inside of the called function, you could do something like

mov ecx,ebp ;save our current stack frame
pop ebp ;get the old value of EBP that was there before our function got called
mov dword [_caller_address],dword [ebp+4] ;this isn't actually a valid opcode. you figure it out. 
mov ebp,ecx ;restore old state
push ebp 

This is very unsafe though. Optimizations on the compiler will probably break it. It will only work for x86-32, and depending on OS and compiler it may not work if it follows a different calling standard.

The way it works is this:

Functions in C look something like

_Sum:
        push    ebp             ; create stack frame
        mov     ebp, esp
        mov     eax, [ebp+8]    ; grab the first argument
        mov     ecx, [ebp+12]   ; grab the second argument
        add     eax, ecx        ; sum the arguments
        pop     ebp             ; restore the base pointer
        ret

So, if say you had _SumCall it'd look somethign like

_SumCall:
        push    ebp             ; create stack frame
        mov     ebp, esp
        mov     eax, [ebp+8]    ; grab the first argument
        mov     ecx, [ebp+12]   ; grab the second argument
        push ecx ;first argument for call
        push eax ;second argument for call
        call _Sum
        pop     ebp             ; restore the base pointer
        ret

So you see, it relies on the fact that the callee is responsible for stack frame preservation.

If you try it and it doesn't work, ensure both the caller and callee have at least 1 local variable/argument. Failing that, then well, your just screwed because the compiler made some optimization that broke this assumption.

Once again. This is very unsafe and is extremely not-portable

Reference: http://courses.ece.illinois.edu/ece390/books/labmanual/c-prog-mixing.html

Earlz
  • 62,085
  • 98
  • 303
  • 499
  • It didn't work for me with -O2 and I can't discard optimizations because the library where the caller is contained is not mine. In linux it was really easy. Just one call to "int backtrace (void **buffer, int size)". In windows I guess "StackWalk64" is my solution but haven't managed to make it work yet. – user246100 Jan 31 '10 at 18:53
  • Even then it is not safe because how do you know what in the stack is a function call? What you are asking for is something that is not trivially solvable. – Earlz Feb 01 '10 at 20:25
0

I had an idea for you "unknown (google)". Retrieve the address of where your function will return to, patch that address to do "get to where it returns and call a function of yours passing you that value", return, and in your callback use the argument you receive and fix what you patched with the original values.

By the way, I'm hoping you are not using this to invade the Pentagon computers.

user246100
  • 670
  • 1
  • 11
  • 20
0

What about something a bit more straight ? *Not sure if it works on any platform/CPU:

void adr(void *x)
{
    *(void**)x = *(&x - 1); // x points to input parameter pushed before call
}

void *x;
adr(&x); // sets return adress to x
Jan
  • 2,178
  • 3
  • 14
  • 26