세그멘테이션 ⭐⭐⭐

세그멘테이션 ⭐⭐⭐

개요

세그멘테이션(Segmentation)은 프로그램을 논리적 단위인 세그먼트로 나누어 관리하는 메모리 기법입니다. 코드, 데이터, 스택 등 의미 있는 단위로 분리하여 보호와 공유가 용이합니다.


목차

  1. 세그먼트의 개념
  2. 세그먼트 테이블
  3. 주소 변환
  4. 보호와 공유
  5. 페이징과 세그멘테이션 비교
  6. 세그멘테이션 + 페이징 결합
  7. Intel x86 세그멘테이션
  8. 연습 문제

1. 세그먼트의 개념

1.1 프로그래머 관점의 메모리

┌─────────────────────────────────────────────────────────────────────────┐
│                    프로그래머가 보는 메모리                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   프로그래머는 메모리를 연속된 바이트 배열이 아닌,                       │
│   논리적 단위의 집합으로 인식합니다.                                     │
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────┐       │
│   │                        프로그램                              │       │
│   ├─────────────────────────────────────────────────────────────┤       │
│   │                                                              │       │
│   │   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │       │
│   │   │    main()    │  │  함수 A()   │  │  함수 B()    │      │       │
│   │   │     코드     │  │     코드     │  │     코드     │      │       │
│   │   └──────────────┘  └──────────────┘  └──────────────┘      │       │
│   │                                                              │       │
│   │   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │       │
│   │   │  전역 변수   │  │    상수      │  │    스택      │      │       │
│   │   │   (데이터)   │  │   (읽기전용)  │  │  (지역변수)  │      │       │
│   │   └──────────────┘  └──────────────┘  └──────────────┘      │       │
│   │                                                              │       │
│   │   ┌──────────────┐  ┌──────────────┐                        │       │
│   │   │   심볼 테이블 │  │    힙       │                        │       │
│   │   │  (디버그용)   │  │  (동적할당)  │                        │       │
│   │   └──────────────┘  └──────────────┘                        │       │
│   │                                                              │       │
│   └─────────────────────────────────────────────────────────────┘       │
│                                                                          │
│   각각의 논리 단위 = 세그먼트                                           │
│   세그먼트마다 다른 크기, 다른 보호 속성                                │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

1.2 세그먼트의 특징

┌─────────────────────────────────────────────────────────────────────────┐
│                       세그먼트 특징                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   1. 가변 크기                                                          │
│      - 페이지와 달리 고정 크기가 아님                                   │
│      - 논리적 단위에 따라 크기가 다름                                   │
│                                                                          │
│   2. 논리적 분리                                                        │
│      ┌──────────────┐                                                   │
│      │ 코드 세그먼트 │ → 실행 가능, 읽기 전용                           │
│      ├──────────────┤                                                   │
│      │ 데이터 세그먼트│ → 읽기/쓰기 가능                                │
│      ├──────────────┤                                                   │
│      │ 스택 세그먼트 │ → 자동 확장, 아래로 성장                         │
│      ├──────────────┤                                                   │
│      │ 힙 세그먼트  │ → 동적 할당, 위로 성장                            │
│      └──────────────┘                                                   │
│                                                                          │
│   3. 보호 용이                                                          │
│      - 각 세그먼트에 다른 접근 권한 부여                                │
│      - 코드 수정 방지, 스택 실행 방지 등                                │
│                                                                          │
│   4. 공유 용이                                                          │
│      - 코드 세그먼트를 여러 프로세스가 공유                             │
│      - 공유 라이브러리 구현에 적합                                      │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2. 세그먼트 테이블

2.1 세그먼트 테이블 구조

