In x86, when you want to access a memory address, you would specify an address that would be translated into a memory address through two stages: segmentation, and paging:
But is segmentation also used in x64? (I think it is not used, but I am not sure if it is not used in all cases, or are there some cases where it is used).
For the purpose of the picture you posted, segmentation is only used when the addressing mode uses the registers fs
or gs
(because these were being actively configured with a non zero base by Linux and Windows).
Segmentation works remarkably different in protected (32-bit) and long (64-bit) mode with respect to real mode (16-bit).
Particularly, a segment is not just a base and a limit but a set of attributes loaded from two tables (GDT or LDT) filled with segment descriptors.
For all segment registers but fs
and gs
the CPU ignores the base when computing the effective address (a.k.a. offset), an action that has the same effect as using 0 for the base.
Furthermore, for all the segment registers, it performs no limit check (however the linear address must be canonical).
It's worth saying that when loading a segment register the CPU still loads all the information from the segment descriptor in the GDT/LDT (including the base and the limit).
This is necessary to support compatibility mode (32-bit semantic), in fact the segment descriptors for code and data have not been expanded to have a 64-bit base and limit (after the effect of the granularity bit).
That's why the bases for fs
and gs
are specified separately in two 64-bit MSR registers.
The Intel SDM claims that the fs
and gs
bases are physically mapped to these 64-bit MSRs, it's not clear to me then if loading fs
and gs
from a segment descriptor will also set the MSRs. That should be the case but I haven't investigated (EDIT prl did and confirmed this is the case).
While bases and limits are gone but for a pair of registers, all other checks remains.
Particularly the DPL (the privilege specified in a descriptor) of the code segment sets the CPL (the privilege of the executing code).
The stack segment must have a DPL equals to the CPL (and so also is for another privilege called RPL).cs
must still be loaded with a code segment, readable and writable attributes are still enforced (possibly but for fs
and gs
).
All the system descriptors remains (call gates, TSS selectors and so on).
So all the protection mechanisms (but for the limit) of the segmentation remains, so I won't say it is not used.
Actually, the segmentation machinery is deeply integrated in the way the CPU enter a new mode of execution (with protection), it's impossible not to use it.
Of course, the linear address translation is not using it anymore (but for the usual two fs
and gs
), and exactly due to these registers I think it's better to still keep your picture in mind.
There are a few exceptions to the protections listed above:
fs
and gs
have no attribute check (as per Intel SDM), this could mean that it would be possible to load a non-readable code segment and read from it or a non writable data segment and write to it. This would contradict the SDM which also states that "Segment selectors for code segments that are not readable or for system segments cannot be loaded into data-segment registers (DS, ES, FS, and GS)" or more generally "No instruction may write into a data segment if it is not writable. No instruction may read an executable segment unless the readable flag is set.".
The readable bit of code segment is not functioning normally. Literally from the SDM: "the remaining fields function normally (except for the readable bit in the type field)" but then it doesn't go into telling what it exactly does instead (presumably nothing, it is ignored).
Null selectors are always valid. This is exploited during a privilege changing control transfer (which changed with the new 64-bit mode).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With