컴퓨터에서 실행되는 모든 프로그램은 기계어로 변환되어야 한다. 기계어는 0과 1로 이루어진 명령어의 조합으로, CPU가 직접 해석하여 실행할 수 있는 형태를 말합니다. 하지만 기계어는 사람이 직접 작성하거나 이해하기 어렵기 때문에, 보다 직관적인 방식으로 프로그래밍할 수 있도록 어셈블리어가 만들어졌습니다. 어셈블리어는 사람이 읽고 이해할 수 있도록 CPU 명령어를 텍스트 형태로 표현한 저수준 프로그래밍 언어이며, 이를 기계어로 변환하는 역할을 하는 프로그램이 **어셈블러(Assembler)**이다.

어셈블러의 개념은 1940년대 초반, 컴퓨터가 처음 개발되던 시기와 함께 등장했다. 초창기 컴퓨터는 사람이 직접 0과 1로 이루어진 기계어 코드를 입력해야 했기 때문에 프로그래밍이 매우 어려웠고, 실수로 인한 오류도 많았다. 이를 개선하기 위해 사람 친화적인 명령어를 사용하여 기계어를 좀 더 쉽게 작성할 수 있도록 한 것이 **어셈블리어(Assembly Language)**의 시작이었다.

1950년대 초반, IBM의 초기 컴퓨터 시스템에서는 기계어 코드를 보다 쉽게 변환하기 위해 다양한 어셈블러가 개발되었다. 이후 다양한 아키텍처와 프로세서가 등장하면서, 각각의 하드웨어에 맞는 어셈블러가 개발되었다. 1960~70년대에는 어셈블러를 이용한 프로그래밍이 일반적이었으나, 고급 프로그래밍 언어(예: C, FORTRAN 등)의 발전과 함께 사용 빈도가 줄어들기 시작했다. 하지만 어셈블리어 프로그래밍이 필요한 분야에서는 필수적인 도구로 남아 있었다.

1980년대와 90년대에는 PC가 대중화되면서 다양한 어셈블러가 등장하였으며, 특히 x86 아키텍처가 시장을 지배하게 되면서 NASM (Netwide Assembler), MASM (Microsoft Macro Assembler) 등이 널리 사용되었다. 이 시기에는 DOS, Windows, UNIX 등의 운영체제에서 어셈블리 프로그래밍이 이루어졌다. 2000년대 이후, 64비트 아키텍처(x86-64)의 도입과 함께 NASM, GAS (GNU Assembler) 등 리눅스와 오픈소스 환경에서 활용할 수 있는 어셈블러가 더욱 발전하였다. 현대의 어셈블러는 단순한 기계어 변환 도구를 넘어서 매크로 기능, 최적화 기능, 교차 어셈블러 등을 포함하는 강력한 도구로 발전하였다.

운영체제에 따라 사용되는 어셈블러는 다를 수 있으며, 리눅스에서는 NASM와 GAS가 주로 사용된다. NASM은 x86 및 x86-64용으로 ELF 바이너리 포맷을 지원하고, GAS는 GCC 컴파일러와 함께 AT&T 문법을 사용한다.


NASM

NASM 사용법

일반적으로 어셈블러를 사용하여 어셈블리 코드를 실행 가능한 프로그램으로 바꾸기 위해선 아래의 과정을 거쳐야 한다.

  1. 어셈블리 코드 작성
  2. 어셈블러를 사용해 어셈블리 코드를 목적 파일(Object File)로 변환
  3. 링커(Linker)를 사용하여 실행 파일 생성

**목적 파일(Object File)과 링커(Linker)

목적 파일(Object file)**이란 컴파일이나 어셈블 과정에서 소스 코드로부터 생성된 기계 코드(Machine code)를 포함하고 있는 파일을 뜻한다. 목적 파일에는 각 함수나 전역 변수에 해당하는 기계어, 명령어 그리고 아직 연결되지 않은 외부 심볼 등이 포함되어 있다. 파일별로 목적 파일을 만들어 두면 여러 모듈을 독립적으로 컴파일할 수 있어 전체 빌드 시간을 크게 단축할 수 있으며, 재사용성과 효율성이 크게 향상된다.

**링커(Linker)**는 여러 목적 파일들을 하나로 결합해 최종적으로 실행 가능한 파일을 생성한다. 이 과정에서 각 목적 파일 사이 함수 호출이나 변수 참조 같은 심볼 이름을 연결하고, 각 목적 파일에서 사용하던 상대 주소를 실제 메모리 주소로 재배치하는 등의 과정을 거친다. 이렇게 완성된 실행 파일은 운영체제가 직접 로드해 실행할 수 있는 독립적인 바이너리가 된다.

어셈블리 코드 작성

다음과 같은 형태로 작성할 수 있다.

section .data
    message db "Hello, Dreamhack!", 0xA
    msg_len equ $ - message

section .text
    global _start

_start:
    mov rax, 1
    mov rdi, 1
    mov rsi, message
    mov rdx, msg_len
    syscall

    mov rax, 60
    xor rdi, rdi
    syscall

어셈블러를 사용해 코드를 목적 파일로 변환