I'm trying to understand how segmentation works under x86-64. From what I see, it's mostly disabled, but not entirely. It looks like GS and FS registers are still using it.

So I was reviewing the structure of the segment descriptor in Windows 7 x64 kernel using WinDbg. Also so that not to crash the OS right away, I decided to play with a segment that doesn't use segmentation. Say SS register:

enter image description here

I then decided to modify it in raw memory and reload it via lgdt instruction. So I changed its lower 16 bits to 0x1234, as such (view in memory):

enter image description here

Or so I thought. When I ran the dg command, it showed the limit as 01234fff.

So I have two questions:

  1. Where does that fff come from in the limit reported by WinDbg? (shown in red in the first screenshot.)

  2. How can a 32-bit base in the segment descriptor encompass the entire 64-bit flat addressing range?

  • Segment 18h has its G (granularity) bit set, see Pg in the Gran column, which means that its segment limit is interpreted in 4-KByte units. 4K=1000h, minus one, gives the last addressable byte, the way segment limits are interpreted. As for the base, I'll let someone else answer it. I think base addresses are not used at all for code and data segments in x86-64. – ahmd0 Jun 28 '18 at 22:56
  • this is not really an RE question, stackoverflow may be a better fit for it... – Igor Skochinsky Jun 29 '18 at 0:53

Q1: In its manual "Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1"

Intel writes in the chapter "3.5.1 Segment Descriptor Tables":

"As with segments, the limit value is added to the base address to get the address of the last valid byte. A limit value of 0 results in exactly one valid byte. Because segment descriptors are always 8 bytes long, the GDT limit should always be one less than an integral multiple of eight (that is, 8N – 1)."

This could explain why the limit of 01234 is filled with fff, to satisfy that condition.

Q2: Same manual, chapter 3.4.1 "Logical Address Translation in IA-32e Mode":

"In 64-bit mode, the offset and base address of the segment are 64-bits instead of 32 bits. The linear address format is also 64 bits wide and is subject to the canonical form requirement. Each code segment descriptor provides an L bit. This bit allows a code segment to execute 64-bit code or legacy 32-bit code by code segment."

Although this answers the question in so far as in 64-bit mode there are no 32-bit base addresses in code segments (if I understands their manual correctly), I could nowhere find a picture corresponding to the Fig.3-8 on p.3-10 with 64-bit base addresses instead of 32-bit ones. The L-bit can be retrieved from that picture. It is not decoded in kd, however, in contrast to the other bits. The Flags value of 02xx of the first (Privilege Level 0, highest) and last (Privilege Level 3) code segments indicate the L-bit, and mark these code segments as 64 bit segments.

In the OP's upper screenshot the Base and Limit are indeed 64 bits, if I get this right. However, the mapping to the lower output is not clear to me. My knowledge of kd is limited, however.

enter image description here


A limit of 0x1234 was requested. The segment is paged, as indicated by the G (granularity) bit, and decoded by kd. The intel manual is not so very clear, IMO. If one goes into the manual "AMD64 Architecture Programmer’s Manual Volume 2: System Programming" , it writes on p.81:

"Setting the G bit to 1 indicates that the limit field is scaled by 4 Kbytes (4096 bytes)", also having mentioned in a comment.

This means the limit in bytes translates to 0x01234000. About the 0xfff I assume that the system acts in the same way as if entering 0 in the limit field. Quote AMD, p.81: "Setting the limit of 0 when G=1 [i.e. paging] inidcates a segment limit of 4095 [=0xfff]. In case the system acts in the same way with the request made here this would result in a limit value of 0x01234fff.

Another uncertainty remains, however. The given explanation assumes that WinDbg displays the limit in bytes and not in 4K pages.

  • Multiple of 8 would result in a 3 bit left shift, so if you subtract 1, it will be 7. How is it 0FFFh then? – c00000fd Jun 29 '18 at 2:30
  • Agree. I edited the answer with a more detailed explanation attempt, which would have not fitted in a comment. – josh Jun 29 '18 at 11:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.