Jump to page: 1 2 3
Thread overview
[Issue 9931] New: Bus error interfacing with C function returning structs with floats
Apr 14, 2013
Jacob Carlborg
Apr 14, 2013
Martin Nowak
Apr 14, 2013
Jacob Carlborg
Apr 14, 2013
Martin Nowak
Apr 15, 2013
Jacob Carlborg
Apr 16, 2013
Jacob Carlborg
Apr 16, 2013
Jacob Carlborg
Apr 17, 2013
Martin Nowak
Apr 17, 2013
Jacob Carlborg
Apr 17, 2013
John Colvin
Apr 17, 2013
John Colvin
Apr 17, 2013
Jacob Carlborg
Apr 17, 2013
Jacob Carlborg
Apr 17, 2013
Jacob Carlborg
[Issue 9931] Mac OS X ABI not followed when returning structs for extern (C)
Apr 17, 2013
John Colvin
Apr 17, 2013
John Colvin
Apr 17, 2013
Jacob Carlborg
Apr 17, 2013
Jacob Carlborg
Apr 23, 2013
Jacob Carlborg
Apr 24, 2013
Martin Nowak
Apr 24, 2013
Jacob Carlborg
Apr 26, 2013
Walter Bright
Apr 26, 2013
Jacob Carlborg
Apr 26, 2013
Walter Bright
Apr 26, 2013
Walter Bright
Apr 27, 2013
Jacob Carlborg
Apr 27, 2013
Martin Nowak
Apr 27, 2013
Jacob Carlborg
April 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931

           Summary: Bus error interfacing with C function returning
                    structs with floats
           Product: D
           Version: D2
          Platform: x86
        OS/Version: Mac OS X
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: doob@me.com


--- Comment #0 from Jacob Carlborg <doob@me.com> 2013-04-14 09:25:06 PDT ---
This code:

http://pastebin.com/U5XdFfDq

Will result in a bus error when compiled as 32bit. Three ways the bus error won't happen:

* If I compile as 64bit everything works fine
* If the function "foo" is moved inline in the "main" function everything works
fine
* If I store the return value of "fp" in "foo" in a temporary variable and then
return it

Mac OS X 10.8.2.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931


Martin Nowak <code@dawg.eu> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |code@dawg.eu
         Resolution|                            |INVALID


--- Comment #1 from Martin Nowak <code@dawg.eu> 2013-04-14 09:53:35 PDT ---
You can't cast the "..." part o a C vararg function away.
You also don't pass a pointer to the struct return to objc_msgSend_stret, which
is the first parameter.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931


Jacob Carlborg <doob@me.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |


--- Comment #2 from Jacob Carlborg <doob@me.com> 2013-04-14 11:43:05 PDT ---
You're supposed to invoke the functions like that. The objc_msgSend functions need to be casted to the correct signature.

http://stackoverflow.com/questions/8405737/how-do-i-return-a-struct-value-from-a-runtime-defined-class-method-under-arc

This works perfectly fine in C:

http://pastebin.com/cTfn0PJS

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931



--- Comment #3 from Martin Nowak <code@dawg.eu> 2013-04-14 16:56:04 PDT ---
NSRect foo (id screen)
{
    alias extern (C) NSRect function (id, SEL) frameFp;
    auto fp = cast(frameFp) &objc_msgSend_stret;
    return fp(screen, sel_registerName("visibleFrame".ptr));
}

- You omit the pointer to the return value, that might accidently work on some ABIs because a hidden pointer to the return value is passed as first argument.

What's the problem with this?

