C 언어로 125줄 만에 VM을? 저수준 프로그래밍의 세계로!

by DD
3개월 전
조회수 14

C 언어를 사용하여 125줄 이내로 간단한 가상 머신(VM)을 구현하는 튜토리얼 소개

LC-3 아키텍처를 기반으로, 레지스터 기반 VM의 작동 원리를 설명하고, 어셈블리 명령어 실행

비트 연산, 포인터, 함수 포인터 등 C 언어의 핵심 개념을 활용하여 VM 구현

META II 어셈블리를 활용한 VM 구현 제안 및 다양한 VM 구현 아이디어 공유

LC-3 아키텍처 기반 VM 구현

본 튜토리얼은 LC-3 아키텍처를 기반으로 한 레지스터 기반 VM(Register-based VM)을 구현한다. VM은 CPU, 메모리, I/O 장치로 구성되며, CPU는 ALU, CU, 레지스터로 세분화된다. 특히, 16비트 메모리 공간을 활용하여 프로그램과 데이터를 저장하고, 명령어 사이클(Instruction Cycle)을 통해 명령어를 해석하고 실행한다. 튜토리얼에서는 add, ld, st, jmp 등 14개의 LC-3 어셈블리 명령어를 지원하며, 각 명령어에 대한 C 함수를 제공한다.

C 언어 핵심 개념 활용

튜토리얼은 비트 연산, 포인터, 함수 포인터, C 매크로 등 C 언어의 핵심 개념을 활용하여 VM을 구현한다. 특히, OpCode 추출 매크로(OpCode Extraction Macro)를 사용하여 명령어의 OpCode를 추출하고, 함수 포인터 배열(Function Pointer Array)을 통해 명령어 실행을 관리한다. 이러한 방식을 통해 switch 문 없이 효율적으로 명령어를 실행할 수 있으며, 코드의 가독성을 높인다. 또한, 메모리 접근 함수(mr, mw)를 통해 메모리 접근을 추상화하여 향후 기능 확장에 용이하도록 설계했다.

조건 플래그(Condition Flags)와 분기(Branching)

VM은 RCND 레지스터(Condition Flags Register)를 사용하여 연산 결과를 추적하고, br 명령어(Conditional Branch Instruction)를 통해 조건부 분기를 구현한다. uf 함수(Update Flags Function)를 통해 연산 결과에 따라 RCND 레지스터를 업데이트하고, br 명령어는 RCND 레지스터의 상태와 일치하는 조건이 충족될 경우 지정된 주소로 점프한다. 이러한 메커니즘은 if 문과 유사한 방식으로 프로그램의 흐름을 제어하며, 복잡한 로직을 구현하는 데 필수적이다.

META II 어셈블리어를 활용한 VM 구현 제안

댓글에서는 META II 어셈블리어를 사용하여 VM을 구현하는 방법을 제안한다. META II는 간결한 문법과 자기 컴파일러(Self-compiling Compiler) 특성을 가지고 있어, 적은 코드 라인으로 VM을 구현할 수 있다. 댓글 작성자는 META II 어셈블리어의 단일 명령어(Single Instruction)를 활용하여 VM을 구현하고, 파서(Parser), 링커(Linker) 등을 포함한 VM을 100줄의 Haskell 코드로 구현한 경험을 공유한다. 이는 VM 구현에 대한 다양한 접근 방식을 제시한다.

Writing a simple VM in less than 125 lines of C (2021)