Self-Improvement

ARM 기초 (레지스터 종류, 명령어 등, LDR, STR) 본문

ARM

ARM 기초 (레지스터 종류, 명령어 등, LDR, STR)

JoGeun 2020. 8. 5. 13:30

레지스터 종류

 R0 ~ R12 : 범용 레지스터 (다목적 레지스터), R11(스택 프레임 포인터)
 R0 : 함수 리턴 값 저장 (EAX 같은 느낌) 
 R0 ~ R3 : 함수 호출 인자 전달 
 R13 ~ R15 : 특수 레지스터 
 R13(SP) : 스택 포인터 : 스택의 맨 위를 가리킴 
 R14(LR) : 링크 레지스터 : 서브루틴 후에 돌아갈 리턴 주소 저장 
 R15(PC) : 프로그램 카운터 : 현재 fetch되고 있는 명령어의 주소 - 따라서 현재 실행되는 명령어의 다음다음 주소
 CPSR : 현재 프로그램 상태 레지스터

 

Instruction

 분기 명령  B, BL
 데이터 연산 명령  ADD, ADC, SUB, SBC, RSB, RSC, AND, ORR, BIC, MOV, MVN, CMP, CMN, TST, TEQ
 Multiply 명령  MUL, MLA, SMULL, SMLAL, UMULL, UMLAL
 Load/Store 명령  LDR, LDRB, LDRBT, LDRH, LDRSB, LDRSH, LDRT, STR, STRB, STRBT, STRH, STRT
 Swap 명령  SWP, SWPB
 Load/Store Multiply 명령  LDM, STM
 Software Interrupt 명령  SVC
 PSR 전송 명령  MRS, MSR
 Co-Processor 명령  MRC, MCR, LDC, STC
 Branch Exchange 명령  BX
 ...  ARM Architecture 별로 명령어들이 추가 존재

- ARM은 메모리 내에 직접 데이터를 쓰거나 가져올 수 없음

- 특정 명령을 통해 메모리 값을 레지스터에 가져오거나, 레지스터 값을 메모리에 써야 함 (LDR, STR 명령어)

- RISC 구조의 대표적인 특징, Load/Store 구조

- 32비트 상수 값은 Operand로 사용할 수 없음

 

조건부 실행

 EQ  Z Flag set  같다
 NE  Z Flag Clear  같지 않다
 CS  C Flag Set  크거나 같다.(unsigned)
 CC  C Flag Clear  작다(unsigned)
 MI  N Flag Set  음수
 PL  N Flag Clear  양수 또는 0
 VS  V Flag Set  오버플로우 발생
 VC  V Flag ClEAR  오버플로우 X
 HI  C Flag Set, Z Flag Clear  크다.(Unsigned)
 LS  C Flag Clear  작다.(Unsigned)
 GE  N Flag = V Flag  크거나 같다.
 LT  N Flag != V Flag  작다
 GT  Z Flag Clear AND (N = V)  크다
 LE  Z Flag Set OR (N != V)  작거나 같다
 AL  Ignore  무조건 실행

 

1. 산술 연산 명령어

 ADD R0,R1,R2  R1과 R2를 더하여 R0에 저장
 SUBEQ R0,R1,#8  EQ 조건이면 R2에서 8을 빼서 R0에 저장하고 결과에 따라 CPSR Flag를 설정함
 ADDS R1,R2,R0  R2와 R0을 더하여 R1에 저장하고 결과에 따라 CPSR Flag를 설정함

 

2. 논리 연산 명령어

 AND R0,R1,R2  R1과 R2를 AND 연산하여 R0에 저장
 ANDEQS R0,R1,R2  EQ 조건이면 R1과 R2를 AND 연산하여 R0에 저장하고 결과에 따라 CPSR Flag를 설정함
 BICLE R1,R2,R0  LE 조건이면 R2와 R0를 XOR 하고 결과를 R1에 저장

 

3. 비교 명령어

 CMP R0,R1  R1과 R2를 비교하여 그 결과로 CPSR에 Flag 설정
 TSTEQ R2,#8  EQ 조건이면 R2와 #8을 비교 후 결과로 CPSR Flag 설정
 CMN  LE 조건이면 R2와 R0를 XOR하고 결과를 R1에 저장

 

4. MOVE 명령어

 MOV R0,R1  R1을 R0으로 옮긴다.
 MOVLE R0,R2  LE 조건이면 R2를 R0으로 옮긴다
 MVN R0,R2  R2 XOR 0xFFFFFFFF한 값을 R0에 옮긴다 (Negative로 변경)

 

5. 분기 명령어

 BL somewhere  Somewhere로 분기와 LR에 돌아올 주소 저장 (함수 호출에 사용)
 함수 호출 후 되돌아갈 때 MOV PC,LR 사용함
 B somewhere  Somewhere로 분기
 CMP R1,#0
 BEQ success
 R1이 0이면 (EQ조건이면) success로 분기

 

