윈도우즈 시스템 프로그래밍 1장
시작 전 소개
위 책을 읽으며 제가 개인적으로 공부한 부분 등을 채워 넣을 예정입니다.
책의 내용의 경우 요약의 형태로 작성 할 예정이어서, 혹시나 제 게시물만으로 공부를 하실 분이 있다면 내용이 부족할 수도 있습니다.
왜 시작부터 하드웨어 이야기를 하는가
전공자들에게는 이 책이 어떨지 모르겠으나, 알고리즘만 공부한 뒤 이 책을 처음 읽었을 때 내 소감은 막막하다는 말 그 자체였다.
그러나, 시스템 프로그래밍을 공부하기 위해서는 windows가 제공하는 시스템 함수를 정확하게 이해해야하고
이것을 위해 필요한 것이 컴퓨터가 어떻게 돌아가는가와 같은 기초적인 지식이다.
컴퓨터 하드웨어의 구성
CPU에 대한 이해
ALU
CPU내부에 있는 연산을 담당하는 블록이다.
산술 연산 및 AND/OR과 같은 논리 연산을 담당한다.
왜 장치가 아니라 블록일까
나는 이 책을 읽으며, 너무 멍청하게도 블록이라는 말에 꽂혀 ALU가 물리적 분리가 아닌 논리적 분류인 줄 알았다.
즉 CPU라는 물리적인 부품 안에 ALU는 클래스와 같이 가상적인 분류에서만 존재한다는 착각을 했던 것이다.
그러나, ALU는 CPU 내부의 작은 칩셋에 포함된 복잡한 하드웨어 구성요소 중 하나로
물리적으로 CPU내부에 통합되어있다.
개념적으로는 CPU의 하위 시스템 중 하나로 나와 같이 이해할 수도 있으나, 물리적으로도 CPU내에서 독립적으로 존재한다.
컨트롤 유닛
ALU는 산술연산과 논리 연산만 할 줄 알기 때문에 명령어의 해석을 하지 못한다.
그렇기 때문에 컨트롤 유닛은 명령어를 해석하고 ALU에게 해야할 일에 대한 신호를 보내주는 역할을 한다.
레지스터(Register Set)
임시적으로 데이터를 저장하기 위한 조그마한 메모리 공간.
명령을 수행하는 데에 필요한 데이터를 저장하는 곳으로 5와 9를 더하는 연산으로 예시를 들자면 다음과 같이 작동한다.
5와 9를 더하는 연산 진행하기
A레지스터: 5 저장
B레지스터: 9 저장
ALU: ‘5+9’라는 연산 진행 후 14라는 결과를 도출
c레지스터: ALU로 부터 14라는 결과를 받아 저장
버스 인터페이스
외부와 데이터를 주고받는 데에 필요한 통로와 같다.
I/O버스는 하드디스크 램등 독립적으로 떨어진 장치들이 서로 데이터를 주고 받고 유기적으로 동작할 수 있도록 해주는 장치이다.
그리고 이 I/O버스의 통신 방식을 이해하고 있어서, 그때그때 데이터의 전송 방식 및 할 일은 지정해주는 것이 버스 인터페이스이다.
버스 인터페이스가 없다면?
⬛ 여러 장치가 데이터를 보내려고 할 때 충돌이 일어나서 데이터가 전송되지 않거나
왜곡이 일어날 수 있다.
⬛ 어드레스 버스(주소버스)가 없다면, 각 장치가 자신의 데이터를 쓸 메모리 주소를 정확하게 알지 못해서 잘못된 위치에 데이터가 쓰일 수 있다.
⬛ 제어 신호의 충돌로 어떤 장치가 버스를 제어하는지 혼란이 생길 수 있다.
⬛ 시간적 충돌이 발생하여 데이터의 전송이나 명령이 올바른 순서로 작동하지 않을 수 있다.
클럭신호(CPU의 구성요소 아님)
클럭 신호는 타이밍을 제공하는 데에 중요한 기여를 한다.
여기에서 말하는 타이밍이란 간단하게 설명하자면, 작업처리 속도가 느린 장치의 속도에 맞추어주는 작업이다.
이 신호에 맞추어 데이터를 전송하는 방식을 통해, 출력장치와 연산 장치의 속도를 맞추어줌으로써 버퍼가 올바른 값을 읽도록 해준다.
버퍼란
버퍼는 CPU와 보조 기억장치 사이에 있는 임시 저장공간이다.
말 그대로 임시 저장공간이기 때문에 용량이 작아서
클럭신호가 없다면 값이 저장되는 과정에서 다른 값으로 데이터가 변하게 될 수도 있다.
이것을 한마디로 표현하자면, 올바른 클럭신호가 없어서 올바른 타이밍에 버퍼에 저장되지 않으면 데이터 무결성이 위협받을 수 있다는 것이다.
프로그램의 실행과정
전처리기 작업
#include,#define
등으로 처리한 지시자의 지시에 따라 소스코드를 변경한다.
const의 경우 컴파일러 지시자이기 때문에
컴파일러의 단계에서 처리된다.
컴파일러에 의한 번역
전처리기 작업으로 치환된 소스코드를 컴파일러에 의해 어셈블리 코드로 번역하는 과정
어셈블러에 의한 바이너리 코드 생성
텍스트코드↔바이너리 코드
1과 0으로만 구성된 코드
0011이 ADD를 읨한다면, 어셈블러는 프로그래머가 ADD를 입력했을 때 0011로 변환하여 CPU가 이해할 수 있도록 해준다.
링커에 의한 연결과 결합
프로그램에서 참조하는 함수나 라이브러리들을 하나로 묶고 실행파일을 생성한다.
이 실행파일 내에 있는 바이너리 코드가 존재하는데 이것이 실행되기까지는 3개의 단계가 있다.
링커 속 바이너리코드 형태의 명령어->메모리 공간에 올라감
->CPU에 의해 실행
이때 여러 개의 명령어 ABC가 있다고 가정
메모리 공간에 있는 ABC가 순차적으로 CPU로 이동을 해야 실행이 가능하다.
Fetch(1단계-메모리에서 CPU로 이동)
메모리 상에 존재하는 A가 CPU로 이동
이때 이동을 위해 앞에서 설명한 개념인 버스 인터페이스가 쓰인다.
또한 이동된 명령어를 잠시동안 저장하기 위해 레지스터 역시 사용된다.
Decode(2단계-해석)
어떤 일을 하라는 명령어인지 분석하는 단계.
바이너리 코드로 쓰여있는 명령어 A의 의미를 해석한다.
이때 컨트롤 유닛이 중요한 역할을 한다.
Exeuction(3단계-실행의 단계)
2단계에서 해석된 명령어 대로 CPU가 실행하는 단계
여기에서는 다양한 주체가 있으나,
산술연산과 논리연산에 한하여 ALU가 주체가 된다.
내용 묶기
버스 시스템
어드레스 버스/데이터 버스/컨트롤 버스로 구성
[주의사항]
데이터가 이동할 때 메인 메모리에 저장된 데이터를 CPU로 올리는 것만 언급되었으나
버스 시스템은 단방향이 아니라 양쪽으로 통신 가능하다.
즉 레지스터에 저장된 데이터를 메모리로 저장하는 것 역시 가능하다.
데이터 버스
데이터(피연산자나 명령어)의 이동을 위해 필요한 버스
어드레스 버스
주소값 이동을 위해 필요한 버스
메모리 영역에 주소값을 전달할 뿐 아니라, 데이터를 전송하느 컨트롤러까지 포함된 개념이다.
컨트롤 버스
CPU가 원하는 바를 메모리에 전달 시 사용
데이터를 보낼 것인지 받을 것인지와 같은 내용의 사인을 전달한다.
댓글남기기