01. 시스템 프로그래밍의 이해와 접근
시스템(컴퓨터 시스템)의 범위
시스템 프로그래밍이란?
- 컴퓨터 시스템을 동작시키는 또는 활용하는 소프트웨어 개발
- 대표적인 시스템 프로그램: Windows, UNIX와 같은 운영체제들
- 시스템 프로그램: 하드웨어를 사용할 수 있도록 도와주는 프로그램
- 위와 같은 운영체제 개발자들을 가리켜 시스템 프로그래머라고 할 수 있다.
- 또한, 어셈블리 언어나 C 언어를 이용하여 하드웨어를 직접 컨트롤하는 개발자들도 시스템 프로그래머라고 부른다.
- But, Windows나 UNIX와 같은 운영체제에서 제공하는 라이브러리(운영체제의 기능을 활용할 수 있는 시스템 함수들의 집합)를 사용하여 프로그램을 개발하는 개발자들도 시스템 프로그래머라고 부를 수 있다. ex) Windows 시스템 프로그래머, UNIX 시스템 프로그래머
- 시스템 프로그래밍의 폭 넓은 정의: 시스템 프로그래밍이란 특정 운영체제 기반의 컴퓨터에게 일을 시키기 위한 프로그램을 구현하는 것
→ 시스템 프로그래밍을 제대로 공부하기 위해서는 운영체제와 컴퓨터 구조를 알아야 함
응용 소프트웨어 개발과의 차이점
- 시스템 프로그래밍은 모든 응용 프로그램에 포함되는 요소이다.
02. 컴퓨터 하드웨어의 구성
CPU ↔ Cache ↔ Main Memory ↔ Hard Disk
CPU(Central Processing Unit)
- 중앙처리장치로서 기본적으로 연산을 담당한다.
- 연산이 이뤄지는 원리는 무엇인가?
메인 메모리(Main Memory)
- 램(RAM)이라는 저장장치로 구성된다.
- 컴파일이 완료된 프로그램 코드가 올라가서 실행되는 영역
- 메인 메모리는 프로그램 실행을 위해 존재하는 메모리
- 프로그램 실행 방식을 이해하는 것
- 컴퓨터를 구성하는 구성요소 사이에서 데이터를 주고 받기 위해 사용되는 경로(매개체)
- 주고 받는 데이터의 종류와 역할에 따라서 Address Bus, Data Bus, Control Bus 이렇게 세 가지로 구분된다.
- 입/출력 버스의 대략적인 역할은 하드디스크, 메인 메모리, CPU 등 모두 입/출력 버스에 연결되어 있는데, 이러한 버스 시스템을 기반으로 하드디스크 ↔ 메인 메모리, 메인 메모리 ↔ CPU 등 데이터의 입/츨력이 가능하게 해준다.
03. CPU에 대한 이해
ALU(Arithmetic Logic Unit)
- CPU 내부에서 실제 연산을 담당하는 블록
- 덧셈이나 뺄셈과 같은 산술 연산
- AND나 OR와 같은 논리연산
- 크게 기본적인 연산은 위와같이 2가지로 나뉜다.
컨트롤 유닛(Control Unit)
- 프로그래머가 작성한 프로그램을 컴파일하면 실행파일이 생성되고, 이 실행파일에는 CPU에게 일을 시키기 위한 명령어들이 저장되어 있다.
- 실행파일에 있는 명령어들이 일련의 과정을 통해서 CPU 내부로 들어갔을 때, CPU에 존재하는 각각의 블럭들이 처리해야 할 명령어들을 해석한다.
- CPU의 총 사령관
CPU 내부에 존재하는 레지스터들(Register Set)
- CPU 내부에 임시적으로 데이터를 저장하기 위한 아주 작은 메모리, 즉 2진 데이터(Binary Data) 저장을 위한 저장장치이다.
- CPU에 따라서 16비트, 32비트, 64비트 정도의 데이터를 저장한다.
- 레지스터들은 CPU 내부에 여러 개가 존재하는데 CPU의 종류에 따라서 그 개수와 형태가 다양하고, 레지스터들은 각각의 용도가 정해져 있다.
버스 인터페이스(Bus Interface)
- 컴퓨터에는 CPU, 하드디스크, RAM, 사운드 카드, 그래픽 카드 등 여러 장치들이 서로 독립적으로 동작하는 것이 아니라 I/O 버스라는 매개체를 통해서 서로 데이터를 주고 받으면서 동작한다.
- 이 때, CPU 내에 I/O 버스의 통신 방식(어떻게 데이터를 전송하는지)을 이해하고 있는 장치가 버스 인터페이스이다.
— I/O 버스와 CPU와의 연결을 위해서 인터페이스가 필요한 것처럼, I/O 버스와 하드디스크, I/O 버스와 그래픽 카드와의 연결을 위해서도 인터페이스가 필요하다. 즉 I/O 버스에 연결되는 장치들은 모두 인터페이스가 필요하다.
클럭 신호(Clock Pluse)
- 클럭 신호는 CPU를 구성하는 요소는 아니지만, CPU를 구성하는 구성 요소에 제공되어야 하는 신호로서 아주 중요한 의미를 지닌다.
- 클럭 신호는 타이밍을 제공하기 위해서 필요하다.
- 예시) CPU의 클럭 속도가 1.6Mhz라고 가정한다면, 이 경우에 클럭발생기는 1초당 1,600,000번의 클럭을 발생시키게 설정되고 매 클럭이 발생할 때마다 그 클럭에 맞춰서 일을 한다.
- 정리) 클럭발생기에 의해 발생되는 클럭 신호는 CPU를 구성하는 요소 요소에 제공되며, 이 신호에 맞춰서 CPU가 일을 한다.
- 컴퓨터 시스템의 동기화의 필요성 때문에 일련의 연산 과정 중 속도가 느린 장치의 발생 속도에 클럭 신호를 맞춰야 한다.
04. 프로그램의 실행과정
폰 노이만의 컴퓨터 구조
- CPU ↔ 메모리 ← 프로그램
- (Stored Program Concept) 프로그램이라는 것이 존재하고, 이 프로그램은 컴퓨터 내부에 저장되어서 순차적으로 실행되어야 한다.
프로그램의 실행과정
-
실행 파일 생성 과정: 전처리기 → 컴파일러 → 어셈플러 → 링커
- 전처리기에 의한 치환작업
- 컴파일러에 의한 번역
- 컴파일러에 의해서 소스코드 → 어셈블리 코드로 변역된다.
- 어셈블리 코드란? CPU가 디자인될 때, CPU에게 일을 시키기 위한 명령어도 함께 디자인되는데, 이러한 명령어를 조합해서 만들어진 프로그램 코드를 의미한다.
- 어셈블러에 의한 바이너리 코드 생성
- 바이너리 코드: 1과 0으로만 구성되는 코드
- 컴퓨터는 오로지 1과 0만을 이해하기 때문에 컴파일러에 의해 번역된 어셈블리 코드는 컴퓨터에 의해 실행되기에 앞서서 바이너리 코드로 번역되어야 한다.
- 링커에 의한 연결과 결합
- 프로그램 내에서 참조하는 함수나 라이브러리들을 하나로 묶는 작업
- 이 과정이 끝나게 되면 실행 가능한 실행파일이 생성된다.
-
실행 파일 안에 컴퓨터가 실행해야 할 바이너리 코드가 존재한다. 이 바이너리 코드가 메모리에 로드되는 과정과 폰 노이만의 'Stored Program Concept'을 하나로 묶어서 전체적인 프로그램 실행 과정에 대해서 알아보자.
-
폰 노이만의 'Stored Program Concept'
- Fetch: 메모리 상에 존재하는 명령어를 CPU로 가져오는 작업
- Decode: CPU에 가져다 놓은 명령어를 CPU가 해석하는 단계이다.
- Execution: 해석된 명령어의 명령대로 CPU가 실행하는 단계이다.
05. 하드웨어 구성의 재접근
폰 노이만의 컴퓨터 구조 vs 오늘날의 컴퓨터 구조
- 앞서 살펴본 폰 노이만의 컴퓨터 구조를 오늘날의 컴퓨터 구조로 구체화시켜보자
- 명령어 실행을 위해서 제일 먼저 하는 일은 Fetch인데, 어떠한 이동 경로를 통해서 명령어의 Fetch가 진행되는 것인가?
- 데이터를 이동하는 데 있어서 사용되는 전송 경로를 가리켜 버스 시스템이라 한다.
- 버스 시스템은 주고 받는 데이터의 종류에 따라서 어드레스 버스, 데이터 버스, 그리고 컨트롤 버스 이렇게 3가지 요소로 구성된다.
- 데이터 버스: 데이터를 이동하기 위해 필요한 버스 (명령어 또는 피연산자)
- 어드레스 버스: 주소 값을 이동하기 위해 필요한 버스
- 컨트롤 버스: CPU가 원하는 바를 메모리에 전달할 때 사용됨. CPU와 메모리가 서로 특별한 사인을 주고받는 용도로 사용되는 버스
- 명령어를 CPU 안에 가져다 놓을 때 어디에 저장하는 것인가?
- 메인 메모리에 저장되어 있는 명령어의 실행을 위해서 명령어를 CPU로 이동시키고 이렇게 이동된 명령어를 저장하기 위해 사용하는 것은 레지스터이다. (Instruction Register)
- CPU 안에 가져다 놓은 명령어는 Decode 단계에서 해석되는데, 이는 CPU 안에 존재하는 누구에 의해서 진행되는 것인가?
- 마지막 단계인 Execution은 누구에 의해서 진행되는가?
- 명령어의 요구대로 실행을 하는 Execution의 주체는 누구일까? 사실 명령어를 통해서 요구하는 것은 형태가 아주 다양하다. 데이터의 이동, 산술 및 논리 연산 등이 있지만 예를 들어 명령어의 내용이 산술 및 논리 연산이라면 산술 및 논리 연산을 하는 Execution의 주체는 ALU(Arithmetic Logic Unit)이 될 것이다.
요약
- ALU와 컨트롤 유닛의 기능적 역할
- 명령어가 CPU로 입력되었을 때 ALU와 컨트롤 유닛의 역할을 기억하자. 명령어의 내용대로 연산을 하는 주 요소는 ALU이지만, 명령어를 분석해서 해야 할 일을 결정하는 요소는 컨트롤 유닛이다.
- 레지스터의 필요성
- 클럭 펄스의 필요성
- 클럭은 동기화를 위해서 필요한 장치이고, CPU는 인가되는 클럭 펄스에 맞춰서 일을 함
- Fetch, Decode, Execution
- 'Stored program concept'의 명령어 실행 단계는 Fetch → Decode → Execution이다. 메인 메모리에 저장되어 있는 명령어를 CPU 내부로 가져오고, 컨트롤 유닛에 의해 분석된 다음 ALU에 의해 연산이 이뤄진다.
- 버스 인터페이스
- CPU 내부 및 외부에 있는 요소들은 서로 I/O 버스를 통해서 데이터를 주고 받는다. BUS를 통해서 데이터를 주고 받기 위해서는 BUS의 통신방식에 맞게 데이터 입/출력을 돕는 인터페이스 장치가 있어야 하며, 이 인터페이스 장치를 가리켜 컨트롤러 혹은 어댑터라고 부른다.
Reference