You are on page 1of 4

page 1 of 4

ENCM 369 Winter 2017: The Stack Handout


Page 1 of this handout shows where the stack fits within the MARS address space organization. Pages 24
have code examples showing how the stack is used to help procedures work.
This handout is designed to support multiple lectures! Please keep bringing this handout to lectures
until all of the code examples have been discussed.

Memory map for MARS programs:


0xfffffffc
reserved for
use by operating
system kernel Remarks:

0x80000000 The stack grows downward in address


0x7ffffffc space while the data segment grows up-
Stack
ward in address space.
$sp
room for growth Some MIPS assemblers allow program-
of stack and/or mers to use the small data area for fre-
data segment quently accessed global variables. A trick
involving $gp (GPR 28) allows programs
Data address depends on size of data segment to have slightly faster access to the small
segment data area than to other parts of the data
0x10000000 segment. MARS is somewhat weird re-
unused space garding the small data area: the simula-
tor reserves this area and initializes $gp
Text address depends on size of text segment
to point into it, but the MARS assembler
Segment 0x00400000 makes it quite difficult to allocate and ini-
reserved for 0x003ffffc
tialize data in the small data area. So
O/S kernel in ENCM 369, all static data in MARS
0x00000000
will be in the area starting with address
0x1001_0000.
Details of the data segment:
address depends on size of static data Memory organizations for programs run-
plus size of dynamically allocated data ning on real 32-bit operating systems and
Free store
or real hardwaree.g., 32-bit versions of
heap Linux, Microsoft Windows, or Mac OS X
on x86are similar but details will vary.

The same concepts apply for programs


address depends on size of static data running on 64-bit versions of Linux, Mi-
Static data crosoft Windows, and Mac OS X, but the
addresses are 64 bits wide instead of 32.
0x10010000
0x1000fffc
Small data
0x10000000
ENCM 369 Winter 2017: The Stack Handout page 2 of 4

a-register conflict example number 1


This page shows code to illustrate one of two methods to separate incoming arguments from outgoing
arguments in nonleaf procedures. This page has only code; explanation for the design of the assembly-
language code will be provided in a lecture.
Some C code:

int bob(int i);


int fred(int j, int k)
{
int x;
x = bob(k + 10);
return k - j - x;
}

Translation of fred, with incoming arguments copied to s-registers:

.text
.globl fred
fred:
# prologue
addi $sp, $sp, -16
sw $ra, 12($sp) # save $ra for return to caller
sw $s2, 8($sp) # save $s2 for some other procedure
sw $s1, 4($sp) # save $s1 for some other procedure
sw $s0, 0($sp) # save $s0 for some other procedure
add $s0, $a0, $zero # copy j from $a0 to $s0
add $s1, $a1, $zero # copy k from $a1 to $s1

# body
addi $a0, $s1, 10 # $a0 = k + 10
jal bob
add $s2, $v0, $zero # x = r.v. from bob
sub $t0, $s1, $s0 # $t0 = k - j
sub $v0, $t0, $s2 # r.v. = k - j - x

# epilogue
lw $s0, 0($sp) # recover old value of $s0
lw $s1, 4($sp) # recover old value of $s1
lw $s2, 8($sp) # recover old value of $s2
lw $ra, 12($sp) # copy backed-up $ra for correct return
addi $sp, $sp, 16
jr $ra

Note: Copying incoming arguments to s-registers is one one of two effective methods for resolving the con-
flict between incoming and outgoing arguments. The other method involves copying incoming arguments
to stack slots; this method is shown on the next page.
ENCM 369 Winter 2017: The Stack Handout page 3 of 4

a-register conflict example number 2


This page shows code to illustrate the second of two methods to separate incoming arguments from outgoing
arguments in nonleaf procedures. As with the previous example, explanation for the design of the assembly-
language code will be provided in a lecture.
The same C code as before:

int bob(int i);


int fred(int j, int k)
{
int x;
x = bob(k + 10);
return k - j - x;
}

Translation of fred, with incoming arguments copied to the stack:

.text
.globl fred
fred:
# prologue
addi $sp, $sp, -16
sw $a1, 12($sp) # copy k to stack slot at 12($sp)
sw $a0, 8($sp) # copy j to stack slot at 8($sp)
sw $ra, 4($sp) # save $ra for return to caller
sw $s0, 0($sp) # save $s0 for some other procedure

# body
# Before calling bob, we can safely get k from $a1. But after
# calling bob, we must get j and k from stack slots.
addi $a0, $a1, 10 # $a0 = k + 10
jal bob
add $s0, $v0, $zero # x = r.v. from bob
lw $t0, 12($sp) # $t0 = k
lw $t1, 8($sp) # $t1 = j
sub $t2, $t0, $t1 # $t2 = k - j
sub $v0, $t2, $s0 # r.v. = k - j - x

# epilogue
lw $s0, 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 16
jr $ra
ENCM 369 Winter 2017: The Stack Handout page 4 of 4

Examples of local variables on the stack


Below are a C program, with a function called test_negatives needing local variables on the stack,
and an assembly language translation of test_negatives.
The function test_negatives is a test harness for the function negatives.

void negatives(const int *arr, int n, test_negatives:


int *pcount, int *psum) # prologue
// Updates *pcount with count of negative addi $sp, $sp, -32
// values in arr[0] ... arr[n - 1]. sw $ra, 28($sp)
// Updates *psum with sum of negative
// values in arr[0] ... arr[n - 1]. # body
{ # Initialize x. (Instead of the following
*pcount = 0; # ten instructions, a real C compiler
*psum = 0; # might generate a static array and a
while (n > 0) { # loop to copy the array to the stack.)
if (*arr < 0) { addi $t0, $zero, 10
(*pcount)++; sw $t0, 8($sp) # x[0]
*psum += *arr; addi $t0, $zero, -20
} sw $t0, 12($sp)
n--; addi $t0, $zero, 30
arr++; sw $t0, 16($sp)
} addi $t0, $zero, -40
return; sw $t0, 20($sp)
} addi $t0, $zero, 50
sw $t0, 24($sp) # x[4]
void test_negatives(void)
{ addi $a0, $sp, 8 # $a0 = &x[0]
int count, sum, x[ ] = addi $a1, $zero, 5 # $a1 = 5
{ 10, -20, 30, -40, 50 }; addi $a2, $sp, 0 # $a2 = &count
negatives(x, 5, &count, &sum); addi $a3, $sp, 4 # $a3 = &sum
jal negatives
// Could a set a breakpoint here to
// check that count == 2 and sum == -60. # Could set a breakpoint on the lw
return; # instruction to see what is in count
} # and sum.

int main(void) # epilogue


{ lw $ra, 28($sp)
test_negatives(); addi $sp, $sp, 32
return 0; jr $ra
}

You might also like