Why isn't the stack pointer changing in this simple sketch?
Another way the compiler can optimize is to compile small or single-use functions inline. What you expected would get wrapped inside a call and return sequence, may not. 

Inserting __attribute__ ((noinline)) ahead of the function definition can suppress that optimization:

__attribute__ ((noinline)) void foo(int bar)
{
   // do something
}


suppresses the inlining for function foo(). Inlining has frustrated my investigations more than once, so I created this easier to remember macro. (The keyword is just __NOINLINE; the #else-clause is there so that, umm, "someone", doesn't unwittingly try to use the "__attribute..." declarator with another compiler that doesn't recognize it).

// Don't compile this function inline
//   '__NOINLINE void foo(void){ ... }'
#ifdef __GNUC__
#define __NOINLINE  __attribute__ ((noinline))
#else
#define NOINLINE error 'NOINLINE' not defined for this compiler
#endif