Machine Program
- Program Counter는 processor 내에 위치하는 레지스터로서, 다음 instruction의 byte address를 보관함.
- 보통은 다음 instruction을 찾기 위해 4 bytes를 더한다.
- 32개의 레지스터 중 일부는 symbolic register name을 갖는다. e.g.
zero
(x0), a0-a7
(x10-x17; 즉 argument registers for function calls)
- pseudo-instructions: 실제 instruction이 아니라 자주 사용되는 것을 ㅈ간단히 표현하는 것임. e.g. (move)
mv rd, rs = addi rd, rs, 0
, (load immediate) li rd, 13 = addi rd, x0, 13
, (no operation) nop = addi x0, x0, 0
Function Calls
- 함수를 부르는 절차는 다음으로 구성된다.
- argument를 준비
- transfer control to function
- acquire storage for function
- perform the task of function
- return value를 준비
- return control
- RISC-V Calling Conventions
a0-a7
(x10-x17): 8 argument registers
ra
: return address(x1
)
s0-s1
(x8-x9), s2-s11
(x18-x27): saved registers
jr
은 함수가 끝날 때 다시 ra
의 위치로 돌아오는 데 사용함. 여기서는 j
을 사용하지 않음. 왜냐하면 jump는 address의 값을 직접 넣기를 요구하는데, 함수는 그런 식으로 사용되지 않기 때문에 register를 넣을 수 있는 jr
을 사용함. e.g. jr ra
ret = jr ra
이라는 pseudo instruction으로 할 수도 있음.
jal
(jump and link): 함수로 갈 때 자주 사용되는 jump and save return address를 한번에 해준다. e.g. jal sum
- 진실: 사실은
jal
과 jalr
만 있다.
jal rd, Label
: jump and link
jalr rd, rs, imm
: jump and link register
j: jal x0, Label
jr: jalr x0, x1, 0
- function call을 하는 동안 기존의 register값들을 어딘가에 저장해 두어야 함. 이를 위해서 stack을 이용하는데, stack은 레지스터가 아닌 메모리 상에 있기 때문에 이를 point하기 위한 레지스터가 필요함.
sp
가 바로 stack pointer로 x2
에 있음. stack은 높은 주소에서 낮은 주소로 쌓이기 때문에, Push하면 sp를 감소하고, Pop하면 sp를 증가시킨다.
# prologue
addi sp, sp, -8 # stack for 2 items
sw s1, 4(sp) # save s1 for use afterwards
sw s0, 0(sp)
add s0, a0, a1
add s1, a2, a3
sub a0, s0, s1
# epilogue
lw s0, 0(sp) # restore register
lw s1, 4(sp)
addi sp, sp, 8
jr ra
Nested Calls and Register Conventions
- caller vs. callee
- register를 두 가지로 나눔
- function call 동안 계속 변하지 않고 보존되는 레지스터들:
sp, gp, tp, s0-s11(saved registers)
- 보존되지 않는 레지스터들:
a0-a7(argument registers), ra(return address), t0-t6(temporaries)
int sumSquare(int x, int y) {
return mult(x, x) + y;
}
// 위 함수에 대한 어셈블리
sumSquare:
addi sp, sp, -8 # stack pointer 이동
sw ra, 4(sp) # save return address
sw a1, 0(sp) # save y. a1 was containing y
mv a1, a0 # argument for mult(x, x). a0 contains x
jal mult # call mult
lw a1, 0(sp) # restore y
add a0, a0, a1 # mult() + y operation
lw ra, 4(sp) # get return address
addi sp, sp, 8 # restore stack pointer
jr ra
Memory
- RV32에서는 text segment(program)가 가장 low end(
0001_0000
), static data segment(constants, static variables)가 그 다음(1000_0000
), heap은 작은 데서 큰 데로 자라고, stack은 큰 데서 작은 데로 자란다.
댓글