1P by GN⁺ 20시간전 | ★ favorite | 댓글 1개
  • x86-16 어셈블리로 작성된 SectorC는 x86 머신의 부트 섹터(512바이트) 안에 들어가는 초소형 C 컴파일러로, 실제 동작 가능한 프로그램을 작성할 수 있을 만큼의 C 언어 부분집합을 지원함
  • 전역 변수, 함수, if/while 문, 연산자, 포인터 역참조, 주석, 인라인 어셈블리 등을 포함해, 최소한의 구조로도 완전한 프로그램 실행이 가능함
  • 토크나이저를 단순화하기 위해 공백 기반 토큰화atoi() 해시를 이용한 Barely C 언어를 설계, 기존 C 문법을 유지하면서도 극단적인 크기 절감을 달성함
  • 코드 최적화 과정에서 점프 제거, 호출 병합, 8비트 오프셋 활용, stosw/lodsw 사용 등 다양한 어셈블리 수준의 압축 기법을 적용해 468바이트에서 303바이트로 축소함
  • 결과적으로 512바이트 안에서 토크나이저, 파서, 코드 생성기, 런타임을 모두 포함한 완전한 C 컴파일러를 구현, 소프트웨어 최소화의 극단적 사례를 보여줌

SectorC 개요

  • SectorC는 x86-16 어셈블리로 작성된 C 컴파일러로, 512바이트 부트 섹터 안에 완전히 들어감
    • GitHub 저장소는 xorvoid/sectorc
    • 지원 언어는 실제 프로그램 작성이 가능한 수준의 C 부분집합
  • 지원 기능에는 전역 변수, 함수, 제어문(if/while), 다양한 연산자, 포인터 역참조, 인라인 어셈블리, 주석 등이 포함됨
  • 예시 프로그램으로 VGA 모드에서 사인파 애니메이션을 그리는 코드가 제시됨