┌─────────────────────────────────────────────────────────────────────────┐
│                      세그먼트 테이블                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   세그먼트 테이블 기준 레지스터 (STBR): 0x5000                          │
│   세그먼트 테이블 길이 레지스터 (STLR): 5                               │
│                                                                          │
│   ┌────────────┬────────────────┬────────────┬───────────────────────┐  │
│   │ 세그먼트   │ 기준 주소      │   한계     │       보호            │  │
│   │  번호      │ (Base)         │  (Limit)   │                       │  │
│   ├────────────┼────────────────┼────────────┼───────────────────────┤  │
│   │     0      │   0x00000      │   1400     │   R-X (코드)         │  │
│   │     1      │   0x06300      │   400      │   R-- (상수)         │  │
│   │     2      │   0x04300      │   1100     │   RW- (데이터)       │  │
│   │     3      │   0x03200      │   1000     │   RW- (스택)         │  │
│   │     4      │   0x04700      │   2000     │   RW- (힙)           │  │
│   └────────────┴────────────────┴────────────┴───────────────────────┘  │
│                                                                          │
│   Base: 세그먼트의 물리 메모리 시작 주소                                │
│   Limit: 세그먼트의 최대 크기 (바이트)                                  │
│   보호: R(읽기), W(쓰기), X(실행)                                       │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

2.2 물리 메모리 배치

┌─────────────────────────────────────────────────────────────────────────┐
│                    물리 메모리에서의 세그먼트                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   물리 메모리                                                            │
│   ┌──────────────────────────────────────────────────────────────────┐  │
│   │ 0x00000 ┌────────────────────────────────────┐                   │  │
│   │         │        세그먼트 0 (코드)           │                   │  │
│   │         │           1400 바이트              │                   │  │
│   │ 0x00578 └────────────────────────────────────┘                   │  │
│   │         ┌────────────────────────────────────┐                   │  │
│   │         │            빈 공간                 │                   │  │
│   │ 0x03200 └────────────────────────────────────┘                   │  │
│   │         ┌────────────────────────────────────┐                   │  │
│   │         │       세그먼트 3 (스택)            │                   │  │
│   │         │           1000 바이트              │                   │  │
│   │ 0x035E8 └────────────────────────────────────┘                   │  │
│   │         ┌────────────────────────────────────┐                   │  │
│   │ 0x04300 │       세그먼트 2 (데이터)          │                   │  │
│   │         │           1100 바이트              │                   │  │
│   │ 0x0474C └────────────────────────────────────┘                   │  │
│   │         ┌────────────────────────────────────┐                   │  │
│   │ 0x04700 │        세그먼트 4 (힙)             │                   │  │
│   │         │           2000 바이트              │                   │  │
│   │ 0x04ED0 └────────────────────────────────────┘                   │  │
│   │         ┌────────────────────────────────────┐                   │  │
│   │ 0x06300 │       세그먼트 1 (상수)            │                   │  │
│   │         │           400 바이트               │                   │  │
│   │ 0x06490 └────────────────────────────────────┘                   │  │
│   │         ...                                                      │  │
│   └──────────────────────────────────────────────────────────────────┘  │
│                                                                          │
│   주의: 세그먼트가 물리 메모리에서 연속이지만, 순서대로 배치되지 않음   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3. 주소 변환

3.1 논리 주소 구조

┌─────────────────────────────────────────────────────────────────────────┐
│                       세그먼트 논리 주소                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   논리 주소 = <세그먼트 번호, 오프셋>                                   │
│                                                                          │
│   예: <2, 400> = 세그먼트 2의 400번째 바이트                            │
│                                                                          │
│   ┌─────────────────┬────────────────────────────────┐                  │
│   │ 세그먼트 번호(s)│         오프셋(d)              │                  │
│   │     4비트       │          12비트                │                  │
│   └─────────────────┴────────────────────────────────┘                  │
│                                                                          │
│   이 예에서:                                                             │
│   - 최대 16개 세그먼트 (2^4)                                            │
│   - 세그먼트당 최대 4KB (2^12)                                          │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3.2 주소 변환 과정

