www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Calling C functions from D that return structs

reply SiegeLord <none none.org> writes:
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
parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
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
parent SiegeLord <none none.com> writes:
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