작업을 하다보면 가끔씩 어셈블러를 만지게 됩니다.


기본적인 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 로 표현하면 위의  두 문장의 차이와 동일합니다.
    보통 ! 를 사용하는 경우는 데이타를 저장하는 공간이 메모리의 주소가 아니라 스택일 경우 입니다.