본문 바로가기
TIL (Today I Learned)/컴퓨터 시스템(CS)

[CS] CS:APP #1

by 둥굴프 2022. 11. 30.
해당 포스트는 다음 서적을 참고하여 작성하였습니다. [컴퓨터 시스템(CS:APP) 제 3판, 퍼스트북]

 

CHAPTER 1

 

컴퓨터 시스템을 배워야 하는 이유 (파워 프로그래머에게 필요한 역략)

 

(1) C코드를 최적화하는 방법을 알게된다.

(2) 컴파일러가 프로시저 호출을 어떻게 구현하는지 알게된다.

(3) 버퍼 오버플로우 위험성으로부터 어떻게 시스템을 보호할 수 있는지 알게된다.

(3) 링커 과정에서 발생하는 심각한 에러를 이해하고 회피하는 방법을 알게된다.

(4) 유닉스 쉘, 동적 메모리 할당 패키지, 웹 서버를 작성하는 방법을 알게된다.

(5) 멀티 프로레서 코어들이 한 개의 칩에 집적됨에 따라 동시성의 가능성과 위험성을 알게된다.

 

 

1.1 정보는 비트와 컨텍스트로 이루어진다.

 

오로지 아스키 문자들로만 이루어진 파일들은 텍스트 파일이라고 부른다.

다른 모든 파일들은 바이너리 파일이라고 한다.

 

서로 다른 객체들을 구분하는 유일한 방법은 이들을 바라보는 컨텍스트에 의해서다.

다른 컨텍스트에서는 동일한 일련의 바이트가 정수, 부동소수, 문자열 또는 기계어 명령을 의미할 수 있다.

 

 

1.2 프로그램은 다른 프로그램에 의해 다른 형태로 번역된다

// hello.c
#include <stdio.h>

int main()
{
	printf("Hello, World\n");
    return 0;
}

hello.c를 시스템에서 실행시키려면 각 C 문장들은 저급 기계어 인스트럭션들로 번역되어야만 한다.

이 인스트럭션들은 실행가능 목적 프로그램이라고 한다. 실행가능 목적 피일이라고도 부른다.

컴파일러 드라이버는 유닉스 시스템에서 다음과 같이 소스파일에서 오브젝트 파일로 번역한다.

gcc -o hello hello.c

GCC 컴파일러 드라이버는 hello.c를 읽어서 실행파일인 hello로 번역한다.

다음과 같은 4개의 단계를 합쳐서 컴파일 시스템이라고 부른다.

(1) 전처리기

(2) 컴파일러

(3) 어셈블러

(4) 링커

 

1) 전처리기 단계

본래의 C프로그램을 #문자로 시작하는 디렉티브(directive)에 따라 수정한다.

헤더파일을 프로그램 문장에 직접 삽입한다.

hello.i라는 새로운 C 프로그램이 생성된다.

 

2) 컴파일 단계

컴파일러(ccl)은 텍스트파일 hello.i를 텍스트파일인 hello.s로 번역한다.

이 파일에는 어셈블리어 프로그램이 저장된다.

 

3) 어셈블리 단계

어셈블러(as)가 hello.s를 기계어 인스트럭션으로 번역한다.

재배치가능 목적프로그램의 형태로 묶어서 hello.o라는 목적파일에 그 결과를 저장한다.

이 파일은 바이너리 파일이다.

 

4) 링크 단계

printf함수는 이미 컴파일된 별도의 목적파일인 printf.o에 들어있다.

이 파일은 hello.o 파일과 어떤 형태로든 결합되어야 한다,

링커 프로그램(ld)이 이 통합작업을 수행한다.

결과인 hello파일은 실행가능 목적파일로 메모리에 적재되어 시스템에 의해 실행된다.

 

1.4 프로세서는 메모리에 저장된 인스트럭션을 읽고 해석한다

 

쉘은 커맨드라인 인터프리터로 프롬프트를 출력하고 명령어 라인을 입력 받아 그 명령을 실행한다.

 

