如何实现返回运行时确定的大型结构类型的 IMP 函数?
背景:CamelBones 在 Objective-C 运行时注册 Perl 类。 为此,每个 Perl 方法都注册到相同的 IMP 功能;该函数检查其自身 &要查找的 _cmd
参数 调用哪个 Perl 方法。
多年来,这种方法一直运作良好,对于那些 使用 objc_msgSend 调度。但现在我想添加对 从 Perl 方法返回浮点和大型结构类型。 浮点并不难;我将简单地编写另一个返回的 IMP double,用于处理通过 objc_msgSend_fpret 分派的消息。
问题是如何处理 objc_msgSend_stret
。写一个 为每个可能的结构返回类型单独的 IMP
是不切实际的,对于 有两个原因:首先,因为即使我这样做只是针对结构类型 这是在编译时已知的,这是一个荒谬的函数数量。 其次,因为我们正在讨论一个可以与任何任意 Objective-C 和 Java 框架相链接的框架。 Perl 代码,在编译框架时我们不知道所有潜在的结构类型。
我希望做的是编写一个可以处理任何返回的 IMP
通过 objc_msgSend_stret 分派的类型。我可以把它写成 返回void
,并将指针参数传递给返回缓冲区,例如 旧的 objc_msgSend_stret 已声明?即使那件事发生了 现在工作了,以后还能继续工作吗?
感谢您的任何建议 - 我一直在为这个问题绞尽脑汁。 :-)
更新:
这是我从 Apple 的一位运行时工程师在他们的 objc 语言邮件列表中收到的建议:
必须编写汇编代码来处理 本案。
您的建议在某些方面失败了 架构,其中 ABI 代表“功能” 返回 void 并带有指向 a 的指针 结构作为第一个参数”不同 来自“返回结构的函数”。 (在 i386 上,结构地址被弹出 由调用者从堆栈中取出 案例中的被调用者在另一个案例中 案例。)这就是为什么原型
objc_msgSend_stret
已更改。汇编代码将捕获 结构返回地址,将其偷偷放入 非结构返回 C 函数调用 在不打扰其他人的情况下 参数,然后做正确的事情 退出时特定于 ABI 的清理(
ret $4
在 i386 上)。或者,组件 代码可以捕获所有 参数。货运机械 做这样的事情。那个代码 可能在开源 CoreFoundation 中 如果你想看看有什么技巧 看起来像。
我将保留这个问题,以防有人集思广益,提出更好的想法,但由于这个问题直接来自苹果自己的“运行时管理员”,我认为这可能是我可能得到的最权威的答案。我想是时候掸掉 x86 参考手册上的灰尘并清除我的汇编器上的锈迹了……
Background: CamelBones registers Perl classes with the Objective-C runtime.
To do this, every Perl method is registered with the same IMP
function; that function examines its self
& _cmd
arguments to find
which Perl method to call.
This has worked well enough for several years, for messages that were
dispatched with objc_msgSend
. But now I want to add support for
returning floating-point and large struct types from Perl methods.
Floating-point isn't hard; I'll simply write another IMP that returns
double, to handle messages dispatched with objc_msgSend_fpret
.
The question is what to do about objc_msgSend_stret
. Writing a
separate IMP
for every possible struct return type is impractical, for
two reasons: First, because even if I did so only for struct types
that are known at compile-time, that's an absurd number of functions.
And second, because we're talking about a framework that can be linked against any arbitrary Objective-C & Perl code, we don't know all the potential struct types when the framework is being compiled.
What I hope to do is write a single IMP
that can handle any return
type that's dispatched via objc_msgSend_stret
. Could I write it as
returning void
, and taking a pointer argument to a return buffer, like
the old objc_msgSend_stret
was declared? Even if that happened to
work for now, could I rely on it continuing to work in the future?
Thanks for any advice - I've been racking my brain on this one. :-)
Update:
Here's the advice I received from one of Apple's runtime engineers, on their objc-language mailing list:
You must write assembly code to handle
this case.Your suggestion fails on some
architectures, where ABI for "function
returning void with a pointer to a
struct as the first argument" differs
from "function returning a struct".
(On i386, the struct address is popped
from the stack by the caller in one
case and by the callee in the other
case.) That's why the prototype forobjc_msgSend_stret
was changed.The assembly code would capture the
struct return address, smuggle it into
non-struct-return C function call
without disturbing the rest of the
parameters, and then do the right
ABI-specific cleanup on exit (ret $4
on i386). Alternatively, the assembly
code can capture all of the
parameters. The forwarding machinery
does something like this. That code
might be in open-source CoreFoundation
if you want to see what the techniques
look like.
I'll leave this question open, in case someone brainstorms a better idea, but with this coming directly from Apple's own "runtime wrangler," I figure it's probably as authoritative an answer as I'm likely to get. Time to dust off the x86 reference manuals and knock the rust off my assembler-fu, I guess...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看来苹果工程师是对的:唯一的出路就是汇编代码。以下是一些有用的入门指南:
希望它有所帮助。
It seems that the Apple engineer is right: the only to way to go is assembly code. Here are some usefull pointers to getting started:
Hope it helps.