我目前正在为我的引导程序设置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字节大吗?
答案 0 :(得分:2)
是的,这是因为您在GDT条目中使用了4kb的粒度。来自Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 3A中有关 5.3极限检查的
:清除G标志(字节粒度)时,有效限制为该段中20位限制字段的值 描述符。在此,限制范围是0到FFFFFH(1 MB)。 设置了G标志(4 KB页面粒度)后, 处理器将限制字段中的值缩放2 ^ 12(4 KB)。在这种情况下,有效极限范围 从FFFH(4 KB)到FFFFFFFFH(4 GB)。请注意,使用缩放比例(设置了G标志)时, 段偏移量(地址)不会根据限制进行检查;例如,请注意,如果细分限制为0, 偏移量0到FFFH仍然有效。
在Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A中, LSL 指令对使用的机制进行了描述,并描述了您在BOCHS中看到的行为:
段限制是一个20位的值,包含在该段的字节0和1中以及字节6的前4位中 描述符。如果描述符具有字节粒度段限制(粒度标志设置为0),则目标 操作数加载有字节粒度值(字节限制)。 如果描述符有页面细分范围限制( 粒度标志设置为1),LSL指令会将页面粒度限制(页面限制)转换为字节限制 在将其加载到目标操作数之前。 通过将20位“原始”限制向左移动12来执行翻译 位,并用1s填充低阶12位。
您问的问题当我选择0xFF时,粒度为4kb的大小会扩展为0xFFFFF,所以我只能将段设为1mb-1字节大吗?。使用页面粒度,将0xFF段限制左移12位,产生0xFF000,将低12位设置为1。结果是实际限制为0xFFFFF字节。此限制允许寻址完整的1MiB内存,从指定的基数开始,该内存为0到0xFFFFF(包括0)。如果您希望段具有特定的字节大小(介于0x00000和0xFFFFF之间),则可以使用字节粒度。可以使用不同的粒度定义描述符。