메모리란?
작업을 처리하기 위한 기억장치로 물리메모리(RAM), 가상 메모리(SDD, HDD의 swap)이 존재한다.
- CPU는 작업을 수행할 때 메인 메모리까지 참조 가능하다.
- 각 프로세스는 자신만의 메모리를 할당 받고, 메모리를 사용하여 동작을 수행한다.
가상 메모리: 필요한 내용만 물리 메모리에 올려 메모리를 관리하는 기법, 요구 페이징 기법을 사용한다.
+) 가상 메모리에는 방어적 코드를 포함한 불필요한 코드가 올라간다.
요구 페이징 기법: valid, invalid(유, 무효 비트)로 페이지가 메모리에 존재하는지 확인, 없으면 보조 저장 장치에서 가져온다.
메모리 구조
코드 영역(Text)
: 절대 변경되면 안되는 데이터가 저장된다.
: 명령문을 포함한 코드에 직접적으로 적혀있는 문자열,
상수가 이 영역에 저장된다. (+ 컴파일된 기계어)
데이터 영역(Data)
: 적역 변수, 정적 변수 등이 저장된다.
: 종료될 때까지 메모리에 남아있는다.
: BSS 영역을 두고 초기화 되지 않은 변수는 BSS,
초기화 된 변수는 Data로 분류한다.
힙 영역(Heap)
: 프로그래머에 의해 동적으로 할당된 변수가 저장된다.
: C언어에서는 malloc(), Java에선 new() 변수가 해당된다.
: 사용자가 직접 관리해야하는 영역이다.
: 런타임 시 크기가 결정된다.
:free()를 만나면 해제된다.
스택 영역(Stack)
: 함수를 호출할 때 지역변수, 매개변수, 리턴값 등이 저장된다.
: 함수가 종료되면 메모리에서 해제된다.
: 높은 주소에서 낮은 주소로 할당되며, 컴파일 시에 크기가
결정된다. (윈도우는 약 1mb, 리눅스는 약 8mb)
* 스택 영역의 장/단점
- 낭비되는 공간이 없다.
- 하나의 명령만으로 메모리 조작과 Address 조작이 가능하다.
- 한계가 있어 한계를 초과하도록 삽입할 수 없다. (즉, 유연성이 부족하다.)
* 힙 영역의 장/단점
- 프로그램에 필요한 개체의 개수나 크기를 미리 알 수 없는 경우에 사용 가능하다.
- 개체가 너무 커서 스택 할당자에 맞지 않는 경우 사용 가능하다.
- 할당 작업과 해제 작업, 힙 손상/경합 등으로 인한 속도 저하.
: 주로 병합을 사용할 때 해제 작업에 더 많은 주기가 소요된다.
: 응용 프로그램에서 힙 블록을 적절하게 사용하지 않을 경우 힙이 손상된다. (이중 해제, 해제 후 블록 사용, 블록 경계를 벗어나 덮어쓰기 등)
: 두 개 이상의 쓰레드에서 동시에 데이터에 액세스 하려고 하면 경합이 발생.
한쪽 스레드의 작업이 완료되어야 다른 쪽 쓰레드의 작업이 진행될 수 있다.(다중 프로세서 시스템에서 일어나는 문제 중 하나.)
경합은 일반적으로 쓰레드와 프로세스의 컨텍스트 스위칭을 가져온다. 이 경우 프로세서 캐시에서 데이터가 손상되어 쓰레드가 다시 살아날 때 데이터를 다시 작성해야해 리소스가 훨씬 많이 소모된다.
컨텍스트 스위칭: 여러개의 프로세스가 실행되고 있을 때 기존에 실행되던 프로세스를 중단하고 다른 프로세스를 실행시키는 것.
<Stack>
마지막에 저장한 데이터를 가장 먼저 꺼내는 후입 선출(LIFO, Last In First Out) 구조이다.
위에서도 서술한 것처럼 스택 메모리의 역할은 함수 내의 지역 변수를 임시저장한다. 함수 호출 시 매개변수를 전달하고, 복귀주소를 지정한다.
스택 프레임(=스택 영역)
: 함수 호출 시 할당되는 메모리 블록(지역 변수 선언으로 할당)이며, 함수 종료 시 호출 전에 저장해둔 주소로 복귀한다.
스택 메모리와 스택 프레임은 조금씩 다르지만 서로 밀접한 관계이다.
<Stack vs Heap>
이 두 영역은 반비례 관계이다. Stack 영역이 클 수록 Heap 영역이 작아지고, Heap 영역이 클 수록 Stack 영역이 작아진다.
Stack은 이미 할당 되어 있는 공간을 사용하고 Heap은 사용자가 직접 할당해 사용하는 공간이라 속도만 본다면 Stack이 훨씬 빠르고 좋다. (다만, 스택은 공간이 매우 작아 모든 응용 프로그램에서 스택을 사용할 수는 없다.)
자세히 알아보면, 스택에서 할당의 의미는 이미 생성되어 있는 공간에 대해 포인터의 위치만 바꿔주는 단순한 CPU Instruction이다.
반면, 힙에서의 할당은 요청된 chuck의 크기, 현재 메모리의 fragmentation 상황 등 다양한 요소를 고려하기 때문에 더 많은 CPU Instruction이다.
Stack: 단일 Instruction, Heap: 다중 Instruction
<오버플로우(Overflow)>
Stack 영역에 저장되는 지역번수는 사용된 뒤에 소멸하기 때문에 데이터 용량의 불확실성을 가진다. 따라서 Stack 영역에서의 주소값은 밑에서부터 채워지며 다음의 주소는 선언된 순서대로 할당된다.
반면에, Heap 영역에서의 주소값은 위에서부터 채워지기 때문에 두 메모리 영역의 주소가 겹쳐 오버플로우가 발생할 수도 있다.
Heap Overflow: Heap이 위에서부터 주소값을 채워 내려가다 Stack 영역을 침범하는 경우
Stack Overflow: Stack 영역이 Heap 영역을 침범하는 영우
// 임베디드 환경과 일반 PC(x86, x64 등등)에서의 환경하고는 차이가 있다. 위의 정보들은 모두 일반 PC에서의 환경을 기준으로 서술한 것으로 임베디드 환경의 메모리 구조는 다음과 같다.
메모리 구조(임베디드 시스템)
1. 전체 메모리 구조
임베디드 환경에서 주로 쓰이는 ARM Cortex-M의 총 주소 공간은 6개의 큰 구역으로 나뉜다.
1. Code region
: .text와 .rodate section처럼 읽기 전용으로 flash에 저장됐던 내용들은 이 구역으로 매핑된다. (IVT에 대한 내용도 매핑)
: 0이 아닌 초기값으로 정의된 심볼도 이 영역에 위치하는데, 런타임 시에 수정된 수 있기 때문에 이 쓰기 가능한 구역으로 복제 또는 재매핑되어야 한다.
2. SRAM region & RAM region
3. Built-in & External Peripheral region
4. System region
: 프로세서를 위한 시스템 제어 레지스터와 주변 장치 제어 레지스터 등이 포함된다.
: 프로세서가 previleged level에서 동작할 때만 접근이 가능한 특수 영역이다.
코드 영역(Text)
: .hex, .bin 같은 프로그램 코드가 존재
: 함수, 제어문, 상수
데이터 영역(Data)
: 전역 변수가 존재한다.
힙 영역(Heap)
: malloc(), calloc()등으로 생성된 동적 변수가 존재.
: free() 함수로 할당된 영역을 반납해줘야 한다.
스택 영역(Stack)
: 함수 호출 시 할당되며 종료 시 반납되는 지역 변수가 존재
일반 환경과 임베디드 시스템의 차이점
: heap, stack 또한 전역 변수의 Array로 선언되어 있다.
Array로 선언하면 연속적인 메모리 영역으로 잡을 수 있을 뿐만 아니라, 이름을 알기에 디버깅 시 쉽게 접근할 수 있다는 장점이 있다.
참고 자료
'System & Reversing > 필기' 카테고리의 다른 글
dll 파일이란? (+ lib과의 차이점) (0) | 2023.03.10 |
---|---|
어셈블리 핸드레이와 함수 프롤로그/에필로그(+ 스택 프레임) (0) | 2023.03.10 |
어셈블리어의 개요, 기초 문법(+ x86, arm) (0) | 2023.03.10 |
아키텍처의 개념, 종류, 특징(통합본) (0) | 2023.03.10 |
프로그램 언어의 종류(기계어, 저급언어, 고급언어) (0) | 2023.03.09 |