第三章 Windows驱动编译环境配置、安装和调试

来源:互联网 发布:数据分析30岁后怎么走 编辑:程序博客网 时间:2024/04/29 21:48

3.1用c语言还是用C++语言

从理论上讲,只要能编译出PE二进制文件格式的语言都可以编写驱动,C、C++、汇编语言甚至Delphi语言都可以,但提供DDK只含有C\C++的链接库,所以最好用C\C++来开发驱动。

C++面向对象,灵活性和模块性高。但C语言实例多。个人还是倾向于用C语言。

3.1.1 调用约定

分为四种__cdecl, __stdcall, __fastcall 和 thiscall,其中最常见到的就是前两种。

1)__cdecl

c语言调用约定, c语言调用会在obj文件中产生一个符号来代表函数,符号的形式是下划线+函数名,并且函数体以ret形式返回。参数的压栈为从右到左。由于函数以ret返回,所以调用后的堆栈与调用前是不同的,需要将栈指针+参数长度。由调用者恢复堆栈。

例void __cdecl Foo(int a, int b);

Foo(0x12345678, 0x11223344)

展开汇编为:

push 11223344h

push 12345678h

call _Foo

add esp,8

2)__stdcall

void __stdcall Foo(int a, int b)

c语言调用在obj文件中产生一个符号来代替函数。形式为 下划线+函数名@X, X代表清理堆栈时需要的数字,函数以 ret X返回。从右向左压栈。函数负责恢复堆栈。

Foo(0x12345678, 0x11223344)

展开汇编为

push 11223344h

push 12345678h

call _Foo@8


驱动程序的编写需要标准调用约定。而一般vc编译器默认为C调用约定,所以用vc编译时注意修改调用约定。DDK编译环境编译驱动时默认为标准调用约定。

3.1.2函数的导出名

cl.exe既可以编译C语言又可以编译C++,编译器会默认根据文件的扩展名来用不同编译方式。同一种调用约定按不同德编译方式会产生不同德编译结果。

例 void __stdcall Foo(int a, int b)

在C++编译方式中会编译成obj文件后的符号为?Foo@@YGXHH@Z, 而在c编译方式中为_Foo@8.

windows驱动的默认入口函数为_DriverEntry@8。因此用c++编译时会导致连接错误。所以需要用extern “C”来解决。

例extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegisterPath)


同样在c++程序中包含ntddk.h和wdm.h时,也会有编译错误。也需要用extern "C"来修饰。


#ifdef __cplusplus

extern "C"

{

#endif

#include <NTDDK.h>

#ifdef __cplusplus

}

#endif