Segmentation

Definition

Segmentation: Memory management dividing process into logical segments (code, data, stack, heap) with each segment mapped independently to physical memory. Segments vary in size.

Logical organization matching program structure unlike paging (fixed-size units).

Basic Segmentation Concept

Segments

Process divided into multiple logical segments:

Process Address Space:
┌─────────────────────┐
│ Text (Code)         │ Segment 0
│                     │ (read-only, sharable)
├─────────────────────┤
│ Initialized Data    │ Segment 1
│ (globals)           │ (read-write)
├─────────────────────┤
│ Uninitialized Data  │ Segment 2
│ (bss)               │
├─────────────────────┤
│ Heap                │ Segment 3
│ (dynamic)           │ (grows downward)
│                     │
├─────────────────────┤
│ Stack               │ Segment 4
│ (grows upward)      │
└─────────────────────┘

Segment Table

Maps logical segments to physical addresses:

Segment | Base  | Limit | Protection
────────┼───────┼───────┼────────────
  0     | 0     | 4000  | R only (code)
  1     | 4000  | 1500  | RW (data)
  2     | 5500  | 2000  | RW (heap)
  3     | 7500  | 3000  | RW (stack)

Logical Address

Two components:

Logical Address: (segment_number, offset)

Example:
(1, 500) → Segment 1, offset 500 bytes

Segment 1:
Base: 4000
Offset: 500
Physical: 4000 + 500 = 4500

Address Translation (Segmentation)

Step-by-Step

Logical Address: (2, 300)

Step 1: Extract segment number and offset
  Segment Number: 2
  Offset: 300

Step 2: Look up segment table
  Segment_Table[2]:
    Base: 5500
    Limit: 2000

Step 3: Check offset valid
  Offset (300) < Limit (2000)? YES

Step 4: Calculate physical address
  Physical = Base + Offset
  Physical = 5500 + 300
  Physical = 5800

Step 5: Check protection
  Segment allows read/write? YES
  Access granted!

Segment Types and Usage

1. Code Segment

Contains: Program instructions
Size: Fixed (determined at compile time)
Characteristics:
  - Read-only (re-entrant)
  - Shareable (many processes use same code)
  - Cannot grow

Example: Binary /usr/bin/ls
(same code shared by all users running ls)

2. Data Segment

Contains: Global variables
Size: Fixed (determined at compile time)
Characteristics:
  - Read-write
  - Not shareable (each process different values)
  - Cannot grow

Example:
int globalCounter = 0;
char globalBuffer[1024];

3. Stack Segment

Contains: Local variables, return addresses, function parameters
Size: Dynamic (grows as needed)
Characteristics:
  - Read-write
  - Grows upward (toward higher addresses or downward)
  - Shrinks when functions return
  - Limit prevents overflow

Example:
void func() {
  int localVar;  // Pushed to stack
}

4. Heap Segment

Contains: Dynamically allocated memory
Size: Dynamic (grows as allocated)
Characteristics:
  - Read-write
  - Grows downward (toward higher addresses)
  - Allocations fragmented
  - malloc()/new() allocate from heap

Example:
int *arr = malloc(sizeof(int) * 1000);

Benefits of Segmentation

1. Logical Organization

Matches program structure:

Code ≠ Data ≠ Stack ≠ Heap
Different characteristics
Different segment sizes
Different protections

2. Dynamic Size

Segments grow as needed:

Program allocates memory:
Heap grows 10MB
Stack grows 5MB
Other segments unchanged

No need to pre-allocate total process size!

3. Sharing

Share segments between processes:

Process A Code Segment = Process B Code Segment (shared)
Process A Data Segment ≠ Process B Data Segment (separate)

File: /usr/bin/emacs (10MB)
Users: 1000
With sharing: 1 copy in memory (10MB)
Without sharing: 1000 copies (10GB!)

4. Protection

Different protections for segments:

Code segment: READ only (execute)
Data segment: READ/WRITE
Stack segment: READ/WRITE
Heap segment: READ/WRITE

Hardware enforces at segment level

5. Relocation

Segments can move independently:

Code segment: Physical 0-4000
Data segment: Physical 4000-5500
Heap segment: Physical 5500-7500

Rearrange for defragmentation:
Code segment: Physical 10000-14000
Data segment: Physical 14000-15500
Heap segment: Physical 15500-17500

Just update segment table!

Disadvantages of Segmentation

1. External Fragmentation

Free space becomes scattered:

After many allocation/deallocation:
Segment table:
Segment | Base | Limit
────────┼──────┼──────
  0     | 0    | 1000
  1     | 1000 | 500  (free)
  2     | 2000 | 2000
  3     | 4500 | 500  (free)
  4     | 5000 | 1000

Free space: 500 + 500 = 1000 bytes total
But scattered! Can't fit 800-byte allocation!

Need compaction (expensive!)

2. Complexity

More complex than paging:

Segment table per process
Variable-size allocations
Complex allocation algorithms
Compaction handling

More OS overhead

3. Sharing Complexity

Segment sharing needs care:

Code segment shared (read-only): Safe
Data segment shared: Dangerous!

Two processes share data segment:
Process A modifies global variable
Process B sees modification
Synchronization issues!

Usually shared only for read-only code

4. Address Calculation

Address calculation more complex:

With paging (simple):
Physical = Frame * PageSize + Offset

With segmentation (complex):
Check segment exists
Check offset in limit
Add base
Hardware must be smart!

Segment table can be large

Paging vs Segmentation

FeaturePagingSegmentation
Unit SizeFixed (4KB)Variable (logical)
AddressSingle number(segment, offset)
Internal Frag~50% of pageNone
External FragNoneSignificant
Logical MatchNo (arbitrary)Yes (structure)
CompactionNone neededMay be needed
SharingDifficultEasy
Virtual MemoryYesLimited
Hardware CostLowMedium

Virtual Memory with Segmentation

Concept

Segments on disk when not used:

Segment 0 (Code): 4000 bytes, in memory
Segment 1 (Data): 1500 bytes, in memory
Segment 2 (Unused Heap): 1000MB, on disk
Segment 3 (Stack): 5000 bytes, in memory

Process seems to have 1000MB+
Actually using: ~10MB in memory
Rest on disk

Segment Fault

Access to segment not loaded:

Process accesses Segment 2 (on disk)
Segment Table[2]: Valid bit = 0 (not in memory)
Segment Fault!

Handler:
1. Load segment from disk
2. Set valid bit = 1
3. Retry instruction

Modern Use of Segmentation

Pure segmentation rarely used in modern systems

Why:

  • External fragmentation (problem!)
  • Complex management
  • Paging simpler

Hybrid approach: Segmentation + Paging

Windows (x86):
Uses segmentation for process separation
Uses paging within each segment

Modern x86-64:
Segmentation mostly disabled
Pure paging used

Linux:
Paging predominantly
Minimal segmentation use

Example: Intel x86 Segmentation

Real Mode (16-bit)

Segmentation only (no paging)
Segment size: 64KB max
Segment base: Multiple of 16 bytes

Address: (segment, offset)
Physical = segment_base + offset

Protected Mode (32-bit)

Segmentation enabled
Segment size: Up to 4GB
Can add paging on top

Address: Selector (segment number) + offset
Selector used to look up segment descriptor
Descriptor provides: base, limit, protection

Summary

Segmentation divides process into logical segments matching program structure (code, data, stack, heap). Segments variable size, grow dynamically. Segment table maps logical segment+offset to physical address. Benefits: logical organization, protection, sharing, dynamic sizing. Disadvantages: external fragmentation, complexity, harder to implement efficient virtual memory. Modern systems prefer paging (simple, no external fragmentation) or hybrid (segmentation + paging). Segmentation mostly historical but understanding important for x86 protected mode and some specialized systems. Paging became dominant due to simplicity and efficiency.