有人可以解释一下这个直接组装的 x86 JMP 操作码吗?

发布于 2024-07-14 03:27:24 字数 992 浏览 14 评论 0原文

在学校我们一直使用引导程序来运行没有操作系统的独立程序。 我一直在研究这个程序,当启用保护模式时,通过直接将操作码和操作数组装为程序中的数据来执行远跳转。 这是针对 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.  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。

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

感谢您的关注!

At school we have been using a bootstrap program to run stand-alone programs without an operating system. I have been studying this program and when protected mode is enabled there is a far jump executed by directly assembling the opcode and operands as data within the program. This was for the GNU assembler:


         /* 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 */

First of all, why would one want to do this (instead of the instruction mnemonic)?

I have been looking at the Intel manuals, but am still a little confused by the code. Specifically in Volume 2A, page 3-549, there is a table of opcodes. The relevant entry:

EA *cp* JMP ptr16:32  Inv.  Valid  Jump far, absolute, address given in
operand

The actual opcode is obvious, but the the first byte, 0x66, has me confused. Referring to the table in the Intel manual, the cp apparently means that a 6 byte operand will follow. And obviously 6 bytes follow in the next two lines. 0x66 encodes an 'Operand-size override prefix'. What does this have to do with the cp in the table? I was expecting there to be some hex value for the cp, but instead there is this override prefix. Can someone please clear this up for me?

Here is a dump from od:

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

TARGET_ADDRESS was defined as 0x00010000.

I am also confused a bit by the significance of the last two bytes. However, that seems to be another question altogether. It is getting quite late, and I have been staring at code and the Intel manuals for hours, so I hope I got my point across.

Thanks for looking!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月棠 2024-07-21 03:27:24

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

The 0x66 indicates that the JMP (0xEA) refers to six bytes. The default is refering to 64K (16 bits) in real mode or to 32 bits in protected mode (if I recall well). Having it increased, it also includes the segment descriptor, the index of the segment either in the GDT or the LDT, which means, that this code is making what is traditionally called a "long jump": a jump that cross beyond segments in the x86 architecture. The segment, in this case, points to the second entry on the GDT. If you look before in that program, you'll likely see how the GDT is defined in terms of the segment starting address and length (look in the Intel manual to study the GDT and LDT tables, 32 bit entry describing each segment).

人心善变 2024-07-21 03:27:24

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

I run into this a bit. Some assemblers will only jump to a LABEL . In this case the person wants to make an absolute jump to a specific hard coded offset. jmp TARGET_ADDRESS won't work I am guessing, so they just put it as bytes to get around this issue.

海之角 2024-07-21 03:27:24

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

0x66 specifies operand size override of the current code segment size. Assuming that current code size is 16-bit, the new instruction pointer will be 32-bit, not 16-bit. If current code segment size is 32-bit, the 0x66 will render target instruction pointer as 16-bit. The current code size attribute depends on CS selector in use and its attributes loaded from GDT/LDT table. In real mode the code segment size is usually 16-bit except special cases of "unreal" mode.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文