我正在尝试在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 错误仍然存在。
不幸的是,
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 中找到它,一切都会好的,在这一点上最小