loader: Add Windows support

This commit is contained in:
Paweł Bylica 2018-07-05 13:01:20 +02:00
parent 02b52e2926
commit 49e26b1ede
No known key found for this signature in database
GPG Key ID: 7A0C037434FE77EF
6 changed files with 57 additions and 28 deletions

View File

@ -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

View File

@ -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 $<BUILD_INTERFACE:${include_dir}>$<INSTALL_INTERFACE:include>)
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})

View File

@ -8,11 +8,34 @@
#include <stdint.h>
#include <string.h>
#if _WIN32
#include <Windows.h>
#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 <dlfcn.h>
#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_LENGTH 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_LOADER_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_LENGTH];
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_LENGTH);
strcpy_s(name + prefix_length, PATH_MAX_LENGTH, 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_LOADER_SYMBOL_NOT_FOUND;
}

View File

@ -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} $<TARGET_FILE_NAME:vm-mock> ${CMAKE_SHARED_LIBRARY_PREFIX}aaa${CMAKE_SHARED_LIBRARY_SUFFIX}
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> double_prefix_aaa.evm
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> double-prefix-aaa.evm
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> eee-bbb.dll
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> ${CMAKE_SHARED_LIBRARY_PREFIX}eee1${CMAKE_SHARED_LIBRARY_SUFFIX}
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> eee2${CMAKE_SHARED_LIBRARY_SUFFIX}
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> ${CMAKE_SHARED_LIBRARY_PREFIX}eee3
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE_NAME:vm-mock> eee4
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> libaaa.so
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> double_prefix_aaa.evm
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> double-prefix-aaa.evm
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> eee-bbb.dll
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> libeee1.so
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> eee2.so
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> libeee3.x
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> eee4
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> ../aaa.evm
COMMAND ${CMAKE_COMMAND} -E touch empty.file
)

View File

@ -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);
}
}
#endif

View File

@ -3,12 +3,14 @@
* Licensed under the MIT License. See the LICENSE file.
*/
void* evmc_create_aaa()
#include <evmc/utils.h>
EVMC_EXPORT void* evmc_create_aaa()
{
return (void*)0xaaa;
}
void* evmc_create_eee_bbb()
EVMC_EXPORT void* evmc_create_eee_bbb()
{
return (void*)0xeeebbb;
}