digitalmars.D - Calling C functions from D that return structs
- SiegeLord <none none.org> Mar 25 2011
- Rainer Schuetze <r.sagitario gmx.de> Mar 26 2011
- SiegeLord <none none.com> Mar 26 2011
I want a workabout for this bug: http://d.puremagic.com/issues/show_bug.cgi?id=3717 Basically, a C function that returns a structure and is compiled with a non-DMC compiler thrashes the stack when called from D. Here's the assembly code for a function that does it (sorry for the AT&T assembler syntax): <_al_map_rgba>: push %ebp mov %esp,%ebp mov 0x8(%ebp),%eax movzbl 0xc(%ebp),%edx mov 0x66d24020(,%edx,4),%edx mov %edx,(%eax) movzbl 0x10(%ebp),%edx mov 0x66d24020(,%edx,4),%edx mov %edx,0x4(%eax) movzbl 0x14(%ebp),%edx mov 0x66d24020(,%edx,4),%edx mov %edx,0x8(%eax) movzbl 0x18(%ebp),%edx mov 0x66d24020(,%edx,4),%edx mov %edx,0xc(%eax) leave ret $0x4 lea 0x0(%esi),%esi It's signature is this: ALLEGRO_COLOR al_map_rgba(ubyte r, ubyte g, ubyte b, ubyte a); Where ALLEGRO_COLOR is a quad of bytes. What I want is some sort of inline assembly preamble (and/or postamble, as it were) that will make it possible for me to call that function correctly. The suggestion made by Walter in the bug report is unacceptable for my purposes. What I have tried is this: ALLEGRO_COLOR get() { auto c = al_map_rgba(255,255,255,255); asm { sub ESP, 4; } return c; } But it did not work. Any help appreciated. -SiegeLord
Mar 25 2011
As you have already noticed, the problem is the "ret 4" generated by
gcc. This is obviously gcc's (non-standard?) way to deal with the hidden
struct pointer for the return value.
Though I have not tried it with mingw, one solution could be to write a
C wrapper for the function that uses normal pointer arguments for the
return value.
If you want the wrapper on the D side, your "get" solution is not
working because the assignment to c is before the adjustment of ESP
(without optimizations, it might work because EBP is used instead for
copying). But you can forget about the return value, its just a copy of
the hidden pointer. A declaration causing the same assembly is:
extern(C) ALLEGRO_COLOR* al_map_rgba(ref ALLEGRO_COLOR c, ubyte r, ubyte
g, ubyte b, ubyte a);
and could be used like this to correct the "ret 4":
ALLEGRO_COLOR get()
{
ALLEGRO_COLOR c;
al_map_rgba(c,255,255,255,255);
asm {
sub ESP, 4;
}
return c;
}
Actually, I have not tried to link this against a mingw generated C
function, so please take it with a grain of salt.
Rainer
SiegeLord wrote:
I want a workabout for this bug:
http://d.puremagic.com/issues/show_bug.cgi?id=3717
Basically, a C function that returns a structure and is compiled with a
non-DMC compiler thrashes the stack when called from D. Here's the assembly
code for a function that does it (sorry for the AT&T assembler syntax):
<_al_map_rgba>:
push %ebp
mov %esp,%ebp
mov 0x8(%ebp),%eax
movzbl 0xc(%ebp),%edx
mov 0x66d24020(,%edx,4),%edx
mov %edx,(%eax)
movzbl 0x10(%ebp),%edx
mov 0x66d24020(,%edx,4),%edx
mov %edx,0x4(%eax)
movzbl 0x14(%ebp),%edx
mov 0x66d24020(,%edx,4),%edx
mov %edx,0x8(%eax)
movzbl 0x18(%ebp),%edx
mov 0x66d24020(,%edx,4),%edx
mov %edx,0xc(%eax)
leave
ret $0x4
lea 0x0(%esi),%esi
It's signature is this:
ALLEGRO_COLOR al_map_rgba(ubyte r, ubyte g, ubyte b, ubyte a);
Where ALLEGRO_COLOR is a quad of bytes. What I want is some sort of inline
assembly preamble (and/or postamble, as it were) that will make it possible for
me to call that function correctly. The suggestion made by Walter in the bug
report is unacceptable for my purposes.
What I have tried is this:
ALLEGRO_COLOR get()
{
auto c = al_map_rgba(255,255,255,255);
asm
{
sub ESP, 4;
}
return c;
}
But it did not work. Any help appreciated.
-SiegeLord
Mar 26 2011
Thanks! I got it working with both my original code and your code (I actually had an issue elsewhere in my program that caused this to happen). -SiegeLord
Mar 26 2011








SiegeLord <none none.com>