cs

[크래프톤 정글] 컴퓨터 시스템 hello.c 실행 전체 플로우 정리

하루이2222 2024. 10. 16. 17:48

우리가 프로그램을 실행하기까지의 전체 과정을 설명하면, 먼저 hello.c 파일을 작성한 후 빌드를 시키면 다음과 같은 과정들이 차례대로 진행된다.

1. 전처리 과정

  1. 헤더 파일 확장: #include로 포함된 헤더 파일들이 실제 코드로 확장된다.
  2. 매크로 확장: #define으로 정의된 매크로가 코드에 삽입된다.
  3. 주석 제거: 소스 코드 내 모든 주석이 제거된다.

이 과정을 통해 전처리가 완료되며, 그 결과물은 .i 파일로 저장된다.

2. 컴파일 과정

  1. 구문 분석: 소스 코드의 문법을 검사하여 파싱한다.
  2. 구문 트리 생성: 구문 트리를 생성하여 코드의 구조를 분석한다.
  3. 중간 표현(IR): 구문 트리를 기반으로 중간 표현(Intermediate Representation)으로 변환된다.
  4. 어셈블리 코드 생성: 중간 표현을 기반으로 어셈블리 코드가 생성되며, 결과물은 .s 파일로 저장된다.

3. 어셈블러 과정

  1. 어셈블리 코드의 인스트럭션 변환: 어셈블러는 어셈블리 언어를 opcodeoperand로 구성된 기계어 명령어로 변환한다.
  2. 심볼 테이블 생성: 변수, 함수 등의 위치 정보를 담은 심볼 테이블이 생성된다.
  3. 섹션 분할: 코드, 데이터, 초기화된 변수, 초기화되지 않은 변수 등의 섹션이 분할된다.

이 과정을 통해 재배치 가능한 목적 파일인 .o 파일이 생성되며, 이 파일은 심볼 정보, 코드 영역, 초기화된 변수와 비초기화 변수에 대한 정보를 포함하고 있다.

4. 링커 과정

  1. 심볼 결합: 각 객체 파일의 심볼을 결합하고, 정의되지 않은 외부 참조를 해결한다.
  2. 동적 라이브러리 연결: 동적 라이브러리를 프로그램에 연결한다.
  3. 주소 재배치: 가상 메모리 주소를 할당하기 위해 페이지 번호와 오프셋을 사용하여 재배치 과정을 진행한다.
  4. 섹션 결합: 여러 객체 파일의 각 섹션을 결합하여 실행 파일을 생성한다.

이렇게 생성된 실행 파일은 ELF 포맷으로, 재배치 가능 목적 파일들과 크게 다르지 않지만 여러 목적 파일이 하나로 결합된 형태이다.

보완 설명 - 주소 재배치

링크 과정에서 주소 재배치는 페이지 번호와 오프셋을 통해 가상 주소가 할당되는 과정이다. 이후 프로그램 실행 중 MMU가 가상 주소를 물리 주소로 변환해, 실제 메모리에서의 위치를 관리한다. 이는 CPU와 MMU가 협력하여 가상 주소와 물리 주소 사이를 효율적으로 변환하는 작업이다.

더 자세한 과정 -> https://developsvai5096.tistory.com/94


5. 프로그램 실행

  1. ./hello를 실행하면 리눅스의 /bin이 실행 파일을 찾아 구문 분석을 하고, execve 시스템 콜을 통해 커널에 해당 파일을 실행하라는 명령을 전달한다.
  2. 커널은 실행 파일을 열어 실행 내용을 확인하고, 프로세스에 가상 메모리 공간을 할당한다.
  3. 프로세스 테이블에 등록되고, PCB(Process Control Block)가 생성되어 프로세스에 고유한 PID가 부여된다.
  4. 초기화 루틴이 실행되면서 프로세스의 기본 환경이 설정된다.

보완 설명 - /bin

/bin은 리눅스 및 유닉스 계열 운영체제에서 "binary" 의 약자로, 기본 시스템 명령어들이 저장된 디렉터리다. 이 디렉터리에는 시스템 부팅과 운영에 필수적인 실행 파일들이 위치하며, 일반 사용자와 시스템 관리자 모두가 사용하는 기본적인 명령어들이 여기에 존재한다. 참고로 /bin 경로는 시스템 전역에서 사용되는 명령이 존재하고, 사용자별 명령어는 "/home/username/bin" 이거나 사용자가 설치한 명령어를 전역에서 사용하고 싶다면 "/usr/local/bin" 경로를 사용한다.

6. CPU 명령어 실행

  1. 프로그램 카운터(PC)는 main 함수를 가리키고, CPU는 명령어 사이클(페치-디코드-실행)을 반복하며 명령어를 처리한다.
  2. 함수가 호출될 때마다 호출 스택이 쌓이며, 반환할 때 스택에서 제거된다.
  3. 동적 할당이 일어날 경우, 운영체제는 필요한 메모리를 에서 할당해준다.

7. 메모리에서 값을 가져오는 과정

  1. CPU는 명령어가 가리키는 가상 주소를 MMU(Memory Management Unit)에 전달하여 물리 주소로 변환을 요청한다.
  2. MMU는 가상 주소를 페이지 번호와 오프셋으로 나누어 처리한다.
  3. 해당 페이지가 메모리에 존재하면, 그 페이지에서 값을 가져온다.
  4. 만약 페이지가 메모리에 존재하지 않으면, 페이지 테이블에서 해당 페이지의 주소를 찾지 못해 페이지 폴트가 발생한다.
  5. MMU는 페이지 폴트를 처리하기 위해 트랩을 발생시키고, CPU는 페이지 폴트 처리 루틴으로 이동한다.
  6. 페이지 폴트 핸들러가 호출되며, 운영체제가 DMA(Direct Memory Access)를 통해 디스크에서 해당 페이지를 메모리로 가져온다.
  7. 운영체제의 메모리 관리 서브시스템에 의해 페이지가 메모리에 적재된다.
  8. 트랩이 종료되고, CPU는 다시 중단된 명령어로 돌아가 실행을 계속한다.

보완 설명 - 페이지 폴트 처리

페이지 폴트가 발생하면, 운영체제는 DMA를 사용해 디스크에서 해당 페이지를 효율적으로 메모리로 가져온다. 이때 커널의 메모리 관리 서브시스템이 페이지를 적재하고, CPU는 중단되었던 명령어로 돌아가 다시 실행을 이어간다.

더 자세한 과정