Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine the return address on stack?

Tags:

c

stack

linux

gcc

I know that if I am inside some function foo() which is called somewhere from bar() function, then this return address is pushed on stack.

    #include <stdio.h>

    void foo()
    {
            unsigned int x;
            printf("inside foo %x\n", &x);
    }
    int main()
    {
            foo();
            printf("in main\n");
            return 0;
    }

In above code, I will get address of first pushed local variable on stack when foo function is active. How can I access the return address (main called foo) that is pushed somewhere before this variable on stack? Is that location fixed and can be accessed relative to first local variable? How can I modify it?

EDIT: My environment is Ubuntu 9.04 on x86 processor with gcc compiler.

like image 870
Vinit Dhatrak Avatar asked Nov 07 '09 13:11

Vinit Dhatrak


People also ask

Where is the return address stored?

If needed, this may be stored in the call stack just as the return address is. The typical call stack is used for the return address, locals, and parameters (known as a call frame).

How many bytes is return address in stack?

Secondly, if C platform keeps close ties to the underlying hardware (as is usually the case), then on platforms with flat memory model it should be fairly straightforward: 64 bit machine means 64 bit return address; 32 bit machine means 32 bit return address.

Is EIP the return address?

When a call is executed, the instruction is read from the address in EIP, EIP is incremented past the call instruction and this updated EIP (i.e. the address of the instruction after the call) is pushed onto the stack - it becomes the return address - and the function address is loaded into EIP as the next instruction ...


2 Answers

There is a gcc builtin for this: void * __builtin_return_address (unsigned int level)

See http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html

On some architectures, you can find it on the stack relative to the first parameter. On ia32, for example, the parameters are pushed (in opposite order) and then a call is made that will push the return address. Remember that the stack almost always (and on ia32) grows downward. Although technically you need the ABI or calling conventions (sometimes called linkage conventions) for your language and hardware platform, in practice you can usually guess if you know how the procedure call machine op works.

The relationship between the first parameter to a function and the position of the return address on the stack is far more likely to be a reliably fixed value than the relationship between a local and the return address. However, you can certainly print out the address of a local, and of the first parameter, and you will often find the PC right in between.

$ expand < ra.c
#include <stdio.h>

int main(int ac, char **av) {
  printf("%p\n", __builtin_return_address(0));
  return 0;
}
$ cc -Wall ra.c; ./a.out
0xb7e09775
$ 
like image 177
DigitalRoss Avatar answered Sep 27 '22 20:09

DigitalRoss


When you declare local variables, they are also on the stack - x, for instance.

If you then declare an int * xptr and initialize it to &x, it will point at x.

Nothing (much) stops you from decrementing that pointer to peek a little before, or incrementing it to look later. Somewhere around there is your return address.

like image 40
Carl Smotricz Avatar answered Sep 27 '22 19:09

Carl Smotricz