[밑바닥부터 만드는 컴퓨팅] 06장 어셈블러

3 minute read

개요

해당 내용은 ‘밑바닥부터 만드는 컴퓨팅 시스템’ 책의 6장 내용을 정리하였습니다.

1. 배경

기계어는 기호형과 2진 형식으로 정의됩니다. 예시로 2진 코드는 110000101000000110000000000000111 와 같이 작성되며, 이는 실제 하드웨어에서 해석되어 수행합니다. 이 명령어에서 왼쪽 8비트는 연산코드(LOAD), 다음 8비트는 레지스터(R3), 나머지 16비트는 주소(7)를 뜻합니다. 이를 해석하면 메모리 주소 7의 값을 레지스터 R3에 로드하라는 뜻이 됩니다. 현대의 컴퓨터는 이러한 기초적인 연산을 수십 수백개를 지원하고 있습니다.

하지만 이러한 2진 코드는 사람이 보기에는 너무 불편합니다. 그렇기때문에 2진값으로 표현하는 대신 LOAD R3 7 과 같이 약속된 문법으로 명령어를 표기하는 방법이 있는데, 이러한 표현 방법을 어셈블리라고 부릅니다. 작성된 어셈블리는 어셈블러를 이용하여 2진 코드로 변경하며, 컴퓨터는 변경된 2진 코드로 프로그램을 실행하게 됩니다.

1.1 기호

2진 명령어는 2진 코드로 표현됩니다. 2진 명령어들은 실제 숫자를 이용하여 메모리 주소 참조를 표기합니다. 숫자는 미리 정의된 기호로 치환할 수 있습니다. 만약 weight라는 변수의 주소값이 7이라면 메모리 주소의 값 7 대신에 weight로 치환하여 작성할 수 있습니다. 어셈블리는 일반적으로 두가지 방법으로 기호를 도입합니닫.

  • 변수 : 프로그래머가 변수명으로 기호를 사용하면 번역기는 자동적으로 그 기호를 주소에 할당합니다.
  • 레이블 : 프로그래머는 프로그램 내 다양한 위치 기호를 표시할 수 있습니다. 예를 들어 어떤 코드의 시작 부분을 loop라는 레이블로 정의할 수 있습니다.

어셈블리 언어에서 기호를 사용한다는 말은 어셈블러가 단순한 텍스트 처리 프로그램보다 더 복잡하다는 뜻입니다. 미리 정의된 기호를 미리 정의돈 2진 코드로 변경하는 작업은 복잡하지 않습니다. 하지만 프로그램에서 사용하는 변수명과 기호 레이블을 실제 메모리 주소에 매핑하는 일은 간단하지 않습니다. 실제로 하드웨어에서 소프트웨어로 전환되는 과정 중 가장 먼저 접하는 복잡한 작업이 이러한 교환 변환 작업입니다. 이러한 문제는 일반적으로 다음과 같이 처리합니다.

1.1.1 기호 변환

image

위 프로그램에서는 isum 두개의 변수와 loop, end 두개의 레이블이 있습니다.

번역된 코드는 주소 0부터 시작하는 메모리에 저장하고, 변수들은 1024부터 할당하도록 합니다. 다음으로 소스코드에 새로운 기호가 나타날 때 마다 테이블에 추가하는 방식으로 기호 테이블을 구성합니다. 기호 테이블이 다 만들어지면 이 테이블을 이용해 프로그램을 기호가 없는 코드로 옮기게 됩니다.

위 규칙에 따르면 isum은 각각 주소 1024와 1025에 할당됩니다. 다른 주소라고 하더라도 같은 물리적 주소를 참조할 수 있다면 상관은 없습니다.

이 프로그램은 단순하게 설명하기 위하여 작성된 규칙이며, 실제의 컴퓨터는 이것보다는 복잡합니다.

이 규칙에 따르면 실행 가능한 가장 큰 프로그램은 명령어가 1024개인 프로그램입니다. 하지만 실제 프로그램은 훨씬 더 크고, 보통 변수 저장 시작 주소도 더 뒤에서 시작합니다.

그리고 명령어들이 word 하나에 매핑된다는 것은 아주 단순한 가정입니다. 일반적인 번역 과정에서 어떤 어셈블리 명령들은 명령어 몇 개로 분리되어 여러 메모리 위치를 차지하게 됩니다.

