Linux ELF 실행 파일이 있는데 ENOENT가 날 때 PT_INTERP 확인하기
Linux 실행 파일이 존재하고 실행 권한도 있는데 ENOENT가 날 때, readelf로 ELF 인터프리터 경로를 확인하고 빌드·런타임을 맞춘다.
Linux에서 ELF 실행 파일이 존재하고 실행 권한도 있는데 No such file or directory가 나오면 readelf -lW ./app에서 프로그램 인터프리터 경로를 확인한다. 동적 링크된 ELF가 요구하는 로더가 실행 환경에 없으면 커널은 실행 파일이 있어도 ENOENT를 반환할 수 있다. 컨테이너나 다른 배포판으로 바이너리를 옮겼을 때 이 상황을 진단하는 방법을 로컬 예제로 확인한다.
청록색 실행 모듈 옆에 주황색 테두리의 빈 슬롯이 있는 일러스트
커널이 실행 파일을 열고도 ENOENT를 반환하는 이유
동적 링크된 ELF에는 프로그램 헤더의 PT_INTERP에 인터프리터 경로가 들어간다. 커널은 실행 과정에서 그 경로의 로더를 연다. execve(2)의 ENOENT는 실행 대상 경로가 없을 때뿐 아니라 ELF 인터프리터 또는 스크립트 인터프리터가 없을 때도 발생한다. 경로와 실행 권한을 확인한 뒤에도 문제가 남으면 바이너리가 요구하는 인터프리터를 확인한다. Linux execve(2) · ELF 형식
로더 경로와 아키텍처 확인하기
readelf -hW ./app의Machine을 확인한다. 의도한 대상 아키텍처와 비교하고, 호스트와 다른 아키텍처라면 실행 환경에 해당 에뮬레이션이 구성됐는지 확인한다.
readelf -lW ./app에서INTERP와Requesting program interpreter줄을 찾는다. 표시된 절대 경로가 실제 실행 환경에서 유효한지 확인한다. 컨테이너를 쓴다면 최종 이미지의 파일시스템을 기준으로 확인하며, 심볼릭 링크라면 대상까지 확인한다.
- 로더가 있는 상태에서 특정 공유 라이브러리 이름이 오류에 나타나면
readelf -dW ./app의NEEDED항목과 로더의 검색 경로를 확인한다.NEEDED는 바이너리의 직접 의존성이므로, 공유 라이브러리가 요구하는 추가 의존성도 따로 확인할 수 있다. GNU readelf 문서 · Linux ld.so(8)
존재하는 파일로 ENOENT 재현하기
아래 예제는 같은 C 소스로 두 바이너리를 만든다. 두 번째 바이너리에는 GNU 링커 옵션으로 임시 디렉터리 안의 존재하지 않는 로더를 지정한다. Python 3, GCC, GNU 링커와 readelf가 있는 Linux에서 elf_loader_demo.py로 저장해 python3 elf_loader_demo.py를 실행한다. GNU ld 옵션
2026년 11월 13일 Linux x86-64에서 Python 3.12.14, GCC 14.2.0, GNU Binutils 2.44로 실행했다. 첫 바이너리는 정상적으로 출력했고, 두 번째 바이너리는 파일과 실행 권한이 모두 있는 상태에서 ENOENT로 실패했다.
빌드 환경과 실행 환경 맞추기
배포 시 바이너리를 빌드한 아키텍처와 libc 계열에 맞는 런타임을 선택하고, 필요한 공유 라이브러리를 포함한다. glibc용 바이너리를 musl 기반 이미지로 옮기는 경우에는 목적 환경용으로 다시 빌드하거나 호환되는 런타임을 선택한다. 로더 파일명만 맞춰도 libc나 공유 라이브러리의 ABI가 다르면 실행에 실패할 수 있다. 정적 링크를 지원하는 프로그램이라면 정적 산출물을 검토하고 PT_INTERP 유무와 실제 동작을 확인한다. Linux ld.so(8) · ELF 형식
예제는 로컬에서 ELF 로더가 없는 경우를 검증했다. 컨테이너, 정적 빌드, 다른 아키텍처에서의 실행은 실험 범위에서 제외했다.
English version ·
Linux ELF Binary Exists but Returns ENOENT? Check PT_INTERP