cs

[크래프톤 정글] 컴퓨터 시스템 ~ 1장

하루이2222 2024. 9. 15. 02:05

이 포스트의 내용은 '컴퓨터 시스템 A Programmer's Perspective' 도서의 내용을 기반으로 합니다.

1장: 컴퓨터 시스템 개요

1.1 컴퓨터 시스템의 기본 개념

  • 컴퓨터 시스템은 하드웨어와 소프트웨어로 구성된다. 이 둘은 서로 밀접하게 연결되어 있으며, 프로그램이 하드웨어 상에서 어떻게 동작하는지를 이해하는 것이 중요하다.
  • 하드웨어 구성 요소: 프로세서(CPU), 메모리, I/O 장치 등이 있다. 프로세서는 프로그램의 명령어를 실행하고, 메모리는 데이터를 저장하며, I/O 장치는 외부 세계와의 인터페이스를 제공한다.

1.2 프로그램의 실행

  • 프로그램이 실행되는 과정:
    1. 소스 코드 작성: 프로그래머가 고급 언어(C, Java 등)로 작성한 소스 코드.
    2. 컴파일: 컴파일러가 소스 코드를 어셈블리 언어로 변환하고, 이후 어셈블러가 이를 기계어로 변환한다.
    3. 링킹(Linking): 링커가 여러 오브젝트 파일(object files)과 라이브러리를 결합하여 실행 가능한 프로그램을 생성한다.
    4. 로딩(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. 사용자 입력 단계 (그림 1.5 시작)
    • 사용자가 키보드로 입력을 하면, 키보드는 I/O 장치를 통해 키보드 컨트롤러에 신호를 보낸다.
    • 키보드 컨트롤러는 입력 데이터를 I/O 브리지를 통해 시스템 버스(System Bus)로 전달한다.
    • 이 데이터는 인터럽트(Interrupt)로 CPU에 알려지며, CPU는 현재 실행 중인 작업을 잠시 멈추고, 인터럽트 서비스 루틴(Interrupt Service Routine, ISR)을 실행하여 입력 데이터를 처리한다.
  2. 데이터가 CPU에 전달됨
    • CPU가 인터럽트를 처리하면서 입력 데이터를 레지스터 파일(Register File)에 임시 저장한다.
    • 레지스터에 있는 데이터는 CPU가 빠르게 접근하여 처리할 수 있으므로, 데이터는 여기서 일시적으로 머문다.
  3. CPU에서 메모리로 데이터 저장
    • 입력 데이터가 처리되면, CPU는 이 데이터를 메인 메모리(Main Memory)에 저장한다.
    • 이 과정은 데이터가 지속적으로 사용될 수 있도록 하기 위함이며, 일반적으로 프로그램은 메모리에 저장된 데이터를 사용하여 동작한다.
    • 따라서, CPU는 메모리 버스를 통해 입력 데이터를 메모리로 전송한다.
  4. 사용자 명령 해석 및 실행 준비 (그림 1.6로 연결되는 부분)
    • 사용자가 입력한 명령이 프로그램 실행 명령(예: ./hello)인 경우, 이 명령은 쉘(Shell)에 의해 해석된다.
    • 쉘은 입력된 명령어를 분석하여 실행 파일의 경로와 이름을 확인한 후, 운영체제 커널(Kernel)에게 exec() 시스템 호출을 사용하여 프로그램 실행을 요청한다.
  5. 운영체제 커널의 프로세스 생성
    • 운영체제는 실행 파일을 실행하기 위해 새로운 프로세스를 생성한다.
    • 이때 커널은 fork() 시스템 호출을 사용하여 부모 프로세스(쉘)의 복사본을 생성하고, 자식 프로세스로서 새로운 메모리 공간을 할당받는다.
    • 이 자식 프로세스는 exec() 시스템 호출을 통해 현재 프로세스를 실행 파일로 덮어쓴다.
  6. 실행 파일 로드 준비 (그림 1.6의 시작)
    • 커널은 새로 생성된 프로세스의 메모리 공간을 초기화하고, 기존의 메모리 내용을 제거하거나 덮어쓴다.
    • 운영체제의 로더(Loader)가 호출되어 실행 파일을 메모리에 로드할 준비를 한다.
    • 로더는 파일의 헤더 정보를 읽고, 프로그램의 코드와 데이터 세그먼트, 힙(Heap), 스택(Stack) 등을 메모리에 적절하게 배치할 메모리 공간을 할당한다.
  7. 실행 파일 로드 (그림 1.6의 주요 내용)
    • 로더는 프로그램의 각 세그먼트를 메모리의 특정 위치로 복사한다:
      • 코드 세그먼트(Text Segment): 프로그램의 명령어가 저장된다.
      • 데이터 세그먼트(Data Segment): 초기화된 전역 변수와 정적 변수가 저장된다.
      • 힙(Heap): 동적 메모리 할당에 사용할 공간이 마련된다.
      • 스택(Stack): 함수 호출 시 사용되는 지역 변수와 반환 주소 등이 저장된다.
    • 로더는 필요한 동적 라이브러리를 로드하고, 동적 링커(dynamic linker)를 통해 프로그램과 라이브러리의 함수 주소를 연결한다.
  8. 프로세스 실행 준비 완료
    • 실행 파일이 메모리에 로드되면, 로더는 프로그램의 진입점(Entry Point)(일반적으로 main 함수의 시작 주소)를 프로그램 카운터(PC)에 설정한다.
    • 커널은 새로운 프로세스에 CPU의 제어권을 넘기고, 프로그램의 명령어 실행을 시작한다.
  9. 프로그램 실행 (그림 1.6의 끝)
    • CPU는 프로그램의 진입점에서부터 명령어를 순차적으로 실행하며, 메모리에 저장된 데이터를 읽거나 쓰면서 프로그램을 진행한다.
    • 프로그램이 종료되면, 운영체제는 프로세스의 자원을 회수하고 메모리를 해제한다.