Building a DLL that includes libraries for Mozilla js-ctypes

488 views Asked by At

I'm trying to build a DLL to be used in a Mozilla Firefox extension. I'm using Cygwin in Windows 7. I have the C code working fine and it builds ok:

#include<stdio.h>
#include<windows.h>

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
  return TRUE;
}

extern "C"
{
    __declspec(dllexport) int add(int a,int b) //int a,int b
    {
        return(a+b);
    }
}

I followed the instructions here: Build a DLL to be used by Mozilla js-ctypes.

The problem is that when I try to include a different library, the js-ctypes cannot read the DLL afterwards:
[10:20:53.575] Error: couldn't open library C:\Users\admin\workspaces\Extensions\formfinder\components\test.dll @ chrome://formfinder/content/overlay.js:104

All I'm adding to my C file is #include <ZZ.h> at the top, which is then complemented by the make commands:

i686-w64-mingw32-g++ -c -I/usr/local/include/NTL -I/usr/local/include test.cc  
i686-w64-mingw32-g++ -shared -o test.dll test.o -Wl,--out-implib,libmylib.dll -Wl,-e_DllMain@12

I'm using i686-w64-mingw32-g++ instead of gcc/g++ because the DLL can't be opened otherwise. I'm not sure why though.

Any help would be appreciated.

1

There are 1 answers

0
nmaier On BEST ANSWER

I don't quite get what is asked, but probably why the Cygwin gcc (or mingw-w64 gcc) is producing a DLL you cannot ctypes.open().

DLLs produced by the Cygwin gcc do have external dependencies on some Cygwin DLLs, at least cygwin1.dll providing a posix abstraction. Shipping these DLLs with your add-on is a pain and not really a sane thing to do.

You'll want to use a mingw compiler (e.g. the i686-w64-mingw32-g++ one). You could also use a Microsoft or Intel compiler instead.

OK, mingw-w64 it is for now:

$ i686-w64-mingw32-g++ -shared -o test_add.dll test_add.cc
$ objdump -p test_add.dll
The Import Tables (interpreted .idata section contents)
...
DLL Name: KERNEL32.dll
...
DLL Name: msvcrt.dll
...
The Export Tables (interpreted .edata section contents)
...
[Ordinal/Name Pointer] Table
        [   0] add

Alright, our DLL imports kernel32.dll and msvcrt.dll and nothing unexpected, and also exports our add.

Lets try it, then:

var lib = ctypes.open("C:\\cygwin\\home\\user\\test_add.dll");
try {
    try {
        var adder = lib.declare("add", ctypes.default_abi, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t);
        console.log(adder(3,5));
    }
    catch(ex) {
        console.error(ex, ex.message);
    }
}
finally {
    lib.close();
}

Produces an output of: 8.

Next, all binaries should be ASLR enabled.

$ peflags -v test_add.dll
test_add.dll: coff(0x2106[+executable_image,+line_nums_stripped,+32bit_machine,+dll]) pe(0x0000)

Turns out, it isn't (no dynamicbase)

So let's improve our linker command:

$ i686-w64-mingw32-g++ -shared -o test_add.dll test_add.cc -Wl,-nxcompat,-dynamicbase
$ peflags -v test_add.dll
test_add.dll: coff(0x2106[+executable_image,+line_nums_stripped,+32bit_machine,+dll]) pe(0x0140[+dynamicbase,+nxcompat])

Alright then.

But this is not all, unfortunately. When compiling C++ and using certain features, the linker will automatically link in the stdlibc++, e.g. when using std::string.

Adding a std::string to our source, recompiling/relinking, and another objdump tells us:

DLL Name: libgcc_s_sjlj-1.dll
vma:  Hint/Ord Member-Name Bound-To
7470       16  _Unwind_SjLj_Register
7488       17  _Unwind_SjLj_Resume
74a0       19  _Unwind_SjLj_Unregister

DLL Name: libstdc++-6.dll
vma:  Hint/Ord Member-Name Bound-To
74bc      743  _ZNSaIcEC1Ev
74cc      746  _ZNSaIcED1Ev
74dc     1080  _ZNSsC1EPKcRKSaIcE
74f4     1105  _ZNSsD1Ev
7500     3535  __gxx_personality_sj0

In that case, you'd have to ship those libaries as well (make sure to peflags the ASLR bits and follow the license), or avoid anything that could produce an exception or would otherwise require stdlibc++. Or you can static link the stuff:

i686-w64-mingw32-g++ -shared -o test_add.dll test_add.cc -Wl,-nxcompat,-dynamicbase -static-libgcc -static-libstdc++

Static linking will blow up the output DLL size, of course.