┌─────────────────────────────────────────────────────────────────────────┐
│                      세그먼트 주소 변환                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   논리 주소: <2, 400>                                                   │
│                                                                          │
│   ┌─────────────────────────────────────────────────────────────────┐   │
│   │                                                                  │   │
│   │   1. 세그먼트 번호 추출: s = 2                                  │   │
│   │                                                                  │   │
│   │   2. 범위 검사: s < STLR?                                       │   │
│   │      2 < 5 → OK                                                 │   │
│   │                                                                  │   │
│   │   3. 세그먼트 테이블 조회                                       │   │
│   │      segment[2] = {base: 0x04300, limit: 1100}                  │   │
│   │                                                                  │   │
│   │   4. 한계 검사: d < limit?                                      │   │
│   │      400 < 1100 → OK                                            │   │
│   │      (만약 d >= limit이면 TRAP 발생!)                           │   │
│   │                                                                  │   │
│   │   5. 물리 주소 계산                                             │   │
│   │      물리 주소 = base + d                                       │   │
│   │                = 0x04300 + 400                                  │   │
│   │                = 0x04300 + 0x190                                │   │
│   │                = 0x04490                                        │   │
│   │                                                                  │   │
│   └─────────────────────────────────────────────────────────────────┘   │
│                                                                          │
│   결과: <2, 400> → 0x04490                                              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3.3 하드웨어 구현

┌─────────────────────────────────────────────────────────────────────────┐
│                    세그멘테이션 하드웨어                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│                         논리 주소                                        │
│                    ┌───────┬────────┐                                   │
│                    │   s   │   d    │                                   │
│                    └───┬───┴────┬───┘                                   │
│                        │        │                                        │
│                        ▼        │                                        │
│   ┌─────────────────────────┐   │                                       │
│   │   세그먼트 테이블       │   │                                       │
│   │   (STBR 기준)          │   │                                       │
│   │                         │   │                                       │
│   │   ┌───────┬─────────┐   │   │                                       │
│   │   │ limit │  base   │◀──┘   │                                       │
│   │   └───┬───┴────┬────┘       │                                       │
│   └───────┼────────┼────────────┘                                       │
│           │        │            │                                        │
│           ▼        ▼            │                                        │
│   ┌────────────┐ ┌────────┐     │                                       │
│   │ 비교기     │ │  가산기│◀────┘                                       │
│   │  d < limit │ │ base+d │                                             │
│   └─────┬──────┘ └───┬────┘                                             │
│         │            │                                                   │
│     ┌───┴───┐        │                                                  │
│     │  yes  │  no    │                                                  │
│     │   │   │   │    │                                                  │
│     ▼   │   ▼   │    ▼                                                  │
│    OK   │ TRAP  │  물리 주소                                            │
│         │       │                                                        │
│         └───────┘                                                        │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

3.4 C언어 구현

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

#define MAX_SEGMENTS 16

typedef struct {
    uint32_t base;      // 기준 주소
    uint32_t limit;     // 한계 (크기)
    bool valid;         // 유효 비트
    uint8_t protection; // 보호 비트 (R=1, W=2, X=4)
} SegmentTableEntry;

SegmentTableEntry segment_table[MAX_SEGMENTS];
int stlr = 0;  // Segment Table Length Register

#define PROT_READ  1
#define PROT_WRITE 2
#define PROT_EXEC  4

// 논리 주소 → 물리 주소 변환
int translate_segment_address(uint16_t segment, uint32_t offset,
                               uint8_t access_type, uint32_t* physical) {
    // 1. 세그먼트 번호 범위 검사
    if (segment >= stlr) {
        printf("ERROR: Invalid segment number %d (STLR=%d)\n", segment, stlr);
        return -1;  // Segmentation Fault
    }

    // 2. 유효성 검사
    SegmentTableEntry* entry = &segment_table[segment];
    if (!entry->valid) {
        printf("ERROR: Segment %d is not valid\n", segment);
        return -1;  // Segmentation Fault
    }

    // 3. 한계 검사
    if (offset >= entry->limit) {
        printf("ERROR: Offset %u >= Limit %u in segment %d\n",
               offset, entry->limit, segment);
        return -1;  // Segmentation Fault
    }

    // 4. 보호 검사
    if ((entry->protection & access_type) != access_type) {
        printf("ERROR: Protection violation in segment %d\n", segment);
        printf("  Required: 0x%x, Allowed: 0x%x\n",
               access_type, entry->protection);
        return -1;  // Protection Fault
    }

    // 5. 물리 주소 계산
    *physical = entry->base + offset;
    return 0;
}

