Making Linux Binaries Load Local .so Libraries Automatically
리눅스에서 “실행 파일 옆의 .so를 자동으로 찾게” 만드는 핵심은 ELF rpath/runpath의 $ORIGIN 토큰이다.
Hun Jang Dec 5, 2025
$ORIGIN으로 이식성 높은 바이너리 만들기
- ELF 바이너리는 필요한 공유 라이브러리를 동적 로더(
ld.so)가 찾는다.
- 기본 탐색 경로는
LD_LIBRARY_PATH→DT_RUNPATH/DT_RPATH→ 시스템 디렉터리 순서로 이뤄진다(세부 동작은 아래 참고).
$ORIGIN은 현재 로드되는 객체(실행 파일 또는 .so) 파일이 있는 디렉터리를 의미한다. 그래서 배포 폴더 안에bin/과lib/만 있으면 시스템에 설치 없이도 실행 가능해진다.
빌드 시 설정(권장)
- 작은따옴표로 감싸 셸이
$ORIGIN을 확장하지 않도록 한다.
- 여러 경로를 넣으려면
Wl,-rpath,'$ORIGIN/../lib:$ORIGIN'.
빌드 후 수정(이미 만들어진 바이너리)
chrpath도 가능하지만 DT_RUNPATH를 다루기엔 patchelf가 더 범용적이다.
rpath vs runpath 한 줄 정리
- RUNPATH(DT_RUNPATH): 현대적 방식.
LD_LIBRARY_PATH가 먼저 적용되고 그다음 RUNPATH가 적용된다.
- RPATH(DT_RPATH): 구식. 있을 때는 종종
LD_LIBRARY_PATH보다 우선되어 예상치 못한 탐색 순서를 만들 수 있다.
- 최신 툴체인은 기본적으로 RUNPATH를 쓴다. 필요하면
-disable-new-dtags로 RPATH를 강제할 수 있다. 일반 배포는 RUNPATH 유지가 안전하다.
디버깅 팁
구조 예시(셀프 컨테인드 배포)
자주 겪는 함정
- 따옴표 누락:
Wl,-rpath,$ORIGIN/../lib로 쓰면 셸이$ORIGIN을 빈 문자열로 바꿔버린다.
- 심볼릭 링크/SONAME 불일치:
libmylib.so → libmylib.so.1및SONAME을 맞춰야 런타임 로딩이 깔끔하다.
- setuid 바이너리: 보안상
$ORIGIN/LD_LIBRARY_PATH가 무시될 수 있다.
- 컨테이너/서로 다른 배포판: GLIBC 최소 버전 차이로 로딩 실패 가능 → 가능한 한 낮은 빌드 베이스로 컴파일하거나 정적 링크 후보를 검토.