제29회 International Obfuscated C Code Contest(IOCCC) 2025 수상작
요약
IOCCC 2025 수상작인 GameBoy 에뮬레이터 제작 과정과 개인적인 프로그래밍 언어 및 SUBLEQ VM 구현 경험을 다룹니다. 극도로 제한된 코드 크기 내에서 에뮬레이터를 최적화하고 난독화하는 기술적 도전과 학습 과정을 공유합니다.
핵심 포인트
- 2503자 제한 내에 Z80 및 GameBoy 에뮬레이터 구현
- 코드 압축을 위한 C 언어의 극한 활용 및 역공학 기법 사용
- 튜링 완전성을 갖춘 개인용 프로그래밍 언어 및 Brainfuck 인터프리터 제작
- OISC(One Instruction Set Computer) 기반의 SUBLEQ VM 구조 분석
재미있게 봤다니 기쁨 :-) 어떻게 만들어졌는지 보고 싶다면 원본은 여기 있음 https://github.com/ncw/ioccc-gameboy
거기에 난독화하지 않은 버전도 대략 있음. 실제로 작업한 건 그쪽이고, 이후 프로그램으로 변수명을 전부 짓누르고 GameBoy 모양에 맞게 압축했음
출품작의 크기 제한이 가장 힘들었음. IOCCC 출품작은 공백 제외 2503자까지 허용되고, 전체 코드 크기는 4KB인데, Z80 프로세서와 GameBoy 하드웨어 에뮬레이터를 넣기엔 정말 작음
처음엔 C로 완전한 GameBoy 에뮬레이터를 작성했고 공백 제외 약 6000자에서 시작함. 그 뒤 2503자 제한에 맞추려고 약 100시간을 썼고, 한동안은 들어갈지 확신이 없었음
목표를 Tetris 실행으로 정했음. Tetris는 비교적 단순한 게임이라 Z80 에뮬레이터의 half carry 플래그나 GameBoy 에뮬레이션의 윈도잉 시스템처럼 필요 없는 기능을 제거함. 또한 C 코드를 끔찍하게 혹사했고, implicit int로 다시는 잊을 수 없는 짓도 했음. IOCCC 규칙 검사기가 C 프로그램으로 구현돼 있어서, 그걸 역공학해 허점을 찾는 데도 시간을 썼음. 특정 연산자들이 토큰 하나로만 계산된다는 걸 발견한 게 특히 유용했음
충분히 작아진 뒤에는 실행할 게임도 넣어야 했음. Z80 어셈블리로 작성한 테스트 프로그램, 어셈블리로 만든 원주율 계산기, gbdk-2020으로 C로 만든 3D 틱택토, C로 만든 체스 프로그램까지 4개를 만들었음. 꽤 많은 오픈소스 게임도 이 에뮬레이터에서 돌아간다는 걸 알게 돼 가능할 때는 다운로더도 추가함. 의외로 BCD 산술을 쓰는 게임은 많지 않았음
재미있는 프로젝트였음
지난 몇 주 동안 Linux/amd64 어셈블리로 컴파일되는 내 간단한 프로그래밍 언어를 만들고 있었음
파일 열기, 셸 명령 실행, strstr, strcpy 같은 표준 라이브러리 루틴을 잔뜩 작성할 수도 있었고, 솔직히 학습 과정에서 필요 없는 것도 구현하긴 했음. 예를 들어 print(getenv("HOME"))는 동작함. 하지만 곧 테스트와 과시용 예제 프로그램이 필요하다는 걸 깨달음
그래서 당연히 처음 구현한 진짜 프로그램은 brainfuck 인터프리터였음. 덕분에 내 언어는 이제 간접적으로 튜링 완전함
초기 버전은 유명한 mandelbrot 프로그램 출력을 내는 데 9분이 걸려서 여러 최적화를 했고, 이후 switch/case 문 지원도 넣어 속도를 높였음. 이제 같은 출력을 2분에 만들 수 있으니 개선 여지는 있지만 꽤 진전도 있음
내 언어 안에 또 다른 언어를 구현하는 반칙 같은 방식이 아주 만족스러웠음. 물론 전부 재미와 학습용이고, 나 자신을 포함해 누구도 진지하게 쓰라고 만든 건 아님 https://github.com/skx/s-lang
와! 그리고 튜링 완전한 SUBLEQ 변형을 아주 흥미롭게 구현했음
이 VM은 OISC, 즉 One Instruction Set Computer를 구현한다. 이 명령은 세 개의 부호 있는 32비트 피연산자 a, b, c를 받고, 메모리 m[]에서 다음처럼 프로그램을 실행한다:
1 PC(program counter)는 0에서 시작
2 다음 명령을 가져옴, 즉 부호 있는 32비트 피연산자 a, b, c
3 어떤 피연산자든 하위 비트가 설정돼 있으면 그 비트를 제거하고, 해당 피연산자를 m[operand], 즉 그 주소의 역참조 값으로 바꿈
4 m[b] = m[b] - m[a]로 설정
5 m[b]가 0 이하이면 PC를 c로 설정하고, 아니면 PC를 3워드 증가
6 2단계로 돌아감
이 아이디어는 마음에 드는 것 같지만, 링크된 Eternal Software Initiative [1]는 좀 혼란스러움. 이를 디코딩하는 명령 설명이 여러 버전 있고 서로 충돌함
여기에는 Set m[b] = m[b] - m[a]라고 되어 있음
그다음 GitHub의 참조 구현 [2]으로 연결되고, 거기서는 냅킨 메모 [3]만 있으면 된다고 함. 읽은 값을 전부 4로 나누는 방식이고, 참조 구현 [4]도 이를 뒷받침함. 하지만 왜 2가 아니라 4를 고른 건지 명확하지 않음. 비트 하나를 낭비하는 것처럼 보임. 이 비트가 필요했는지, 아니면 향후 확장을 위해 예약된 건지 궁금함
원래 구현은 4로 나누지 않았고 나중에 추가된 것 같지만, LLVM 코드 생성을 조금 쉽게 하는 것 말고 왜 필요했는지 모르겠음. 4로 나누지 않으면 설명된 시스템이 불가능한지 확인하려면 예제를 많이 따라가 봐야 할 듯함. 아마 짝수 주소에만 접근할 수 있고 PC는 매번 3씩 증가하니 코드 위치를 참조하기는 확실히 성가셨을 것임
참조 구현은 위치 64에 접근하면 마법처럼 동작해서 64~67 위치를 현재 시각으로 덮어씀. 냅킨 설명에는 나오지만 메인 페이지 설명에는 없음
두 설명 모두 마법의 -1 주소를 언급하므로, 구현 의존적인 UTC 시계도 자유롭게 쓸 수 있는 메모리를 망가뜨리는 대신 음수 주소로 구현하지 않은 점이 이상함
두 설명 모두 정기 타이머 인터럽트 과정도 언급하는데, 이것도 아쉬움. 주소 0을 인터럽트 핸들러 위치로, 1을 저장된 PC로 재사용하므로 프로그램 시작 직후 초기 진입점인 위치 0을 덮어써야 함
[1] https://eternal-software.org/
[2] https://github.com/adriancable/eternal
[3] https://github.com/adriancable/eternal/blob/main/docs/napkin...
[4] https://github.com/adriancable/eternal/blob/main/vm/vm.c
내려받아 빌드해 봤고, 지금까지 본 것 중 가장 인상적인 것이라고 자신 있게 말할 수 있음
궁금한 사람이 있을까 봐: IOCCC는 가이드라인에서 LLM 사용을 명시적으로 허용함
"IOCCC has a rich history of remarkable winning entries created by authors who skillfully employed various techniques (often their own tools) to develop their code."
나는 비AI 쪽이지만, 이 경우는 흥미로움. 특히 온라인에 난독화 C 코드가 많지 않고, LLM이 실제 코드에서 의도를 추론하기도 어렵기 때문임. LLM 도움을 받은 출품작을 본 적 있는지 궁금함
반대로도 흥미로움. LLM이 난독화된 코드의 기능을 얼마나 잘 맞힐 수 있을까?
이건 주로 심사위원들에게 영향을 줌. 조악한 코드가 쏟아질 가능성을 스스로 열어두는 셈이지만, 대회 성격상 심사위원들은 흥미로운 코드와 낮은 품질의 코드를 매우 잘 구분할 것 같음
IOCCC가 기계의 도움으로 만들었을 수도 있는 코드를 받아들이는 건 좋다고 봄. 덕분에 순수 수작업 우승작의 가치가 더 커져 보임
그러면 LLM 체조 대회가 된 건가?
"도구"에 AI가 포함된다면 규칙 7은 자기모순이 됨 https://www.ioccc.org/2025/rules.html
여기서 말하는 건 맞춤 코드 생성기를 가리키는 것 같음. "풍부한 역사"를 명시적으로 말하는데, AI가 없던 시절까지 포함하는 표현이라면 왜 AI를 뜻한다고 봐야 하는지 모르겠음
에뮬레이터를 만든 뒤 32KB 제한 안에서 실행할 수 있는 게임을 찾으려고 GitHub를 뒤졌음. 당신 걸 찾았고, 고마움 :-) ./try.sh 스크립트에 사용자가 GitHub에서 내려받아 테스트할 수 있는 옵션을 넣어뒀음
2000년에 첫 인턴십 면접을 봤는데, C 프로그래머 팀에 합류하는 자리였음. 면접관들이 예전 우승작 하나를 보여주고 코드를 리뷰해 보라며 방을 나갔음. 5분쯤 뒤 돌아와서 물었음
– 그래서요?
– 죄송합니다, 시간을 낭비하게 했네요. 전혀 이해를 못 하겠습니다
그러자 다들 웃음을 터뜨리고 입사 절차를 시작하자고 했음
요즘도 인턴을 이렇게 놀리는지 궁금함. 그때 당황했던 나를 떠올리면 아직도 웃김
오오오! IOCCC가 돌아왔구나!
주최자들에게 사랑을 보냄 <3 <3 <3 IOCCC를 계속 이어줘서 고맙고, 다시는 사라지지 말아줬으면 함
Capture the Flag에는 명확한 목표가 있지만, Obfuscated C Contest에는 그런 게 없음. 목표 지향 대회에서 AI가 발전하는 건 이해되지만, 예술적 감각이 들어가는 개방형 대회에서 무엇을 발전으로 봐야 할지는 잘 모르겠음
"영리한 아이디어를 떠올린 뒤 AI에게 IOCCC 제약에 맞춰 구현해 달라고 할 수 있지 않나?"를 묻는 거라면, 현재 AI 도구는 아직 인간 심사위원이 가치 있다고 볼 수준으로 그걸 해내지 못한다고 봄
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기