함수 작성 시 고려할 요소
- argument가 제대로 수행되고 값을 올바르게 반환하는지
- instruction이 순서에 맞춰 제대로 실행되는지
- caller함수의 레지스터가 내부 함수를 수행하는 동안 변조되지 않고 잘 보존되는지
새로운 프로시저를 호출할 때는 두 가지 함수를 사용한다.
1. Precedure call : jump and link
jal x1, ProcedureLabel
새로운 함수를 호출하기 전 원래 수행되던 instruction 주소를 rd에 저장한다.
2. Precedure return : jump and link register
jalr x0, 0(x1)
두 번째 오퍼랜드에서 명시한 레지스터(x1)에 저장된 주소로 돌아간다.
x0은 instruction의 주소를 나타낸다. 하지만 반환 시에는 사용되지 않는다.
caller
새로운 함수를 호출하고 파라미터를 넘겨줌, x10-x17 레지스터 이용
callee
불리는 함수
return address
함수가 반환될 때 돌아올 주소
PC(program counter)
instruction의 주소를 저장하는 레지스터
만약 callee가 사용하려는 레지스터에 이미 caller의 값이 할당되어있어서 쓸 수 없다면 어떻게 해결할까?
-> caller가 사용하던 값을 stack에 잠깐 저장한다.
기존값 저장(sw) > 레지스터 사용 > 기존값 불러오기(lw) > jalr
Stack
push와 pop으로 데이터를 옮긴다. 선입후출 방식이다.
저장 위치 기준은 sp(stack pointer)로, 예를 들어 값을 스택의 두 번째 주소에 저장하고 싶다면 8(sp)에 할당한다.
8b 마이크로프로세서라면?
8-bit -> 1byte로 생각해서 레지스터 3개를 스택에 올릴 때 sp에서 오프셋 24가 아닌 12를 빼준다.
RISC-V는 4byte기반이다.

만약 이미 쓰인 레지스터가 callee 이후 더이상 쓰이지 않는다면, 애초에 callee에서 쓸 때부터 스택에 저장할 필요가 없을 것이다. 그렇다면 추후에 다시 쓰일 값과 쓰이지 않을 값을 어떻게 구분할 수 있을까?
RISC-V에서는 효율적으로 스택을 활용하기 위해 처음부터 일시적으로 쓰이는 레지스터와 그렇지 않은 레지스터를 구별해두었다.
x5-x7, x28-x31 : temporary
x8-x9, x18-x27 : saved
callee는 레지스터 번호를 보고 보존할지 말지 결정한다.
임베디드시스템에서는 x15까지 사용하기 때문에 x15안에 saved와 temporary가 모두 있어야 한다. 하지만 대부분의 컴퓨터는 x32, x64이다. 여러 시스템에 맞춰 레지스터의 전 구간에 saved와 temporary를 배치하기 위해 연속적으로 레지스터를 정하지 않았다.