Lecture 02 - Memory, Stack and Function Calls

Course: Computer Architectures

Topics

Address vs value

A label names a memory location.

Example:

Val_A: .word 10

Keep these separate:

Val_A             = address
memory[Val_A]     = stored value

Load address

la x1, Val_A

puts the address of Val_A into x1.

Load word

lw x1, 0(x1)

loads the word stored at address:

x1 + 0

Store word

sw x3, 0(x4)

stores the value from x3 at:

x4 + 0

Why offset(base)?

RISC-V loads and stores use:

offset(base_register)

This is useful for arrays.

Example:

lw x5, 0(x1)
lw x6, 4(x1)
lw x7, 8(x1)

With 4-byte words, these can access consecutive elements.

Walking through arrays

If x1 points at the current word:

addi x1, x1, 4

moves the pointer to the next word.

That is why vector code often advances several pointers by 4 each iteration.

Function calls

ra is the ABI name for:

x1

A function call commonly saves the address to return to in ra.

Example:

jal ra, function

call function is a convenient pseudo-instruction for calling a subroutine.

Returning

ret

returns using the address stored in ra.

Why save ra?

If function A calls function B, B’s call will use ra too.

So A must preserve its own return address if it needs it afterward.

Simplified example:

funcA:
    addi sp, sp, -4
    sw   ra, 0(sp)
 
    call funcB
 
    lw   ra, 0(sp)
    addi sp, sp, 4
    ret

Stack idea

The stack grows by moving sp to a new memory location before saving data.

Example:

initial sp = 1000
A saves at 996
B saves at 992
C saves at 988

This prevents nested calls from overwriting each other’s saved return addresses.

The stack is LIFO:

main -> A -> B -> C
C -> B -> A -> main

Questions to review

  • What is the difference between la and lw?
  • Why is 0(x1) not redundant?
  • Why does an array pointer increase by 4 for .word data?
  • Why must a non-leaf function preserve ra?