int main() {
    // 세그먼트 테이블 초기화
    segment_table[0] = (SegmentTableEntry){
        .base = 0x00000, .limit = 1400, .valid = true,
        .protection = PROT_READ | PROT_EXEC  // 코드 세그먼트
    };
    segment_table[1] = (SegmentTableEntry){
        .base = 0x06300, .limit = 400, .valid = true,
        .protection = PROT_READ  // 상수 세그먼트
    };
    segment_table[2] = (SegmentTableEntry){
        .base = 0x04300, .limit = 1100, .valid = true,
        .protection = PROT_READ | PROT_WRITE  // 데이터 세그먼트
    };
    stlr = 3;

    uint32_t physical;

    // 테스트 1: 정상 접근
    if (translate_segment_address(2, 400, PROT_READ, &physical) == 0) {
        printf("Segment 2, Offset 400 -> Physical 0x%X\n", physical);
    }

    // 테스트 2: 한계 초과
    translate_segment_address(2, 1200, PROT_READ, &physical);

    // 테스트 3: 보호 위반 (코드 세그먼트에 쓰기 시도)
    translate_segment_address(0, 100, PROT_WRITE, &physical);

    return 0;
}

4. 보호와 공유

4.1 세그먼트 보호

┌─────────────────────────────────────────────────────────────────────────┐
│                       세그먼트 보호 비트                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   세그먼트 디스크립터의 보호 필드:                                      │
│                                                                          │
│   ┌─────┬─────┬─────┬─────────────────────────────┐                     │
│   │  R  │  W  │  X  │           설명              │                     │
│   ├─────┼─────┼─────┼─────────────────────────────┤                     │
│   │  1  │  0  │  1  │  코드 세그먼트 (실행/읽기)  │                     │
│   │  1  │  0  │  0  │  상수 세그먼트 (읽기 전용)  │                     │
│   │  1  │  1  │  0  │  데이터 세그먼트 (읽기/쓰기)│                     │
│   │  0  │  0  │  0  │  접근 불가                  │                     │
│   └─────┴─────┴─────┴─────────────────────────────┘                     │
│                                                                          │
│   추가 보호 속성:                                                        │
│   - DPL (Descriptor Privilege Level): 0-3, 접근 가능한 특권 수준       │
│   - Present: 세그먼트가 메모리에 있는지                                 │
│   - Accessed: 접근 여부 (페이지 교체에 사용)                            │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

4.2 세그먼트 공유

┌─────────────────────────────────────────────────────────────────────────┐
│                       세그먼트 공유                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   프로세스 A                          프로세스 B                         │
│   ┌─────────────────┐                ┌─────────────────┐                │
│   │ 세그먼트 테이블 │                │ 세그먼트 테이블 │                │
│   ├─────────────────┤                ├─────────────────┤                │
│   │ 0: 코드         │────────┐       │ 0: 코드         │────────┐      │
│   │   base=0x1000   │        │       │   base=0x1000   │        │      │
│   │   limit=5000    │        │       │   limit=5000    │        │      │
│   ├─────────────────┤        │       ├─────────────────┤        │      │
│   │ 1: 데이터       │───┐    │       │ 1: 데이터       │───┐    │      │
│   │   base=0x8000   │   │    │       │   base=0xC000   │   │    │      │
│   │   limit=3000    │   │    │       │   limit=4000    │   │    │      │
│   └─────────────────┘   │    │       └─────────────────┘   │    │      │
│                         │    │                             │    │      │
│                         │    ▼                             │    ▼      │
│   물리 메모리           │    ┌─────────────────────────────┼────┐      │
│   ┌─────────────────────┼────│      공유 코드 세그먼트     │────┤      │
│   │ 0x1000              │    │      (libc.so 등)          │    │      │
│   │                     │    │        5000 바이트          │    │      │
│   │                     │    └─────────────────────────────┼────┘      │
│   │                     │                                  │           │
│   │                     ▼                                  ▼           │
│   │ 0x8000        ┌──────────────┐                ┌──────────────┐    │
│   │               │ A의 데이터   │  0xC000        │ B의 데이터   │    │
│   │               │ (개별)      │                │ (개별)      │    │
│   │               └──────────────┘                └──────────────┘    │
│   └──────────────────────────────────────────────────────────────────┘  │
│                                                                          │
│   코드 세그먼트: 공유 (같은 물리 주소 참조)                             │
│   데이터 세그먼트: 개별 (각 프로세스 고유)                              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

5. 페이징과 세그멘테이션 비교

┌─────────────────────────────────────────────────────────────────────────┐
│                  페이징 vs 세그멘테이션 비교                             │
├───────────────────────┬─────────────────────┬───────────────────────────┤
│        항목           │      페이징         │      세그멘테이션          │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 분할 단위             │ 고정 크기 (페이지)  │ 가변 크기 (세그먼트)      │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 프로그래머 인식       │ 투명함 (모름)       │ 인식함 (논리적 단위)      │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 외부 단편화           │ 없음                │ 있음                      │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 내부 단편화           │ 있음 (마지막 페이지)│ 없음                      │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 테이블 크기           │ 클 수 있음          │ 세그먼트 수에 비례        │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 메모리 할당           │ 간단                │ 복잡 (First-Fit 등)       │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 보호 단위             │ 페이지 단위         │ 논리적 단위 (유연함)      │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 공유                  │ 가능하나 복잡       │ 논리적 단위로 쉬움        │
├───────────────────────┼─────────────────────┼───────────────────────────┤
│ 현대 사용             │ 주로 사용           │ 페이징과 결합             │
└───────────────────────┴─────────────────────┴───────────────────────────┘

6. 세그멘테이션 + 페이징 결합

6.1 세그먼트 페이징 (Segmentation with Paging)

┌─────────────────────────────────────────────────────────────────────────┐
│               세그먼트 + 페이징 결합 주소 변환                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   논리 주소                                                              │
│   ┌────────────┬────────────┬──────────────┐                            │
│   │ 세그먼트(s) │ 페이지(p)  │  오프셋(d)   │                            │
│   └─────┬──────┴─────┬──────┴──────┬───────┘                            │
│         │            │             │                                     │
│         ▼            │             │                                     │
│   ┌──────────────┐   │             │                                     │
│   │ 세그먼트     │   │             │                                     │
│   │   테이블     │   │             │                                     │
│   ├──────────────┤   │             │                                     │
│   │ 세그먼트 s:  │   │             │                                     │
│   │ 페이지 테이블│───┘             │                                     │
│   │ 시작 주소   │                  │                                     │
│   └──────┬───────┘                  │                                     │
│          │                          │                                     │
│          ▼                          │                                     │
│   ┌──────────────┐                  │                                     │
│   │ 페이지 테이블 │                  │                                     │
│   │ (세그먼트별) │                  │                                     │
│   ├──────────────┤                  │                                     │
│   │ 페이지 p:    │                  │                                     │
│   │ 프레임 번호  │───────────┐      │                                     │
│   └──────────────┘           │      │                                     │
│                              │      │                                     │
│                              ▼      ▼                                     │
│                        ┌──────────────┐                                   │
│                        │물리 주소     │                                   │
│                        │= 프레임×크기│                                   │
│                        │  + 오프셋    │                                   │
│                        └──────────────┘                                   │
│                                                                          │
│   장점: 세그먼트의 논리적 분리 + 페이징의 외부 단편화 제거              │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

6.2 MULTICS 시스템

