512바이트 부트 섹터에 C 컴파일러를 구겨 넣는 광기: SectorC 분석


요즘 엔지니어링 씬을 보면 한숨이 나올 때가 있습니다. “Hello World” 하나 띄우는데 수백 메가바이트짜리 Docker 이미지를 굽고, 간단한 웹앱 하나에 node_modules가 블랙홀처럼 불어나는 세상이니까요. 자원의 풍요가 오히려 엔지니어링의 본질인 ‘최적화’와 ‘효율’을 갉아먹고 있는 건 아닌가 하는 생각이 들던 찰나, 제 도파민을 자극하는 프로젝트를 하나 발견했습니다.

바로 SectorC 입니다. x86-16 부트 섹터, 즉 단 512바이트 안에 들어가는 C 컴파일러입니다. 512 킬로바이트가 아니라, 바이트입니다.

처음엔 “장난치나?” 싶었습니다. C 언어의 Lexer(어휘 분석기)만 짜도 512바이트는 훌쩍 넘길 텐데, 파서와 코드 제너레이터까지 넣었다니요. 오늘은 이 미친 프로젝트가 어떻게 불가능을 가능으로 바꿨는지, 그 기술적 깊이를 파헤쳐 보겠습니다.

불가능에 도전하는 512바이트의 제약

이 프로젝트의 저자인 xorvoid는 단순히 코드를 줄인 게 아니라, 컴파일러의 구조 자체를 재정의했습니다. 일반적인 컴파일러 개론 책에 나오는 방식으로는 절대 불가능한 크기입니다.

1. Lexer를 없애버린 천재적인 꼼수: atoi 해싱

컴파일러를 만들 때 가장 먼저 부딪히는 벽은 소스 코드를 토큰화하는 과정입니다. int, if, while 같은 키워드를 식별하고 변수명을 파싱해야 하죠. 저자는 여기서 Big Insight 를 얻습니다.

atoi() 함수는 문자열을 정수로 바꾼다. 그렇다면 이걸 해시 함수로 쓰면 어떨까?”

이게 무슨 소리냐면, 소스 코드에 있는 모든 문자열(키워드, 변수명 등)을 atoi()를 통해 그냥 숫자로 변환해 버린다는 겁니다. int라는 문자열을 읽어서 TOKEN_KEYWORD_INT로 매핑하는 게 아니라, int라는 텍스트 자체가 atoi를 통과하면서 고유한(혹은 고유하다고 믿는) 16비트 정수값이 됩니다.

  • 변수명: 별도의 심볼 테이블(Symbol Table)에 문자열을 저장하지 않습니다. 변수명의 해시값을 오프셋으로 사용하여 64K 메모리 세그먼트의 특정 주소를 가리키게 합니다.
  • 충돌(Collision): 당연히 해시 충돌이 발생할 수 있습니다. 하지만 저자는 쿨하게 이 문제를 무시합니다. “어차피 512바이트 컴파일러인데, 충돌 나면 변수명 바꾸면 그만이지”라는 태도죠. 이 지점이 바로 엔지니어링의 트레이드오프를 극단적으로 보여주는 부분입니다.

2. Forth에서 훔쳐온 아이디어, 그리고 실패

저자는 처음에 Forth 언어의 Threaded Code 방식을 차용하려 했습니다. 2바이트 정렬을 이용해 명령어들을 1바이트로 압축하려는 시도였죠. next, enter 같은 루틴을 만들어서 바이트코드를 실행하려 했으나, 결과적으로는 오버헤드 때문에 실패했습니다.

저는 이 실패 기록이 성공담보다 더 흥미로웠습니다. 시니어 엔지니어라면 알겠지만, 최적화 과정에서 ‘우아한 추상화’가 오히려 독이 되는 경우가 많습니다. 결국 저자는 가장 원초적인 x86 어셈블리 최적화로 회귀합니다.

  • jmp 대신 Fall-through(그냥 다음 줄로 실행 흐름이 넘어가게 함) 활용
  • call 대신 jmp를 이용한 Tail-call 최적화
  • stosw, lodsw 같은 x86 문자열 처리 명령어의 적극적 활용

이게 진짜 C 언어가 맞나?

“C 컴파일러”라고 주장하지만, 엄밀히 말하면 Barely C 라고 부르는 게 맞습니다. 하지만 놀랍게도 튜링 완전(Turing-complete)하며 꽤 복잡한 로직도 소화합니다.

  • 전역 변수, 함수 정의, if, while 지원
  • 포인터 역참조(*), 각종 연산자(+, -, <<, == 등) 지원
  • 인라인 머신 코드(asm) 지원

특히 인라인 asm 지원은 신의 한 수입니다. I/O가 없는 언어는 껍데기에 불과한데, asm 구문을 통해 BIOS 인터럽트를 직접 호출하여 화면에 픽셀을 찍거나 PC 스피커로 소리를 낼 수 있게 만들었습니다. 실제로 예제 코드에는 사인파(Sine wave)를 그리는 로직이 포함되어 있습니다.

(위의 Base64 코드가 컴파일러의 전부입니다. 아름답지 않나요?)

Hacker News의 반응: “이게 진짜 낭만이지”

이 프로젝트가 공개되자마자 Hacker News는 뜨겁게 달아올랐습니다. 저와 비슷한 연배의 엔지니어들은 80년대 부트 섹터 게임을 만들던 시절의 향수를 느끼고 있습니다.

“AI 시대가 이런 프로젝트들의 가치를 떨어뜨리는 것 같아 아쉽다. 예전엔 프로그래밍이 진짜 스킬을 보여주는 재미가 있었는데.”

특히 최근 화제가 된 Claude가 작성한 10만 라인짜리 C 컴파일러 와 비교하는 댓글들이 인상적입니다. AI가 짠 수만 라인의 코드보다, 인간이 극한의 제약 속에서 깎아낸 512바이트가 훨씬 더 ‘엔지니어링’스럽다는 의견이 지배적입니다. 물론 Claude의 컴파일러는 리눅스 커널을 빌드할 수 있겠지만, SectorC가 주는 지적 쾌감과는 비교할 수 없죠.

한 유저는 atoi 해싱 트릭을 보며 이렇게 말했습니다.

“만약 이 구현이 1980년대에 나왔다면, C 표준 위원회는 ‘해시 충돌이 나는 토큰은 Undefined Behavior(UB)다’라는 규칙을 만들었을 것이다.”

결론: Bloatware 시대에 던지는 경종

SectorC는 실무에서 쓸 수 있는 물건은 아닙니다. 에러 핸들링? 없습니다. 코드 안전성? 기대하지 마세요. 하지만 이 프로젝트는 우리에게 중요한 질문을 던집니다.

“우리는 정말 필요한 코드를 작성하고 있는가?”

최신 프레임워크와 라이브러리 뒤에 숨어서, 컴퓨터가 실제로 어떻게 도는지 잊어버린 채 ‘조립’만 하고 있는 건 아닌지 반성하게 됩니다. 가끔은 이렇게 밑바닥까지 내려가서, 바이트 단위로 비트를 쥐어짜는 야생의 코딩을 즐겨보는 것도 엔지니어로서의 감각을 날카롭게 유지하는 좋은 방법이라 생각합니다.

이번 주말에는 무거운 IDE 대신, 헥스 에디터(Hex Editor)를 한번 켜보시는 건 어떨까요?

References: