【发布时间】:2021-08-27 05:51:40
【问题描述】:
我在网上查了很多,每次只能找到GDT、LDT和IDT的尺寸。
这里我问的不是表格的大小,而是寄存器
的大小我知道 GDTR 是一个 64 位寄存器,但对其他寄存器一无所知。
【问题讨论】:
标签: x86 nasm cpu-architecture cpu-registers gdt
我在网上查了很多,每次只能找到GDT、LDT和IDT的尺寸。
这里我问的不是表格的大小,而是寄存器
的大小我知道 GDTR 是一个 64 位寄存器,但对其他寄存器一无所知。
【问题讨论】:
标签: x86 nasm cpu-architecture cpu-registers gdt
IDTR 也可以指向虚拟地址空间中的任何位置,因此显然它的基址也必须是 64 位的。 lidt 和 lgdt 采用相同的限制/基本结构格式,the pseudocode 表明它们在 64 位模式下这样做:
GDTR(Limit) ← SRC[0:15];
GDTR(Base) ← SRC[16:79];
限制(最大字节偏移)应被视为 GDTR / IDTR 的一部分。 documentation for sidt 也表示“存储 IDTR”,它存储的是相同的 2 + 8 字节结构,具有限制 + 基数。 (GDTR 在内部使用限制来检查段选择器,然后在 GDT 中查找它们,因此如果超过限制,您使用 lgdt 的地址的 64k 内的内存可以用于其他用途。)
似乎lidt / lgdt 不检查 GDT/IDT 基址是否为规范地址。文档说他们#GP(0) 如果内存地址采用非规范形式。 但我认为这是在谈论到达 10 字节内存操作数的寻址模式,而不是基地址。
(如果无法将non-canonical 地址放入GDTR 或IDTR,CPU 可以在内部仅存储重要的48 bits(或PML5 的57),从而将大小降低到6 + 2 = 8 个字节。并将符号扩展回 64 位作为sidt / sgdt 的一部分。但可能是可以通过 GDTR 往返任意 64 位值,只需确保 CPU 在输入有效地址之前不需要将 GDT 用于任何事情!)
lldt 的文档表明如果没有错误:
LDTR(SegmentSelector) ← SRC;
LDTR(SegmentDescriptor) ← GDTSegmentDescriptor;
这表示内部 LDTR 保留 16 位段选择器(ldtr 的实际操作数,例如 ldtr ax),以及加载选定的 GDT 条目并保留它。 GDT 条目是 8 个字节,但它可以将该条目解码为某种内部格式。 (可能不包括 type 字段,已经检查过了,需要是 type == LDT)
这意味着与 DS 或 SS 等段寄存器一样,如果您在运行 lldt 后更改 GDT 内容,则在您运行 lldt 时所选条目的基数/限制将继续适用。
再次,文档显示:
TaskRegister(SegmentSelector) ← SRC;
TaskRegister(SegmentDescriptor) ← TSSSegmentDescriptor;
与 LDTR 一样,您只能检索段选择器,而不是它存储的实际描述符。 str r/m16 和 sldt r/m16 只写一个 16 位目标操作数。
但实际的内部寄存器需要保存整个段描述符,而不是使用选择器重新索引当前 GDT。
【讨论】:
sidt 或sgtd 再次获得基础和限制。这总共是 2 + 8 = 10 个字节。所以是的,从这个意义上说,所有 10 个字节都可以访问。但是,只有基地址的低 6 个字节才能真正用作实际地址。 (或者 PML5 的低 57 位用于 57 位虚拟地址。)所以是的,基地址的高位实际上是无用的。不过,限制不是。