Self-Improvement
ARM 기초 (레지스터 종류, 명령어 등, LDR, STR) 본문
레지스터 종류
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
'ARM' 카테고리의 다른 글
ARM의 함수 포인터(function pointer) 예제 (0) | 2021.01.12 |
---|---|
ARM의 포인터(pointer) 사용예제 [R3] (0) | 2021.01.11 |
IDA에서 ARM의 SUB "-" 부분과 스택(stack) 부분 (0) | 2021.01.11 |
ARM - Socket( bind, socket ) 코드 분석 (htons, htonl) (0) | 2020.12.03 |
[pwnable.kr] leg 풀이 (ARM 문제) (0) | 2020.06.23 |