바이트코드 (Bytecode)

컴퓨터과학·AI
한 줄 정의: 사람이 쓴 코드를 컴퓨터 부품이 직접 알아듣는 기계어로 바로 바꾸지 않고, 그 중간 단계로 만들어 두는 표준화된 명령어 형태입니다.

쉽게 풀면

같은 한국어 소설을 영어권, 프랑스어권, 일본어권 독자에게 각각 번역해서 팔아야 한다고 해봅시다. 매번 한국어에서 각 언어로 직접 번역하기보다, 먼저 누구나 이해하기 쉬운 "쉬운 표준 영어" 요약본을 하나 만들어 두면, 그 요약본만 각 나라 언어로 옮기면 되니 훨씬 효율적입니다. 바이트코드도 이와 비슷합니다. 프로그래밍 언어로 짠 코드를 컴퓨터 기종마다 다른 기계어로 바로 바꾸는 대신, 먼저 컴퓨터와 비슷하면서도 특정 하드웨어에 얽매이지 않는 중간 형태(바이트코드)로 바꿔둡니다. 이 바이트코드는 각 컴퓨터에 설치된 가상 머신이 읽어서 실제 기계어로 마무리 번역해 실행합니다.

왜 중요한가

바이트코드는 컴파일러, 가상 머신, 프로그래밍 언어 설계 전반에서 이식성과 실행 효율을 동시에 다루는 핵심 매개체이기 때문에 논문에서 자주 등장합니다. 특정 하드웨어에 종속되지 않는 실행 환경을 설계하려는 연구, 그리고 동적 컴파일이나 실행 시점 최적화를 다루는 연구는 대부분 바이트코드 형태를 전제로 논의를 전개합니다. 또한 보안 분야에서는 바이트코드 자체를 분석 대상으로 삼아 악성 코드 탐지나 취약점 분석을 수행하기도 하며, 소프트웨어 엔지니어링 분야에서는 바이트코드 수준의 계측을 통해 프로그램 동작을 관찰하는 기법이 널리 쓰입니다.

논문에서는 이렇게 쓰입니다

"제안된 컴파일러는 소스 코드를 플랫폼에 독립적인 바이트코드(bytecode)로 변환한 뒤, 가상 머신에서 이를 실행하여 이식성을 확보하였다."

이 문장은 코드를 특정 컴퓨터 기종에 맞춘 기계어로 바로 만들지 않고, 어떤 컴퓨터에서도 돌아갈 수 있는 중간 형태로 먼저 바꾸었다는 뜻입니다.

"본 연구에서는 바이트코드(bytecode) 수준에서 계측 코드를 삽입하여 실행 중 함수 호출 빈도와 메모리 접근 패턴을 추적하였다."

소스 코드를 직접 수정하는 대신, 컴파일된 이후의 바이트코드 단계에 관찰용 코드를 끼워 넣어 프로그램이 실제로 어떻게 동작하는지 측정했다는 의미입니다.

"악성 애플리케이션 탐지를 위해 정적 분석 단계에서 바이트코드(bytecode)를 역어셈블하고, 위험 API 호출 패턴을 그래프 형태로 추출하였다."

프로그램을 실행하지 않은 상태에서도 바이트코드를 들여다보면 어떤 위험한 동작을 할 가능성이 있는지 미리 파악할 수 있다는 점을 활용한 분석 방식입니다.

조금 더 깊게 보면

바이트코드는 보통 스택 기반 혹은 레지스터 기반의 명령어 집합으로 설계되며, 각 명령어는 사람이 읽는 소스 코드보다 단순하고 규격화되어 있어 가상 머신이 해석하거나 실행 시점에 기계어로 변환하기 쉽습니다. 실행 방식은 크게 매 명령어를 그때그때 해석하는 방식과, 자주 실행되는 부분을 감지해 실제 기계어로 미리 컴파일해두는 방식으로 나뉘며, 후자를 일반적으로 JIT(Just-In-Time) 컴파일이라고 부릅니다. 논문에서 바이트코드를 다룰 때는 이 실행 방식의 차이, 그리고 바이트코드에 계측이나 변환을 가하는 시점(컴파일 직후, 로드 시점, 실행 중 등)이 연구의 성격을 좌우하는 경우가 많으므로 함께 눈여겨볼 필요가 있습니다.

주의할 점

바이트코드는 사람이 읽는 원본 코드도 아니고, 하드웨어가 곧바로 실행하는 순수 기계어도 아닌 그 사이의 중간 단계입니다. 코드의 문법 구조를 나무 모양으로 표현한 추상 구문 트리가 컴파일 초반 단계의 결과물이라면, 바이트코드는 그보다 더 나중, 실행 직전 단계의 결과물이라는 점에서 서로 다른 단계에 속합니다.

관련 용어