【问题标题】:What happens when a method is called? Where are the arguments pushed?调用方法时会发生什么?争论被推到哪里去了?
【发布时间】:2011-10-18 21:03:50
【问题描述】:

当您调用一个方法时,例如[objectA message:arg1 argument:arg2],参数会发生什么变化?

例如,当您调用一个方法时,该方法的地址被压入调用堆栈。但是争论会发生什么?他们不是也被推到某个堆栈吗?否则,方法的代码怎么知道在哪里找到它的参数?

我问的原因是因为当你得到一个堆栈跟踪时,你会得到按顺序调用的函数或方法的地址。当一个方法或函数返回时,调用它的方法或函数仍然具有对其自身参数的引用。所以我必须在某处引用arg1arg2。因此,从 iOS 设备上的堆栈跟踪和堆栈符号中,您必须能够获取调用任何其他方法或函数的方法或函数,并获取其参数。

你如何得到这些论点?

关于另一个问题:objective C log method call,他们展示了一种获取方法的NSMethodSignature 的方法,并使用该方法可以获取参数的数量和类型。

这样,知道参数的位置后,您就可以获取已调用的每个函数或方法以及用于调用它们的参数。

任何帮助将不胜感激。


更新

2011-08-03

作为对“fakeAccount22”cmets 的回复,我想在运行时从应用程序内执行此操作。

我的问题基本上归结为:在运行时和应用程序内,您如何访问 iOS 设备的 Objective-C 中的调用堆栈或堆栈指针? Mac OSX 有什么不同吗?

【问题讨论】:

  • 您想在运行时执行此操作吗?还是来自堆栈跟踪?从应用程序内部?还是来自调试器?
  • @fakeAccount22,我想在运行时从应用程序内执行此操作。
  • ios 和 osx 不同。不同型号的 iPhone、iPad 和 iPod 中的各种 arm 处理器是不同的。生成堆栈跟踪是一回事(有内置的方法),访问寄存器值(即堆栈指针)是另一回事。您可能可以使用内联汇编来做到这一点。您将需要对 arm ABI 有一个很好的理解,并理解学习一些反汇编代码。不同类型、结构、浮点数、对象等的值的处理方式不同。您可能必须从内存中的地址反汇编每个函数和方法。

标签: objective-c ios methods callstack


【解决方案1】:

这里的关键时刻是当你调用时

[objectA message:arg1 argument:arg2]

您没有调用方法,而是发送消息。为什么?因为最后这一行被编译器翻译成这样:

objc_msgSend(objectA, "message:argument:", arg1, arg2)

这就是所有的魔法。其他一切都像在 C 中一样工作。这里非常好explanation

这就是为什么所有的 Objective C 方法都可以被翻译成它们的 C 类(嗯,它们实际上是被翻译的)。例如。您的示例如下所示:

return_type method(id self, SEL _cmd, arg1_type arg1, arg2_type arg2) {
//implementation
}

【讨论】:

  • 你知道有什么好的参考资料可以解释如何在构建之前将 objc 代码翻译成 C 代码吗?
  • @gsempe 老实说,我从未调查过这方面的问题。但我认为您可以找到 GCC 或 LLVM 文档。
  • 我查看了 GCC 文档。没想到看 LLVM 之一。谢谢
  • @gsempe - GCC 或 LLVM 在构建之前将 Objective-C 转换为 C,没有中间步骤 (早在 198x 时就有了,但现在没有了)。编译器将按原样解析 Objective-C 并输出所需的代码。将方法 send 替换为函数调用,并不比将浮点操作替换为函数调用更奇怪。
【解决方案2】:

除了 Max 写的内容之外,方法的名称和参数是已知的,因为编译器会生成大量从源代码生成的调试信息,调试器可以使用它来查找方法的名称以及名称和值他们的参数等。当您在没有调试器的情况下运行代码时,通常不容易获得此调试信息,尽管如果您知道它的存储格式,它应该可以以某种方式访问​​。但请注意,它可能会随着每次新编译而改变。

在函数调用之前,调用代码将参数推送到调用堆栈上,当调用函数时,处理器也会将返回地址推送到那里。在函数内部,堆栈指针被存储,现在堆栈也可以用来存储局部变量。在函数结束时,原始堆栈指针被恢复(这使得局部变量无效且不可访问)并且处理器弹出返回地址并继续执行调用后的代码。调用者代码然后从堆栈中删除参数并继续其其余代码。

FWIW,这就是它在 C 中发生的方式。还有其他类似的方案,其中项目以不同的顺序压入堆栈,甚至传入寄存器,或者函数从堆栈中清除参数。这种方案称为调用约定。 Obj-C 使用cdecl 调用约定,这或多或少是我描述它的方式。

【讨论】:

    猜你喜欢
    • 2014-06-19
    • 2019-08-04
    • 1970-01-01
    • 2013-11-01
    • 2014-01-16
    • 1970-01-01
    • 2022-06-17
    • 1970-01-01
    • 2012-05-31
    相关资源
    最近更新 更多