1.4.1 시스템의 하드웨어 조직

 

버스(bus)

컴포넌트들 간에 바이트 정보들을 전송한다.

버스는 일반적으로 워드word라고 하는 고정 크기의 바이트 단위로 데이터를 전송하도록 설계된다.

 

메인 메모리

데이터와 프로그램을 모두 저장하는 임시 저장장치다.

각 기계어 인스트럭션은 다양한 바이트 크기를 갖는다.

 

프로세서

주처리장치(CPU) 또는 프로세서는 메인메모리에 저장된 인스트럭션들을 해독(실행)하는 엔진이다.

프로세서의 중심에는 워드 크기의 레지스터인 프로그램 카운터(PC)가 있다.

PC는 메인 메모리의 기계어 인스트럭션을 가리킨다.

 

프로그램 카운터의 작동과정

- 프로세서는 PC가 가리키는 메모리로부터 인스트럭션을 읽는다.

- 인스트럭션에서 비트들을 해석하여 간단한 동작을 실행한다.

- PC를 다음 인스트럭션 위치로 업데이트 한다.

 

인스트럭션의 요청에 의해 CPU가 실행하는 간단한 작업의 예 :

적재(Load) : 메인 메모리에서 레지스터에 한 바이트 또는 워드를 이전 값에 덮어쓰는 방식으로 복사.

저장(Store) : 레지스터에서 메인 메모리로 한 바이트 또는 워드를 이전 값을 덮어쓰는 방식으로 복사.

작업(Operate) : 두 레지스터 값을 ALU로 복사하고 두 개의 워드로 수식연산을 수행한 뒤, 결과를 덮어쓰기 방식으로 레지스터에 저장.

점프(Jump) : 인스트럭션 자신으로부터 한 개의 워드를 추출하고, 이것을 PC에 덮어쓰기 방식으로 복사한다.

 

 

1.4.2 hello 프로그램의 실행

쉘은 파일 내의 코드와 데이터를 복사하는 일련의 인스트럭션을 실행하여 실행파일 hello를 디스크에서 메인 메모리로 로딩한다.

 

 

1.5 캐시가 중요하다

시스템이 정보를 한 곳에서 다른 곳으로 이동시키는 일에 많은 시간을 보낸다.

메인 메모리를 더 빠르게 동작하도록 만드는 것보다 프로세서를 더 빨리 동작하도록 만드는 것이 더 쉽고 비용이 적게 든다.

프로세서-미모리 간 격차에 대응하기 위해 시스템 설계자는 보다 작고 빠른 캐시 메모리라고 부르는 저장장치를 고안하여 프로세서가 단기간에 필요로 할 가능성이 높은 정보를 임시로 저장할 목적으로 사용한다.

캐시는 SRAM Static Random Access Memory이라는 하드웨어 기술을 이용해 구현한다.

프로그램이 지엽적인 영역의 코드와 데이터를 액세스하는 경향인 지역성locality을 활용하여 시스템이 매무 크고 빠른 메모리 효과를 얻을 수 있다는 것이다.

자주 액세스할 가능성이 높은 데이터를 캐시가 보관하도록 설정하면 빠른 캐시를 이용해서 대부분의 메모리 작업을 수행할 수 있게 된다.

 

 

1.6 저장장치들은 계층 구조를 이룬다

레지스터 파일은 계층구조의 최상위인 레벨0, 즉 L0를 차지한다.

메모리 계층구조의 주요 아이디어는 한 레벨의 저장장치가 다음 하위레벨 저장장치의 캐시 역할을 한다는 것이다.

 

 

1.7 운영체제는 하드웨어를 관리한다

응용프로그램이 하드웨어를 제어하려면 언제나 운영체제를 통해서 해야 한다.

운영 체제는 두 가지 주요 목적을 가지고 있다.

(1) 하트웨어를 잘못 사용하는 것을 막기 위해

