-
#if __LINUX_ARM_ARCH__ >= 6
-
static inline unsigned long arch_local_irq_save(void)
-
{
-
unsigned long flags;
-
asm volatile(" mrs %0, cpsr @ arch_local_irq_save\n"
-
" cpsid i"
-
: "=r" (flags) : : "memory", "cc");
-
return flags;
-
}
인라인 어셈블리
인라인 어셈블리에 대해서 간단히 짚고 넘어가자. 나중에 보면 이해가 안될거 같으니까.
보통 다음과 같은 문법이다.
__asm__ __volatile__ (asms : output: input: clobber);
ANSI에서는 __asm__만 쓰니까, asm 보단 __asm__을 쓰는게 낫다. volatile(__volatile__)은 최적화를 진행하지 않는다. 컴파일러가 괜히 머리 쓴다고 사용되지 않는다고 판단되는 변수를 없애는 불상사를 방지한다.
asm은 따옴표로 둘러싸인 어셈블리 코드(여기서는 "mrs ... cpsid i"가 되겠다)이며, %와 같은 형태로 input, output parameter를 사용할 수 있다. 컴파일 후, 파라미터가 치환된 대로 어셈블리 코드로 나타난다.
output은 결과값을 출력하는 변수이다.
"=r"(flags)이다. =는 쓰기전용이란 뜻이다.
input은 output과 같은 방식으로 사용하고, 인라인 어셈블리 코드에 넘겨주는 parameter를 적는다.
clobber는 asm를 실행 시, 값이 변하는 것을 적어준다. 각 변수는 쉼표로 구분되며 각각을 따옴표로 감싸준다. "memory", "cc"가 되겠다.
이제 실제 코드를 분석해 보면,
mrs %0, cpsr 에서는 "=r" (flags)에서, 레지스터 넘버를 flags로 받은 뒤 나오는 레지스터로 cpsr를 저장시킨다. 그 후 cpsid i를 통해 인터럽트를 disable 시킨다. cpsid i는 arm cortex에서 인터럽트를 disable 시킨다. armv7 전용 명령어로 알고 있었는데, ifdef에서 version 6부터 체크하는 걸 보니, armv6에서도 가능한가 보다.
clobber 영역의 "memory"는 컴파일러에게 어셈브릴 코드가 메모리의 어딘가를 변경한다고 가르쳐 주는 것이다. 만약 이렇게 안해주면 컴파일러는 어셈블리코드에서 메모리의 내뇽을 변경하는 것을 컴파일러는 전혀 알 수 없다. "memory"를 명시해 주면, 컴파일러는 어셈블리 코드를 실행하기 전/후에 레지스터에 저장되어 있는 모든 변수의 값을 갱신하도록 한다. "cc"는 컴파일러에게 어셈블리 명령어가 컨디션 코드 플래그를 읽고 쓴다고 알려준다. 설명이 길어졌다. 결국, cpsr를 저장하고 인터럽트를 disable 시킨다.
'프로그래밍 > C' 카테고리의 다른 글
symbol visibility (0) | 2013.08.07 |
---|---|
typedef 와 static 을 동시에 사용 못하는 이유 (0) | 2012.11.24 |
include guard에 대해서 (0) | 2012.09.24 |
구조체 초기화 방법 (0) | 2012.08.21 |
error: expected identifier before numeric constant (0) | 2012.07.03 |