또한 각 변수가 하나의 메모리 위치를 점유한다는 가정도 단순한 가정입니다. 프로그래밍 언어에는 다양한 변수 타입이 있습니다. C언어에는 char(1 byte), int(4 byte), long(8 byte) 와 같이 다양한 변수 타입이 존재합니다.

1.1.2 어셈블러

어셈블러 프로그램은 2진 기계어로 변역해야만 컴퓨터에서 실행할 수 있습니다. 번역 작업은 어셈블러가 수행합니다. 어셈블러는 어셈블러를 한줄씩 입력받아 같은 의미인 2진 명령어로 출력합니다. 이렇게 번역된 2진 명령어는 프로그램 실행 시 메모리에 로드되어 실행됩니다.

어셈블러는 기본적으로 번역 기능이 있는 텍스트 처리 프로그램입니다. 따라서 어셈블러를 작성할 때는 어셈블리 문법에 대하여 2진 코드로 변환할 수 있는 목록이 있어야 합니다. 기계어 명세라 불리는 이 규칙을 따르면, 작업을 수행하는 프로그램을 만들 수 있습니다.

  • 구문 분석을 통해 기호 명령 내 필드를 식별한다.
  • 각 필드에 대응하는 기계어 비트를 생성한다.
  • 모든 기호 참조를 메모리 주소를 가르키는 숫자로 바꾼다.
  • 2진 코드들을 조립하여 완전한 기계 명령어로 바꾼다.

2. 핵 어셈블리 - 2진 번역 명세서

2.1 문법 관례와 파일 형식

2진 기계어 코드는 hack, 어셈블리 코드는 asm 확장자로 하는 텍스트 파일에 저장합니다. 예를들어 aaa.asm을 번역하면 aaa.hack이 생성됩니다.

2진 코드 파일은 텍스트 라인으로 이뤄집니다. 각 라인마다 0과 1로 구성된 16비트의 문자열이 있으며, 이 문자열은 16비트 기계어 명령 하나를 변환한 것입니다. 이러한 16비트 기계어 명령이 모여서 프로그램을 구성합니다.

어셈블리어 파일은 명령어나 기호 선언 라인들로 구성됩니다.

  • 명령어 : A-명령어 또는 C-명령어
  • Symbol : 의사명령은 symbol을 프로그램의 다음 명령어가 저장되는 메모리 위치에 연결합니다.

상수는 10진법으로 표기된 음수가 아닌 숫자여야 합니다. 사용자 정의 기호는 맨 앞 글자가 숫자가 아닌 문자열로 이뤄집니다.

주석은 두개의 빗금(//)의 시작부터 라인 끝까지로 간주되어 무시됩니다.

공백과 빈 라인은 무시됩니다.

2.2 명령어

핵 기계어는 주소 명령어(A-명령어) 와 계산 명령어(C-명령어) 라는 두 종류의 명령어로 구성됩니다. 명령어 형식은 다음과 같습니다.

image

comp, dest, jump 필드들을 2진 형태로 번역하는 방법은 아래의 표를 참고바랍니다.

image

image

2.3 기호

핵 어셈블리 명령은 상수나 기호를 이용해 메모리 주소를 참조할 수 있습니다. 어셈블리 프로그램에서 기호를 사용하는 방법은 세가지입니다.

2.3.1 선언 기호

핵 어셈블리 프로그램에서는 다음과 같은 선언 기호를 사용할 수 있습니다.

레이블 RAM 주소 (hexa)
SP 0 0x0000
LCL 1 0x0001
ARG 2 0x0002
THIS 3 0x0003
THAT 4 0x0004
R0 - R15 0 ~ 15 0x0000 ~ f
SCREEN 16384 0x4000
KBD 24576 0x6000

2.3.2 레이블 기호

의사명령은 기호 Xxx 가 프로그램의 다음 명령이 있는 명령어 메모리 위치를 참조하도록 정의합니다. 한 레이블은 한번만 정의할 수 있으며, 어셈블리 프로그램 내 어디서든 사용할 수 있습니다.

2.3.3 변수 기호

선언 기호가 아니거나, 프로그램 내에서 (Xxx)명령으로 정의되지 않은 기호 Xxx는 변수로 취급됩니다. 변수는 등장한 순서대로 RAM주소 16에서 시작하는 메모리 주소에 차례대로 매핑됩니다.

2.4

아래는 정수 1부터 100까지 더하는 프로그램의 어셈블리 코드와 2진 코드입니다.

image

Leave a comment