NSRect foo(id screen)
{
    NSRect res;
    objc_msgSend_stret(&res, screen, sel_registerName("visibleFrame"));
    return res;
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 15, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931



--- Comment #4 from Jacob Carlborg <doob@me.com> 2013-04-14 23:38:54 PDT ---
(In reply to comment #3)
> NSRect foo (id screen)
> {
>     alias extern (C) NSRect function (id, SEL) frameFp;
>     auto fp = cast(frameFp) &objc_msgSend_stret;
>     return fp(screen, sel_registerName("visibleFrame".ptr));
> }
> 
> - You omit the pointer to the return value, that might accidently work on some ABIs because a hidden pointer to the return value is passed as first argument.

I don't know why it behaves like this but that's how you're supposed to invoke the function. This is the Objective-C runtime and it's kind of special.

> What's the problem with this?
> 
> NSRect foo(id screen)
> {
>     NSRect res;
>     objc_msgSend_stret(&res, screen, sel_registerName("visibleFrame"));
>     return res;
> }

On Mac OS X 10.6.3 it segfaults. I haven't tried on 10.8.2 yet. It also
segfaults if I cast it to: extern (C) void function (NSRect*, id, SEL).

BTW, the original example doesn't _not_ cause a bus error on Mac OS X 10.6.3.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 16, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931



--- Comment #5 from Jacob Carlborg <doob@me.com> 2013-04-16 00:10:33 PDT ---
Here's one of my post from the discussion of this issue at the newsgroup:

http://forum.dlang.org/thread/kkefk8$2663$1@digitalmars.com

I've done some investigation about how the "objc_msgSend" family of functions work, including "objc_msgSend_stret". For those who don't know they're are part of the Objective-C runtime used for calling Objective-C methods.

These functions are _not_ regular C functions, they're completely implemented using assembly. What they basically do is looking up the Objective-C method to call and just calls it (some caching is involved as well).

What's special about this is that it won't mess with any resister or stack used for passing function arguments or sending back return values. What happens when it has found the correct Objective-C method is that it will just jump to the function. All registers and the stack are already correct, from the call to the objc_msgSend itself. I assume that is way the objc_msgSend method need to be cast to the correct signature before calling it. We don't want to use the ABI for variadic functions (as declared by objc_msgSend), we want the ABI used for the target function, that is, the Objective-C method.

An Objective-C method is implement like a regular C function, following the ABI of the platform. It has to take at least these two parameters:

void foo (id self, SEL _cmd);

"self" would be the object we're calling the method on. "_cmd" is the selector
(method) being called.

Then what's objc_msgSend_stret used for. The objc_msgSend_stret function is used for returning structs that are too large to fit in the register. This is completely dependent on the platform ABI.

I don't know if this helps.

Some info about how objc_msgSend works:

http://www.friday.com/bbum/2009/12/18/objc_msgsend-part-1-the-road-map/

Some info about why objc_msgSend_stret exists:

http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 16, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931



--- Comment #6 from Jacob Carlborg <doob@me.com> 2013-04-16 12:28:13 PDT ---
I think I found smaller test case for this problem, without the casts and Objective-C runtime functions:

http://forum.dlang.org/thread/kkk8kh$2jsu$1@digitalmars.com

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 17, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931



--- Comment #7 from Martin Nowak <code@dawg.eu> 2013-04-16 17:57:26 PDT ---
Seems like OSX deviates from the SysV IA-32 ABI for memory struct returns.
The callee does NOT return the hidden pointer in EAX.
Instead the caller has to use the value passed as argument.

0x0000267c <D4test3barFZS4test3Foo+20>: call   0x26a0 <foo>
0x00002681 <D4test3barFZS4test3Foo+25>: add    $0xc,%esp
0x00002684 <D4test3barFZS4test3Foo+28>: mov    %eax,%esi // <- EAX is trashed
0x00002686 <D4test3barFZS4test3Foo+30>: mov    -0x4(%ebp),%edi
0x00002689 <D4test3barFZS4test3Foo+33>: movsl  %ds:(%esi),%es:(%edi)
0x0000268a <D4test3barFZS4test3Foo+34>: movsl  %ds:(%esi),%es:(%edi)
0x0000268b <D4test3barFZS4test3Foo+35>: movsl  %ds:(%esi),%es:(%edi)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 17, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931



--- Comment #8 from Jacob Carlborg <doob@me.com> 2013-04-16 23:38:53 PDT ---
(In reply to comment #7)
> Seems like OSX deviates from the SysV IA-32 ABI for memory struct returns.
> The callee does NOT return the hidden pointer in EAX.
> Instead the caller has to use the value passed as argument.

I don't know if this is what you're but the the ABI documentation says:

"When a function returns a structure or union larger than 8 bytes, the caller passes a pointer to appropriate storage as the first argument to the function."

And:

"The called function returns structures according to their aligned size.

* Structures 1 or 2 bytes in size are placed in EAX.
* Structures 4 or 8 bytes in size are placed in: EAX and EDX.
* Structures of other sizes are placed at the address supplied by the caller.
For example, the C++ language occasionally forces the compiler to return a
value in memory when it would normally be returned in registers. See “Passing
Arguments” for more information."

http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
April 17, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=9931


John Colvin <john.loughran.colvin@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |john.loughran.colvin@gmail.
                   |                            |com


--- Comment #9 from John Colvin <john.loughran.colvin@gmail.com> 2013-04-17 08:04:52 BST ---
(In reply to comment #7)
> 0x0000267c <D4test3barFZS4test3Foo+20>: call   0x26a0 <foo>
> 0x00002681 <D4test3barFZS4test3Foo+25>: add    $0xc,%esp
> 0x00002684 <D4test3barFZS4test3Foo+28>: mov    %eax,%esi // <- EAX is trashed
> 0x00002686 <D4test3barFZS4test3Foo+30>: mov    -0x4(%ebp),%edi
> 0x00002689 <D4test3barFZS4test3Foo+33>: movsl  %ds:(%esi),%es:(%edi)
> 0x0000268a <D4test3barFZS4test3Foo+34>: movsl  %ds:(%esi),%es:(%edi)
> 0x0000268b <D4test3barFZS4test3Foo+35>: movsl  %ds:(%esi),%es:(%edi)

You're reading it the wrong way around, at&t is src,des

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
« First   ‹ Prev
1 2 3