可以安全地将objc_msgsend强制转换为变长参数函数

时间:2019-04-25 03:24:15

标签: c objective-c objective-c-runtime

假设我在运行时有一个对象及其选择器之一,我打算安全地调用它,所以我定义了

#define objc_msgsend_va ((void (*)(id, SEL, ...))objc_msgsend)

#define Call_object(obj, sel, ...) objc_msgsend_va(obj, sel, ## __VA_ARGS__)

我可以用Call_object宏安全地替换任何方法调用,否则可能导致某种崩溃。

这是为了定义一个宏以在iOS设备上运行任意运行时方法,我无法显式转换每种方法的正确函数类型,因此我使用了变长参数。

主要考虑因素是使用此类宏的安全性。

1 个答案:

答案 0 :(得分:3)

底线:

不是,这绝对是不安全的。它可以在很多常见情况下工作,但是va_args与将参数直接传递给函数并不相同。

请,请继续使用NSInvocation它可以为您解决大约99%的问题,同时更加安全。可能存在一些无法解决的极端情况(例如,参数列表中的SSE / AVX向量),但是它比您可能会一起破解的东西要跨越式发展。

让我们按体系结构对其进行分解,然后查看 可能在哪些方面起作用。

通用

这些问题将无处不在,没有实际的解决方案。

  1. 作为va_args传递时,浮点数始终会加倍。参见the C standard,第6.5.2.2节

  2. shortchar的情况相同。它们也会全部变大,通过时会引起很多痛苦。从技术上讲(与浮点数不同,因为浮点数有时会通过特殊的FPU寄存器传递),对于整数类型,可以通过将它们包装在单个元素结构中来解决。这将阻止他们被提升。不过请不要这样做。

  3. 联合,或复杂的结构。还需要其他对齐方式和填充方式以及注意事项。如果您想要一个稳定的解决方案,则必须深入研究编译器代码。

  4. 如果您开始触摸返回值,事情将变得更加复杂,并且您需要了解架构何时将结构打包到寄存器中以获取返回值(请参见a lot {{ 3}}先前的讨论)。

PowerPC

我对此并不打扰。如果仍然需要定位这些macOS设备,则有两件事:

  1. 我对你很不好。

  2. 您可能拥有比我更多的背景信息。祝你好运,加油!

x86

32位 x86非常理智。我的头顶上没有复杂的寄存器参数通过,我觉得这可能很理智。除了前面提到的问题外,最大的问题是由x87 FPU引起的问题。避免漂浮,否则您可能不会在这里燃烧世界。

x86-64

64位 x86完全是另一种野兽。您将需要学习很多有关编译器如何将寄存器分配给参数(并返回值!)的知识,当然还有新的SSE浮点寄存器。

ARMv6 / ARMv7 / ARMv7s(32位ARM)

我要把它们放在一起,从这个角度来看并没有太大的区别。

像x86-64一样,如果要确保100%安全,则必须了解有关哪些寄存器在堆栈中的位置,但是如果内存被调用,则此处的浮点传递会更简单。

这里的苹果of是您的朋友。

ARM64

这是我最不了解的地方,对于其中任何信息不正确,我深表歉意。

大多数函数调用完全通过寄存器执行,因此我们以前的所有担忧仍然存在。现在有新的FPU寄存器需要处理浮点数,但是如果您要达到这一点,那就没有什么不可逾越的了。