인프런 커뮤니티 질문&답변

chltnckd7님의 프로필 이미지
chltnckd7

작성한 질문수

ARM Cortex-M 프로세서 프로그래밍

s337_인라인 어셈블러

인라인 어셈블러 질문드립니다.

작성

·

411

1

  1.  

    인라인 어셈블러 포맷에서 ::: 마지막란에 Clobber list가 온다고 배웠습니다.

Clobber list에 "memory"를 쓰면 메모리 장벽이 생성된다는게 어떤 의미인지 구체적으로 알 수 있을까요?

 

  1. 강의 예시로 나온 코드의 내용입니다.

    (strexb %0, %2 %1" : "=&r"(result), "=Q"(*addr): "r" ((uint32_t)value));

    어셈블러 문법상 :::는 무조건 적어야한다고 강의를 통해 배웠는데요. 위 코드에서는 ' : ' 가 2개 뿐인걸로 확인했습니다. 특정 상황에서는 ' : '를 3개 다 적지 않아도 되는건가요?

     

    감사합니다~

     

답변 1

1

홍영기님의 프로필 이미지
홍영기
지식공유자

안녕하세요, chltnckd7님!

Q1. 인라인 어셈블러 포맷에서 ::: 마지막란에 Clobber list가 온다고 배웠습니다.

Clobber list에 "memory"를 쓰면 메모리 장벽이 생성된다는게 어떤 의미인지 구체적으로 알 수 있을까요?

A1. 컴파일 과정에서 컴파일러는 최적화를 위해 필요한 경우 사용자 작성 코드를 재배치(Reordering)할 수 있습니다. 게다가 캐쉬, 레지스터를 사용하는 경우까지 가세하게 되니까 이는 시스템의 각 요소들 사이의 메모리 연산의 순서에 대한 보장이 굉장히 어렵고 중요한 문제가 될 수 있습니다. 이에 메모리 장벽이라는 기술을 사용할 수 있는데, DMB, DSB, ISB 와 같은 메모리 장벽을 위한 어셈블리 명령어를 사용할 경우 이를 통해 명령어의 사용전 코드 블럭과 사용 후의 코드 블럭사이에서의 메모리 연산의 실행 순서를 보장할 수 있습니다.

e.g. 클로버(memory)가 사용된 코드의 예

__STATIC_FORCEINLINE void __enable_irq(void){
__ASM volatile ("cpsie i" : : : "memory");
}

코드 블럭 A 영역

__enable_irq(); // 이 함수 호출을 기준으로 앞선 코드 블럭 A 영역에서의 메모리 관련 동작이 완전히 끝나야만, 코드 블럭 B의 실행이 진행된다.

코드 블럭 B 영역

메모리 장벽에 관련하여 자세한 것은 다음의 글을 참고하면 좋습니다.

 

Q2. 강의 예시로 나온 코드의 내용입니다.

(strexb %0, %2 %1" : "=&r"(result), "=Q"(*addr): "r" ((uint32_t)value));

어셈블러 문법상 :::는 무조건 적어야한다고 강의를 통해 배웠는데요. 위 코드에서는 ' : ' 가 2개 뿐인걸로 확인했습니다. 특정 상황에서는 ' : '를 3개 다 적지 않아도 되는건가요?

A2. 아래 시놉시스처럼 콜론은 입출력 오퍼랜드와 클로버가 작성된 상태에 따라 다릅니다.

asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ] )

클로버가 인라인어셈블리에 표현되어 있다면 콜론 기호는 3개가 필요하지만, 표현된 문장에 클로버가 생략되어 있다면 콜론 기호는 2개 이하이겠지요. 자세한 내용은 아래 예시를 참조 바랍니다.

e.g. 클로버를 사용한 예( 콜론 3개 )

__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control){
__ASM volatile ("MSR control, %0" : : "r" (control) : "memory");
}

e.g. 클로버를 사용하지 않은 예( 콜론 2개 )

__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control){
__ASM volatile ("MSR control, %0" : : "r" (control));
}

 

chltnckd7님의 프로필 이미지
chltnckd7
질문자

__STATIC_FORCEINLINE int MOV_TEST(volatile int *val1)

{

int result;

__ASM volatile( "MOV %0, %1" : "=r"(result) : "Q"(*val1) );

return result;

}

mov를 인라인 어셈블리로 위와 같이 작성 하였는데 해당 오류가 나옵니다.

오류 내용 :

Error: undefined symbol r3 used as an immediate value

 

일반 변수를 사용하면 잘 되는데 포인터로 작성하면 오류가 생기네요. 왜 이런 걸까요?

혹시나 __ASM volatile( "MOV %0, [%1]" : "=& r"(result) : "r"(val1) ); 이렇게 작성해도 오류가 나오네요.

홍영기님의 프로필 이미지
홍영기
지식공유자

mov 명령의 오퍼랜드에는 메모리를 사용할 수 없습니다. 레지스터나 상수만이 가능하죠.

예를들어, mov r0,r1 혹은 mov r0,#4

그러므로 코드는 다음과 같이 작성되어야 합니다.

__STATIC_FORCEINLINE int MOV_TEST(volatile int* val1)
{
int result;
__ASM volatile( "ldr %0, %1" : "=r"(result) : "Q"(*val1) );
return result;
}

printf("ret=%#x\n", MOV_TEST(&a));

===

실행결과

ret=0x12345678

chltnckd7님의 프로필 이미지
chltnckd7
질문자

아.. 메모리를 사용한 거였네요.. 감사합니다.

막상 배운 어셈블리 언어들 인라인어셈블리로 작성해보려니 쉽지 않네요~

chltnckd7님의 프로필 이미지
chltnckd7

작성한 질문수

질문하기