【问题标题】:Meaning of REX.w prefix before AMD64 jmp (FF25)AMD64 jmp (FF25) 之前 REX.w 前缀的含义
【发布时间】:2016-04-22 08:25:16
【问题描述】:

在解决一个错误时,我发现两个 Win64 DLL 的导入跳转表之间存在差异。 kernel32.dll 的 64 位版本在其导入跳转表中使用普通的 FF25 jmp 指令。另一方面,advapi32.dll 的 64 位版本使用 48FF25,它表示 jmp 操作码之前的 REX.w=1 前缀。但是,两者似乎都有 32 位操作数指定 RIP+偏移地址。

这个特定操作码上的 REX.w 前缀有什么意义吗?

我不经常使用机器代码,所以请原谅任何事实错误。

【问题讨论】:

  • 我想你会发现它记录在英特尔文档中。
  • intel手册中没有列出,我手上的反汇编器也看不懂。我认为rex.w 只是被忽略了。

标签: winapi assembly x86-64


【解决方案1】:

REX.W 前缀被忽略。在 64 位模式下,FF /4 操作码始终具有 64 位操作数 (JMP r/m64),因此操作数大小更改前缀 (REX.W, 66) 无效。

出现此 REX.W 前缀的原因可能是为了符合 Microsoft 的 x64 调用约定关于展开的规则。跳转导入存根实际上是一个单指令函数,并且由于 Windows 上的异常是异步的,它们随时可能发生,执行此函数时可能会产生异常。微软放置了多个restrictions on instructions used at the start and end of functions。特别是该函数必须以仅包含某些指令的结尾结束。根据 MSDN 上的Kevin Frei's blog,如果最后一条指令是间接跳转,则它必须使用 REX.W 前缀:

另一个注意事项:如果最终的 jmp 不是 ip-relative jmp,而是间接的 jmp,它必须以 REX 前缀开头,以指示操作系统展开 跳转到函数之外的例程,否则, 操作系统假定它是跳转到同一函数内的不同位置。

使用REX.W之间的不一致可能是因为上面描述的这条规则与微软官方文档对最终JMP指令的要求并不完全一致:

结语中只允许使用 jmp 语句的子集。这些都是 仅具有 ModRM 内存引用的 jmps 类,其中 ModRM mod 字段值 00。在带有 ModRM mod 字段值 01 的结语中使用 jmps 或 10 被禁止。

请注意,由于这将排除不使用 ModR/M 编码的相关 JMP 指令,这是结束函数的最常见的 JMP 类型,所以我倾向于认为这是错误的官方文档.

导致不一致的其他可能原因是 Microsoft 的 unwinder 专门处理导入跳转存根,或者没有 REX.W 前缀的跳转存根是一个错误,并且在发生异常时会导致程序在极不可能的情况下终止在他们被处决的时候。

【讨论】:

  • 就是这个原因。 CoreClr 在github.com/dotnet/coreclr/blob/master/src/unwinder/amd64/… 有一份操作系统展开器的副本,您可以在其中查看堆栈展开器的工作原理。正如 Kevin 在他的博客中指出的那样,它确实会检查 REX 前缀。
  • 这在RtlVirtualUnwind function 的 SDK 文档中也有半记录,特别是在“备注”下,其中提供了堆栈展开代码识别的 x64 上的结尾标记的详尽列表.
猜你喜欢
  • 2018-03-14
  • 2019-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多