有人可以解释这种直接组装86 JMP的操作码?
-
23-08-2019 - |
题
在学校里,我们一直在使用引导程序,而无需操作系统独立运行的程序。我一直在研究这个方案,并保护在启用模式有直接组装操作码和操作数的程序中的数据执行的远跳转。这是用于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,有我感到困惑。参照在英特尔手册该表中,CP显然意味着一个6字节的操作数将遵循。很显然6个字节按照接下来的两行。 0x66编码“操作数大小覆盖前缀”。这是什么都在表中的CP办?我原以为那里是为CP一些十六进制值,而是有这个覆盖前缀。有人可以请清除此为我?
下面是从OD转储:
c022 **ea66 0000 0001 0010** ba52 03f2 c030
TARGET_ADDRESS被定义为0x00010000在
我也由最后的两个字节的意义混淆了一下。然而,这似乎是另一个问题完全。这是已经非常晚了,我已经在代码和英特尔手册小时一直盯着,所以我希望我在我的点。
感谢您看!
解决方案
在0x66指示JMP(0xEA)指的是六个字节。默认值是指的在实模式,或者在保护模式下的32位64K(16位)(如果我记得好)。有了它增加,它也包括段描述,无论是在GDT或LDT,这意味着该段的指数,这个代码是使什么是传统上被称为“长跳”:一个跳跃,在交叉超越段x86架构。段,在这种情况下,指出在GDT第二个条目。如果您在该程序前,你可能会看到GDT是如何起始地址和长度段来定义的(看看英特尔手册学习GDT和LDT表,32位条目描述每个段)。
其他提示
我碰上这一点。有些汇编只会跳转到一个标签。在这种情况下,人要做出一个绝对跳转到一个特定的硬编码后的偏移。 JMP TARGET_ADDRESS将无法正常工作,我猜,所以他们只是把它作为一个字节来解决这个问题。
0x66指定当前代码段大小的操作数尺寸替换。假设当前的代码尺寸是16位,新指令指针将是32位,而不是16位。如果当前代码段的大小是32位,则0x66将渲染目标指令指针为16位。当前代码大小属性依赖于CS选择器在使用中并且从GDT / LDT表中加载其属性。在实模式下的代码段的大小通常为16位的除外“虚幻”模式的特殊情况。