MIPS Functions

MIPS Functions

The Stack

Suppose you have a program as follows:

C
int f(int);
int g(int);
int h(int);

int main(void) {
	int n,m;
	n = 5;
	m = f(n);
	return 0;
}

int f(int x) {
	return g(x);
}

int g(int y) {
	int r = 4 * h(y);
	return r;
}

int h(int z) {
	int i;
	int p = 1;
	for (i = 1; i < z; i++) {
		p = p * i;
	}
	
	return p;
}

Since this program performs no dynamic allocation with functions such as malloc, it makes no explicit use of the heap. Instead, much of the transient state associated with each active function call can be represented on the stack. Each invocation is associated with a region of stack memory known as a stack frame.

Stack frames

A stack frame contains the information required for a particular invocation of a function. Depending on the architecture and compiler, this can include local variables, function parameters and other information required to return to the calling function.

As we progress from main() to h(), the state of the stack can be roughly represented as follows:

Once a function completes and returns to its caller, its stack frame is no longer required and its space can be reclaimed. The frames are therefore removed in the reverse order from which they were created:

Infinite Recursion

Since the stack is finite, it is obvious that we can only accumulate so many function calls before exhausting the available stack space, and end up with a stack overflow. One straightforward way this can occur is through unbounded recursion. Recursion is when a function directly (or indirectly) calls itself;

C
void f(int x) {
	printf("%d\n", x);
	f(x + 1);
}

Here, every invocation of f() creates another invocation before the previous one has returned: