컴퓨터구조 & 운영체제

혼자 공부하는 컴퓨터구조 + 운영체제 Chapter 3 정리

rltjq09 2024. 3. 15. 10:43
728x90

3.1 소스 코드와 명령어

고급 언어와 저급 언어

고급 언어 : 사람이 쉽게 이해할 수 있도록 만들어진 프로그래밍 언어

저급 언어 : 컴퓨터가 직접 이해하고 실행할 수 있는 언어

 

고급 언어로 작성된 소스 코드가 실행되려면 저급 언어(명령어)로 변환되어야 한다

 

저급 언어에는 기계어와 어셈블리어가 존재한다

기계어란, 0과 1의 명령어 비트로 이루어진 언어이다

가독성을 위해 십육진수로 변환되어서 표현되기도 한다

이처럼 숫자로만 이루어져 있기 때문에 사람이 보고 어떤 명령어인지 알 수 없다

이를 사람이 이해하는 데 도움을 주기 위해 등장한 언어가 어셈블리어 이다

어셈블리어란, 0과 1로 표현된 명령어(기계어)를 읽기 편한 형태로 변역해주는 언어이다

 

컴파일 언어와 인터프리터 언어

고급 언어를 저급 언어로 변환하는 방법에는 2가지가 존재한다

1. 컴파일 언어

컴파일러에 의해 소스 코드 전체가 저급 언어로 변환되어 실행되는 고급 언어를 의미한다

대표적인 예시로 C가 존재한다

컴파일 언어로 작성된 코드는 컴파일러로 전달되게 되는데, 컴파일러는 코드를 보고 오류 또는 오타 같은 것이 없는지 검증한다

없다는 것이 검증되면 이를 저급 언어로 변환한다

이 과정을 컴파일이라고 하며, 저급 언어로 변환된 코드를 목적 코드라고 한다

 

2. 인터프리터 언어

인터프리터에 의해 소스 코드가 한 줄씩 실행되는 고급 언어를 의미한다

대표적인 예시로 Python이 존재한다

컴파일 언어와의 차이점이라고 한다면, 코드 전체를 보고 검증을 한 후에 실행하는 것이 아닌 한 줄 한 줄 확인하면서 실행한다는 것이다

이때, 매 라인을 저급 언어로 변환해주는 도구를 인터프리터라고 한다

이렇듯, 한 줄씩 실행하기 때문에 컴파일 언어와 달리 중간에 오류가 있어도 오류 이전까지는 코드가 실행된다는 특징이 있다

 

목적 파일 vs 실행 파일

목적 파일 : 목적 코드로 이루어진 파일

실행 파일 : 실행 코드로 이루어진 파일 (ex. installer.exe)

 

목적 코드가 실행 파일이 되기 위해서는 링킹이라는 작업을 거쳐야 한다

링킹이 되는 과정

1. helper.c와 main.c 라는 소스 코드를 작성

2. 각 소스 코드를 목적 코드로 컴파일 → helper.o와 main.o 라는 목적 파일이 생성

3. main.o 안에는 helper.o를 실행해야 하는 내용이 포함되어 있음, 이는 컴파일 과정에서 반영 x

4. 이때 링킹이라는 작업을 통해 main.o가 helper.o를 실행할 수 있도록 연결

 

3.2 명령어의 구조

연산 코드와 오퍼랜드

명령어는 연산 코드와 오퍼랜드로 구성되어 있다

연산 코드(연산자) : 명령어가 수행할 연산

오퍼랜드(피연산자) : 연산에 사용할 데이터 혹은 연산에 사용할 데이터가 저장된 위치

이때, 연산 코드가 담기는 영역을 연산 코드 필드, 오퍼랜드가 담기는 영역을 오처랜드 필드라고 한다

 

오퍼랜드 필드에는 주로 데이터가 저장된 위치, 즉 메모리 주소나 레지스터 이름이 주로 담긴다

이래서 오퍼랜드 필드를 다른 말로 주소 필드라고도 한다

명령어 중 오퍼랜드가 하나도 없으면 0-주소 명령어, 1개이면 1-주소 명령어, 2개는 2-주소 명령어, 3개는 3-주소 명령어라고 한다

 

