• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Which flavor of objc_msgSend for NSSize return
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Which flavor of objc_msgSend for NSSize return


  • Subject: Re: Which flavor of objc_msgSend for NSSize return
  • From: Greg Parker <email@hidden>
  • Date: Fri, 11 May 2007 19:36:56 -0700

Rosyna wrote:

I'm trying to call a method that returns an NSSize on i386. Do I use objc_msgSend, _fpret, or _stret?

Short answer: write a small test program, compile it, and examine or run the generated code. Use whatever the compiler used. The compiler is always right. Note that the answer may differ between architectures, so compile the test code on every architecture you care about.



glenn andreas wrote:

From <http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/IA32.html#//apple_ref/doc/uid/ TP40002492-SW5 > (with added labeling):

Returning Results
This is how functions pass results to their callers:
1) The called function places integral or pointer results in EAX.
2) The called function places floating-point results in ST0. The caller removes the value from this register, even when it doesn’t use the value.
3) The called function returns structures according to their aligned size:
3a) Structures 1 or 2 bytes in size are placed in EAX.
3b) Structures 4 or 8 bytes in size are placed in: EAX and EDX.
3c) Structures or other sizes are placed at the address supplied by the caller. See “Passing Arguments” for more information.
4) The called function places vectors at the address supplied by the caller.


So my understanding is that anything that would be returned in registers (1, 3a, 3b) are objc_msgSend, something returning a float (2) is _fpret, and that leaves 3c (returning a struct via an address supplied by the caller) corresponding to _stret

This is correct for i386.

For ppc, the rules are similar: structs returns via a caller-supplied address are handled by objc_msgSend_stret, and everything else is handled by objc_msgSend. The rules for which structs are returned via a caller-supplied address are architecture-specific. On all architectures, Objective-C parameter passing follows the C parameter passing rules, so check the C ABI for details.


Sherm Pendley wrote:

The runtime reference simply says to call _stret for all structure
return types - it doesn't distinguish between struct sizes. I
followed that rule for CamelBones, and it passes all its self-tests
on i386, as well as running every app I've tried without fail.

It's more accurate to say that you *can* use vanilla objc_msgSend()
for small structs, as an optimization, than to say that you must.
IMHO, given what the runtime reference says, and given several years
of seeing its description verified first-hand "in the field," using
_stret for all structs seems to me to be safer than trying to decide
which to use for any given combination of struct type, architecture,
and phase of the moon.

This is incorrect. Using objc_msgSend when you should use objc_msgSend_stret, or vice versa, will crash in the messenger or pass incorrect values to the called method or return incorrect values to the caller.


For example, the test program below fails on i386 when using objc_msgSend_stret() to call a method that returns NSSize. The third call to +stret passes incorrect parameters (and incidentally may corrupt the stack, depending on optimizations, because it's calling objc_msgSend_stret directly without casting to an appropriately-typed function pointer). The fourth call to +stret crashes in the messenger.

% cat test.m
#include <Foundation/Foundation.h>
#include <objc/objc-runtime.h>

@interface Foo : NSObject @end
@implementation Foo
+(NSSize) stret {
    printf("in +[%p %s]\n", self, sel_getName(_cmd));
    return (NSSize){0, 0};
}
@end

int main() {
NSSize s;
id obj = [Foo class];
SEL sel = @selector(stret);
NSSize (*msgSend)(id, SEL) = (NSSize(*)(id, SEL)) objc_msgSend;
NSSize (*msgSendStret)(id, SEL) = (NSSize(*)(id, SEL)) objc_msgSend_stret;
s = [obj stret]; // #1: ok
s = msgSend(obj, sel); // #2: ok
objc_msgSend_stret(&s, obj, sel); // #3: never call objc_msgSend* directly
s = msgSendStret(obj, @selector(stret)); // #4: crashes
return 0;
}


% cc -g test.m -framework Foundation
% ./a.out
in +[0x3020 stret]
in +[0x3020 stret]
in +[0xbffff6f8 `0]
Segmentation fault


-- Greg Parker email@hidden Runtime Wrangler

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


  • Follow-Ups:
    • Re: Which flavor of objc_msgSend for NSSize return
      • From: Sherm Pendley <email@hidden>
  • Prev by Date: Re: Which flavor of objc_msgSend for NSSize return
  • Next by Date: Re: Which flavor of objc_msgSend for NSSize return
  • Previous by thread: Re: Which flavor of objc_msgSend for NSSize return
  • Next by thread: Re: Which flavor of objc_msgSend for NSSize return
  • Index(es):
    • Date
    • Thread