본문 바로가기

Background

x18-x27 (callee-saved) register

x18에서 x27 레지스터는 RISC-V 아키텍처에서 **저장된 레지스터(Saved Registers)**로 사용되며, 각각 **s2**부터 **s11**이라는 이름을 갖습니다. 이 레지스터들은 함수 호출 시 값이 보존되는(callee-saved) 레지스터들로, 함수가 호출되는 동안 중요한 데이터를 안전하게 유지하기 위해 설계되었습니다. 이는 함수가 중첩되거나 재귀적으로 호출될 때 데이터의 일관성을 보장하며, 함수 내에서 장기적인 데이터를 저장하고 사용할 수 있도록 합니다.

x18 (s2) ~ x27 (s11) 레지스터의 주요 역할과 사용 이유

  1. 중요한 데이터 보존:
    • s2 (x18)부터 s11 (x27)까지의 레지스터는 함수가 자신의 실행 중에 중요한 데이터를 저장하는 데 사용됩니다. 예를 들어, 반복적으로 사용하는 변수, 일정한 값을 유지해야 하는 상수, 또는 함수 간에 공유해야 하는 중요한 정보 등을 저장할 때 이들 레지스터가 사용됩니다.
    • 함수가 호출되더라도 이들 레지스터의 값이 보존되므로, 함수 호출 사이에서도 데이터를 안정적으로 유지할 수 있습니다.
  2. callee-saved 레지스터:
    • s2부터 s11까지의 레지스터는 callee-saved로, 호출된 함수(callee)가 이들 레지스터의 값을 관리하고 보존해야 합니다. 함수가 시작될 때 이 레지스터들의 현재 값을 스택에 저장하고, 함수가 종료될 때 스택에서 복원합니다.
    • 이러한 관리 방식 덕분에, 함수가 중첩되거나 다른 함수가 호출되더라도, 호출된 함수는 자신이 필요한 데이터를 안전하게 사용하고, 호출된 후에도 이전 상태가 유지됩니다.
  3. 연산 및 데이터 저장:
    • 이 레지스터들은 함수 내에서 연산 결과를 저장하거나, 함수가 여러 번 호출되면서 필요한 데이터를 유지하는 데 유용합니다. 예를 들어, 반복문에서 사용되는 값이나, 함수 호출 전후에 필요한 데이터가 저장될 수 있습니다.
    • 또한, 복잡한 연산을 수행하는 함수에서 이들 레지스터를 사용하여 여러 중간 결과를 저장하고, 이후에 이를 다시 활용할 수 있습니다.

x18 - x27 사용 예시

다음은 s2 (x18)부터 s11 (x27) 레지스터가 함수 호출 전후의 데이터 보존 및 사용되는 예시입니다:

  • 데이터 보존을 위한 스택 사용
addi sp, sp, -40        # 스택 포인터 감소 (10개의 레지스터 공간 확보)
sw x18, 0(sp)           # s2 (x18)의 값을 스택에 저장
sw x19, 4(sp)           # s3 (x19)의 값을 스택에 저장
sw x20, 8(sp)           # s4 (x20)의 값을 스택에 저장
# ...
sw x27, 36(sp)          # s11 (x27)의 값을 스택에 저장

# 함수 연산 수행 (s2 ~ s11 레지스터 사용 가능)

lw x18, 0(sp)           # s2 (x18)의 값을 스택에서 복원
lw x19, 4(sp)           # s3 (x19)의 값을 스택에서 복원
lw x20, 8(sp)           # s4 (x20)의 값을 스택에서 복원
# ...
lw x27, 36(sp)          # s11 (x27)의 값을 스택에서 복원
addi sp, sp, 40         # 스택 포인터 복원

이 예시에서 함수는 s2부터 s11까지의 레지스터를 스택에 저장하고, 함수가 종료되기 전에 스택에서 원래 값을 복원합니다. 이를 통해 함수가 호출되기 전의 상태를 그대로 유지할 수 있습니다.

  • 함수 내에서의 반복적 사용
my_function:
    addi x18, x0, 100   # s2 (x18)에 상수 100 저장
    addi x19, x0, 0     # s3 (x19)에 초기값 0 저장

loop:
    add x19, x19, x18   # s3에 s2 값을 더함 (반복 연산)
    blt x19, x0, loop   # 조건에 따라 반복

    ret

이 예시에서 함수는 s2 (x18)와 s3 (x19)를 반복 연산에서 사용합니다. s2에 상수를 저장하고, s3에 초기값을 설정한 후, 반복문을 통해 연산을 수행합니다. 이들 레지스터는 함수가 종료될 때까지 값을 유지하므로 안정적으로 사용될 수 있습니다.

callee-saved 레지스터 관리

  • s2 (x18)부터 s11 (x27) 레지스터는 callee-saved 레지스터이므로, 함수가 시작될 때 스택에 값을 저장하고, 함수가 종료될 때 복원하는 작업이 필수적입니다. 이는 함수가 다른 함수를 호출하더라도 이전 함수의 상태를 보존하여, 호출 구조가 중첩되거나 재귀적으로 호출되더라도 데이터의 일관성을 보장합니다.
  • 이러한 관리 방식은 컴파일러가 자동으로 처리하며, 개발자는 이들 레지스터를 안전하게 사용할 수 있습니다.

x18-x27의 설계 철학

x18에서 x27까지의 레지스터는 RISC-V의 안정성과 일관성을 보장하는 설계 철학을 반영합니다. 이들 레지스터는 함수 간의 호출 구조가 복잡하더라도, 데이터를 안전하게 보존하여 함수가 자신만의 상태를 유지할 수 있게 합니다. 이를 통해 프로그램의 일관성을 유지하면서도, 코드가 간결하고 효율적으로 작성될 수 있습니다.

결론

x18 (s2)부터 x27 (s11) 레지스터는 RISC-V 아키텍처에서 보존된 데이터를 관리하고, 함수 호출 시 데이터의 일관성을 유지하는 데 중요한 역할을 합니다. 이 레지스터들은 함수 간 호출 구조가 복잡해지거나, 재귀적으로 호출되는 상황에서도 데이터를 안정적으로 관리할 수 있도록 설계되었습니다. 이를 통해 RISC-V 아키텍처는 안정적이고 신뢰성 있는 함수 호출 구조를 구현할 수 있으며, 프로그램의 성능과 안정성을 극대화할 수 있습니다.

'Background' 카테고리의 다른 글

R-Type  (0) 2024.10.20
x28~x31(Temporaries) register  (0) 2024.10.20
x12-x17 (caller-saved) register  (0) 2024.10.20
x10-x11 (caller-saved) register  (0) 2024.10.20
x9(callee-saved s1) register  (0) 2024.10.20