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

问题描述 投票:1回答:1

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

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

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

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

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

主要考虑的是像这样使用宏的安全性。

c objective-c objective-c-runtime
1个回答
3
投票

Bottom Line:

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

拜托,拜托,请使用NSInvocation。它为您解决了大约99%,同时更安全。可能存在它无法解决的边缘情况(例如,参数列表中的SSE / AVX向量),但它将超出您可能共同攻击的范围。

让我们通过架构来解决这个问题,看看这可能会起作用。

普遍

这些问题随处可见,没有真正的解决方案。

  1. 当作为va_args传递时,浮点总是增大为双精度。参见the C standard,第6.5.2.2节
  2. shorts和chars也是如此。他们都会被大家化,这会在传递过程中造成很大的痛苦和痛苦。从技术上讲(与浮点数不同,因为它们有时会在特殊的FPU寄存器中传递),对于整数类型,您可以通过将它们包装在单个元素结构中来解决这个问题。这将阻止他们被提升。不过请不要这样做。
  3. 工会,或复杂的结构结构。需要额外的对齐和填充以及考虑因素。如果你想要一个稳定的解决方案,你将不得不深入研究编译器代码。
  4. 如果你开始触及返回值,事情就会变得更加复杂,你需要了解结构何时被结构体打包到寄存器中以获得返回值(参见a lot of之前的讨论)。

PowerPC的

我不打扰这个。如果您仍然需要针对这些macOS设备,请做两件事:

  1. 我觉得你很难受。
  2. 你可能有比我更多的背景。祝你好运,而且速度快。

86

32位x86相当理智。没有复杂的注册参数传递,在我的头顶,我觉得这可能是相当理智。除了之前提到的问题,最重要的是x87 FPU引起的问题。避免漂浮,你可能不会在这里燃烧世界。

X86-64

64位x86完全是另一个野兽。你将不得不学习很多关于编译器如何将寄存器分配给参数(和返回值!),当然还有新的SSE寄存器用于浮点。

ARMv6 / ARMv7 / ARMv7s(32位ARM)

我将把这些混为一谈,从这个角度来看没有重大差异。

像x86-64一样,如果你想100%安全,你将需要了解哪些寄存器在堆栈中的哪个位置,但是如果存储器召回,浮点传递在这里更简单。

Apple的ABI guide将是您的朋友。

ARM64

这是我的知识最不稳定的地方,如果任何这些信息不正确,我道歉。

大多数函数调用都是通过寄存器完成的,因此我们之前的所有担忧仍然存在。现在有新的FPU寄存器,你必须处理浮点数,但如果你已经到了这一点,那就没有什么不可克服的了。

© www.soinside.com 2019 - 2024. All rights reserved.