Nim icon indicating copy to clipboard operation
Nim copied to clipboard

DLLs compiled with --tlsEmulation:off can not be loaded with LoadLibraryEx

Open yglukhov opened this issue 3 years ago • 8 comments

# mymod.nim
echo "hi"
# test.nim
{.emit:"""
#include <windows.h>
""".}
proc test() =
    var hDLL: pointer
    {.emit: """
        hDLL = LoadLibraryEx("<<FULL_PATH_TO>>\\mymod.dll", NULL,
                            LOAD_LIBRARY_SEARCH_DEFAULT_DIRS |
                            LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
    """.}

    echo "isNil: ", hDLL.isNil

test()
nim c --app:lib --threads:on --tlsEmulation:off mymod
nim c -r test

Output:

isNil: true

Changing tlsEmulation to on produces output:

hi
isNil: false

EDIT: In case of failure, GetLastError is ERROR_MOD_NOT_FOUND (0x7E).

yglukhov avatar Feb 01 '21 07:02 yglukhov

@yglukhov

  • please report GetLastError refs https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror
  • can't the more portable std/dynlib be used instead of raw OS calls?

timotheecour avatar Feb 01 '21 08:02 timotheecour

please report GetLastError

Updated description

can't the more portable std/dynlib be used instead of raw OS calls?

nim's loadLib seems to work fine, but Python 3.9.1 is using LoadLibraryEx to load modules.

yglukhov avatar Feb 01 '21 08:02 yglukhov

see https://devblogs.microsoft.com/oldnewthing/20131127-00/?p=2553 which provides more info on how to debug ERROR_MOD_NOT_FOUND; it could be that a dependent dll can't be found

timotheecour avatar Feb 01 '21 08:02 timotheecour

I'm afraid i'm not much of a windows user to dig it. But hopefully the sample should be easy enough to debug for anyone with a proper windows machine.

yglukhov avatar Feb 01 '21 08:02 yglukhov

nim's loadLib seems to work fine, but Python 3.9.1 is using LoadLibraryEx to load modules. It seems that LoadLibrary works.

import os

{.emit:"""
#include <windows.h>
""".}
proc test() =
    var hDLL: pointer
    {.emit: """
        hDLL = LoadLibrary("d:\\qqpcmgr\\desktop\\Nim\\foo.dll");
    """.}

    echo osLastError()
    echo "isNil: ", hDLL.isNil

test()

Or loadLibray doesn't provide flags parameters, it also works. I think some dlls may be not searched.

This works too

import os

{.emit:"""
#include <windows.h>
""".}
proc test() =
    var hDLL: pointer
    {.emit: """
        hDLL = LoadLibraryEx("d:\\qqpcmgr\\desktop\\Nim\\foo.dll", NULL,
                            LOAD_WITH_ALTERED_SEARCH_PATH);
    """.}

    echo osLastError()
    echo "isNil: ", hDLL.isNil

test()

ringabout avatar Feb 02 '21 07:02 ringabout

As reported by @cer1969, --tlsEmulation:off causes the final binary to depend on __emutls_get_address symbol from libgcc_s_seh-1.dll.

yglukhov avatar Mar 24 '21 09:03 yglukhov

Compiling the binary with --passL:-static helps. Maybe consider adding it to global nim.cfg.

EDIT: s/library/binary

yglukhov avatar Feb 15 '22 14:02 yglukhov

Compiling the library with --passL:-static helps. Maybe consider adding it to global nim.cfg.

This works and only add 37 kb to the library. Thanks

cer1969 avatar Mar 16 '22 20:03 cer1969