8

在学校,我们一直在使用引导程序来运行没有操作系统的独立程序。我一直在研究这个程序,当启用保护模式时,通过直接将操作码和操作数组装为程序中的数据来执行远跳转。这是给 GNU 汇编器的:


         /* this code immediately follows the setting of the PE flag in CR0 */

.byte   0x66, 0xEA
.long   TARGET_ADDRESS
.word   0x0010          /* descriptor #2, GDT, RPL=0 */

首先,为什么要这样做(而不是指令助记符)?

我一直在查看英特尔手册,但仍然对代码感到有些困惑。特别是在第 2A 卷第 3-549 页中,有一个操作码表。相关条目:

EA *cp* JMP ptr16:32 Inv. 有效跳转远,绝对,地址
操作数

实际的操作码很明显,但第一个字节 0x66 让我感到困惑。参考英特尔手册中的表格, cp 显然意味着后面会跟着一个 6 字节的操作数。接下来的两行显然是 6 个字节。0x66 编码一个“操作数大小覆盖前缀”。这和表中的cp有什么关系?我原以为cp会有一些十六进制值,但是有这个覆盖前缀。有人可以帮我解决这个问题吗?

这是来自 od 的转储:

c022 **ea66 0000 0001 0010** ba52 03f2 c030

TARGET_ADDRESS 被定义为 0x00010000。

我也对最后两个字节的重要性感到困惑。然而,这似乎完全是另一个问题。现在已经很晚了,我已经盯着代码和英特尔手册看了好几个小时,所以我希望我能明白我的意思。

感谢您的关注!

4

3 回答 3

12

0x66 表示 JMP (0xEA) 指的是六个字节。默认值是指实模式下的 64K(16 位)或保护模式下的 32 位(如果我没记错的话)。增加它后,它还包括段描述符,即 GDT 或 LDT 中的段索引,这意味着该代码正在执行传统上所谓的“长跳转”:跨越x86 架构。在这种情况下,该段指向 GDT 上的第二个条目。如果您之前查看该程序,您可能会看到 GDT 是如何根据段起始地址和长度定义的(查看英特尔手册以研究 GDT 和 LDT 表,描述每个段的 32 位条目)。

于 2009-02-13T07:59:05.090 回答
2

我遇到了一点。一些汇编程序只会跳转到 LABEL 。在这种情况下,人们想要绝对跳转到特定的硬编码偏移量。我猜 jmp TARGET_ADDRESS 不起作用,所以他们只是把它作为字节来解决这个问题。

于 2009-05-14T16:58:29.153 回答
0

0x66 指定当前代码段大小的操作数大小覆盖。假设当前代码大小是 16 位,新指令指针将是 32 位,而不是 16 位。如果当前代码段大小为 32 位,则 0x66 会将目标指令指针呈现为 16 位。当前代码大小属性取决于使用的 CS 选择器及其从 GDT/LDT 表加载的属性。在实模式下,代码段大小通常为 16 位,“虚幻”模式的特殊情况除外。

于 2014-08-19T08:58:18.387 回答