강좌 & 팁
글 수 2,412
2011.04.30 22:12:18 (*.138.143.120)
44137
작업을 하다보면 가끔씩 어셈블러를 만지게 됩니다.
기본적인 mov/ldr/cmp/add/sub/b 가 주를 이루는데요.
스택이나 최소한의 레지스터만을 가지고 현재의 내용을 저장하고 싶을때가 있습니다.
이때 유용하게 사용하는 것이 블록전송 명령 + ! 인데요...
간단한 예를 한번 보겠습니다.
특정 주소로 레지스터의 내용을 복사하고자 합니다.
.type __label_address, %object
__label_address:
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
adr r0, __label_address
stmia r0, {r1, r12, sp, lr}
위의 코드는 r1-r12, 그리고 r13인 sp, r14인 lr 레지스터를 위에 선언된 label 위치에 고이 모셔줍니다.
r0 레지스터가 오염되긴 했지만 어떤 레지스터도 변경된 것이 없습니다.
그러면 스택에 저장하고 싶을때는 어떻게 할까요?
stmia r0, {r1, r12, sp, lr}
이렇게 합니다.
그런데 문제가 있네요. 스택은 방향이 두방향이 있을수 있습니다.
위의 예는 sp 의 위치부터 증가하면서 저장합니다.
반대의 경우라면 이렇게 합니다.
stmda r0, {r1, r12, sp, lr}
눈치 채셨겠지만 stmia 는 increment, stmda 는 decrement 입니다.
이 명령이 수행되어도 r0 의 값은 변함이 없습니다.
그러면 연속적으로 데이타를 더 저장하려 할때 저장한 숫자만큼 더해서
다시 r0 값을 주어야 하나요? 라는 의문이 듭니다.
이런 경우를 대비해서 만든것이 ! 입니다.
stmia r0, {r1, r12, sp, lr}
stmia r0!, {r1, r12, sp, lr}
위의 두 명령어의 차이는 수행하는 역할은 동일합니다만 그 수행의 결과로
r0 의 값은 달라지게 됩니다.
첫번째 명령어는 결과가 변함이 없고 두번재 명령어는 결과값이 r0 에서 56 만큼 커집니다.
14개의 레지스터가 4byte 단위의 연산이기때문에 14*4=56 만큼 바뀌게 됩니다.
stmia r0, {r1, r12, sp, lr}
stmib r0, {r1, r12, sp, lr}
위의 두개의 연산의 차이는 뭘까요?
연산을 수행하기 전에 r0 의 값을 증가시킬 것이냐 수행하고 나서 증가시키느냐의 차이입니다.
*src++ = *dst++;
*++src = *dst++;
C 로 표현하면 위의 두 문장의 차이와 동일합니다.
보통 ! 를 사용하는 경우는 데이타를 저장하는 공간이 메모리의 주소가 아니라 스택일 경우 입니다.