用C++进行Windows驱动开发的一些进展

发布者:blowfish
发布于:2017-11-14 18:09
Windows驱动开发这一块一直是纯C的天下。为什么要用C++进行Windows驱动开发呢?当然是为了利用C++特性带来的便利。

大致上,用C++开发Windows驱动,有这么一些便利需求:
1、利用C++的封装、继承、多态,实现代码高效复用;
2、利用C++的RAII机制,避免资源泄漏;
   如果没有RAII释放,开发者得回到资源释放的老路上去。通常是有这么几条路可走:
   a、在函数中的每个返回之前,都加上释放资源的语句。这是最原始的做法,繁琐,而且一个地方忘加就意味着泄漏。
   b、使用goto,跳到函数的尾部,在尾部统一释放所有资源。受“尽量不要使用goto”的现代编码规范的约束,一般人不爱用这个,怕被别人鄙视。
   c、使用do {} while(0),遇到失败时break,在do/while循环的后面统一释放所有资源;
   d、使用try {} finally {},遇到失败时执行leave,在SEH块的finally块中统一释放所有资源。
   一旦享受了C++的RAII福利后,以上不优雅的做法,基本上都无法接受了。
3、利用C++的轮子库STL。还是为了复用;
    STL中大量使用allocator、exception等特性,需要做特殊处理。

由于Windows驱动需要考虑paged/nonpaged内存、各级IRQL、内核异常处理、浮点协处理器等特性,而编译器在处理C++代码时会自动插入一些"不可见"的数据和代码(包括自动链接CRT库实现全局/静态对象的自动构造/析构、C++异常处理、RTTI、vtable、模板展开等),早期编译器不能精确指定这些“隐藏”数据和代码的位置,也从没提供过内核层的CRT库,所以用C++编写Windows驱动面临较大的困难。微软和OSR也针对用C++开发Windows驱动出过一些调研paper,结论当然是比较悲观,一般不推荐用C++写驱动,要写的话,需要清楚地知道自己在干什么,得是专家中的专家,可能还要经常把编译器生成的代码反汇编出来看看是否满足预期。

微软官方白皮书《C++ for Kernel Mode Drivers: Pros and Cons》:
http://download.microsoft.com/download/5/b/5/5b5bec17-ea71-4653-9539-204a672f11cf/kmcode.doc

Advanced C++ features and Kernel-mode programming don’t mix:
https://blogs.msdn.microsoft.com/adioltean/2005/04/24/advanced-c-features-and-kernel-mode-programming-dont-mix/

OSR上的经典文章《Guest Article: C++ in an NT Driver》(不一定是OSR官方帖子):
http://www.osronline.com/article.cfm?article=490

由于C++便利性的诱惑,自然有开发者前赴后继地研究怎么用Windows开发驱动,并搞出来自己的C++ framework for windows driver。

最早的应该是曾经大名鼎鼎的DriverStudio(顺带怀念一下调试器王者SoftICE,那耗掉很多日夜的绿色文本界面),现在还能搜到3.2版本的下载。

BazisLib:
http://bazislib.sysprogs.org

Global Relief Effort - C++ Runtime Support for the NT DDK:
http://www.osronline.com/article.cfm?article=57

Kernel C++ Runtime Library:
http://www.hollistech.com/Resources/Cpp/kernel_c_runtime_library.htm

C++ in Kernel Drivers (c++, boost, std):
http://www.zer0mem.sk/?p=517

下面这个应该是集大成者,实现了异常处理、RTTI,可能是逆向后实现的。能否用于生产代码,使用者需自行斟酌。

ntke cpprtl:
http://www.osronline.com/showthread.cfm?link=250151

微软在用C++进行Windows驱动开发方面,也做了一些改进。

1、在VS2012中增加了/kernel编译选项,可以关闭一些内核不直接支持的C++特性:C++异常、RTTI、new/delete操作符(如果用到,必须由开发者自己提供)。
https://msdn.microsoft.com/en-us/library/jj620896.aspx

2、在VS2013中增加了code_seg()编译指示的扩展。开发者可以通过这个编译指示告诉编译器将对应的语言实体(类、变量、成员函数、模板、lambda表达式等)放在哪个段中。通常是用code_seg()指定哪些放在paged段中,因为默认是放在nonpaged的text/data段的。
这对于用C++开发Windows驱动是一个非常大的利好,虽然喜欢用C++的驱动开发者仍旧得带着镣铐跳舞。
https://msdn.microsoft.com/en-us/library/dn636922(v=vs.140).aspx

3、在自家开源的驱动NetAdpaterCx.sys的代码中,用C++实现了简单的runtime支持,主要是几个头文件。这说明现在微软自家也是有用C++来写驱动的。
https://github.com/Microsoft/Network-Adapter-Class-Extension/tree/master/rtl

声明:该文观点仅代表作者本人,转载请注明来自看雪