┌─────────────────────────────────────────────────────────────────────────┐
│                      MULTICS 메모리 관리                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   34비트 가상 주소:                                                      │
│   ┌──────────────┬──────────────┬──────────────┐                        │
│   │ 세그먼트(18) │ 페이지(6)    │  오프셋(10)  │                        │
│   └──────────────┴──────────────┴──────────────┘                        │
│                                                                          │
│   - 세그먼트 수: 2^18 = 256K 세그먼트                                   │
│   - 세그먼트당 페이지: 2^6 = 64 페이지                                  │
│   - 페이지 크기: 2^10 = 1KB                                             │
│   - 세그먼트 최대 크기: 64 × 1KB = 64KB                                 │
│                                                                          │
│   주소 변환:                                                             │
│   1. 세그먼트 번호로 세그먼트 테이블 조회                               │
│   2. 해당 세그먼트의 페이지 테이블 위치 획득                            │
│   3. 페이지 번호로 페이지 테이블 조회                                   │
│   4. 프레임 번호 + 오프셋 = 물리 주소                                   │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7. Intel x86 세그멘테이션

7.1 보호 모드 세그먼트 레지스터

┌─────────────────────────────────────────────────────────────────────────┐
│                    x86 세그먼트 레지스터                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   16비트 세그먼트 선택자 (Segment Selector)                             │
│   ┌────────────────────────────┬─────┬───────┐                          │
│   │    인덱스 (13비트)         │ TI  │  RPL  │                          │
│   └────────────────────────────┴─────┴───────┘                          │
│                                                                          │
│   TI: Table Indicator (0=GDT, 1=LDT)                                    │
│   RPL: Requested Privilege Level (0-3)                                  │
│                                                                          │
│   세그먼트 레지스터들:                                                   │
│   ┌──────┬────────────────────────────────────────┐                     │
│   │  CS  │ Code Segment - 현재 실행 중인 코드    │                     │
│   │  DS  │ Data Segment - 기본 데이터            │                     │
│   │  SS  │ Stack Segment - 스택                  │                     │
│   │  ES  │ Extra Segment - 추가 데이터           │                     │
│   │  FS  │ 추가 세그먼트 (스레드 로컬 스토리지)  │                     │
│   │  GS  │ 추가 세그먼트 (커널에서 사용)         │                     │
│   └──────┴────────────────────────────────────────┘                     │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7.2 세그먼트 디스크립터

┌─────────────────────────────────────────────────────────────────────────┐
                  x86 세그먼트 디스크립터 (64비트)                        
├─────────────────────────────────────────────────────────────────────────┤
                                                                          
   비트:  63      56 55   52 51   48 47          40 39   32              
         ┌─────────┬───────┬───────┬──────────────┬───────┐              
   상위  Base[31:24]Flags Limit   Access Byte  Base                 
   32비트  (8비트) (4비트)[19:16]   (8비트)    [23:16]              
         └─────────┴───────┴───────┴──────────────┴───────┘              
                                                                          
   비트:  31              16 15                   0                       
         ┌─────────────────┬─────────────────────┐                       
   하위    Base[15:0]        Limit[15:0]                              
   32비트    (16비트)          (16비트)                               
         └─────────────────┴─────────────────────┘                       
                                                                          
   Base: 32비트 세그먼트 시작 주소 (분산 저장)                           
   Limit: 20비트 세그먼트 크기                                           
                                                                          
   Flags (4비트):                                                        
   ┌────┬────┬────┬────┐                                                 
    G  D/B  L  AVL                                                  
   └────┴────┴────┴────┘                                                 
   G: Granularity (0=바이트, 1=4KB 단위)                                 
   D/B: Default operation size (0=16bit, 1=32bit)                        
   L: 64-bit code segment                                                
   AVL: Available for system software                                    
                                                                          
   Access Byte:                                                          
   ┌────┬─────┬────┬────┬────┬────┬────┬────┐                            
    P   DPL  S   E  DC  RW   A                                  
   └────┴─────┴────┴────┴────┴────┴────┴────┘                            
   P: Present bit                                                        
   DPL: Descriptor Privilege Level (0-3)                                 
   S: Descriptor type (0=system, 1=code/data)                            
   E: Executable (0=data, 1=code)                                        
   DC: Direction/Conforming                                              
   RW: Readable(code)/Writable(data)                                     
   A: Accessed                                                           
                                                                          
└─────────────────────────────────────────────────────────────────────────┘

7.3 x86 주소 변환 (세그멘테이션 + 페이징)

