关闭

内核模式驱动不推荐使用C++的缘由

标签: 编程语言c++windows内核
2291人阅读 评论(0) 收藏 举报
分类:
本文所讲内容主要源自Windows DDK文档。

一、内存页面交换
和用户模式程序不同,内存页面交换对内核模式的代码不是透明的,而是需要一定程度的主动管理,要保证在代码执行过程中不会需要载入新的页面。编译器有相关的扩展#pragma指令来帮助C代码显式控制生成的二进制代码布局,以便相关的代码被放在一起,被调用时只需载入最少的页面。

而对C++而言,还存在一些编译器自动生成的代码块和数据,没有办法主动控制它们。比如编译器生成的缺省构造函数、析构函数、类型转换函数、赋值运算符重载;用于支持多重继承的adjustor thunk(没听说过?读这个),用于实现虚函数调用的virtual function thunk,用于管理基类和多态的virtual function table thunk;自动实例化(非显式实例化)的泛型代码;还有虚表本身。

对于这些问题,大多可以通过避免使用这些C++语言特性来解决。

此外,内联函数本身,也可能导致问题。因为,它有可能没被内联,而是生成了一个普通的函数,而且取决于被调用的位置,它可能存在于多个代码段。这个可以用宏或者编译器扩展的__forceinline来替代。

二、堆分配
对普通应用而言,通常我们只用一个动态内存分配的堆。而在内核模式驱动中,是很可能会用到多个内存池的,至少你会用到tagged memory。tagged memory其实就是给分配的内存加一个数字标签,以方便调试诊断,快速找到是谁的代码出的问题。这都意味着,对动态内存的分配和释放,需要一些额外的参数。这对C风格的分配函数,加个参数是很容易的,而对C++的new/delete,则很难办。new算符其实是可以带一个指针参数的,但delete算符没有。

三、STL
内核模式能使用的运行时库并不是全部,而只是一个子集,有些链接时报错,有些能链接但不起作用,也有的看起来能用但会产生某些副作用。STL大部分以源码形式存在于头文件里,看起来似乎没什么问题,但其实,它内部偶尔也会调用一些不能在内核模式使用的运行库函数。

STL对象也是不宜跨越DLL边界的。这个其实不只是STL,所有C++的对象都不宜,写过C++的DLL的应该都知道。C++的API是没有ABI规范的,不同编译器、不同版本、不同实现生成的二进制API接口都可能不一样,所以需要在外部接口上用extern "C",因为C是有ABI规范且被广泛支持的。即使如此,也还要注意,不同的DLL是可能用不同的堆的,所以对动态内存分配的资源,要遵循谁分配谁释放的原则。

此外,STL编译出的代码虽然效率很高,但代码体积一般都偏大,对驱动而言,一般期望其更精简一些。

所以,总体而言,官方并不推荐在内核级驱动里使用STL。

四、异常和RTTI
首先,内核模式的库并不是异常安全的,所以异常的使用必须独立于任何外部交互和库调用。其次,异常发生时的栈内存开销很大,对栈空间非常有限的内核模式程序而言,最多可以达到总栈空间的1/6。但是,编译器为C提供的结构化异常处理(__try/__except/__finally)没有这些问题,可以使用。

RTTI则依赖于一个在内核模式不能用的库,所以不能用。

总结
刨去这些东西之后,就得到一个大体可用的C++功能子集了。什么,还剩什么功能?很多呀,比如命名空间、引用类型、运算符重载……哎,别扔板砖啊。
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    文章分类
    最新评论