Operating Systems
📂 Memory Management
· 2 of 5
45 min read
Memory Segmentation in OS — Address Translation, Protection, Sharing
Master Segmentation from Galvin's Operating System Concepts through four interactive step-by-step animations. Watch the MMU translate two-part logical addresses ⟨s, d⟩ into physical addresses through a segment table, see permission bits enforce read/write/execute rules, learn how two processes share a library segment, and work through address-translation traps at exact boundaries. Two fully worked numericals with the classic Galvin table.
Section 01
The Story That Explains Segmentation
📖 Real World Analogy
The University Library
Walk into any university library. Books aren't shelved as one endless line ordered by
accession number. They're organised into sections: Physics on the second floor,
Literature in the east wing, Reference books in the reading room, Journals in the
basement. Each section has its own catalogue entry — "Physics starts at shelf 4B and
spans 60 metres."
When you ask for "Physics — Quantum Mechanics, page 42", the librarian doesn't
need to know a single global address. She looks up "Physics" in her map (base = shelf 4B),
walks 3 shelves in, finds page 42. Two conceptual pieces: the section name
and the offset within it.
That's exactly how Segmentation organises memory. A program is not one
contiguous ribbon of bytes — it's a collection of logical units (code, data, stack, heap,
each function's frame) with their own sizes and permissions. The OS keeps a table telling
hardware where each segment physically lives.
💡
Why Segmentation Feels Natural to Programmers
When you write code, you don't think of memory as one flat 4 GB array. You think:
"this is my main function", "this is my array", "this is my stack of function calls".
Segmentation is the memory-management scheme that matches the programmer's mental
model. Each logical unit is a segment with its own base, limit, and permissions.
Section 02
The User's View of Memory — Segments
Galvin lists the typical segments that make up a compiled program. Each is a separate logical
entity; the programmer refers to them by name (or by segment number), and the OS handles the
actual RAM addresses.
💻
Code Segment
read + execute
Instructions of the program. Read-only after loading, executable. May be shared between
processes running the same binary (huge memory saving).
📊
Data Segment
read + write
Global variables, constants (in a read-only sub-segment), initialised static data.
Non-executable — attempting to execute here traps.
📚
Stack Segment
grows downward
Function call frames, local variables, return addresses. Grows downward from a high
address on most architectures. Overflow → segmentation fault.
🔥
Heap Segment
grows upward
Dynamically allocated memory (malloc / new). Grows upward. Managed by the runtime
library rather than the compiler.
💬
Symbol Table
debugger metadata
Names of functions and variables, used by debuggers. Present in debug builds; stripped
in production builds.
📚
Shared Libraries
code shared across processes
Dynamically loaded libraries (libc, libm). One physical copy shared by all processes
that use them — the killer app of segmentation-based sharing.
Section 03
Segmentation Architecture — Logical Address Format
Under segmentation, a logical address is a pair <s, d>:
📋 Logical Address Fields
s
Segment number. Identifies which segment (which entry in the segment table).
d
Offset within segment. Byte position from the start of that segment (0 to limit − 1).
The Segment Table
Each process has a segment table in memory. Row i of the table
describes segment i: its base (starting physical address) and
limit (length in bytes). Optional protection bits control read / write /
execute permissions.
// Segment table entry structure (simplified)struct SegDescriptor {
unsigned int base; // physical start addressunsigned int limit; // length in bytesunsigned int permissions; // R / W / X flagsbool valid; // is this entry in use?
};
Two Hardware Registers Locate the Table
🔐 STBR — Segment Table Base Register
Physical address where this process's segment table starts
Updated by OS on every context switch
🔐 STLR — Segment Table Length Register
Number of segments the process has
Sanity check — reject segment numbers ≥ STLR
Section 04
Address Translation — Step by Step
MMU Translation for a Segmented Address <s, d>
🎮 Interactive — Translate Several Addresses
Segment table for our example program (from Galvin):
Segment
Base
Limit
Description
0
1400
1000
subroutine
1
6300
400
sqrt library
2
4300
400
main
3
3200
1100
stack
4
4700
1000
symbol table
Address translation — step through each part of the process
Step 0 of 8
START
Segment table loaded above. Click Next to translate a series of logical addresses. Watch valid cases produce a physical address; watch bad accesses trap to the OS.
Section 05
Memory Protection with Segments
Each segment carries protection bits — read (R), write (W), execute (X). The MMU checks the
intended operation against the bits and the offset check on every access. Two-way
safety net.
🔒 Typical Segment Permissions
Code
R + X — read (fetch), execute (jump). NOT writable.
Data
R + W — read, write. NOT executable (prevents shellcode injection).
Stack
R + W — read, write. NOT executable (same reason as data).
Rodata
R only — read-only constants. Attempts to write cause a segfault.
Shared lib
R + X (shared) — one physical copy shared by all processes using the library.
🎮 Interactive — Protection Violations
Try different access types on a code segment (R+X) and a data segment (R+W). Watch which
succeed and which trigger a segmentation fault.
Permission checks — same segment, different operations
Step 0 of 5
START
We have a code segment (R+X) and a data segment (R+W). Both live in RAM. Watch what happens when a program tries different kinds of access. This is exactly how NX-bit and DEP prevent buffer overflow exploits.
Section 06
Sharing Segments — Memory Wins
A killer advantage of segmentation is sharing. If two processes need the
same code (the C library, an editor loaded twice, a game engine's rendering module), they
can share one physical copy. Both processes' segment tables have entries pointing
to the same base address.
🎮 Interactive — Two Processes Share a Library Segment
Shared segment across two processes
Step 0 of 4
START
Two processes are running. Each has its own segment table. Both need the sqrt library. Click Next to see how segmentation elegantly shares one physical copy.
🔑
Why This Matters
On a Linux system running 100 processes, if libc were duplicated per process it would
waste GB of RAM. Segmentation-style sharing (used in modern paging too, but the idea
originates here) means one physical copy of libc serves all 100 processes.
Same idea powers shared memory IPC (shmget) and memory-mapped files.
Section 07
Fragmentation in Segmentation
Segmentation still allocates variable-sized chunks contiguously — so external
fragmentation returns, just like plain contiguous allocation.
✅ What Segmentation Fixes
Each segment can grow / shrink independently
Different segments have different protection bits
Sharing is trivial (share one segment)
Programmer's mental model matches memory layout
❌ What Segmentation Doesn't Fix
External fragmentation — segments are still contiguous
Compaction needed to reclaim wasted space
Segment table itself uses memory
Two memory accesses per user reference (table lookup + data)
🚩
Best of Both — Segmentation with Paging
Real systems like Intel x86 combine both: segmentation gives the
programmer's view (code, data, stack), while paging breaks each segment
into fixed-size pages that the OS can scatter through physical memory. Best of both
worlds — this is what modern OSes actually run.
Section 08
Numerical Problem 1 — Address Translation Practice
Given
Segment
Base
Limit
0
219
600
1
2300
14
2
90
100
3
1327
580
4
1952
96
Translate each of the following logical addresses to a physical address. If invalid, state why.
Segment 5 doesn't exist (only 0–4 defined) — TRAP. Would fail the STLR check.
🏆
Summary
Valid translations: 649, 2310,
1727. Three trapped addresses illustrate the three failure
modes: offset ≥ limit (twice) and segment number ≥ STLR (once).
Section 09
Numerical Problem 2 — Interactive Walkthrough
Use a different segment table. Click Next to translate each address one at a time and see
the base + offset math.
Segment Table
Segment
Base
Limit
0
1200
500
1
2400
200
2
0
800
3
3200
400
Numerical 2 — Translate each address step by step
Logical address
—
segment s = ?, offset d = ?
Lookup & check
base = ?, limit = ?
check: —
Verdict
Awaiting first address…
Step 0 of 4
START
We'll translate four logical addresses using the segment table above. Some are valid, some fail. Click Next to begin with the first address.
Section 10
Segmentation vs Paging
Aspect
Segmentation
Paging
Block size
Variable — one per segment
Fixed — one page (4 KB typical)
Programmer visibility
Yes — natural units (code, stack, ...)
Invisible
Address form
<s, d> — two-part
<p, d> — page + offset (transparent)
External fragmentation
Yes
No
Internal fragmentation
None
Up to one page per segment
Sharing granularity
Whole segments
Individual pages
Protection granularity
Per-segment
Per-page
Table size
Small (few segments)
Large (millions of pages)
🔑
The Winner Is: Both
Modern x86-64 systems use segmentation with paging. Segments define the
logical view (code, data, stack); paging manages the physical mapping so segments don't
need to be contiguous. You get segmentation's flexibility with paging's fragmentation-free
allocation.
Section 11
Real-World Applications
💾
Intel x86 Protected Mode
Introduced full segmentation in the 80286 (1982). GDT (Global Descriptor Table) and
LDT (Local Descriptor Table) hold segment descriptors. x86-64 largely retired
segmentation in favour of flat paging, but CS/DS/SS still exist.
GDT · LDT · Selectors
📂
Shared Libraries
libc.so, libm.so, DLLs on Windows — all use the shared-segment principle. One physical
copy in RAM serves every process using the library. Massive memory savings.
Dynamic linking · .so · .dll
🖥️
Buffer Overflow Defence
Stack and heap segments marked non-executable (NX bit, DEP). Attempts to jump to
shellcode on the stack cause an immediate trap. Direct descendant of segmentation
protection bits.
NX · DEP · W^X
👤
Multics (Historical)
The 1965 Multics OS pioneered segmentation combined with paging. Every file was a segment.
Cited by Galvin as the archetypal segmented system. Direct ancestor of UNIX.
Historical · Multics
📡
JVM Method Area & Heap
Java splits the JVM's memory into method area (classes/bytecode — R+X), heap (objects —
R+W), stack (per thread — R+W). Same idea as OS segmentation, one level up.
Method area · Heap · Stack
🔒
Kernel vs User Space
Every OS partitions memory into "kernel segment" (high addresses, ring 0) and "user
segment" (low addresses, ring 3). Different permission bits. The oldest form of
segmentation still in universal use.
Ring 0 · Ring 3
Section 12
Golden Rules — Segmentation
🔑 Galvin's Non-Negotiable Rules
1
A logical address under segmentation is the pair <s, d> — segment number and offset. The compiler produces these; the MMU translates them.
2
Each process has a segment table. Row i stores base and limit for segment i. Two hardware registers (STBR, STLR) point at the table and give its size.
3
Address translation runs two checks on every access: s < STLR (valid segment number) and d < limit (offset within segment). Physical = base + d if both pass; trap otherwise.
4
Protection bits per segment enforce read/write/execute rules. Modern NX-bit exploits protection: mark stack/data as non-executable to stop shellcode. This is a direct segmentation legacy.
5
Segmentation supports sharing elegantly. Two processes' tables can have entries pointing to the same physical base — one shared library, many users.
6
Segmentation still allocates contiguously, so it suffers from external fragmentation. Compaction can help but isn't cheap.
7
Every memory access under pure segmentation requires two memory reads: one to fetch the segment descriptor, one for the actual data. TLBs cache descriptors to make this fast.
8
Segmentation matches the programmer's mental model perfectly (code, data, stack, heap). Paging is invisible to the programmer. Segmentation wins on clarity; paging wins on performance.
9
Modern systems (Intel x86, MULTICS heritage) combine segmentation with paging: segments define the logical view, pages handle physical placement. Best of both.
10
The Galvin address translation formula never varies: physical = segment_table[s].base + d, gated by s < STLR and d < limit. Memorise it.