在学校,我们一直使用 Bootstrap 来运行没有操作系统的独立程序。我一直在研究这个程序,当启用保护模式时,通过直接将操作码和操作数组装为程序中的数据来执行远跳转。这是针对 GNU 汇编器的:
/* this code immediately follows the setting of the PE flag in CR0 */<p></p>
<pre><code>.byte 0x66, 0xEA
.long TARGET_ADDRESS
.word 0x0010 /* descriptor #2, GDT, RPL=0 */
</code></pre>
<p></p>
首先,为什么要这样做(而不是指令助记符)?
我一直在查看英特尔手册,但对代码仍然有点困惑。具体来说,在第 2A 卷第 3-549 页中,有一个操作码表。相关条目:
EA *cp* JMP ptr16:32 Inv. Valid Jump far, absolute, address given in operand
实际的操作码很明显,但第一个字节 0x66 让我感到困惑。引用Intel手册中的表格,cp显然意味着后面将有一个6字节的操作数。显然接下来的两行是 6 个字节。 0x66 编码“操作数大小覆盖前缀”。这和表中的cp有什么关系呢?我原以为 cp 有一些十六进制值,但有这个覆盖前缀。有人可以帮我解决这个问题吗?
这是来自 od 的转储:
c022 **ea66 0000 0001 0010** ba52 03f2 c030
TARGET_ADDRESS 被定义为 0x00010000。
我也对最后两个字节的重要性感到有点困惑。然而,这似乎完全是另一个问题。现在已经很晚了,我已经盯着代码和英特尔手册几个小时了,所以我希望我能明白我的观点。
感谢您的浏览!
最佳答案
0x66 表示 JMP (0xEA) 指的是 6 个字节。默认值是指实模式下的 64K(16 位)或保护模式下的 32 位(如果我没记错的话)。增加它后,它还包括段描述符,即 GDT 或 LDT 中段的索引,这意味着该代码正在执行传统上称为“长跳转”的操作:跨越 GDT 中的段的跳转。 x86架构。在本例中,该段指向 GDT 上的第二个条目。如果您之前查看过该程序,您可能会看到 GDT 是如何根据段起始地址和长度定义的(查看 Intel 手册以研究 GDT 和 LDT 表,描述每个段的 32 位条目)。
关于assembly - 有人可以解释一下这个直接组装的 x86 JMP 操作码吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/545093/