IT_Programming/System Programming

[펌] ARM Developer Suite(ADS) 1.2 에서 C 코드와 ASM 코드 섞어 쓰기

JJun ™ 2009. 10. 7. 15:08

--------------------------------------------------------------------------------------------------

출처 : http://ituner.tistory.com/134

--------------------------------------------------------------------------------------------------
1. C 코드 내에 어셈블리 코드를 inline으로 사용하기

(1) 사용방식

asm("instruction[;instruction]"); 또는 C 컴파일러의 구문을 사용하면 다음과 같다.
__asm
{
     instruction [; instruction]
     ...
     [instruction]
}

(2) 분기문에 사용되는 라벨은 끝에 ‘:’를 찍는다.
__asm
{
     loop :
     ...
     [instruction]
}


(3) C 코드에서 사용하는 char, short, int 타입의 변수를 그대로 가져다 쓸 수 있다.
void my_strcpy(const char *src, char *dst)
{
     int ch;
     __asm
     {
          loop:
          // ARM version
          LDRB ch, [src], #1
          STRB ch, [dst], #1
     }

     ...

}

(4) 일반적인 어셈블리 코드와 다른 점
      - PC(Program Counter)값을 읽어오거나 쓸 수 없다.
      - LDR Rn, =variable_name 과 같은 구문을 쓸 수 없다.
      - C 변수명으로 r0, v1 과 같은 레지스터명을 쓸 수 없다.
      - stack 과 관련된 명령어를 쓸 수 없으며, 쓸 필요도 없다. ☜ 컴파일러가 자동으로 해준다
      - 일반적인 함수호출과 관련된 레지스터는 원래의 의미가 사라진다.

        예를 들어 r0-r3는 더 이상 함수호출에서 입력으로 들어오는 인자를 나타내지 않는다.

      - 레지스터를 쓸 때는 컴파일러가 그 값을 다른 용도로 쓰지 않는지 주의한다.
         ☞ C 에서 사용하던 변수를 그대로 쓰는 것이 안전하다.

(5) 예 : long 타입의 변수 곱하기
long long smull(int x, int y)
{
     long long res;
     __asm { SMULL ((int*)&res)[0], ((int*)&res)[1], x, y }
     return res;
}

 

 

 

--------------------------------------------------------------------------------------------------

 

 


2. C 코드와 어셈블리 코드를 함께 링크해서 사용하기

 


(1) C 전역 변수를 어셈블리 코드 안에서 사용하기

load/store 류의 명령어와 ‘=’를 사용한다. ☞ inline asm 에서는 반대로 ‘=’를 사용할 수 없다.
참조하고자 하는 변수가 char 타입이면 LDRB/STRB를 사용한다. Short 타입이면 LDRH/STRH,

또는 아키텍쳐에 따라 LDRB/STRB를 두 번 사용한다. int 타입이면 LDR/STR를 사용한다.
signed 변수이면 LDRSB LDRSH 와 같은 부호 명령어를 사용한다.
예)
AREA globals,CODE,READONLY
EXPORT asmsubroutine
IMPORT globvar
asmsubroutine
LDR r1, =globvar ; read address of globvar into
; r1 from literal pool
LDR r0, [r1]
ADD r0, r0, #2
STR r0, [r1]
MOV pc, lr
END

 


(2) C에서 어셈블리 코드를 불러다 쓰기
C 코드 쪽에서는 extern을 선언해주면 된다.
예)
#include <stdio.h>
extern void strcopy(char *d, const char *s);
int main()
{ const char *srcstr = "First string - source ";
char dststr[] = "Second string - destination ";
/* dststr is an array since we’re going to change it */
printf("Before copying:\n");
printf(" %s\n %s\n",srcstr,dststr);
strcopy(dststr,srcstr);
printf("After copying:\n");
printf(" %s\n %s\n",srcstr,dststr);
return (0);
}


어셈블리 코드 쪽에서는 EXPORT 해주면 된다.

☞ 어셈블리 코드에서는 inline asm 과 달리 라벨을 붙일 때, ‘:’가 없다.
예)
AREA SCopy, CODE, READONLY
EXPORT strcopy
strcopy ; r0 points to destination string.
; r1 points to source string.
LDRB r2, [r1],#1 ; Load byte and update address.
STRB r2, [r0],#1 ; Store byte and update address.
CMP r2, #0 ; Check for zero terminator.
BNE strcopy ; Keep going if not.
MOV pc,lr ; Return.
END

 

 

 

--------------------------------------------------------------------------------------------------

 


 

3. ADS에서 함수 호출과 관련된 중요한 규약

   (ATPCS : ARM-Thumb Procedure Call Standard)

 

 

(1) 레지스터 규칙
- r0-r3는 a1-a4라고도 하는데, 함수 호출에서 입력과 출력 인자가 된다.

  인자가 5개 이상인 것은 스택을 이용하는데, 속도가 현저히 떨어지므로 가급적 4개 이내로 인자를 쓴다.


- r4-r11은 v1-v8 이라고도 하는데, 함수 안에서 내부적인 변수로 사용한다.
- r12는 ip라고도 부르는데, 프로시져 간에 호출할 때, 다용도로 사용한다.
- r13은 sp라는 별칭의 스택 포인터이다. 다른 용도로는 사용할 수 없다.
- r14는 lr이라고도 하는데, 링크 레지스터로 return address를 저장한다.

   다른 곳에 별도로 이 값이 저장된 경우 다른 용도로 사용할 수 있다.

- r15는 pc로 program counter 이다. 다른 용도로 절대 사용 못한다.

(2) 함수를 호출할 때는 내부적인 용도로 변수를 사용한 경우, 스택에 저장했다가 return 할 때,

     원상 복구해야 한다. 이것은 LDM/STM 의 스택 관련 명령어를 사용하면 된다.

예)
utoa
STMFD sp!, {v1-v3, lr} ; save 2 variable registers and
; the return address
MOV v1, a1 ; keep char *buffer for later
MOV v2, a2 ; and keep the number for later
MOV a1, a2

ADD v2, v2, #'0' ; final digit
STRB v2, [a1], #1 ; store digit at end of buffer
LDMFD sp!, {v1-v3, pc} ; restore and return
END

함수 호출 시에 스택을 저장하고 복원하는 것은 매우 정형화된 루틴이므로 그대로 사용하면 된다.

sp 레지스터 끝에 ‘!’는 스택에 저장/복원한 다음 그만큼 sp를 이동하라는 뜻이므로 꼭 붙여줘야 한다.

 

--------------------------------------------------------------------------------------------------


참고문헌
ARM Developer Suite 1.2 Developer Guide ch. 2, ch. 4
ARM Developer Suite 1.2 Assembler Guide ch. 4

 

--------------------------------------------------------------------------------------------------