www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Problem passing string to cpp on 64bit linux

reply Gerrit Wichert <gwichert yahoo.com> writes:

currently i'm trying to get wxD running on my opensuse 11.4 64bit box.

I've got it running before on opensuse 11.3 32bit using dmd 2.41 (with 
some little tweaking to the wxd sources).

After Upgrading my box, I installed the 64bit version of dmd 2.43 and 
tried to compile it in 64bit mode. It needed a little more tweaking 
(casting down some length properties where wxWidgets expected int), but 
finally I got it to compile and link with my app. But when I tried to 
run it I only got a segfault.

Using GDB on it I was able to locate the problem. For passing strings to 
cpp wxD makes use of a neat little trick.
Strings were just passed to a C function expecting a struct of type 
'dstr' like in this testing code.

app.d ================================
import std.stdio;

// struct d_str {
//    size_t length;
//    const(char) *data;

//    this( string text) {
//       length = text.length;
//       data = text.ptr;
//    }
// }
// static extern (C) void cpp_test( d_str text);

static extern (C) void cpp_test( string text);

void main( string[] args) {
    //d_str dtext = "this is a testcall";
    string dtext = "this is a testcall";
    cpp_test( dtext);

test.cpp ==============================
#include <stdio.h>
#include <string.h>

struct dstr {
     size_t          length;
     const char*     data;

extern "C"
void cpp_test( dstr ctext) {
     printf( "string is: %.*s\n", (int)ctext.length, ctext.data);

compiled with:
g++ -g -Wall -c -o test.o test.cpp && dmd -gc test.o app.

As said above this worked fine in 32 bit mode but stopped working when 
compiled in 64 bit mode.
The received struct in the called cpp function just contains garbage. 
The calling and receiving functions disassemble to the following sequences.

Dump of assembler code for function D main:
    0x000000000045ae40 <+0>:     push   %rbp
    0x000000000045ae41 <+1>:     mov    %rsp,%rbp
    0x000000000045ae44 <+4>:     sub    $0x10,%rsp
    0x000000000045ae48 <+8>:     mov    0x3fdb9(%rip),%rdx        # 
0x49ac08 <_TMP0+8>
    0x000000000045ae4f <+15>:    mov    0x3fdaa(%rip),%rax        # 
0x49ac00 <_TMP0>
    0x000000000045ae56 <+22>:    mov    %rax,-0x10(%rbp)
    0x000000000045ae5a <+26>:    mov    %rdx,-0x8(%rbp)
    0x000000000045ae5e <+30>:    rex.W push %rdx
    0x000000000045ae60 <+32>:    rex.W push %rax
    0x000000000045ae62 <+34>:    callq  0x45adf4 <cpp_test(dstr)>
    0x000000000045ae67 <+39>:    add    $0x10,%rsp
    0x000000000045ae6b <+43>:    xor    %eax,%eax
    0x000000000045ae6d <+45>:    leaveq
    0x000000000045ae6e <+46>:    retq
End of assembler dump.

Dump of assembler code for function cpp_test(dstr):
    0x000000000045adf4 <+0>:     push   %rbp
    0x000000000045adf5 <+1>:     mov    %rsp,%rbp
    0x000000000045adf8 <+4>:     sub    $0x10,%rsp
    0x000000000045adfc <+8>:     mov    %rdi,%rdx
    0x000000000045adff <+11>:    mov    %rsi,%rax
    0x000000000045ae02 <+14>:    mov    %rdx,-0x10(%rbp)
    0x000000000045ae06 <+18>:    mov    %rax,-0x8(%rbp)
    0x000000000045ae0a <+22>:    mov    -0x8(%rbp),%rdx
    0x000000000045ae0e <+26>:    mov    -0x10(%rbp),%rax
    0x000000000045ae12 <+30>:    mov    %eax,%esi
    0x000000000045ae14 <+32>:    mov    $0x49abc4,%edi
    0x000000000045ae19 <+37>:    mov    $0x0,%eax
    0x000000000045ae1e <+42>:    callq  0x45a728 <printf plt>
    0x000000000045ae23 <+47>:    leaveq
    0x000000000045ae24 <+48>:    retq
End of assembler dump.

If I interpret this right then the problem is D pushing the array on the 
stack while cpp is expecting the structs values in the rdi and rsi 
registers. The GDB command 'ptype dtext' returns 'type = ucent' for the 
D string type. Since this is a 128 bit type I thought it may be passed 
on the stack because it doesn't fit in the registers.
I the tried to pass an explicit struct (outcommented code) but with the 
same outcome. It also seems to be passed on the stack.
So now I'm at the end of my wits. Is this expected or a bug in the 64bit 
linux implementation? And what can i do to keep this neat little trick 

Gerrit Wichert
Jul 03 2011
parent Walter Bright <newshound2 digitalmars.com> writes:
On 7/3/2011 9:42 AM, Gerrit Wichert wrote:
 Strings were just passed to a C function expecting a struct of type 'dstr' like
 in this testing code.

Passing structs as value parameters do not follow the C ABI on Linux 64. This is a known bug.
Jul 03 2011