(2) 단순하고 균일한 메커니즘을 사용하여 복잡하고 매우 다른 저수준 하드웨어 장치들을 조작할 수 있도록 하기 위해

 

운영체제는 이 두 가지 목표를 근본적인 추상화를 통해 달성한다. 프로세스, 가상메모리, 파일.

파일 : 입출력장치의 추상화

가상메모리 : 메인 메모리와 디스크 입출력 장치의 추상화

프로세스 : 프로세서, 메인 메모리, 입출력장치 모두의 추상화 결과

 

 

1.7.1 프로세스

프로세스는 실행 중인 프로그램에 대한 운영체제의 추상화다.

프로세서가 프로세스들을 바꿔주는 방식으로 한 개의 CPU가 다수의 프로세스를 동시에 실행하는 것처럼 보이게 해준다.

운영체제는 문맥 전환context switching이라는 방법을 사용해서 이러한 교차실행을 수행한다.

다른 프로세스로의 전환은 운영체제 커널kernel에 의해 관리된다.

커널은 운영체제 코드의 일부분으로 메모리에 상주한다.

커널은 별도의 프로세스가 아니라는 점에 유의해야 한다.

커널은 모든 프로세스를 관리하기 위해 시스템이 이용하는 코드와 자료구조의 집합이다.

 

 

1.7.2 쓰레드(Thread)

최근의 시스템에서는 프로세스가 실제로 쓰레드Thread라고 하는 다수의 실행 유닛으로 구성되어 있다.

각각의 쓰레드는 해당 프로세스의 컨텍스트에서 실행되며 동일한 코드와 전역 데이터를 공유한다.

다수의 프로세스들에서보다 데이터의 공유가 더 쉽고, 쓰레드가 프로세스보다 더 효율적이다.

 

 

1.7.3 가상메모리

가상메모리는 각 프로세스들이 메인 메모리 전체를 독점적으로 사용하고 있는 것 같은 환상을 제공하는 추상화이다.

주소공간의 최상위 영역은 모든 프로세스들이 공통으로 사용하는 운영체제의 코드와 데이터를 위한 공간이다. 주소공간의 하위 영역은 사용자 프로세스의 코드와 데이터를 저장한다.

 

프로그램 코드와 데이터, 힙 Heap, 공유 라이브러리, 스택 Stack, 커널 가상메모리

 

: C 표준함수인 malloc이나 free를 호출하면서 런타임에 동적으로 그 크기가 늘었다 줄었다 한다.

커널 가상메모리 : 주소공간의 맨 윗부분은 커널을 위해 예약되어있다.

 

가상메모리가 작동하기 위해서는 프로세서가 만들어내는 모든 주소를 하드웨어로 번역하는 등의 하드웨어와 운영체제 소프트웨어 간의 복잡한 상호작용이 필요하다. 프로세스의 가상메모리의 내용을 디스크에 저장하고 메인 메모리를 디스크의 캐시로 사용하는 것이다.

 

1.7.4 파일

파일은 더도 덜도 말고 그저 연속된 바이트들이다.

모든 입출력 장치는파일로 모델링한다.

 

1.8 시스템은 네트워크를 사용하여 다른 시스템과 통신한다

네트워크는 단지 또 다른 입출력장치로 볼 수 있다.

 

1.9.2 동시성과 병렬성

동시성concurrency : 다수의 동시에 벌어지는 일을 갖는 시스템에 관한 일반적인 개념

병렬성parallelism : 동시성을 사용해서 시스템을 보다 빠르게 동작하도록 하는 것

 

 

 

 

 

 

글을 마치며,

 

chpater1에서 컴퓨터 시스템의 작동 개요를 확인했다.

처음 보는 단어들이 많다.

열심히 공부하자.

다음에는 chapter3 프로그램의 기계수준 표현에 대해 포스팅할 예정이다.

 

긴 글 읽어주셔서 감사드립니다.

22.11.30

댓글