From 0d6ce13671bd5efcbef0fa17175d9c9daa105a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Jul 2018 13:01:20 +0200 Subject: [PATCH] loader: Add Windows support --- appveyor.yml | 3 ++- lib/loader/CMakeLists.txt | 4 +--- lib/loader/loader.c | 42 ++++++++++++++++++++++++++-------- test/unittests/CMakeLists.txt | 17 +++++++------- test/unittests/test_loader.cpp | 13 +++++++---- test/unittests/vm_mock.c | 6 +++-- 6 files changed, 57 insertions(+), 28 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 67e98d485..c9bccd9aa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,5 +25,6 @@ build_script: | cmake --build . --config %CONFIGURATION% --target install after_build: | - C:\projects\evmc\build\test\Release\evmc-test.exe + cd C:\projects\evmc\build\test + Release\evmc-test.exe C:\install\bin\evmc-vmtester.exe C:\install\bin\evmc-examplevm.dll diff --git a/lib/loader/CMakeLists.txt b/lib/loader/CMakeLists.txt index db7c5b36c..fbc6b6e57 100644 --- a/lib/loader/CMakeLists.txt +++ b/lib/loader/CMakeLists.txt @@ -11,8 +11,6 @@ add_library( add_library(evmc::loader ALIAS loader) set_target_properties(loader PROPERTIES OUTPUT_NAME evmc-loader) target_include_directories(loader PUBLIC $$) -if(CMAKE_DL_LIBS) - target_link_libraries(loader INTERFACE ${CMAKE_DL_LIBS}) -endif() +target_link_libraries(loader INTERFACE ${CMAKE_DL_LIBS}) install(TARGETS loader EXPORT evmcTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/lib/loader/loader.c b/lib/loader/loader.c index 688e83966..5164e99ce 100644 --- a/lib/loader/loader.c +++ b/lib/loader/loader.c @@ -8,11 +8,34 @@ #include #include +#if _WIN32 +#include +#define DLL_HANDLE HMODULE +#define DLL_OPEN(filename) LoadLibrary(filename) +#define DLL_CLOSE(handle) FreeLibrary(handle) +#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn) GetProcAddress(handle, name) +#define HAVE_STRCPY_S 1 +#else #include +#define DLL_HANDLE void* +#define DLL_OPEN(filename) dlopen(filename, RTLD_LAZY) +#define DLL_CLOSE(handle) dlclose(handle) +#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn)(uintptr_t) dlsym(handle, name) +#define HAVE_STRCPY_S 0 +#endif #define PATH_MAX_LENGHT 4096 -#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +#if !HAVE_STRCPY_S +static void strcpy_s(char* dest, size_t destsz, const char* src) +{ + size_t len = strlen(src); + if (len > destsz - 1) + len = destsz - 1; + memcpy(dest, src, len); + dest[len] = 0; +} +#endif typedef struct evmc_instance* (*evmc_create_fn)(); @@ -34,7 +57,7 @@ struct evmc_instance* evmc_load(const char* filename, enum evmc_loader_error_cod goto exit; } - void* handle = dlopen(filename, RTLD_LAZY); + DLL_HANDLE handle = DLL_OPEN(filename); if (!handle) { ec = EVMC_ERRC_CANNOT_OPEN; @@ -44,7 +67,7 @@ struct evmc_instance* evmc_load(const char* filename, enum evmc_loader_error_cod const char prefix[] = "evmc_create_"; const size_t prefix_length = strlen(prefix); char name[sizeof(prefix) + PATH_MAX_LENGHT]; - strcpy(name, prefix); + strcpy_s(name, sizeof(name), prefix); const char* sep_pos = strrchr(filename, '/'); const char* name_pos = sep_pos ? sep_pos + 1 : filename; @@ -54,7 +77,7 @@ struct evmc_instance* evmc_load(const char* filename, enum evmc_loader_error_cod if (strncmp(name_pos, lib_prefix, lib_prefix_length) == 0) name_pos += lib_prefix_length; - strncpy(name + prefix_length, name_pos, PATH_MAX_LENGHT); + strcpy_s(name + prefix_length, PATH_MAX_LENGHT, name_pos); char* ext_pos = strrchr(name, '.'); if (ext_pos) @@ -64,26 +87,25 @@ struct evmc_instance* evmc_load(const char* filename, enum evmc_loader_error_cod while ((dash_pos = strchr(dash_pos, '-')) != NULL) *dash_pos++ = '_'; - const void* symbol = dlsym(handle, name); - if (!symbol) + evmc_create_fn create_fn = DLL_GET_CREATE_FN(handle, name); + if (!create_fn) { const char* short_name_pos = strrchr(name, '_'); if (short_name_pos) { short_name_pos += 1; memmove(name + prefix_length, short_name_pos, strlen(short_name_pos) + 1); - symbol = dlsym(handle, name); + create_fn = DLL_GET_CREATE_FN(handle, name); } } - if (symbol) + if (create_fn) { - evmc_create_fn create_fn = (evmc_create_fn)(uintptr_t)symbol; instance = create_fn(); } else { - dlclose(handle); + DLL_CLOSE(handle); ec = EVMC_ERRC_SYMBOL_NOT_FOUND; } diff --git a/test/unittests/CMakeLists.txt b/test/unittests/CMakeLists.txt index 6fd2db346..d2181ce05 100644 --- a/test/unittests/CMakeLists.txt +++ b/test/unittests/CMakeLists.txt @@ -3,6 +3,7 @@ # Licensed under the MIT License. See the LICENSE file. add_library(vm-mock SHARED vm_mock.c) +target_link_libraries(vm-mock PRIVATE evmc) if(UNIX) set(cmd create_symlink) @@ -12,14 +13,14 @@ endif() add_custom_command( TARGET vm-mock POST_BUILD - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ ${CMAKE_SHARED_LIBRARY_PREFIX}aaa${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ double_prefix_aaa.evm - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ double-prefix-aaa.evm - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ eee-bbb.dll - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ ${CMAKE_SHARED_LIBRARY_PREFIX}eee1${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ eee2${CMAKE_SHARED_LIBRARY_SUFFIX} - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ ${CMAKE_SHARED_LIBRARY_PREFIX}eee3 - COMMAND ${CMAKE_COMMAND} -E ${cmd} $ eee4 + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ libaaa.so + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ double_prefix_aaa.evm + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ double-prefix-aaa.evm + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ eee-bbb.dll + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ libeee1.so + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ eee2.so + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ libeee3.x + COMMAND ${CMAKE_COMMAND} -E ${cmd} $ eee4 COMMAND ${CMAKE_COMMAND} -E ${cmd} $ ../aaa.evm COMMAND ${CMAKE_COMMAND} -E touch empty.file ) diff --git a/test/unittests/test_loader.cpp b/test/unittests/test_loader.cpp index 517ea28e6..c9930493f 100644 --- a/test/unittests/test_loader.cpp +++ b/test/unittests/test_loader.cpp @@ -108,9 +108,10 @@ TEST(loader, eee_bbb) EXPECT_EQ(x, 0xeeebbb); } -TEST(loader, DISABLED_nextto) +#if _WIN32 +TEST(loader, nextto) { - // FIXME: Does not work because dlopen searches only system paths. + // On Unix dlopen searches for system libs when the path does not contain "/". auto path = "aaa.evm"; @@ -122,6 +123,7 @@ TEST(loader, DISABLED_nextto) x = (uintptr_t)evmc_load(path, nullptr); EXPECT_EQ(x, 0xaaa); } +#endif TEST(loader, eee1) { @@ -151,7 +153,7 @@ TEST(loader, eee2) TEST(loader, eee3) { - auto path = "unittests/libeee3"; + auto path = "unittests/libeee3.x"; evmc_loader_error_code ec; auto x = evmc_load(path, &ec); @@ -162,8 +164,10 @@ TEST(loader, eee3) EXPECT_EQ(x, nullptr); } +#if !_WIN32 TEST(loader, eee4) { + // Windows is not loading DLLs without extensions. auto path = "unittests/eee4"; evmc_loader_error_code ec; @@ -173,4 +177,5 @@ TEST(loader, eee4) x = evmc_load(path, nullptr); EXPECT_EQ(x, nullptr); -} \ No newline at end of file +} +#endif diff --git a/test/unittests/vm_mock.c b/test/unittests/vm_mock.c index 7a1422b3e..4ab78b7c7 100644 --- a/test/unittests/vm_mock.c +++ b/test/unittests/vm_mock.c @@ -3,12 +3,14 @@ * Licensed under the MIT License. See the LICENSE file. */ -void* evmc_create_aaa() +#include + +EVMC_EXPORT void* evmc_create_aaa() { return (void*)0xaaa; } -void* evmc_create_eee_bbb() +EVMC_EXPORT void* evmc_create_eee_bbb() { return (void*)0xeeebbb; }