--------------------------------------------------------------------------------------------------
출처 : 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
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);
}
☞ 어셈블리 코드에서는 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
--------------------------------------------------------------------------------------------------
'IT_Programming > System Programming' 카테고리의 다른 글
[UNIX] 공유 메모리를 이용한 프로세스 간 통신(IPC) (0) | 2011.02.21 |
---|---|
[Linux] 데몬 생성 함수 / IPC (0) | 2009.11.12 |
[펌] 리눅스에서 시리얼 제어 하기 (0) | 2009.09.30 |
GDB를 이용한 디버깅 (0) | 2009.05.26 |
Gcc Complie & Linking (0) | 2009.05.19 |