TECH 으로 돌아가기
TECH HACKER NEWS 오늘 6분 읽기 27 READS

리눅스 커널이 드디어 $ORIGIN을 (어느 정도) 지원합니다 — '옮기면 안 도는 바이너리'의 오랜 숙제

리눅스에서 잘 돌던 프로그램을 통째로 복사해서 다른 서버에 옮겼더니 실행이 안 되는 경험, 한 번쯤 있으실 텐데요. 심지어 에러 메시지가 'No such file or directory'라서 더 황당하죠. 파일이 분명 눈앞에 있는데 없다니요. 이게 사실 실행 파일이 아니라 동적 링커의 경로 문제인 경우가 많거든요. 오늘 소개할 소식은 이 오래된 숙제를 리눅스 커널 차원에서 풀어주는 변화가 들어오고 있다는 이야기예요.

바이너리 하나가 실행되기까지

터미널에서 ./myapp을 실행하면 무슨 일이 벌어지는지부터 볼게요. 커널이 execve라는 시스템 콜을 처리하면서 파일의 ELF 헤더(리눅스 실행 파일의 표준 형식)를 읽어요. 동적 링킹된 바이너리에는 PT_INTERP라는 항목에 '인터프리터'의 경로가 적혀 있는데요. 여기서 인터프리터는 파이썬 같은 게 아니라 동적 링커, 보통 /lib64/ld-linux-x86-64.so.2라는 절대 경로예요. 커널은 우리 프로그램보다 이 링커를 먼저 메모리에 올리고, 링커가 libc 같은 공유 라이브러리들을 찾아 연결해준 다음에야 main이 실행돼요. 그러니까 모든 동적 링킹 프로그램은 실행될 때마다 이 하드코딩된 경로에 의존하고 있는 셈이죠.

$ORIGIN이 뭐냐면

라이브러리를 찾는 단계에는 이미 좋은 해법이 있어요. 동적 링커는 바이너리에 기록된 RPATH나 RUNPATH라는 목록을 보고 라이브러리를 찾는데, 여기에 $ORIGIN이라는 특수 토큰을 쓸 수 있거든요. 뜻은 '지금 실행되는 바이너리가 놓여 있는 바로 그 디렉터리'예요. 그래서 myapp과 libfoo.so를 같은 폴더에 넣고 RUNPATH를 $ORIGIN으로 잡아두면, 그 폴더를 어디로 옮기든 라이브러리는 잘 찾아요. 그런데 문제는 그 앞 단계예요. PT_INTERP에 적힌 동적 링커 경로는 커널이 직접 해석하는데, 커널은 지금까지 $ORIGIN을 전혀 몰랐거든요. 절대 경로만 받아줬죠. 그래서 glibc 버전이 다른 배포판이나, NixOS처럼 /lib64 같은 표준 경로 자체가 없는 시스템에서는 바이너리가 아예 시작조차 못 했어요. 아까 그 황당한 에러의 정체가 이거예요. 없는 건 실행 파일이 아니라 /lib64/ld-linux였던 거죠.

지금까지의 우회책들

이 문제를 피하려고 생태계는 온갖 방법을 써왔어요. patchelf라는 도구로 배포 후에 PT_INTERP 경로를 뜯어고치기도 하고, Nix는 아예 빌드 시점에 /nix/store 아래의 고정된 절대 경로를 박아 넣는 방식으로 재현성을 확보했죠. AppImage 같은 포터블 앱 포맷은 자체 실행 로직으로 이 단계를 우회하고, 애초에 musl로 정적 링킹해서 동적 링커 자체를 없애버리는 선택지도 있어요. Go나 Rust로 만든 CLI 도구들이 배포하기 편하다고 사랑받는 이유 중 하나도 정적 링킹으로 이 문제를 피해 가기 때문이거든요. 다 되긴 하는데, 하나같이 추가 도구나 빌드 제약이 따라붙는 우회로였어요.

이번 변화, 그리고 'sort of'인 이유

원문 제목에 'sort of', 그러니까 '어느 정도는'이라는 단서가 붙은 이유가 있는데요. 커널이 동적 링커처럼 $ORIGIN이라는 문자열을 완전히 똑같이 확장해주는 게 아니라, 인터프리터 경로를 실행 파일의 위치를 기준으로 해석할 수 있게 해주는, 말하자면 $ORIGIN의 취지를 제한된 형태로 구현한 변화이기 때문이에요. 문법적으로 완전한 호환은 아니지만, 실용적으로 가장 중요한 시나리오는 뚫리는 거죠. 바이너리와 동적 링커, 라이브러리를 한 폴더에 담아서 tar로 묶으면, 압축을 푼 위치가 어디든 그대로 실행되는 진짜 '들고 다닐 수 있는' 리눅스 프로그램이 가능해지는 거예요.

우리한테 뭐가 달라지나

당장 내일부터 쓸 수 있는 기능은 아니에요. 커널에 변화가 들어와도 배포판에 퍼지고 툴체인이 활용하기까지는 시간이 걸리니까요. 하지만 방향성은 분명해요. 사내 CLI 도구나 에이전트를 여러 서버에 배포할 때 지금은 '도커에 넣거나, 정적 링킹하거나, 각 배포판별로 빌드하거나' 중에 골라야 하는데, 앞으로는 tarball 하나로 끝나는 선택지가 생기는 거거든요. Nix나 Bazel처럼 재현 가능한 빌드를 지향하는 생태계에도 반가운 소식이고요. 컨테이너가 해결해주던 문제의 일부를 훨씬 가벼운 방법으로 풀 수 있게 되는 셈이에요.

정리하면, 리눅스 바이너리가 특정 시스템 경로에 묶여 있던 마지막 사슬 하나가 느슨해지고 있다는 소식이에요. 여러분은 리눅스용 도구를 배포할 때 어떤 방법을 쓰세요? 도커, 정적 링킹, 배포판별 패키징 중에서 뭐가 제일 덜 고통스러우셨는지 궁금하네요.


🔗 출처: Hacker News

SOURCE · HACKER NEWS
원문 전체 보기 → https://fzakaria.com/2026/07/20/linux-kernel-will-support-or...
SHARE
처리 중...