┌─────────────────────────────────────────────────────────────────────────┐
│               x86 전체 주소 변환 과정                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│   논리 주소                                                              │
│   ┌──────────────────┬────────────────────────────────┐                 │
│   │ 세그먼트 선택자   │         오프셋                │                 │
│   │    (16비트)       │        (32비트)               │                 │
│   └────────┬─────────┴───────────────┬────────────────┘                 │
│            │                         │                                   │
│            ▼                         │                                   │
│   ┌─────────────────────┐            │                                   │
│   │  세그멘테이션 단계   │            │                                   │
│   │                     │            │                                   │
│   │  GDT/LDT 조회      │            │                                   │
│   │  Base + Offset      │◀───────────┘                                   │
│   │  = 선형 주소        │                                                │
│   └──────────┬──────────┘                                                │
│              │                                                           │
│              ▼ 선형 주소 (Linear Address)                               │
│   ┌─────────────────────┐                                                │
│   │   페이징 단계        │                                                │
│   │                     │                                                │
│   │  CR3 → 페이지       │                                                │
│   │  디렉토리 → 테이블   │                                                │
│   │  → 프레임            │                                                │
│   └──────────┬──────────┘                                                │
│              │                                                           │
│              ▼                                                           │
│         물리 주소                                                        │
│                                                                          │
│   현대 운영체제 (Linux, Windows):                                       │
│   - 세그멘테이션 단순화 (Base=0, Limit=최대)                            │
│   - 실질적으로 페이징만 사용                                            │
│   - 선형 주소 = 논리 주소 (플랫 메모리 모델)                            │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

7.4 Linux의 세그멘테이션 사용

// Linux x86에서의 세그먼트 설정 (arch/x86/include/asm/segment.h)

// GDT 엔트리 인덱스 (Linux 커널)
#define GDT_ENTRY_KERNEL_CS     1
#define GDT_ENTRY_KERNEL_DS     2
#define GDT_ENTRY_DEFAULT_USER_CS   3
#define GDT_ENTRY_DEFAULT_USER_DS   4

// 세그먼트 선택자 계산
// 인덱스 << 3 | TI(0=GDT) | RPL
#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)      // 0x08
#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)      // 0x10
#define __USER_CS   (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)  // 0x1B (RPL=3)
#define __USER_DS   (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3)  // 0x23 (RPL=3)

// 플랫 메모리 모델: 모든 세그먼트가 0에서 시작, 4GB까지
// Base = 0x00000000
// Limit = 0xFFFFFFFF (G=1이면 4GB)

/*
 * Linux는 세그멘테이션을 최소한으로 사용:
 * - 커널/사용자 권한 분리 (CS, DS 세그먼트)
 * - 스레드 로컬 스토리지 (FS, GS 세그먼트)
 * - 실제 메모리 보호는 페이징으로 수행
 */

연습 문제

문제 1: 세그먼트 주소 변환

다음 세그먼트 테이블로 논리 주소 <1, 500>을 물리 주소로 변환하시오.

세그먼트 Base Limit
0 1000 600
1 2000 400
2 3000 800
정답 보기
1. 세그먼트 번호: 1
2. 오프셋: 500
3. 세그먼트 1 Limit: 400

오프셋(500) >= Limit(400) 이므로 Segmentation Fault!

주소 변환 실패 - 세그먼트 범위 초과

문제 2: 세그먼트 보호

다음 시나리오에서 보호 위반이 발생하는지 판단하시오.

세그먼트 테이블: | 세그먼트 | Base | Limit | 보호 | |---------|------|-------|------| | 0 (코드) | 0x1000 | 2000 | R-X | | 1 (데이터)| 0x5000 | 3000 | RW- |

  1. 세그먼트 0의 주소 500에서 명령어 페치
  2. 세그먼트 0의 주소 100에 데이터 쓰기
  3. 세그먼트 1의 주소 2500에서 읽기
정답 보기
1. 세그먼트 0 (코드), 주소 500, 실행(X)
   - 500 < 2000: 범위 OK
   - X 권한 있음: 보호 OK
    정상 실행