설계 배경과 접근 방식

  • 기존 C 토크나이저는 512바이트로는 불가능할 정도로 크기 때문에, 언어 구조 자체를 단순화해야 했음
  • Big Insight #1: Forth 언어처럼 공백으로 구분된 토큰 구조를 도입해 “Barely C”라는 변형 언어를 설계
    • 예: int(main)(){while(!done){ 같은 구문을 하나의 “메가 토큰”으로 처리
    • 기존 C 컴파일러에서도 여전히 유효한 C 코드로 인식됨
  • Big Insight #2: atoi() 함수를 해시 함수처럼 사용해 토큰을 숫자로 변환
    • 정수 리터럴, 키워드, 식별자를 모두 atoi() 결과값으로 처리
    • 식별자는 64K 배열의 인덱스로 접근

Barely C 구현

  • 첫 구현은 468바이트로, atoi 기반 토큰을 사용하는 재귀 하강 파서 구조
    • 심볼 테이블 없이 64K 세그먼트를 해시값으로 직접 접근
    • 코드 생성은 OTCC 스타일로 ax 레지스터를 결과 저장소로 사용
  • 이후 바이트 스레드 코드(byte-threaded code) 실험을 통해 Forth식 구조를 시도했으나, 512바이트 내에서는 오히려 비효율적이어서 폐기됨

코드 최소화 기법

  • 직선적 구조로 돌아가 468바이트 → 303바이트로 축소
    • 점프 제거(fall-through) , tail-call, 호출 병합(call fusion) , stosw/lodsw 활용, 8비트 점프 오프셋 유지 등의 기법 사용
  • 207바이트 여유 공간을 확보해 추가 기능을 구현

완전한 C 기능 확장

  • 200바이트 추가로 완전한 C 문법 지원 달성
    • 중첩된 if/while 블록, 다양한 *이항 연산자(+, -, , &, |, ^, <<, >>, ==, !=, <, >, <=, >=)
    • 함수 정의 및 재귀 호출, 인라인 어셈블리(asm) , 한 줄/여러 줄 주석 지원
    • 연산자 테이블(binary_oper_tbl)을 통해 각 연산자를 4바이트로 정의, 14개 연산자를 56바이트로 처리

문법 구조

  • 전체 문법은 program, var_decl, func_decl, statement, expr 등으로 구성
  • ///* */ 주석 모두 지원
  • 문법 정의 텍스트 자체가 704바이트로, 실제 구현보다 큼

인라인 어셈블리와 런타임

  • asm 구문을 통해 x86-16 기계어를 직접 삽입 가능
    • I/O 처리를 위해 필수적인 기능
  • 런타임(rt/)은 C로 작성된 두 파일로 구성
    • rt/lib.c: 인라인 어셈블리 기반 라이브러리 루틴
    • rt/_start.c: 프로그램 진입점 _start()

예제 프로그램

  • examples/hello.c: 텍스트를 0xB8000 메모리에 직접 출력
  • examples/sinwave.c: VGA 모드 0x13에서 사인파 애니메이션 표시
  • examples/twinkle.c: PC 스피커로 “Twinkle Twinkle Little Star” 연주 (소리 경고 포함)

결론

  • SectorC는 불가능해 보이는 목표를 실현한 초소형 C 컴파일러로,
    소프트웨어 최소화와 창의적 언어 설계의 극단적 사례를 보여줌
  • 글의 마지막은 유머러스한 “무엇을 배웠는가” 선택지로 마무리되며,
    불가능에 도전하는 태도와 소프트웨어 단순화의 가치를 풍자적으로 강조함
Hacker News 의견들
  • 만약 이런 구현이 1980년대에 존재했다면, C 표준에는 서로 다른 토큰이 같은 16비트 값으로 해시 충돌을 일으킬 경우 정의되지 않은 동작(UB)을 유발한다는 규칙이 생겼을 것 같음
    2000년대의 최적화 컴파일러들은 그런 토큰을 그냥 no-op으로 최적화해버렸을지도 모름 😉
    • “너는 -wTokenHashCollision 옵션을 켜지 않았잖아! 네 무지 때문에 UB가 발생한 거야. 명세는 완벽히 명확함!” 이라며 농담 섞인 반응을 남김
    • 너무 현실적이라 웃음이 터졌음. LMAO
  • 최근 내가 만든 X86-16 부트 섹터 C 컴파일러와 비슷해 보임
    부트 섹터 게임을 만드는 건 정말 향수를 자극하는 마법 같은 경험임. 프로그래밍이 진짜 재미있던 시절이 떠오름
    요즘 AI 시대에는 이런 프로젝트들이 너무 저평가되는 게 아쉬움
    내 프로젝트 링크
    • 음, 글에서 다루는 건 완전한 C가 아닌, 512바이트 안에 들어가는 C 유사 언어 컴파일러
      네 프로젝트는 부트 섹터용 코드를 생성할 수 있는 옵션이 있는 것 같음.
      둘 다 흥미롭지만, 공통점은 ‘boot sector’, ‘C’, ‘compiler’ 정도뿐임
    • “프로그래밍이 진짜 재미있던 시절”이라는 말에 공감하지만, 이제는 더 많은 사람들이 같은 걸 할 수 있게 되었음
      그래서 더 이상 내가 특별하지 않다는 생각이 듦
  • 이런 프로젝트는 현대 개발이 얼마나 하드웨어로부터 멀어졌는지를 상기시켜줌
    우리는 추상화를 계속 쌓아올려서 “Hello World” 하나 돌리는데도 200MB의 node_modules가 필요함
    그런데 누군가는 512바이트 안에 C 컴파일러를 넣음
    모두가 부트 섹터 코드를 써야 한다는 건 아니지만, 이런 프로젝트를 읽는 건 정말 겸손해지는 경험임. 교육적인 가치도 큼
  • 내가 바로 이 프로젝트의 작성자일지도 모름. 만드는 과정이 정말 즐거웠음!
    • 정말 멋짐. 나도 미니멀한 C 컴파일러를 만들고 있는데, 부트 섹터에 맞추는 게 아니라 8비트 시스템을 목표로 함
      이 프로젝트는 C의 핵심 구조가 얼마나 단순한지 잘 보여줌.
      C가 B 언어에서, 그리고 B가 Fortran의 축소판에서 발전했다는 점이 흥미로움
    • if, while, for를 단순한 goto 루틴으로 바꾸면 얼마나 더 작아질지 궁금함
      어셈블리에는 결국 jmp밖에 없으니까 말임.
      그리고 “choose your own adventure”가 아니라 “chose your own adventure”라고 해야 함 :)
      나는 미니멀리즘을 사랑함
    • 이 컴파일러나 ‘barely-C’ 개념은 부트스트래핑 체인에 활용할 수도 있을 것 같음
      아주 작은 플랫폼 전용 바이너리에서 시작해 점점 더 복잡한 도구와 컴파일러를 만들어가는 식임
      예시로 mishmashvmtcc_bootstrap_alt 프로젝트를 참고할 수 있음
  • 아름다운 프로젝트임. 다만 제목에 2023을 빨리 추가하는 게 좋겠음
    당시 논의는 이곳에서 있었음
    • 고마움! 매크로 확장 버전으로는
      SectorC: A C Compiler in 512 bytes - 링크 - 2023년 5월 (댓글 80개) 정도로 정리할 수 있음
  • 어제 HN에 올라온, Claude가 2주 만에 2만 달러로 만든 10만 줄짜리 C 컴파일러와 비교해보면 흥미로움
    • 재밌는 비교지만, 그쪽은 리눅스 커널을 컴파일하고 여러 아키텍처용 코드를 생성할 수 있음
      반면 이 프로젝트는 C의 일부만 처리 가능함
      즉, 이건 완전한 C 컴파일러라기보다 C의 부분집합을 다루는 컴파일러임.
      이 컴파일러로 컴파일 가능한 코드는 실제 C 컴파일러로도 가능하지만, 그 반대는 아님
  • 토큰 해싱을 이용해 의사 심볼 테이블을 만드는 방식이 정말 우아함
    • 나도 예전에 테스트 도구용 파서를 만들 때 심볼 해시값만으로 식별자를 관리한 적이 있음
      다행히 32비트 충돌이 날 만큼 많은 심볼을 쓰진 않았길 바람
    • 나도 같은 생각임. 해싱 토큰 트릭이 정말 멋짐
      참고로 0x01e0~0x01fd 사이에 21바이트 여유 공간이 남아 있음. 뭔가 더 넣을 수 있을지도 ;)
  • “atoi()가 일반 텍스트에 대해 나쁜 해시 함수처럼 동작한다”는 부분이 흥미로움
    하지만 내가 기억하기로 atoi()는 유효하지 않은 입력에 대해 0을 반환하도록 정의되어 있었음
  • 부트 섹터용 컴파일러에 대한 관심이 꽤 많음
    Linux에서 실행할 때는 qemu 호출을 coreaudio 대신 alsa로 바꾸면 됨
    이를 위한 pull request를 GitHub에 올렸음. 작성자가 내 verbose한 셸 스크립트 스타일을 괜찮게 본다면 머지될 수도 있음
  • 정말 멋진 글이었음! 예전에 내가 만든 부트섹터 OS가 떠오름
    이제 거기에 C 컴파일러를 추가해볼 때가 된 것 같음
    내 OS 프로젝트 링크