메인라인 커널은 이미 Clang / LLVM 빌드를 공식 지원한다.
하지만 SoC 벤더 커널(특히 4.x/5.4 계열)이나 오래된 BSP 트리는 여전히 GCC 전용 코드가 많다.
리눅스 커널 Clang 빌드 호환성은 아래 글에서 대략의 타임라인을 확인할 수 있다.
이 글에서는 GCC에서는 되는데 Clang에서 깨지는 대표 패턴을 유형별로 정리한다.
실전에서 가장 자주 마주치는 것들만 모았다.
Clang 빌드 적용시 깨지는 지점은 대체로 4군데다.
- inline asm
- GCC 전용 확장 문법
- section / attribute 처리
- 링커(ld.lld) 차이
1. Inline Assembly (가장 많이 깨짐)
1-1. 잘못된 constraint 사용
GCC 전용 패턴
asm volatile("..." : "=r"(val) : "0"(val));- GCC는 느슨하게 허용
- Clang은 constraint mismatch에 엄격
해결 방향
- constraint 명확히 지정
"=r"/"r"분리- early-clobber (
"=&r") 필요한지 확인
1-2. clobber 누락
asm volatile("mov %0, %%cr3" : : "r"(val));Clang은 memory clobber 누락을 더 잘 잡는다.
수정
asm volatile("mov %0, %%cr3" : : "r"(val) : "memory");1-3. Integrated Assembler 문제
Clang 기본은 IAS(통합 어셈블러)다.
GCC 빌드에서 GNU as에 의존하던 코드가 깨질 수 있다.
임시 해결
make LLVM=1 LLVM_IAS=0
그러나 근본 해결은
.S문법을 GNU as 의존에서 벗어나게 수정.arch,.syntaxdirective 점검
2. GCC 전용 확장 문법
2-1. Statement Expression 남용
#define foo(x) ({ int y = x; y + 1; })Clang도 지원하지만 복잡한 nested 매크로에서 깨지는 경우 있음.
2-2. typeof + 비표준 패턴
typeof(a) b;Clang은 __typeof__ 형태를 선호.
안전한 형태
__typeof__(a) b;2-3. asm goto 미지원 구버전
오래된 Clang에서는 asm goto 지원이 미흡했다.
벤더 커널이 4.x 계열이면 문제 발생 가능.
3. section / attribute 관련 문제
3-1. section attribute 정렬 문제
__attribute__((section(".my_section")))Clang은 alignment 요구가 엄격하다.
해결
__attribute__((section(".my_section"), aligned(8)))3-2. weak symbol 처리 차이
GCC는 관대
Clang은 duplicate weak symbol에서 에러 발생 가능
특히:
- 드라이버
- vendor HAL
에서 자주 발생
4. 링커(ld.lld) 차이
4-1. undefined symbol 처리
ld.bfd는 느슨하게 넘어가는 경우가 있다.
ld.lld는 바로 실패한다.
ld.lld: error: undefined symbol: foo
이 경우는 실제로 코드가 잘못된 경우가 많다.
4-2. orphan section 처리 차이
벤더 링크 스크립트가 오래된 경우
warning: orphan section `.init.something`
ld.lld는 섹션 정렬/배치 규칙이 더 엄격하다.
5. volatile / memory barrier 관련 차이
Clang은 최적화가 더 공격적이다.
GCC에서 “우연히” 동작하던 코드가
- barrier 누락
- READ_ONCE/WRITE_ONCE 누락
때문에 동작이 바뀌는 경우 있다.
➡️ Clang으로 옮기면서 숨어 있던 메모리 버그가 드러나는 경우가 많다.
6. LTO 활성화 시 추가 문제
벤더 커널은 LTO 전제를 두고 작성되지 않은 경우가 많다.
깨지는 대표 패턴:
- static 함수가 최적화로 제거됨
- inline 함수 visibility 문제
- asm symbol name mismatch
7. BTF / pahole 연계 문제
Clang + BTF에서 깨지는 경우:
- 오래된 pahole
- struct layout 가정 코드
- packed struct alignment 문제
8. 실제 포팅 전략 (현실적인 접근)
벤더 커널을 Clang으로 옮길 때는 이렇게 간다.
1단계
- LTO 끄기
- IAS 끄기
- BTF 끄기
make LLVM=1 LLVM_IAS=0
2단계
- inline asm 수정
- attribute 정리
- section 정렬 맞추기
3단계
- IAS 다시 켜기
- BTF 켜기
- sanitizer 적용
9. 가장 자주 깨지는 TOP 5 요약
- inline asm constraint 문제
- GNU as 전용 문법
- section alignment 누락
- ld.lld의 엄격한 undefined symbol 처리
- memory barrier 누락 코드
10. 결론
벤더 커널이 Clang에서 깨진다는 건
Clang이 이상해서가 아니라
GCC가 너무 관대했기 때문인 경우가 많다.
Clang 전환은 단순한 컴파일러 교체가 아니라
- 코드 품질 개선
- 숨은 버그 노출
- 장기 유지보수성 확보
의 과정에 가깝다.
참고
- Linux kernel – Clang/LLVM 빌드 문서
https://docs.kernel.org/kbuild/llvm.html - ClangBuiltLinux
https://github.com/clangbuiltlinux - LLVM Inline Assembly 문서
https://llvm.org/docs/InlineAsm.html