Lecture
세그먼트(Segment)
- 적재되는 데이터의 용도별로 메모리의 구획을 나눈 것 이다.
- 리눅스에서는 프로세스의 메모리를 크게 5가지의 세그먼트(코드 세그먼트, 데이터 세그먼트, BSS 세그먼트, 힙 세그먼트, 스택 세그먼트)로 나뉜다.
이렇게 나누는 이유?
각 용도에 맞게 적절한 권한을 부여할 수 있다는 장점이 있기 때문!
권한의 종류?
읽기, 쓰기, 실행 세 가지가 존재한다.
CPU는 메모리에 대해 권한이 부여된 행위만 할 수 있다.
예를 들어....
데이터 적재가 되는 곳에는 읽기 권한이 부여되고, 실행 대상이 아니기 때문에 실행 권한은 부여되지 않는다!
코드 세그먼트(Code Segment)
- 실행 가능한 기계 코드가 위치하는 영역이다.
- 다른 말로 텍스트 세그먼트(Text Segment)라고도 불린다.
- 프로그램이 동작하기 위해서는 코드를 실행해야 하므로 읽기 권한과 실행 권한이 부여된다.
- 악의적 코드 삽입 방지 등 공격자의 접근을 어렵게 하기 위해서 쓰기 권한은 제거된다.
def func(): return 31337
위의 정수 31337을 반환하는 함수가 컴파일 되면 기계 코드로 변환되는데, 이 기계 코드가 코드 세그먼트에 위치하게 된다.
데이터 세그먼트(Data Segment)
- 컴파일 시점에 값이 정해진 전역변수 및 전역 상수들이 위치한다.
- 이 세그먼트의 데이터를 읽어야 하므로 읽기 권한이 부여된다.
- 데이터 세그먼트는 쓰기가 가능한 세그먼트와 쓰기가 불가능한 세그먼트로 분류된다.
쓰기가 가능한 데이터 세그먼트
- 전역 변수와 같이 프로그램이 실행되면서 값이 변할 수 있는 데이터들이 위치한다.
- data 세그먼트라 부른다
쓰기가 불가능한 데이터 세그먼트
- 프로그램이 실행되면서 값이 변하면 안되는 데이터들이 위치한다.
- rodata(read-only-data) 세그먼트라 부른다.
예시)
int data_num = 31337; // data
char data_rwstr[] = "writeable_data"; // data
const char data_rostr[] = "readonly_data"; // rodata
char *str_ptr = "readonly"; // str_ptr: data, "readonly": rodata
int main() { . . . }
BSS 세그먼트(BSS Segment, Block Started By Symbol Segment)
- 컴파일 시점에 값이 정해지지 않은 전역 변수가 위치한다.
- 프로그램이 시작될 때, 모두 0으로 값이 초기화된다.
- 읽기 권한 및 쓰기 권한이 부여된다.
int bss_data;
int main(){
printf("%d\n", bss_data); // 0
return 0;
}
스택 세그먼트(Stack Segment)
- 프로세스의 스택이 위치한다.
- 스택 세그먼트는 스택 프레임(Stack Frame)이라는 단위로 사용된다.
- 읽기 권한과 쓰기 권한이 부여된다.
스택 프레임(Stack Frame)?
- 함수가 호출될 때 생성되고, 함수가 반환될 때 해제된다.
void func(){
int choice = 0;
scanf("%d", &choice);
if(choice){
call_true();
}else{
call_false();
}
return 0;
}
위의 코드를 보면...
- 사용자의 입력에 따라 call_true(), call_false()가 호출된다.
- 따라서, 일반적으로 실행한 프로세스가 얼마 만큼의 스택 프레임을 사용할지 계산하는것은 불가능하다.
- 그래서 운영체제는 프로세스를 시작할 때 작은 크기의 스택 세그먼트를 먼저 할당한 후, 부족할 경우 이를 확장한다.
- 종종, '아래로 자란다'라는 말을 사용하기도 하는데, 이는 스택이 확장될 때 마다 기존 주소보다 '낮은 주소'로 확장되기 때문이다.
위의 코드에서는 choice가 스택에 저장된다.
힙 세그먼트(Heap Segment)
- 힙 데이터가 위치한다.
- 스택과 마찬가지로 실행중에 동적으로 할당될 수 있으며, 리눅스에서는 스택 세그먼트와 반대 방향으로 자란다.
- c에서 malloc(), calloc()등을 호출해서 할당받는 메모리가 이 세그먼트에 위치한다.
- 일반적으로 읽기 권한과 쓰기 권한이 부여된다.
힙 세그먼트와 스택 세그먼트가 반대로 자라는 이유?
- 두 세그먼트가 동일한 방향으로 자라고, 연속된 메모리 주소에 각각 할당된다고 가정했을 때, 기존의 힙 세그먼트를 사용한 후 이를 확장하는 과정에서 스택 세그먼트와 충돌한다.
- 따라서 이를 해결하기 위해 스택을 메모리 끝에 위치시키고, 힙과 스택을 반대방향으로 자라게 한다.
int main(){
int *heap_data_ptr = malloc(sizeof(*heap_data_ptr)); // 동적 할당한 힙 영역의 주소를 가르킴
*heap_data_ptr = 31337; // 힙 영역에 값을 씀
printf("%d\n", *heap_data_ptr); // 힙 영역의 값을 사용함
return 0;
}
위의 코드를 보면...
- heap_data_ptr에 malloc()으로 동적할당한 영역의 주소를 대입한다.
- 이 영역에 값을 쓴다.
- heap_data_ptr은 지역변수이므로 스택에 위치하며, malloc으로 할당받은 힙 세그먼트의 주소를 가리킨다.
Note
세그먼트 | 역할 | 일반적인 권한 | 사용 예 |
코드 세그먼트 | 실행 가능한 코드가 저장된 영역 | 읽기, 실행 | main()등의 함수 코드 |
데이터 세그먼트 | 초기화된 전역 변수 또는 상수가 위치하는 영역 | 읽기와 쓰기 또는 읽기 전용 | 초기화된 전역 변수, 전역 상수 |
BSS 세그먼트 | 초기화되지 않은 데이터가 위치하는 영역 | 읽기, 쓰기 | 초기화되지 않은 전역 변수 |
스택 세그먼트 | 임시 변수가 저장되는 영역 | 읽기, 쓰기 | 지역 변수, 함수의 인자 등 |
힙 세그먼트 | 실행중에 동적으로 사용되는 영역 | 읽기, 쓰기 | malloc(), calloc() 등으로 할당 받은 메모리 |
'문제 풀이 > [DreamHack]' 카테고리의 다른 글
[DreamHack] SystemHacking Stage2 - x86 Assembly: Essential Part 1 (0) | 2022.12.20 |
---|---|
[DreamHack] SystemHacking Stage2 - Quiz: Computer Architecture (0) | 2022.12.19 |
[DreamHack] SystemHacking Stage2 - Background: Computer Architecture (0) | 2022.12.19 |
[DreamHack] System Hacking Stage2 - Quiz: Linux Memory Layout (0) | 2022.12.19 |
[DreamHack] System Hacking - STAGE 1 리눅스 환경 구축 (0) | 2022.12.19 |