1

I'm trying to understand the workings of the D flag in the code segment descriptor when used in the x86-64 code. It's set in the D/B bit 22 of the code segment descriptor as shown on this diagram:

enter image description here

The Intel documentation (from section 3.4.5 Segment Descriptors) states the following:

enter image description here

D/B (default operation size/default stack pointer size and/or upper bound) flag

Performs different functions depending on whether the segment descriptor is an executable code segment, an expand-down data segment, or a stack segment. (This flag should always be set to 1 for 32-bit code and data segments and to 0 for 16-bit code and data segments.)

• Executable code segment. The flag is called the D flag and it indicates the default length for effective addresses and operands referenced by instructions in the segment. If the flag is set, 32-bit addresses and 32-bit or 8-bit operands are assumed; if it is clear, 16-bit addresses and 16-bit or 8-bit operands are assumed. The instruction prefix 66H can be used to select an operand size other than the default, and the prefix 67H can be used select an address size other than the default.

So I'm trying to understand which x86-64 instructions does it affect and how?

PS. When I try to run some tests (in Windows kernel) by setting that bit on, the OS immediately triple faults.

MikeF
  • 1,021
  • 9
  • 29

1 Answers1

6

If L (long mode) is set for a code segment descriptor, D must be clear. The L=1 / D=1 combination is currently meaningless / reserved. Intel documents this nearby in the same document you were looking at.

If L is clear, then D selects between 16 and 32-bit mode. (i.e. the default operand / address size). And yes, 16-bit protected mode exists, but no, nobody uses it.


There are only 3 possibilities for default address/operand-size:

  • 16-bit modes (real, vm86, protected): default address and operand-size = 16-bit
  • 32-bit protected mode: default address and operand-size = 32-bit
  • 64-bit mode: default address size = 64-bit, default operand-size = 32-bit

There's no option to have 16x 64-bit registers but a default operand size of 16-bit or 64-bit. Or a default address size of 32-bit overrideable to 64.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Oh, so what I was doing by having the L bit set and by also setting the D bit was "illegal" and that is why I was getting a triple fault, correct? – MikeF Jul 13 '18 at 16:02
  • Hold on though. After reading the Intel documentation once again (the one that I showed above) -- why are they mentioning the `66H` and `67H` prefixes in the same paragraph where they discuss the `D` flag for the executable code? Those prefixes work only in the 64-bit long mode when the `L` flag is set in the code segment descriptor. So if the `D` flag has to be cleared in that case, why do they bring up those prefixes? That's the part that confuses me. – MikeF Jul 13 '18 at 19:27
  • 1
    @MikeF: No, it's REX prefixes that are long-mode only. Operand-size prefixes swap between 16 and 32-bit in 32-bit mode the same as in 64-bit mode, or the opposite way in 16-bit mode. (e.g. `add eax,eax` needs a 66H prefix in 16-bit mode, but not in 32 or 64.) Look at some assembler output for `add eax, [esi]` vs. `add ax, [si]` in 16 vs. 32 bit mode. (e.g. run `nasm -l` to make a listing that includes machine code) – Peter Cordes Jul 13 '18 at 23:09