Bochs GDT 段限制以十六进制左移 3 次并添加 0xFFF。这是正常的吗?

Bochs GDT Segment limit is shifted left 3 times in hex and 0xFFF is added. Is this normal?

我目前正在为我的引导加载程序设置 GDT。我有 3 (4) 个细分市场:

这是我设置 GDT 的代码:

  7 ; GDT null segment
  8 gdt_null:
  9     dq 0x00
 10 
 11 ; GDT code segment (4GB)
 12 gdt_code:
 13     dw 0xFFFF
 14     dw 0x00
 15     db 0x00
 16     db 10011010b
 17     db 11001111b
 18     db 0x00
 19 
 20 ; GDT data segment (4GB)
 21 gdt_data:
 22     dw 0xFFFF
 23     dw 0x00
 24     db 0x00
 25     db 10010010b
 26     db 11001111b
 27     db 0x00                                                                                          
 28 
 29 ; Extra segmet for stack
 30 ; Preventing bufferoverflows from stack could write into other data
 31 ; Size is 1M (0x100 * 4kb) startting from base 7e00 (512 bytes after 7c00)
 32 gdt_stack:
 33     dw 0x0100
 34     dw 0x7e00
 35     db 0x00
 36     db 10010010b
 37     db 11001000b
 38     db 0x00

但是当我将二进制文件加载到 bochs 中时,它给出了以下结果:

字节完全按照我定义的方式加载到内存中:

这里我意识到0xFFF每次都添加到一个段。是因为我用了4kb的粒度吗?

当我选择 0xFF 作为 4kb 粒度的大小时,这将扩展为 0xFFFFF,所以我只能使段 1mb - 1 字节大?

是的,因为你在GDT条目中使用了4kb的粒度。来自 Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 3A 关于 5.3 限制检查:

When the G flag is clear (byte granularity), the effective limit is the value of the 20-bit limit field in the segment descriptor. Here, the limit ranges from 0 to FFFFFH (1 MByte). When the G flag is set (4-KByte page granularity), the processor scales the value in the limit field by a factor of 2^12 (4 KBytes). In this case, the effective limit ranges from FFFH (4 KBytes) to FFFFFFFFH (4 GBytes). Note that when scaling is used (G flag is set), the lower 12 bits of a segment offset (address) are not checked against the limit; for example, note that if the segment limit is 0, offsets 0 through FFFH are still valid.

来自 Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2ALSL 指令描述了所使用的机制并描述了您在 BOCHS 中看到的行为:

The segment limit is a 20-bit value contained in bytes 0 and 1 and in the first 4 bits of byte 6 of the segment descriptor. If the descriptor has a byte granular segment limit (the granularity flag is set to 0), the destination operand is loaded with a byte granular value (byte limit). If the descriptor has a page granular segment limit (the granularity flag is set to 1), the LSL instruction will translate the page granular limit (page limit) into a byte limit before loading it into the destination operand. The translation is performed by shifting the 20-bit “raw” limit left 12 bits and filling the low-order 12 bits with 1s.

你问了这个问题当我选择 0xFF 作为 4kb 粒度的大小时,这将扩展到 0xFFFFF,所以我只能使段 1mb - 1 字节大?。对于页面粒度,0xFF 段限制向左移动 12 位产生 0xFF000,低 12 位设置为 1。结果是 0xFFFFF 字节的实际限制。此限制允许寻址从指定基数开始的 0 到 0xFFFFF(含)的完整 1MiB 内存。如果您希望段具有特定的字节大小(介于 0x00000 和 0xFFFFF 之间),您可以使用字节粒度。可以使用不同的粒度定义描述符。