
인생의 의미를 (잃기) 위해 어셈블리로 웹서버를 짠 사람
요즘 웹서버 하나 만들려면 선택지가 정말 많죠. Node.js로 몇 줄이면 뚝딱이고, Go나 Rust 같은 언어를 쓰면 성능도 뽑아낼 수 있고요. Python의 Flask나 FastAPI를 쓰면 거의 마법처럼 서버가 뜹니다. 그런데 어떤 사람이 이런 편한 길을 다 무시하고, 순수 어셈블리어(Assembly) 로 웹서버를 만들었어요. 프로젝트 이름은 'ymawky'인데, 제목부터가 "내 인생에 (의미가 없다는) 의미를 부여하기 위해"라는 자조적인 농담이에요. 개발자 특유의 유머가 묻어나죠.
어셈블리어가 뭐냐면, 컴퓨터 CPU가 직접 알아듣는 기계어와 거의 1:1로 대응되는 가장 낮은 수준의 프로그래밍 언어예요. 우리가 보통 쓰는 파이썬이나 자바스크립트는 인간이 읽기 쉽게 추상화된 고급 언어인데, 어셈블리는 그 반대편 끝에 있어요. 메모리 주소를 직접 다루고, CPU 레지스터(임시 저장 공간)에 값을 옮기고, 시스템 콜이라는 운영체제 호출까지 손으로 일일이 작성해야 합니다. 한 줄짜리 print("hello")가 어셈블리에서는 수십 줄로 늘어나기도 해요.
어셈블리 웹서버는 어떻게 동작할까
웹서버라는 건 결국 "누가 80번 또는 8080번 포트로 HTTP 요청을 보내면, 그걸 받아서 적절한 응답을 돌려주는 프로그램"이에요. 고급 언어에서는 listen(), accept() 같은 라이브러리 함수 한두 개로 끝나지만, 어셈블리에서는 이걸 리눅스 시스템 콜(syscall) 로 직접 호출해야 합니다.
구체적으로 보면, 먼저 socket 시스템 콜을 호출해서 TCP 소켓을 만들고, bind로 특정 포트에 묶고, listen으로 연결 대기 상태로 전환한 뒤, accept로 클라이언트 연결을 받아들이는 흐름이에요. 각 단계마다 시스템 콜 번호를 EAX 레지스터에 넣고, 인자들을 RDI, RSI, RDX 같은 레지스터에 차례로 세팅한 다음 syscall 명령을 실행합니다. C로 짜면 한 줄인 작업이 어셈블리에서는 정확히 어떤 레지스터에 어떤 값을 넣을지 매뉴얼을 봐가며 짜야 하는 거죠.
HTTP 응답도 마찬가지예요. "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html>..."같은 문자열을 메모리에 미리 박아두고, write 시스템 콜로 소켓에 그대로 흘려보냅니다. 파서라는 것도 따로 없어요. 어떤 요청이 오든 그냥 같은 응답을 뱉는, 가장 원시적인 형태죠. 그래도 브라우저로 접속하면 진짜 HTML이 보입니다.
왜 이런 짓(?)을 할까
실용적으로 보면 어셈블리 웹서버는 거의 의미가 없어요. 유지보수도 어렵고, 보안 패치도 직접 다 해야 하고, HTTPS 같은 건 꿈도 못 꾸죠. 그런데도 이런 프로젝트가 꾸준히 나오는 데는 이유가 있어요.
첫째는 학습 효과 입니다. 웹서버가 추상화된 라이브러리 뒤에서 실제로 어떻게 OS와 대화하는지, TCP 연결이 어떤 시스템 콜의 조합으로 만들어지는지를 뼛속까지 이해하게 돼요. 평소에 app.listen(3000) 한 줄 쓰는 게 사실은 얼마나 많은 일을 숨기고 있는지 체감할 수 있죠. 둘째는 바이너리 크기와 성능 이에요. 어셈블리로 잘 짠 서버는 몇 KB짜리 실행 파일로 동작합니다. 의존성 0, 런타임 0이죠. 셋째는 솔직히 말해서 재미와 자기만족 이에요. 등산하는 사람한테 왜 굳이 힘들게 산을 오르냐고 묻는 거랑 비슷해요.
비슷한 결의 프로젝트들
사실 이런 "극한 로우레벨" 프로젝트는 의외로 계보가 있어요. 예전에 어셈블리로만 작성된 운영체제 MenuetOS, KolibriOS 같은 게 있었고, GUI까지 어셈블리로 그리는 도전이 있었죠. 웹 쪽에서는 C로 단일 파일에 모든 걸 넣은 redbean 같은 프로젝트가 유명해요. Cosmopolitan Libc를 써서 윈도우, 맥, 리눅스에서 동시에 실행되는 단일 바이너리 웹서버였죠.
또 Rust 진영에서는 no_std 환경에서 OS도 없이 베어메탈로 네트워크 스택을 짜보는 시도들이 있고요. 이런 프로젝트들의 공통점은 "추상화를 걷어내고 컴퓨터의 진짜 모습을 보자" 라는 거예요.
한국 개발자에게 주는 시사점
실무에서 어셈블리로 서버를 짤 일은 거의 없을 거예요. 하지만 이런 프로젝트의 코드를 한 번 정독해보는 건 충분히 가치가 있어요. 특히 백엔드 개발자라면 syscall 흐름을 따라가면서 "내가 매일 쓰는 프레임워크가 OS와 어떤 식으로 대화하는지"를 그림으로 그릴 수 있게 되거든요. 이건 나중에 성능 튜닝이나 장애 대응할 때 진짜 큰 차이를 만듭니다. strace로 시스템 콜을 추적할 때, 그 출력이 더 이상 외계어로 보이지 않게 되는 거죠.
또 임베디드나 펌웨어, 보안 분야로 가고 싶은 분들에게는 어셈블리 감각이 거의 필수예요. 리버스 엔지니어링, 익스플로잇 분석, CTF 같은 분야는 어셈블리를 못 읽으면 시작도 못 합니다. ymawky 같은 프로젝트는 "이 정도는 나도 따라 해볼 만하겠는데?" 하는 진입점이 되어줄 수 있어요.
마무리
결국 이 프로젝트가 우리에게 주는 메시지는 단순해요. 추상화의 편안함에만 머무르지 말고, 가끔은 그 아래 무엇이 있는지 들여다보자. 그게 더 좋은 개발자로 성장하는 길이거든요.
여러분은 평소에 추상화 아래 레이어를 얼마나 자주 들여다보시나요? 혹시 한 번쯤 "실용성 0, 학습 효과 100" 인 사이드 프로젝트를 해보신 경험이 있다면 어떤 거였는지 궁금해요.
🔗 출처: Hacker News
"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"
실제 수강생 후기- 비전공자도 6개월이면 첫 수익
- 20년 경력 개발자 직강
- 자동화 프로그램 + 소스코드 제공