기계어와 어셈블리어를 이해하면 컴퓨터가 내부에서 어떻게 동작하는지를 더욱 자세히 알 수 있고 컴퓨터 구조를 소프트웨어 관점에서 바라볼 수 있다. 실제로 기계어와 어셈블리어를 사용하여 프로그래밍을 하는 일은 드물지만 이를 이해하면 고급 언어를 사용할 때 더 효율적인 프로그래밍이 가능하다.
기계어(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바이트 선언 |