확장 어셈블러 템플릿 (입력, 출력, 클리버 등)을 사용하는 경우 템플리트의 레지스터 이름에 %
을 추가해야합니다. 이 경우 . 이렇게하면이 오류와 관련된 문제가 해결됩니다.
error: invalid 'asm': operand number missing after %-letter
이것은 새로운 문제를 나타냅니다.
operand type mismatch for 'movq'
문제는 "r"(count)
입력 제약이 count
의 값을 포함하는 레지스터를 선택해야 컴파일러를 알 수 있다는 것입니다 : 당신은 유사한 오류가 발생합니다. count가 int
유형으로 정의되었으므로 32 비트 레지스터를 선택합니다. 논증을 위해서, 그것은 EAX을 선택한다고 가정한다.
movq %eax, %rcx
당신은 64 비트 레지스터 따라서 오류로 32 비트 레지스터의 내용을 이동 movq
을 사용할 수 없습니다 교체 후에는이 명령을 생성하기 위해 노력했을 것이다. 더 나은 선택은 ECX을 대상으로 사용하여 둘 다 동일한 유형이되도록하는 것입니다.
asm("mov %0, %%ecx;"
"startofloop: ; "
"sub $0x1, %%ecx; "
"jne startofloop; ":: "r"(count));
는 다른 방법이 "ri"(count)
의 입력 피연산자를 사용하도록 선택 할 수 : 같이 개정 코드가 보일 것이다. 이것은 컴파일러가 레지스터 또는 즉시 값을 선택할 수있게합니다. 더 높은 최적화 수준 (-O1
, -O2
)에 그것은 가능성이 count
가 일정하게 유지하는 것이이 경우에 (100,000,000)을 결정하고 생성 코드와 같은 :
mov $100000000, %ecx
startofloop:
sub $0x1, %ecx
jne startofloop
보다는 레지스터에 100000000를 배치하고에 복사 강제 ECX 대신 즉시 값을 사용할 수 있습니다.
템플릿에서 심각한 문제는 ECX하지만 GCC이에 대한 지식이없는 의 내용을 파괴하는 것입니다. GCC은 코드 내에서 실제로 수행 할 작업을 템플릿에서 구문 분석하지 않습니다. ECX과 구속력을 가지고 있다는 것은 잘 모릅니다. 컴파일러는 템플릿 전후에 동일한 값을 갖는 ECX에 의존 할 수 있습니다. 출력 피연산자에서 참조되지 않은 레지스터를 파괴하면 clobber 목록에 명시 적으로 나열해야합니다.이런 식으로 뭔가가 작동합니다 :
asm("mov %0, %%ecx;" "startofloop: ; " "sub $0x1, %%ecx; " "jne startofloop; ":: "ri"(count) : "rcx");
지금 GCC이 전과 템플릿이 실행 된 후 같은 값 인 RCX의 값에 의존 할 수 없다 알고있다. 내부 카운터로 고정 레지스터를 사용하는 대신 GCC을 사용하여 사용할 수있는 것을 선택할 수 있습니다. 이렇게하면 우리는 더 이상 clobber가 필요 없다는 것을 의미합니다. 계산에 사용할 수있는 더미 변수 (임시 변수)를 만들 수 있습니다. 이 코드가 최적화되지 않도록하기 위해 어셈블러 템플릿에 volatile
특성을 사용할 수 있습니다. 어셈블러 템플릿에 출력 피연산자가없는 경우에는 필요하지 않습니다. 다음과 같은 코드가 작동 것이다 :
는 int count=100000000
int dummy;
asm volatile("mov %1, %0;"
"startofloop: ; "
"sub $0x1, %0; "
"jne startofloop; ":"=rm"(dummy): "ri"(count));
=rm
출력 제약은 메모리 위치 또는 레지스터 중 하나가이 피연산자에 이용 될 수 있다고 말한다. 컴파일러를 선택하면 더 나은 코드를 생성 할 수 있습니다. 이 경우
mov $0x5f5e100,%ebx
startofloop:
sub $0x1,%ebx
jne startofloop
컴파일러가 카운트 즉시 피연산자 ($ 0x5f5e100 = $ 100000000)를 사용하기로 결정했습니다 : -O1
의 최적화 수준에서 당신은 가능성과 같을 것이다 생성 된 코드를 찾아 낼 것입니다. dummy
변수는 레지스터 EBX까지 최적화되었습니다.
템플릿을 개선하기 위해 할 수있는 다른 트릭이 있습니다. 하나는 변수 count
의 값을 보존하기 위해 등장 GNU documentation
코드의 확장 어셈블러 템플릿에 대한 자세한 내용을보실 수 있습니다. 템플릿을 실행하기 전에 count
이 동일한 값을 가져야하는 요구 사항이 아니라면 입력 및 출력 모두에 count
을 사용할 수 있습니다.
asm volatile("startofloop: ; "
"sub $0x1, %0; "
"jne startofloop; ":"+rm"(count):);
+rm
출력 오퍼랜드는 입력 오퍼랜드로서 사용되는 것을 의미처럼 그 코드는 볼 수 있었다. 이 경우 완료되면 count
은 항상 0이어야합니다.
당신이 출력에 GCC는-S
옵션을 생성 된 어셈블리 코드를 사용하는 경우 다음 출력이 청소기 보이는 귀하의 템플릿을 변경하실 수 있습니다. ;
(세미콜론) 대신 \n\t
을 사용하십시오. 이렇게하면 어셈블러 템플릿이 여러 줄로 나뉘어 들여 쓰기가 추가됩니다. 예 : 아무런 대안이없는 경우를 제외하고
일반적으로 asm volatile("mov %1, %0\n\t"
"startofloop:\n\t"
"sub $0x1, %0\n\t"
"jne startofloop\n\t":"=rm"(dummy): "ri"(count));
말하기, 당신은 인라인 어셈블러 템플릿을 사용할 수 없습니다. C에 코드를 작성하고 원하는 어셈블러를 출력하도록 컴파일러를 안내하거나 필요한 경우 컴파일러 내장 함수를 사용하십시오. 인라인 어셈블러는 최후의 수단으로 사용되거나 숙제가 요구 될 경우 사용해야합니다. David Wohlferd는 주제에 Wiki article이라고 썼습니다.
확장 된 어셈블러 템플릿 (입력, 출력, 클로버 등)을 사용하는 경우 레지스터 이름에 여분의 '%'를 추가해야합니다. 어쩌면'%% rcx'을 시도해보십시오.RCX를 덮어 쓰고 출력 피연산자로 나타나지 않으므로 clobber 목록에 나열해야합니다. –
@MichaelPetch, clobber의 좋은 점. 불행히도,'%% rcx'를 할 때, 'movq'에 대해'피연산자 유형 불일치가 발생합니다. – merlin2011
'count'가 32 비트 정수이고 어셈블러 템플릿이 대체를 위해 (eax와 같은) 32 비트 레지스터를 선택했을 가능성이 높습니다. '%'뒤에'q'를 두어 64 비트 레지스터를 사용하려면'% 0'을 사용할 수 있습니다. 'movq % q0, %% rcx;'와 같은 것 –