Lecture 6
Subroutines. Call stack. Calling conventions.
Lecture
Outline
- Functions, caller, callee
- Jump-and-link instructions
- Register conventions
- Stack pointer
- Stack frame
- Caller-saved and callee-saved registers
Examples
Workshop
Outline
- Demonstrate using the RISC-V toolchain in Cloud Ubuntu VM (optional)
- Demonstrate using Godbolt, show both GCC and Clang (optional)
- Practice programs that allocate variables and arrays on stack
- Practice writing programs that use functions
- Practice using caller-saved and callee-saved registers
- Practice writing nested and recursive functions
How to call a function?
Saving registers:
- The caller does not know what registers are used by the callee.
- The callee does not know what registers are used by the caller.
- Therefore, the callee is likely to overwrite registers that are important for the caller.
- To avoid this situation, a programmer must follow the calling conventions.
Register conventions:
- Callee-saved registers:
sp
,s0
-s11
- Caller-saved registers:
ra
,a0
-a7
,t0
-t6
What is done by the caller?
- Save all caller-saved registers, which must be preserved, to the stack.
- Put the arguments into registers
a0
-a7
. - Call the function.
- When the function returns, read the return values from
a0
anda1
. - Restore all the previously saved caller-saved registers from the stack.
What is done by the callee?
- Save all callee-saved registers, which will be modified, to the stack.
- Perform some operations (if the callee wants to call a function, it becomes the caller for this callee function).
- Save the result to registers
a0
anda1
. - Restore all the previously saved callee-saved registers from the stack.
- Return back to the caller.
Tasks
-
Translate the following C code into the RISC-V assembly language:
int f(int x, int y) { return 2 * x + y; } int g(int x, int y) { return 3 * y - x); } int main() { int x = read_int(); int y = read_int(); int z = f(x, y) + x + g(x, y) - y; print_int(z); }
-
Translate the following C code into the RISC-V assembly language:
int f(int x, int y) { return 2 * x + y; } int g(int a, int b, int c, int d) { return f(a, c) - f(b, d); } int main() { int a = read_int(); int b = read_int(); int c = read_int(); int d = read_int(); int x = g(a, b, c, d); print_int(x); }
-
Write program
divide.s
that inputs two positive integer valuesN
andD
, finds their quotient (Q
) and remainder (R
) using the algorithm below, and prints the result. The algorithm must be implemented as a function (the code from the previous seminar can be reused).function divide_unsigned(N, D) Q := 0; R := N while R ≥ D do Q := Q + 1 R := R − D end return (Q, R) end
-
Write program
gcd.s
that inputs two positive integer valuesa
andb
, finds their greatest common divisor using the algorithm below, and prints the result. The algorithm must be implemented as a recursive function.function gcd(a, b) if b = 0 return a else return gcd(b, a mod b)
-
Write program
fib.s
that inputs integer valuen
, computes n-th Fibonacci number using the algorithm below, and prints the result. The algorithm must be implemented as a recursive function.int fib(int n) { if (n < 2) return n; else return fib(n-1) + fib(n-2); }
-
Write program
sum.s
that first inputs integer valuen
, after that inputsn
integer elements and stores them in the stack, then calls functionsum
adding all the elements, and, finally, prints the sum.
Homework
Solve the following tasks and submit then into Ejudge:
References
- Functions in RISC-V. Section 2.8 in [CODR].
- RISC-V Calling Conventions (MIT slides)
- Call stack (Wikipedia).
- Calling convention (Wikipedia).