【问题标题】:Assembly CALL instruction, write faults?汇编 CALL 指令,写入错误?
【发布时间】:2011-09-21 13:13:31
【问题描述】:

在使用一些操作码反汇编的 linux 内核的页面错误处理程序中,我看到在 x86 架构上,CALL 或 0xE8 指令偶尔会引发写入错误,并且 ESI 和 EDI 都是 NULL。我想知道这是否有特定原因,因为 CALL 需要一个内存地址并将 EIP 更改为该值,并且不需要页面,因为它只是 EIP + relative_offset。如果有人能解决这个问题,将不胜感激。

【问题讨论】:

    标签: assembly linux-kernel kernel page-fault


    【解决方案1】:

    call 指令不会只是更改eip - 它还必须在更改之前将当前eip(更新为指向下一条指令)写入堆栈。 jmp-type 指令将按照您的建议执行,但 call 稍有不同,因为您稍后必须能够 ret 到当前位置。

    我不能确定,因为您没有向我们提供代码、完整的寄存器内容和页表( 会是一个问题的大量信息),但它似乎我最可能的解释是堆栈当前已关闭,需要重新购买。

    我最初想到的另一种可能性是您要跳转到的地址是非居民地址,但我认为这不会导致 call 本身出现故障。

    之后很快导致错误,因为 CPU 试图获取下一条指令,但我认为这不是你的描述所表明的,因为:

    • 您在call 上声明它正在发生;和
    • 那将是读取错误,而不是写入错误。

    esiedi 值不是问题 - 它们不参与 call

    【讨论】:

    • 因此,将 EIP 的值写入 RET 的堆栈似乎会导致这种情况。谢谢,我忘记了这一点,并认为由于堆栈将在内存中的位置,但由于它发生的很少,可能只是因为页面是 pte_none 并且必须扩展堆栈。
    • 它不会将 eip 写入堆栈。它将下一条指令的地址写入堆栈
    • @BlackBear,作为指令读取的一部分,IP 几乎肯定已经在 CPU 内部进行了更新,所以我在技术上声称是正确的 :-) 虽然,对于今天的大规模流水线 CPU,谁真的知道?我会调整答案以澄清。谢谢。
    • EIP 在写入堆栈之前会递增,因此据我所知应该是正确的。
    • EIP 是一个伪寄存器,实际上是在现代处理器中在管道解析回写时从管道状态调用时重建的。它是在调用“之前”还是“之后”发生的概念是没有意义的,因为大多数处理器都运行无序管道。
    猜你喜欢
    • 2014-12-31
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 1970-01-01
    • 2015-03-16
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多