Vlam Vlam - 3 months ago 12
C Question

D integrating with C library causes gibberish to be output

I have a C library which has something like below:

Abc.h file



typedef struct
{
uint8_t dbtype;
uint32_t dbcount;
} Abc;

void test_string(Abc* abcobj, char* strA, char* strB);
Abc* create_abc(void);


Abc.c



void test_string(Abc* abcobj, char* strA, char* strB)
{
printf("Str A is %s and str B is %s\n", strA, strB);
return;
}

Abc* create_abc()
{
Abc* abcobj;
abcobj = (Abc*) calloc(1, sizeof(Abc));
return abcobj;
}


Now, I am trying to call these functions in my D code.

testD.d



module testD;

import std.stdio;
import core.stdc.string;
import core.sys.posix.dlfcn;

extern (C)
{
struct Abc {
ubyte dbtype;
int dbcount;
}
}

int main() {
auto lib = dlopen("Abc.so".ptr, RTLD_LAZY | RTLD_LOCAL);

if (lib is null) {
return -1;
}

void function(Abc* abcobj, char* strA, char* strB) test_string = cast(void function(Abc* abcobj, char* strA, char* strB))dlsym(lib, "test_string");
Abc* function() create_abc = cast(Abc* function())dlsym(lib, "create_abc");

char* strA = cast(char*)("this is string one");
char* strB = cast(char*)("this is string two");

Abc* abcobj = create_abc();
test_string(abcobj, strA, strB);

if (dlclose(lib) == 0) {
return 0;
}
else {
return -1;
}
} // main() function


I compile the testD.d using:

dmd testD.d

Then run the ./testD

When the test_string outputs the sentence, the value for strA always comes out as gibberish while strB comes out just fine.

Why is this happening??

Answer

Because the .so was made with C, you've compiled the library with C linkage, however when you're importing the symbols, you're discarding the fact, which means that D tries to use the D calling convention to invoke the code, which is different from the C calling convention.

When you import the functions, you need to specify this, so the dlsym lines need to look like:

extern (C) void function(Abc* abcobj, char* strA, char* strB) test_string =
    cast(void function(Abc* abcobj, char* strA, char* strB))dlsym(lib, "test_string");
extern (C) Abc* function() create_abc =
    cast(Abc* function())dlsym(lib, "create_abc");

Once you get the calling convention right, the correct results should come out from the call.

Comments