가끔 아래와 같은 cmn ARM 어셈블리어를 볼 수가 있는데 좀 더 깊히 살펴보도록 하겠습니다.
cmn r4,#0x1
 
평소에는 잘 알고 있는 것 같은데 실제 이슈를 볼 때 ARM Instruction을 만나면 머리가 흐릿해지면서
가물가물 해지는 경우가 많아서요. 
 
ARM 공식 사이트에 가면 cmn을 음수 비교 구문이라고 소개해 놓았습니다.
구문
CMN{cond} Rn, Operand2
CMN 명령어는 Rn의 값에 Operand2의 값을 더합니다. 이 명령어는 결과가 버려진다는 점을 제외하고 ADDS 명령어와 동일합니다.
 
그럼 아래 명령어를 실제 Trace32로 실행시켜보면  r4가 -1인지 아닌 지를 체크하는 동작을 해요.
cmn     r4,#0x1
___addr/line|code_____|label____|mnemonic________________|comment
NSR:C016DB1C|E3740001            cmn     r4,#0x1          ; r4,#1
NSR:C016DB20|0AFFFFF0            beq       0xC016DAE8  // <<-- r4가 -1이면 0xC016DAE8로 점프
NSR:C016DB24|E59F0448            ldr     r0,0xC016DF74    ; facility,0xC016DF74
NSR:C016DB28|E2444001            sub     r4,r4,#0x1       ; r4,r4,#1
 
위 어셈블리 코드를 C 언어로 바꾸면 더 이해하기 쉽죠.   
if ( r4 == - 0x1) {
   b  0xC016DAE8
}   else {
   b  0xC016DB24
}
 
 
 
strleb란 명령어를 본 적이 있나요? 전 잘 몰라서요, 이 명령어가 어떻게 동작하는지 테스트를 해봤거든요.
그 내용을 정리해서 업데이트할께요.
 
제가 만난 명령어는 아래와 같거든요.
cmp     r3, #2                  @ 1  //<<--[1]
strleb  r2, [r0], #1            @ 1
 
해석을 하면 아래와 같아요.
"R3이 0x2보다 같거나 작을 경우[1], r2의 하위 2바이트를 r0가 가리키는 주소에 있는 값에 저장한 후 r2를 1만큼 증가시킴"
 
"strltb" 명령어는 아래 단어를 줄인 것 같은데요.
Str(Store)|le(Signed less than OR equal)  | b(Byte)
 
이 내용이 머리에 잘 안 들어와서 실제 Trace32로 이 명령어가 동작하기 전/후를 점검해봤어요.
cmp     r3, #2                  @ 1  
strleb  r2, [r0], #1            @ 1
 
일단 R3이 1이니까 2보다 작죠.
R0은 C000A000 주소를 갖고 있고, C000A000 메모리에는 FFFFFFFF값이 있어요.
N _  R0   C000A000    R8          0
Z Z  R1          0       R9          0
C C  R2   EEEECCCC  R10         0
V _  R3          1        R11         0
 
_____address|________0________4________8________C
NSD:C0009FF0| 00000000 00000000 00000000 00000000
NSD:C000A000|>FFFFFFFF 00000000 00000000 00000000
NSD:C000A010| 00000000 00000000 00000000 00000000
 
이 명령어를 수행하면, R0이 1만큼 커져서 C000A001이 되구요.
R0이 가르켰던 C000A000 메모리 공간에 있는 FFFFFFFF값 하위 2바이트가 CC로 바뀌어 있어요. 
[After]
N N  R0   C000A001   R8          0 
Z _  R1          0       R9          0
C _  R2   EEEECCCC  R10         0
V _  R3          1       R11         0
 
_____address|________0________4________8________C
NSD:C0009FF0| 00000000 00000000 00000000 00000000
NSD:C000A000|>FFFFFFCC 00000000 00000000 00000000
NSD:C000A010| 00000000 00000000 00000000 00000000
 
ARM사에 계신 ARM개발자님께서 왜 이런 명령어를 개발하셨을까요?
아마 명령어당 ARM core의 실행 횟수를 줄이려고 이런 명령어를 만드신게 아닌 가 생각되네요. 
 
