기계어와 어셈블리어를 이해하면 컴퓨터가 내부에서 어떻게 동작하는지를 더욱 자세히 알 수 있고 컴퓨터 구조를 소프트웨어 관점에서 바라볼 수 있도록 합니다. 실제로 기계어와 어셈블리어를 사용하여 프로그래밍을 하는 일은 드물지만 이를 이해하면 고급 언어를 사용할 때 더 효율적인 프로그래밍이 가능합니다.
기계어(Machine Language)
컴퓨터의 종류에 따라 컴퓨터가 이해할 수 있는 기계어의 모양은 조금씩 다릅니다. 이 포스팅에서는 Pep/8이라는 가상 머신을 기준으로 내용을 전개합니다. (기계어 코드 표를 참고하면 더 자세히 공부할 수 있습니다.)
기계어로 "Hi"를 출력하려면 다음과 같은 기계어 프로그램을 입력해야 합니다.
메모리 주소 | 기계어(16진수) | 기계어(2진수) |
0000 0003 0006 |
50 00 48 50 00 69 00 zz |
0101 0000 0000 0000 0100 1000 0101 0000 0000 0000 0110 1001 0000 0000 |
메모리 주소란 실제로 기계어 프로그램이 메인 메모리에 로드되었을 때의 메모리 주소를 의미합니다. 알 수 없는 기계어들을 조금씩 해석해보도록 하겠습니다. 첫 번째 인스트럭션(기계어 명령어)부터 보겠습니다. 첫 번째 인스트럭션은 0101 0000 0000 0000 0100 1000이라는 숫자들의 집합입니다.
Opcode | 어드레싱 모드 | 피연산자 지시자 |
01010 | 000 | 0000 0000 0100 1000 |
위의 표를 보면 알 수 있듯, 첫 번째 인스트럭션은 Opcode(명령 코드), Addressing mode(메모리 접근), Operand Specifier(피연산자 지시자)로 이루어집니다. Opcode는 기계어의 명령 코드이며 위에서는 01010이라는 값을 가지는데, 이는 Character output(0101 0aaa)을 의미합니다. 이때 01010은 Opcode이고, aaa는 어드레싱 모드에 해당합니다.
첫 번째 인스트럭션의 어드레싱 모드를 보면 000이라는 값을 가집니다. 이는 "즉시 주소 지정 방식"을 의미하며 뒤의 피연산자 지시자가 실제 연산이 수행된다는 것입니다.
이를 모두 종합해보면 첫 번째 인스트럭션은 "ASCII값이 16진수로 0x48에 해당하는 문자인 'H'를 출력하라"는 것입니다. 이러한 방식으로 기계어를 해석할 수 있습니다.
두 번째 인스트럭션도 첫 번째와 유사합니다. 두 번째 인스트럭션은 "ASCII값이 16진수로 0x69에 해당하는 문자인 'i'를 출력하라"는 것입니다.
세 번째 인스트럭션은 1바이트 인스트럭션으로 stop 명령어입니다. 말그대로 프로그램 수행을 종료하는 명령어입니다. 그리고 기계어 프로그램의 끝에는 zz를 붙여야 오류가 나지 않습니다. 기계어는 여기까지만 알아보도록 하겠습니다.
어셈블리어(Assembly Language)
어셈블리어는 기계어와 고급 언어의 중간에 위치한 언어입니다. 0과 1로 이루어진 기계어를 기억하기 쉬운 영어 단어로 바꾸어놓은 것이 어셈블리어의 핵심 아이디어입니다. 어셈블리어의 인스트럭션은 크게 두 가지로 나뉩니다.
- mnemonic 인스트럭션: 기계어와 1대1 대응되는 인스트럭션으로 기계어의 2진수를 기억하기 좋은 영단어로 바꾼 것이다.
- pseudo 인스트럭션: 프로그래밍의 편이를 위해 추가된 인스트럭션입니다.
같은 문자 출력 인스트럭션 예제를 통해 기계어와 어셈블리어를 비교해보겠습니다. 확실히 어셈블리어 인스트럭션의 형식이 조금 더 가독성이 좋음을 알 수 있습니다.
- 2진수 표현: 0101 0000 0000 0000 0100 1000
- 16진수 표현: 50 00 48
- 어셈블리어 표현: CHARO 0x0048 i
어셈블리어 인스트럭션은 다음과 같이 나뉩니다.
Mnemonic | 피연산자 지시자 | 어드레싱 모드 비트 |
CHARO | 0x0048 | i |
위의 인스트럭션은 addressing mode bit가 'i'이기 때문에 즉시 주소 지정 방식(Immediate mode)로 ASCII 0x48값을 가지는 문자 'H'를 출력합니다. 어셈블리어의 인스트럭션에 대해 조금 더 자세히 알아보겠습니다.
mnemonic 인스트럭션
Pep/8 가상 머신에서 제공하는 mnemonic 인스트럭션은 총 39개가 있습니다. 다음을 참고하도록 합시다.
인스트럭션은 크게 2종류가 있습니다.
- non-unary instruction: 3바이트로 이루어져 있으며 인스트럭션 지시자 1바이트, 피연산자 지시자 2바이트로 구성된다.
- unary instruction: 1바이트로만 구성된다.
8비트로 구성된 인스트럭션 지시자는 다시 3부분으로 나뉠 수 있습니다. 종류에 따라 레지스터 필드가 없을 수도 있고 어드레싱 모드 필드의 길이가 다를 수 있습니다.
pseudo 인스트럭션
Pseudo 인스트럭션은 어셈블러에게 어떤 명령을 내리는 인스트럭션이며, 실제로 2진수 기계어로 변경되지 않고, 데이터 설정이나 어셈블러에게 어떤 명령을 내리는 것이 주된 역할입니다. Pep/8 가상머신의 pseudo 인스트럭션은 총 8개가 있습니다.
Pesudo 인스트럭션 | 기능 |
.ADDRESS symbol | 심볼의 주소를 2바이트로 선언 |
.ASCII "string" | ASCII 바이트의 문자열 선언 |
.BLOCK n | n개의 바이트 블록 선언 |
.BURN 0xFFFF | 0xFFFF에서 ROM에 굽는 작업을 시작 |
.BYTE constant | 1바이트 선언 |
.END | 어셈블러에게 끝을 알리는 심볼 |
.EQUATE constant | 상수값 선언 |
.WORD constant | 2바이트 선언 |