Β§16.1–16.2Segmentation: Generalized Base/Bounds … Which Segment Are We Referring To?

Part I OSTEP pp. 155–158 Β· ~7 min read

  • segmentation
  • segment
  • sparse address space

Base and bounds relocated the whole address space as one slab. Look again at what that slab mostly contains:

Figure 16.1: An Address Space (Again) β€” 16KB, and mostly hole
Program Code β“˜0KB(free) β“˜2KBHeap β–Ύ β“˜β–Ό4KB(free) β€” the big middle β“˜7KBStack β–΄ β“˜β–²14KB16KB

click a region marked β“˜ for details

The space between stack and heap is not being used β€” yet it occupies physical memory anyway when the whole space is relocated. One base/bounds pair is wasteful, and it can’t even run a program whose address space exceeds physical memory.

The Crux: How To Support A Large Address Space

How do we support a large address space with (potentially) a lot of free space between the stack and the heap? A 32-bit space is 4GB; a typical program touches megabytes β€” yet base/bounds demands the entire space be resident.

16.1 Segmentation: Generalized Base/Bounds

The fix β€” dating to the very early 1960s β€” is segmentation : instead of one base/bounds pair in the MMU , have one per logical segment. A segment is just a contiguous portion of the address space of a particular length; our canonical space has three β€” code, heap, and stack. Now each can be placed independently in physical memory:

Figure 16.2: Placing Segments In Physical Memory β€” 64KB, only used bytes allocated
Operating System β“˜0KB(not in use)16KBβ–²26KB(not in use)28KB32KBHeap β–Ύ β“˜β–Ό34KB(not in use) β“˜37KB64KB

click a region marked β“˜ for details

Only used memory gets physical space, so huge, mostly-empty ( sparse ) address spaces become affordable. The hardware is exactly what you’d guess: three base/bounds pairs (Figure 16.3 β€” the register table under the translator below), where each size register plays the old bounds role.

Translation, per segment. Virtual address 100 sits in the code segment: the hardware adds it to code’s base β€” 100 + 32KB = 32868 β€” checks 100 < 2KB βœ“, and issues the reference. But virtual address 4200 (in the heap) sets a trap: naΓ―vely adding 4200 to the heap base 34KB gives 39016 β€” the wrong address. We must first extract the offset into the heap: the heap begins at virtual 4KB, so 4200 βˆ’ 4096 = 104, and 34KB + 104 = 34920. And a reference to 7KB or beyond β€” past the end of the heap? Out of bounds, trap, likely termination. Try all of them:

Figures 16.3 + 16.4: the segment registers β€” and every translation in the chapter, live. Click a preset or type any 14-bit address.

virtual address

100

00000001100100

β†’

MMU (segmentation)

1. top 2 bits = 00 β†’ Code

2. offset = VA & 0xFFF = 100

3. bounds:Β 100 < 2048 βœ“

4. PA = 32 KB (32768) + 100 = 32868

β†’

physical address

32868

SegmentselectorBaseSizeGrows positive?
Code β—€0032 KB (32768)2 KB (2048)1
Heap0134 KB (34816)3 KB (3072)1
Stack1128 KB (28672)2 KB (2048)0 (backwards)

The tour: 100 β†’ code’s byte 100 β†’ 32868. 4200 β†’ heap byte 104 β†’ 34920. 3000 β†’ code’s quadrant but past its 2KB size β†’ fault (the hole between segments!). 7168 (7KB) β†’ one byte past the heap β†’ the book’s famous violation. 9000 β†’ selector 10, which no segment backs. 15360 (15KB) β†’ the stack, which grows BACKWARDS β€” the negative-offset trick is the next page’s business, but the answer (27KB) is already right.

Aside: The Segmentation Fault

The term segmentation fault (or violation) arises from exactly this: a memory access on a segmented machine to an illegal address. Humorously, the term persists even on machines with no segmentation support at all. Or not so humorously, if you can’t figure out why your code keeps faulting.

16.2 Which Segment Are We Referring To?

How does the hardware know an address’s segment, and its offset within it? The common explicit approach (used by VAX/VMS): chop the address space by the top few bits of the virtual address. Three segments need two bits; our 14-bit address splits like this β€” here’s 4200:

The 14-bit virtual address 4200: top two bits select the segment, bottom twelve are the offset

13012111010090807061514031201000
Segment
01 = heap
Offset β€” 0000 0110 1000 = 0x068 = 104

Selector 00 β†’ use code’s base/bounds; 01 β†’ heap; 11 β†’ stack. The bottom 12 bits are the offset β€” no subtraction needed β€” and the offset eases the bounds check too: just compare it against the segment’s size. If base and bounds were arrays indexed by segment, the hardware would do:

// get top 2 bits of 14-bit VA
Segment = (VirtualAddress & SEG_MASK) >> SEG_SHIFT
// now get offset
Offset  = VirtualAddress & OFFSET_MASK
if (Offset >= Bounds[Segment])
    RaiseException(PROTECTION_FAULT)
else
    PhysAddr = Base[Segment] + Offset
    Register = AccessMemory(PhysAddr)

For our example: SEG_MASK = 0x3000, SEG_SHIFT = 12, OFFSET_MASK = 0xFFF. Watch the same arithmetic run in the translator above β€” the binary readout under the virtual address is this exact split.

Two costs come bundled with the convenience. With three segments and two bits, one selector pattern (10) backs no segment β€” a quarter of the virtual space, gone (some systems merged code into the heap’s segment and spent only one bit). And each segment gets a hard maximum size β€” here 4KB, a 16KB space chopped into four β€” so a heap or stack that wants to grow beyond it is out of luck.

There are other ways: in the implicit approach, the hardware infers the segment from how the address was formed β€” generated by the program counter? code segment. Based off the stack or base pointer? stack. Anything else? heap.

But wait β€” preset 15360 above already whispered it: the stack doesn’t even grow the same direction as everything else. That takes one more bit of hardware, next.

Check yourself

1.Why is one base-and-bounds pair for the whole address space wasteful β€” and what exactly does segmentation change?

2.The heap's base register holds 34KB. Translate virtual address 4200 (the heap begins at virtual 4KB).

3.In the explicit approach with a 14-bit virtual address and 2 selector bits, which costs come bundled with the convenience?

4.A process references virtual address 3000 β€” inside its 16KB address space, in the gap after the 2KB code segment and before the heap begins at 4KB. What happens?

5.So where does the dreaded term 'segmentation fault' actually come from?

5 questions