이 글에서는 Linux 커널 기준으로 자주 사용하는 inline asm constraint를 정리한다.
GCC + Clang 공통 기준으로, 특히 Clang에서 주의해야 할 포인트를 포함한다.
1. 기본 구조
asm volatile (
"asm template"
: output operands
: input operands
: clobber list
);
구조는 항상 4파트다.
| 파트 | 역할 |
|---|---|
| template | 실제 asm 코드 |
| outputs | C ← asm |
| inputs | C → asm |
| clobber | 깨지는 레지스터/상태 |
2. 출력 Operand 제약 (Output Constraints)
| 제약 | 의미 | Clang 주의 |
|---|---|---|
"=r" | 레지스터에 출력 | 가장 기본 |
"=m" | 메모리에 출력 | 메모리 barrier 필요 |
"=&r" | early-clobber | 입력보다 먼저 덮어씀 |
"+r" | read/write (입출력 겸용) | tied operand 대체용 |
"=a" | 특정 레지스터 (x86 eax) | 아키텍처 의존 |
가장 중요한 것: =r vs +r
=r
- write-only
- 입력과 같은 변수면
"0"필요
+r
- read + write
- 같은 레지스터 사용을 가장 안전하게 표현
- Clang 포팅 시 80%는 이걸로 해결
3. 입력 Operand 제약 (Input Constraints)
| 제약 | 의미 |
|---|---|
"r" | 레지스터 |
"m" | 메모리 |
"i" | 즉시값 (컴파일 타임 상수) |
"0" | 0번 output과 같은 레지스터 |
"1" | 1번 output과 같은 레지스터 |
"g" | register or memory |
"a" | 특정 레지스터 |
Tied Operand
: "=r"(val)
: "0"(val)
의미:
input이 0번째 output과 같은 레지스터 사용
Clang에서는 이것보다 +r이 더 안전하다.
4. Early-Clobber (=&r)
이건 매우 중요하다.
언제 필요한가?
asm이 출력 레지스터를
입력 읽기 전에 덮어쓸 때
예
asm volatile(
"mul %2"
: "=&r"(res)
: "0"(a), "r"(b)
);
Clang은 early-clobber 누락을 더 잘 잡는다.
5. Clobber List 정리
: /* outputs */
: /* inputs */
: "memory", "cc"
| clobber | 의미 |
|---|---|
"memory" | 메모리 상태 변경 |
"cc" | condition code 변경 |
"rax" | 특정 레지스터 변경 |
memory clobber의 중요성
Clang은 최적화가 공격적이다.
GCC에서 되던 코드도
memory clobber가 없으면 reorder될 수 있다.
asm volatile("" ::: "memory");
= full barrier 효과
6. 자주 쓰이는 레지스터 제약 (아키텍처별)
x86
| 제약 | 레지스터 |
|---|---|
"a" | rax |
"b" | rbx |
"c" | rcx |
"d" | rdx |
"S" | rsi |
"D" | rdi |
ARM64
| 제약 | 의미 |
|---|---|
"r" | x0-x30 |
"w" | SIMD/FP reg |
"Q" | 메모리 operand |
"I" | small immediate |
ARM64는 Clang에서 IAS 영향 많이 받는다.
7. GCC에서 되지만 Clang에서 깨지는 대표 패턴
잘못된 tied operand
asm volatile("..."
: "=r"(val)
: "0"(val));
권장
asm volatile("..."
: "+r"(val));
memory clobber 누락
asm volatile("mov %0, %%cr3" : : "r"(val));
수정
asm volatile("mov %0, %%cr3"
:
: "r"(val)
: "memory");
early-clobber 누락
asm("mul %2"
: "=r"(res)
: "0"(a), "r"(b));
수정
asm("mul %2"
: "=&r"(res)
: "0"(a), "r"(b));
8. constraint 선택 가이드 (실전용)
| 상황 | 추천 |
|---|---|
| 단순 계산 | "+r" |
| write-only output | "=r" |
| 입력과 같은 레지스터 필요 | "+r" |
| output이 먼저 덮어씀 | "=&r" |
| 메모리 접근 | "m" + "memory" |
| CPU flag 변경 | "cc" |
9. 커널 포팅 전략
벤더 커널 Clang 전환 시:
"0"패턴 →+r우선 검토- asm 에러 → early-clobber 의심
- 이상 동작 → memory clobber 확인
- ARM64 → IAS 문제 먼저 의심
10. 핵심 요약
Clang 포팅의 90%는 여기서 끝난다:
+r적극 사용- early-clobber 정확히 지정
- memory clobber 명확히 작성
- tied operand 남용 금지