FORCE:UNRESOLVED и разрешение символов в WindowsC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 FORCE:UNRESOLVED и разрешение символов в Windows

Сообщение Anonymous »

Я пытаюсь понять, как флаг компоновщика /FORCE:UNRESOLVED предназначен для использования в Windows. Я хотел бы создать библиотеку с неразрешенными символами с ожиданием, что они будут заполнены во время выполнения. Я предположил, что этого можно добиться, указав флаг во время компоновки, а затем сохранив определение в исполняемом файле, который загружает эту библиотеку. Я не ожидал, что будет какая-либо разница между динамической связью во время загрузки и во время выполнения в логике разрешения символов, но я попробовал и то, и другое, просто чтобы быть уверенным. В обоих случаях наличие неопределенного символа приводит к незаметному сбою программы в момент загрузки динамической библиотеки.
Вот MWE, демонстрирующий проблему (я включил полный CMake для удобства воспроизведения, но я не думаю, что там есть что-то актуальное). Если я удалю функцию power_six из библиотеки и перестану пытаться ее вызвать, все будет работать как положено, но если определение существует в библиотеке, то основной исполняемый файл выйдет из строя при загрузке библиотеки. Может ли кто-нибудь объяснить, что я делаю неправильно и как в этом случае должно работать разрешение символов? В документации Windows я нашел хорошие ресурсы по разрешению путей к библиотекам, а спецификация PE указывает на то, как хранится связь, но я не вижу никакой информации о правилах разрешения символов в этом случае. Ожидается ли, что DllMain будет реализован таким образом, чтобы каким-то образом заполнять символы? Если да, то как это сделать?

Код: Выделить всё

// lib\lib.h
int square(int x);
int power_six(int x);

Код: Выделить всё

// lib\lib.c
#include "lib.h"
#include "windows.h"

// This must be provided by another file in the process space.
int cube(int x);

int square(int x) {
return x * x;
}

int power_six(int x) {
return cube(square(x));
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
// No-op included because the FORCE docs indicate that the entry point must
// be defined for this flag to have an effect.
}

Код: Выделить всё

# lib\CMakeLists.txt
cmake_minimum_required(VERSION 3.26.4 FATAL_ERROR)

project(lib VERSION 0.0.1 LANGUAGES C)

# For simplicity in testing, always export symbols on Windows
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

add_library(lib SHARED lib.c)
target_include_directories(lib PUBLIC "$" "$")
target_link_options(lib PRIVATE "/FORCE:UNRESOLVED")

include(GNUInstallDirs)
install(
TARGETS lib
DESTINATION ${CMAKE_INSTALL_LIBDIR}
EXPORT ${PROJECT_NAME}-exports
)
install(
FILES lib.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

include(CMakePackageConfigHelpers)

foreach(tree_type BUILD INSTALL)
if(tree_type STREQUAL "BUILD")
set(install_location ".")
else()
set(install_location "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
endif()

set(build_location "${PROJECT_BINARY_DIR}/${install_location}")

write_basic_package_version_file(
"${build_location}/${PROJECT_NAME}-config-version.cmake"
VERSION ${CMAKE_PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion)
configure_package_config_file("${CMAKE_CURRENT_LIST_DIR}/cmake/config.cmake.in"
"${build_location}/${PROJECT_NAME}-config.cmake"
INSTALL_DESTINATION "${install_location}")

if(tree_type STREQUAL "BUILD")
export(EXPORT ${PROJECT_NAME}-exports
FILE "${PROJECT_NAME}-targets.cmake"
NAMESPACE ${PROJECT_NAME}::)
else()
install(DIRECTORY "${build_location}/" DESTINATION "${install_location}")
install(EXPORT ${PROJECT_NAME}-exports
DESTINATION "${install_location}"
FILE "${PROJECT_NAME}-targets.cmake"
NAMESPACE ${PROJECT_NAME}::)
endif()
endforeach()

Код: Выделить всё

// lib\cmake\config.cmake.in
@PACKAGE_INIT@

cmake_minimum_required(VERSION @CMAKE_MINIMUM_REQUIRED_VERSION@)

include("${CMAKE_CURRENT_LIST_DIR}/lib-targets.cmake" REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/lib-config-version.cmake"  REQUIRED)

set(${CMAKE_FIND_PACKAGE_NAME}_CONFIG "${CMAKE_CURRENT_LIST_FILE}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(${CMAKE_FIND_PACKAGE_NAME} CONFIG_MODE)

Код: Выделить всё

# executable\main.c
#include 
#include "windows.h"

// Here's the definition of cube that should be visible to lib.c
int cube(int x) {
return x * x * x;
}

// Option 1: Load-time linkage
/*#include "lib.h"*/

/*int main() {*/
/*    int const x = 2;*/
/*    int const x_2 = square(x);*/
/*    printf("The square of %d is %d\n", x, x_2);*/
/*    int const x_6 = power_six(x);*/
/*    printf("The sixth power of %d is %d\n", x, x_2);*/
/*}*/

// Option 2: Run-time dynamic linking

typedef int (__cdecl *MYPROC)(int);

int main() {
int const x = 2;
int x_2 = -1;
int x_6 = -1;
char const * path_to_lib = ...;

HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult = FALSE;

printf("Attempting to load the library\n");
hinstLib = LoadLibrary(path_to_lib);

if (hinstLib != NULL)
{
printf("Found the lib\n");
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "square");
if (NULL != ProcAdd)
{
printf("Found the function\n");
x_2 = (ProcAdd) (x);
}

ProcAdd = (MYPROC) GetProcAddress(hinstLib, "power_six");
if (NULL != ProcAdd)
{
printf("Found the function\n");
x_6 = (ProcAdd) (x);
}
fFreeResult = FreeLibrary(hinstLib);
}
printf("The square of %d is %d\n", x, x_2);
}

Код: Выделить всё

// executable\CMakeLists.txt
cmake_minimum_required(VERSION 3.26.4 FATAL_ERROR)

project(example VERSION 0.0.1 LANGUAGES C)

add_executable(example main.c)
find_package(lib)
target_link_libraries(example PRIVATE lib::lib)

include(GNUInstallDirs)
install(
TARGETS example
DESTINATION bin
EXPORT ${PROJECT_NAME}-exports
)
Обновление
Я спросил об этом на форуме разработчиков Microsoft, и пришел к выводу, что это невозможно.

Подробнее здесь: https://stackoverflow.com/questions/790 ... on-windows
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»