6. 데이터 전송 명령어 - Pre-index 방식

 LDR R1, [R2,R4]  R2+R4 위치에서 데이터를 워드만큼 읽어서 R1에 저장
 LDR R1, [R2,R4]!  R2+R4 위치에서 데이터를 워드만큼 읽어서 R1에 저장 후 R2의 값은 R2+R4 값으로 변경됨
 STR R1, [R2,R4]  R1 값을 R2+R4 위치에 워드 만큼 저장함
 LDR R1, [R2,#8]  R2+8 위치에서 워드만큼 읽어서 R1에 저장 함

 

7. 데이터 전송 명령어 - Post-index 방식

 LDR R1, [R2],#4  R2에서 워드만큼 읽어서 R1에 저장 후 R2+4 값으로 R2 변경 함
 LDR R1, [R2],R4  R2에서 워드만큼 읽어서 R1에 저장 후 R2+R4 값으로 R2 변경 함
 STR R1, [R2],R4  R1 값을 R2 위치에 워드 만큼 저장 후 R2+R4 값으로 R2 변경 함

 

8. 데이터 전송 명령어 - PC-Relative 방식

 LDR R1, label label : DCD 0xdeadbeef  Label 위치에서 데이터 0xdeadbeef를 워드만큼 읽어서 R1에 저장
 LDR R1, =0xdeadbeef  데이터 0xdeadbeef를 R1에 저장한다.

 

9. 다중 데이터 전송 명령어

 STMIA R0, {R1,R2,R3}  R1, R2, R3 데이터를 R0 위치부터 저장함
 STMIA R0!, {R1,R2,R3}  R1, R2, R3 데이터를 R0 위치에 저장하고 R0 값에 12가 더해짐, 12=R1(4)+R2(4)+R3(4)
 LDMIA R0, {R1,R2,R3}  R0 위치에서 데이터를 차례대로 읽은 후 각각 R1, R2, R3에 저장
 LDMIA R0!, {R1,R2,R3}  R0 위치에서 데이터를 차례대로 읽은 후 각각 R1, R2, R3에 저장 후 R0에 12가 더해짐
 LDMIA R0, {R0-R7}  R0 위치에서 데이털르 읽은 후 R0~R7까지 각각 저장
 LDMIA R0!, {R0-R2, PC}  R0 위치에서 데이터를 읽은 후 R0~R2까지 그리고 PC까지 합한 16이 R0에 더해짐

 

10. Software Interrupt 명령어

 SWI 0x80  CPSR을 SPSR_svc에 저장 후 PC를 0x08(SWI의 예외 처리 Handler)로 분기 후 0x80을 보고 정의된 동작 실행

 

11. ARM<-->Thumb mode 명령어

 BLX thumb_Func  thumb_Func로 분기하고 Thumb mode로 전환하고 R14 Register에 돌아올 주소 저장
 BLXEQ R0  EQ 조건이면 R0이 지정하는 위치로 분기하고 상태 정보에 따라 상태를 전환하고 R14에   Regiset에 돌아올 주소 저장

 

* Thumb mode 도입 이유

- 기존 ARM 명령을 사용하여 만들어진 바이너리 보다 크기가 약 75% 적음

- 크기가 적어지면 Flash나 Rom 같은 저장 장치의 단가를 줄일 수 있음

- 16비트 메모리 인터페이스를 사용하면 가격과 전력 소모를 줄일 수 있음

 

LDR, STR

ldr r0, addr_var1 = addr_var1 주소를 r0 = 0x10090을 R0에

ldr r1, addr_var2 = addr_var2 주소를 r1 = 0x10094를 R1에

ldr r2, [r0] = r0 주소의 값을 r2에 = 0x3을 R2에

str r2, [r1] = r2 값을 r1 값에 = 0x3을 0x10094의 값에

 

str r2, [r1, #2] = r1+2 주소의 값에 r2 값을 = 0x1009c+2 주소(0x1009e)의 값에 0x3을

str r2, [r1, #4]! = r1+4 주소의 값에 r2 값을 넣고 r1+4 주소를 r1에 = 0x1009c+4 주소의 값에 0x3을 넣고 0x100a0을 r1에

ldr r3, [r1], #4 = r1 주소의 값을 r3에 넣고 r1+4를 r1에 = 0x100a0 주소의 값 0x3을 r3에 넣고 0x100a0+4를 r1에 

 

str r2, [r1, r2] = r1+r2의 주소의 값에 r2 값을 = 0x1009c+0x3의 주소의 값에 0x3을

str r2, [r1, r2]! = r1+r2의 주소의 값에 r2 값을 넣고 r1에 r1+r2 주소를 = 0x1009c+0x3의 주소의 값에 0x3을 넣고 r1에 0x1009f를

ldr r3, [r1], r2 = r1의 값을 r3에 넣고 r1+r2의 주소를 r1에 = 0x3을 r3에 넣고 0x100a2를 r1에

 

Reference

https://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf