Loading learning content...
We've examined each component of segmented address translation in isolation: segment number extraction, offset extraction, bounds checking, and physical address formation. Now it's time to synthesize this knowledge by tracing complete translation examples from start to finish.
Worked examples are invaluable for cementing understanding. By following concrete numbers through each step, seeing exactly how bits are extracted, how tables are indexed, and how addresses are computed, the abstract mechanisms become tangible and intuitive. These examples will prepare you to trace translations yourself, debug memory issues, and understand hardware documentation.
By the end of this page, you will be able to trace any logical address through the complete translation pipeline, calculate physical addresses by hand, identify and diagnose translation failures, and understand how real systems report addressing information.
Before working through examples, let's establish a concrete system configuration that we'll use throughout this page. This represents a simplified but realistic segmented memory system.
1234567891011121314151617181920212223242526272829303132333435363738
=== Example System Configuration === Logical Address Format:┌────────────────────────────────────┐│ 16-bit Logical Address │├──────────────┬─────────────────────┤│ Segment (4b) │ Offset (12b) ││ bits 15-12 │ bits 11-0 │└──────────────┴─────────────────────┘ Physical Address: 24 bits (16 MB addressable) Key Parameters: - Maximum segments per process: 16 (2^4) - Maximum segment size: 4096 bytes (2^12) - Physical memory: 16 MB (2^24) Segment Table for Process P (5 valid segments): ┌─────┬────────────┬───────┬─────────┬────────────┐│ Seg │ Base │ Limit │ Present │ Protection │├─────┼────────────┼───────┼─────────┼────────────┤│ 0 │ 0x100000 │ 4096 │ Yes │ R-X │ Code│ 1 │ 0x200000 │ 8192 │ Yes │ RW- │ Data│ 2 │ 0x300000 │ 2048 │ Yes │ RW- │ Stack│ 3 │ 0x400000 │ 16384 │ Yes │ RW- │ Heap│ 4 │ 0x000000 │ 4096 │ No │ RW- │ Swapped└─────┴────────────┴───────┴─────────┴────────────┘ STBR (Segment Table Base Register): 0x800000STLR (Segment Table Length Register): 5 Notes: - Segment 0 (Code): Read & Execute, starts at 1 MB - Segment 1 (Data): Read & Write, starts at 2 MB - Segment 2 (Stack): Read & Write, starts at 3 MB - Segment 3 (Heap): Read & Write, starts at 4 MB - Segment 4 (Extra): Currently swapped to disk (not present)| Component | Formula | Example (addr = 0x3A5F) |
|---|---|---|
| Segment Number | addr >> 12 | 0x3A5F >> 12 = 0x3 |
| Offset | addr & 0xFFF | 0x3A5F & 0xFFF = 0xA5F |
| Physical Address | base + offset | (from table) + 0xA5F |
The 4-bit segment / 12-bit offset split is chosen for pedagogical clarity. With only 16 possible segments and 4 KB maximum segment size, all values are small enough to trace comfortably. Real systems like Intel x86 use larger values but the same principles apply.
Let's trace a successful memory access that passes all checks and produces a valid physical address.
Scenario: A program executes MOV AX, [0x1800] — reading from logical address 0x1800.
Step-by-Step Translation:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
=== Translation of Logical Address 0x1800 === STEP 1: Parse the Logical Address─────────────────────────────────────────────Logical Address: 0x1800Binary: 0001 1000 0000 0000 ├──┘ └──────────────┤ │ │ │ └── Offset bits (12 bits) │ └── Segment bits (4 bits) STEP 2: Extract Segment Number─────────────────────────────────────────────Segment Number = 0x1800 >> 12 = 0x1800 / 4096 = 0x1 (segment 1) Calculation: 0x1800 = 6144 decimal 6144 / 4096 = 1 (integer division) STEP 3: Extract Offset─────────────────────────────────────────────Offset = 0x1800 & 0x0FFF = 0x800 = 2048 decimal Calculation: 0x1800 AND 0x0FFF: 0001 1000 0000 0000 & 0000 1111 1111 1111 ───────────────────── 0000 1000 0000 0000 = 0x800 STEP 4: Validate Segment Number─────────────────────────────────────────────Check: segment (1) < STLR (5)?Answer: 1 < 5 ✓ VALID The segment number is within the valid range. STEP 5: Look Up Segment Table Entry─────────────────────────────────────────────Segment Table Entry for Segment 1: Base: 0x200000 (2 MB) Limit: 8192 bytes Present: Yes Protection: RW- (Read, Write, no Execute) Entry address = STBR + (segment_num × entry_size) = 0x800000 + (1 × 8) = 0x800008 STEP 6: Check Present Bit─────────────────────────────────────────────Is segment present in memory?Answer: Yes ✓ VALID STEP 7: Check Bounds─────────────────────────────────────────────Check: offset (2048) < limit (8192)?Answer: 2048 < 8192 ✓ VALID The offset is within the segment's bounds. STEP 8: Form Physical Address─────────────────────────────────────────────Physical Address = Base + Offset = 0x200000 + 0x800 = 0x200800 Calculation: 0x200000 (base: 2,097,152) + 0x000800 (offset: 2,048) ────────── 0x200800 (physical: 2,099,200) ═══════════════════════════════════════════════FINAL RESULT: Logical 0x1800 → Physical 0x200800 ✓ SUCCESS═══════════════════════════════════════════════The logical address 0x1800 successfully translates to physical address 0x200800. The CPU can now access the memory at this physical location. This entire process happens in hardware within a few clock cycles.
Now let's trace an address that fails bounds checking—a common programming error that results in a segmentation fault.
Scenario: A program has an array out-of-bounds bug and accesses logical address 0x2900 within the stack segment.
Step-by-Step Translation:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
=== Translation of Logical Address 0x2900 === STEP 1: Parse the Logical Address─────────────────────────────────────────────Logical Address: 0x2900Binary: 0010 1001 0000 0000 ├──┘ └──────────────┤ Seg Offset STEP 2: Extract Segment Number─────────────────────────────────────────────Segment Number = 0x2900 >> 12 = 0x2 (segment 2 - Stack) STEP 3: Extract Offset ─────────────────────────────────────────────Offset = 0x2900 & 0x0FFF = 0x900 = 2304 decimal STEP 4: Validate Segment Number─────────────────────────────────────────────Check: segment (2) < STLR (5)?Answer: 2 < 5 ✓ VALID STEP 5: Look Up Segment Table Entry─────────────────────────────────────────────Segment 2 (Stack): Base: 0x300000 (3 MB) Limit: 2048 bytes ← Note: only 2048! Present: Yes Protection: RW- STEP 6: Check Present Bit ─────────────────────────────────────────────Is segment present? Yes ✓ VALID STEP 7: Check Bounds ← FAILURE OCCURS HERE─────────────────────────────────────────────Check: offset (2304) < limit (2048)? Offset: 2304 (0x900) Limit: 2048 (0x800) 2304 < 2048 ? Answer: NO ✗ FAULT! The offset exceeds the segment's limit! ═══════════════════════════════════════════════FAULT: SEGMENT BOUNDS VIOLATION═══════════════════════════════════════════════ What happens next: 1. MMU asserts fault signal 2. CPU saves state (registers, flags, PC) 3. CPU switches to kernel mode 4. Control jumps to exception handler 5. OS examines fault type and address Possible OS responses: - If stack growth possible: extend stack, retry - If actual bug: deliver SIGSEGV to process - Default: process terminated, core dump generated Error message might look like: "Segmentation fault (core dumped)" or "SIGSEGV at address 0x2900, stack segment overflow"Analysis:
This failure represents a common bug: stack overflow. The stack segment was allocated only 2048 bytes (offsets 0x000 to 0x7FF), but the program tried to access offset 0x900 (2304). This could happen from:
The bounds check caught this before any memory corruption could occur.
Without bounds checking, this access would have proceeded to physical address 0x300900, which lies in a different segment's memory (or unmapped space). This could corrupt data, leak sensitive information, or enable code injection. Bounds checking prevents all of these outcomes.
Another failure case: referencing a segment number that doesn't exist in the segment table.
Scenario: A corrupted pointer contains the value 0xA100, referencing segment 10 which doesn't exist.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
=== Translation of Logical Address 0xA100 === STEP 1: Parse the Logical Address─────────────────────────────────────────────Logical Address: 0xA100Binary: 1010 0001 0000 0000 STEP 2: Extract Segment Number─────────────────────────────────────────────Segment Number = 0xA100 >> 12 = 0xA (10 decimal) STEP 3: Extract Offset─────────────────────────────────────────────Offset = 0xA100 & 0x0FFF = 0x100 = 256 decimal STEP 4: Validate Segment Number ← FAILURE HERE─────────────────────────────────────────────Check: segment (10) < STLR (5)? Segment Number: 10 STLR (valid range): 5 10 < 5 ? Answer: NO ✗ FAULT! ═══════════════════════════════════════════════FAULT: INVALID SEGMENT NUMBER═══════════════════════════════════════════════ The segment number exceeds the segment table length.No segment table entry exists for segment 10. This typically indicates: - Wild/corrupted pointer - Uninitialized pointer variable - Use-after-free bug - Stack smashing corrupted saved pointer - Deliberate attack attempt OS Response: - Cannot resolve: no valid segment metadata - Deliver SIGSEGV to process - Process terminated| Address | Segment # | STLR Check | Result |
|---|---|---|---|
| 0x0500 | 0 | 0 < 5 ✓ | Valid segment |
| 0x1A00 | 1 | 1 < 5 ✓ | Valid segment |
| 0x4FFF | 4 | 4 < 5 ✓ | Valid segment |
| 0x5000 | 5 | 5 < 5 ✗ | Invalid segment |
| 0xFFFF | 15 | 15 < 5 ✗ | Invalid segment |
Notice that this fault occurs before any segment table access. The STLR check prevents reading invalid memory when looking up the segment descriptor. This is an important defense: even a corrupted segment table can't cause the translation hardware to access arbitrary memory.
What happens when a valid segment number references a segment that has been swapped out to disk?
Scenario: The program accesses logical address 0x4200, referencing segment 4 which exists but is currently swapped out.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
=== Translation of Logical Address 0x4200 === STEP 1: Parse the Logical Address─────────────────────────────────────────────Logical Address: 0x4200Segment Number: 4Offset: 0x200 (512 decimal) STEP 2-4: Segment Number Valid─────────────────────────────────────────────Check: segment (4) < STLR (5)?Answer: 4 < 5 ✓ VALID STEP 5: Look Up Segment Table Entry─────────────────────────────────────────────Segment 4: Base: 0x000000 (invalid - not loaded) Limit: 4096 bytes Present: NO ← Segment is swapped out! Protection: RW- STEP 6: Check Present Bit ← FAULT HERE─────────────────────────────────────────────Is segment present in memory?Answer: NO ✗ FAULT! ═══════════════════════════════════════════════FAULT: SEGMENT NOT PRESENT═══════════════════════════════════════════════ This is a "soft" fault - potentially resolvable: 1. CPU traps to kernel 2. Kernel identifies fault type: missing segment 3. Kernel locates segment on disk 4. Kernel finds free physical memory 5. Kernel loads segment from disk to memory 6. Kernel updates segment table entry: - Base = new physical location - Present = Yes 7. Kernel resumes the process 8. Instruction is restarted 9. Translation now succeeds! This is the mechanism for demand segmentation (similar todemand paging, but at segment granularity). Timeline: [Fault] → [Disk I/O: ~10ms] → [Table Update] → [Resume] → [Success]Key Difference from Previous Faults:
Unlike bounds violations or invalid segment numbers (which indicate bugs), a "segment not present" fault is a normal part of system operation when demand segmentation or swapping is used. The OS handles it transparently:
This is similar to how demand paging works with page faults.
Systems using demand segmentation only load segments when first accessed. A newly forked process might have all segments marked 'not present', loading them from the parent or disk only on demand. This reduces memory usage and startup time for large programs.
Here's a quick reference showing multiple translations using our example segment table, demonstrating the variety of outcomes possible.
| Logical | Seg | Offset | Base | Limit | Result |
|---|---|---|---|---|---|
| 0x0100 | 0 | 0x100 | 0x100000 | 4096 | Physical: 0x100100 ✓ |
| 0x0FFF | 0 | 0xFFF | 0x100000 | 4096 | Physical: 0x100FFF ✓ |
| 0x1000 | 1 | 0x000 | 0x200000 | 8192 | Physical: 0x200000 ✓ |
| 0x1800 | 1 | 0x800 | 0x200000 | 8192 | Physical: 0x200800 ✓ |
| 0x1FFF | 1 | 0xFFF | 0x200000 | 8192 | Physical: 0x200FFF ✓ |
| 0x2000 | 2 | 0x000 | 0x300000 | 2048 | Physical: 0x300000 ✓ |
| 0x27FF | 2 | 0x7FF | 0x300000 | 2048 | Physical: 0x3007FF ✓ |
| 0x2800 | 2 | 0x800 | 2048 | FAULT: 0x800 ≥ 2048 ✗ | |
| 0x3A5F | 3 | 0xA5F | 0x400000 | 16384 | Physical: 0x400A5F ✓ |
| 0x4000 | 4 | FAULT: Not Present ✗ | |||
| 0x5000 | 5 | FAULT: Seg 5 ≥ STLR ✗ | |||
| 0xFFFF | 15 | FAULT: Seg 15 ≥ STLR ✗ |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
#include <stdio.h>#include <stdint.h> /* * Batch Translation Example * Demonstrates multiple translations with various outcomes */ typedef struct { uint32_t base; uint32_t limit; int present;} SegEntry; SegEntry seg_table[] = { {0x100000, 4096, 1}, // Seg 0: Code {0x200000, 8192, 1}, // Seg 1: Data {0x300000, 2048, 1}, // Seg 2: Stack {0x400000, 16384, 1}, // Seg 3: Heap {0x000000, 4096, 0}, // Seg 4: Swapped};#define STLR 5 const char* translate(uint16_t logical, uint32_t* physical) { uint16_t seg = logical >> 12; uint16_t off = logical & 0x0FFF; if (seg >= STLR) return "Invalid segment"; if (!seg_table[seg].present) return "Not present"; if (off >= seg_table[seg].limit) return "Bounds violation"; *physical = seg_table[seg].base + off; return "Success";} int main() { uint16_t test_addresses[] = { 0x0100, 0x0FFF, 0x1000, 0x1800, 0x1FFF, 0x2000, 0x27FF, 0x2800, 0x3A5F, 0x4000, 0x5000, 0xFFFF }; int num_tests = sizeof(test_addresses)/sizeof(test_addresses[0]); printf("%-10s %-4s %-6s %-10s %-10s %s\n", "Logical", "Seg", "Offset", "Base", "Physical", "Status"); printf("%-10s %-4s %-6s %-10s %-10s %s\n", "-------", "---", "------", "----", "--------", "------"); for (int i = 0; i < num_tests; i++) { uint16_t addr = test_addresses[i]; uint32_t physical = 0; const char* status = translate(addr, &physical); uint16_t seg = addr >> 12; uint16_t off = addr & 0x0FFF; printf("0x%04X %-4u 0x%03X ", addr, seg, off); if (seg < STLR && seg_table[seg].present) { printf("0x%06X ", seg_table[seg].base); } else { printf("%-10s ", "-"); } if (physical != 0) { printf("0x%06X ", physical); } else { printf("%-10s ", "-"); } printf("%s\n", status); } return 0;}Notice how the segment number is always addr >> 12 (equivalent to the first hex digit). Mental math tip: for addresses like 0x3A5F, just look at the leading digit (3) to immediately know the segment. The remaining digits (A5F) are the offset.
Being able to perform these calculations quickly is valuable for debugging, interview questions, and understanding system behavior. Here are techniques for fast mental calculation.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
=== Practice Problems === Given the segment table from our examples, translate these: Problem 1: Logical Address 0x0ABC───────────────────────────────Your work: Segment = 0x0ABC >> 12 = ___ Offset = 0x0ABC & 0xFFF = ___ Base = _______ (look up seg ___) Limit = _______ Bounds check: ___ < ___ ? Physical = _______ Answer: Segment 0, Offset 0xABC, Base 0x100000 Bounds: 0xABC (2748) < 4096 ✓ Physical: 0x100000 + 0xABC = 0x100ABC ───────────────────────────────────────────── Problem 2: Logical Address 0x3FFF───────────────────────────────Your work: Segment = ___ Offset = ___ Base = _______ Limit = _______ Bounds check: ___ < ___ ? Physical = _______ Answer: Segment 3, Offset 0xFFF (4095) Base 0x400000, Limit 16384 Bounds: 4095 < 16384 ✓ Physical: 0x400FFF ───────────────────────────────────────────── Problem 3: Logical Address 0x1FFF (edge case)───────────────────────────────Your work: Segment = ___ Offset = ___ Limit check: ___ < ___ ? Answer: Segment 1, Offset 0xFFF (4095) Limit 8192 Bounds: 4095 < 8192 ✓ Physical: 0x200FFF (This is valid - well within bounds) ───────────────────────────────────────────── Problem 4: Logical Address 0x2900 (failure case)───────────────────────────────Your work: Segment = ___ Offset = ___ Limit = ___ Bounds check: ___ < ___ ? Answer: Segment 2, Offset 0x900 (2304) Limit 2048 Bounds: 2304 < 2048 ✗ FAIL Result: Bounds violation faultIn exams, always show your work clearly: (1) Extract segment and offset, (2) State the base and limit from the table, (3) Show the bounds comparison, (4) Calculate the physical address. Even if you make an arithmetic error, showing the correct process often earns partial credit.
Working through concrete examples transforms abstract understanding into practical skill. You can now trace any logical address through the complete segmented translation pipeline.
Module Complete:
You have now completed the Address Translation module for Segmentation. You understand:
This knowledge forms the foundation for understanding more advanced topics like segmentation with paging, the Intel x86 memory model, and the historical evolution from segmentation to modern virtual memory systems.
Congratulations! You've mastered segmented address translation. You can now extract address components, validate accesses, compute physical addresses, and diagnose translation failures. This understanding is fundamental to operating systems, systems programming, and computer architecture.