Is it safe to say that all segment registers under
Windows & Linux are set to zero? For instance,
if I temporarily had to use ESP or EBP as a
data pointer, I wouldn't need to prefix it with DS:,
would I?
Thanks.
Well... not exactly... They're set to a selector (zero would be an
invalid selector!), which references a descriptor - not all the same
one, but all have their "base" set to zero (and their "limit" set to
4G-1). There's an exception to that. Windows apparently uses fs for
"thread local storage". I think I've seen similar code in recent Linux.
I ASSume that this would contain a selector pointing to a descriptor
whose "base" was non-zero (and whose "limit" was smaller?), but I'm not
sure on that part.
> For instance,
> if I temporarily had to use ESP or EBP as a
> data pointer, I wouldn't need to prefix it with DS:,
> would I?
Right. Nor worry about the destination of the "string" instructions
being es:edi. You can safely assume that ds:, es:, ss:, and cs: refer to
the same memory. We can *almost* forget they exist... (ain't that nice?!)
Best,
Frank
> Noop wrote:
> > Hi all,
> >
> > Is it safe to say that all segment registers under
> > Windows & Linux are set to zero?
>
> Well... not exactly... They're set to a selector (zero would be an
> invalid selector!), which references a descriptor - not all the same
> one, but all have their "base" set to zero (and their "limit" set to
> 4G-1). There's an exception to that. Windows apparently uses fs for
> "thread local storage". I think I've seen similar code in recent
> Linux. I ASSume that this would contain a selector pointing to a
> descriptor whose "base" was non-zero (and whose "limit" was
> smaller?), but I'm not sure on that part.
>
In 64 bit mode isn;t it that all segment registers are set to zero,
except FS and GS? An if you want to set some other value
in FS and GS they automatically are set to zero?
All in all I would be interested if it is possible to set up
segments in Linux or Windows and program like before,
think segmented. It is said that design of HLL influences,
that you can;t do segments in 32 bit env.
As I understand there are two pointers LDT and GDT,
and they point to segments table , so when you load
segment register they represent index in that table.
Ok, GDT is protected by OS but LDT can be used
by application or is it either protected?
Greets!
Sometimes online sometimes not
they have a conceptual base of 0, but the segments are not themselves 0...
0 is a special reserved value for segments, and setting a segment to this
value makes it unusable (it can be compared to a NULL pointer).
think of it more this way (for 32-bit x86):
CS: ring=3, base=0, limit=4GB, type=32-bit code
DS: ring=3, base=0, limit=4GB, type=32-bit data
DS=ES=SS
segments are actually offsets into a table known as the GDT, which holds a
bunch of info WRT a particular segment (base, limit, type, ...). when
loading a segment register, this info is grabbed from this table.
now, FS and GS are special, in that they have a base!=0 amd typically a
small limit, and are used by OS's to refer to thread-local state
(thread-local vars, ...).
Win32 uses FS for a TIB/TEB structure.
Win64 uses GS for a TEB with a different layout.
Linux AFAIK uses GS but with a non-fixed layout (depends on OS version...).
in x86-64, CS/DS/ES/SS have to have a base of 0, and the limit is ignored.
FS and GS then are special in that they are the only segments which can
still have a base!=0.
I am not sure if valid, but I had heard some rumors of the possibility of
re-adding segment base/limit support to long-mode, but I am not certain as
to this (nor as to what exactly this would do to the GDT, though it may be
similar to what has happened to the IDT). but, I don't know...
They (the segment selectors loaded into segment registers) are almost
certainly not NULL in 64-bit mode in Windows and Linux...
> 0 is a special reserved value for segments, and setting a segment to this
> value makes it unusable (it can be compared to a NULL pointer).
...but they can be set to NULL selectors and be usable. AFAIR, in the
kernel mode only, though, but you can check the documentation for
conditions/details. AFAIR from testing, in 64-bit mode any loadable
selector (the restrictions are very very similar to non-64-bit
protected mode except now NULL selectors are OK too under certain
conditions) is usable for *all* accesses once the selector is loaded
(i.e. you can write through a code selector loaded into DS,ES,FS,GS or
a readable data segment selector).
Alex
Alexei please explain following from Intel manual , as I really
can;t interpret how 64 bit mode works.
"
2.2 MODES OF OPERATION
The IA-32 supports three operating modes and one quasi-operating mode:
• Protected mode — This is the native operating mode of the processor. It
provides a rich set of architectural features, flexibility, high performance and
backward compatibility to existing software base.
• Real-address mode — This operating mode provides the programming
environment of the Intel 8086 processor, with a few extensions (such as the
ability to switch to protected or system management mode).
• System management mode (SMM) — SMM is a standard architectural feature
in all IA-32 processors, beginning with the Intel386 SL processor. This mode
provides an operating system or executive with a transparent mechanism for
implementing power management and OEM differentiation features. SMM is
entered through activation of an external system interrupt pin (SMI#), which
generates a system management interrupt (SMI). In SMM, the processor
switches to a separate address space while saving the context of the currently
Vol. 3A 2-11
SYSTEM ARCHITECTURE OVERVIEW
running program or task. SMM-specific code may then be executed transparently.
Upon returning from SMM, the processor is placed back into its state prior to the
SMI.
• Virtual-8086 mode — In protected mode, the processor supports a quasioperating
mode known as virtual-8086 mode. This mode allows the processor
execute 8086 software in a protected, multitasking environment.
Intel 64 architecture supports all operating modes of IA-32 architecture and IA-32e
modes:
• IA-32e mode — In IA-32e mode, the processor supports two sub-modes:
compatibility mode and 64-bit mode. 64-bit mode provides 64-bit linear
addressing and support for physical address space larger than 64 GBytes.
Compatibility mode allows most legacy protected-mode applications to run
unchanged.
"
What is 32 e mode?
Then:
"
4.4.1.1 NULL Segment Checking in 64-bit Mode
In 64-bit mode, the processor does not perform runtime checking on NULL segment
selectors. The processor does not cause a #GP fault when an attempt is made to
access memory where the referenced segment register has a NULL segment
selector.
"
What does this means?
"
3.2.4 Segmentation in IA-32e Mode
In IA-32e mode of Intel 64 architecture, the effects of segmentation depend on
whether the processor is running in compatibility mode or 64-bit mode. In compatibility
mode, segmentation functions just as it does using legacy 16-bit or 32-bit
protected mode semantics.
In 64-bit mode, segmentation is generally (but not completely) disabled, creating a
flat 64-bit linear-address space. The processor treats the segment base of CS, DS,
ES, SS as zero, creating a linear address that is equal to the effective address. The FS
and GS segments are exceptions. These segment registers (which hold the segment
base) can be used as an additional base registers in linear address calculations. They
facilitate addressing local data and certain operating system data structures.
Note that the processor does not perform segment limit checks at runtime in 64-bit
mode.
"
Finally:
"
3.4.4 Segment Loading Instructions in IA-32e Mode
Because ES, DS, and SS segment registers are not used in 64-bit mode, their fields
(base, limit, and attribute) in segment descriptor registers are ignored. Some forms
of segment load instructions are also invalid (for example, LDS, POP ES). Address
calculations that reference the ES, DS, or SS segments are treated as if the segment
base is zero.
The processor checks that all linear-address references are in canonical form instead
of performing limit checks. Mode switching does not change the contents of the
segment registers or the associated descriptor registers. These registers are also not
changed during 64-bit mode execution, unless explicit segment loads are performed.
In order to set up compatibility mode for an application, segment-load instructions
(MOV to Sreg, POP Sreg) work normally in 64-bit mode. An entry is read from the
system descriptor table (GDT or LDT) and is loaded in the hidden portion of the
segment descriptor register. The descriptor-register base, limit, and attribute fields
are all loaded. However, the contents of the data and stack segment selector and the
descriptor registers are ignored.
When FS and GS segment overrides are used in 64-bit mode, their respective base
addresses are used in the linear address calculation: (FS or GS).base + index +
displacement. FS.base and GS.base are then expanded to the full linear-address size
supported by the implementation. The resulting effective address calculation can
wrap across positive and negative addresses; the resulting linear address must be
canonical.
In 64-bit mode, memory accesses using FS-segment and GS-segment overrides are
not checked for a runtime limit nor subjected to attribute-checking. Normal segment
loads (MOV to Sreg and POP Sreg) into FS and GS load a standard 32-bit base value
in the hidden portion of the segment descriptor register. The base address bits above
the standard 32 bits are cleared to 0 to allow consistency for implementations that
use less than 64 bits.
The hidden descriptor register fields for FS.base and GS.base are physically mapped
to MSRs in order to load all address bits supported by a 64-bit implementation. Software
with CPL = 0 (privileged software) can load all supported linear-address bits
into FS.base or GS.base using WRMSR. Addresses written into the 64-bit FS.base and
GS.base registers must be in canonical form. A WRMSR instruction that attempts to
write a non-canonical address to those registers causes a #GP fault.
When in compatibility mode, FS and GS overrides operate as defined by 32-bit mode
behavior regardless of the value loaded into the upper 32 linear-address bits of the
hidden descriptor register base field. Compatibility mode ignores the upper 32 bits
when calculating an effective address.
A new 64-bit mode instruction, SWAPGS, can be used to load GS base. SWAPGS
exchanges the kernel data structure pointer from the IA32_KernelGSbase MSR with
the GS base register. The kernel can then use the GS prefix on normal memory references
to access the kernel data structures. An attempt to write a non-canonical value
(using WRMSR) to the IA32_KernelGSBase MSR causes a #GP fault.
"
This is beat of confusing to me.
Thanks,
Branimir
Once you've switched the CPU into 64-bit mode, only the following
modes are available:
64-bit
16/32-bit protected (compatibility)
This mode subset is what 32e is. What's different in it is memory,
interrupt and task management, which are done the 64-bit way (you
don't have old-style page tables for non-64-bit modes, task switching
no longer works, etc).
> Then:
> "
> 4.4.1.1 NULL Segment Checking in 64-bit Mode
> In 64-bit mode, the processor does not perform runtime checking on NULL segment
> selectors. The processor does not cause a #GP fault when an attempt is made to
> access memory where the referenced segment register has a NULL segment
> selector.
> "
>
> What does this means?
That means if you manage to load a NULL selector into a segment
register in 64-bit mode (this is relaxed in 64-bit mode), there will
be no further checks on the selector/segment type after the segment
register load and you will be able to access code/data through it
(which is impossible in 16/32-bit protected mode).
What exactly is confusing in the above text?
It clearly states that in 64-bit mode:
- segment bases for CS,DS,ES and SS are always 0 (GDT/LDT base fields
are ignored or required to be 0)
- segment bases for FS and GS are taken from the appropriate MSRs
- there are no segment limit checks (except for the offsets being
canonical (that is, limited in number of bits that can be either 0 or
1 (there's some MSR register that says how many bits are available for
the virtual address, which is not 64, but fewer, something like 48)
and being properly sign-extended))
- SWAPGS swaps GS base (previously loaded from GS.Base MSR) with
IA32_KernelGSbase MSR to make it easier/faster to save/restore GS base
- segmentation for 16/32-bit protected (compatibility) mode remains
the same
Alex
>
> What exactly is confusing in the above text?
> It clearly states that in 64-bit mode:
> - segment bases for CS,DS,ES and SS are always 0 (GDT/LDT base fields
> are ignored or required to be 0)
> - segment bases for FS and GS are taken from the appropriate MSRs
> - there are no segment limit checks (except for the offsets being
> canonical (that is, limited in number of bits that can be either 0 or
> 1 (there's some MSR register that says how many bits are available for
> the virtual address, which is not 64, but fewer, something like 48)
> and being properly sign-extended))
> - SWAPGS swaps GS base (previously loaded from GS.Base MSR) with
> IA32_KernelGSbase MSR to make it easier/faster to save/restore GS base
> - segmentation for 16/32-bit protected (compatibility) mode remains
> the same
>
> Alex
Thanks, they should employ you to write manuals ;)
Greets!
Actually, I think that's not in an MSR, but rather returned by CPUID.
Alex
According to the perceived quality of their documents (mistakes/typos
per page or their total number per volume) as function of time,
*IMHO*, they've recently been doing everything to make their manuals
more obscure and to cover up bugs. In that case I doubt they want to
employ me or anyone else at least as knowledgeable to diligently write
or correct these manuals. :)
The good thing is, you can cross-check many things with AMD manuals or
simply try something out and see what happens. That's how I've been
coping with the ambiguity of the x86 docs. And that's how I know many
things I know and so can you. :)
Alex
<--
According to the perceived quality of their documents (mistakes/typos
per page or their total number per volume) as function of time,
*IMHO*, they've recently been doing everything to make their manuals
more obscure and to cover up bugs. In that case I doubt they want to
employ me or anyone else at least as knowledgeable to diligently write
or correct these manuals. :)
The good thing is, you can cross-check many things with AMD manuals or
simply try something out and see what happens. That's how I've been
coping with the ambiguity of the x86 docs. And that's how I know many
things I know and so can you. :)
-->
yep, although in a few cases I have seen the same issues in both docs, and
to me this has seemed suspect...
generally agreed though.
Yep. Obviously, they don't even read their own IA-32 documentation.
Maybe they have something better for internal usage, dunno. Until very
recently, their CR0.WP bit description looked like the person who
wrote it was smoking something heavy - one half confusing, the other
half wrong. They eventually fixed it, though (after what, 15 years of
CR0.WP being around?).
My current favorite is the "privileged software exception". Vol. 3B is
chock-full of references to this mysterious exception type, but *what*
it is is never explained anywhere. The horrible truth may be that
Intel has yet to invent exceptions that belong to this type...
Well it certainly has some mysterious aspects!
First, it’s not an exception in the traditional sense at all: Rather
it's part of the control of how an exception/interrupt is *injected*
*into* a virtual machine by a hypervisor. For example, if you were
injecting a (virtual) external interrupt (let's say from the virtual
serial port), you'd do a VM-Entry and specify a type of "External
Interrupt" (along with the interrupt vector number and some other
stuff).
There are distinctions because the way that x86 handles different
types of interrupts/exceptions varies. For example, injecting an
“Overflow” interrupt (a trap, rather than a fault) requires that the
saved EIP point to the instruction *after* the INTO instruction that
generated the trap, whereas a page fault requires that the saved EIP
point to the faulting instruction (and it also stores a parameter on
the stack detailing the page fault).
Privileged software exceptions don’t appear to be related to any
particular x86 events (basically everything you might want to inject
is covered under one of the other categories). I pretty sure they’re
intended to provide a fast way to communicate from the VMM to a guest
OS with an interrupt-like mechanism. Of course you *could* just
inject an external interrupt, but that probably ends up requiring
various trips through the APIC emulators, and all sorts of nasty guest
OS code. The privileged software exceptions are something of a
hybrid, in that they’re more like the response to an INTx (but without
the privilege checking).
FWIW, Xen doesn’t use them at all, and some of the VMM-to-guest
interfaces he provides are, in fact, done via something looking
somewhat like a traditional I/O device.