리눅스는 인터프리터다
(astrid.tech)- initrd를 커널이 직접 해석하고 실행하는 프로그램 단위로 정의하며, Linux를 일종의 인터프리터로 재해석함
-
kexec,base64,cpio를 이용해 자기 자신을 재부팅하는 재귀형 Linux 배포판을 구성, initrd가 스스로를 다시 실행함 -
/init스크립트가 자신의 cpio 이미지를 출력하도록 하면 Quine 형태의 자기 복제 initrd가 형성됨 - ELF 실행 구조와
ld.so,binfmt_misc를 통해 인터프리터 계층이 커널까지 이어지는 구조를 설명함 -
kexec나 QEMU를 활용하면 Linux 위에서 또 다른 Linux를 꼬리 재귀적으로 실행할 수 있어, 커널·가상화·인터프리터의 경계를 실험적으로 확장함
rkx.gz 역공학과 자기 재귀형 initrd 구조
-
curl https://astrid.tech/rkx.gz | gunzip | sudo sh명령은 20MB 크기의 base64 인코딩된 셸 스크립트를 다운로드하고 실행함- 스크립트는 root 권한을 확인하고
kexec,base64,cpio의 존재를 검사 - base64 데이터를 디코딩해
r이라는 cpio 아카이브를 만들고, 그 안에서k라는 커널 이미지를 추출 -
kexec를 이용해k를 커널로,r을 램디스크로 로드 후 실행
- 스크립트는 root 권한을 확인하고
-
r.cpio내부에는/bin,/init,k파일이 포함되며,k는 Linux 6.18.18 커널 이미지,/init은 셸 스크립트 형태-
/init은/proc을 마운트하고,/r에 현재 파일 시스템을 cpio로 묶은 뒤kexec로/k와/r을 다시 실행 - 결과적으로 자기 자신을 계속 재부팅하는 재귀형 Linux 배포판이 됨
-
Linux 커널을 인터프리터로 보는 관점
- initrd는 단순한 부팅용 램디스크가 아니라, Linux 커널이 해석하고 실행하는 프로그램으로 볼 수 있음
-
curl | sh나python3 script.py처럼 initrd도 커널에 의해 실행되는 입력 프로그램 형태 - 따라서 Linux 커널은 initrd를 해석하는 인터프리터로 기능
-
- 이 구조는 꼬리 재귀 최적화(tail-call optimization) 와 유사함
-
kexec는 이전 커널을 덮어쓰지 않고 새로운 메모리 공간에 로드해 실행 - 각 커널은 이전 상태를 유지하지 않으며, 새로운 “스택 프레임”으로 교체됨
-
Quine과 initrd 자기 복제
- Quine은 자기 자신을 출력하는 프로그램을 의미
-
/init스크립트가 마지막에cat /r을 수행하도록 하면 자신과 동일한 cpio를 출력 - 이 경우 Linux initrd 인터프리터의 Quine이 형성됨
- 모든 파일이 RAM 상의
tmpfs에 존재하므로 실제 디스크 I/O는 발생하지 않음
-
ELF, ld.so, 그리고 인터프리터의 계층
- ELF 실행 파일은 헤더에 인터프리터(ld-linux-x86-64.so.2) 경로를 포함함
- 실행 시 커널은
ld.so를 먼저 실행하고,ld.so가 ELF의 동적 라이브러리를 로드 후 프로그램을 실행 - 따라서 ELF도 일종의 인터프리터 언어로 볼 수 있음
- 실행 시 커널은
-
/bin/sh는ld.so에 의해 해석되고,ld.so는 커널이 직접 해석-
ld.so는 정적 링크된 ELF이므로 커널이 직접 실행 가능 - 이로써 인터프리터 계층의 기저(base case) 가 형성됨
-
binfmt_misc를 통한 CPIO 실행
-
binfmt_misc를 이용하면 특정 매직 바이트를 가진 파일을 지정된 인터프리터로 실행 가능- 예시 등록 명령:
echo ':cpio:M::\x30\x37\x30\x37\x30\x31::/path/to/my/script.sh:' > /proc/sys/fs/binfmt_misc/register - 이 설정으로
chmod +x된 CPIO 파일을 직접 실행 가능
- 예시 등록 명령:
- QEMU를 이용해 CPIO를 initrd로 실행하는 스크립트를 인터프리터로 등록할 수 있음
- QEMU는 지정된 커널과 initrd를 사용해 가상 머신을 부팅
- 결과적으로 CPIO 파일의 인터프리터는 QEMU가 구동하는 Linux 커널이 됨
재귀적 인터프리터와 “가장 이상한 루프”
- QEMU 기반 인터프리터는 새로운 Linux 환경 스택 프레임을 생성
- Linux 위에서 또 다른 Linux를 실행하는 구조로, 메모리 한계까지 중첩 가능
-
kexec기반 인터프리터로 대체하면 꼬리 호출 최적화된 재귀형 Linux 실행이 가능
-
/init에서 binfmt_misc를 등록하고/r을 실행하도록 구성하면 자기 자신을 실행하는 initrd가 완성됨-
/r은 CPIO 포맷의 다음 init 프로세스이며, 실행 시 다시 자신을 해석
-
결론
- initrd는 단순한 부팅 도구가 아니라, Linux 커널이 해석하는 프로그램 단위
-
kexec와binfmt_misc를 이용하면 Linux 자체를 인터프리터처럼 재귀적으로 실행 가능 - 이 구조는 커널, 가상화, 인터프리터, 자기 복제 프로그램의 경계를 허무는 실험적 개념
- 관련 소스코드는 GitHub 저장소 ifd3f/rekexec에 공개됨
Hacker News 의견들
-
이 글을 읽으면서 너무 많은 오해 때문에 고통스러웠음
cpio 아카이브는 파일시스템이 아님. 글쓴이는 initramfs를 사용하는데, 이는 tmpfs 기반임. Linux는 cpio를 tmpfs로 추출할 수 있음. 파일과 디렉토리의 아카이브는 그 자체로 프로그램이 아님
어떤 것이 비슷하게 보인다고 해서 동일한 것은 아님. 바이너리 프로그램은 CPU에서 실행되며, 인터프리터가 있다면 그것은 하드웨어 환경에 숨어 있음. 이는 커널의 범위를 벗어남
쉘 스크립트를 실행하려면 그 스크립트를 해석할 쉘이 필요함. 글쓴이는 이 부분을 생략하고 커널과 쉘 프로그램을 혼동함
Linux는 initramfs나 ramdisk 없이도 컴파일 가능하며, 여전히 파일시스템의 유저랜드를 실행할 수 있음
“Linux initrd interpreter”라는 표현은 정말 잘못된 설명임- ELF 파일도 그 자체로는 프로그램이 아닐 수 있음. 일부 ELF는 동적 라이브러리로 엔트리포인트가 없기 때문임. ELF 중 일부가 실행 가능하듯, CPIO 중 일부도 실행 가능하다고 볼 수 있음. 결국 ld.so가 ELF를 메모리에 풀고 엔트리포인트를 실행하는 것과, 커널이 initramfs를 풀고 엔트리포인트를 실행하는 것은 유사한 개념임
- cpio 안의 init 파일이 실제로 해석되는 프로그램이며, 나머지 파일들은 그 프로그램이 사용할 메모리 역할을 함
- 바이너리 프로그램은 CPU에서 실행되지만, 프로그램 파일 자체는 여러 섹션으로 구성된 아카이브 구조임. CPU는 프로그램 파일을 직접 이해하지 못함. Linux는 프로그램이 실행될 주소 공간을 설정하고, 그 후 프로그램 카운터가 가리키는 주소로 점프함. ELF의 메타데이터 섹션이 이 과정을 정의함
- 적어도 AI가 쓴 글은 아니라는 점이 위안임
-
모든 OS는 커널 권한으로 머신 코드 인터프리터 역할을 하는 것 아님?
- 아니라고 생각함. OS는 각 명령어를 직접 해석하지 않고, CPU에 넘겨서 실행시킴
- OS는 시스템 자원을 사용할 수 있게 하는 인터페이스임. CPU가 머신 코드를 해석하고, OS는 CPU가 무엇을 실행할지 지시할 수 있음
- 이 경우에는 CPIO 파일을 위한 인터프리터라고 볼 수 있음
-
이 글은 “Linux는 인터프리터다”라는 정신적 모델로 보면 괜찮지만, 문자 그대로 받아들이면 틀림
CPU 명령어 수준에서의 해석이 아니라, 커널이 ELF, shebang 스크립트, initramfs 같은 실행 형식을 조율하는 역할로 보면 더 타당함. 혼란은 ‘인터프리터’의 두 가지 의미가 섞인 데서 비롯된 듯함 -
핵심은 비유가 맞느냐가 아니라, ‘실행’이라는 개념이 얼마나 환경에 의존적인가를 보여준다는 점임
-
“모든 것은 인터프리터다?”
- 그렇지만 컴파일러는 예외임
-
Turing의 Theta Combinator
- 그게 이 글과 어떤 관련이 있는지 잘 모르겠음. 함수형 프로그래밍 개념에 익숙하지 않음
-
시리즈의 이전 글에서, 글쓴이는 Contabo의 오브젝트 스토리지를 쓰기 싫어서 직접 VPS 이미지를 만들었다고 함
월 1.50달러를 아끼려 50시간을 쓰는 것과, 25만 달러를 토큰에 쓰는 극단 사이에 균형점이 있다고 생각함.
인프라 비용을 감당 못 한다면, 기술력보다 사회적 요인이 문제일 수도 있음. Doom을 curl로 돌리는 데 집착하는 건 생산적이지 않다고 느낌- 나도 예전에 그랬음. VPS 월 5유로가 너무 비싸서, 돈이 모일 때까지 인스턴스를 종료하고 루트 파일시스템을 엄마 노트북에 백업하곤 했음. 나중엔 Kindle에 Terminal IDE를 깔아 busybox와 gcc로 놀았음. Spartacus Rex에게 커리어의 시작을 만들어줘서 감사함
- 글쓴이의 말은 농담이었음. 실제 이유는 바로 다음 문단에 있음 — “재미있는 트릭이라 생각했고, 블로그에 올리면 나도 배우고 독자도 배우고 인터넷 포인트도 얻는 win-win이라 생각했음”
- 어떤 사람에게는 비생산적으로 보여도, 특별한 관심사를 즐기는 건 정신 건강에 중요함. ADHD인 나에게는 오히려 꼭 필요한 활동임
- “1.50달러를 못 내면 프로가 아니다”라는 말은 이상함. 프로페셔널은 돈을 받느냐로 정의되는 것이지, 지출로 정의되는 게 아님
-
man ld.so를 보면, ELF의.interp섹션에 저장된 동적 링커가 실행된다고 명시되어 있음. 섹션 이름 자체가 흥미로움 -
Linux는 프로그래머블 인터페이스로서 매우 유용함. Windows도 가능하지만, Linux가 더 적합하다고 느낌
GUI는 Windows가 낫다고 생각하지만, GNOME이나 KDE도 불편함. 그래서 fluxbox, icewm, 때로는 xfce나 mate-desktop을 씀. 요즘은 단순하고 빠른 환경을 선호함. 대부분의 작업은 커맨드라인과 코드 편집으로 처리함- 빠르고 단순한 환경을 원한다면 Sway + foot 조합이 좋음. 키바인드로 워크스페이스를 구성하면 데스크탑 없이도 쾌적하게 쓸 수 있음
- Windows GUI가 낫다는 건 동의 못함. GNOME, KDE도 별로지만 Windows는 Microsoft의 복잡한 WM에서 벗어날 수 없음. 개인적으로는 Xerox 계열보다 mpx/mux 계열 인터페이스(예: 9wm, cwm, dwm)가 훨씬 낫다고 생각함. Engelbart의 철학에 더 가깝고 전반적으로 더 깔끔함