0

In what I've learned so far about segmentation:

  • A virtual address contains a segment selector and an offset
  • The segment selector is used in conjunction with the GDTR to find the linear address of the segment descriptor
  • The segment descriptor houses information regarding the chosen segment, including its linear address

So, my questions are:

  • Based on what I've read, the virtual address is loaded into the segment register, and then somehow the translation is continued from there. What happens to the segment register after the virtual address has been loaded into it to obtain the descriptor?

  • As I understand it, the segment register also holds a cached value of the descriptor. How does this come into play during the translation process?

  • How does the system determine which segment register to load in, given that a segment selector can have up to 2^13 different values and there are only six primary registers?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
VortixDev
  • 965
  • 1
  • 10
  • 23
  • TL:DR: segmentation happens first to produce a linear virtual address, then everything else happens. The normal description assumes segment base = 0. – Peter Cordes Sep 07 '18 at 21:59
  • 1
    You tagged this question with x86-64...so beware that AMD ignored the segment registers (except FS and GS) when they defined the x86-64 architecture, so they don't actually function in the hardware anymore. I've heard it rumored that Microsoft is responsible for AMD keeing FS and GS, as these are integral to the way Windows tracks its process and thread structures. – lockcmpxchg8b Sep 08 '18 at 18:41
  • @lockcmpxchg8b: Linux uses FS for thread-local storage on x86-64, the same way it uses GS on i386. I'd be surprised if AMD considered neutering FS and GS to have base/limit fixed at 0/max in long mode the way they did for the classic segments, because their design for [`syscall`](http://felixcloutier.com/x86/SYSCALL.html) assumes that the kernel will use [`swapgs`](http://felixcloutier.com/x86/SWAPGS.html) and a load from `[gs: somewhere]` to find the kernel stack. But maybe that design came after they decided to keep segment bases. – Peter Cordes Sep 09 '18 at 03:09
  • (other segments still need valid descriptors, and the CS segment descriptor is how you put the CPU in long mode vs. compat vs. 16-bit protected mode.) re: design of `syscall`, see [Why does Windows64 use a different calling convention from all other OSes on x86-64?](https://stackoverflow.com/a/35619528) for links to mailing list archives about the design of `syscall` and `swapgs` (between AMD architects and Linux kernel devs, resulting in AMD adding a mask for RFLAGS and using R11 to save the old RFLAGS, so the kernel could make sure interrupts are disabled if it wants.) – Peter Cordes Sep 09 '18 at 03:11
  • @lockcmpxchg8b: also, it's hardly "doesn't function in hardware". Every x86-64 CPU is required to support legacy mode (32-bit kernel or other non-x86-64-aware code), and also compat mode (64-bit kernel, 32-bit user-space, using 64-bit page tables). I *think* non-zero bases for CS/DS/ES/SS still work in compat mode, but I'm not sure. They might not. But anyway, base=0 is special-cased on real hardware to have lower latency (for loads) than non-zero segment bases, even in pure 32-bit mode. The base-adding hardware is per load/store port AGU, not per segment register, so has to handle FS/GS. – Peter Cordes Sep 09 '18 at 03:20
  • Related: [What is the difference between linear ,physical ,logical and virtual memory address?](https://stackoverflow.com/q/62997536) – Peter Cordes Jan 23 '22 at 21:52

2 Answers2

6

The usual translation goes as follow:

 Logical address   -->   GDT -->  Linear address          --> Page tables --> Physical Address
(segment:offset)                 (segment base + offset)         

\______________________________________________________/ 
                  Virtual address                                     
             (can be either logical or linear)

If running in VMX non-root mode (i.e. in a VM) and EPT is enabled then:

 Logical address   -->   GDT -->  Linear address          --> Page tables --> Guest Physical Address --> EPT --> (System) Physical Address
(segment:offset)                 (segment base + offset)         

\______________________________________________________/                      \__________________________________________________________/
                  Virtual address                                                        Physical address
             (can be either logical or linear)

If an IOMMU is present (like the umbrella technology VT-d):

Logical address   -->   GDT -->  Linear address          --> Page tables --> Guest Physical Address --> EPT --> (System) Physical Address  -->  1 or 2 level translation --> (IO) Physical address
(segment:offset)                 (segment base + offset)         

\______________________________________________________/                     \___________________________________________________________________________________________________________________/
                  Virtual address                                                        Physical address
             (can be either logical or linear)

The MMIO can even perform the translation of the Guest Virtual Address or the Guest Physical Address (one of it's purposes is to reify the Virtual address of an application to the hardware and simplify the management of the plethora of address spaces encountered during the translation).

Note As Hadi Brais pointed out, the term "Virtual address" only designates a Linear address in the Intel and AMD manuals.
I find it more useful to label both the logical and the linear addresses as virtual because they are before the page translation step.


The segment register holds a segment selector that index a segment descriptor that is used to performs the security checks and get the segment base that is summed with the offset part of the logical address.
After that, it's done.

Every address specified at the instruction level is a logical address - requiring the lookup of the segment descriptor.
To avoid reading it from memory each time the memory is accessed by an instruction, the CPU caches it - otherwise that would be a performance killer.

The OS setup the segment registers based on what it need to do but it rarely need more that four segments anyway.

The primary intent for segmentation (in PM) was to fulfil process isolation by defining non overlapping segments for each program.
A program usually need only a stack segment, a data segment and a code segment - the other three are there to avoid saving/restoring the data segment back then when a segment max size was 64KiB (read: Real mode. fs and gs were added later though).

Today OSes use a flat model where there are only two segments (code and data/stack - this is a simplification, other segments are required) encompassing the whole address space, plus OS specifics segments for things like TLS or PEB/TEB.
So six segment registers are even more than it's needed, the 8192 entries of the GDT are there in case they are (if even) needed.

Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • 1
    The address translation process depends on the [operating mode](https://en.wikipedia.org/wiki/X86-64#Operating_modes). The segment descriptor cache is accessed instead of the GDT. The segmentation unit is part of the MMU. I think you meant the paging unit instead. Intel does not use in its manual the term "virtual address" but AMD uses it as a synonym to linear address. Process isolation is achieved not necessarily by making segments non-overlapping, but by having protection attributes per segment descriptor. – Hadi Brais Sep 07 '18 at 16:53
  • @HadiBrais Thanks for the points but I don't quite understand the nature of your comment? The question is asked in the context of PM and I also stated that the descriptor is cached (the "picture" represent the process in the theory). Virtual address is a quite used term, it is present in the manual (albeit a lot less then I though!) and in the optimisation manual. If two segments of two different apps overlap, and both apps can write to their segments, then they are not isolated. But again, we both know this :) You are right about the MMU, I should call it "page tables" – Margaret Bloom Sep 07 '18 at 21:02
  • 2
    Yeah the Intel optimization manual uses the term virtual address as a synonym to linear address. But my point was your picture seems to indicate that a virtual address is either a logical address or a linear address. This is sometimes the definition used in some textbooks and papers, but Intel and AMD do not use that definition. I thought the picture is supposed to reflect what happens in reality because the MMU I think you used it to refer to the TLB caches. That's why I said "GDT" should be replaced by the descriptor cache. That was a little confusing to me. – Hadi Brais Sep 07 '18 at 21:14
  • But now that you changed the MMU to page tables, it is consistent with using the GDT instead of the descriptor caches. So I guess it's fine now if that was your intention. – Hadi Brais Sep 07 '18 at 21:16
  • @HadiBrais Ah, I got it. Yes, maybe Virtual address should only be under only the linear address part. But again, I like to consider the terms Virtual and Physical as attributes. I'll add a note. Thank you very much for the good point! – Margaret Bloom Sep 07 '18 at 21:21
  • "logical address" does have a formal synonym: far pointer. The offset part of the logical address has two formal synonyms: near pointer and effective address. All of the synonyms are used in the Intel manual because it's fun I guess :) – Hadi Brais Sep 07 '18 at 21:27
  • Thanks for your answer! I'm still a bit foggy on how the segment registers are called to action. You mentioned that the OS sorts out the registers, but how does it tell instructions like MOV which register to check for any logical address operands? – VortixDev Sep 07 '18 at 22:36
  • @VortixDev With `mov` do you mean a move to a segment register (e.g. `mov ds, ax`) or a load/store (e.g. `mov eax, DWORD [...]`)? The OS sets the segments so to make an user application unprivileged. The code generated by the compiler than almost always never use a segment override. – Margaret Bloom Sep 08 '18 at 07:19
  • @MargaretBloom I mean load/store: what mechanism does the CPU provide to allow the OS to select the register it goes into? – VortixDev Sep 08 '18 at 14:38
  • 1
    @VortixDev Segment override. You tell which segment to use: `mov eax, DWORD [cs:label]` uses `CS` instead of the default `DS`, for example. Most loads/stores uses `DS` implicitly, but not all (es: when `r/e/bp` is used as a base or for strings instructions). – Margaret Bloom Sep 08 '18 at 23:34
  • Correction to the previous comment, SS: is the default segment base when R/E or RBP/EBP/BP is used as a base (or for the stack pointer, by instructions like push/pop, so SS:SP can be accessed, but only implicitly, not via an addressing mode with 16-bit address-size). ES:(E)DI is only used implicitly for some string instructions. – Peter Cordes Mar 20 '21 at 10:06
-1

For question 1: Well until the next virtual/logical address is loaded to the segment register, the current selector will be present.(no change, holds the same virtual address).

For question 2: Initially, Segmentation process takes place (i.e. conversion of Virtual address to 32-bit linear address).

First, 16-bit selector will be loaded to a segment register. This 16-bit Selector contains (13-bit descriptor number,1-bit Table Index, 2-bit RPL[Requested Privilege Level]).

Now the 32-bit Base address of the GDT/LDT (GDT if TI=0) from GDTR/LDTR is added with the 13-bit pointer and points to a Descriptor in the respective GDT?LDT.

A Descriptor is a 8-byte entry that contains 32-bit base address of a Memory segment, Access Rights and Limits/length/size of the Memory segment.

Now all the 3 entities mentioned above are copied to the programmer invisible cache register part of the selected segment register.

This 32-bit base address from the cache is added with 32-bit offset from Virtual or logical address to form Linear address. This is used as physical address if paging is disabled, else, page translation is done to obtain the physical address of a segment in memory segment.

For question 3:

It really doesn't matter a lot because the bits in 8-bit Access rights in a descriptor specifies the use of a memory segment as code/data/stack/extra segments.Access rights in a descriptor

  • For question 1: You don't load a virtual address into a segment *register*; you load a segment *selector* which indexes a GDT entry. That entry contains a linear base address which is loaded into the hidden segment descriptor, as you later describe. (It's not really a cache; it latches whatever the last value was and never refreshes itself from the GDT on its own, although it is common to refer to the internal segment state as a "descriptor cache".) – Peter Cordes Jan 01 '22 at 15:01
  • *added with 32-bit offset from Virtual or logical address* - I don't think that terminology is accurate. A logical address is a full seg:off pair, like `ds:edi`. A virtual address is a linear address. The offset part of a seg:off logical address is the "**effective address**". In an addressing-mode like `[eax + ecx]` (with implicit DS segment), `eax+ecx` is the offset, DS base is the base, `ds_base + eax + ecx` is the linear virtual address. See [What is the difference between linear ,physical ,logical and virtual memory address?](https://stackoverflow.com/a/62998232) – Peter Cordes Jan 01 '22 at 15:05
  • Also [What is an effective address?](https://stackoverflow.com/q/36704481) re: that term, also sourcing its definition in Intel's manuals. – Peter Cordes Jan 01 '22 at 15:10
  • If paging is disabled, there are no virtual addresses anywhere during translation from logical to linear = physical. This could be a good answer if you used the right names for different kinds of addresses, but using mixed up terminology in several places is likely to confuse beginners when they read anything else about x86 memory addressing. – Peter Cordes Jan 01 '22 at 15:21