【问题标题】:Why do assembly call address have 0xFBFFFFFF added to them?为什么程序集调用地址添加了 0xFBFFFFFF?
【发布时间】:2012-08-26 01:11:11
【问题描述】:

好的,我正在为我正在开发的操作系统编写汇编程序。我对所有 mov 指令都有很好的了解,现在我想实现像 call 和 jmp 这样的指令。我真的没有很好的文档,所以我正在查看 NASM 生成的机器代码以找出操作码等。我想看看 call 的操作码是什么,所以我编译了一些在乞讨时以标签开头的代码。我希望调用操作码之后的地址是 00 00 00 00 但它是 FB FF FF FF。我认为这与符号有关,所以我用调用 0x000000 编译代码以查看发生了什么并且地址完全相同(0xFBFFFFFF)。有人可以向我解释一下吗?我很困惑。

【问题讨论】:

  • I really do not have good documentation - 怎么会?从 intel.com 或 amd.com 下载 CPU 文档。他们有漂亮的指令集表,指令编码和操作的描述。

标签: assembly call object-code


【解决方案1】:

在 32 位用户模式 ​​x86 代码中最常见的 CALL 形式是CALL rel32,它“调用”到操作数上的一个点加上下一条指令的地址。这是一个近亲电话。

作为参考,可以使用绝对调用,但编码是 6 个字节而不是 5 个;编码为FF 14 XX XX XX XX。额外的字节 (14) 告诉指令读取将用作立即数的立即数位移。但是,这将需要根据加载程序的模块库进行重写;搬迁时不需要注意相对调用。

为了可视化它的工作原理,当指令执行时,会发生这种情况:

  • EIP(指令指针)递增指向下一条指令,
  • 将该地址压入堆栈(以提供返回地址),
  • 立即数(例如 rel32 值)被添加到 EIP,并且
  • 下一条指令照常从(新的)[EIP] 读取。

当这条指令被编码时,它看起来像这样:E8 XX XX XX XX。从中可以看出指令的长度是5个字节。

因为EIP 增加了指令的长度,所以调用将相对于指令开始后5 个字节的点。因此,如果您的 CALL 0x00000000 指令的相对地址是 0x00000000,则需要从 EIP 中减去 5;您的汇编程序已将绝对地址转换为相对地址。

偏移量可以是负数。另外,请记住 x86 地址是 little-endian。因此,指令是E8 FB FF FF FF

有趣的是,这条特定指令的结果是,EIP+5 将不断被压入堆栈,直到生成异常 (#SS(0))。

【讨论】:

    【解决方案2】:

    显示您正在反汇编的实际代码会很有用。该数字很可能是小端负偏移量。 0xFFFFFFFB = -5 2s 补码。你写了吗:

    Label: call Label
    

    如果 call 是一个 1 字节的操作码和一个 4 字节的相对偏移量,那将是有意义的。

    【讨论】:

    • 啊啊,忘了小端序了。那么它很可能只是一个直接的相对地址。
    • 大声笑我认为负数只是前面有一位表示它是负数还是正数。哈哈,谢谢。
    【解决方案3】:

    call 通常以各种形式出现,例如一个使用绝对地址跳转,另一个相对于当前地址跳转。这可能是相对的,虽然这四个字节可能不是直接的偏移量。

    如果有疑问,尤其是在实现汇编程序时,您可能需要查看手册或数据表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 2016-03-08
      • 1970-01-01
      • 2021-07-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多