프로그램 실행 과정

1. C 파일이 실행 파일로 변환되는 과정

A. 전처리 : Preprocessor / cpp

전처리기 지시문을 처리합니다. 예를 들어, #include, #define 등이 처리됩니다.

## main.c (C 소스 파일) => main.i (전처리된 파일)
$ gcc -E main.c -o main.i

B. 컴파일 : Compiler / cc1/cc1plus

전처리된 파일을 분석하여 어셈블리 코드로 변환합니다.

## main.i (전처리된 파일) => main.s (어셈블리 코드 파일)
$ gcc -S main.i -o main.s

C. 어셈블리 : Assembler / as

어셈블리 코드를 더 잘개 쪼개서 기계어 인스트럭션 단위로 만들고, 이것들을 모아 목적 파일을 생성합니다.

## main.s (어셈블리 코드 파일) => main.o (목적 파일)
$ gcc -c main.s -o main.o

D. 링크 : Linker / ld

여러 목적 파일과 라이브러리를 결합하여 실행 파일을 생성합니다.

## main.o (목적 파일) => main (실행 파일)
$ gcc main.o -o main

2. 프로그램 실행

A. 실행파일 생성 (컴파일)

컴파일러는 소스 코드를 분석하여 각 종류의 데이터를 적절한 세그먼트로 분류

  • Text 세그먼트 : 실행 가능한 기계어 코드를 텍스트 세그먼트로 분류
  • Data 세그먼트 : 초기화된 전역 변수와 정적 변수
    이 값들은 컴파일 시 이미 알려져 있고, 링크 과정에서 해당 세그먼트에 배치
  • BSS 세그먼트: 초기화되지 않은 전역 변수와 정적 변수
    초기화되지 않은 데이터를 위한 공간을 제공
    링크 과정에서 해당 세그먼트에 배치되고 실제 메모리는 프로그램 로드 시 할당

B. 실행 파일 로드

운영 체제의 로더(Loader)가 실행 파일을 스토리지에서 메모리로 적재.
이때, 실행 파일의 헤더 정보를 읽어서 프로그램 실행에 필요한 메모리 구조를 파악

C. 메모리 영역(Segment) 생성 및 맵핑 ★ ★ ★ ★ ★

컴파일러와 링커에 의해 설정된 세그먼트 위치와 크기를 기반으로 실제 메모리 영역을 설정

실행파일에 정의된 대로 메모리에 로드

  • Text (Read Only) : 실행 파일의 기계어 코드
  • Data (R/W) : 초기화된 전역 변수 및 정적 변수
  • BSS (R/W) : 초기화되지 않은 전역 변수 및 정적 변수. 실행 시 0으로 초기화

런타임에 결정

  • Heap (R/W) : 동적 메모리 할당이 이루어지는 영역
    프로그램 실행 중에 malloc, calloc, realloc 등의 함수로 메모리를 할당
  • Stack (R/W) : 함수 호출 시 지역 변수 및 함수 호출 정보(리턴 주소, 매개변수, 지역 변수 등)를 저장, 호출 시 스택 프레임이 생성되고, 함수가 종료되면 스택 프레임이 해제

D. 실행

메모리에 적재된 후, CPU는 Text 세그먼트의 시작 주소에서 프로그램을 실행

  1. 프로그램 시작 : main 함수가 호출되면서 프로그램 실행이 시작
  2. 함수 호출 : 각 함수 호출 시 스택에 스택 프레임이 생성
    스택 프레임에는 함수의 매개변수, 지역 변수, 리턴 주소가 포함
  3. 메모리 할당 : 동적 메모리 할당이 필요한 경우 힙에서 메모리를 할당
  4. 프로그램 종료 : main 함수가 종료되거나 exit 함수가 호출되면, 프로그램 실행이 종료되고 운영 체제는 메모리를 회수

3. 예제

#include <stdio.h>;
#include <stdlib.h>;

int global_var = 10; // Data 영역

void function() {
    int local_var = 20; // Stack 영역
    printf("Local variable: %d\n", local_var);
}

int main() {
    static int static_var = 30; // Data 영역
    int *heap_var = (int *)malloc(sizeof(int)); // Heap 영역
    if (heap_var == NULL) {
        return 1;
    }
    *heap_var = 40;
    printf("Global variable: %d\n", global_var);
    printf("Static variable: %d\n", static_var);
    printf("Heap variable: %d\n", *heap_var);

    function();

    free(heap_var); // Heap 메모리 해제
    return 0;
}
  • global_var와 static_var는 Data 영역에 위치
  • local_var는 Stack 영역에 위치
  • heap_var는 Heap 영역에 위치
  • function과 main 함수의 기계어 코드는 Text 영역에 위치
이 글은 카테고리: Tip & Tech에 포함되어 있으며 태그: , , (이)가 사용되었습니다. 고유주소를 북마크하세요.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다