1

我正在尝试在 Visual Studio 2012 中构建一个使用 GnuTLS 的项目。我从网站下载了最新的官方 Windows 版本,并通过lib /def:libgnutls-28.def在 bin 目录中运行 Visual Studio 命令提示符创建了一个链接库。

添加 a 后typedef long ssize_t,代码编译正常,但链接失败并出现以下错误:

source_file.obj : error LNK2001: unresolved external symbol _gnutls_free
C:\Path\to\executable.exe : fatal error LNK1120: 1 unresolved externals

我正在调用gnutls_free释放一些由库分配和返回的内存。如果我删除对 的调用gnutls_free,则项目链接成功。鉴于这gnutls_free只是库导出的全局变量(包含函数指针),我不确定为什么访问它会导致对不同符号的未解析引用。我已经证实这gnutls_free不是#define任何东西。

作为测试,我尝试这样做gnutls_free_function test = gnutls_free;也导致链接错误。在 GnuTLS 源代码上运行grep -w -r _gnutls_free .什么也不返回,所以我很茫然。

任何让这项工作的想法将不胜感激。

编辑:

添加__declspec(dllimport)gnutls_freein的声明gnutls.h允许链接成功。有没有办法在不维护头文件的自定义版本的情况下实现这一点?

4

1 回答 1

1

似乎没有办法让链接器或导入库自动取消引用 IAT 指向数据项的指针,就像对函数所做的那样(通过一个静态链接到导入函数的模块的小蹦床函数) . 该__declspec(dllimport)属性告诉编译器需要执行此取消引用,以便它可以插入代码以隐式执行 IAT 指针的取消引用。这允许访问导出的数据,并且函数允许编译器通过 IAT 指针的间接调用而不是通过调用 trampoline 函数来调用导入的函数。

请参阅 Raymond Chen 的几篇关于dllimport函数调用的文章(不幸的是,他没有讨论导入数据):

MS 链接器或导入库没有帮助编译器以“天真”方式获取导入数据的机制 - 编译器需要__delcspec(dllimport)提示需要通过 IAT 进行额外的取消引用。__declspec(dllimport)无论如何,这一切的重点是,除了使用属性之外,似乎没有其他方法可以导入数据。

如果您想避免修改gnutls分布(我可以理解),这是一个相当不完美的解决方法:

您可以创建一个小目标文件,其中只包含一个简单的包装器gnutls_free();因为gnutls_free()有一个没有真正依赖的接口,你可以有必要的声明'硬编码'而不是包括gnutls.h

typedef void (*gnutls_free_function) (void *);
__declspec(dllimport) extern gnutls_free_function gnutls_free;

void xgnutls_free(void* p)
{
    gnutls_free(p);
}

让您的代码调用xgnutls_free()而不是gnutls_free().

不是一个很好的解决方案 - 它需要您的代码调用包装器(因此,如果您要合并可能依赖的 3rd 方代码,这尤其不是很好gnutls_free()),但它可能已经足够好了。

于 2013-01-30T11:00:52.233 回答