HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

A C function for returning the address of the calling function

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
theaddressfunctionreturningforcalling

Problem

Suppose you are given two functions, foo and bar, and neither of them are inlined. Now, if foo calls for bar and bar calls for called_from, bar receives the address of the caller, that is, the address of foo. I know that there is no real need for such computation as it is always possible to simply pass an enumeration that indicates the caller, yet I was in the mood for hacking the stack.

My code compiles on Visual Studio.

main.cpp:

#include 

/************************************************************************
* Suppose that foo() calls for bar() and bar() calls for called_from(). *
* Now if neither bar() and foo() are inlined functions, bar() receives  *
* the address of foo() from the function called_from().                 *
************************************************************************/
void* called_from() {
    __asm {
        mov eax, [ebp] 
        mov eax, [eax]     // foo's ebp
        mov eax, [eax + 4] // foo's return address
        mov edx, eax;      // we might need a copy of
                           // the foo's return address

        sub eax, 5;        // the adress of the instruction 'call foo'
        mov bl, [eax]      // the opcode of the call instruction
        inc eax            // [eax] points to the address of foo

        mov eax, [eax];    // load the caller's address

        cmp bl, 0xE8
        je RelationalAddress // the address is relational

        cmp bl, 0xFF
        je Exit              // the adress is absolute
        jmp Abort

        RelationalAddress:
        add eax, edx         // convert relational address
                             // to an abolute one
        jmp Exit

        Abort:
        mov eax, 0           // failure, return null pointer
        Exit: 
    }
}

// We need the macro as otherwise it will obscure the actual caller.
#define is_called_from(n) (called_from() == (void*) n)


Here are a few tests:

```
void foo();
void bar();
void baz();

int main() {
print

Solution

Didn't totally work

After porting the code to gnu C style, it only "sort of" worked for me. I was able to have foo() print that it was called from bar() or baz(). However, if foo() was called directly from main(), then it crashed when trying to find its caller. That's probably because on my system (Cygwin 32-bit, using Gnu C compiler), main() doesn't have a caller on the stack.
Clobbered register

It's not safe to write to ebx without pushing it on the stack and popping it off later. ebx is considered non-volatile, which means that a function must preserve its value. If you don't, then the calling function will be affected because its local variable may be stored in ebx, for example. You can safely use eax, ecx, and edx though, because they are all considered volatile registers (i.e. you are allowed to clobber them). So you should change your ebx accesses to ecx instead.
Not portable

Your asm statement assumes that the compiler will insert these lines at the top of the function:

pushl   %ebp
    movl    %esp, %ebp


That may be what your compiler does, but it's not a certainty. For example, with my GNU C compiler, it normally outputs the above code. But with the -O2 option, it does this instead:

subl    $28, %esp


If you want to make sure that you get the function prologue you need, you should write the whole thing in assembly and include the prologue/epilogue you require.

Code Snippets

pushl   %ebp
    movl    %esp, %ebp
subl    $28, %esp

Context

StackExchange Code Review Q#108769, answer score: 2

Revisions (0)

No revisions yet.