LNK2019 静态库中定义的函数中未解析的外部符号

问题描述 投票:0回答:1

我正在尝试在Windows 10上通过使用cl.exe来编译驱动程序。它是用纯C编写的。我正在使用Enterprise Windows Driver Kit提供源文件并针对X86进行编译。我知道 msbuild.exe 存在,但我既不想制作 vs proj 文件,也不希望实际的编译过程被混淆。

到目前为止,我能够编译并包含我需要的每个函数,但是,正如我之前注意到的,link.exe 无法找到 ntoskrnl.lib 中实现的任何函数。

具体来说,我无法解析符号“IoCreateDevice”和“IoDeleteDevice”,它们都应该在 ntoskrnl.lib 中实现。

我在bat文件中有这个编译和链接行:

cl ^
 /c /KERNEL /GS- /Tc ^
 filter.c ^
 /I"D:\Downloads\EnterpriseWDK_rs1_release_14393_20160715-1616\Program Files\Windows Kits\10\Include\10.0.14393.0\km"

link filter.obj ^
 "D:\Downloads\EnterpriseWDK_rs1_release_14393_20160715-1616\Program Files\Windows Kits\10\Lib\10.0.14393.0\km\x86\fwpkclnt.lib" ^
 "D:\Downloads\EnterpriseWDK_rs1_release_14393_20160715-1616\Program Files\Windows Kits\10\Lib\10.0.14393.0\km\x86\wdm.lib" ^
 "D:\Downloads\EnterpriseWDK_rs1_release_14393_20160715-1616\Program Files\Windows Kits\10\Lib\10.0.14393.0\km\x86\ntoskrnl.lib" ^
 /SUBSYSTEM:NATIVE /ENTRY:DriverEntry /DRIVER:WDM /KERNEL /VERBOSE /MACHINE:X86 /BASE:0x1000 /NODEFAULTLIB

在链接阶段运行它会产生:

filter.obj : error LNK2019: unresolved external symbol __imp__IoCreateDevice referenced in function _DriverEntry
filter.obj : error LNK2019: unresolved external symbol __imp__IoDeleteDevice referenced in function _unload

Unused libraries:
  D:\Downloads\EnterpriseWDK_rs1_release_14393_20160715-1616\Program Files\Windows Kits\10\Lib\10.0.14393.0\km\x86\ntoskrnl.lib

我知道它正在图书馆搜索:

...
Searching D:\Downloads\EnterpriseWDK_rs1_release_14393_20160715-1616\Program Files\Windows Kits\10\Lib\10.0.14393.0\km\x86\ntoskrnl.lib:
...

并且,为了验证 ntoskrnl.lib 中是否包含函数实现,

dumpbin.exe "[ntoskrnl.lib path]" /EXPORTS | grep -i iocreatedevice
返回:

                  _IoCreateDevice@28

然后,为了验证符号的定义是否存在于

wpm.h
头文件中,我修改了源代码:

...
#if (NTDDI_VERSION >= NTDDI_WIN2K)
#pragma message("DEFINING IOCREATEDEVICE") //my line
_IRQL_requires_max_(APC_LEVEL)
_Ret_range_(<=, 0)
NTKERNELAPI
NTSTATUS
IoCreateDevice(
    _In_  PDRIVER_OBJECT DriverObject,
    _In_  ULONG DeviceExtensionSize,
    _In_opt_ PUNICODE_STRING DeviceName,
    _In_  DEVICE_TYPE DeviceType,
    _In_  ULONG DeviceCharacteristics,
    _In_  BOOLEAN Exclusive,
    _Outptr_result_nullonfailure_
    _At_(*DeviceObject,
        __drv_allocatesMem(Mem)
        _When_((((_In_function_class_(DRIVER_INITIALIZE))
               ||(_In_function_class_(DRIVER_DISPATCH)))),
             __drv_aliasesMem))
    PDEVICE_OBJECT *DeviceObject
    );
#endif
...

在编译时打印:

...
filter.c
DEFINING IOCREATEDEVICE
...

我不明白为什么链接器拒绝链接到_IoCreateDevice的实现版本。它看到了什么而说“这个定义不适用?”


编辑1: 为了尝试强制链接器在链接库时使用给定的顺序,根据 BoP 的注释,我在源代码文件的顶部添加了以下语句,位于任何包含之前:

#pragma comment(lib, "D:\\Downloads\\EnterpriseWDK_rs1_release_14393_20160715-1616\\Program Files\\Windows Kits\\10\\Lib\\10.0.14393.0\\km\\x86\\fwpkclnt.lib")
#pragma comment(lib, "D:\\Downloads\\EnterpriseWDK_rs1_release_14393_20160715-1616\\Program Files\\Windows Kits\\10\\Lib\\10.0.14393.0\\km\\x86\\wdm.lib")
#pragma comment(lib, "D:\\Downloads\\EnterpriseWDK_rs1_release_14393_20160715-1616\\Program Files\\Windows Kits\\10\\Lib\\10.0.14393.0\\km\\x86\\ntoskrnl.lib")

但 LNK2019 错误仍然存在。

c windows x86 driver cl
1个回答
0
投票

不幸的是,

IoCreateDevice
IoDeleteDevice
(以及许多其他内核API)在没有明确指示调用约定的情况下声明。

作为例子

_IRQL_requires_max_(APC_LEVEL)
NTKERNELAPI
VOID
IoDeleteDevice (
    _In_ __drv_freesMem(Mem) PDEVICE_OBJECT DeviceObject
    );

何时会有更正确的定义

_IRQL_requires_max_(APC_LEVEL)
NTKERNELAPI
VOID
NTAPI
IoDeleteDevice (
    _In_ __drv_freesMem(Mem) PDEVICE_OBJECT DeviceObject
    );

因为 api 定义上没有显式

NTAPI
(
__stdcall
) 隐式使用。当您需要使用
/Gd
(
__cdecl
) 作为默认值时,CL 默认使用 __stdcall
 (
/Gz
)。

我如何看待这个?

LNK2019: unresolved external symbol __imp__IoDeleteDevice

为自己说。这是

__cdecl
装饰(在 x86 中)。如果您使用
__stdacll
,相同的符号将被装饰为
__imp__IoDeleteDevice@4

ntoskrnl.lib
中没有
__imp__IoDeleteDevice
__imp__IoCreateDevice 符号。因此,该库未使用,并且您有 2 个未解析的符号。将
/Gz
选项添加到
CL
命令行后 - 链接器已经会搜索
__imp__IoDeleteDevice@28
__imp__IoCreateDevice@4
,在 ntoskrnl.lib 中找到它,一切都会好的,在这一点上最小

© www.soinside.com 2019 - 2024. All rights reserved.