블로그 안 쓴지도 오래됐고 요즘 ARM 공부하고 있어서 정리하려고 한다. 맨날 인텔 기반만 공부하다가 요즘 ARM을 거의 처음 공부해보는데 재미있는 것 같다. 사실 예전에 RISC 기반의 비슷한 MIPS를 대충 공부하기는 했는데 진짜 대충해서.. 다시 공부해야겠다ㅠㅠ
참고로 ARM 공부하기에는 아래 ARM 공식 Docs가 가장 좋은 것 같다ㅎㅎ MTE도 여기서 설명 잘 되어 있었당
Documentation – Arm Developer
developer.arm.com
Processor Mode
Register를 알아보기 전에 먼저 프로세서 모드에 대해서 알아보자
이 모드는 현재 프로세서가 어떤 상태에 있는지를 알려주고, 해당 정보는 CPSR라는 특수 레지스터 내에 저장되게된다.
프로세서 모드는 아래와 같다 (출처: ARM Cortex-A Series Programmer's Guide for ARMv7-A)
User mode를 제외한 나머지 모드는 Privileged Mode이다
그렇다면 normal mode와 privileged mode의 차이점은 무엇일까?
먼저 Privileged mode에서는 자기네들끼리 서로 자유롭게 모드를 바꿀 수 있다.
그런데 user mode에서 preivileged mode로의 변환은 불가능하다. 예를 들어 SYS ↔ FIQ, IRQ ↔ SVC나 Privileged Mode → Normal Mode (USR)은 가능하지만, USR → Privileged Mode로의 변경은 불가능하다!!
또한 privileged mode에서는 IRQ,FIQ등의 인터럽트의 사용 유뮤를 직접 설정할 수 있다.
아래는 위 표를 좀 더 쉽게 요약한 그림이다.
그리고 ARM의 default mode는 SVC 모드라고 한다. 왜냐하면 boot up 시에 supervisor이어야지 ARM에서 모든 권한을 행사할 수 있을테니까!
또한 User 모드와 System 모드는 완전히 똑같은 register set을 사용한다. 얘네 둘을 구별해주는 것은 CPSR의 mode bit이다.
참고로 프로세서 모드에 관해서는 이 링크도 한국어로 잘 설명해주고 있다. -> https://julrams.tistory.com/12
Registers
일단 ARM에서는 r0~r15까지의 16개의 레지스터가 존재하고, 각 레지스터의 크기는 4byte이다. 이 외에도 특수한 레지스터들이 존재한다.
(사실 총 37개의 레지스터가 존재한다. 이에 대해서는 밑에서 보도록 하겠다.)
그러면 일단 이 레지스터들이 어떤 방식으로 사용되는지 보도록 하겠다.
범용 레지스터
이름 | 역할 |
r0~r3 | 함수의 매개변수나 리턴값을 저장. scratch register |
r4~r10 | 변수 레지스터. callee-save |
r11 | SFP. callee-save |
r12 | Intra Procedure Call |
scratch register는 어떤 함수에도 자유롭게 사용할 수 있지만, callee-save register는 함수에서 쓰이기 전에 스택에 데이터를 저장해두고, 함수가 끝날 때 pop해서 복구해야 한다.
참고로 Thumb mode에서는 r0~r7까지 사용하고, r11(SP)는 r7로 대체하여 사용한다.
특수 레지스터
이름 | 역할 |
r13 | Stack Frame Pointer (x86-64경우 rsp) |
r14 | LR (Link Register) : return address 저장 |
r15 | PC (Program Counter) |
CPSR | Current Program Status Register |
SPSR | Saved Program Status Register |
CPSR
CPSR는 프로그램의 현재 상태를 저장한다.
CPSR[31:28]
- Flag Field로 방금 전 연산 결과에 대한 정보(NZCV) 저장
CPSR[7:4]
- CPSR[7,6]: IRQ(보통 인터럽트), FIQ(높은 우선 순위 인터럽트) 비활성화 비트 (1하면 비활성화)
- CPSR[5]: ARM Mode(0), Thumb Mode(1)
참고) IRQ, FIQ 관련해서 알아보기-> https://stackoverflow.com/questions/973933/what-is-the-difference-between-fiq-and-irq-interrupt-system
이거 관련해서는 다음에 기회가 될 때 포스팅하겠다..
CPSR[4:0]
- 현재 프로세서 모드 저장 (맨 위에 있었던 표의 이진수로 인코딩된 부분이 저장되게 됨)
아래는 위 내용을 정리한 그림이다.
Banked Register
한편, 현재 어느 프로세서 모드에 있느냐에 따라, 레지스터들이 다른 물리적 위치를 가질 수 있다는 것이다.
이것을 우리는 Banking이라고 부르게 된다.
참고로 여기서 Low-Register와 r15는 어떤 processor mode에도 동일한 physical 위치를 갖는다.
아래 그림에서 하늘색으로 된 부분이 banking된 부분이다.
보니 프로세서 모드마다 High register 부분 중에서 각각 banking된 레지스터들이 있음을 확인할 수 있다.
이 banked register에 접근하면 다른 물리적 메모리에 접근하게 된다.
User와 System 모드를 제외하고서는 일단 r13(sp)와 SPSR는 항상 banking되게 된다.
그리고 이 banked register에서는 따로 어떤 레지스터를 접근할지 명시해주지 않는다. 이게 뭔 소리냐면, SP_svc를 접근한다고 하는게 아니라 그냥 SP를 접근한다고 하게된다. 그리고 현재 프로세스의 모드가 svc인걸 확인하고 그냥 암시적으로 SP_svc를 접근하게 되는 것이다.
Banked Register가 아닌 레지스터들은 user,system모드와 레지스터들을 공유하게 된다.
예를들어 User 모드에서 abort 모드로 전환할 경우, r0~r12 내용을 스택에 push하고 CPSR는 SPSR에 저장한다.
그리고 다시 abort에서 user로 전환할 때, SPSR에 저장한 것을 CPSR로 옮기고, 스택에 저장되어있는 user mode의 레지스터들을 가져와서 복구하게 된다. (약간 srop에서 sigreturn 배웠던 거랑 비슷한 느낌인듯)
위 그림처럼 banked register를 제외한 레지스터들은 다 공유하게 되어 빈칸으로 나오게 된다.
아까 위에서 말했던 총 37개의 레지스터가 여기서 나온다. 총 R0~R15 (16개) + CPSR (1개) + FIQ의 R8~R14, SPSR (8개) + SVC의 R13, R14, SPSR (3개) + Abort의 R13, R14, SPSR (3개) + IRQ의 R13, R14, SPSR (3개), UND의 R13, R14, SPSR (3개) = 16 + 1 + 8 + 3 + 3 + 3 + 3= 37개가 되는 것이다!
ARM64 Register
위에는 다 32bit 기준이었고, 64bit환경에서는 아래와 같은 레지스터들을 사용한다.
Wn,Xn에서 W는 32bit를 X는 64bit를 의미하고 n에 들어갈 수 있는 숫자는 0부터 30까지이다.
32bit instruction을 이용할 경우 상위 4byte는 무시된다.
References
드림핵 임베디드 해킹 로드맵,
https://recipes.tistory.com/307