Linux 메모리 레이아웃
리눅스 프로세스 메모리를 코드·데이터·BSS·힙·스택 5개 세그먼트로 나눠 정리했습니다.
리눅스 프로세스의 메모리 구조
메모리 레이아웃(Memory Layout)
리눅스에서는 프로세스의 메모리를 크게 5가지 세그먼트(Segment)로 구분
→ 세그먼트(Segment): 프로세스 메모리를 용도별로 나누어 관리하는 영역
- 코드 세그먼드(Code Segment)
- CPU가 실제로 실행하는 명령어들이 저장되는 공간
- 실행할 수 있어야 하므로 읽기 권한과 실행 권한이 주어짐
- 쓰기 권한은 안주어짐 → 해커가 취약점을 이용하여 프로그램의 코드를 수정할 수 있어
- 어셈블리어에서는 section .text: 를 입력한 뒤 아랫줄에 어셈블리어 코드를 입력하여 컴파일 시 코드 세그먼트에 기계 코드가 자리잡히게 됨
section .data message db "Hello, World!", 0xA message_len equ $ - message section .text global _start _start: mov rax, 1 mov rdi, 1 mov rsi, message mov rdx, message_len syscall mov rax, 60 xor rdi, rdi syscall - 데이터 세그먼트
- 컴파일 시점에 값이 정해진 전역 변수 및 전역 상수들이 위치
- CPU가 이 세그먼트의 데이터를 읽을 수 있어야 하므로, 읽기 권한 부여
- 쓰기가 가능한 세그먼트와 쓰기가 불가능한 세그먼트로 분류
- 쓰기가 가능한 세그먼트: 전역 변수와 같이 프로그램이 실행되면서 값이 변할 수 있는 데이터들이 위치 → Data 세그먼트
- 쓰기가 불가능한 세그먼트(rodata(read-only data) 세그먼트): 프로그램이 실행되면서 값이 변하면 안되는 데이터들 위치, 전역으로 선언된 상수가 여기에 포함
- 문자열 자체가 수정 가능한지 여부에 따라 data 또는 rodata 영역에 저장
-
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)
- 컴파일 시점에 값이 정해지지 않은 전역 변수가 위치하는 메모리 영역
- 개발자가 선언만 하고 초기화하지 않은 전역변수 등이 포함
- 운영체제가 프로그램이 시작될 때, BSS 영역을 모두 0으로 초기화
- 읽기 권한 및 쓰기 권한 부여
- 아래 코드에서 초기화되지 않은 전역 변수인 bss_data가 BSS 세그먼트에 위치
int bss_data; int main() { printf("%d\n", bss_data); // 0 return 0; } - 스택 세그먼트(Stack Segment)
- 프로세스의 스택에 위치하는 영역
- 함수의 매개변수나 지역 변수같은 임시 변수들이 실행 중에 이곳에 저장
- 읽기 권한 및 쓰기 권한 부여
- 스택 프레임(Stack Frame): 스택을 구성하는 단위
- 매개변수, 반환 주소, 지역 변수를 저장
- 각 함수가 실행을 마쳤을 때 해당 함수가 어느 함수로부터 호출 되었는지에 대한 경로와 함수의 정보를 저장하기 위해 존재함
- 함수들의 영역을 구분해주는 역할
- CPU가 자유롭게 값을 읽고 쓸 수 있어야 하므로, 읽기와 쓰기 권한 부여
- 힙 세그먼트(Heap Segment)
- 힙 데이터가 위치하는 세그먼트
- 실행 중 크기가 동적으로 변하는 데이터를 저장할 때 사용
- C언어에서 malloc(), calloc() 등을 오출해서 할당받는 메모리가 이 세그먼트에 위치
- 읽기와 쓰기 권한 부여
<aside> 💡
각 세그먼트는 역할과 접근 권한이 다르며, 이를 통해 운영체제는 메모리를 효율적이고 안전하게 관리함
</aside>
전역 변수와 지역 변수
| 구분 | 전역 변수(Global Variable) | 지역 변수(Local Variable) |
|---|---|---|
| 선언 위치 | 함수 외부 | 함수 내부 |
| 사용 범위 | 프로그램 전체 | 선언된 함수 내부 |
| 생성 시점 | 프로그램 시작 시 | 함수 호출 시 |
| 소멸 시점 | 프로그램 종료 시 | 함수 종료 시 |
| 저장 영역 | Data/BSS Segment | Stack Segment |
| 특징 | 여러 함수에서 접근 가능 | 해당 함수에서만 사용 가능 |
| 예시 | int global_num = 10; | int local_num = 5; |
int global_num = 10; // 전역 변수
void func() {
int local_num = 5; // 지역 변수
}
Comments