Calling C functions from D that return structs

Rainer Schuetze r.sagitario at gmx.de
Sat Mar 26 01:16:35 PDT 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


More information about the Digitalmars-d mailing list