참, 대단하신 것 같네요.
 
"ldm r6,{r2-r3}" 명령어를
Trace32로 실행한 과정을 업데이트할께요.
 
R6 레지스터가 C011AACC 주소를 가르키고 있고,
C011AACC 주소에는 10001000 값이 담겨져 있어요.
[Before]
N _  R0          0  R8          0  ^S+ ^Stack_+
Z _  R1          0  R9          0
C _  R2          0  R10         0
V _  R3          0  R11         0
Q _  R4          0  R12         0
     R5          0  R13  D000D000
0 _  R6   C011AACC  R14         0
1 _  R7          0  PC   C01A7310
2 _  SPSR       10  CPSR     01D3
 
(where)
_____address|________0________4________8________C
NSD:C011AAC0| E59F2198 E59F3198 E88B000C>10001000
NSD:C011AAD0| E59B300C E12FFF33 E5942014 E5943010
NSD:C011AAE0| E023A392 E5942000 E2833080 E0823003
 
"ldm r6,{r2-r3}" 명령어를 실행하고 나니,
R2와 R3이 각각, 10001000, E59B300C로 업데이트 되었네요.
[After]
N _  R0          0  R8          0
Z _  R1          0  R9          0
C _  R2   10001000  R10         0
V _  R3   E59B300C  R11         0
Q _  R4          0  R12         0
     R5          0  R13  D000D000
0 _  R6   C011AACC  R14         0
1 _  R7          0  PC   C01A7314
2 _  SPSR       10  CPSR     01D3
 
아래와 같이 보면 좀 더 이해하기 쉽겠죠?
_____address|________0________4________8________C
NSD:C011AAC0| E59F2198 E59F3198 E88B000C>10001000(R2)
NSD:C011AAD0| E59B300C(R3) E12FFF33 E5942014 E5943010
NSD:C011AAE0| E023A392 E5942000 E2833080 E0823003
 
 
ldrd 명령어에 대해서 소개하고자 해요.
아래와 같은 ldr 명령어는 많이 봤는데, 갑자기 이런 명령어가 보이니 당황스럽기도 하네요.
ldr  r2, [r4,#0x8]
 
자 이제, 구체적으로 아래 Instruction이 실행된 후 레지스터가 어떻게 업데이트 되는지 살펴볼께요.
ldrd    r2,r3,[r4,#0x8]
 
참고로 R4는 0xD000D000 인데요. 0xD000D000+0x8 에 위치한 공간에 아래 값을 갖고 있네요.
_____address|________0________4________8________C
NSD:D000D000| 00000000 11111111 >22222222 33333333
NSD:D000D010| 00000000 00000000 00000000 00000000
NSD:D000D020| 00000000 00000000 00000000 00000000
NSD:D000D030| 00000000 00000000 00000000 00000000
NSD:D000D040| 00000000 00000000 00000000 00000000
 
"ldrd    r2,r3,[r4,#0x8]" 명령어가 실행되기 전 레지스터 상태는 아래와 같은데요, R2/R3가 0x0이네요.
N _  R0          0  R8          0
Z _  R1          0  R9          0
C _  R2          0  R10         0
V _  R3          0  R11         0
Q _  R4   D000D000  R12         0
     R5          0  R13  EEEECCC0
0 _  R6          0  R14         0
1 _  R7          0  PC   C0174658
2 _  SPSR       10  CPSR     01D3
 
실행 후에는 (0xD000D000+0x8)에 위치한 메모리 덤프를 R2/R3에 로드하네요.
N _  R0          0  R8          0
Z _  R1          0  R9          0
C _  R2   22222222  R10         0
V _  R3   33333333  R11         0
Q _  R4   D000D000  R12         0
     R5          0  R13  EEEECCC0
0 _  R6          0  R14         0
1 _  R7          0  PC   C017465C
2 _  SPSR       10  CPSR     01D3
 
정리하면 아래 명령어는 r4에서 0x8만큼 떨어진 메모리 공간에 있는 값을 8 바이트 만큼 읽어서
R2/R3에 로딩하는 군요.
ldrd    r2,r3,[r4,#0x8]
 

+ Recent posts