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.
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.