본문 바로가기

Dreamhack-system

Linux Memory Layout

리눅스에서는 프로세스의 메모리를 크게 5가지의 Segment(세그먼트)로 구분

코드 세그먼트, 테이터 세그먼트, BSS 세그먼트, 힙 세그먼트, 스택 세그먼트

 

코드 세그먼트(Code Segment)는 실행 가능한 기계 코드가 위치하는 영역

텍스트 세그먼트(Text Segment)라고도 불림

이 세그먼트에는 읽기 권한과 실행 권한이 부여됨

정수 31337을 반환하는 main함수가 컴파일 되면 기계코드로 변환되는데

이 기계코드가 코드 세그먼트에 위치하게 됩니다.

ㅇint main() {return 31337;}

 

데이터 세그먼트(Data Segment)에는 컴파일 시점에 값이 정해진 전역 변수 및 전역 상수가 위치

cpu가 데이터를 읽을 수 있어야 하므로 읽기 권한이 부여됨

데이터 세그먼트는 쓰기가 가능한 세그먼트와 쓰기가 불가능한 세그먼트로 분류됨

쓰기 가능한 세그먼트는 data 세그먼트 , 쓰기가 불가능한 세그먼트는 rodata(read-only data) 세그먼트 라고 부름

str_ptr은 "readonly"라는 문자열을 가리키고 있는데 이 문자열은 상수 문자열 취급되어 rodata에 위치하고 이를 가리키는

str_ptr은 전역 변수로서 data에 위치한다.

int data_num = 31337; //data

char data_rwstr[] = "writable_data"; //data

const char data_rostr[] = "readonly_data"; //rodata

char *str_ptr = "readonly"; //str_ptr은 data, 문자열은 rodata

int main() { ... }

 

BSS 세그먼트(BSS Segment, Block Started By Symbol Segment)는 컴파일 시점에 값이 정해지지 않은 전역 변수가 위치하는 메모리 영역이다.

이 세그먼트의 메모리 영역은 프로그램이 시작될 때, 모두 0으로 값이 초기화됨

이러한 특성 때문에 C코드를 작성할 때, 초기화되지 않은 전역 변수의 값은 0이 됨

이 세그먼트에는 읽기 권한 및 쓰기 권한이 부여된다.

아래 코드에서 초기화되지 않은 전역 변수인 bss_data가 BSS 세그먼트에 위치하게 됨

int bss_data;

int main() {
	printf("%d\n", bss_data); //0
    return 0;
   }

 

 

스택 세그먼트(Stack Segment)는 프로세스의 스택이 위치하는 영역

함수의 인자나 지역 변수와 같은 임시 변수들이 실행중에 여기에 저장됨

스택 세그먼트는 스택 프레임(Stack Frame)이라는 단위로 사용됨

스택 프레임은 함수가 호출될 때 생성되고, 반환될 때 해제된다. 

이 영역에는 CPU가 자유롭게 값을 읽고 쓸 수 있어야 하므로, 읽기와 쓰기 권한이 부여됨

 

아래 코드에서 유저가 입력한 choice에 따라 call_true()가 호출될 수도, call_false()가 호출될 수도 있다.

따라서, 어떤 프로세스가 실행될 때, 이 프로세스가 얼마 만큼의 스택 프레임을 상요하게 될 지를 미리 계산하는 것은 일반적으로 불가능합니다. 그래서 운영체제는 프로세스를 시작할 때 작은 크기의 스택 세그먼트를 먼저 할당해주고, 부족해 질 때마다 이를 확장해준다. 스택에 대해서 '아래로 자란다'라는 표현을 종종 사용하는데, 이는 스택이 확장될 때, 기존 주소보다 낮은 주소로 확장되기 때문이다. 

아래의 코드에서는 지역변수 choice가 스택에 저장되게 된다.

void func() {
	int choice = 0;
    
    scanf("%d", &choice);
    
    if(choice)
    	call_ture();
    else
    	call_false();
        
    return 0;
}

 

 

힙 세그먼트(Heap Segment)는 힙 데이터가 위치하는 세그먼트이다.

스택과 마찬가지로 실행중에 동적으로 할당될 수 있으며, 리눅스에서는 스택 세그먼트와 반대 방향으로 자란다.

C언어에서 malloc(), calloc() 등을 호출해서 할당받는 메모리가 이 세그먼트에 위치하게 되며, 일반적으로 읽기와 쓰기 권한이 부여된다.

 

아래 예제 코드는 heap_data_ptr에 malloc()으로 동적 할당한 영역의 주소를 대입하고, 이 영역에 값을 쓴다.

heap_data_ptr은 지역변수이므로 스택에 위치하며, malloc으로 할당받는 힙 세그먼트의 주소를 가리킨다. 

int main() {
	int *heap_data_ptr = malloc(sizeof(*heap_data_ptr)); //동적 할당한 힙 영역의 주소를 가리킴
    
    *heap_data_ptr = 31337; // 힙 영역에 값을 씀
    
    printf("%d\n", *heap_data_ptr); // 힙 영역의 값을 사용함
    
    return 0;
}

 

 

최종 정리

세그먼트 역할 일반적인 권한 사용 예
코드 세그먼트 실행 가능한 코드가 저장된 영역 읽기, 실행 main()등의 함수 코드
데이터 세그먼트 초기화된 전역 변수 또는 상수가 위치하는 영역 읽기와 쓰기 또는 읽기 전용 초기화된 전역 변수, 전역 상수
BSS 세그먼트 초기화되지 않은 데이터가 위치하는 영역 읽기, 쓰기  지역 변수, 함수의 인자 등
스택 세그먼트 임시 변수가 저장되는 영역 읽기, 쓰기 지역 변수, 함수의 인자 등
힙 세그먼트 실행중에 동적으로 사용되는 영역 읽기, 쓰기 malloc(), calloc() 등으로 할당 받은 메모리

'Dreamhack-system' 카테고리의 다른 글

x86 Assembly : Essential Part(1)  (0) 2023.01.17
Quiz: Computer Architecture  (0) 2023.01.17
Background: Computer Architecture  (0) 2023.01.17