Search code examples
gccdllfirefox-addonmozillajsctypes

Building a DLL that includes libraries for Mozilla js-ctypes


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.


Solution

  • 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.