I am answering in the context of the AVR calling conventions, as they
are the only ones I know well enough to be able to answer here.
Can we use this to, for example, change what function is "calling"
FooBar() by replacing the function pointer of the calling function
on the call stack to another function?
That will probably be impossible in C++. Let's say you have the
following call chain: main() → f() → FooBar(). In the body of
FooBar(), the stack will look like this (oldest stuff at top):
return address from f() to main()
registers saved by the f() prologue
return address from FooBar() to f()
registers saved by the FooBar() prologue
Getting the stack pointer is easy. No need to declare a dummy variable,
just:
char *stack_pointer = (char *) SP;
Now, to change the required return address, you need to skip over the
registers saved by the FooBar() prologue. And this is the big problem:
you do not know how many registers were saved there. Function prologues
are written by the compiler, and whatever they save depends on how many
registers are needed within the function, which in turn depends on the
complexity of that function. Even minor changes to the function can
modify the number of registers its prologue saves.
The only solution to this problem I can imagine is to forego the
compiler-generated prologue and write FooBar() in assembly. If you
wish to do it within a C++ file, you can attach the "naked" attribute to
the function and write its body using inline assembly.
Or can we change the values of function variables in the calling
function in mischievous fashion?
No need to tamper with the stack for this. The compiler strives to store
as many local variable as possible in CPU registers rather than the
stack. The caller's local variables are most likely still in those
registers and you can modify them at will (in assembly). That's why you
have this register-saving prologue and register-restoring epilogue in
the first place. Indeed, if you make the function "naked" and don't do
the saving/restoring yourself, you will very likely end up corrupting
the caller's locals.