【问题标题】:Using JMP instead of CALLS使用 JMP 代替 CALLS
【发布时间】:2014-03-15 09:48:31
【问题描述】:

是否可以使用 JMP 指令跳转到函数的起始地址,为什么要这样做?

【问题讨论】:

  • 呼叫可以返回呼叫发起的地方,跳转不能。您不能实现使用带有跳转的函数的过程程序。
  • 我明白了。现在很清楚了。感谢您清理它。
  • 您可以使用JMP 跳转到函数的开头,它通常用于尾调用优化
  • 感谢您的任期。搜索了一下。
  • @HansPassant:我编辑了问题以删除无效部分。

标签: assembly keil


【解决方案1】:

在 Prinziple 中,只要遵守规则,您就可以混合使用 jmp 和调用。 call 自动将返回地址压栈。

 call x
 mov eax, 0   <-  returns here

x:
  do something
  ret

这也可以通过以下代码来完成:

 jmp x
 :retAdr
 mov eax, 0   <-  returns here

x:
   do something
    push retAdr    <- Basically it would be similar to a jmp, but of course the target can be calculated as well.
   ret

当然你也可以反过来做。

call x
mov eax, 0

x:
   pop eax  <- ret adress
   do something
   jmp eax

虽然这些伪代码示例可能看起来没什么用,但有时在特殊情况下以这种方式使用它们可能会很有用。 jmp 的目标可以是任何地址,因此它也可以是函数或过程。这里没有区别。

我已经在 ant-debugging 技术中看到了这一点,用于模糊返回路径并使逆向变得更加困难。它也可以用于 jmp 表或其他东西。当我在其他地方重新编写现有函数时,我对函数使用了 jmp,然后将代码转发给 originall 函数(注入代码)。

【讨论】:

  • 几乎正是我想要的。因此,只要返回地址在栈顶,rets 就可以用于跳转。谢谢。
  • 您需要考虑的是返回地址的大小。通常这将是一个 32 位的值,但当然,如果它是包含该段的长跳转,它也可以是 48 位。通常编译器/汇编器知道这一点,但如果你手动干预,如果你使用错误的大小可能会导致问题。
  • 谢谢。在这种情况下,我无法使用 RETS 转到不同的细分市场。我可以使用两个寄存器来存储返回地址,然后改用 JMP。
  • 始终适用相同的规则。如果包含段,您只需使用适当的说明或堆栈设置。在普通的 32 位代码中,您不必处理它,因为它通常使用平面内存模型。
  • 谢谢。就我而言,我可能会将控制权转移到另一个细分市场,因此我可能需要注意这一点。
【解决方案2】:

最常见的例子是 Jester 提到的尾调用优化,通常是在中间函数不返回值或初始调用者忽略返回值时。编码示例:

        call    x
;       ...
x:
;       ...
        call    y
        ret

优化为:

        call    x
;       ...
x:
;       ...
        jmp     y

【讨论】:

  • 谢谢。那么,在 second 的情况下,函数 y 永远不会返回,对吧?因为如果是这样,那么在 RETS 命令之前必须有一个 push 指令,以便 x 调用者的下一条指令将正确执行 -> 导致根本没有优化。
  • 序列是对x的调用(将返回地址压栈),跳转到y,y会返回到调用x之后的位置。
  • 我明白了,所以在那里,只有一个返回地址被推入/弹出堆栈。谢谢。
猜你喜欢
  • 2021-02-04
  • 2023-01-24
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 2016-11-27
  • 2023-04-04
  • 2012-04-06
  • 1970-01-01
相关资源
最近更新 更多