연산 코드는 크게 4가지 유형으로 구분지을 수 있다

1. 데이터 전송

2. 산술/논리 연산

3. 제어 흐름 변경

4. 입출력 제어

 

명령어의 종류와 생김새는 CPU마다 다르지만, 아래의 명령어들은 모두 공통으로 사용하는 대표적인 것들의 예시이다

1. 데이터 전송

MOVE : 데이터를 옮겨라

STORE : 메모리에 저장하라

LOAD(FETCH) : 메모리에서 CPU로 데이터를 가져와라

PUSH : 스택에 데이터를 저장하라

POP : 스택의 최상단 데이터를 가져와라

 

2. 산술/논리 연산

ADD / SUBTRACT / MULTIPLY / DIVIDE : +, -, *, / 을 수행하라

INCREMENT / DECREMENT : 오퍼랜드에 1을 더하라 / 오퍼랜드에 1을 빼라

AND / OR / NOT : AND, OR, NOT 연산을 수행하라

COMPARE : 두 개의 숫자 또는 TRUE / FALSE 값을 비교하라

 

3. 제어 흐름 변경

JUMP : 특정 주소로 실행 순서를 옮겨라

CONDITIONAL JUMP : 조건에 부합할 때 특정 주소로 실행 순서를 옮겨라

HALT : 프로그램의 실행을 멈춰라

CALL : 되돌아올 주소를 저장한 채 특정 주소로 실행 순서를 옮겨라

RETURN : CALL을 호출할 때 저장했던 주소로 돌아가라

 

4. 입출력 제어

READ (INPUT) : 특정 입출력 장치로부터 데이터를 읽어라

WRITE (OUTPUT) : 특정 입출력 장치로 데이터를 써라

START IO : 입출력 장치를 시작하라

TEST IO : 입출력 장치의 상태를 확인하라

 

주소 지정 방식

오퍼랜드 필드에 데이터의 주소를 작성하는 이유는 명령어의 길이 때문이다

만약, 하나의 명령어에 n비트가 할당되고 연산 코드 필드가 m 비트라면 오퍼랜드 필드에 할당될 수 있는 최대 비트는 n-m이다

총 16비트 중 4비트를 연산 코드 필드에 할당하고 2-주소 명령어라면, 각 오퍼랜드 필드 당 6비트로 64개의 정보밖에 표현할 수 없다

하지만 해당 필드에 주소를 저장하면 데이터는 더 많은 비트로 저장될 수 있을 것이다

이때, 연산의 대상이 되는 데이터가 저장된 위치를 유효 주소라고 한다

 

이런 식으로 오퍼랜드 필드에 데이터가 저장된 위치를 명시할 때 데이터 위치를 찾는 방법을 주소 지정 방식이라고 한다

즉, 유효 주소를 찾는 방법이라고 할 수 있다

 

주소 지정 방식의 다양한 유형

1. 즉시 주소 지정 방식

연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식

따로 주소를 따라가 데이터를 가져오는 과정이 없기 때문에 속도는 빠르지만 그만큼 정보의 양이 줄어든다

 

2. 직접 주소 지정 방식

오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식

이 역시 여전히 정보의 양이 적기 때문에 유효 주소를 표현하는 데 제한적이다

 

3. 간접 주소 지정 방식

유효 주소의 주소를 오퍼랜드 필드에 명시하는 방식

주소의 주소를 명시해서 제한된 양으로도 다양한 데이터에 접근할 수 있도록 하는 것이다

 

4. 레지스터 주소 지정 방식

연산에 사용할 데이터를 저장한 레지스터를 오퍼랜드 필드에 직접 명시하는 방식

CPU 내부에 있는 레지스터에 접근하기 때문에 다른 방식보다 더 빠르게 동작한다

 

5. 레지스터 간접 주소 지정 방식

연산에 사용할 데이터는 메모리에 저장하고, 해당 주소(유효 주소)를 레지스터에 저장한 뒤 이를 오퍼랜드 필드에 명시하는 방식

728x90