1

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

4

3 回答 3

4

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

Label: call Label

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

于 2012-08-31T08:36:22.043 回答
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))。

于 2013-05-08T09:44:59.473 回答
0

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

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

于 2012-08-31T08:35:18.053 回答