이 포스트의 내용은 '컴퓨터 시스템 A Programmer's Perspective' 도서의 내용을 기반으로 합니다.
1장: 컴퓨터 시스템 개요
1.1 컴퓨터 시스템의 기본 개념
- 컴퓨터 시스템은 하드웨어와 소프트웨어로 구성된다. 이 둘은 서로 밀접하게 연결되어 있으며, 프로그램이 하드웨어 상에서 어떻게 동작하는지를 이해하는 것이 중요하다.
- 하드웨어 구성 요소: 프로세서(CPU), 메모리, I/O 장치 등이 있다. 프로세서는 프로그램의 명령어를 실행하고, 메모리는 데이터를 저장하며, I/O 장치는 외부 세계와의 인터페이스를 제공한다.
1.2 프로그램의 실행
- 프로그램이 실행되는 과정:
- 소스 코드 작성: 프로그래머가 고급 언어(C, Java 등)로 작성한 소스 코드.
- 컴파일: 컴파일러가 소스 코드를 어셈블리 언어로 변환하고, 이후 어셈블러가 이를 기계어로 변환한다.
- 링킹(Linking): 링커가 여러 오브젝트 파일(object files)과 라이브러리를 결합하여 실행 가능한 프로그램을 생성한다.
- 로딩(Loading): 로더가 실행 파일을 메모리에 로드하고, 프로세서가 프로그램의 명령어를 실행한다.
1.3 정보의 표현과 저장
- 컴퓨터는 이진수(binary)를 사용하여 정보를 저장한다. 모든 데이터(정수, 부동 소수점, 문자 등)는 이진수로 표현된다.
- 바이트(byte)는 컴퓨터 메모리에서 데이터 저장의 기본 단위다. 메모리는 바이트 주소(address)로 구분되며, 각 주소는 고유한 값을 갖는다.
- 다양한 데이터 타입(정수, 부동 소수점, 포인터 등)이 메모리에 어떻게 저장되고 표현되는지를 이해하는 것이 중요하다.
1.4 프로세서와 컴파일러의 역할
- 컴파일러는 고급 언어를 기계어로 변환하는 프로그램이다. 컴파일러는 소스 코드를 어셈블리 코드로 변환하고, 어셈블러는 어셈블리 코드를 기계어로 변환한다.
- 프로세서(CPU)는 기계어 명령어를 읽고 실행한다. 이 과정에서 CPU는 메모리에서 데이터를 읽고, 처리하며, 결과를 다시 메모리에 쓴다.
1.5 운영체제의 역할
- 운영체제(OS)는 컴퓨터의 자원을 관리하고, 프로그램이 하드웨어와 상호작용할 수 있도록 도와준다. 운영체제는 CPU 스케줄링, 메모리 관리, 파일 시스템, 네트워킹 등 다양한 기능을 제공한다.
- 운영체제는 프로세스(Process)라는 실행 단위를 통해 프로그램이 실행되도록 한다. 각 프로세스는 독립적인 메모리 공간을 가지고 있으며, 운영체제는 이들을 관리한다.
1.6 컴퓨터 시스템의 계층 구조
- 컴퓨터 시스템은 다양한 계층(Layer)으로 구성되어 있으며, 각 계층은 하위 계층의 추상화를 제공한다.
- 응용 프로그램 계층: 사용자가 직접 실행하는 프로그램(예: 웹 브라우저, 텍스트 편집기).
- 운영체제 계층: 프로그램과 하드웨어 간의 인터페이스 역할을 한다.
- 하드웨어 계층: CPU, 메모리, 디스크, 네트워크 장치 등의 실제 물리적 컴포넌트.
1.7 컴퓨터 시스템과 프로그래밍
- 프로그래머가 시스템을 이해하면 더 나은 성능과 효율성을 갖춘 프로그램을 작성할 수 있다.
- 메모리 계층 구조를 이해하면 캐시 친화적인 코드를 작성할 수 있고, CPU 아키텍처를 이해하면 병렬 프로그래밍 및 최적화를 할 수 있다.
- 프로그래머는 시스템의 저수준 세부사항(예: 포인터, 메모리 주소, 비트 연산 등)을 이해함으로써 시스템 프로그래밍 및 디버깅에서 이점을 가질 수 있다.
보충 설명
hello 프로그램의 실행(p10)
- 사용자 입력 단계 (그림 1.5 시작)
- 사용자가 키보드로 입력을 하면, 키보드는 I/O 장치를 통해 키보드 컨트롤러에 신호를 보낸다.
- 키보드 컨트롤러는 입력 데이터를 I/O 브리지를 통해 시스템 버스(System Bus)로 전달한다.
- 이 데이터는 인터럽트(Interrupt)로 CPU에 알려지며, CPU는 현재 실행 중인 작업을 잠시 멈추고, 인터럽트 서비스 루틴(Interrupt Service Routine, ISR)을 실행하여 입력 데이터를 처리한다.
- 데이터가 CPU에 전달됨
- CPU가 인터럽트를 처리하면서 입력 데이터를 레지스터 파일(Register File)에 임시 저장한다.
- 레지스터에 있는 데이터는 CPU가 빠르게 접근하여 처리할 수 있으므로, 데이터는 여기서 일시적으로 머문다.
- CPU에서 메모리로 데이터 저장
- 입력 데이터가 처리되면, CPU는 이 데이터를 메인 메모리(Main Memory)에 저장한다.
- 이 과정은 데이터가 지속적으로 사용될 수 있도록 하기 위함이며, 일반적으로 프로그램은 메모리에 저장된 데이터를 사용하여 동작한다.
- 따라서, CPU는 메모리 버스를 통해 입력 데이터를 메모리로 전송한다.
- 사용자 명령 해석 및 실행 준비 (그림 1.6로 연결되는 부분)
- 사용자가 입력한 명령이 프로그램 실행 명령(예:
./hello
)인 경우, 이 명령은 쉘(Shell)에 의해 해석된다. - 쉘은 입력된 명령어를 분석하여 실행 파일의 경로와 이름을 확인한 후, 운영체제 커널(Kernel)에게
exec()
시스템 호출을 사용하여 프로그램 실행을 요청한다.
- 사용자가 입력한 명령이 프로그램 실행 명령(예:
- 운영체제 커널의 프로세스 생성
- 운영체제는 실행 파일을 실행하기 위해 새로운 프로세스를 생성한다.
- 이때 커널은
fork()
시스템 호출을 사용하여 부모 프로세스(쉘)의 복사본을 생성하고, 자식 프로세스로서 새로운 메모리 공간을 할당받는다. - 이 자식 프로세스는
exec()
시스템 호출을 통해 현재 프로세스를 실행 파일로 덮어쓴다.
- 실행 파일 로드 준비 (그림 1.6의 시작)
- 커널은 새로 생성된 프로세스의 메모리 공간을 초기화하고, 기존의 메모리 내용을 제거하거나 덮어쓴다.
- 운영체제의 로더(Loader)가 호출되어 실행 파일을 메모리에 로드할 준비를 한다.
- 로더는 파일의 헤더 정보를 읽고, 프로그램의 코드와 데이터 세그먼트, 힙(Heap), 스택(Stack) 등을 메모리에 적절하게 배치할 메모리 공간을 할당한다.
- 실행 파일 로드 (그림 1.6의 주요 내용)
- 로더는 프로그램의 각 세그먼트를 메모리의 특정 위치로 복사한다:
- 코드 세그먼트(Text Segment): 프로그램의 명령어가 저장된다.
- 데이터 세그먼트(Data Segment): 초기화된 전역 변수와 정적 변수가 저장된다.
- 힙(Heap): 동적 메모리 할당에 사용할 공간이 마련된다.
- 스택(Stack): 함수 호출 시 사용되는 지역 변수와 반환 주소 등이 저장된다.
- 로더는 필요한 동적 라이브러리를 로드하고, 동적 링커(dynamic linker)를 통해 프로그램과 라이브러리의 함수 주소를 연결한다.
- 로더는 프로그램의 각 세그먼트를 메모리의 특정 위치로 복사한다:
- 프로세스 실행 준비 완료
- 실행 파일이 메모리에 로드되면, 로더는 프로그램의 진입점(Entry Point)(일반적으로
main
함수의 시작 주소)를 프로그램 카운터(PC)에 설정한다. - 커널은 새로운 프로세스에 CPU의 제어권을 넘기고, 프로그램의 명령어 실행을 시작한다.
- 실행 파일이 메모리에 로드되면, 로더는 프로그램의 진입점(Entry Point)(일반적으로
- 프로그램 실행 (그림 1.6의 끝)
- CPU는 프로그램의 진입점에서부터 명령어를 순차적으로 실행하며, 메모리에 저장된 데이터를 읽거나 쓰면서 프로그램을 진행한다.
- 프로그램이 종료되면, 운영체제는 프로세스의 자원을 회수하고 메모리를 해제한다.
'cs' 카테고리의 다른 글
[크래프톤 정글] hello.s 의 어셈블리 의 구조 (0) | 2024.09.30 |
---|---|
[크래프톤 정글 ] hello.c의 실행 과정 (0) | 2024.09.30 |
[크래프톤 정글] cpu 레지스터 (1) | 2024.09.30 |
[크래프톤 정글] 컴퓨터 시스템 13p - 메모리 계층 구조 (0) | 2024.09.15 |
Django vs Flask vs Spring (1) | 2024.07.23 |