digitalmars.D - Bus error interfacing with C function returning large struct
- Jacob Carlborg (53/53) Apr 16 2013 The following code will result in a bus error on Mac OS X 10.8.2 using
- Jacob Carlborg (5/10) Apr 16 2013 If I a store the return value of "foo" in a temporary variable in "bar"
- John Colvin (10/62) Apr 16 2013 Some observations:
- Jacob Carlborg (22/29) Apr 16 2013 I don't know, that's why I'm asking here :) This is what Martin Nowak
- John Colvin (2/87) Apr 17 2013 I was wrong. Ignore the previous post.
- John Colvin (6/58) Apr 17 2013 Martins reply in the bug report correctly identifies the problem,
- Jacob Carlborg (5/10) Apr 17 2013 Ok, perhaps we can come up with a better description for the issue as we...
- John Colvin (8/14) Apr 17 2013 clang just happened to put the arguments to foo in to registers
- Jacob Carlborg (11/18) Apr 17 2013 Ok, I see. The docs for the ABI says:
The following code will result in a bus error on Mac OS X 10.8.2 using DMD 2.062 compiled for 32bit (segfault on 64bit). A couple of notes: * This code runs fine on Mac OS X 10.6.3 * It seems the struct has to be over 64 bits in size * "foo" need to take an argument Dissassembly at the bottom. I think this is the same problem I had with interfacing with the objc_msgSend_stret function, see other post: http://forum.dlang.org/thread/kkefk8$2663$1 digitalmars.com C code: struct Foo { int a; int b; int c; }; typedef struct Foo Foo; Foo foo (int a) { Foo f; f.a = 1; f.b = 2; f.c = 3; return f; } D code: struct Foo { int a; int b; int c; } extern (C) Foo foo (int a); Foo bar () { return foo(0); } extern (C) int printf(in char*, ...); void main () { auto frame = bar(); printf("a=%d b=%d c=%d\n".ptr, frame.a, frame.b, frame.c); } GDB session with dissassembly: http://pastebin.com/rguwXucR Dissassembly of the corresponding C program compiled with Clang: http://pastebin.com/MG8Tnkzp Dissassembly of "foo" on Mac OS X 10.8.2 using Clang 4.1: http://pastebin.com/0jKqksxx Dissassembly of "foo" on Mac OS X 10.6.3 using Clang 1.5: http://pastebin.com/kbdfuVcB -- /Jacob Carlborg
Apr 16 2013
On 2013-04-16 21:26, Jacob Carlborg wrote:The following code will result in a bus error on Mac OS X 10.8.2 using DMD 2.062 compiled for 32bit (segfault on 64bit). A couple of notes: * This code runs fine on Mac OS X 10.6.3 * It seems the struct has to be over 64 bits in size * "foo" need to take an argumentIf I a store the return value of "foo" in a temporary variable in "bar" the bus error goes away. -- /Jacob Carlborg
Apr 16 2013
On Tuesday, 16 April 2013 at 19:26:09 UTC, Jacob Carlborg wrote:The following code will result in a bus error on Mac OS X 10.8.2 using DMD 2.062 compiled for 32bit (segfault on 64bit). A couple of notes: * This code runs fine on Mac OS X 10.6.3 * It seems the struct has to be over 64 bits in size * "foo" need to take an argument Dissassembly at the bottom. I think this is the same problem I had with interfacing with the objc_msgSend_stret function, see other post: http://forum.dlang.org/thread/kkefk8$2663$1 digitalmars.com C code: struct Foo { int a; int b; int c; }; typedef struct Foo Foo; Foo foo (int a) { Foo f; f.a = 1; f.b = 2; f.c = 3; return f; } D code: struct Foo { int a; int b; int c; } extern (C) Foo foo (int a); Foo bar () { return foo(0); } extern (C) int printf(in char*, ...); void main () { auto frame = bar(); printf("a=%d b=%d c=%d\n".ptr, frame.a, frame.b, frame.c); } GDB session with dissassembly: http://pastebin.com/rguwXucR Dissassembly of the corresponding C program compiled with Clang: http://pastebin.com/MG8Tnkzp Dissassembly of "foo" on Mac OS X 10.8.2 using Clang 4.1: http://pastebin.com/0jKqksxx Dissassembly of "foo" on Mac OS X 10.6.3 using Clang 1.5: http://pastebin.com/kbdfuVcBSome observations: Assuming main is doing everything properly, it's passing a pointer to 12 bytes of stack space to bar in eax (as per the D ABI). bar then puts that pointer on the stack for foo (as per the IA32 OS X ABI). However, it looks to me like it's in the wrong place, because of this line: 0x00002673 <D4test3barFZS4test3Foo+11>: sub $0x8,%esp This is just from a quick glance, I may have added my hexes wrongly.
Apr 16 2013
On 2013-04-17 01:03, John Colvin wrote:Some observations: Assuming main is doing everything properly, it's passing a pointer to 12 bytes of stack space to bar in eax (as per the D ABI). bar then puts that pointer on the stack for foo (as per the IA32 OS X ABI). However, it looks to me like it's in the wrong place, because of this line: 0x00002673 <D4test3barFZS4test3Foo+11>: sub $0x8,%esp This is just from a quick glance, I may have added my hexes wrongly.I don't know, that's why I'm asking here :) This is what Martin Nowak said in the bug report: "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." http://d.puremagic.com/issues/show_bug.cgi?id=9931#c7 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 -- /Jacob Carlborg
Apr 16 2013
On Tuesday, 16 April 2013 at 23:03:44 UTC, John Colvin wrote:On Tuesday, 16 April 2013 at 19:26:09 UTC, Jacob Carlborg wrote:I was wrong. Ignore the previous post.The following code will result in a bus error on Mac OS X 10.8.2 using DMD 2.062 compiled for 32bit (segfault on 64bit). A couple of notes: * This code runs fine on Mac OS X 10.6.3 * It seems the struct has to be over 64 bits in size * "foo" need to take an argument Dissassembly at the bottom. I think this is the same problem I had with interfacing with the objc_msgSend_stret function, see other post: http://forum.dlang.org/thread/kkefk8$2663$1 digitalmars.com C code: struct Foo { int a; int b; int c; }; typedef struct Foo Foo; Foo foo (int a) { Foo f; f.a = 1; f.b = 2; f.c = 3; return f; } D code: struct Foo { int a; int b; int c; } extern (C) Foo foo (int a); Foo bar () { return foo(0); } extern (C) int printf(in char*, ...); void main () { auto frame = bar(); printf("a=%d b=%d c=%d\n".ptr, frame.a, frame.b, frame.c); } GDB session with dissassembly: http://pastebin.com/rguwXucR Dissassembly of the corresponding C program compiled with Clang: http://pastebin.com/MG8Tnkzp Dissassembly of "foo" on Mac OS X 10.8.2 using Clang 4.1: http://pastebin.com/0jKqksxx Dissassembly of "foo" on Mac OS X 10.6.3 using Clang 1.5: http://pastebin.com/kbdfuVcBSome observations: Assuming main is doing everything properly, it's passing a pointer to 12 bytes of stack space to bar in eax (as per the D ABI). bar then puts that pointer on the stack for foo (as per the IA32 OS X ABI). However, it looks to me like it's in the wrong place, because of this line: 0x00002673 <D4test3barFZS4test3Foo+11>: sub $0x8,%esp This is just from a quick glance, I may have added my hexes wrongly.
Apr 17 2013
On Tuesday, 16 April 2013 at 19:26:09 UTC, Jacob Carlborg wrote:The following code will result in a bus error on Mac OS X 10.8.2 using DMD 2.062 compiled for 32bit (segfault on 64bit). A couple of notes: * This code runs fine on Mac OS X 10.6.3 * It seems the struct has to be over 64 bits in size * "foo" need to take an argument Dissassembly at the bottom. I think this is the same problem I had with interfacing with the objc_msgSend_stret function, see other post: http://forum.dlang.org/thread/kkefk8$2663$1 digitalmars.com C code: struct Foo { int a; int b; int c; }; typedef struct Foo Foo; Foo foo (int a) { Foo f; f.a = 1; f.b = 2; f.c = 3; return f; } D code: struct Foo { int a; int b; int c; } extern (C) Foo foo (int a); Foo bar () { return foo(0); } extern (C) int printf(in char*, ...); void main () { auto frame = bar(); printf("a=%d b=%d c=%d\n".ptr, frame.a, frame.b, frame.c); } GDB session with dissassembly: http://pastebin.com/rguwXucR Dissassembly of the corresponding C program compiled with Clang: http://pastebin.com/MG8Tnkzp Dissassembly of "foo" on Mac OS X 10.8.2 using Clang 4.1: http://pastebin.com/0jKqksxx Dissassembly of "foo" on Mac OS X 10.6.3 using Clang 1.5: http://pastebin.com/kbdfuVcBMartins reply in the bug report correctly identifies the problem, it's a bug in dmds implementation of the OS X IA32 ABI. This is quite a severe bug, it's only by luck that eax was set to 0 causing an immediate error. I suggest it should be marked critical.
Apr 17 2013
On 2013-04-17 12:05, John Colvin wrote:Martins reply in the bug report correctly identifies the problem, it's a bug in dmds implementation of the OS X IA32 ABI.I see. I'm still wondering why it works on Mac OS X 10.6.3, just luck?This is quite a severe bug, it's only by luck that eax was set to 0 causing an immediate error. I suggest it should be marked critical.Ok, perhaps we can come up with a better description for the issue as well. -- /Jacob Carlborg
Apr 17 2013
On Wednesday, 17 April 2013 at 11:14:52 UTC, Jacob Carlborg wrote:On 2013-04-17 12:05, John Colvin wrote:clang just happened to put the arguments to foo in to registers different on 10.6.3 Instead of loading the 0 argument in to eax it loaded the pointer to the struct like it would in system V ABI (linux) I have no idea whether this is a complete coincidence, or whether clang has changed it's approach to the OS X abi, or whether the ABI itself has changed.Martins reply in the bug report correctly identifies the problem, it's a bug in dmds implementation of the OS X IA32 ABI.I see. I'm still wondering why it works on Mac OS X 10.6.3, just luck?
Apr 17 2013
On 2013-04-17 13:43, John Colvin wrote:clang just happened to put the arguments to foo in to registers different on 10.6.3 Instead of loading the 0 argument in to eax it loaded the pointer to the struct like it would in system V ABI (linux) I have no idea whether this is a complete coincidence, or whether clang has changed it's approach to the OS X abi, or whether the ABI itself has changed.Ok, I see. The docs for the ABI says: 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. -- /Jacob Carlborg
Apr 17 2013