2. 세그먼트 0 (코드), 주소 100, 쓰기(W)
   - 100 < 2000: 범위 OK
   - W 권한 없음 (R-X만): 보호 위반!
    Protection Fault

3. 세그먼트 1 (데이터), 주소 2500, 읽기(R)
   - 2500 < 3000: 범위 OK
   - R 권한 있음 (RW-): 보호 OK
    정상 실행

문제 3: 세그먼트 공유

프로세스 A와 B가 있고, 둘 다 같은 공유 라이브러리(1000바이트)를 사용합니다. 이 라이브러리가 물리 주소 0x10000에 로드되어 있을 때, 각 프로세스의 세그먼트 테이블을 작성하시오.

(A는 세그먼트 2에, B는 세그먼트 3에 라이브러리 매핑)

정답 보기
프로세스 A 세그먼트 테이블:
| 세그먼트 | Base    | Limit | 보호 | 설명     |
|---------|---------|-------|------|----------|
| 0       | 0x5000  | 2000  | R-X  | A의 코드 |
| 1       | 0x8000  | 1500  | RW-  | A의 데이터|
| 2       | 0x10000 | 1000  | R-X  | 공유 라이브러리|

프로세스 B 세그먼트 테이블:
| 세그먼트 | Base    | Limit | 보호 | 설명     |
|---------|---------|-------|------|----------|
| 0       | 0x20000 | 3000  | R-X  | B의 코드 |
| 1       | 0x25000 | 2000  | RW-  | B의 데이터|
| 2       | ...     | ...   | ...  | 기타     |
| 3       | 0x10000 | 1000  | R-X  | 공유 라이브러리|

→ 세그먼트 A:2와 B:3가 같은 물리 주소(0x10000)를 가리킴
→ 라이브러리 코드가 메모리에 한 번만 적재됨

문제 4: 외부 단편화

세그먼트 방식에서 외부 단편화가 발생하는 이유와 해결 방법을 설명하시오.

정답 보기
외부 단편화 발생 이유:
1. 세그먼트는 가변 크기
2. 세그먼트 할당/해제 반복으로 메모리에 작은 홀들 생성
3. 총 자유 공간은 충분하지만 연속 공간 부족

예:
[사용][500KB 홀][사용][300KB 홀][사용][200KB 홀]
총 자유공간: 1000KB, 하지만 600KB 세그먼트 할당 불가

해결 방법:
1. 압축 (Compaction)
   - 세그먼트를 이동하여 홀 통합
   - 비용이 높음 (프로세스 중단 필요)

2. 페이징 결합
   - 세그먼트를 페이지로 분할
   - 외부 단편화 제거
   - 현대 시스템의 표준 방식

3. 버디 시스템 (Buddy System)
   - 2의 거듭제곱 크기로 메모리 분할
   - 단편화 감소, 빠른 병합

문제 5: x86 세그먼트 선택자

Linux에서 사용자 프로세스의 CS 레지스터 값이 0x23입니다. 이를 해석하시오.

정답 보기
0x23 = 0b00100011

세그먼트 선택자 구조: [Index(13)|TI(1)|RPL(2)]

0x23 = 0000 0000 0010 0011

Index (비트 15-3): 0000 0000 0010 0 = 4
TI (비트 2): 0 = GDT
RPL (비트 1-0): 11 = 3 (사용자 모드)

해석:
- GDT의 4번째 엔트리 (GDT_ENTRY_DEFAULT_USER_CS)
- 사용자 모드 (Ring 3)
- 이것은 사용자 코드 세그먼트를 가리킴

Linux 커널 코드와 일치:
#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)
              = (4 * 8 + 3)
              = 32 + 3
              = 35
              = 0x23 

다음 단계

14_Virtual_Memory.md에서 요구 페이징과 가상 메모리 시스템을 배워봅시다!


참고 자료

  • Silberschatz, "Operating System Concepts" Chapter 8
  • Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3
  • Linux kernel source: arch/x86/kernel/cpu/common.c (GDT 초기화)
  • Tanenbaum, "Modern Operating Systems" Chapter 3
to navigate between lessons