How to implement an IMP function that returns a large struct type determined at run-time?

Objective CPerlObjective C-Runtime

Objective C Problem Overview


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 for > objc_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...

Objective C Solutions


Solution 1 - Objective C

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:

  • From the Objective-C runtime code: The i386 and x86_64 hand-crafted messenger assmbly stubs for the various messaging methods.
  • An SO answer that provides an overview of the dispatching.
  • A in-depth review of the dispatching mecanism with a line-by-line analysis of the assembly code

Hope it helps.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSherm PendleyView Question on Stackoverflow
Solution 1 - Objective CLaurent EtiembleView Answer on Stackoverflow