Re: Which flavor of objc_msgSend for NSSize return
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