명령어 중 이런게 있었다
0x8448 mov r3, pc
0x844a mov r4, pc
r3 에는 0x8448 이, r4 에는 0x844a 가 들어갈 것 같았는데
실제로는 r3 에는 0x844c, r4 에는 0x844e 가 들어갔다.
조금 찾아보니 pc 값은 thumb mode 에서는 항상 +4 byte , arm mode 에서는 +8 byte 라고 하는데..
(http://www.iamroot.org/xe/Kernel_8_ARM/49399)
그래도 pc값을 저장하는 시점에서 + 4byte 값이 들어간다는 것이 이해가 안되었다.
영어 자료에서 찾게 된 내용은 이렇다.
ARM 파이프라인에는 3 단계가 있어서, PC는 항상 fetched 된 인스트럭션을 가리키고 있습니다. 명령어가 해석되는 단계에서는 PC-4, 그리고 실행되는 단계에서는(디버거에서는 현재 인스트럭션이라고 나타나는) PC-8 값을 갖게 됩니다.
good explanation, and good for citing the ARM ARM. In the ARM 3-stage pipeline, the PC always points to the instruction being fetched, and PC-4 points to the instruction being decoded, and PC-8 is the "current instruction", i.e. the instruction being executed. This is also why exceptions must adjust the LR value before returning. As you noted, this applies to ARM (32-bit) instructions, hence the 4-byte adjustment per pipeline stage
- 출처 : http://stackoverflow.com/questions/2102921/strange-behaviour-of-ldr-pc-value
으아!
조금 더 찾아보니... 국내 블로그 중에서도 이런 주옥같은 내용이.
3. Allocating Stack and Saving Usr Mode Context
arch/arm/kernel/entry-common.S:
.align 5
ENTRY(vector_swi)
sub sp, sp, #S_FRAME_SIZE
| . |
| . |
+-----+ <----- sp
| . | |
| . | |
| . | |
| . | |
| . | pt_regs (18 * sizeof(long))
| . | |
| . | |
| . | |
| . | v
+-----+ <----- sp
| . |
| . |
stmia sp, {r0 - r12} @ Calling r0 - r12
ARM( add r8, sp, #S_PC )
ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
mrs r8, spsr @ called from non-FIQ mode,
@ so ok.
str lr, [sp, #S_PC] @ Save calling PC
str r8, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
...
| . |
| . |
+----------+
| r0_orig |
+----------+
| spsr_svc |
+----------+
| lr_svc |
+----------+
| lr_usr |
+----------+
| sp_usr |
+----------+
| r12 |
+----------+
| . |
| . |
+----------+
| r0 |
+----------+ <---- sp
| . |
| . |
spsr_svc : 예외발생 이전의 usr 모드에서 사용중이던 cpsr 의 값이 spsr_svc 에 저장되어있음.
lr_svc : 예외발생 이전의 usr 모드에서 사용중이던 pc의 값 (lr_svc = CPSR.T == O ? pc - 4 : pc - 2) 이 lr_svc 에 저정되어 있음. swi 는 decode 단계에서 발생하므로 pc–4를 하면 swi를 일으킨 명령 바로 다음의 주소를 얻게 된다.
pc fetch
pc - 4 decode
pc - 8 execute
위 표는 fetch -> decode -> execute 로 이어지는 파이프라인 특성때문에 pc 값이 fetch 단계의 주소를 가리키고 있어 pc 를 읽어 들이는 실제 명령수행 단계에서는 ARM 모드의 경우 8byte, Thumb 모드에서는 4 바이트만큼 항상 앞서 있다.
r0_orig : 시그널 처리시에 시스템콜을 다시 실행해야 하는 경우 r0의 값을 다시 복구하기 위해 사용됨.
우와... 놀라운 정리. 출처는 http://pr1mary.blogspot.kr/2013/11/how-arm-supervisor-call-exception.html
정말 감사합니다.
그래서 이후 pc 갖고 계산할 때는 파이프라인 따져서, 명령어 + 2줄 뒤 로 본다.
'Research > Reverse' 카테고리의 다른 글
About overflow flag (0) | 2016.02.16 |
---|---|
intager <-> string 변환과 속도 (0) | 2015.08.10 |
olly/ida에서의 HW Bp 처리방식 차이 (0) | 2014.07.03 |
[써볼만한 주제] unlikly 결과 어셈블리는 ? (0) | 2014.03.31 |
Anti Reverse Engineering - BreakPoint (0) | 2013.12.16 |