Interrupt control in STM32
Whenever an interrupt is triggered and the program is leaving its current work, there is some saving to do. The status bits in the status register are used for many tasks, that can be interrupted by an external/internal event. Imagine you check if a variable has reached a specific value and if this i true a conditional jump is to be made. Therefor the comparison will (potentially) set the zero bit of the status register. But if an interrupt is happening right between these two steps (comparing and jumping), the zero bit of the status register might be changed by operations in the ISR. That's why your mircoprocessor has a stack to save the statusregister with a push operation before entering an ISR and restoring it with pull after leaving the ISR. That way it is ensured, that an ISR will not break you program.
Also the processor has to save the current position in the code, the program counter. After finishing the ISR the program counter can be set back to the stored value for the program to continue.
When an exception (interrupt) happens the context of what the core is doing at that moment needs to be pushed on stack, so it is possible to return to it later. This is done by a stackframe.
For an exception a stackframe looks like this:
Registers R4 to R11 are not pushed to stack unless the exception code needs them. The compiler may push/pop these registers if required. Above is the minimum amount of registers pushed by hardware, to keep things quick.
When the exception is finished, the hardware reverses the stackframe and restores the context to continue execution.
The processor can skip returning the stackframe if another interrupt is still pending. This is called tail-chaining.
More info about the Exception Model of the Cortex M0 can be found in the ARM docs.